From 90868b87dca780034d38220254830a050e24906a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E5=8D=A1=E6=9E=97=E5=88=98?= Date: Sat, 6 Jul 2024 17:53:43 +0800 Subject: [PATCH 0001/1285] Update upgrade_openssh9.8p1.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增多核同时编译选项 --- upgrade_openssh9.8p1.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/upgrade_openssh9.8p1.sh b/upgrade_openssh9.8p1.sh index 2cc0b307c..cd83c270d 100644 --- a/upgrade_openssh9.8p1.sh +++ b/upgrade_openssh9.8p1.sh @@ -13,6 +13,10 @@ else exit 1 fi +# 询问用户是否需要多线程编译 +echo "请输入同时编译的核心数量:" +read multi_thread_compile + # 等待并检查锁文件 wait_for_lock() { while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do @@ -57,7 +61,7 @@ install_openssh() { tar -xzf openssh-${OPENSSH_VERSION}.tar.gz cd openssh-${OPENSSH_VERSION} ./configure - make + make -j$multi_thread_compile make install } From 92f56e47250a3fdd92f1f8d4eeec0388e1e0b685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E5=8D=A1=E6=9E=97=E5=88=98?= Date: Sat, 6 Jul 2024 20:35:55 +0800 Subject: [PATCH 0002/1285] Update upgrade_openssh9.8p1.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 已更改为自动检测核心数量 --- upgrade_openssh9.8p1.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/upgrade_openssh9.8p1.sh b/upgrade_openssh9.8p1.sh index cd83c270d..4e703dd1f 100644 --- a/upgrade_openssh9.8p1.sh +++ b/upgrade_openssh9.8p1.sh @@ -13,10 +13,6 @@ else exit 1 fi -# 询问用户是否需要多线程编译 -echo "请输入同时编译的核心数量:" -read multi_thread_compile - # 等待并检查锁文件 wait_for_lock() { while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do @@ -61,13 +57,13 @@ install_openssh() { tar -xzf openssh-${OPENSSH_VERSION}.tar.gz cd openssh-${OPENSSH_VERSION} ./configure - make -j$multi_thread_compile + make -j$(nproc) make install } # 重启SSH服务 restart_ssh() { - case $OS in + case $OS 在 ubuntu|debian) systemctl restart ssh ;; From 62227c875c427c868734b8b8c2d971b5fdb98e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E5=8D=A1=E6=9E=97=E5=88=98?= Date: Sun, 7 Jul 2024 07:22:08 +0800 Subject: [PATCH 0003/1285] Update upgrade_openssh9.8p1.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复无法正常运作的Bug --- upgrade_openssh9.8p1.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade_openssh9.8p1.sh b/upgrade_openssh9.8p1.sh index 4e703dd1f..f53bb0d5e 100644 --- a/upgrade_openssh9.8p1.sh +++ b/upgrade_openssh9.8p1.sh @@ -57,7 +57,7 @@ install_openssh() { tar -xzf openssh-${OPENSSH_VERSION}.tar.gz cd openssh-${OPENSSH_VERSION} ./configure - make -j$(nproc) + make -j${nproc} make install } From 2d89878098f6f04e53e784354a899684e38883c0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 10 Aug 2025 05:10:32 +0000 Subject: [PATCH 0004/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-10=2005:10:32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 335 +++++++++++++++++++++++++++++++++++++++---------- jp/kejilion.sh | 329 ++++++++++++++++++++++++++++++++++++++---------- kr/kejilion.sh | 327 ++++++++++++++++++++++++++++++++++++++--------- tw/kejilion.sh | 317 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 1060 insertions(+), 248 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 4648ca502..8522d0a2c 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.3" +sh_v="4.0.5" gl_hui='\e[37m' @@ -1185,7 +1185,7 @@ iptables_panel() { 5) # IP whitelist - read -e -p "Please enter the IP or IP segment to release:" o_ip + read -e -p "Please enter the IP or IP segment to be released:" o_ip allow_ip $o_ip ;; 6) @@ -1556,7 +1556,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -1738,7 +1738,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to the mode parameter + # Decide to turn on or off WAF according to mode parameters if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2371,18 +2371,25 @@ web_optimization() { +check_docker_app() { + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + check_docker="${gl_lv}已安装${gl_bai}" + else + check_docker="${gl_hui}未安装${gl_bai}" + fi +} -check_docker_app() { +# check_docker_app() { -if docker inspect "$docker_name" &>/dev/null; then - check_docker="${gl_lv}已安装${gl_bai}" -else - check_docker="${gl_hui}未安装${gl_bai}" -fi +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# check_docker="${gl_lv}${gl_bai} installed" +# else +# check_docker="${gl_hui}${gl_bai} is not installed" +# fi -} +# } check_docker_app_ip() { @@ -2720,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2751,6 +2758,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "$docker_nameInstalled" @@ -2764,6 +2773,9 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "$docker_nameInstalled" check_docker_app_ip @@ -2777,6 +2789,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -2817,7 +2831,6 @@ done - docker_app_plus() { send_stats "$app_name" while true; do @@ -2827,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2857,13 +2870,20 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 2) docker_app_update + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + ;; 5) echo "${docker_name}Domain access settings" @@ -3538,15 +3558,21 @@ while true; do install wget iptables_open panel_app_install + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}Install" ;; 2) panel_app_manage + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}control" ;; 3) panel_app_uninstall + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt send_stats "${panelname}uninstall" ;; *) @@ -3875,6 +3901,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The FRP server has been installed" ;; 2) @@ -3883,6 +3911,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The FRP server has been updated" ;; 3) @@ -3892,7 +3922,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; 5) @@ -3916,7 +3947,7 @@ frps_panel() { 8) send_stats "Block IP access" - echo "If you have accessed the anti-generation domain name, you can use this function to block IP+ port access, which is more secure." + echo "If you have accessed the anti-generation domain name, use this function to block IP+ port access, which is more secure." read -e -p "Please enter the port you need to block:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3966,6 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The FRP client has been installed" ;; 2) @@ -3974,6 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The FRP client has been updated" ;; @@ -3983,6 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; @@ -4052,18 +4089,24 @@ yt_menu_pro() { install ffmpeg sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The installation is complete. Press any key to continue..." read ;; 2) send_stats "Update yt-dlp..." echo "Update yt-dlp..." sudo yt-dlp -U + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "Update completed. Press any key to continue..." read ;; 3) send_stats "Uninstalling yt-dlp..." echo "Uninstalling yt-dlp..." sudo rm -f /usr/local/bin/yt-dlp + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "Uninstall is complete. Press any key to continue..." read ;; 5) @@ -4944,7 +4987,7 @@ elrepo_install() { fi # Print detected operating system information echo "Operating system detected:$os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm @@ -8411,58 +8454,75 @@ linux_ldnmp() { linux_panel() { + + + + while true; do clear - # send_stats "App Market" echo -e "Application Market" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Official version of Baota Panel${gl_kjlan}2. ${gl_bai}aaPanel International Edition" - echo -e "${gl_kjlan}3. ${gl_bai}1Panel new generation management panel${gl_kjlan}4. ${gl_bai}NginxProxyManager Visual Panel" - echo -e "${gl_kjlan}5. ${gl_bai}OpenList multi-store file list program${gl_kjlan}6. ${gl_bai}Ubuntu Remote Desktop Web Edition" - echo -e "${gl_kjlan}7. ${gl_bai}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${gl_bai}QB Offline BT Magnetic Download Panel" - echo -e "${gl_kjlan}9. ${gl_bai}Poste.io mail server program${gl_kjlan}10. ${gl_bai}RocketChat multiplayer online chat system" + + local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") + + # Set the color with loop + for i in {1..100}; do + if echo "$app_numbers" | grep -q "^$i$"; then + declare "color$i=${gl_lv}" + else + declare "color$i=${gl_bai}" + fi + done + + echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager Visual Panel" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" + echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}11. ${color11}Zendao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" + echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" + echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome Adware${gl_kjlan}18. ${color18}onlyoffice online office OFFICE" + echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Zendao project management software${gl_kjlan}12. ${gl_bai}Qinglong Panel Timed Task Management Platform" - echo -e "${gl_kjlan}13. ${gl_bai}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${gl_bai}Simple picture bed picture management program" - echo -e "${gl_kjlan}15. ${gl_bai}emby multimedia management system${gl_kjlan}16. ${gl_bai}Speedtest speed test panel" - echo -e "${gl_kjlan}17. ${gl_bai}AdGuardHome Adware${gl_kjlan}18. ${gl_bai}onlyoffice online office OFFICE" - echo -e "${gl_kjlan}19. ${gl_bai}Thunder Pool WAF firewall panel${gl_kjlan}20. ${gl_bai}portainer container management panel" + echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" + echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed Speed Test Tool" + echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}VScode web version${gl_kjlan}22. ${gl_bai}UptimeKuma monitoring tool" - echo -e "${gl_kjlan}23. ${gl_bai}Memos web page memo${gl_kjlan}24. ${gl_bai}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${gl_bai}Nextcloud network disk${gl_kjlan}26. ${gl_bai}QD-Today timing task management framework" - echo -e "${gl_kjlan}27. ${gl_bai}Dockge Container Stack Management Panel${gl_kjlan}28. ${gl_bai}LibreSpeed Speed Test Tool" - echo -e "${gl_kjlan}29. ${gl_bai}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}PhotoPrism Private Album System" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" + echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI Chat Aggregation Website" + echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" + echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}StirlingPDF tool collection${gl_kjlan}32. ${gl_bai}drawio free online charting software${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Sun-Panel Navigation Panel${gl_kjlan}34. ${gl_bai}Pingvin-Share file sharing platform" - echo -e "${gl_kjlan}35. ${gl_bai}Minimalist circle of friends${gl_kjlan}36. ${gl_bai}LobeChatAI Chat Aggregation Website" - echo -e "${gl_kjlan}37. ${gl_bai}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${gl_bai}Xiaoya alist family bucket" - echo -e "${gl_kjlan}39. ${gl_bai}Bililive live broadcast recording tool${gl_kjlan}40. ${gl_bai}webssh web version SSH connection tool" + echo -e "${gl_kjlan}41. ${color41}Mouse Management Panel${gl_kjlan}42. ${color42}Nexte remote connection tool" + echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub Acceleration Station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}Prometheus Monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Mouse Management Panel${gl_kjlan}42. ${gl_bai}Nexte remote connection tool" - echo -e "${gl_kjlan}43. ${gl_bai}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${gl_bai}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${gl_bai}Docker acceleration station${gl_kjlan}46. ${gl_bai}GitHub Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${gl_bai}Prometheus Monitoring${gl_kjlan}48. ${gl_bai}Prometheus (host monitoring)" - echo -e "${gl_kjlan}49. ${gl_bai}Prometheus (Container Monitoring)${gl_kjlan}50. ${gl_bai}Replenishment monitoring tool" + echo -e "${gl_kjlan}51. ${color51}PVE Chicken Panel${gl_kjlan}52. ${color52}DPanel Container Management Panel" + echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" + echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${gl_bai}PVE Chicken Panel${gl_kjlan}52. ${gl_bai}DPanel Container Management Panel" - echo -e "${gl_kjlan}53. ${gl_bai}llama3 chat AI model${gl_kjlan}54. ${gl_bai}AMH Host Website Building Management Panel" - echo -e "${gl_kjlan}55. ${gl_bai}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${gl_bai}FRP intranet penetration (client)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${gl_bai}Deepseek chat AI big model${gl_kjlan}58. ${gl_bai}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${gl_bai}NewAPI big model asset management${gl_kjlan}60. ${gl_bai}JumpServer open source bastion machine" + echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" + echo -e "${gl_kjlan}65. ${color65}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" + echo -e "${gl_kjlan}67. ${color67}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL Certificate Management Platform" + echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot Chat Robot Framework" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}Online translation server${gl_kjlan}62. ${gl_bai}RAGFlow big model knowledge base" - echo -e "${gl_kjlan}63. ${gl_bai}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${gl_bai}it-tools toolbox" - echo -e "${gl_kjlan}65. ${gl_bai}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${gl_bai}yt-dlp video download tool" - echo -e "${gl_kjlan}67. ${gl_bai}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${gl_bai}AllinSSL Certificate Management Platform" - echo -e "${gl_kjlan}69. ${gl_bai}SFTPGo file transfer tool${gl_kjlan}70. ${gl_bai}AstrBot Chat Robot Framework" + echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden Password Manager${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV Private Movie" + echo -e "${gl_kjlan}75. ${color75}Melody Music Elf${gl_kjlan}76. ${color76}Online DOS old games" + echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki Intelligent Document Management System" + echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${gl_bai}Navidrome Private Music Server${gl_kjlan}72. ${gl_bai}bitwarden Password Manager${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${gl_bai}LibreTV Private Film and Television${gl_kjlan}74. ${gl_bai}MoonTV Private Movie" - echo -e "${gl_kjlan}75. ${gl_bai}Melody Music Elf${gl_kjlan}76. ${gl_bai}Online DOS old games" - echo -e "${gl_kjlan}77. ${gl_bai}Thunder offline download tool${gl_kjlan}78. ${gl_bai}PandaWiki Intelligent Document Management System" - echo -e "${gl_kjlan}79. ${gl_bai}Beszel server monitoring" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8652,7 +8712,7 @@ linux_panel() { echo -e "Nezha Monitoring$check_docker $update_status" echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8742,7 +8802,7 @@ linux_panel() { fi echo "" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "Access address:" echo "https://$yuming" @@ -8788,6 +8848,9 @@ linux_panel() { --restart=always \ -d analogic/poste.io + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "poste.io has been installed" echo "------------------------" @@ -8809,6 +8872,10 @@ linux_panel() { -h "$yuming" \ --restart=always \ -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "poste.io has been installed" echo "------------------------" @@ -8821,6 +8888,8 @@ linux_panel() { docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; @@ -9119,7 +9188,7 @@ linux_panel() { echo -e "Thunder Pool Service$check_docker" echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9136,6 +9205,8 @@ linux_panel() { install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "The Thunder Pool WAF panel has been installed" check_docker_app_ip @@ -9147,6 +9218,8 @@ linux_panel() { bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "Thunder Pool WAF panel has been updated" check_docker_app_ip @@ -9157,6 +9230,8 @@ linux_panel() { 4) cd /data/safeline docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" echo "docker compose down && docker compose down --rmi all" ;; @@ -10623,6 +10698,127 @@ linux_panel() { ;; + 80) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden-linkwarden-1" + local docker_port="8080" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + + # Download the official docker-compose and env files + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + + # Generate random keys and passwords + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) + + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + + # Add administrator account information + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + # Start the container + docker compose up -d + + clear + echo "Installed" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # Keep the original variable + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + + 81) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" + + docker_app_install() { + + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d + + } + + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + + 0) kejilion ;; @@ -10844,9 +11040,9 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities (Xiuyuan)" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tool${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}File Manager" echo -e "${gl_kjlan}------------------------" @@ -10854,6 +11050,7 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}Set up a system recycling bin${gl_kjlan}34. ${gl_bai}System backup and recovery" echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" + echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and Security" @@ -10874,7 +11071,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys are set" + echo "Shortcut keys have been set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -11538,7 +11735,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -11853,6 +12050,12 @@ EOF ;; + 39) + clear + send_stats "Command line history" + bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + ;; + 41) clear send_stats "Message board" @@ -12664,7 +12867,7 @@ echo "Install load balancing k loadbalance |k load balancing" echo "Firewall panel k fhq |k firewall" echo "Open port k dkdk 8080 |k Open port 8080" echo "Close port k gbdk 7800 |k Close port 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 89c7f4814..023c6369d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.3" +sh_v="4.0.5" gl_hui='\e[37m' @@ -1556,7 +1556,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1738,7 +1738,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることにしました + # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2371,18 +2371,25 @@ web_optimization() { +check_docker_app() { + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + check_docker="${gl_lv}已安装${gl_bai}" + else + check_docker="${gl_hui}未安装${gl_bai}" + fi +} -check_docker_app() { +# check_docker_app() { -if docker inspect "$docker_name" &>/dev/null; then - check_docker="${gl_lv}已安装${gl_bai}" -else - check_docker="${gl_hui}未安装${gl_bai}" -fi +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# check_docker = "$ {gl_lv} $ {gl_bai}インストール" +# else +# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" +# fi -} +# } check_docker_app_ip() { @@ -2720,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2751,6 +2758,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "$docker_nameインストール" @@ -2764,6 +2773,9 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "$docker_nameインストール" check_docker_app_ip @@ -2777,6 +2789,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" send_stats "アンインストール$docker_name" ;; @@ -2817,7 +2831,6 @@ done - docker_app_plus() { send_stats "$app_name" while true; do @@ -2827,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2857,13 +2870,20 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 2) docker_app_update + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + ;; 5) echo "${docker_name}ドメインアクセス設定" @@ -3538,15 +3558,21 @@ while true; do install wget iptables_open panel_app_install + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}インストール" ;; 2) panel_app_manage + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}コントロール" ;; 3) panel_app_uninstall + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt send_stats "${panelname}アンインストール" ;; *) @@ -3875,6 +3901,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRPサーバーがインストールされています" ;; 2) @@ -3883,6 +3911,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRPサーバーが更新されました" ;; 3) @@ -3892,7 +3922,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; 5) @@ -3916,7 +3947,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" + echo "アンチジェネレーションドメイン名にアクセスした場合は、この関数を使用して、より安全なIP+ポートアクセスをブロックします。" read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3966,6 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRPクライアントがインストールされています" ;; 2) @@ -3974,6 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRPクライアントが更新されました" ;; @@ -3983,6 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; @@ -4052,18 +4089,24 @@ yt_menu_pro() { install ffmpeg sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) send_stats "yt-dlpを更新..." echo "yt-dlpを更新..." sudo yt-dlp -U + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) send_stats "yt-dlpのアンインストール..." echo "yt-dlpのアンインストール..." sudo rm -f /usr/local/bin/yt-dlp + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) @@ -5183,7 +5226,7 @@ optimize_high_performance() { echo -e "${gl_lv}その他の最適化...${gl_bai}" # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -8411,58 +8454,75 @@ linux_ldnmp() { linux_panel() { + + + + while true; do clear - # send_stats「アプリマーケット」 echo -e "アプリケーション市場" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Baotaパネルの公式バージョン${gl_kjlan}2. ${gl_bai}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${gl_bai}1パネルの新世代管理パネル${gl_kjlan}4. ${gl_bai}nginxproxymanagerビジュアルパネル" - echo -e "${gl_kjlan}5. ${gl_bai}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${gl_bai}UbuntuリモートデスクトップWebエディション" - echo -e "${gl_kjlan}7. ${gl_bai}Nezha Probe VPS監視パネル${gl_kjlan}8. ${gl_bai}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${gl_bai}poste.ioメールサーバープログラム${gl_kjlan}10. ${gl_bai}Rocketchatマルチプレイヤーオンラインチャットシステム" + + local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") + + # ループで色を設定します + for i in {1..100}; do + if echo "$app_numbers" | grep -q "^$i$"; then + declare "color$i=${gl_lv}" + else + declare "color$i=${gl_bai}" + fi + done + + echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" + echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" + echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" + echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" + echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" + echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${gl_bai}Qinglongパネルの時限タスク管理プラットフォーム" - echo -e "${gl_kjlan}13. ${gl_bai}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${gl_bai}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${gl_bai}Emby Multimedia Management System${gl_kjlan}16. ${gl_bai}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${gl_bai}AdGuardhomeアドウェア${gl_kjlan}18. ${gl_bai}唯一のオフィスオンラインオフィスオフィス" - echo -e "${gl_kjlan}19. ${gl_bai}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${gl_bai}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" + echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" + echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}vscode webバージョン${gl_kjlan}22. ${gl_bai}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${gl_bai}メモWebページメモ${gl_kjlan}24. ${gl_bai}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${gl_bai}NextCloudネットワークディスク${gl_kjlan}26. ${gl_bai}QD-Todayタイミングタスク管理フレームワーク" - echo -e "${gl_kjlan}27. ${gl_bai}Dockge Container Stack Managementパネル${gl_kjlan}28. ${gl_bai}librespeed速度テストツール" - echo -e "${gl_kjlan}29. ${gl_bai}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}フォトプリズムプライベートアルバムシステム" + echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" + echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}StirlingPDFツールコレクション${gl_kjlan}32. ${gl_bai}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}サンパネルナビゲーションパネル${gl_kjlan}34. ${gl_bai}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${gl_bai}友達のミニマリストのサークル${gl_kjlan}36. ${gl_bai}Lobechataiチャット集約Webサイト" - echo -e "${gl_kjlan}37. ${gl_bai}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${gl_bai}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${gl_bai}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${gl_bai}WebSH WebバージョンSSH接続ツール" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" + echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" + echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}マウス管理パネル${gl_kjlan}42. ${gl_bai}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${gl_bai}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${gl_bai}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${gl_bai}Docker加速ステーション${gl_kjlan}46. ${gl_bai}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${gl_bai}プロメテウス監視${gl_kjlan}48. ${gl_bai}プロメテウス(ホスト監視)" - echo -e "${gl_kjlan}49. ${gl_bai}プロメテウス(コンテナ監視)${gl_kjlan}50. ${gl_bai}補充監視ツール" + echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${gl_bai}PVEチキンパネル${gl_kjlan}52. ${gl_bai}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${gl_bai}llama3チャットAIモデル${gl_kjlan}54. ${gl_bai}AMHホストWebサイトビルディングマネジメントパネル" - echo -e "${gl_kjlan}55. ${gl_bai}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${gl_bai}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${gl_bai}deepseekチャットaiビッグモデル${gl_kjlan}58. ${gl_bai}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${gl_bai}Newapi Big Model Asset Management${gl_kjlan}60. ${gl_bai}Jumpserverオープンソースバス剤マシン" + echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" + echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" + echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" + echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}オンライン翻訳サーバー${gl_kjlan}62. ${gl_bai}Ragflow Big Model Knowledge Base" - echo -e "${gl_kjlan}63. ${gl_bai}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${gl_bai}IT-Toolsツールボックス" - echo -e "${gl_kjlan}65. ${gl_bai}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${gl_bai}YT-DLPビデオダウンロードツール" - echo -e "${gl_kjlan}67. ${gl_bai}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${gl_bai}AllinsSL証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${gl_bai}SFTPGOファイル転送ツール${gl_kjlan}70. ${gl_bai}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" + echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" + echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${gl_bai}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${gl_bai}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${gl_bai}libretvプライベート映画とテレビ${gl_kjlan}74. ${gl_bai}MOONTVプライベート映画" - echo -e "${gl_kjlan}75. ${gl_bai}メロディーミュージックエルフ${gl_kjlan}76. ${gl_bai}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${gl_bai}サンダーオフラインダウンロードツール${gl_kjlan}78. ${gl_bai}Pandawikiインテリジェントドキュメント管理システム" - echo -e "${gl_kjlan}79. ${gl_bai}Beszelサーバーの監視" + echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8652,7 +8712,7 @@ linux_panel() { echo -e "Nezhaの監視$check_docker $update_status" echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8742,7 +8802,7 @@ linux_panel() { fi echo "" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "アクセスアドレス:" echo "https://$yuming" @@ -8788,6 +8848,9 @@ linux_panel() { --restart=always \ -d analogic/poste.io + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "Poste.ioがインストールされています" echo "------------------------" @@ -8809,6 +8872,10 @@ linux_panel() { -h "$yuming" \ --restart=always \ -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "Poste.ioがインストールされています" echo "------------------------" @@ -8821,6 +8888,8 @@ linux_panel() { docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; @@ -9119,7 +9188,7 @@ linux_panel() { echo -e "サンダープールサービス$check_docker" echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9136,6 +9205,8 @@ linux_panel() { install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip @@ -9147,6 +9218,8 @@ linux_panel() { bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "サンダープールWAFパネルが更新されました" check_docker_app_ip @@ -9157,6 +9230,8 @@ linux_panel() { 4) cd /data/safeline docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; @@ -10623,6 +10698,127 @@ linux_panel() { ;; + 80) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden-linkwarden-1" + local docker_port="8080" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + + # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + + # ランダムキーとパスワードを生成します + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) + + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + + # 管理者アカウント情報を追加します + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + # コンテナを起動します + docker compose up -d + + clear + echo "インストール" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 元の変数を保持します + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + + 81) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" + + docker_app_install() { + + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d + + } + + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + + 0) kejilion ;; @@ -10844,9 +11040,9 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}opensshの高リスクの脆弱性(xiuyuan)を修正" + echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" @@ -10854,6 +11050,7 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" + echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" @@ -11219,7 +11416,7 @@ EOF ;; 4) read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudoアクセス許可を削除します + # sudoersファイルからユーザーのsudo許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; @@ -11853,6 +12050,12 @@ EOF ;; + 39) + clear + send_stats "コマンドラインの履歴" + bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + ;; + 41) clear send_stats "メッセージボード" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 528d0abca..b30d886f0 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.3" +sh_v="4.0.5" gl_hui='\e[37m' @@ -1185,7 +1185,7 @@ iptables_panel() { 5) # IP 화이트리스트 - read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip + read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) @@ -1556,7 +1556,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -2371,18 +2371,25 @@ web_optimization() { +check_docker_app() { + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + check_docker="${gl_lv}已安装${gl_bai}" + else + check_docker="${gl_hui}未安装${gl_bai}" + fi +} -check_docker_app() { +# check_docker_app() { -if docker inspect "$docker_name" &>/dev/null; then - check_docker="${gl_lv}已安装${gl_bai}" -else - check_docker="${gl_hui}未安装${gl_bai}" -fi +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# check_docker = "$ {gl_lv} $ {gl_bai} 설치" +# else +# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" +# fi -} +# } check_docker_app_ip() { @@ -2720,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2751,6 +2758,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "$docker_name설치" @@ -2764,6 +2773,9 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "$docker_name설치" check_docker_app_ip @@ -2777,6 +2789,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" send_stats "제거하십시오$docker_name" ;; @@ -2817,7 +2831,6 @@ done - docker_app_plus() { send_stats "$app_name" while true; do @@ -2827,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2857,13 +2870,20 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 2) docker_app_update + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + ;; 5) echo "${docker_name}도메인 액세스 설정" @@ -3538,15 +3558,21 @@ while true; do install wget iptables_open panel_app_install + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}설치하다" ;; 2) panel_app_manage + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}제어" ;; 3) panel_app_uninstall + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt send_stats "${panelname}제거하십시오" ;; *) @@ -3875,6 +3901,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP 서버가 설치되었습니다" ;; 2) @@ -3883,6 +3911,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP 서버가 업데이트되었습니다" ;; 3) @@ -3892,7 +3922,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; 5) @@ -3916,7 +3947,7 @@ frps_panel() { 8) send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3966,6 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP 클라이언트가 설치되었습니다" ;; 2) @@ -3974,6 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP 클라이언트가 업데이트되었습니다" ;; @@ -3983,6 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; @@ -4052,18 +4089,24 @@ yt_menu_pro() { install ffmpeg sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 2) send_stats "yt-dlp 업데이트 ..." echo "yt-dlp 업데이트 ..." sudo yt-dlp -U + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 3) send_stats "yt-dlp 제거 ..." echo "yt-dlp 제거 ..." sudo rm -f /usr/local/bin/yt-dlp + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 5) @@ -8411,58 +8454,75 @@ linux_ldnmp() { linux_panel() { + + + + while true; do clear - # Send_stats "앱 시장" echo -e "응용 프로그램 시장" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Baota 패널의 공식 버전${gl_kjlan}2. ${gl_bai}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${gl_bai}1 파넬 신세대 관리 패널${gl_kjlan}4. ${gl_bai}nginxproxymanager 시각적 패널" - echo -e "${gl_kjlan}5. ${gl_bai}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${gl_bai}우분투 원격 데스크탑 웹 에디션" - echo -e "${gl_kjlan}7. ${gl_bai}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${gl_bai}QB 오프라인 BT 자기 다운로드 패널" - echo -e "${gl_kjlan}9. ${gl_bai}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${gl_bai}Rocketchat 멀티 플레이어 온라인 채팅 시스템" + + local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") + + # 루프로 색상을 설정하십시오 + for i in {1..100}; do + if echo "$app_numbers" | grep -q "^$i$"; then + declare "color$i=${gl_lv}" + else + declare "color$i=${gl_bai}" + fi + done + + echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" + echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" + echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" + echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" + echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" + echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" + echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${gl_bai}Qinglong 패널 시간 작업 관리 플랫폼" - echo -e "${gl_kjlan}13. ${gl_bai}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${gl_bai}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${gl_bai}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${gl_bai}스피드 테스트 속도 테스트 패널" - echo -e "${gl_kjlan}17. ${gl_bai}Adguardhome Adware${gl_kjlan}18. ${gl_bai}Office Office Online Office Office" - echo -e "${gl_kjlan}19. ${gl_bai}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${gl_bai}Portainer 컨테이너 관리 패널" + echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" + echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}VSCODE 웹 버전${gl_kjlan}22. ${gl_bai}Uptimekuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${gl_bai}메모 웹 페이지 메모${gl_kjlan}24. ${gl_bai}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${gl_bai}NextCloud 네트워크 디스크${gl_kjlan}26. ${gl_bai}QD-Today 타이밍 작업 관리 프레임 워크" - echo -e "${gl_kjlan}27. ${gl_bai}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${gl_bai}Librespeed 속도 테스트 도구" - echo -e "${gl_kjlan}29. ${gl_bai}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}Photoprism 개인 앨범 시스템" + echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" + echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" + echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" + echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${gl_bai}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}썬 패널 탐색 패널${gl_kjlan}34. ${gl_bai}Pingvin-Share 파일 공유 플랫폼" - echo -e "${gl_kjlan}35. ${gl_bai}미니멀리스트 친구들${gl_kjlan}36. ${gl_bai}LobeChatai 채팅 집계 웹 사이트" - echo -e "${gl_kjlan}37. ${gl_bai}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${gl_bai}Xiaoya Alist 가족 버킷" - echo -e "${gl_kjlan}39. ${gl_bai}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${gl_bai}Websh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" + echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}마우스 관리 패널${gl_kjlan}42. ${gl_bai}Nexte 원격 연결 도구" - echo -e "${gl_kjlan}43. ${gl_bai}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${gl_bai}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${gl_bai}도커 가속 스테이션${gl_kjlan}46. ${gl_bai}Github Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${gl_bai}프로 메테우스 모니터링${gl_kjlan}48. ${gl_bai}프로 메테우스 (호스트 모니터링)" - echo -e "${gl_kjlan}49. ${gl_bai}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${gl_bai}보충 모니터링 도구" + echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" + echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${gl_bai}PVE 치킨 패널${gl_kjlan}52. ${gl_bai}DPANEL 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${gl_bai}llama3 채팅 AI 모델${gl_kjlan}54. ${gl_bai}AMH 호스트 웹 사이트 빌딩 관리 패널" - echo -e "${gl_kjlan}55. ${gl_bai}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${gl_bai}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${gl_bai}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${gl_bai}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${gl_bai}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${gl_bai}점프 서버 오픈 소스 요새 기계" + echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" + echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" + echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" + echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}온라인 번역 서버${gl_kjlan}62. ${gl_bai}래그 플로 큰 모델 지식 기반" - echo -e "${gl_kjlan}63. ${gl_bai}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${gl_bai}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${gl_bai}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${gl_bai}YT-DLP 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${gl_bai}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${gl_bai}AllInsSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${gl_bai}sftpgo 파일 전송 도구${gl_kjlan}70. ${gl_bai}Astrbot 채팅 로봇 프레임 워크" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" + echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" + echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${gl_bai}Navidrome 개인 음악 서버${gl_kjlan}72. ${gl_bai}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${gl_bai}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${gl_bai}Moontv 개인 영화" - echo -e "${gl_kjlan}75. ${gl_bai}멜로디 음악 엘프${gl_kjlan}76. ${gl_bai}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${gl_bai}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${gl_bai}Pandawiki 지능형 문서 관리 시스템" - echo -e "${gl_kjlan}79. ${gl_bai}Beszel 서버 모니터링" + echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8652,7 +8712,7 @@ linux_panel() { echo -e "Nezha 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8742,7 +8802,7 @@ linux_panel() { fi echo "" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "액세스 주소 :" echo "https://$yuming" @@ -8788,6 +8848,9 @@ linux_panel() { --restart=always \ -d analogic/poste.io + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "Poste.io가 설치되었습니다" echo "------------------------" @@ -8809,6 +8872,10 @@ linux_panel() { -h "$yuming" \ --restart=always \ -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "Poste.io가 설치되었습니다" echo "------------------------" @@ -8821,6 +8888,8 @@ linux_panel() { docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; @@ -9119,7 +9188,7 @@ linux_panel() { echo -e "썬더 풀 서비스$check_docker" echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9136,6 +9205,8 @@ linux_panel() { install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "Thunder Pool WAF 패널이 설치되었습니다" check_docker_app_ip @@ -9147,6 +9218,8 @@ linux_panel() { bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip @@ -9157,6 +9230,8 @@ linux_panel() { 4) cd /data/safeline docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." echo "docker compose down && docker compose down --rmi all" ;; @@ -10623,6 +10698,127 @@ linux_panel() { ;; + 80) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden-linkwarden-1" + local docker_port="8080" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + + # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + + # 임의의 키와 암호를 생성합니다 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) + + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + + # 관리자 계정 정보를 추가하십시오 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + # 컨테이너를 시작하십시오 + docker compose up -d + + clear + echo "설치" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 원래 변수를 유지하십시오 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + + 81) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" + + docker_app_install() { + + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d + + } + + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + + 0) kejilion ;; @@ -10844,9 +11040,9 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점 수정 (Xiuyuan)" + echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -10854,6 +11050,7 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" @@ -10874,7 +11071,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" + echo "바로 가기 키가 설정되었습니다" send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings @@ -11853,6 +12050,12 @@ EOF ;; + 39) + clear + send_stats "명령 줄 기록" + bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + ;; + 41) clear send_stats "게시판" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 6d28b8d24..f112e919e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.3" +sh_v="4.0.5" gl_hui='\e[37m' @@ -2371,18 +2371,25 @@ web_optimization() { +check_docker_app() { + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + check_docker="${gl_lv}已安装${gl_bai}" + else + check_docker="${gl_hui}未安装${gl_bai}" + fi +} -check_docker_app() { +# check_docker_app() { -if docker inspect "$docker_name" &>/dev/null; then - check_docker="${gl_lv}已安装${gl_bai}" -else - check_docker="${gl_hui}未安装${gl_bai}" -fi +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# check_docker="${gl_lv}已安裝${gl_bai}" +# else +# check_docker="${gl_hui}未安裝${gl_bai}" +# fi -} +# } check_docker_app_ip() { @@ -2720,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2751,6 +2758,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "$docker_name已經安裝完成" @@ -2764,6 +2773,9 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "$docker_name已經安裝完成" check_docker_app_ip @@ -2777,6 +2789,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "應用已卸載" send_stats "解除安裝$docker_name" ;; @@ -2817,7 +2831,6 @@ done - docker_app_plus() { send_stats "$app_name" while true; do @@ -2827,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2857,13 +2870,20 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 2) docker_app_update + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + ;; 5) echo "${docker_name}域名訪問設置" @@ -3538,15 +3558,21 @@ while true; do install wget iptables_open panel_app_install + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}安裝" ;; 2) panel_app_manage + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt send_stats "${panelname}控制" ;; 3) panel_app_uninstall + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt send_stats "${panelname}解除安裝" ;; *) @@ -3875,6 +3901,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP服務端已經安裝完成" ;; 2) @@ -3883,6 +3911,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP服務端已經更新完成" ;; 3) @@ -3892,7 +3922,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; 5) @@ -3966,6 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP客戶端已經安裝完成" ;; 2) @@ -3974,6 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "FRP客戶端已經更新完成" ;; @@ -3983,6 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; @@ -4052,18 +4089,24 @@ yt_menu_pro() { install ffmpeg sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "安裝完成。按任意鍵繼續..." read ;; 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." sudo yt-dlp -U + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新完成。按任意鍵繼續..." read ;; 3) send_stats "正在卸載 yt-dlp..." echo "正在卸載 yt-dlp..." sudo rm -f /usr/local/bin/yt-dlp + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "卸載完成。按任意鍵繼續..." read ;; 5) @@ -8411,58 +8454,75 @@ linux_ldnmp() { linux_panel() { + + + + while true; do clear - # send_stats "應用市場" echo -e "應用市場" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}寶塔面板官方版${gl_kjlan}2. ${gl_bai}aaPanel寶塔國際版" - echo -e "${gl_kjlan}3. ${gl_bai}1Panel新一代管理面板${gl_kjlan}4. ${gl_bai}NginxProxyManager可視化面板" - echo -e "${gl_kjlan}5. ${gl_bai}OpenList多存儲文件列表程序${gl_kjlan}6. ${gl_bai}Ubuntu遠程桌面網頁版" - echo -e "${gl_kjlan}7. ${gl_bai}哪吒探針VPS監控面板${gl_kjlan}8. ${gl_bai}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${gl_bai}Poste.io郵件服務器程序${gl_kjlan}10. ${gl_bai}RocketChat多人在線聊天系統" + + local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") + + # 用循環設置顏色 + for i in {1..100}; do + if echo "$app_numbers" | grep -q "^$i$"; then + declare "color$i=${gl_lv}" + else + declare "color$i=${gl_bai}" + fi + done + + echo -e "${gl_kjlan}1. ${color1}寶塔面板官方版${gl_kjlan}2. ${color2}aaPanel寶塔國際版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager可視化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存儲文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠程桌面網頁版" + echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件服務器程序${gl_kjlan}10. ${color10}RocketChat多人在線聊天系統" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}11. ${color11}禪道項目管理軟件${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟件${gl_kjlan}18. ${color18}onlyoffice在線辦公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}禪道項目管理軟件${gl_kjlan}12. ${gl_bai}青龍面板定時任務管理平台" - echo -e "${gl_kjlan}13. ${gl_bai}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${gl_bai}簡單圖床圖片管理程序" - echo -e "${gl_kjlan}15. ${gl_bai}emby多媒體管理系統${gl_kjlan}16. ${gl_bai}Speedtest測速面板" - echo -e "${gl_kjlan}17. ${gl_bai}AdGuardHome去廣告軟件${gl_kjlan}18. ${gl_bai}onlyoffice在線辦公OFFICE" - echo -e "${gl_kjlan}19. ${gl_bai}雷池WAF防火牆面板${gl_kjlan}20. ${gl_bai}portainer容器管理面板" + echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" + echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud網盤${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆棧管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相冊系統" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}VScode網頁版${gl_kjlan}22. ${gl_bai}UptimeKuma監控工具" - echo -e "${gl_kjlan}23. ${gl_bai}Memos網頁備忘錄${gl_kjlan}24. ${gl_bai}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${gl_bai}Nextcloud網盤${gl_kjlan}26. ${gl_bai}QD-Today定時任務管理框架" - echo -e "${gl_kjlan}27. ${gl_bai}Dockge容器堆棧管理面板${gl_kjlan}28. ${gl_bai}LibreSpeed測速工具" - echo -e "${gl_kjlan}29. ${gl_bai}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}PhotoPrism私有相冊系統" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播錄製工具${gl_kjlan}40. ${color40}webssh網頁版SSH連接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}StirlingPDF工具大全${gl_kjlan}32. ${gl_bai}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Sun-Panel導航面板${gl_kjlan}34. ${gl_bai}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${gl_bai}極簡朋友圈${gl_kjlan}36. ${gl_bai}LobeChatAI聊天聚合網站" - echo -e "${gl_kjlan}37. ${gl_bai}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${gl_bai}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${gl_bai}Bililive直播錄製工具${gl_kjlan}40. ${gl_bai}webssh網頁版SSH連接工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠程連接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" + echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}耗子管理面板${gl_kjlan}42. ${gl_bai}Nexterm遠程連接工具" - echo -e "${gl_kjlan}43. ${gl_bai}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${gl_bai}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${gl_bai}Docker加速站${gl_kjlan}46. ${gl_bai}GitHub加速站${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${gl_bai}普羅米修斯監控${gl_kjlan}48. ${gl_bai}普羅米修斯(主機監控)" - echo -e "${gl_kjlan}49. ${gl_bai}普羅米修斯(容器監控)${gl_kjlan}50. ${gl_bai}補貨監控工具" + echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${gl_bai}PVE開小雞面板${gl_kjlan}52. ${gl_bai}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${gl_bai}llama3聊天AI大模型${gl_kjlan}54. ${gl_bai}AMH主機建站管理面板" - echo -e "${gl_kjlan}55. ${gl_bai}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${gl_bai}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${gl_bai}Deepseek聊天AI大模型${gl_kjlan}58. ${gl_bai}Dify大模型知識庫${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${gl_bai}NewAPI大模型資產管理${gl_kjlan}60. ${gl_bai}JumpServer開源堡壘機" + echo -e "${gl_kjlan}61. ${color61}在線翻譯服務器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp視頻下載工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL證書管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}在線翻譯服務器${gl_kjlan}62. ${gl_bai}RAGFlow大模型知識庫" - echo -e "${gl_kjlan}63. ${gl_bai}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${gl_bai}it-tools工具箱" - echo -e "${gl_kjlan}65. ${gl_bai}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${gl_bai}yt-dlp視頻下載工具" - echo -e "${gl_kjlan}67. ${gl_bai}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${gl_bai}AllinSSL證書管理平台" - echo -e "${gl_kjlan}69. ${gl_bai}SFTPGo文件傳輸工具${gl_kjlan}70. ${gl_bai}AstrBot聊天機器人框架" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂服務器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" + echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}在線DOS老遊戲" + echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" + echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${gl_bai}Navidrome私有音樂服務器${gl_kjlan}72. ${gl_bai}bitwarden密碼管理器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${gl_bai}LibreTV私有影視${gl_kjlan}74. ${gl_bai}MoonTV私有影視" - echo -e "${gl_kjlan}75. ${gl_bai}Melody音樂精靈${gl_kjlan}76. ${gl_bai}在線DOS老遊戲" - echo -e "${gl_kjlan}77. ${gl_bai}迅雷離線下載工具${gl_kjlan}78. ${gl_bai}PandaWiki智能文檔管理系統" - echo -e "${gl_kjlan}79. ${gl_bai}Beszel服務器監控" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8652,7 +8712,7 @@ linux_panel() { echo -e "哪吒監控$check_docker $update_status" echo "開源、輕量、易用的服務器監控與運維工具" echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8742,7 +8802,7 @@ linux_panel() { fi echo "" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "訪問地址:" echo "https://$yuming" @@ -8788,6 +8848,9 @@ linux_panel() { --restart=always \ -d analogic/poste.io + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "poste.io已經安裝完成" echo "------------------------" @@ -8809,6 +8872,10 @@ linux_panel() { -h "$yuming" \ --restart=always \ -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear echo "poste.io已經安裝完成" echo "------------------------" @@ -8821,6 +8888,8 @@ linux_panel() { docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; @@ -9119,7 +9188,7 @@ linux_panel() { echo -e "雷池服務$check_docker" echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker inspect "$docker_name" &>/dev/null; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9136,6 +9205,8 @@ linux_panel() { install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "雷池WAF面板已經安裝完成" check_docker_app_ip @@ -9147,6 +9218,8 @@ linux_panel() { bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear echo "雷池WAF面板已經更新完成" check_docker_app_ip @@ -9157,6 +9230,8 @@ linux_panel() { 4) cd /data/safeline docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" echo "docker compose down && docker compose down --rmi all" ;; @@ -10623,6 +10698,127 @@ linux_panel() { ;; + 80) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden-linkwarden-1" + local docker_port="8080" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + + # 下載官方 docker-compose 和 env 文件 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + + # 生成隨機密鑰與密碼 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) + + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + + # 追加管理員賬號信息 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + # 啟動容器 + docker compose up -d + + clear + echo "已經安裝完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 保留原本的變量 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + 81) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" + + docker_app_install() { + + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d + + } + + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + 0) kejilion ;; @@ -10846,7 +11042,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}ROOT私鑰登錄模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞(岫源)" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞" echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux內核升級${gl_kjlan}28. ${gl_bai}Linux系統內核參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" @@ -10854,6 +11050,7 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}設置系統回收站${gl_kjlan}34. ${gl_bai}系統備份與恢復" echo -e "${gl_kjlan}35. ${gl_bai}ssh遠程連接工具${gl_kjlan}36. ${gl_bai}硬盤分區管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令行歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重啟服務器${gl_kjlan}100. ${gl_bai}隱私與安全" @@ -11853,6 +12050,12 @@ EOF ;; + 39) + clear + send_stats "命令行歷史記錄" + bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + ;; + 41) clear send_stats "留言板" From 69cdaca8e171595b6d7b1a67e16b973df5ccff7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:51:15 +0800 Subject: [PATCH 0005/1285] Update kejilion.sh --- cn/kejilion.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1c2b0d9c1..6515bc7cc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -4573,8 +4573,8 @@ dd_xitong() { echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}感谢MollyLau大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4598,34 @@ dd_xitong() { echo "------------------------" read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in + + 1) - send_stats "重装debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "重装debian 13" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "重装debian 11" + send_stats "重装debian 12" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 10" + send_stats "重装debian 11" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 9" + send_stats "重装debian 10" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; From 9e9fb4c1eb276c4ec59b757ded83a909f0714681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:51:43 +0800 Subject: [PATCH 0006/1285] Update kejilion.sh --- kejilion.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 78bf8ceca..d5e7b8f4e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -4573,8 +4573,8 @@ dd_xitong() { echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}感谢MollyLau大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4598,34 @@ dd_xitong() { echo "------------------------" read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in + + 1) - send_stats "重装debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "重装debian 13" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "重装debian 11" + send_stats "重装debian 12" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 10" + send_stats "重装debian 11" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 9" + send_stats "重装debian 10" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; From 8155060c948134f49b97c916be8a922b5cf4673d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:54:58 +0800 Subject: [PATCH 0007/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 634a8da6e..698418fe6 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1249,5 +1249,9 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增Linkwarden书签管理器工具的安装及使用。 应用市场新增JitsiMeet视频会议具的安装及使用。 ------------------------ +2025-08-10 v4.0.6 +系统工具重装系统新增Debian13的重装选项。Debian13 性能 安全 稳定全面提升。 +------------------------ + From 6fd16381c62c77199ca9d0a03bb7cf815d2f8308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:09:38 +0800 Subject: [PATCH 0008/1285] Update kejilion.sh --- kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d5e7b8f4e..2fdbb51c0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2372,7 +2372,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2727,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -4571,7 +4571,7 @@ dd_xitong() { echo "重装系统" echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢MollyLau大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -8715,7 +8715,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8805,7 +8805,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9191,7 +9191,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" From 260a67ffb3cc8f0d050d53146298cc69f63e9ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:10:22 +0800 Subject: [PATCH 0009/1285] Update kejilion.sh --- cn/kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6515bc7cc..41c485c89 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2372,7 +2372,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2727,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -4571,7 +4571,7 @@ dd_xitong() { echo "重装系统" echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢MollyLau大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -8715,7 +8715,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8805,7 +8805,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9191,7 +9191,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" From d78877ad9aec2b7003b9c431d30f176c2bb89b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:18:01 +0800 Subject: [PATCH 0010/1285] Update kejilion.sh --- cn/kejilion.sh | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 41c485c89..7ac5d87dc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="CN" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -8715,7 +8707,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8805,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9191,7 +9183,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" From 62577318b8e3ef9316a5de86e8adb5de702c44dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:18:36 +0800 Subject: [PATCH 0011/1285] Update kejilion.sh --- kejilion.sh | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2fdbb51c0..3da2dc4b5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -8715,7 +8707,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8805,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9191,7 +9183,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" From 2f4c02f362ff0fef2a12562828a0b21b3b7f03db Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 11 Aug 2025 06:16:49 +0000 Subject: [PATCH 0012/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-11=2006:16:49?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 69 +++++++++++++++++++++----------------------- jp/kejilion.sh | 77 +++++++++++++++++++++++--------------------------- kr/kejilion.sh | 73 ++++++++++++++++++++++------------------------- tw/kejilion.sh | 53 ++++++++++++++++------------------ 4 files changed, 126 insertions(+), 146 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 8522d0a2c..e9c857476 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2119,7 +2119,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}${gl_bai} installed" # else # check_docker="${gl_hui}${gl_bai} is not installed" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -4571,10 +4563,10 @@ dd_xitong() { echo "Reinstall the system" echo "--------------------------------" echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." - echo -e "${gl_hui}Thanks to MollyLau and bin456789 for the script support!${gl_bai} " + echo -e "${gl_hui}Thanks to the script support of leitbogioro and bin456789!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4590,34 @@ dd_xitong() { echo "------------------------" read -e -p "Please select the system to reinstall:" sys_choice case "$sys_choice" in + + 1) - send_stats "Reinstall debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "Reinstall debian 13" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "Reinstall debian 11" + send_stats "Reinstall debian 12" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Reinstall debian 10" + send_stats "Reinstall debian 11" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Reinstall debian 9" + send_stats "Reinstall debian 10" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; @@ -4986,7 +4981,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Operating system detected:$os_name $os_version" + echo "Detected operating systems:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -5812,7 +5807,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Example to create a new connection:" + echo "Create a new connection example:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -5953,7 +5948,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can be connected to other Linux systems via SSH" + echo "Can connect to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -7918,7 +7913,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8508,7 +8503,7 @@ linux_panel() { echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" @@ -8712,7 +8707,7 @@ linux_panel() { echo -e "Nezha Monitoring$check_docker $update_status" echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8802,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "Access address:" echo "https://$yuming" @@ -9188,7 +9183,7 @@ linux_panel() { echo -e "Thunder Pool Service$check_docker" echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -11040,7 +11035,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" @@ -12173,7 +12168,7 @@ EOF echo "Privacy and Security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 023c6369d..2777ea9a6 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2119,7 +2119,7 @@ web_security() { 22) send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" echo "CFパラメーターを取得します:" echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker = "$ {gl_lv} $ {gl_bai}インストール" # else # check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3393,7 +3385,7 @@ ldnmp_web_status() { echo "------------------------" echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" - echo "5.アクセスログを表示6。エラーログを表示します" + echo "5. 查看访问日志 6. 查看错误日志" echo "7.グローバル構成の編集8。サイト構成の編集" echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" echo "------------------------" @@ -4571,10 +4563,10 @@ dd_xitong() { echo "システムを再インストールします" echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - echo -e "${gl_hui}スクリプトサポートについては、MollylauとBin456789に感謝します!${gl_bai} " + echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4590,34 @@ dd_xitong() { echo "------------------------" read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in + + 1) - send_stats "Debian 12を再インストールします" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "Debian 13を再インストールします" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "Debian 11を再インストールします" + send_stats "Debian 12を再インストールします" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Debian 10を再インストールします" + send_stats "Debian 11を再インストールします" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Debian 9を再インストールします" + send_stats "Debian 10を再インストールします" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; @@ -5370,7 +5365,7 @@ Kernel_optimize() { echo "--------------------" echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" + echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを同時に改善します。" echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" @@ -5812,7 +5807,7 @@ list_connections() { # 新しい接続を追加します add_connection() { send_stats "新しい接続を追加します" - echo "新しい接続を作成する例:" + echo "新しい接続例を作成します:" echo "- 接続名:my_server" echo "- IPアドレス:192.168.1.100" echo "- ユーザー名:root" @@ -7004,7 +6999,7 @@ linux_docker() { echo "ボリューム操作" echo "------------------------" echo "1.新しいボリュームを作成します" - echo "2。指定されたボリュームを削除します" + echo "2. 删除指定卷" echo "3.すべてのボリュームを削除します" echo "------------------------" echo "0。前のメニューに戻ります" @@ -7918,7 +7913,7 @@ linux_ldnmp() { ;; 2) echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8712,7 +8707,7 @@ linux_panel() { echo -e "Nezhaの監視$check_docker $update_status" echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8802,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "アクセスアドレス:" echo "https://$yuming" @@ -9188,7 +9183,7 @@ linux_panel() { echo -e "サンダープールサービス$check_docker" echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -11040,7 +11035,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" @@ -11416,7 +11411,7 @@ EOF ;; 4) read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudo許可を削除します + # sudoersファイルからユーザーのsudoアクセス許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; @@ -12076,10 +12071,10 @@ EOF echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo -e "5.すべてのポートを開きます" echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" - echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice @@ -12173,7 +12168,7 @@ EOF echo "プライバシーとセキュリティ" echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" echo "--------------------" @@ -12520,7 +12515,7 @@ while true; do echo echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" - echo -e "${gl_kjlan}1. ${gl_bai}サーバーを追加します${gl_kjlan}2. ${gl_bai}サーバーを削除します${gl_kjlan}3. ${gl_bai}サーバーを編集します" + echo -e "${gl_kjlan}1. ${gl_bai}サーバーを追加します${gl_kjlan}2. ${gl_bai}删除服务器 ${gl_kjlan}3. ${gl_bai}编辑服务器" echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元します" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}バッチでタスクを実行します${gl_bai}" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b30d886f0..ab2dde8ff 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야하는지 확인하십시오 +# 가상 메모리를 생성 해야하는지 확인하십시오 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -2119,7 +2119,7 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker = "$ {gl_lv} $ {gl_bai} 설치" # else # check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -4571,10 +4563,10 @@ dd_xitong() { echo "시스템을 다시 설치하십시오" echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - echo -e "${gl_hui}스크립트 지원을 위해 Mollylau 및 Bin456789에게 감사드립니다!${gl_bai} " + echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4590,34 @@ dd_xitong() { echo "------------------------" read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice case "$sys_choice" in + + 1) - send_stats "데비안 12를 다시 설치하십시오" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "데비안 13을 다시 설치하십시오" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "데비안 11을 다시 설치하십시오" + send_stats "데비안 12를 다시 설치하십시오" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "데비안 10을 다시 설치하십시오" + send_stats "데비안 11을 다시 설치하십시오" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "데비안 9를 다시 설치하십시오" + send_stats "데비안 10을 다시 설치하십시오" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; @@ -4986,7 +4981,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "운영 체제 감지 :$os_name $os_version" + echo "감지 된 운영 체제 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -5812,7 +5807,7 @@ list_connections() { # 새 연결을 추가하십시오 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결을 만드는 예 :" + echo "새 연결 예제 :" echo "- 연결 이름 : my_server" echo "-IP 주소 : 192.168.1.100" echo "- 사용자 이름 : 루트" @@ -6555,7 +6550,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침입자 게임" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" @@ -6754,7 +6749,7 @@ linux_tools() { 32) clear - send_stats "모든 설치 (게임 및 화면 보호기 제외)" + send_stats "모든 설치 (게임 및 스크린 세이버 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; @@ -7918,7 +7913,7 @@ linux_ldnmp() { ;; 2) echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8712,7 +8707,7 @@ linux_panel() { echo -e "Nezha 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8802,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "액세스 주소 :" echo "https://$yuming" @@ -9188,7 +9183,7 @@ linux_panel() { echo -e "썬더 풀 서비스$check_docker" echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -11040,7 +11035,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" @@ -12394,7 +12389,7 @@ linux_file() { # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사하십시오" + send_stats "파일 또는 디렉토리를 복사합니다" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index f112e919e..82089bc1d 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.5" +sh_v="4.0.6" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2363,16 +2363,8 @@ web_optimization() { } - - - - - - - - check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2383,7 +2375,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安裝${gl_bai}" # else # check_docker="${gl_hui}未安裝${gl_bai}" @@ -2727,7 +2719,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2840,7 +2832,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -4571,10 +4563,10 @@ dd_xitong() { echo "重裝系統" echo "--------------------------------" echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" - echo -e "${gl_hui}感謝MollyLau大佬和bin456789大佬的腳本支持!${gl_bai} " + echo -e "${gl_hui}感謝leitbogioro大佬和bin456789大佬的腳本支持!${gl_bai} " echo "------------------------" - echo "1. Debian 12 2. Debian 11" - echo "3. Debian 10 4. Debian 9" + echo "1. Debian 13 2. Debian 12" + echo "3. Debian 11 4. Debian 10" echo "------------------------" echo "11. Ubuntu 24.04 12. Ubuntu 22.04" echo "13. Ubuntu 20.04 14. Ubuntu 18.04" @@ -4598,31 +4590,34 @@ dd_xitong() { echo "------------------------" read -e -p "請選擇要重裝的系統:" sys_choice case "$sys_choice" in + + 1) - send_stats "重裝debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "重裝debian 13" + dd_xitong_3 + bash reinstall.sh debian 13 reboot exit ;; + 2) - send_stats "重裝debian 11" + send_stats "重裝debian 12" dd_xitong_1 - bash InstallNET.sh -debian 11 + bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重裝debian 10" + send_stats "重裝debian 11" dd_xitong_1 - bash InstallNET.sh -debian 10 + bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重裝debian 9" + send_stats "重裝debian 10" dd_xitong_1 - bash InstallNET.sh -debian 9 + bash InstallNET.sh -debian 10 reboot exit ;; @@ -8712,7 +8707,7 @@ linux_panel() { echo -e "哪吒監控$check_docker $update_status" echo "開源、輕量、易用的服務器監控與運維工具" echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8802,7 +8797,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "訪問地址:" echo "https://$yuming" @@ -9188,7 +9183,7 @@ linux_panel() { echo -e "雷池服務$check_docker" echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" From 8de0d2b1e33430eec10387c4aae871c24f4e1518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 14:56:21 +0800 Subject: [PATCH 0013/1285] Update kejilion.sh --- cn/kejilion.sh | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7ac5d87dc..2d8da0e91 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="CN" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# echo "数据库名: $dbname" -# echo "用户名: $dbuse" -# echo "密码: $dbusepasswd" -# echo "数据库地址: mysql" -# echo "表前缀: wp_" } @@ -3293,7 +3294,6 @@ ldnmp_Proxy_backend() { add_yuming fi - # 获取用户输入的多个IP:端口(用空格分隔) if [ -z "$reverseproxy_port" ]; then read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # 动态生成 upstream 配置 upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # 替换模板中的占位符 sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,11 +3341,11 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear send_stats "LDNMP站点管理" @@ -3355,8 +3353,7 @@ ldnmp_web_status() { echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output} 证书到期时间" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,7 +3366,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} $output $db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -8707,7 +8704,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8797,7 +8794,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9183,7 +9180,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" From edec4817dfe0a3c360ca4c7b9ad4bb456f2036fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 14:56:56 +0800 Subject: [PATCH 0014/1285] Update kejilion.sh --- kejilion.sh | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3da2dc4b5..39cd0eba5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# echo "数据库名: $dbname" -# echo "用户名: $dbuse" -# echo "密码: $dbusepasswd" -# echo "数据库地址: mysql" -# echo "表前缀: wp_" } @@ -3293,7 +3294,6 @@ ldnmp_Proxy_backend() { add_yuming fi - # 获取用户输入的多个IP:端口(用空格分隔) if [ -z "$reverseproxy_port" ]; then read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # 动态生成 upstream 配置 upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # 替换模板中的占位符 sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,11 +3341,11 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear send_stats "LDNMP站点管理" @@ -3355,8 +3353,7 @@ ldnmp_web_status() { echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output} 证书到期时间" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,7 +3366,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} $output $db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -8707,7 +8704,7 @@ linux_panel() { echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8797,7 +8794,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9183,7 +9180,7 @@ linux_panel() { echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" From 01d7af63c3f2e052840593afec4e8f3beafbc104 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 11 Aug 2025 07:37:54 +0000 Subject: [PATCH 0015/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-11=2007:37:54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 71 +- jp/kejilion.sh | 4309 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 73 +- tw/kejilion.sh | 49 +- 4 files changed, 2245 insertions(+), 2257 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index e9c857476..839b9a966 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -1185,7 +1185,7 @@ iptables_panel() { 5) # IP whitelist - read -e -p "Please enter the IP or IP segment to be released:" o_ip + read -e -p "Please enter the IP or IP segment to release:" o_ip allow_ip $o_ip ;; 6) @@ -1556,7 +1556,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -1738,7 +1738,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to mode parameters + # Decide to turn on or off WAF according to the mode parameter if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2119,7 +2119,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}${gl_bai} installed" # else # check_docker="${gl_hui}${gl_bai} is not installed" @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# echo "Database name: $dbname" -# echo "Username: $dbuse" -# echo "Password: $dbusepasswd" -# echo "Database address: mysql" -# echo "Table prefix: wp_" } @@ -3293,7 +3294,6 @@ ldnmp_Proxy_backend() { add_yuming fi - # Get multiple IPs entered by the user: ports (separated by spaces) if [ -z "$reverseproxy_port" ]; then read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # Dynamically generate upstream configuration upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # Replace placeholders in templates sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,11 +3341,11 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear send_stats "LDNMP site management" @@ -3355,8 +3353,7 @@ ldnmp_web_status() { echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output}Certificate expiration time" + echo -e "Site:${output}Certificate expiration time" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,7 +3366,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "database:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -3939,7 +3936,7 @@ frps_panel() { 8) send_stats "Block IP access" - echo "If you have accessed the anti-generation domain name, use this function to block IP+ port access, which is more secure." + echo "If you have accessed the anti-generation domain name, you can use this function to block IP+ port access, which is more secure." read -e -p "Please enter the port you need to block:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5807,7 +5804,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Create a new connection example:" + echo "Example to create a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -5948,7 +5945,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can connect to other Linux systems via SSH" + echo "Can be connected to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}The environment is installed${gl_bai} $output $db_output" + echo -e "${gl_lv}The environment is installed${gl_bai}Site:$outputdatabase:$db_output" fi fi @@ -7682,7 +7679,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "Backend login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -7913,7 +7910,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8707,7 +8704,7 @@ linux_panel() { echo -e "Nezha Monitoring$check_docker $update_status" echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8797,7 +8794,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "Access address:" echo "https://$yuming" @@ -9183,7 +9180,7 @@ linux_panel() { echo -e "Thunder Pool Service$check_docker" echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" @@ -11066,7 +11063,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys have been set" + echo "Shortcut keys are set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -12168,7 +12165,7 @@ EOF echo "Privacy and Security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 2777ea9a6..01a706586 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -574,7 +574,7 @@ while true; do docker restart $(docker ps -q) ;; 11) - send_stats "コンテナを入力します" + send_stats "进入容器" read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end @@ -611,7 +611,7 @@ while true; do 15) send_stats "コンテナポートアクセスを許可します" - read -e -p "コンテナ名を入力してください:" docker_name + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -641,43 +641,43 @@ docker_image() { while true; do clear send_stats "Docker画像管理" - echo "Docker画像リスト" + echo "Docker镜像列表" docker image ls echo "" - echo "ミラー操作" + echo "镜像操作" echo "------------------------" - echo "1.指定された画像を取得する3。指定された画像を削除します" - echo "2。指定された画像4を更新します。すべての画像を削除します" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "鏡を引っ張ります" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}画像を取得する:$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "画像を更新します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}更新された画像:$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "ミラーを削除します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "すべての画像を削除します" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "サポートされていない分布:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "オペレーティングシステムを決定することはできません。" + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 現在の構成には既にIPv6設定があるかどうかを確認してください + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 構成を更新し、IPv6を有効にします + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 現在の構成をお読みください + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 現在のIPv6ステータスを確認してください + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のクロージングルールを削除します + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # オープンルールを追加します + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートが開かれました$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "ポートが開かれました" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のオープンルールを削除します + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 緊密なルールを追加します + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "ポートは閉じた$port" + echo "已关闭端口 $port" fi done - # 既存のルールを削除する(ある場合) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 最初に新しいルールを挿入します + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "ポートは閉じた" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存のブロッキングルールを削除します + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 許可ルールを追加します + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IPをリリースしました$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "IPをリリースしました" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存の許可ルールを削除します + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # ブロッキングルールを追加します + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IPブロック$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IPブロック" + send_stats "已阻止IP" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 防御DDOをオンにします + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS防御をオンにします" + send_stats "开启DDoS防御" } -# DDOS防御をオフにします +# 关闭DDoS防御 disable_ddos_defense() { - # 防御DDOをオフにします + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS防御をオフにします" + send_stats "关闭DDoS防御" } -# 国家IPルールを管理する機能 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # IPSETが存在しない場合は作成します + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # iptablesでIPをブロックします + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "正常にブロックされました$country_codeIPアドレス" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 許可された国のIPSETを作成する(存在しない場合) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 既存の国家ルールを削除します + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 指定された国のIPのみが許可されています + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "正常に許可されています$country_codeIPアドレス" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 国のiptablesルールを削除します + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # Ipsetを破壊します + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "正常に持ち上げられました$country_codeIPアドレスの制限" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高度なファイアウォール管理" - send_stats "高度なファイアウォール管理" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "ファイアウォール管理" + echo "防火墙管理" echo "------------------------" - echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5。IPホワイトリスト6。IPブラックリスト" - echo "7.指定されたIPをクリアします" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. ping 12を許可します。Pingを無効にします" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" - echo "17.指定国でのIP制限をリリースします" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "オープンポート番号を入力してください:" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "指定されたポートを開きます" + send_stats "开放指定端口" ;; 2) - read -e -p "閉じたポート番号を入力してください:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "指定されたポートを閉じます" + send_stats "关闭指定端口" ;; 3) - # すべてのポートを開きます + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを開きます" + send_stats "开放所有端口" ;; 4) - # すべてのポートを閉じます + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを閉じます" + send_stats "关闭所有端口" ;; 5) - # IPホワイトリスト - read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IPブラックリスト - read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 指定されたIPをクリアします - read -e -p "クリアされたIPを入力してください:" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "指定されたIPをクリアします" + send_stats "清除指定IP" ;; 11) - # pingを許可します + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "pingを許可します" + send_stats "允许PING" ;; 12) - # pingを無効にします + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "pingを無効にします" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "許可された国$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "国をブロックします$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "国をきれいにします$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 現在のシステムですべてのスワップパーティションを取得します + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 反復して、すべてのスワップパーティションを削除します + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfileが使用されなくなったことを確認してください + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 古い /swapfileを削除します + # 删除旧的 /swapfile rm -f /swapfile - # 新しいスワップパーティションを作成します + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 仮想メモリを作成する必要があるかどうかを判断します +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginxバージョンを取得します + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQLバージョンを取得します + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHPバージョンを取得します + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redisバージョンを取得します + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 必要なディレクトリとファイルを作成します + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.ymlファイルをダウンロードして置き換えます + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.ymlファイルに置き換えます + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされています" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "更新タスクが更新されました" + echo "续签任务已更新" } @@ -1451,15 +1451,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}証明書ストレージパス${gl_bai}" - echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1468,7 +1468,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1484,8 +1484,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" - echo "サイト情報証明書の有効期限" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1524,19 +1524,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "ドメイン名証明書の成功したアプリケーション" + send_stats "域名证书申请成功" else - send_stats "ドメイン名証明書のアプリケーションは失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" - echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" - echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" - echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" - echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" - echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" - echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "もう一度展開してみてください$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1547,7 +1547,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "ドメイン名の再利用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1556,8 +1556,8 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1621,8 +1621,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1641,11 +1641,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "ログイン情報:" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "起動する$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1655,29 +1655,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ゾーン_idsを配列に変換します + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # キャッシュをクリーニングするかどうかをユーザーに促します - read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" - read -e -p "API_TOKENを入力してください:" API_TOKEN - read -e -p "CFユーザー名を入力してください:" EMAIL - read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 各ZONE_IDをループして、Clear Cacheコマンドを実行します + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1685,13 +1685,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "キャッシュクリアリクエストが送信されました。" + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "サイトキャッシュをクリーンアップします" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1701,28 +1701,28 @@ web_cache() { web_del() { - send_stats "サイトデータを削除します" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "ドメイン名の削除:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # ドメイン名をデータベース名に変換します + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します - echo "データベースの削除:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1738,23 +1738,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAFをオンにしてください:コメントを削除します + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # WAFを閉じる:コメントを追加します + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1801,11 +1801,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1828,12 +1828,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1856,7 +1856,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotliをオンにする:コメントを削除します + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1870,7 +1870,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる:コメントを追加します + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1886,11 +1886,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1912,7 +1912,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTDをオンにしてください:コメントを削除します + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1927,7 +1927,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # ZSTDを閉じる:コメントを追加します + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1943,11 +1943,11 @@ nginx_zstd() { else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1974,7 +1974,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1988,7 +1988,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP環境防御" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2002,25 +2002,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" - echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21。CloudFlareモード22。5秒シールドの高負荷" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31。WAF32をオンにしてください。WAFをオフにします" - echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2080,7 +2080,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2095,11 +2095,11 @@ web_security() { ;; 21) - send_stats "CloudFlareモード" - echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2114,21 +2114,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CFパラメーターを取得します:" - echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" - echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken - read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2145,23 +2145,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負荷自動シールドオープニングスクリプトが追加されました" + echo "高负载自动开盾脚本已添加" else - echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "サイトWAFが有効になっています" - send_stats "サイトWAFが有効になっています" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "サイトWAFは閉鎖されています" - send_stats "サイトWAFは閉鎖されています" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2187,10 +2187,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processesの設定値を取得します +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 値に応じてモード情報を設定します +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2206,21 +2206,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotliが有効であり、コメントされていないかどうかを確認してください + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIPが有効になっており、コメントされていないかどうかを確認してください + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2236,33 +2236,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP環境を最適化します" - echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1。標準モード2。高性能モード(推奨2H4g以上)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" - echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" - echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "サイト標準モード" + send_stats "站点标准模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2274,7 +2274,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2286,23 +2286,23 @@ web_optimization() { optimize_balanced - echo "LDNMP環境は標準モードに設定されています" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "サイトの高性能モード" + send_stats "站点高性能模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2314,7 +2314,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2324,7 +2324,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP環境は、高性能モードに設定されています" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,10 +2383,10 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker = "$ {gl_lv} $ {gl_bai}インストール" +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2386,7 +2394,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "アクセスアドレス:" +echo "访问地址:" ip_address @@ -2424,31 +2432,31 @@ check_docker_image_update() { return fi - # コンテナの作成時間と画像名を取得します + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # ミラーウェアハウスとタグを抽出します + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # デフォルトのラベルは最新です + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 公式画像のサポートを追加します + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIから画像公開時間を取得します + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 買収の時間を確認します + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # タイムスタンプを比較します + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2467,7 +2475,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2477,34 +2485,34 @@ block_container_port() { install iptables - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2514,7 +2522,7 @@ block_container_port() { fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2525,7 +2533,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2535,17 +2543,17 @@ clear_container_rules() { install iptables - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2554,17 +2562,17 @@ clear_container_rules() { - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2575,7 +2583,7 @@ clear_container_rules() { fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2589,25 +2597,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:block_host_port <ポート番号> <承認IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2616,27 +2624,27 @@ block_host_port() { - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 確立された関連接続および関連する接続のトラフィックを許可します + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2648,47 +2656,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2730,18 +2738,18 @@ while true; do fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2754,12 +2762,12 @@ while true; do grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "インストール$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2769,12 +2777,12 @@ while true; do grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新します$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2783,30 +2791,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" - send_stats "アンインストール$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2843,18 +2851,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2878,22 +2886,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2978,17 +2986,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# セッションが存在するかどうかを確認する関数 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 存在しないセッション名が見つかるまでループします +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 新しいTMUXセッションを作成します +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3063,11 +3071,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "再起動" + echo "已重启" reboot ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -3110,8 +3118,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再度インストールできません" - echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3121,10 +3129,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP環境をインストールします" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3138,10 +3146,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx環境をインストールします" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3152,8 +3160,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginxがインストールされています" -echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3164,7 +3172,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "LDNMP環境を最初にインストールしてください" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3174,7 +3182,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "最初にNGINX環境をインストールしてください" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3185,16 +3193,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webnameインストール情報は次のとおりです。" + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3206,8 +3214,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# エコー「データベース名:$ dbname」 -# エコー「ユーザー名:$ dbuse」 -# エコー「パスワード:$ dbusepasswd」 -# エコー「データベースアドレス:mysql」 -# エコー「テーブルプレフィックス:WP_」 } @@ -3254,17 +3255,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "発生防止ポートを入力してください。" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3287,15 +3288,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi - # ユーザーが入力した複数のIPを取得:ポート(スペースで区切られています) if [ -z "$reverseproxy_port" ]; then - read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # 上流の構成を動的に生成します upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # テンプレートのプレースホルダーを交換します sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,20 +3341,19 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMPサイト管理" - echo "LDNMP環境" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output}証明書の有効期限" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,35 +3366,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "サイトディレクトリ" + echo "站点目录" echo "------------------------" - echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" - echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" echo "5. 查看访问日志 6. 查看错误日志" - echo "7.グローバル構成の編集8。サイト構成の編集" - echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20.指定されたサイトデータを削除します" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3406,15 +3403,15 @@ ldnmp_web_status() { ;; 2) - send_stats "サイトドメイン名を変更します" - echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" - read -e -p "古いドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # MySQLの交換 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3432,7 +3429,7 @@ ldnmp_web_status() { done done - # ウェブサイトディレクトリの交換 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3453,10 +3450,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "関連するサイトを作成します" - echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" - read -e -p "既存のドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3470,25 +3467,25 @@ ldnmp_web_status() { ;; 5) - send_stats "アクセスログを表示します" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "エラーログを表示します" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "グローバル構成を編集します" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "サイト構成を編集します" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3498,7 +3495,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "サイトデータを表示します" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3534,16 +3531,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" - echo "公式ウェブサイトの紹介:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1。インストール2。管理3。アンインストール" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3552,20 +3549,20 @@ while true; do panel_app_install local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - send_stats "${panelname}インストール" + send_stats "${panelname}安装" ;; 2) panel_app_manage local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - send_stats "${panelname}コントロール" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - send_stats "${panelname}アンインストール" + send_stats "${panelname}卸载" ;; *) break @@ -3609,8 +3606,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRPサーバーをインストールします" - # ランダムポートと資格情報を生成します + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3631,17 +3628,17 @@ EOF donlond_frp frps - # 出力生成情報 + # 输出生成的信息 ip_address echo "------------------------" - echo "クライアントの展開に必要なパラメーター" - echo "サービスIP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRPパネル情報" - echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" - echo "FRPパネルのユーザー名:$dashboard_user" - echo "FRPパネルパスワード:$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3651,9 +3648,9 @@ EOF configure_frpc() { - send_stats "FRPクライアントをインストールします" - read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr - read -e -p "外部ネットワークドッキングトークンを入力してください:" token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3673,17 +3670,17 @@ EOF } add_forwarding_service() { - send_stats "FRPイントラネットサービスを追加します" - # ユーザーにサービス名と転送情報を入力するように促します - read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "イントラネットポートを入力してください:" local_port - read -e -p "外部ネットワークポートを入力してください:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # ユーザー入力を構成ファイルに書き込みます + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3693,8 +3690,8 @@ remote_port = ${remote_port} EOF - # 出力生成情報 - echo "仕える$service_nameFRPC.TOMLに正常に追加されました" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3705,12 +3702,12 @@ EOF delete_forwarding_service() { - send_stats "FRPイントラネットサービスを削除します" - # ユーザーに削除する必要があるサービス名を入力するように促します - read -e -p "削除する必要があるサービス名を入力してください:" service_name - # SEDを使用して、サービスとその関連構成を削除します + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "仕える$service_nameFRPC.TOMLから削除されました" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3720,7 +3717,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーを印刷します + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3741,7 +3738,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3750,11 +3747,11 @@ list_forwarding_services() { type } - # 現在のサービス名を更新します + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 前の値をクリアします + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3783,7 +3780,7 @@ list_forwarding_services() { } END { - # 最後のサービスの情報を印刷します + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3796,17 +3793,17 @@ list_forwarding_services() { -# FRPサーバーポートを取得します +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# アクセスアドレスを生成します +# 生成访问地址 generate_access_urls() { - # 最初にすべてのポートを取得します + # 首先获取所有端口 get_frp_ports - # 8055/8056以外のポートがあるかどうかを確認してください + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3815,18 +3812,18 @@ generate_access_urls() { fi done - # 有効なポートがある場合にのみタイトルとコンテンツを表示します + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRPサービス外部アクセスアドレス:" + echo "FRP服务对外访问地址:" - # IPv4アドレスを処理します + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # IPv6アドレスを処理する(存在する場合) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3835,7 +3832,7 @@ generate_access_urls() { done fi - # HTTPS構成の処理 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3862,32 +3859,32 @@ frps_main_ports() { frps_panel() { - send_stats "FRPサーバー" + send_stats "FRP服务端" local docker_name="frps" local docker_port=8056 while true; do clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPサーバー$check_frp $update_status" - echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00。サービスのステータスを更新します0。前のメニューに戻ります" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3895,7 +3892,7 @@ frps_panel() { generate_frps_config local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRPサーバーがインストールされています" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3905,7 +3902,7 @@ frps_panel() { donlond_frp frps local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRPサーバーが更新されました" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3916,37 +3913,37 @@ frps_panel() { close_port 8055 8056 local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 5) - echo "ドメイン名アクセスへの逆イントラネット侵入サービス" - send_stats "FRP外部ドメイン名へのアクセス" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します" - read -e -p "リリースするポートを入力してください:" frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合は、この関数を使用して、より安全なIP+ポートアクセスをブロックします。" - read -e -p "ブロックする必要があるポートを入力してください。" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRPサービスステータスを更新します" - echo "FRPサービスステータスは更新されました" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3959,17 +3956,17 @@ frps_panel() { frpc_panel() { - send_stats "FRPクライアント" + send_stats "FRP客户端" local docker_name="frpc" local docker_port=8055 while true; do clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPクライアント$check_frp $update_status" - echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3977,13 +3974,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3991,7 +3988,7 @@ frpc_panel() { configure_frpc local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRPクライアントがインストールされています" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4001,7 +3998,7 @@ frpc_panel() { donlond_frp frpc local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRPクライアントが更新されました" + echo "FRP客户端已经更新完成" ;; 3) @@ -4012,7 +4009,7 @@ frpc_panel() { close_port 8055 local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 4) @@ -4057,68 +4054,68 @@ yt_menu_pro() { fi clear - send_stats "YT-DLPダウンロードツール" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" - echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードされたビデオリスト:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" - echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "オプション番号を入力してください:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "YT-DLPのインストール..." - echo "YT-DLPのインストール..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "インストールが完了しました。任意のキーを押して続行します..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlpを更新..." - echo "yt-dlpを更新..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." sudo yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "更新が完了しました。任意のキーを押して続行します..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlpのアンインストール..." - echo "yt-dlpのアンインストール..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." sudo rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。任意のキーを押して続行します..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "単一のビデオダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "バッチビデオのダウンロード" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "バッチダウンロードを開始します..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4126,31 +4123,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "カスタムビデオのダウンロード" - read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "実行が完了したら、キーを押して続行します..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3ダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "ビデオを削除します" - read -e -p "削除ビデオの名前を入力してください:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4186,7 +4183,7 @@ set_timedate() { -# DPKG割り込みの問題を修正します +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4195,7 +4192,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}システムの更新...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4214,7 +4211,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi } @@ -4222,7 +4219,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4251,13 +4248,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." apk cache clean - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APKキャッシュを削除してください..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4275,23 +4272,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "未使用の依存関係をクリーンアップ..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." pkg clean -y - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi return @@ -4331,26 +4328,26 @@ fi set_dns_ui() { root_use -send_stats "DNSを最適化します" +send_stats "优化DNS" while true; do clear - echo "DNSアドレスを最適化します" + echo "优化DNS地址" echo "------------------------" - echo "現在のDNSアドレス" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1。外国DNS最適化:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2。国内のDNS最適化:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3。DNS構成を手動で編集します" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4358,7 +4355,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "外国のDNS最適化" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4366,12 +4363,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内のDNS最適化" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "DNS構成を手動で編集します" + send_stats "手动编辑DNS配置" ;; *) break @@ -4394,13 +4391,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthenticationが見つかった場合は、はいに設定します + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 発見された場合、pubkeyauthenticationはyesに設定されています + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4408,7 +4405,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4419,7 +4416,7 @@ correct_ssh_config() { new_ssh_port() { - # バックアップSSH構成ファイル + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4432,7 +4429,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSHポートは次のように変更されています。$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4450,7 +4447,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4462,17 +4459,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4490,7 +4487,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4499,26 +4496,26 @@ import_sshkey() { add_sshpasswd() { -echo "ルートパスワードを設定します" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "システムを再インストールします" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4529,41 +4526,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4579,21 +4576,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "再インストールするシステムを選択してください:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "Debian 13を再インストールします" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4601,49 +4598,49 @@ dd_xitong() { ;; 2) - send_stats "Debian 12を再インストールします" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Debian 11を再インストールします" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Debian 10を再インストールします" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "Ubuntu 24.04を再インストールします" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "Ubuntu 22.04を再インストールします" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04を再インストールします" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "Ubuntu 18.04を再インストールします" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4652,7 +4649,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10を再インストールします" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4660,7 +4657,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9を再インストールします" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4668,7 +4665,7 @@ dd_xitong() { ;; 23) - send_stats "alma10を再インストールします" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4676,7 +4673,7 @@ dd_xitong() { ;; 24) - send_stats "alma9を再インストールします" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4684,7 +4681,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10を再インストールします" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4692,7 +4689,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9を再インストールします" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4700,7 +4697,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42を再インストールします" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4708,7 +4705,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41を再インストールします" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4716,7 +4713,7 @@ dd_xitong() { ;; 29) - send_stats "CENTOS10を再インストールします" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4724,7 +4721,7 @@ dd_xitong() { ;; 30) - send_stats "CENTOS9を再インストールします" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4732,7 +4729,7 @@ dd_xitong() { ;; 31) - send_stats "アルパインを再インストールします" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4740,7 +4737,7 @@ dd_xitong() { ;; 32) - send_stats "アーチを再インストールします" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4748,7 +4745,7 @@ dd_xitong() { ;; 33) - send_stats "Kaliを再インストールします" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4756,7 +4753,7 @@ dd_xitong() { ;; 34) - send_stats "Openeulerを再インストールします" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4764,7 +4761,7 @@ dd_xitong() { ;; 35) - send_stats "OpenSuseを再インストールします" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4772,7 +4769,7 @@ dd_xitong() { ;; 36) - send_stats "飛ぶ牛をリロードします" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4781,7 +4778,7 @@ dd_xitong() { 41) - send_stats "Windows11を再インストールします" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4789,13 +4786,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Windows 10を再インストールします" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7を再インストールします" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4803,21 +4800,21 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22を再インストールします" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Windows Server 19を再インストールします" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Windows Server 16を再インストールします" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4825,7 +4822,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11アームを再インストールします" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4842,7 +4839,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3管理" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4855,17 +4852,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "XanmodのBBRV3カーネルをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4875,7 +4872,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4884,7 +4881,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmodカーネルが更新されました。再起動後に有効になります" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4894,7 +4891,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4907,14 +4904,14 @@ bbrv3() { else clear - echo "BBR3加速度をセットアップします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Debian/Ubuntuのみをサポートします" - echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" - echo "VPSには512mのメモリがあります。メモリが不十分なため、接触の欠落を防ぐために、事前に1G仮想メモリを追加してください!" + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "VPS是512M内存的,请提前添加1G虚拟内存,防止因内存不足失联!" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4922,12 +4919,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "オペレーティングシステムの種類を決定できません" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4938,7 +4935,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4949,17 +4946,17 @@ bbrv3() { bbr_on - echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4968,40 +4965,40 @@ bbrv3() { elrepo_install() { - # Elrepo GPG公開キーをインポートします - echo "Elrepo GPG公開キーをインポートしてください..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # システムバージョンを検出します + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # サポートされているオペレーティングシステムで実行されていることを確認してください + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "サポートされていないオペレーティングシステム:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 検出されたオペレーティングシステム情報を印刷します - echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "サポートされていないシステムバージョン:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします - echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5009,37 +5006,37 @@ elrepo_install() { elrepo() { root_use - send_stats "レッドハットカーネル管理" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo Kernelをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hatカーネルを更新します" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" - send_stats "レッドハットカーネルをアンインストールします" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5052,26 +5049,26 @@ elrepo() { else clear - echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" - echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hatカーネルをアップグレードします" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5082,7 +5079,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5092,19 +5089,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "スキャンするディレクトリを指定してください。" + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # マウントパラメーターを構築します + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # CLAMSCANコマンドパラメーターを作成します + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5113,7 +5110,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Dockerコマンドを実行します + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5122,8 +5119,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5135,23 +5132,23 @@ clamav_scan() { clamav() { root_use - send_stats "ウイルススキャン管理" + send_stats "病毒扫描管理" while true; do clear - echo "クラマブウイルススキャンツール" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" - echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "フルディスクスキャン" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5160,7 +5157,7 @@ clamav() { ;; 2) - send_stats "重要なディレクトリスキャン" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,8 +5165,8 @@ clamav() { break_end ;; 3) - send_stats "カスタムディレクトリスキャン" - read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5186,21 +5183,21 @@ clamav() { -# 高性能モード最適化関数 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5212,36 +5209,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# イコライゼーションモード最適化関数 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5253,36 +5250,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# デフォルト設定関数を復元します +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5294,37 +5291,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# ウェブサイトの構築最適化機能 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5336,16 +5333,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5356,62 +5353,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" - echo "Linuxシステムにおけるカーネルパラメーターの最適化" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" - echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" - echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを同時に改善します。" - echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" - echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" - echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能モードの最適化" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "バランスモードの最適化" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "ウェブサイトの最適化モデル" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "ライブストリーミング最適化" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "ゲームサーバーの最適化" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "デフォルト設定を復元します" + send_stats "还原默认设置" ;; *) break @@ -5438,7 +5435,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5447,17 +5444,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "サポートされていないシステム:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "サポートされていないシステム、システムタイプは認識できません。" + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5467,29 +5464,29 @@ update_locale() { linux_language() { root_use -send_stats "システム言語を切り替えます" +send_stats "切换系统语言" while true; do clear - echo "現在のシステム言語:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1。英語2。簡素化された中国語3。伝統的な中国語" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えます" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "簡素化された中国人に切り替えます" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "伝統的な中国人に切り替えます" + send_stats "切换到繁体中文" ;; *) break @@ -5511,7 +5508,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5522,10 +5519,10 @@ break_end shell_bianse() { root_use - send_stats "コマンドラインの美化ツール" + send_stats "命令行美化工具" while true; do clear - echo "コマンドラインの美化ツール" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5535,9 +5532,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5582,7 +5579,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムリサイクルステーション" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5597,17 +5594,17 @@ linux_trash() { fi clear - echo -e "現在のリサイクルビン${trash_status}" - echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" - echo "3。コンテンツを復元4。リサイクルビンをクリアします" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5615,7 +5612,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5623,23 +5620,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "復元するにはファイル名を入力してください。" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreホームディレクトリに復元されました。" + echo "$file_to_restore 已还原到主目录。" else - echo "ファイルは存在しません。" + echo "文件不存在。" fi ;; 4) - read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "リサイクルビンがクリアされました。" + echo "回收站已清空。" fi ;; *) @@ -5651,19 +5648,19 @@ linux_trash() { -# バックアップを作成します +# 创建备份 create_backup() { - send_stats "バックアップを作成します" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # ユーザーにバックアップディレクトリを入力するように求めます - echo "バックアップ例を作成します:" - echo "- 単一のディレクトリをバックアップします: /var /www" - echo "- バックアップ複数のディレクトリ: /etc /home /var /log" - echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" - read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5671,119 +5668,119 @@ create_backup() { "/home" # 用户数据 ) else - # ユーザーが入力したディレクトリをスペースごとに配列に分離します + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # バックアップファイルプレフィックスを生成します + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # ディレクトリ名を抽出し、スラッシュを削除します + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 最後のアンダースコアを削除します + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # バックアップファイル名を生成します + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # ユーザーが選択したディレクトリを印刷します - echo "選択したバックアップディレクトリは次のとおりです。" + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # バックアップを作成します - echo "バックアップを作成します$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # コマンドが成功しているかどうかを確認してください + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "バックアップの作成に失敗しました!" + echo "备份创建失败!" exit 1 fi } -# バックアップを復元します +# 恢复备份 restore_backup() { - send_stats "バックアップを復元します" - # 復元するバックアップを選択します - read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - echo "バックアップの回復$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "バックアップと復元を正常に!" + echo "备份恢复成功!" else - echo "バックアップリカバリに失敗しました!" + echo "备份恢复失败!" exit 1 fi } -# バックアップをリストします +# 列出备份 list_backups() { - echo "利用可能なバックアップ:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# バックアップを削除します +# 删除备份 delete_backup() { - send_stats "バックアップを削除します" + send_stats "删除备份" - read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - # バックアップを削除します + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "バックアップは正常に削除されました!" + echo "备份删除成功!" else - echo "バックアップの削除が失敗しました!" + echo "备份删除失败!" exit 1 fi } -# バックアップメインメニュー +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "システムバックアップ機能" - echo "システムバックアップ機能" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -5795,56 +5792,56 @@ linux_backup() { -# 接続リストを表示します +# 显示连接列表 list_connections() { - echo "接続の保存:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 新しい接続を追加します +# 添加新连接 add_connection() { - send_stats "新しい接続を追加します" - echo "新しい接続例を作成します:" - echo "- 接続名:my_server" - echo "- IPアドレス:192.168.1.100" - echo "- ユーザー名:root" - echo "- ポート:22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "接続名を入力してください:" name - read -e -p "IPアドレスを入力してください:" ip - read -e -p "ユーザー名(デフォルト:root)を入力してください:" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "ポート番号を入力してください(デフォルト:22):" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "選択(1/2)を入力してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5853,89 +5850,89 @@ add_connection() { fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "接続が保存されます!" + echo "连接已保存!" } -# 接続を削除します +# 删除连接 delete_connection() { - send_stats "接続を削除します" - read -e -p "削除するには、接続番号を入力してください。" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 接続がキーファイルを使用している場合、キーファイルを削除します + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "接続が削除されました!" + echo "连接已删除!" } -# 接続を使用します +# 使用连接 use_connection() { - send_stats "接続を使用します" - read -e -p "使用するには、接続番号を入力してください。" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "接続$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # キーに接続します + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1。キーファイルパスは正しいですか?$password_or_key" - echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" - echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # パスワードで接続します + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1.ユーザー名とパスワードが正しいかどうか。" - echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" - echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSHリモート接続ツール" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5947,21 +5944,21 @@ ssh_manager() { while true; do clear - echo "SSHリモート接続ツール" - echo "SSHを介して他のLinuxシステムに接続できます" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5977,156 +5974,156 @@ ssh_manager() { -# 利用可能なハードディスクパーティションをリストします +# 列出可用的硬盘分区 list_partitions() { - echo "利用可能なハードディスクパーティション:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントします +# 挂载分区 mount_partition() { - send_stats "パーティションをマウントします" - read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションはすでに取り付けられています!" + echo "分区已经挂载!" return fi - # マウントポイントを作成します + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントします + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "パーティションマウントに正常に:$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "パーティションマウントは失敗しました!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# パーティションをアンインストールします +# 卸载分区 unmount_partition() { - send_stats "パーティションをアンインストールします" - read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "パーティションはマウントされていません!" + echo "分区未挂载!" return fi - # パーティションをアンインストールします + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティションのアンインストールに正常に:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "パーティションのアンインストールに失敗しました!" + echo "分区卸载失败!" fi } -# マウントされたパーティションをリストします +# 列出已挂载的分区 list_mounted_partitions() { - echo "マウントされたパーティション:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# フォーマットパーティション +# 格式化分区 format_partition() { - send_stats "フォーマットパーティション" - read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションがマウントされました。最初にアンインストールしてください!" + echo "分区已经挂载,请先卸载!" return fi - # ファイルシステムタイプを選択します - echo "ファイルシステムタイプを選択してください:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "選択を入力してください:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "無効な選択!"; return ;; + *) echo "无效的选择!"; return ;; esac - # フォーマットを確認します - read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作はキャンセルされました。" + echo "操作已取消。" return fi - # フォーマットパーティション - echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティション形式は成功しました!" + echo "分区格式化成功!" else - echo "パーティションのフォーマットが失敗しました!" + echo "分区格式化失败!" fi } -# パーティションステータスを確認します +# 检查分区状态 check_partition() { - send_stats "パーティションステータスを確認します" - read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションステータスを確認します - echo "パーティション /dev /$PARTITION状態:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# メインメニュー +# 主菜单 disk_manager() { - send_stats "ハードディスク管理機能" + send_stats "硬盘管理功能" while true; do clear - echo "ハードディスクパーティション管理" - echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" - echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6135,64 +6132,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } -# タスクリストを表示します +# 显示任务列表 list_tasks() { - echo "保存された同期タスク:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 新しいタスクを追加します +# 添加新任务 add_task() { - send_stats "新しい同期タスクを追加します" - echo "新しい同期タスクを作成する例:" - echo "- タスク名:backup_www" - echo "- ローカルディレクトリ: /var /www" - echo "- リモートアドレス:user@192.168.1.100" - echo "- リモートディレクトリ: /バックアップ /www" - echo "- ポート番号(デフォルト22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "タスク名を入力してください:" name - read -e -p "ローカルディレクトリを入力してください:" local_path - read -e -p "リモートディレクトリを入力してください:" remote_path - read -e -p "リモートユーザー@IPを入力してください:" remote - read -e -p "SSHポートを入力してください(デフォルト22):" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "(1/2)を選択してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6200,63 +6197,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "無効なキーコンテンツ!" + echo "无效的密钥内容!" return fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac - echo "同期モードを選択してください:" - echo "1。標準モード(-AVZ)" - echo "2。ターゲットファイル(-avz - delete)を削除します" - read -e -p "(1/2)を選択してください:" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "タスクが節約されました!" + echo "任务已保存!" } -# タスクを削除します +# 删除任务 delete_task() { - send_stats "同期タスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:対応するタスクは見つかりませんでした。" + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # タスクがキーファイルを使用している場合、キーファイルを削除します + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "削除されたタスク!" + echo "任务已删除!" } run_task() { - send_stats "同期タスクを実行します" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # パラメーターを分析します + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6267,51 +6264,51 @@ run_task() { num="$1" fi - # 着信タスク番号がない場合は、ユーザーに入力するように促します + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "実行するタスク番号を入力してください:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:タスクは見つかりませんでした!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期の方向に従ってソースとターゲットのパスを調整します + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "同期をローカルに引く:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH接続の共通パラメーターを追加します + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "エラー:キーファイルが存在しません:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6319,32 +6316,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同期は完了です!" + echo "同步完成!" else - echo "同期は失敗しました!以下を確認してください。" - echo "1。ネットワーク接続は正常ですか?" - echo "2。リモートホストにアクセスできますか?" - echo "3。認証情報は正しいですか?" - echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 時限タスクを作成します +# 创建定时任务 schedule_task() { - send_stats "同期タイミングタスクを追加します" + send_stats "添加同步定时任务" - read -e -p "定期的に同期するには、タスク番号を入力してください。" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi - echo "時限実行間隔を選択してください:" - echo "1)1時間に1回実行します" - echo "2)1日1回実行します" - echo "3)週に1回実行します" - read -e -p "オプションを入力してください(1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6352,66 +6349,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "エラー:有効なオプションを入力してください!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクが既に存在するかどうかを確認してください + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "エラー:このタスクのタイミング同期はすでに存在しています!" + echo "错误: 该任务的定时同步已存在!" return fi - # ユーザーにクロンタブを作成します + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "タイミングタスクが作成されました。$cron_job" + echo "定时任务已创建: $cron_job" } -# スケジュールされたタスクを表示します +# 查看定时任务 view_tasks() { - echo "現在のタイミングタスク:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# タイミングタスクを削除します +# 删除定时任务 delete_task_schedule() { - send_stats "同期タイミングタスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numタイミングタスク" + echo "已删除任务编号 $num 的定时任务" } -# タスク管理メインメニュー +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "RSYNCリモート同期ツール" - echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1.新しいタスクを作成します2。タスクを削除します" - echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6。タイミングタスクを削除します" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6420,9 +6417,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -6437,7 +6434,7 @@ rsync_manager() { linux_ps() { clear - send_stats "システム情報クエリ" + send_stats "系统信息查询" ip_address @@ -6487,41 +6484,41 @@ linux_ps() { echo "" - echo -e "システム情報クエリ" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" - echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" - echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" - echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" - echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" - echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6534,111 +6531,111 @@ linux_tools() { while true; do clear - # send_stats「基本ツール」 - echo -e "基本的なツール" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" - echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" - echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" - echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" - echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" - echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" - echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" curl --help - send_stats "カールをインストールします" + send_stats "安装curl" ;; 2) clear install wget clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" wget --help - send_stats "WGETをインストールします" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" sudo --help - send_stats "sudoをインストールします" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" socat -h - send_stats "SOCATをインストールします" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "HTOPをインストールします" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "IFTOPをインストールします" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" unzip - send_stats "unzipをインストールします" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tar --help - send_stats "タールをインストールします" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmuxをインストールします" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "ffmpegをインストールします" + send_stats "安装ffmpeg" ;; 11) @@ -6646,7 +6643,7 @@ linux_tools() { install btop clear btop - send_stats "BTOPをインストールします" + send_stats "安装btop" ;; 12) clear @@ -6655,7 +6652,7 @@ linux_tools() { clear ranger cd ~ - send_stats "レンジャーをインストールします" + send_stats "安装ranger" ;; 13) clear @@ -6664,7 +6661,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDUをインストールします" + send_stats "安装ncdu" ;; 14) clear @@ -6673,7 +6670,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZFをインストールします" + send_stats "安装fzf" ;; 15) clear @@ -6682,7 +6679,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIMをインストールします" + send_stats "安装vim" ;; 16) clear @@ -6691,7 +6688,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "ナノをインストールします" + send_stats "安装nano" ;; @@ -6702,7 +6699,7 @@ linux_tools() { clear git --help cd ~ - send_stats "gitをインストールします" + send_stats "安装git" ;; 21) @@ -6710,67 +6707,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrixをインストールします" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "SLをインストールします" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "バステットをインストールします" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "nsnakeをインストールします" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Ninvadersをインストールします" + send_stats "安装ninvaders" ;; 31) clear - send_stats "すべてをインストールします" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "すべてをアンインストールします" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "指定されたソフトウェアをインストールします" + send_stats "安装指定软件" ;; 42) clear - read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "指定されたソフトウェアをアンインストールします" + send_stats "卸载指定软件" ;; 0) @@ -6778,7 +6775,7 @@ linux_tools() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -6792,27 +6789,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR管理" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "AlpineはBBR3を有効にします" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6843,37 +6840,37 @@ linux_docker() { while true; do clear - # send_stats「Docker Management」 + # send_stats "docker管理" echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" - echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" - echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Docker環境をインストールします" + send_stats "安装docker环境" install_add_docker ;; @@ -6884,22 +6881,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Dockerグローバルステータス" - echo "Dockerバージョン" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6914,8 +6911,8 @@ linux_docker() { 5) while true; do clear - send_stats "Dockerネットワーク管理" - echo "Dockerネットワークリスト" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -6939,36 +6936,36 @@ linux_docker() { done echo "" - echo "ネットワーク操作" + echo "网络操作" echo "------------------------" - echo "1.ネットワークを作成します" - echo "2。インターネットに参加してください" - echo "3。ネットワークを終了します" - echo "4.ネットワークを削除します" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ネットワークを作成します" - read -e -p "新しいネットワーク名を設定します:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "インターネットに参加してください" - read -e -p "ネットワーク名に参加してください:" dockernetwork - read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "インターネットに参加してください" - read -e -p "出口ネットワーク名:" dockernetwork - read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6977,8 +6974,8 @@ linux_docker() { ;; 4) - send_stats "ネットワークを削除します" - read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -6992,29 +6989,29 @@ linux_docker() { 6) while true; do clear - send_stats "Dockerボリューム管理" - echo "Dockerボリュームリスト" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "ボリューム操作" + echo "卷操作" echo "------------------------" - echo "1.新しいボリュームを作成します" + echo "1. 创建新卷" echo "2. 删除指定卷" - echo "3.すべてのボリュームを削除します" + echo "3. 删除所有卷" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいボリュームを作成します" - read -e -p "新しいボリューム名を設定します:" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7023,7 +7020,7 @@ linux_docker() { ;; 3) - send_stats "すべてのボリュームを削除します" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7032,7 +7029,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7045,7 +7042,7 @@ linux_docker() { ;; 7) clear - send_stats "Dockerクリーニング" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7054,13 +7051,13 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "Dockerソース" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7073,19 +7070,19 @@ linux_docker() { 11) clear - send_stats "Docker V6が開いています" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker V6レベル" + send_stats "Docker v6 关" docker_ipv6_off ;; 20) clear - send_stats "Dockerアンインストール" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7097,7 +7094,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7106,7 +7103,7 @@ linux_docker() { kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7123,151 +7120,151 @@ linux_test() { while true; do clear - # send_stats「テストスクリプトコレクション」 - echo -e "テストスクリプトコレクション" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" - echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" - echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" - echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ネットワーク速度測定" - echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" - echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" - echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" - echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}包括的なテスト" - echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "CHATGPTはステータス検出のロックを解除します" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "リージョンストリーミングメディアのロック解除テスト" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "YeahWUストリーミングメディアのロック解除検出" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "XYKT_IP品質の身体検査スクリプト" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "MTR_TRACE 3ネットワークリターンラインテスト" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "SuperSpeed Three-Net速度測定" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace高速バックホールテストスクリプト" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" - echo "参照できるIPのリスト" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "北京テレコム:219.141.136.12" - echo "北京ユニコム:202.106.50.1" - echo "北京モバイル:221.179.155.161" - echo "上海通信:202.96.209.133" - echo "上海ユニコム:210.22.97.1" - echo "上海モバイル:211.136.112.200" - echo "広州通信:58.60.188.222" - echo "広州ユニコム:210.21.196.6" - echo "広州モバイル:120.196.165.24" - echo "成都通信:61.139.2.69" - echo "成都ユニコム:119.6.6.6" - echo "成都モバイル:211.137.96.205" - echo "Hunan Telecom:36.111.200.100" - echo "Hunan Unicom:42.48.16.100" - echo "Hunan Mobile:39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "指定されたIPを入力してください:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3ネットワークラインテスト" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC多機能速度テストスクリプト" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "ネットワーク品質のテストスクリプト" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABSパフォーマンステスト" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "ベンチパフォーマンステスト" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX Fusion Monster Review" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7277,7 +7274,7 @@ linux_test() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7293,51 +7290,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Scriptコレクション" - echo -e "Oracle Cloud Scriptコレクション" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" - echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" - echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" - echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "必ずインストールしますか? (y/n):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # デフォルト値を設定します + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 - read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Dockerコンテナを実行します + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7345,14 +7342,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloudインストールアクティブスクリプト" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7360,20 +7357,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - read -e -p "必ず続行しますか? (y/n):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7385,28 +7382,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "再インストールされたパスワードを入力してください:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud再インストールシステムスクリプト" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "この機能は開発段階にあるので、お楽しみに!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7416,15 +7413,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7445,7 +7442,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai} $output $db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7494,31 +7491,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp webサイトビルディング" - echo -e "${gl_huang}LDNMP Webサイトビルディング" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" - echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" - echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" - echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" - echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" - echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7532,10 +7529,10 @@ linux_ldnmp() { 3) clear - # ディスクフォーラム + # Discuz论坛 webname="Discuz论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7558,21 +7555,21 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao Cloudデスクトップ + # 可道云桌面 webname="可道云桌面" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7594,20 +7591,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" - echo "Redisホスト:Redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7633,24 +7630,24 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベースプレフィックス:mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "インストールが成功した後、バックグラウンドアドレスにログインします" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 一本足のカウントカード + # 独脚数卡 webname="独脚数卡" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7671,34 +7668,34 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "Redisアドレス:Redis" - echo "Redisパスワード:デフォルトで記入されていません" - echo "Redisポート:6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "ユーザー名:admin" - echo "パスワード:管理者" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" - echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # フララムフォーラム + # flarum论坛 webname="flarum论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7735,12 +7732,12 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:flarum_" - echo "管理者情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -7748,8 +7745,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7773,11 +7770,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースプレフィックス:typecho_" - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -7786,8 +7783,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7812,18 +7809,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7840,10 +7837,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7853,20 +7850,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7877,15 +7874,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "インストールされた拡張機能" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7895,25 +7892,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7923,10 +7920,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "データベースインポートテーブルデータ" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "データベースのインポートが完了しました" + echo "数据库导入完成" ;; *) echo @@ -7938,12 +7935,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:$prefix" - echo "管理者ログイン情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -7956,10 +7953,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "ジャンプドメイン名を入力してください:" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -7981,7 +7978,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -7992,11 +7989,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" - read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8016,8 +8013,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8039,8 +8036,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8057,8 +8054,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8091,8 +8088,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8109,10 +8106,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8122,12 +8119,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8152,21 +8149,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境バックアップ" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "バックアップファイルが作成されました: /home /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8174,9 +8171,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" + echo "文件已传送至远程服务器home目录。" else - echo "転送されるファイルは見つかりませんでした。" + echo "未找到要传送的文件。" fi break ;; @@ -8184,7 +8181,7 @@ linux_ldnmp() { break ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8192,9 +8189,9 @@ linux_ldnmp() { 33) clear - send_stats "タイミングのリモートバックアップ" - read -e -p "リモートサーバーIPを入力してください:" useip - read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8204,18 +8201,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1。毎週のバックアップ2。毎日のバックアップ" - read -e -p "選択を入力してください:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8229,19 +8226,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP環境修復" - echo "利用可能なサイトバックアップ" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8251,7 +8248,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8260,7 +8257,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージは見つかりませんでした。" + echo "没有找到压缩包。" fi ;; @@ -8278,11 +8275,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP環境を更新します" - echo "LDNMP環境を更新します" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "コンポーネントの新しいバージョンを発見します" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8302,13 +8299,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5。完全な環境を更新します" + echo "5. 更新完整环境" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8317,7 +8314,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8328,13 +8325,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8367,8 +8364,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8379,15 +8376,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境を完全に更新します" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8413,7 +8410,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP環境をアンインストールします" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8427,7 +8424,7 @@ linux_ldnmp() { ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8437,7 +8434,7 @@ linux_ldnmp() { ;; *) - echo "無効な入力!" + echo "无效的输入!" esac break_end @@ -8455,12 +8452,12 @@ linux_panel() { while true; do clear - echo -e "アプリケーション市場" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # ループで色を設定します + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8469,59 +8466,59 @@ linux_panel() { fi done - echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" - echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" - echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" - echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" - echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" - echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" - echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" - echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" - echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" - echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" - echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" - echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -8697,27 +8694,27 @@ linux_panel() { ;; 7) clear - send_stats "ネザを作る" + send_stats "搭建哪吒" local docker_name="nezha-dashboard" local docker_port=8008 while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezhaの監視$check_docker $update_status" - echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" - echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1。使用します" + echo "1. 使用" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -8773,7 +8770,7 @@ linux_panel() { ;; 9) - send_stats "郵便局を建設します" + send_stats "搭建邮局" clear install telnet local docker_name=“mailserver” @@ -8782,43 +8779,43 @@ linux_panel() { check_docker_image_update $docker_name clear - echo -e "郵便局サービス$check_docker $update_status" - echo "Poste.ioはオープンソースメールサーバーソリューションです。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "ポート検出" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "アクセスアドレス:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "これらのDNSレコードを最初に解析します" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8828,7 +8825,7 @@ linux_panel() { echo "TXT ? ?" echo "" echo "------------------------" - echo "任意のキーを押して続行します..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -8847,9 +8844,9 @@ linux_panel() { grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -8872,9 +8869,9 @@ linux_panel() { grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -8885,7 +8882,7 @@ linux_panel() { rm -rf /home/docker/mail local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; *) @@ -8918,7 +8915,7 @@ linux_panel() { clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -8928,7 +8925,7 @@ linux_panel() { docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chatがインストールされています" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -8938,7 +8935,7 @@ linux_panel() { docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9019,7 +9016,7 @@ linux_panel() { cd /home/docker/cloud/ docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -9033,7 +9030,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9173,27 +9170,27 @@ linux_panel() { ;; 19) - send_stats "サンダープールを構築します" + send_stats "搭建雷池" local docker_name=safeline-mgt local docker_port=9443 while true; do check_docker_app clear - echo -e "サンダープールサービス$check_docker" - echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9203,7 +9200,7 @@ linux_panel() { local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "サンダープールWAFパネルがインストールされています" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9216,7 +9213,7 @@ linux_panel() { local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "サンダープールWAFパネルが更新されました" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9227,7 +9224,7 @@ linux_panel() { docker compose down --rmi all local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9616,7 +9613,7 @@ linux_panel() { local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9667,7 +9664,7 @@ linux_panel() { ;; 38) - send_stats "Xiaoyaファミリーバケット" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -9862,9 +9859,9 @@ linux_panel() { prometheus_install clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "最初のユーザー名とパスワードは次のとおりです" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -9882,7 +9879,7 @@ linux_panel() { docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9966,7 +9963,7 @@ linux_panel() { 51) clear - send_stats "PVEチキン" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10081,7 +10078,7 @@ linux_panel() { docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10096,7 +10093,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10123,7 +10120,7 @@ linux_panel() { docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10138,7 +10135,7 @@ linux_panel() { docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10146,7 +10143,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10166,17 +10163,17 @@ linux_panel() { docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "初期ユーザー名:admin" - echo "最初のパスワード:changeme" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "アプリが更新されました" + echo "应用已更新" } @@ -10186,7 +10183,7 @@ linux_panel() { cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10231,7 +10228,7 @@ linux_panel() { sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10247,7 +10244,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10499,7 +10496,7 @@ linux_panel() { docker_rum() { - read -e -p "libretvログインパスワードを設定します。" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10528,7 +10525,7 @@ linux_panel() { docker_rum() { - read -e -p "MOONTVログインパスワードを設定します。" app_passwd + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ --name moontv \ @@ -10611,8 +10608,8 @@ linux_panel() { docker_rum() { - read -e -p "設定${docker_name}ログインユーザー名:" app_use - read -e -p "設定${docker_name}ログインパスワード:" app_passwd + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -10705,11 +10702,11 @@ linux_panel() { install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # ランダムキーとパスワードを生成します + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10718,17 +10715,17 @@ linux_panel() { sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 管理者アカウント情報を追加します + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # コンテナを起動します + # 启动容器 docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10738,7 +10735,7 @@ linux_panel() { curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 元の変数を保持します + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10755,7 +10752,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10804,7 +10801,7 @@ linux_panel() { cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10818,7 +10815,7 @@ linux_panel() { kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -10831,35 +10828,35 @@ linux_work() { while true; do clear - send_stats "バックエンドワークスペース" - echo -e "バックエンドワークスペース" - echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" - echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "現在既存のワークスペースのリスト" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" - echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" - echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" - echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" - echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" - echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" - echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" - echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" - echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" - echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -10867,7 +10864,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -10875,63 +10872,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -10943,21 +10940,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常駐モード" - echo -e "SSH常駐モード${tmux_sshd_status}" - echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1。2をオンにします。オフにします" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "ワークスペースを開始します$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -10973,29 +10970,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "カスタムワークスペース" + send_stats "自定义工作区" ;; 23) - read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "バックグラウンドワークスペースにコマンドを注入します" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "ワークスペースを削除します" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -11020,54 +11017,54 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 - echo -e "システムツール" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" - echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" - echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" - echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" - echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" - echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" - echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" - echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" - echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" - echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "ショートカットキーが設定されています" - send_stats "スクリプトのショートカットキーが設定されています" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11075,34 +11072,34 @@ linux_Settings() { 2) clear - send_stats "ログインパスワードを設定します" - echo "ログインパスワードを設定します" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "ルートパスワードモード" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "Pyバージョン管理" - echo "Pythonバージョン管理" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" - echo "クエリの詳細:https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "スクリプトPy管理" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -11135,7 +11132,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi @@ -11164,55 +11161,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スイッチスクリプトPyバージョン" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "オープンポート" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "すべてのポートが開いています" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSHポートを変更します" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 現在のSSHポート番号をお読みください + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 現在のSSHポート番号を印刷します - echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # ユーザーに新しいSSHポート番号を入力するように促します - read -e -p "新しいSSHポート番号を入力してください:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # ポート番号が有効な範囲内にあるかどうかを判断します + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSHポートが変更されました" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSHポート変更を終了します" + send_stats "退出SSH端口修改" break else - echo "ポート番号は無効です。1〜65535の数字を入力してください。" - send_stats "無効なSSHポート入力" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "入力が無効です。番号を入力してください。" - send_stats "無効なSSHポート入力" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -11231,8 +11228,8 @@ EOF ;; 9) root_use - send_stats "新しいユーザーはルートを無効にします" - read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11245,49 +11242,49 @@ EOF passwd -l root - echo "操作が完了しました。" + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6の優先度を設定します" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6の優先度を設定します" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "優先ネットワークを選択します。" choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4の優先度に切り替えました" - send_stats "IPv4の優先度に切り替えました" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6の優先度に切り替えました" - send_stats "IPv6の優先度に切り替えました" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -11305,43 +11302,43 @@ EOF 12) root_use - send_stats "仮想メモリを設定します" + send_stats "设置虚拟内存" while true; do clear - echo "仮想メモリを設定します" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G仮想メモリが設定されています" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G仮想メモリが設定されています" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G仮想メモリが設定されています" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "カスタム仮想メモリが設定されています" + send_stats "已设置自定义虚拟内存" ;; *) @@ -11354,8 +11351,8 @@ EOF 13) while true; do root_use - send_stats "ユーザー管理" - echo "ユーザーリスト" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11366,58 +11363,58 @@ EOF echo "" - echo "アカウント操作" + echo "账户操作" echo "------------------------" - echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3.最高の権限を与える4。最高の権限をキャンセルします" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5.アカウントを削除します" + echo "5. 删除账号" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作が完了しました。" + echo "操作已完成。" ;; 2) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 新規ユーザーのsudo許可を付与します + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - echo "操作が完了しました。" + echo "操作已完成。" ;; 3) - read -e -p "ユーザー名を入力してください:" username - # 新規ユーザーのsudo許可を付与します + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers ;; 4) - read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudoアクセス許可を削除します + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "削除するにはユーザー名を入力してください:" username - # ユーザーとそのホームディレクトリを削除します + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -11430,50 +11427,50 @@ EOF 14) clear - send_stats "ユーザー情報ジェネレーター" - echo "ランダムユーザー名" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "ランダムユーザー名$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "ランダム名" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5つのランダムユーザー名を生成します + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "ランダムなユーザー名$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "ランダムuuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "ランダムuuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16ビットランダムパスワード" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32ビットランダムパスワード" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -11481,46 +11478,46 @@ EOF 15) root_use - send_stats "タイムゾーンを変更します" + send_stats "换时区" while true; do clear - echo "システム時間情報" + echo "系统时间信息" - # 現在のシステムタイムゾーンを取得します + # 获取当前系统时区 local timezone=$(current_timezone) - # 現在のシステム時間を取得します + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # タイムゾーンと時間を表示します - echo "現在のシステムタイムゾーン:$timezone" - echo "現在のシステム時間:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "タイムゾーンの切り替え" + echo "时区切换" echo "------------------------" - echo "アジア" - echo "1。中国の上海時間2。中国の香港時間" - echo "3。日本の東京時間4。韓国のソウル時間" - echo "5。シンガポール時間6。インドのコルカタ時間" - echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。タイのバンコクでの時間" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "ヨーロッパ" - echo "11。英国のロンドン時間12。パリの時間フランスの時間" - echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" - echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "アメリカ" - echo "21。WesternTime22。東部時間" - echo "23。カナダ時間24。メキシコの時間" - echo "25。ブラジル時間26。アルゼンチン時間" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31。UTCグローバル標準時間" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11563,21 +11560,21 @@ EOF 18) root_use - send_stats "ホスト名を変更します" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian、Ubuntu、Centosなどの他のシステム。 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11595,11 +11592,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "ホスト名は次のように変更されています。$new_hostname" - send_stats "ホスト名が変更されました" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "終了すると、ホスト名は変更されていません。" + echo "已退出,未更改主机名。" break fi done @@ -11607,32 +11604,32 @@ EOF 19) root_use - send_stats "システムの更新ソースを変更します" + send_stats "换系统更新源" clear - echo "更新ソース領域を選択します" - echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "中国本土のデフォルトソース" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国本土の教育源" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外起源" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -11640,62 +11637,62 @@ EOF ;; 20) - send_stats "タイミングタスク管理" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "タイミングされたタスクリスト" + echo "定时任务列表" crontab -l echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1。毎月のタスク2。毎週のタスク" - echo "3。毎日のタスク4。時間ごとのタスク" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "選択を入力してください:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "時限タスクを追加します" + send_stats "添加定时任务" ;; 2) - read -e -p "削除する必要があるキーワードを入力してください。" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "タイミングタスクを削除します" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "タイミングタスクを編集します" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -11707,32 +11704,32 @@ EOF 21) root_use - send_stats "ローカルホストの解析" + send_stats "本地host解析" while true; do clear - echo "ネイティブホストのペルシングリスト" - echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.新しい解析2を追加します。解析アドレスを削除します" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホストの解析が追加されました" + send_stats "本地host解析新增" ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "ローカルホストの解析と削除" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -11743,7 +11740,7 @@ EOF 22) root_use - send_stats "SSH防御" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -11755,20 +11752,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防衛プログラム$check_docker" - echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" - echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "2。SSH傍受記録を表示します" - echo "3。リアルタイムログ監視" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -11791,7 +11788,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -11804,47 +11801,47 @@ EOF 23) root_use - send_stats "電流制限シャットダウン機能" + send_stats "限流关机功能" while true; do clear - echo "電流制限シャットダウン機能" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.shファイルが存在するかどうかを確認してください + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gbの値を取得します + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 新しい仮想メモリサイズを入力します - echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" - read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -11857,15 +11854,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "現在の制限シャットダウンが設定されています" - send_stats "現在の制限シャットダウンが設定されています" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "現在の制限シャットダウン関数はオフになっています" + echo "已关闭限流关机功能" ;; *) break @@ -11878,40 +11875,40 @@ EOF 24) root_use - send_stats "秘密キーログイン" + send_stats "私钥登录" while true; do clear - echo "ルート秘密キーログインモード" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "キーペアが生成され、SSHログインのより安全な方法" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "新しいキーを生成します" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "既存の公開キーをインポートします" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "地元の秘密の鍵を表示します" + send_stats "查看本机密钥" echo "------------------------" - echo "公開鍵情報" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "秘密のキー情報" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -11927,18 +11924,18 @@ EOF 25) root_use - send_stats "電報警告" - echo "TG-BOTモニタリングと早期警告機能" - echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" - echo "しきい値に達した後、ユーザーはユーザーに送信されます" - echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" - read -e -p "必ず続行しますか? (y/n):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "電報警告が有効になっています" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -11960,7 +11957,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 〜/.Profileファイルに追加します + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -11971,21 +11968,21 @@ EOF source ~/.profile clear - echo "TG-BOT早期警告システムが開始されました" - echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSHの高リスクの脆弱性を修正します" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12029,7 +12026,7 @@ EOF ;; 37) clear - send_stats "コマンドラインの履歴" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12047,67 +12044,67 @@ EOF 39) clear - send_stats "コマンドラインの履歴" + send_stats "命令行历史记录" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) ;; 41) clear - send_stats "メッセージボード" - echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "ワンストップチューニング" - echo "ワンストップシステムの最適化" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "以下が操作され、最適化されます" - echo "1.システムを最新の状態に更新します" - echo "2。システムジャンクファイルをクリーンアップします" - echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" - echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" - echo -e "5.すべてのポートを開きます" - echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" - echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}バランスの取れた最適化モード${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングスタート" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12124,25 +12121,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" - echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -12150,7 +12147,7 @@ EOF 99) clear - send_stats "システムを再起動します" + send_stats "重启系统" server_reboot ;; 100) @@ -12166,32 +12163,32 @@ EOF local status_message="无法确定的状态" fi - echo "プライバシーとセキュリティ" - echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "現在のステータス:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1。コレクションをオンにします" - echo "2。コレクションを閉じます" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "コレクションが有効になっています" - send_stats "プライバシーとセキュリティコレクションが有効になっています" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "コレクションは閉じた" - send_stats "プライバシーとセキュリティは収集のために閉鎖されています" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -12207,11 +12204,11 @@ EOF 102) clear - send_stats "テックライオンスクリプトをアンインストールします" - echo "テックライオンスクリプトをアンインストールします" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" - read -e -p "必ず続行しますか? (y/n):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -12219,16 +12216,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "スクリプトはアンインストールされています、さようなら!" + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -12238,7 +12235,7 @@ EOF ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -12256,187 +12253,187 @@ EOF linux_file() { root_use - send_stats "ファイルマネージャー" + send_stats "文件管理器" while true; do clear - echo "ファイルマネージャー" + echo "文件管理器" echo "------------------------" - echo "現在のパス" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" - echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" - echo "15.ファイルを削除します" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" - echo "25。ファイルを別のサーバーに渡します" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "ディレクトリ名を入力してください:" dirname - cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" - send_stats "ディレクトリに移動します" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "作成するにはディレクトリ名を入力してください。" dirname - mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" - send_stats "ディレクトリを作成します" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可を入力してください(755など):" perm - chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ディレクトリ権限を変更します" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "現在のディレクトリ名を入力してください:" current_name - read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" - send_stats "ディレクトリの名前を変更します" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "削除するには、ディレクトリ名を入力してください。" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" - send_stats "ディレクトリを削除します" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "前のメニューディレクトリに戻ります" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "作成するにはファイル名を入力してください。" filename - touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" - send_stats "ファイルを作成します" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "編集するにはファイル名を入力してください:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "ファイルを編集します" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "ファイル名を入力してください:" filename - read -e -p "許可を入力してください(755など):" perm - chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ファイル権限を変更します" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "現在のファイル名を入力してください:" current_name - read -e -p "新しいファイル名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" - send_stats "ファイルの名前を変更します" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "削除するには、ファイル名を入力してください。" filename - rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" - send_stats "ファイルを削除します" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" - send_stats "圧縮ファイル/ディレクトリ" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "ファイル名(.tar.gz)を入力してください:" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" - send_stats "ファイル/ディレクトリを解凍します" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" - send_stats "ファイルまたはディレクトリを移動します" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -Rオプションを使用して、ディレクトリを再帰的にコピーします - cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" - send_stats "ファイルまたはディレクトリをコピーします" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "転送されるファイルパスを入力してください。" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "エラー:ファイルは存在しません。" - send_stats "ファイルの転送に失敗しました:ファイルは存在しません" + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" - send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "エラー:リモートサーバーのパスワードを入力してください。" - send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "ログインポートを入力してください(デフォルト22):" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 既知のホストの古いエントリをクリアします + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCPを使用してファイルを転送します + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "スクリプトは最新です$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -12734,15 +12731,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" - send_stats "自動スクリプトの更新をオンにします" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" - send_stats "スクリプト自動更新を閉じます" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -12764,41 +12761,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" -echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" -echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" -echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" -echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" -echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" -echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" -echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" -echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" -echo -e "${gl_kjlan}13. ${gl_bai}システムツール" -echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" -echo -e "${gl_kjlan}15. ${gl_bai}広告列" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "選択を入力してください:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "システムの更新" ; linux_update ;; - 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "ワープ管理" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -12809,13 +12806,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "無効な入力!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -12823,47 +12820,47 @@ done k_info() { -send_stats "Kコマンド参照ユースケース" +send_stats "k命令参考用例" echo "-------------------" -echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "以下は、Kコマンドリファレンスユースケースです。" -echo "スクリプトkを開始します" -echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" -echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" -echo "システムKアップデートを更新| Kアップデート" -echo "クリーンシステムガベージkクリーン| kきれい" -echo "システムパネルk dd |を再インストールしますk再インストール" -echo "BBR3コントロールパネルK BBR3 | K BBRV3" -echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" -echo "仮想メモリkスワップ2048を設定します" -echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" -echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" -echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" -echo "SSHリモート接続ツールK SSH | Kリモート接続" -echo "rsyncリモート同期ツールk rsync | Kリモート同期" -echo "ハードディスク管理ツールKディスク| Kハードディスク管理" -echo "イントラネット浸透(サーバー側)K FRP" -echo "イントラネット浸透(クライアント)K FRPC" -echo "ソフトウェアStart K Start SSHD | k sshdを開始します" -echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" -echo "ソフトウェア再起動k再起動sshd | k再起動sshd" -echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" -echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" -echo "ドメイン名証明書アプリケーションK SSL" -echo "ドメイン名証明書の有効期限クエリK SSL PS" -echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" -echo "Docker Container Management K Docker PS | K Dockerコンテナ" -echo "Docker Image Management K Docker IMG | K Docker画像" -echo "LDNMPサイト管理k Web" -echo "LDNMPキャッシュクリーンアップK Webキャッシュ" -echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" -echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" -echo "ロードバランスkロードバランス| kロードバランシングをインストールします" -echo "ファイアウォールパネルk fhq | kファイアウォール" -echo "オープンポートK DKDK 8080 | Kオープンポート8080" -echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" -echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" -echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" } @@ -12871,19 +12868,19 @@ echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" if [ "$#" -eq 0 ]; then - # パラメーターがない場合は、インタラクティブロジックを実行します + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # パラメーターがある場合は、対応する関数を実行します + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "ソフトウェアをインストールします" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "ソフトウェアをアンインストールします" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -12917,7 +12914,7 @@ else rsync_run) shift - send_stats "タイム付きRSYNC同期" + send_stats "定时rsync同步" run_task "$@" ;; @@ -12936,7 +12933,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -12949,13 +12946,13 @@ else swap) shift - send_stats "仮想メモリをすばやく設定します" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "タイムゾーンをすばやく設定します" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -12999,42 +12996,42 @@ else status|状态) shift - send_stats "ソフトウェアステータスビュー" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "ソフトウェアスタートアップ" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "ソフトウェアの一時停止" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "ソフトウェアの再起動" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "ソフトウェアが起動します" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "証明書のステータスを確認してください" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" else k_info fi @@ -13044,15 +13041,15 @@ else shift case $1 in install|安装) - send_stats "Dockerをすばやくインストールします" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "クイックコンテナ管理" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "クイックミラー管理" + send_stats "快捷镜像管理" docker_image ;; *) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index ab2dde8ff..7f7308d0c 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1185,7 +1185,7 @@ iptables_panel() { 5) # IP 화이트리스트 - read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip + read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성 해야하는지 확인하십시오 +# 가상 메모리를 만들어야하는지 확인하십시오 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1556,7 +1556,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -2119,7 +2119,7 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker = "$ {gl_lv} $ {gl_bai} 설치" # else # check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# Echo "데이터베이스 이름 : $ dbname" -# Echo "사용자 이름 : $ dbuse" -# echo "비밀번호 : $ dbusepasswd" -# Echo "데이터베이스 주소 : mysql" -# 에코 "테이블 접두사 : wp_" } @@ -3293,7 +3294,6 @@ ldnmp_Proxy_backend() { add_yuming fi - # 사용자가 입력 한 여러 IP를 얻습니다 : 포트 (공간별로 분리) if [ -z "$reverseproxy_port" ]; then read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port fi @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # 상류 구성을 동적으로 생성합니다 upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # 템플릿의 자리 표시자를 교체하십시오 sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,11 +3341,11 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear send_stats "LDNMP 사이트 관리" @@ -3355,8 +3353,7 @@ ldnmp_web_status() { echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output}인증서 만료 시간" + echo -e "대지:${output}인증서 만료 시간" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,7 +3366,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "데이터 베이스:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -3939,7 +3936,7 @@ frps_panel() { 8) send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5807,7 +5804,7 @@ list_connections() { # 새 연결을 추가하십시오 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결 예제 :" + echo "새 연결을 만드는 예 :" echo "- 연결 이름 : my_server" echo "-IP 주소 : 192.168.1.100" echo "- 사용자 이름 : 루트" @@ -6550,7 +6547,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침입자 게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" @@ -6749,7 +6746,7 @@ linux_tools() { 32) clear - send_stats "모든 설치 (게임 및 스크린 세이버 제외)" + send_stats "모든 설치 (게임 및 화면 보호기 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치됩니다${gl_bai} $output $db_output" + echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" fi fi @@ -7682,7 +7679,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "백엔드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" @@ -7913,7 +7910,7 @@ linux_ldnmp() { ;; 2) echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8707,7 +8704,7 @@ linux_panel() { echo -e "Nezha 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8797,7 +8794,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "액세스 주소 :" echo "https://$yuming" @@ -9183,7 +9180,7 @@ linux_panel() { echo -e "썬더 풀 서비스$check_docker" echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" @@ -11066,7 +11063,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되었습니다" + echo "바로 가기 키가 설정되어 있습니다" send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 82089bc1d..d4a764461 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -2363,8 +2363,16 @@ web_optimization() { } + + + + + + + + check_docker_app() { - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2375,7 +2383,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then +# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then # check_docker="${gl_lv}已安裝${gl_bai}" # else # check_docker="${gl_hui}未安裝${gl_bai}" @@ -2719,7 +2727,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2832,7 +2840,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -3225,8 +3233,6 @@ ldnmp_wp() { mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip - # wget -O latest.zip https://cn.wordpress.org/latest-zh_CN.zip - # wget -O latest.zip https://wordpress.org/latest.zip unzip latest.zip rm latest.zip echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3238,11 +3244,6 @@ ldnmp_wp() { restart_ldnmp nginx_web_on -# echo "數據庫名: $dbname" -# echo "用戶名: $dbuse" -# echo "密碼: $dbusepasswd" -# echo "數據庫地址: mysql" -# echo "表前綴: wp_" } @@ -3293,7 +3294,6 @@ ldnmp_Proxy_backend() { add_yuming fi - # 獲取用戶輸入的多個IP:端口(用空格分隔) if [ -z "$reverseproxy_port" ]; then read -e -p "請輸入你的多個反代IP+端口用空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi @@ -3310,13 +3310,11 @@ ldnmp_Proxy_backend() { sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - # 動態生成 upstream 配置 upstream_servers="" for server in $reverseproxy_port; do upstream_servers="$upstream_servers server $server;\n" done - # 替換模板中的佔位符 sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -3343,11 +3341,11 @@ ldnmp_web_status() { root_use while true; do local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) - local output="站点: ${gl_lv}${cert_count}${gl_bai}" + local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) - local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" + local db_output="${gl_lv}${db_count}${gl_bai}" clear send_stats "LDNMP站點管理" @@ -3355,8 +3353,7 @@ ldnmp_web_status() { echo "------------------------" ldnmp_v - # ls -t /home/web/conf.d | sed 's/\.[^.]*$//' - echo -e "${output}證書到期時間" + echo -e "站點:${output}證書到期時間" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3369,7 +3366,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "${db_output}" + echo -e "資料庫:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -7453,20 +7450,20 @@ docker_tato() { ldnmp_tato() { local cert_count=$(ls /home/web/certs/*_cert.pem 2>/dev/null | wc -l) -local output="站点: ${gl_lv}${cert_count}${gl_bai}" +local output="${gl_lv}${cert_count}${gl_bai}" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') if [ -n "$dbrootpasswd" ]; then local db_count=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" | wc -l) fi -local db_output="数据库: ${gl_lv}${db_count}${gl_bai}" +local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境已安裝${gl_bai} $output $db_output" + echo -e "${gl_lv}環境已安裝${gl_bai}站點:$output資料庫:$db_output" fi fi @@ -8707,7 +8704,7 @@ linux_panel() { echo -e "哪吒監控$check_docker $update_status" echo "開源、輕量、易用的服務器監控與運維工具" echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -8797,7 +8794,7 @@ linux_panel() { fi echo "" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) echo "訪問地址:" echo "https://$yuming" @@ -9183,7 +9180,7 @@ linux_panel() { echo -e "雷池服務$check_docker" echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" From 76bfe88ea8fe795ab8c50ae1ccf390b29fb25e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:12:28 +0800 Subject: [PATCH 0016/1285] Update kejilion.sh --- cn/kejilion.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2d8da0e91..d30ad375e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "正在安装 yt-dlp..." echo "正在安装 yt-dlp..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "正在卸载 yt-dlp..." echo "正在卸载 yt-dlp..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "卸载完成。按任意键继续..." @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ From 756bdbba1558dd6779ff68f49a551e5e4c03d05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:12:48 +0800 Subject: [PATCH 0017/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d30ad375e..55faf3817 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From 3392bc8e50590796b291343ba0f4e9ecb278a998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:13:22 +0800 Subject: [PATCH 0018/1285] Update kejilion.sh --- kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 39cd0eba5..d30ad375e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "正在安装 yt-dlp..." echo "正在安装 yt-dlp..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "正在卸载 yt-dlp..." echo "正在卸载 yt-dlp..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "卸载完成。按任意键继续..." @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ From 40b88e73a73a7af20ffbfcff694bef0078405fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:29:50 +0800 Subject: [PATCH 0019/1285] Update kejilion.sh --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 55faf3817..b7734a1a9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11238,6 +11238,8 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root From 0fe76b122051603902d1bc5b82b590aa668d7d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:30:32 +0800 Subject: [PATCH 0020/1285] Update kejilion.sh --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index d30ad375e..9e927dcc1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11238,6 +11238,8 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root From dd0d2293297df6e532320529e62248108708e7c6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 11 Aug 2025 10:03:17 +0000 Subject: [PATCH 0021/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-11=2010:03:17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 12 +- jp/kejilion.sh | 164 +++---- kr/kejilion.sh | 1242 ++++++++++++++++++++++++------------------------ tw/kejilion.sh | 12 +- 4 files changed, 719 insertions(+), 711 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 839b9a966..cb43a64c1 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "Installing yt-dlp..." echo "Installing yt-dlp..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "The installation is complete. Press any key to continue..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "Update yt-dlp..." echo "Update yt-dlp..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "Update completed. Press any key to continue..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "Uninstalling yt-dlp..." echo "Uninstalling yt-dlp..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "Uninstall is complete. Press any key to continue..." @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ @@ -11238,6 +11238,8 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 01a706586..a13c90652 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# コマンドを実行する関数を定義します +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! -# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 -# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# ユーザーに条件に同意するように促します +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" - echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" - echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "上記の条件に同意しますか? (y/n):" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "ライセンスの同意" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "許可の拒否" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}インストール$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" - echo "現在利用可能なスペース:$((available_space_mb/1024))g" - echo "最小需要スペース:${required_gb}G" - echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" - send_stats "ディスクスペースが不十分です" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}アンインストール$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi done } -# さまざまな分布に適したUniversal SystemCTL関数 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# サービスを再起動します +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1サービスは再開されました。" + echo "$1 服务已重启。" else - echo "エラー:再起動$1サービスは失敗しました。" + echo "错误:重启 $1 服务失败。" fi } -# サービスを開始します +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1サービスが開始されました。" + echo "$1 服务已启动。" else - echo "エラー:開始$1サービスは失敗しました。" + echo "错误:启动 $1 服务失败。" fi } -# サービスを停止します +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1サービスは停止しました。" + echo "$1 服务已停止。" else - echo "エラー:停止します$1サービスは失敗しました。" + echo "错误:停止 $1 服务失败。" fi } -# サービスのステータスを確認します +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1サービスステータスが表示されます。" + echo "$1 服务状态已显示。" else - echo "エラー:表示できません$1サービスステータス。" + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME電源を入れるように設定します。" + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}操作が完了しました${gl_bai}" - echo "任意のキーを押して続行します..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Dockerコンテナ管理" - echo "Dockerコンテナリスト" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "コンテナ操作" + echo "容器操作" echo "------------------------" - echo "1.新しいコンテナを作成します" + echo "1. 创建新的容器" echo "------------------------" - echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" - echo "3.指定された容器を停止します7。すべての容器を停止します" - echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" - echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11。指定されたコンテナを入力します12。コンテナログを表示します" - echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいコンテナを作成します" - read -e -p "作成コマンドを入力してください:" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "指定された容器を起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "指定された容器を停止します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "指定されたコンテナを削除します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "指定された容器を再起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "すべてのコンテナを起動します" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "すべてのコンテナを停止します" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "すべてのコンテナを削除します" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "すべてのコンテナを再起動します" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) send_stats "进入容器" - read -e -p "コンテナ名を入力してください:" dockername + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "コンテナログを表示します" - read -e -p "コンテナ名を入力してください:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "コンテナネットワークを表示します" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,13 +604,13 @@ while true; do break_end ;; 14) - send_stats "コンテナの占有を表示します" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "コンテナポートアクセスを許可します" + send_stats "允许容器端口访问" read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "コンテナポートアクセスをブロックします" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,7 +640,7 @@ done docker_image() { while true; do clear - send_stats "Docker画像管理" + send_stats "Docker镜像管理" echo "Docker镜像列表" docker image ls echo "" @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "正在安装 yt-dlp..." echo "正在安装 yt-dlp..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "正在卸载 yt-dlp..." echo "正在卸载 yt-dlp..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "卸载完成。按任意键继续..." @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ @@ -11238,6 +11238,8 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 7f7308d0c..3ee9acbaf 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "yt-dlp 설치 ..." echo "yt-dlp 설치 ..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "yt-dlp 업데이트 ..." echo "yt-dlp 업데이트 ..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "yt-dlp 제거 ..." echo "yt-dlp 제거 ..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." @@ -10166,14 +10166,14 @@ linux_panel() { echo "설치" check_docker_app_ip echo "초기 사용자 이름 : 관리자" - echo "초기 비밀번호 : changeme" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "앱이 업데이트되었습니다" + echo "应用已更新" } @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ @@ -10496,7 +10496,7 @@ linux_panel() { docker_rum() { - read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10525,7 +10525,7 @@ linux_panel() { docker_rum() { - read -e -p "MOONTV 로그인 비밀번호 설정 :" app_passwd + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ --name moontv \ @@ -10608,8 +10608,8 @@ linux_panel() { docker_rum() { - read -e -p "설정${docker_name}로그인 사용자 이름 :" app_use - read -e -p "설정${docker_name}로그인 비밀번호 :" app_passwd + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -10702,11 +10702,11 @@ linux_panel() { install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 암호를 생성합니다 + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10715,17 +10715,17 @@ linux_panel() { sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 관리자 계정 정보를 추가하십시오 + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 컨테이너를 시작하십시오 + # 启动容器 docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10735,7 +10735,7 @@ linux_panel() { curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 원래 변수를 유지하십시오 + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10752,7 +10752,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10801,7 +10801,7 @@ linux_panel() { cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10815,7 +10815,7 @@ linux_panel() { kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -10828,35 +10828,35 @@ linux_work() { while true; do clear - send_stats "백엔드 작업 공간" - echo -e "백엔드 작업 공간" - echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." - echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." - echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "현재 기존 작업 공간 목록" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" - echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" - echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" - echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" - echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" - echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" - echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -10864,7 +10864,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -10872,63 +10872,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -10940,21 +10940,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH 거주 모드" - echo -e "SSH 거주 모드${tmux_sshd_status}" - echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. 2를 켜십시오. 2를 끕니다" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -10970,29 +10970,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "사용자 정의 작업 공간" + send_stats "自定义工作区" ;; 23) - read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "배경 작업 공간에 명령을 주입합니다" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "작업 공간을 삭제합니다" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -11017,54 +11017,54 @@ linux_Settings() { while true; do clear - # Send_stats "시스템 도구" - echo -e "시스템 도구" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" - echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" - echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" - echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" - echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" - echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" - echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" - echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" - send_stats "스크립트 바로 가기 키가 설정되었습니다" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11072,34 +11072,34 @@ linux_Settings() { 2) clear - send_stats "로그인 비밀번호를 설정하십시오" - echo "로그인 비밀번호를 설정하십시오" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "루트 비밀번호 모드" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "PY 버전 관리" - echo "파이썬 버전 관리" - echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" - echo "더 많은 버전 : https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "스크립트 PY 관리" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -11132,7 +11132,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi @@ -11161,55 +11161,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 Py 버전을 스위치하십시오" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "포트 열기" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "모든 포트가 열려 있습니다" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSH 포트를 수정하십시오" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 현재 SSH 포트 번호를 읽으십시오 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 현재 SSH 포트 번호를 인쇄하십시오 - echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 - read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # 포트 번호가 유효한 범위 내에 있는지 확인 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH 포트가 수정되었습니다" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH 포트 수정을 종료하십시오" + send_stats "退出SSH端口修改" break else - echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "입력이 유효하지 않으므로 번호를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -11228,8 +11228,8 @@ EOF ;; 9) root_use - send_stats "신규 사용자는 루트를 비활성화합니다" - read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11238,53 +11238,55 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6 우선 순위를 설정하십시오" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6 우선 순위를 설정하십시오" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선호하는 네트워크를 선택하십시오." choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4 우선 순위로 전환되었습니다" - send_stats "IPv4 우선 순위로 전환되었습니다" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6 우선 순위로 전환되었습니다" - send_stats "IPv6 우선 순위로 전환되었습니다" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -11302,43 +11304,43 @@ EOF 12) root_use - send_stats "가상 메모리를 설정합니다" + send_stats "设置虚拟内存" while true; do clear - echo "가상 메모리를 설정합니다" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G 가상 메모리가 설정되었습니다" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G 가상 메모리가 설정되었습니다" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "사용자 정의 가상 메모리가 설정되었습니다" + send_stats "已设置自定义虚拟内存" ;; *) @@ -11351,8 +11353,8 @@ EOF 13) while true; do root_use - send_stats "사용자 관리" - echo "사용자 목록" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11363,58 +11365,58 @@ EOF echo "" - echo "계정 운영" + echo "账户操作" echo "------------------------" - echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. 계정을 삭제하십시오" + echo "5. 删除账号" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 2) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 새로운 사용자에게 허가를 부여하십시오 + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 3) - read -e -p "사용자 이름을 입력하십시오 :" username - # 새로운 사용자에게 허가를 부여하십시오 + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers ;; 4) - read -e -p "사용자 이름을 입력하십시오 :" username - # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자와 홈 디렉토리를 삭제하십시오 + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -11427,50 +11429,50 @@ EOF 14) clear - send_stats "사용자 정보 생성기" - echo "임의의 사용자 이름" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "임의의 사용자 이름$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "임의 이름" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5 개의 임의의 사용자 이름을 생성합니다 + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "임의의 사용자 이름$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "무작위 uuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "무작위 uuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16 비트 랜덤 비밀번호" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32 비트 랜덤 비밀번호" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -11478,46 +11480,46 @@ EOF 15) root_use - send_stats "시간대를 변경하십시오" + send_stats "换时区" while true; do clear - echo "시스템 시간 정보" + echo "系统时间信息" - # 현재 시스템 시간대를 얻으십시오 + # 获取当前系统时区 local timezone=$(current_timezone) - # 현재 시스템 시간을 얻으십시오 + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 시간대와 시간을 보여줍니다 - echo "현재 시스템 시간대 :$timezone" - echo "현재 시스템 시간 :$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "시간대 스위칭" + echo "时区切换" echo "------------------------" - echo "아시아" - echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" - echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" - echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" - echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" - echo "9. 태국 방콕에서의 시간" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "유럽" - echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" - echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" - echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "미국" - echo "21. 서양 시간 22. 동부 시간" - echo "23. 캐나다 시간 24. 멕시코 시간" - echo "25. 브라질 시간 26. 아르헨티나 시간" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC 글로벌 표준 시간" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11560,21 +11562,21 @@ EOF 18) root_use - send_stats "호스트 이름을 수정하십시오" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, Centos 등과 같은 다른 시스템 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11592,11 +11594,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" - send_stats "호스트 이름이 변경되었습니다" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "종료, 호스트 이름이 변경되지 않았습니다." + echo "已退出,未更改主机名。" break fi done @@ -11604,32 +11606,32 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스를 변경하십시오" + send_stats "换系统更新源" clear - echo "업데이트 소스 영역을 선택하십시오" - echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "중국 본토의 기본 소스" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "중국 본토의 교육 원" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "해외 출신" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "취소" + echo "已取消" ;; esac @@ -11637,62 +11639,62 @@ EOF ;; 20) - send_stats "타이밍 작업 관리" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "시간이 정한 작업 목록" + echo "定时任务列表" crontab -l echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. 월간 작업 2. 주간 작업" - echo "3. 일일 작업 4. 시간당 작업" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "선택을 입력하십시오 :" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "시간이 정한 작업을 추가하십시오" + send_stats "添加定时任务" ;; 2) - read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "타이밍 작업을 삭제하십시오" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "타이밍 작업 편집" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -11704,32 +11706,32 @@ EOF 21) root_use - send_stats "지역 호스트 구문 분석" + send_stats "本地host解析" while true; do clear - echo "기본 호스트 구문 분석 목록" - echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "로컬 호스트 구문 분석이 추가되었습니다" + send_stats "本地host解析新增" ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "로컬 호스트 구문 분석 및 삭제" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -11740,7 +11742,7 @@ EOF 22) root_use - send_stats "SSH 방어" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -11752,20 +11754,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH 방어 프로그램$check_docker" - echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" - echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 安装防御程序" echo "------------------------" - echo "2. SSH 차단 레코드보기" - echo "3. 실시간 로그 모니터링" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -11788,7 +11790,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -11801,47 +11803,47 @@ EOF 23) root_use - send_stats "현재 제한 종료 기능" + send_stats "限流关机功能" while true; do clear - echo "현재 제한 종료 기능" - echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.sh 파일이 있는지 확인하십시오 + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gb의 값을 얻으십시오 + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 새 가상 메모리 크기를 입력하십시오 - echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." - read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -11854,15 +11856,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "전류 제한 종료가 설정되었습니다" - send_stats "전류 제한 종료가 설정되었습니다" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 종료 기능이 꺼졌습니다" + echo "已关闭限流关机功能" ;; *) break @@ -11875,40 +11877,40 @@ EOF 24) root_use - send_stats "개인 키 로그인" + send_stats "私钥登录" while true; do clear - echo "루트 비공개 키 로그인 모드" - echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "새로운 키를 생성하십시오" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "기존 공개 키를 가져옵니다" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "로컬 비밀 키를보십시오" + send_stats "查看本机密钥" echo "------------------------" - echo "공개 키 정보" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "개인 키 정보" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -11924,18 +11926,18 @@ EOF 25) root_use - send_stats "전보 경고" - echo "TG-BOT 모니터링 및 조기 경고 기능" - echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." - echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." - echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속할거야? (Y/N) :" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "전보 경고가 활성화되었습니다" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -11957,7 +11959,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # ~/.profile 파일에 추가하십시오 + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -11968,21 +11970,21 @@ EOF source ~/.profile clear - echo "TG-BOT 조기 경고 시스템이 시작되었습니다" - echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSH에서 고위험 취약점을 수정하십시오" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12026,7 +12028,7 @@ EOF ;; 37) clear - send_stats "명령 줄 기록" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12044,67 +12046,67 @@ EOF 39) clear - send_stats "명령 줄 기록" + send_stats "命令行历史记录" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) ;; 41) clear - send_stats "게시판" - echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "원 스톱 튜닝" - echo "원 스톱 시스템 최적화" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "다음은 작동하고 최적화됩니다" - echo "1. 시스템을 최신으로 업데이트하십시오" - echo "2. 시스템 정크 파일 정리" - echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" - echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니 다" - echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" - echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" - echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" - echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "원 스톱 튜닝 시작" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12121,25 +12123,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" - echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -12147,7 +12149,7 @@ EOF 99) clear - send_stats "시스템을 다시 시작하십시오" + send_stats "重启系统" server_reboot ;; 100) @@ -12163,32 +12165,32 @@ EOF local status_message="无法确定的状态" fi - echo "개인 정보 및 보안" - echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." - echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "현재 상태 :$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. 수집을 켭니다" - echo "2. 컬렉션을 닫습니다" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 활성화되었습니다" - send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "컬렉션이 닫혔습니다" - send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -12204,11 +12206,11 @@ EOF 102) clear - send_stats "기술 라이온 스크립트를 제거하십시오" - echo "기술 라이온 스크립트를 제거하십시오" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." - read -e -p "계속할거야? (Y/N) :" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -12216,16 +12218,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "대본은 제거되었습니다." + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -12235,7 +12237,7 @@ EOF ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -12253,187 +12255,187 @@ EOF linux_file() { root_use - send_stats "파일 관리자" + send_stats "文件管理器" while true; do clear - echo "파일 관리자" + echo "文件管理器" echo "------------------------" - echo "현재 경로" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" - echo "15. 파일을 삭제하십시오" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" - echo "25. 파일을 다른 서버로 전달합니다" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" - send_stats "디렉토리로 이동하십시오" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname - mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" - send_stats "디렉토리를 만듭니다" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "디렉토리 권한을 수정하십시오" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name - read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "디렉토리의 이름을 바꿉니다" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname - rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "디렉토리 삭제" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "이전 메뉴 디렉토리로 돌아갑니다" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "작성하려면 파일 이름을 입력하십시오." filename - touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" - send_stats "파일을 만듭니다" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "편집 할 파일 이름을 입력하십시오." filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "파일 편집" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "파일 이름을 입력하십시오 :" filename - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "파일 권한을 수정하십시오" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "현재 파일 이름을 입력하십시오 :" current_name - read -e -p "새 파일 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "파일의 이름을 바꿉니다" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "파일 삭제" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" - send_stats "압축 파일/디렉토리" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" - send_stats "압축 파일/디렉토리 해제" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" - send_stats "파일 또는 디렉토리를 이동하십시오" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 - cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사합니다" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "오류 : 파일이 존재하지 않습니다." - send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "오류 : 원격 서버 비밀번호를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 알려진 호스트를위한 오래된 항목을 명확하게합니다 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCP를 사용하여 파일을 전송합니다 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트는 최신입니다$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -12731,15 +12733,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" - send_stats "자동 스크립트 업데이트를 켜십시오" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" - send_stats "스크립트 자동 업데이트를 닫습니다" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -12761,41 +12763,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" -echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" -echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" -echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" -echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" -echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" -echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" -echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" -echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" -echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" -echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" -echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" -echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" -echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" -echo -e "${gl_kjlan}15. ${gl_bai}광고 열" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" +echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "선택을 입력하십시오 :" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; - 3) clear ; send_stats "시스템 정리" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "워프 관리" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -12806,13 +12808,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "잘못된 입력!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -12820,47 +12822,47 @@ done k_info() { -send_stats "K 명령 참조 사용 사례" +send_stats "k命令参考用例" echo "-------------------" -echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "다음은 K 명령 참조 유스 케이스입니다." -echo "스크립트 시작 k" -echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" -echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" -echo "업데이트 시스템 K 업데이트 | K 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | K 청소" -echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" -echo "BBR3 제어판 K BBR3 | K bbrv3" -echo "커널 튜닝 패널 K nhyh | K 커널 최적화" -echo "가상 메모리 K 스왑 2048을 설정하십시오" -echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" -echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" -echo "시스템 백업 기능 K 백업 | K bf | K 백업" -echo "SSH 원격 연결 도구 K SSH | K 원격 연결" -echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" -echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" -echo "인트라넷 침투 (서버 측) K frps" -echo "인트라넷 침투 (클라이언트) K frpc" -echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" -echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" -echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" -echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" -echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" -echo "도메인 이름 인증서 응용 프로그램 K SSL" -echo "도메인 이름 인증서 만료 쿼리 K SSL PS" -echo "도커 환경 설치 K 도커 설치 | K 도커 설치" -echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" -echo "Docker Image Management K Docker img | K Docker Image" -echo "LDNMP 사이트 관리 K 웹" -echo "LDNMP 캐시 정리 K 웹 캐시" -echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" -echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." -echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" -echo "방화벽 패널 K FHQ | K 방화벽" -echo "포트 k dkdk 8080 | k 오픈 포트 8080" -echo "포트 K GBDK 7800 | K 닫기 포트 7800" -echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" -echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" } @@ -12868,19 +12870,19 @@ echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" if [ "$#" -eq 0 ]; then - # 매개 변수가없는 경우 대화식 로직을 실행하십시오 + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # 매개 변수가있는 경우 해당 함수를 실행하십시오 + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "소프트웨어를 설치하십시오" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "소프트웨어를 제거하십시오" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -12914,7 +12916,7 @@ else rsync_run) shift - send_stats "시간이 정한 RSYNC 동기화" + send_stats "定时rsync同步" run_task "$@" ;; @@ -12933,7 +12935,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -12946,13 +12948,13 @@ else swap) shift - send_stats "가상 메모리를 신속하게 설정했습니다" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "시간대를 빠르게 설정하십시오" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -12996,42 +12998,42 @@ else status|状态) shift - send_stats "소프트웨어 상태보기" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "소프트웨어 시작" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "소프트웨어 일시 정지" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 재시작" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "소프트웨어 부츠" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "인증서 상태를 확인하십시오" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" else k_info fi @@ -13041,15 +13043,15 @@ else shift case $1 in install|安装) - send_stats "Docker를 신속하게 설치하십시오" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "빠른 컨테이너 관리" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "빠른 미러 관리" + send_stats "快捷镜像管理" docker_image ;; *) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index d4a764461..40c625d50 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -4076,8 +4076,8 @@ yt_menu_pro() { send_stats "正在安裝 yt-dlp..." echo "正在安裝 yt-dlp..." install ffmpeg - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp + curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "安裝完成。按任意鍵繼續..." @@ -4085,7 +4085,7 @@ yt_menu_pro() { 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." - sudo yt-dlp -U + yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt echo "更新完成。按任意鍵繼續..." @@ -4093,7 +4093,7 @@ yt_menu_pro() { 3) send_stats "正在卸載 yt-dlp..." echo "正在卸載 yt-dlp..." - sudo rm -f /usr/local/bin/yt-dlp + rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt echo "卸載完成。按任意鍵繼續..." @@ -10409,7 +10409,7 @@ linux_panel() { mkdir -p /home/docker/astrbot/data - sudo docker run -d \ + docker run -d \ -p ${docker_port}:6185 \ -p 6195:6195 \ -p 6196:6196 \ @@ -11238,6 +11238,8 @@ EOF useradd -m -s /bin/bash "$new_username" passwd "$new_username" + install sudo + echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root From 2fe842655b36e4aae6b9e70d94e1dc1d85b6d1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:28:57 +0800 Subject: [PATCH 0022/1285] Update kejilion.sh --- cn/kejilion.sh | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b7734a1a9..43b646c7f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8514,7 +8514,7 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color80}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10810,6 +10810,33 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p 3001:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion From dfd47bb01051f7156c7c3b0a928863b9ff3d5786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:29:29 +0800 Subject: [PATCH 0023/1285] Update kejilion.sh --- kejilion.sh | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 9e927dcc1..32f681ff3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8514,7 +8514,7 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color80}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10810,6 +10810,33 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p 3001:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion From 4519740572a99a53007110ea5318c4c929656c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:30:31 +0800 Subject: [PATCH 0024/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 698418fe6..fe7f3692b 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1251,6 +1251,7 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 ------------------------ 2025-08-10 v4.0.6 系统工具重装系统新增Debian13的重装选项。Debian13 性能 安全 稳定全面提升。 +应用市场新增gpt-load高性能AI透明代理的安装及使用。 ------------------------ From a546f2443c4474a625971ef8169229f97006f16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:32:00 +0800 Subject: [PATCH 0025/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 43b646c7f..b8eeb7701 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8514,7 +8514,7 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color80}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" From af7598f03508d89301ffe1d39c2a6fbbe05c8bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:33:07 +0800 Subject: [PATCH 0026/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 32f681ff3..1d26585ad 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8514,7 +8514,7 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color80}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" From eb3dac6df86f341b46ec2e62acf2f183b9b99ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:38:05 +0800 Subject: [PATCH 0027/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b8eeb7701..8820f17bd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10820,7 +10820,7 @@ linux_panel() { mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ - -p 3001:3001 \ + -p ${docker_port}:3001 \ -e AUTH_KEY=sk-123456 \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest From 4dc9f77f0166b0cf170ce2e3787d08530bbc1183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:38:49 +0800 Subject: [PATCH 0028/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1d26585ad..4fa7f8516 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10820,7 +10820,7 @@ linux_panel() { mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ - -p 3001:3001 \ + -p ${docker_port}:3001 \ -e AUTH_KEY=sk-123456 \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest From cab08ada2e26976d512eb542fa7b960cfc42f55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 12 Aug 2025 17:42:11 +0800 Subject: [PATCH 0029/1285] Update kejilion.sh --- cn/kejilion.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8820f17bd..cc25e59db 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8515,6 +8515,7 @@ linux_panel() { echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10838,6 +10839,36 @@ linux_panel() { + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion ;; From 207407229ad6c26638806558b5ff07fa54e733c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 12 Aug 2025 17:42:51 +0800 Subject: [PATCH 0030/1285] Update kejilion.sh --- kejilion.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 4fa7f8516..bda8058a5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8515,6 +8515,7 @@ linux_panel() { echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10838,6 +10839,36 @@ linux_panel() { + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion ;; From a1bc681f8b6fa2fcb0afe9e1c6050be1374cbbf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 12 Aug 2025 17:44:26 +0800 Subject: [PATCH 0031/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index fe7f3692b..a6702f6d0 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1252,6 +1252,7 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 2025-08-10 v4.0.6 系统工具重装系统新增Debian13的重装选项。Debian13 性能 安全 稳定全面提升。 应用市场新增gpt-load高性能AI透明代理的安装及使用。 +应用市场新增komari服务器监控的安装及使用,平替哪吒监控。 ------------------------ From 316c39f1f75d5b1479db136c84ca800e450a80cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:25:51 +0800 Subject: [PATCH 0032/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cc25e59db..98e19b80a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11458,6 +11458,8 @@ EOF # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + install sudo + echo "操作已完成。" ;; @@ -11465,6 +11467,8 @@ EOF read -e -p "请输入用户名: " username # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) read -e -p "请输入用户名: " username From e50365e861b909d99aabb04906fb23b4bb401e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:26:25 +0800 Subject: [PATCH 0033/1285] Update kejilion.sh --- kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index bda8058a5..6eab6e900 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11458,6 +11458,8 @@ EOF # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + install sudo + echo "操作已完成。" ;; @@ -11465,6 +11467,8 @@ EOF read -e -p "请输入用户名: " username # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) read -e -p "请输入用户名: " username From f6003942e3fdc6c8329ffe2c66840616c2db46bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:00:12 +0800 Subject: [PATCH 0034/1285] Update kejilion.sh --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 98e19b80a..fec4c8430 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then From b3c95d45e93b0ffbbb1e86de491dd33e47c4bce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:01:12 +0800 Subject: [PATCH 0035/1285] Update kejilion.sh --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 6eab6e900..a5ec77011 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then From 4fd60e4a669475db4118474c302e71a51189745f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:48:22 +0800 Subject: [PATCH 0036/1285] Update kejilion.sh --- cn/kejilion.sh | 112 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fec4c8430..ca90face8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -8517,7 +8517,8 @@ linux_panel() { echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9835,7 +9836,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10871,6 +10872,111 @@ linux_panel() { ;; + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "已经安装完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "应用已卸载" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + 0) kejilion ;; From e471408033d257c243039599482fb84360cf6d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:49:04 +0800 Subject: [PATCH 0037/1285] Update kejilion.sh --- kejilion.sh | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a5ec77011..1029bc317 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -8517,7 +8517,8 @@ linux_panel() { echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9835,7 +9836,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10871,6 +10872,111 @@ linux_panel() { ;; + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "已经安装完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "应用已卸载" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + 0) kejilion ;; From ef0806d4ebe3c1987f4f8be8c945c8d185c16bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:51:35 +0800 Subject: [PATCH 0038/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index a6702f6d0..e8a352142 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1254,6 +1254,9 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增gpt-load高性能AI透明代理的安装及使用。 应用市场新增komari服务器监控的安装及使用,平替哪吒监控。 ------------------------ - - +2025-08-13 v4.0.7 +应用市场新增Wallos个人财务管理工的安装及使用, +应用市场新增immich图片视频管理器的安装及使用, +应用市场新增jellyfin媒体管理系统的安装及使用, +------------------------ From 548bd27ae797f45428ad4294ca3797f53ec6bb31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:21:32 +0800 Subject: [PATCH 0039/1285] Update kejilion.sh --- cn/kejilion.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ca90face8..b4aa0f371 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8519,6 +8519,7 @@ linux_panel() { echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10977,6 +10978,63 @@ linux_panel() { ;; + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion ;; From f9334bae13c0fd9434afe6048e2829217393fd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:22:12 +0800 Subject: [PATCH 0040/1285] Update kejilion.sh --- kejilion.sh | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 1029bc317..eaa42b1c9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8519,6 +8519,7 @@ linux_panel() { echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10977,6 +10978,63 @@ linux_panel() { ;; + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 0) kejilion ;; From 051ef913e49c56d8a176df0be7b8ec4db61a1873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:23:24 +0800 Subject: [PATCH 0041/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e8a352142..6f035b0e1 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1258,5 +1258,7 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增Wallos个人财务管理工的安装及使用, 应用市场新增immich图片视频管理器的安装及使用, 应用市场新增jellyfin媒体管理系统的安装及使用, +应用市场新增SyncTV一起看片神器的安装及使用, +应用市场新增Owncast自托管直播平台的安装及使用, ------------------------ From 329a6605909b83632e51208da923d06a6b60a2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:46:57 +0800 Subject: [PATCH 0042/1285] Update kejilion.sh --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b4aa0f371..65605db4e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10998,7 +10998,7 @@ linux_panel() { local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" local docker_passwd="" local app_size="1" docker_app @@ -11027,8 +11027,8 @@ linux_panel() { local docker_describe="开源、免费的自建直播平台" local docker_url="官网介绍: https://owncast.online" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" local app_size="1" docker_app From 48850088f0f9531ad0f24a78fe4f4b2e3e8089b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:47:37 +0800 Subject: [PATCH 0043/1285] Update kejilion.sh --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index eaa42b1c9..5f6a95541 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10998,7 +10998,7 @@ linux_panel() { local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" local docker_passwd="" local app_size="1" docker_app @@ -11027,8 +11027,8 @@ linux_panel() { local docker_describe="开源、免费的自建直播平台" local docker_url="官网介绍: https://owncast.online" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" local app_size="1" docker_app From 4089f898dd892bfb01c27bb1cd2e406761468361 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 14 Aug 2025 03:06:01 +0000 Subject: [PATCH 0044/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-14=2003:06:01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 242 ++- jp/kejilion.sh | 4658 +++++++++++++++++++++++++----------------------- kr/kejilion.sh | 1470 ++++++++------- tw/kejilion.sh | 236 ++- 4 files changed, 3759 insertions(+), 2847 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index cb43a64c1..1ae24ad56 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -5358,7 +5360,7 @@ Kernel_optimize() { echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "A variety of system parameter tuning modes are provided, and users can choose and switch according to their own usage scenarios." - echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" + echo -e "${gl_huang}Tip:${gl_bai}Please use it with caution in the production environment!" echo "--------------------" echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." echo "2. Balanced optimization mode: Balance between performance and resource consumption, suitable for daily use." @@ -7679,7 +7681,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Backend login path: /admin" + echo "Background login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -8514,7 +8516,10 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki Intelligent Document Management System" echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" + echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tools" + echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" + echo -e "${gl_kjlan}87. ${color87}SyncTV movie watching artifact${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9832,7 +9837,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10810,6 +10815,225 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "Installed" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "The app has been uninstalled" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app + + ;; + 0) kejilion @@ -11400,6 +11624,8 @@ EOF # Grant new users sudo permissions echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + install sudo + echo "The operation has been completed." ;; @@ -11407,6 +11633,8 @@ EOF read -e -p "Please enter your username:" username # Grant new users sudo permissions echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) read -e -p "Please enter your username:" username @@ -11729,7 +11957,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a13c90652..ad6c57515 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# コマンドを実行する関数を定義します run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! +# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 +# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# ユーザーに条件に同意するように促します UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" + echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" + echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "上記の条件に同意しますか? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "ライセンスの同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "許可の拒否" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}インストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" + echo "現在利用可能なスペース:$((available_space_mb/1024))g" + echo "最小需要スペース:${required_gb}G" + echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" + send_stats "ディスクスペースが不十分です" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}アンインストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# さまざまな分布に適したUniversal SystemCTL関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# サービスを再起動します restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1サービスは再開されました。" else - echo "错误:重启 $1 服务失败。" + echo "错误:重启 $1サービスは失敗しました。" fi } -# 启动服务 +# サービスを開始します start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1サービスが開始されました。" else - echo "错误:启动 $1 服务失败。" + echo "エラー:開始$1サービスは失敗しました。" fi } -# 停止服务 +# サービスを停止します stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1サービスは停止しました。" else - echo "错误:停止 $1 服务失败。" + echo "エラー:停止します$1サービスは失敗しました。" fi } -# 查看服务状态 +# サービスのステータスを確認します status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1サービスステータスが表示されます。" else - echo "错误:无法显示 $1 服务状态。" + echo "エラー:表示できません$1サービスステータス。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME電源を入れるように設定します。" } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}操作が完了しました${gl_bai}" + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "Dockerコンテナ管理" + echo "Dockerコンテナリスト" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "コンテナ操作" echo "------------------------" - echo "1. 创建新的容器" + echo "1.新しいコンテナを作成します" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" + echo "3.指定された容器を停止します7。すべての容器を停止します" + echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" + echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11。指定されたコンテナを入力します12。コンテナログを表示します" + echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "新しいコンテナを作成します" + read -e -p "作成コマンドを入力してください:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を停止します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定されたコンテナを削除します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を再起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "すべてのコンテナを起動します" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "すべてのコンテナを停止します" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "すべてのコンテナを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "すべてのコンテナを再起動します" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "コンテナを入力します" + read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "コンテナログを表示します" + read -e -p "コンテナ名を入力してください:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "コンテナネットワークを表示します" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "コンテナの占有を表示します" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスを許可します" + read -e -p "コンテナ名を入力してください:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスをブロックします" + read -e -p "コンテナ名を入力してください:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "Docker画像管理" + echo "Docker画像リスト" docker image ls echo "" - echo "镜像操作" + echo "ミラー操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1.指定された画像を取得する3。指定された画像を削除します" + echo "2。指定された画像4を更新します。すべての画像を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "鏡を引っ張ります" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}画像を取得する:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "画像を更新します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}更新された画像:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "ミラーを削除します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "すべての画像を削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "サポートされていない分布:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "オペレーティングシステムを決定することはできません。" return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 現在の構成には既にIPv6設定があるかどうかを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 構成を更新し、IPv6を有効にします if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 元の構成と新しい構成を比較します if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" return fi - # 读取当前配置 + # 現在の構成をお読みください local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 現在のIPv6ステータスを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 元の構成と新しい構成を比較します if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 既存のクロージングルールを削除します iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # オープンルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "ポートが開かれました$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "ポートが開かれました" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 既存のオープンルールを削除します iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 緊密なルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "ポートは閉じた$port" fi done - # 删除已存在的规则(如果有) + # 既存のルールを削除する(ある場合) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 最初に新しいルールを挿入します iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "ポートは閉じた" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 既存のブロッキングルールを削除します iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 許可ルールを追加します if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "IPをリリースしました$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "IPをリリースしました" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 既存の許可ルールを削除します iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # ブロッキングルールを追加します if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IPブロック$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IPブロック" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 防御DDOをオンにします iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDOS防御をオンにします" } -# 关闭DDoS防御 +# DDOS防御をオフにします disable_ddos_defense() { - # 关闭防御 DDoS + # 防御DDOをオフにします iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDOS防御をオフにします" } -# 管理国家IP规则的函数 +# 国家IPルールを管理する機能 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # IPSETが存在しない場合は作成します if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # iptablesでIPをブロックします iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "正常にブロックされました$country_codeIPアドレス" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 許可された国のIPSETを作成する(存在しない場合) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 删除现有的国家规则 + # 既存の国家ルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 指定された国のIPのみが許可されています iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "正常に許可されています$country_codeIPアドレス" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 国のiptablesルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # Ipsetを破壊します if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "正常に持ち上げられました$country_codeIPアドレスの制限" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "高度なファイアウォール管理" + send_stats "高度なファイアウォール管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "ファイアウォール管理" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1.指定されたポート2を開きます。指定されたポートを閉じます" + echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5。IPホワイトリスト6。IPブラックリスト" + echo "7.指定されたIPをクリアします" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. ping 12を許可します。Pingを無効にします" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" + echo "17.指定国でのIP制限をリリースします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "オープンポート番号を入力してください:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "指定されたポートを開きます" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "閉じたポート番号を入力してください:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "指定されたポートを閉じます" ;; 3) - # 开放所有端口 + # すべてのポートを開きます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "すべてのポートを開きます" ;; 4) - # 关闭所有端口 + # すべてのポートを閉じます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "すべてのポートを閉じます" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IPホワイトリスト + read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IPブラックリスト + read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 指定されたIPをクリアします + read -e -p "クリアされたIPを入力してください:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "指定されたIPをクリアします" ;; 11) - # 允许 PING + # pingを許可します iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "pingを許可します" ;; 12) - # 禁用 PING + # pingを無効にします iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "pingを無効にします" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "許可された国$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "国をブロックします$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "国をきれいにします$country_codeIP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 現在のシステムですべてのスワップパーティションを取得します local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 反復して、すべてのスワップパーティションを削除します for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfileが使用されなくなったことを確認してください swapoff /swapfile - # 删除旧的 /swapfile + # 古い /swapfileを削除します rm -f /swapfile - # 创建新的 swap 分区 + # 新しいスワップパーティションを作成します fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 仮想メモリを作成する必要があるかどうかを判断します [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginxバージョンを取得します local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # MySQLバージョンを取得します local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHPバージョンを取得します local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redisバージョンを取得します local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 必要なディレクトリとファイルを作成します cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.ymlファイルをダウンロードして置き換えます wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.ymlファイルに置き換えます sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP環境がインストールされています" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "更新タスクが更新されました" } @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1451,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}証明書ストレージパス${gl_bai}" + echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1468,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1484,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" + echo "サイト情報証明書の有効期限" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1524,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "ドメイン名証明書の成功したアプリケーション" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "ドメイン名証明書のアプリケーションは失敗しました" + echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" + echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" + echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" + echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" + echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" + echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" + echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" break_end clear - echo "请再次尝试部署 $webname" + echo "もう一度展開してみてください$webname" add_yuming install_ssltls certs_status @@ -1547,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "ドメイン名の再利用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1556,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1621,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" } @@ -1641,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "ログイン情報:" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "起動する$ldnmp_pods" } @@ -1655,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # ゾーン_idsを配列に変換します ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # キャッシュをクリーニングするかどうかをユーザーに促します + read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" + read -e -p "API_TOKENを入力してください:" API_TOKEN + read -e -p "CFユーザー名を入力してください:" EMAIL + read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1685,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "キャッシュクリアリクエストが送信されました。" } web_cache() { - send_stats "清理站点缓存" + send_stats "サイトキャッシュをクリーンアップします" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1701,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "サイトデータを削除します" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "ドメイン名の削除:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # ドメイン名をデータベース名に変換します dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します + echo "データベースの削除:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1738,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # モードパラメーターに従ってWAFをオンまたはオフにすることにしました if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # WAFを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1801,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1828,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1856,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotliをオンにする:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1870,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotliを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1886,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1912,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # ZSTDをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1927,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # ZSTDを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1943,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1974,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi @@ -1988,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP環境防御" while true; do check_waf_status check_cf_mode @@ -2002,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" + echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21。CloudFlareモード22。5秒シールドの高負荷" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31。WAF32をオンにしてください。WAFをオフにします" + echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2080,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; 11) @@ -2095,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "CloudFlareモード" + echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2114,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "5秒シールドでの高負荷" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CFパラメーターを取得します:" + echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" + echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID cd ~ install jq bc @@ -2145,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "高負荷自動シールドオープニングスクリプトが追加されました" else - echo "自动开盾脚本已存在,无需添加" + echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "サイトWAFが有効になっています" + send_stats "サイトWAFが有効になっています" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "サイトWAFは閉鎖されています" + send_stats "サイトWAFは閉鎖されています" ;; 33) @@ -2187,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 現在のworker_processesの設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 値に応じてモード情報を設定します if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2206,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Brotliが有効であり、コメントされていないかどうかを確認してください if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # GZIPが有効になっており、コメントされていないかどうかを確認してください if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2236,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP環境を最適化します" + echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1。標準モード2。高性能モード(推奨2H4g以上)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" + echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" + echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "サイト標準モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2274,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2286,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境は標準モードに設定されています" ;; 2) - send_stats "站点高性能模式" + send_stats "サイトの高性能モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2314,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2324,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP環境は、高性能モードに設定されています" ;; 3) @@ -2384,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker = "$ {gl_lv} $ {gl_bai}インストール" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" # fi # } @@ -2394,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "アクセスアドレス:" ip_address @@ -2432,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # コンテナの作成時間と画像名を取得します local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # ミラーウェアハウスとタグを抽出します local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # デフォルトのラベルは最新です [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 公式画像のサポートを追加します [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Docker Hub APIから画像公開時間を取得します local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 買収の時間を確認します if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # タイムスタンプを比較します if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2475,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2485,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2522,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2533,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2543,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2562,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2583,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2597,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:block_host_port <ポート番号> <承認IP>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2624,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 確立された関連接続および関連する接続のトラフィックを許可します if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2656,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2738,18 +2740,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2762,12 +2764,12 @@ while true; do grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "インストール$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2777,12 +2779,12 @@ while true; do grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "更新します$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2791,30 +2793,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "アプリはアンインストールされています" + send_stats "アンインストール$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2851,18 +2853,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2886,22 +2888,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2986,17 +2988,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# セッションが存在するかどうかを確認する関数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 存在しないセッション名が見つかるまでループします while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 新しいTMUXセッションを作成します tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3071,11 +3073,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "再起動" reboot ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -3118,8 +3120,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP環境を再度インストールできません" + echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" break_end linux_ldnmp fi @@ -3129,10 +3131,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP環境をインストールします" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3146,10 +3148,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Nginx環境をインストールします" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3160,8 +3162,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "Nginxがインストールされています" +echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3172,7 +3174,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "LDNMP環境を最初にインストールしてください" ldnmp_install_all fi @@ -3182,7 +3184,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "最初にNGINX環境をインストールしてください" nginx_install_all fi @@ -3193,16 +3195,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webnameインストール情報は次のとおりです。" } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" } @@ -3214,8 +3216,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3255,17 +3257,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "発生防止ポートを入力してください。" port fi nginx_install_status install_ssltls @@ -3288,14 +3290,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3348,12 +3350,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMPサイト管理" + echo "LDNMP環境" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "サイト:${output}証明書の有効期限" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3366,35 +3368,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "データベース:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "サイトディレクトリ" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" + echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" + echo "5.アクセスログを表示6。エラーログを表示します" + echo "7.グローバル構成の編集8。サイト構成の編集" + echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20.指定されたサイトデータを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "ドメイン名証明書を申請します" + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3403,15 +3405,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "サイトドメイン名を変更します" + echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" + read -e -p "古いドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status - # mysql替换 + # MySQLの交換 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3429,7 +3431,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # ウェブサイトディレクトリの交換 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3450,10 +3452,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "関連するサイトを作成します" + echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" + read -e -p "既存のドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status @@ -3467,25 +3469,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "アクセスログを表示します" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "エラーログを表示します" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "グローバル構成を編集します" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "サイト構成を編集します" + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3495,7 +3497,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "サイトデータを表示します" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3531,16 +3533,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" + echo "公式ウェブサイトの紹介:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1。インストール2。管理3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space 1 @@ -3549,20 +3551,20 @@ while true; do panel_app_install local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - send_stats "${panelname}安装" + send_stats "${panelname}インストール" ;; 2) panel_app_manage local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - send_stats "${panelname}控制" + send_stats "${panelname}コントロール" ;; 3) panel_app_uninstall local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}アンインストール" ;; *) break @@ -3606,8 +3608,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRPサーバーをインストールします" + # ランダムポートと資格情報を生成します local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3628,17 +3630,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 出力生成情報 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "クライアントの展開に必要なパラメーター" + echo "サービスIP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRPパネル情報" + echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" + echo "FRPパネルのユーザー名:$dashboard_user" + echo "FRPパネルパスワード:$dashboard_pwd" echo open_port 8055 8056 @@ -3648,9 +3650,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRPクライアントをインストールします" + read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr + read -e -p "外部ネットワークドッキングトークンを入力してください:" token echo mkdir -p /home/frp @@ -3670,17 +3672,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRPイントラネットサービスを追加します" + # ユーザーにサービス名と転送情報を入力するように促します + read -e -p "サービス名を入力してください:" service_name + read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "イントラネットポートを入力してください:" local_port + read -e -p "外部ネットワークポートを入力してください:" remote_port - # 将用户输入写入配置文件 + # ユーザー入力を構成ファイルに書き込みます cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3690,8 +3692,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 出力生成情報 + echo "仕える$service_nameFRPC.TOMLに正常に追加されました" docker restart frpc @@ -3702,12 +3704,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRPイントラネットサービスを削除します" + # ユーザーに削除する必要があるサービス名を入力するように促します + read -e -p "削除する必要があるサービス名を入力してください:" service_name + # SEDを使用して、サービスとその関連構成を削除します sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "仕える$service_nameFRPC.TOMLから削除されました" docker restart frpc @@ -3717,7 +3719,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # ヘッダーを印刷します printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3738,7 +3740,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3747,11 +3749,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 現在のサービス名を更新します if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 前の値をクリアします local_ip="" local_port="" remote_port="" @@ -3780,7 +3782,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 最後のサービスの情報を印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3793,17 +3795,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRPサーバーポートを取得します get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# アクセスアドレスを生成します generate_access_urls() { - # 首先获取所有端口 + # 最初にすべてのポートを取得します get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056以外のポートがあるかどうかを確認してください local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3812,18 +3814,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 有効なポートがある場合にのみタイトルとコンテンツを表示します if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRPサービス外部アクセスアドレス:" - # 处理 IPv4 地址 + # IPv4アドレスを処理します for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # IPv6アドレスを処理する(存在する場合) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3832,7 +3834,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3859,32 +3861,32 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRPサーバー" local docker_name="frps" local docker_port=8056 while true; do clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRPサーバー$check_frp $update_status" + echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00。サービスのステータスを更新します0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3892,7 +3894,7 @@ frps_panel() { generate_frps_config local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRP服务端已经安装完成" + echo "FRPサーバーがインストールされています" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3902,7 +3904,7 @@ frps_panel() { donlond_frp frps local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRP服务端已经更新完成" + echo "FRPサーバーが更新されました" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3913,37 +3915,37 @@ frps_panel() { close_port 8055 8056 local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "ドメイン名アクセスへの逆イントラネット侵入サービス" + send_stats "FRP外部ドメイン名へのアクセス" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IPアクセスを許可します" + read -e -p "リリースするポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IPアクセスをブロックします" + echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" + read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRPサービスステータスを更新します" + echo "FRPサービスステータスは更新されました" ;; *) @@ -3956,17 +3958,17 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRPクライアント" local docker_name="frpc" local docker_port=8055 while true; do clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRPクライアント$check_frp $update_status" + echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3974,13 +3976,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3988,7 +3990,7 @@ frpc_panel() { configure_frpc local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRP客户端已经安装完成" + echo "FRPクライアントがインストールされています" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -3998,7 +4000,7 @@ frpc_panel() { donlond_frp frpc local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "FRP客户端已经更新完成" + echo "FRPクライアントが更新されました" ;; 3) @@ -4009,7 +4011,7 @@ frpc_panel() { close_port 8055 local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 4) @@ -4054,68 +4056,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "YT-DLPダウンロードツール" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" + echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "ダウンロードされたビデオリスト:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" + echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "オプション番号を入力してください:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "YT-DLPのインストール..." + echo "YT-DLPのインストール..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "安装完成。按任意键继续..." + echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlpを更新..." + echo "yt-dlpを更新..." yt-dlp -U local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - echo "更新完成。按任意键继续..." + echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlpのアンインストール..." + echo "yt-dlpのアンインストール..." rm -f /usr/local/bin/yt-dlp local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "単一のビデオダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; 6) - send_stats "批量视频下载" + send_stats "バッチビデオのダウンロード" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "バッチダウンロードを開始します..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4123,31 +4125,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "カスタムビデオのダウンロード" + read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "実行が完了したら、キーを押して続行します..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3ダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "ビデオを削除します" + read -e -p "削除ビデオの名前を入力してください:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4183,7 +4185,7 @@ set_timedate() { -# 修复dpkg中断问题 +# DPKG割り込みの問題を修正します fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4192,7 +4194,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}システムの更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4211,7 +4213,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi } @@ -4219,7 +4221,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4248,13 +4250,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." apk cache clean - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APKキャッシュを削除してください..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4272,23 +4274,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "未使用の依存関係をクリーンアップ..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." pkg clean -y - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi return @@ -4328,26 +4330,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNSを最適化します" while true; do clear - echo "优化DNS地址" + echo "DNSアドレスを最適化します" echo "------------------------" - echo "当前DNS地址" + echo "現在のDNSアドレス" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1。外国DNS最適化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2。国内のDNS最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3。DNS構成を手動で編集します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4355,7 +4357,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "外国のDNS最適化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4363,12 +4365,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "国内のDNS最適化" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS構成を手動で編集します" ;; *) break @@ -4391,13 +4393,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # PasswordAuthenticationが見つかった場合は、はいに設定します if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 発見された場合、pubkeyauthenticationはyesに設定されています if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4405,7 +4407,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4416,7 +4418,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # バックアップSSH構成ファイル cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4429,7 +4431,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSHポートは次のように変更されています。$new_port" sleep 1 @@ -4447,7 +4449,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4459,17 +4461,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" return 1 fi @@ -4487,7 +4489,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } @@ -4496,26 +4498,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "ルートパスワードを設定します" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "システムを再インストールします" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4526,41 +4528,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4576,21 +4578,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "Debian 13を再インストールします" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4598,49 +4600,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "Debian 12を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "Debian 11を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "Debian 10を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "Ubuntu 24.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "Ubuntu 22.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Ubuntu 20.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "Ubuntu 18.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4649,7 +4651,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Rockylinux10を再インストールします" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4657,7 +4659,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Rockylinux9を再インストールします" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4665,7 +4667,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "alma10を再インストールします" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4673,7 +4675,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "alma9を再インストールします" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4681,7 +4683,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Oracle10を再インストールします" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4689,7 +4691,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Oracle9を再インストールします" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4697,7 +4699,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Fedora42を再インストールします" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4705,7 +4707,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Fedora41を再インストールします" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4713,7 +4715,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "CENTOS10を再インストールします" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4721,7 +4723,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "CENTOS9を再インストールします" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4729,7 +4731,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "アルパインを再インストールします" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4737,7 +4739,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "アーチを再インストールします" dd_xitong_3 bash reinstall.sh arch reboot @@ -4745,7 +4747,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "Kaliを再インストールします" dd_xitong_3 bash reinstall.sh kali reboot @@ -4753,7 +4755,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Openeulerを再インストールします" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4761,7 +4763,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "OpenSuseを再インストールします" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4769,7 +4771,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "飛ぶ牛をリロードします" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4778,7 +4780,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Windows11を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4786,13 +4788,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Windows 10を再インストールします" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows 7を再インストールします" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4800,21 +4802,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Windows Server 22を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Windows Server 19を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Windows Server 16を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4822,7 +4824,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Windows11アームを再インストールします" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4839,7 +4841,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "BBRV3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4852,17 +4854,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "XanmodのBBRV3カーネルをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) @@ -4872,7 +4874,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4881,7 +4883,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "Xanmodカーネルが更新されました。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4891,7 +4893,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" server_reboot ;; @@ -4904,14 +4906,14 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3加速度をセットアップします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" - echo "VPS是512M内存的,请提前添加1G虚拟内存,防止因内存不足失联!" + echo "Debian/Ubuntuのみをサポートします" + echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" + echo "VPSには512mのメモリがあります。メモリが不十分なため、接触の欠落を防ぐために、事前に1G仮想メモリを追加してください!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -4919,12 +4921,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "オペレーティングシステムの種類を決定できません" break_end linux_Settings fi @@ -4935,7 +4937,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4946,17 +4948,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -4965,40 +4967,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Elrepo GPG公開キーをインポートします + echo "Elrepo GPG公開キーをインポートしてください..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # システムバージョンを検出します local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # サポートされているオペレーティングシステムで実行されていることを確認してください if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "サポートされていないオペレーティングシステム:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 検出されたオペレーティングシステム情報を印刷します + echo "検出されたオペレーティングシステム:$os_name $os_version" + # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "サポートされていないシステムバージョン:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします + echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" server_reboot } @@ -5006,37 +5008,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "レッドハットカーネル管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "Elrepo Kernelをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hatカーネルを更新します" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" + send_stats "レッドハットカーネルをアンインストールします" server_reboot ;; @@ -5049,26 +5051,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" + echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hatカーネルをアップグレードします" server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -5079,7 +5081,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5089,19 +5091,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "スキャンするディレクトリを指定してください。" return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" - # 构建 mount 参数 + # マウントパラメーターを構築します local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # CLAMSCANコマンドパラメーターを作成します local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5110,7 +5112,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Dockerコマンドを実行します docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5119,8 +5121,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" } @@ -5132,23 +5134,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "ウイルススキャン管理" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "クラマブウイルススキャンツール" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" + echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "フルディスクスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5157,7 +5159,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "重要なディレクトリスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5165,8 +5167,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "カスタムディレクトリスキャン" + read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5183,21 +5185,21 @@ clamav() { -# 高性能模式优化函数 +# 高性能モード最適化関数 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5209,36 +5211,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# イコライゼーションモード最適化関数 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5250,36 +5252,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# デフォルト設定関数を復元します restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5291,37 +5293,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# ウェブサイトの構築最適化機能 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5333,16 +5335,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5353,62 +5355,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linuxカーネルチューニング管理" + echo "Linuxシステムにおけるカーネルパラメーターの最適化" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" + echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" + echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" + echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを同時に改善します。" + echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" + echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" + echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "高性能モードの最適化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "バランスモードの最適化" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "ウェブサイトの最適化モデル" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "ライブストリーミング最適化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "ゲームサーバーの最適化" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "デフォルト設定を復元します" ;; *) break @@ -5435,7 +5437,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end @@ -5444,17 +5446,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "サポートされていないシステム:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "サポートされていないシステム、システムタイプは認識できません。" break_end fi } @@ -5464,29 +5466,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "システム言語を切り替えます" while true; do clear - echo "当前系统语言: $LANG" + echo "現在のシステム言語:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1。英語2。簡素化された中国語3。伝統的な中国語" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "英語に切り替えます" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "簡素化された中国人に切り替えます" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "伝統的な中国人に切り替えます" ;; *) break @@ -5508,7 +5510,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" hash -r break_end @@ -5519,10 +5521,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "コマンドラインの美化ツール" while true; do clear - echo "命令行美化工具" + echo "コマンドラインの美化ツール" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5532,9 +5534,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5579,7 +5581,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "システムリサイクルステーション" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5594,17 +5596,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "現在のリサイクルビン${trash_status}" + echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" + echo "3。コンテンツを復元4。リサイクルビンをクリアします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5612,7 +5614,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" sleep 2 ;; 2) @@ -5620,23 +5622,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "復元するにはファイル名を入力してください。" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restoreホームディレクトリに復元されました。" else - echo "文件不存在。" + echo "ファイルは存在しません。" fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "リサイクルビンがクリアされました。" fi ;; *) @@ -5648,19 +5650,19 @@ linux_trash() { -# 创建备份 +# バックアップを作成します create_backup() { - send_stats "创建备份" + send_stats "バックアップを作成します" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # ユーザーにバックアップディレクトリを入力するように求めます + echo "バックアップ例を作成します:" + echo "- 単一のディレクトリをバックアップします: /var /www" + echo "- バックアップ複数のディレクトリ: /etc /home /var /log" + echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" + read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input - # 如果用户没有输入目录,则使用默认目录 + # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5668,119 +5670,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # ユーザーが入力したディレクトリをスペースごとに配列に分離します IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # バックアップファイルプレフィックスを生成します local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # ディレクトリ名を抽出し、スラッシュを削除します dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 最後のアンダースコアを削除します local PREFIX=${PREFIX%_} - # 生成备份文件名 + # バックアップファイル名を生成します local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # ユーザーが選択したディレクトリを印刷します + echo "選択したバックアップディレクトリは次のとおりです。" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # バックアップを作成します + echo "バックアップを作成します$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # コマンドが成功しているかどうかを確認してください if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "バックアップの作成に失敗しました!" exit 1 fi } -# 恢复备份 +# バックアップを復元します restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "バックアップを復元します" + # 復元するバックアップを選択します + read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "バックアップの回復$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "バックアップと復元を正常に!" else - echo "备份恢复失败!" + echo "バックアップリカバリに失敗しました!" exit 1 fi } -# 列出备份 +# バックアップをリストします list_backups() { - echo "可用的备份:" + echo "利用可能なバックアップ:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# バックアップを削除します delete_backup() { - send_stats "删除备份" + send_stats "バックアップを削除します" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - # 删除备份 + # バックアップを削除します rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "バックアップは正常に削除されました!" else - echo "备份删除失败!" + echo "バックアップの削除が失敗しました!" exit 1 fi } -# 备份主菜单 +# バックアップメインメニュー linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "システムバックアップ機能" + echo "システムバックアップ機能" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -5792,56 +5794,56 @@ linux_backup() { -# 显示连接列表 +# 接続リストを表示します list_connections() { - echo "已保存的连接:" + echo "接続の保存:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 新しい接続を追加します add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "新しい接続を追加します" + echo "新しい接続を作成する例:" + echo "- 接続名:my_server" + echo "- IPアドレス:192.168.1.100" + echo "- ユーザー名:root" + echo "- ポート:22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "接続名を入力してください:" name + read -e -p "IPアドレスを入力してください:" ip + read -e -p "ユーザー名(デフォルト:root)を入力してください:" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "ポート番号を入力してください(デフォルト:22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "選択(1/2)を入力してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5850,89 +5852,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "接続が保存されます!" } -# 删除连接 +# 接続を削除します delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "接続を削除します" + read -e -p "削除するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 接続がキーファイルを使用している場合、キーファイルを削除します if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "接続が削除されました!" } -# 使用连接 +# 接続を使用します use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "接続を使用します" + read -e -p "使用するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "接続$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "接続に失敗しました!以下を確認してください。" + echo "1。キーファイルパスは正しいですか?$password_or_key" + echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" + echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" fi else - # 使用密码连接 + # パスワードで接続します if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "接続に失敗しました!以下を確認してください。" + echo "1.ユーザー名とパスワードが正しいかどうか。" + echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" + echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSHリモート接続ツール" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5944,21 +5946,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSHリモート接続ツール" + echo "SSHを介して他のLinuxシステムに接続できます" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac done } @@ -5974,156 +5976,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 利用可能なハードディスクパーティションをリストします list_partitions() { - echo "可用的硬盘分区:" + echo "利用可能なハードディスクパーティション:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# パーティションをマウントします mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをマウントします" + read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "パーティションはすでに取り付けられています!" return fi - # 创建挂载点 + # マウントポイントを作成します MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # パーティションをマウントします mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "パーティションマウントに正常に:$MOUNT_POINT" else - echo "分区挂载失败!" + echo "パーティションマウントは失敗しました!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# パーティションをアンインストールします unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをアンインストールします" + read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "パーティションはマウントされていません!" return fi - # 卸载分区 + # パーティションをアンインストールします umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "パーティションのアンインストールに正常に:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "パーティションのアンインストールに失敗しました!" fi } -# 列出已挂载的分区 +# マウントされたパーティションをリストします list_mounted_partitions() { - echo "已挂载的分区:" + echo "マウントされたパーティション:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# フォーマットパーティション format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "フォーマットパーティション" + read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "パーティションがマウントされました。最初にアンインストールしてください!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # ファイルシステムタイプを選択します + echo "ファイルシステムタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "選択を入力してください:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "無効な選択!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # フォーマットを確認します + read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "操作はキャンセルされました。" return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # フォーマットパーティション + echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "パーティション形式は成功しました!" else - echo "分区格式化失败!" + echo "パーティションのフォーマットが失敗しました!" fi } -# 检查分区状态 +# パーティションステータスを確認します check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "パーティションステータスを確認します" + read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # パーティションステータスを確認します + echo "パーティション /dev /$PARTITION状態:" fsck "/dev/$PARTITION" } -# 主菜单 +# メインメニュー disk_manager() { - send_stats "硬盘管理功能" + send_stats "ハードディスク管理機能" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "ハードディスクパーティション管理" + echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" + echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6132,64 +6134,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } -# 显示任务列表 +# タスクリストを表示します list_tasks() { - echo "已保存的同步任务:" + echo "保存された同期タスク:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 新しいタスクを追加します add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "新しい同期タスクを追加します" + echo "新しい同期タスクを作成する例:" + echo "- タスク名:backup_www" + echo "- ローカルディレクトリ: /var /www" + echo "- リモートアドレス:user@192.168.1.100" + echo "- リモートディレクトリ: /バックアップ /www" + echo "- ポート番号(デフォルト22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "タスク名を入力してください:" name + read -e -p "ローカルディレクトリを入力してください:" local_path + read -e -p "リモートディレクトリを入力してください:" remote_path + read -e -p "リモートユーザー@IPを入力してください:" remote + read -e -p "SSHポートを入力してください(デフォルト22):" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "(1/2)を選択してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6197,63 +6199,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "無効なキーコンテンツ!" return fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "同期モードを選択してください:" + echo "1。標準モード(-AVZ)" + echo "2。ターゲットファイル(-avz - delete)を削除します" + read -e -p "(1/2)を選択してください:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "タスクが節約されました!" } -# 删除任务 +# タスクを削除します delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "エラー:対応するタスクは見つかりませんでした。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # タスクがキーファイルを使用している場合、キーファイルを削除します if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "削除されたタスク!" } run_task() { - send_stats "执行同步任务" + send_stats "同期タスクを実行します" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # パラメーターを分析します local direction="push" # 默认是推送到远端 local num @@ -6264,51 +6266,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 着信タスク番号がない場合は、ユーザーに入力するように促します if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "実行するタスク番号を入力してください:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "エラー:タスクは見つかりませんでした!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH接続の共通パラメーターを追加します local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "エラー:キーファイルが存在しません:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." chmod 600 "$password_or_key" fi @@ -6316,32 +6318,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "同期は完了です!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "同期は失敗しました!以下を確認してください。" + echo "1。ネットワーク接続は正常ですか?" + echo "2。リモートホストにアクセスできますか?" + echo "3。認証情報は正しいですか?" + echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" fi } -# 创建定时任务 +# 時限タスクを作成します schedule_task() { - send_stats "添加同步定时任务" + send_stats "同期タイミングタスクを追加します" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "定期的に同期するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "時限実行間隔を選択してください:" + echo "1)1時間に1回実行します" + echo "2)1日1回実行します" + echo "3)週に1回実行します" + read -e -p "オプションを入力してください(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6349,66 +6351,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "エラー:有効なオプションを入力してください!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 同じタスクが既に存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "エラー:このタスクのタイミング同期はすでに存在しています!" return fi - # 创建到用户的 crontab + # ユーザーにクロンタブを作成します (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "タイミングタスクが作成されました。$cron_job" } -# 查看定时任务 +# スケジュールされたタスクを表示します view_tasks() { - echo "当前的定时任务:" + echo "現在のタイミングタスク:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# タイミングタスクを削除します delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タイミングタスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "削除されたタスク番号$numタイミングタスク" } -# 任务管理主菜单 +# タスク管理メインメニュー rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "RSYNCリモート同期ツール" + echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1.新しいタスクを作成します2。タスクを削除します" + echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" + echo "5.タイミングタスクを作成6。タイミングタスクを削除します" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6417,9 +6419,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -6434,7 +6436,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "システム情報クエリ" ip_address @@ -6484,41 +6486,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "システム情報クエリ" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" + echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" + echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" + echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" + echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" + echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" echo @@ -6531,111 +6533,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats「基本ツール」 + echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" + echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" + echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" + echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" + echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" + echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" + echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" + echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" curl --help - send_stats "安装curl" + send_stats "カールをインストールします" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" wget --help - send_stats "安装wget" + send_stats "WGETをインストールします" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" sudo --help - send_stats "安装sudo" + send_stats "sudoをインストールします" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" socat -h - send_stats "安装socat" + send_stats "SOCATをインストールします" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "HTOPをインストールします" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "IFTOPをインストールします" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" unzip - send_stats "安装unzip" + send_stats "unzipをインストールします" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tar --help - send_stats "安装tar" + send_stats "タールをインストールします" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tmux --help - send_stats "安装tmux" + send_stats "tmuxをインストールします" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "ffmpegをインストールします" ;; 11) @@ -6643,7 +6645,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "BTOPをインストールします" ;; 12) clear @@ -6652,7 +6654,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "レンジャーをインストールします" ;; 13) clear @@ -6661,7 +6663,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "NCDUをインストールします" ;; 14) clear @@ -6670,7 +6672,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "FZFをインストールします" ;; 15) clear @@ -6679,7 +6681,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "VIMをインストールします" ;; 16) clear @@ -6688,7 +6690,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "ナノをインストールします" ;; @@ -6699,7 +6701,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "gitをインストールします" ;; 21) @@ -6707,67 +6709,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrixをインストールします" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "SLをインストールします" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "バステットをインストールします" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "nsnakeをインストールします" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Ninvadersをインストールします" ;; 31) clear - send_stats "全部安装" + send_stats "すべてをインストールします" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "すべてをアンインストールします" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname install $installname - send_stats "安装指定软件" + send_stats "指定されたソフトウェアをインストールします" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename remove $removename - send_stats "卸载指定软件" + send_stats "指定されたソフトウェアをアンインストールします" ;; 0) @@ -6775,7 +6777,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -6789,27 +6791,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "AlpineはBBR3を有効にします" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6840,37 +6842,37 @@ linux_docker() { while true; do clear - # send_stats "docker管理" + # send_stats「Docker Management」 echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" + echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" + echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Docker環境をインストールします" install_add_docker ;; @@ -6881,22 +6883,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "Dockerグローバルステータス" + echo "Dockerバージョン" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6911,8 +6913,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "Dockerネットワーク管理" + echo "Dockerネットワークリスト" echo "------------------------------------------------------------" docker network ls echo "" @@ -6936,36 +6938,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "ネットワーク操作" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1.ネットワークを作成します" + echo "2。インターネットに参加してください" + echo "3。ネットワークを終了します" + echo "4.ネットワークを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "ネットワークを作成します" + read -e -p "新しいネットワーク名を設定します:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "ネットワーク名に参加してください:" dockernetwork + read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "出口ネットワーク名:" dockernetwork + read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6974,8 +6976,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "ネットワークを削除します" + read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork docker network rm $dockernetwork ;; @@ -6989,29 +6991,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "Dockerボリューム管理" + echo "Dockerボリュームリスト" docker volume ls echo "" - echo "卷操作" + echo "ボリューム操作" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1.新しいボリュームを作成します" + echo "2。指定されたボリュームを削除します" + echo "3.すべてのボリュームを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "新しいボリュームを作成します" + read -e -p "新しいボリューム名を設定します:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7020,7 +7022,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "すべてのボリュームを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7029,7 +7031,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7042,7 +7044,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "Dockerクリーニング" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7051,13 +7053,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "Dockerソース" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7070,19 +7072,19 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker V6が開いています" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker V6レベル" docker_ipv6_off ;; 20) clear - send_stats "Docker卸载" + send_stats "Dockerアンインストール" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7094,7 +7096,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7103,7 +7105,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7120,151 +7122,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats「テストスクリプトコレクション」 + echo -e "テストスクリプトコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" + echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" + echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" + echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}ネットワーク速度測定" + echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" + echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" + echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" + echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" + echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" + echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" + echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" + echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}包括的なテスト" + echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "CHATGPTはステータス検出のロックを解除します" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "リージョンストリーミングメディアのロック解除テスト" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "YeahWUストリーミングメディアのロック解除検出" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "XYKT_IP品質の身体検査スクリプト" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "MTR_TRACE 3ネットワークリターンラインテスト" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "SuperSpeed Three-Net速度測定" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace高速バックホールテストスクリプト" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" + echo "参照できるIPのリスト" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "北京テレコム:219.141.136.12" + echo "北京ユニコム:202.106.50.1" + echo "北京モバイル:221.179.155.161" + echo "上海通信:202.96.209.133" + echo "上海ユニコム:210.22.97.1" + echo "上海モバイル:211.136.112.200" + echo "広州通信:58.60.188.222" + echo "広州ユニコム:210.21.196.6" + echo "広州モバイル:120.196.165.24" + echo "成都通信:61.139.2.69" + echo "成都ユニコム:119.6.6.6" + echo "成都モバイル:211.137.96.205" + echo "Hunan Telecom:36.111.200.100" + echo "Hunan Unicom:42.48.16.100" + echo "Hunan Mobile:39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "指定されたIPを入力してください:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "Ludashi2020 3ネットワークラインテスト" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "I-ABC多機能速度テストスクリプト" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "ネットワーク品質のテストスクリプト" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "YABSパフォーマンステスト" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "ベンチパフォーマンステスト" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "SpiritySDX Fusion Monster Review" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7274,7 +7276,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7290,51 +7292,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud Scriptコレクション" + echo -e "Oracle Cloud Scriptコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" + echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" + echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" + echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" + echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" + read -e -p "必ずインストールしますか? (y/n):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # デフォルト値を設定します local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 + read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # Dockerコンテナを実行します docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7342,14 +7344,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloudインストールアクティブスクリプト" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7357,20 +7359,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" ;; 3) clear - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7382,28 +7384,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "再インストールされたパスワードを入力してください:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud再インストールシステムスクリプト" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "この機能は開発段階にあるので、お楽しみに!" ;; 5) clear @@ -7413,15 +7415,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7442,7 +7444,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" fi } @@ -7463,7 +7465,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" fi fi @@ -7491,31 +7493,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "ldnmp webサイトビルディング" + echo -e "${gl_huang}LDNMP Webサイトビルディング" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" + echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" + echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" + echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" + echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" + echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" + echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -7529,10 +7531,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # ディスクフォーラム webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7555,21 +7557,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:discuz_" ;; 4) clear - # 可道云桌面 + # Kedao Cloudデスクトップ webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7591,20 +7593,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "データベースアドレス:mysql" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" + echo "Redisホスト:Redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7630,24 +7632,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベースプレフィックス:mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "インストールが成功した後、バックグラウンドアドレスにログインします" echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 一本足のカウントカード webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7668,34 +7670,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "Redisアドレス:Redis" + echo "Redisパスワード:デフォルトで記入されていません" + echo "Redisポート:6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "ウェブサイトURL:https://$yuming" + echo "バックグラウンドログインパス: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "ユーザー名:admin" + echo "パスワード:管理者" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" + echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # フララムフォーラム webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7732,12 +7734,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:flarum_" + echo "管理者情報は自分で設定されます" ;; @@ -7745,8 +7747,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7770,11 +7772,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "データベースプレフィックス:typecho_" + echo "データベースアドレス:mysql" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" ;; @@ -7783,8 +7785,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7809,18 +7811,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7837,10 +7839,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7850,20 +7852,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7874,15 +7876,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" echo "-------------" - echo "已经安装的扩展" + echo "インストールされた拡張機能" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7892,25 +7894,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7920,10 +7922,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "データベースインポートテーブルデータ" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "データベースのインポートが完了しました" ;; *) echo @@ -7935,12 +7937,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:$prefix" + echo "管理者ログイン情報は自分で設定されます" ;; @@ -7953,10 +7955,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "ジャンプドメイン名を入力してください:" reverseproxy nginx_install_status install_ssltls certs_status @@ -7978,7 +7980,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -7989,11 +7991,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" + read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8013,8 +8015,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8036,8 +8038,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8054,8 +8056,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8088,8 +8090,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8106,10 +8108,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8119,12 +8121,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8149,21 +8151,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境バックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "バックアップファイルが作成されました: /home /$backup_filename" + read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "エラー:リモートサーバーIPを入力してください。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8171,9 +8173,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" else - echo "未找到要传送的文件。" + echo "転送されるファイルは見つかりませんでした。" fi break ;; @@ -8181,7 +8183,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac done @@ -8189,9 +8191,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "タイミングのリモートバックアップ" + read -e -p "リモートサーバーIPを入力してください:" useip + read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8201,18 +8203,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1。毎週のバックアップ2。毎日のバックアップ" + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8226,19 +8228,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP環境修復" + echo "利用可能なサイトバックアップ" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8248,7 +8250,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8257,7 +8259,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "圧縮パッケージは見つかりませんでした。" fi ;; @@ -8275,11 +8277,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP環境を更新します" + echo "LDNMP環境を更新します" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "コンポーネントの新しいバージョンを発見します" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8299,13 +8301,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" echo "------------------------" - echo "5. 更新完整环境" + echo "5。完全な環境を更新します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8314,7 +8316,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version local version=${version:-latest} cd /home/web/ @@ -8325,13 +8327,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8364,8 +8366,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 4) @@ -8376,15 +8378,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP環境を完全に更新します" cd /home/web/ docker compose down --rmi all @@ -8410,7 +8412,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP環境をアンインストールします" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8424,7 +8426,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -8434,7 +8436,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "無効な入力!" esac break_end @@ -8452,12 +8454,12 @@ linux_panel() { while true; do clear - echo -e "应用市场" + echo -e "アプリケーション市場" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # ループで色を設定します for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8466,59 +8468,62 @@ linux_panel() { fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" + echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" + echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" + echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" + echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" + echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" + echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" + echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" + echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" + echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" + echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" + echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" + echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" + echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" + echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" + echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议" + echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" + echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" + echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" + echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) @@ -8694,27 +8699,27 @@ linux_panel() { ;; 7) clear - send_stats "搭建哪吒" + send_stats "ネザを作る" local docker_name="nezha-dashboard" local docker_port=8008 while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezhaの監視$check_docker $update_status" + echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" + echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1。使用します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -8770,7 +8775,7 @@ linux_panel() { ;; 9) - send_stats "搭建邮局" + send_stats "郵便局を建設します" clear install telnet local docker_name=“mailserver” @@ -8779,43 +8784,43 @@ linux_panel() { check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "郵便局サービス$check_docker $update_status" + echo "Poste.ioはオープンソースメールサーバーソリューションです。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" - echo "端口检测" + echo "ポート検出" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "アクセスアドレス:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "これらのDNSレコードを最初に解析します" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8825,7 +8830,7 @@ linux_panel() { echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" install jq @@ -8844,9 +8849,9 @@ linux_panel() { grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" @@ -8869,9 +8874,9 @@ linux_panel() { grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" ;; @@ -8882,7 +8887,7 @@ linux_panel() { rm -rf /home/docker/mail local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; *) @@ -8915,7 +8920,7 @@ linux_panel() { clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -8925,7 +8930,7 @@ linux_panel() { docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chatがインストールされています" check_docker_app_ip } @@ -8935,7 +8940,7 @@ linux_panel() { docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9016,7 +9021,7 @@ linux_panel() { cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -9030,7 +9035,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9170,27 +9175,27 @@ linux_panel() { ;; 19) - send_stats "搭建雷池" + send_stats "サンダープールを構築します" local docker_name=safeline-mgt local docker_port=9443 while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "サンダープールサービス$check_docker" + echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -9200,7 +9205,7 @@ linux_panel() { local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "雷池WAF面板已经安装完成" + echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9213,7 +9218,7 @@ linux_panel() { local app_no=$sub_choice grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt clear - echo "雷池WAF面板已经更新完成" + echo "サンダープールWAFパネルが更新されました" check_docker_app_ip ;; 3) @@ -9224,7 +9229,7 @@ linux_panel() { docker compose down --rmi all local app_no=$sub_choice sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9613,7 +9618,7 @@ linux_panel() { local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9664,7 +9669,7 @@ linux_panel() { ;; 38) - send_stats "小雅全家桶" + send_stats "Xiaoyaファミリーバケット" clear install_docker check_disk_space 1 @@ -9832,7 +9837,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -9859,9 +9864,9 @@ linux_panel() { prometheus_install clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "最初のユーザー名とパスワードは次のとおりです" } docker_app_update() { @@ -9879,7 +9884,7 @@ linux_panel() { docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9963,7 +9968,7 @@ linux_panel() { 51) clear - send_stats "PVE开小鸡" + send_stats "PVEチキン" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10078,7 +10083,7 @@ linux_panel() { docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10093,7 +10098,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10120,7 +10125,7 @@ linux_panel() { docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10135,7 +10140,7 @@ linux_panel() { docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10143,7 +10148,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10163,17 +10168,17 @@ linux_panel() { docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "初期ユーザー名:admin" + echo "最初のパスワード:changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "アプリが更新されました" } @@ -10183,7 +10188,7 @@ linux_panel() { cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10228,7 +10233,7 @@ linux_panel() { sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10244,7 +10249,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10496,7 +10501,7 @@ linux_panel() { docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretvログインパスワードを設定します。" app_passwd docker run -d \ --name libretv \ @@ -10525,7 +10530,7 @@ linux_panel() { docker_rum() { - read -e -p "设置MoonTV的登录密码: " app_passwd + read -e -p "MOONTVログインパスワードを設定します。" app_passwd docker run -d \ --name moontv \ @@ -10608,8 +10613,8 @@ linux_panel() { docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "設定${docker_name}ログインユーザー名:" app_use + read -e -p "設定${docker_name}ログインパスワード:" app_passwd docker run -d \ --name xunlei \ @@ -10702,11 +10707,11 @@ linux_panel() { install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 公式のDocker-ComposeおよびEnvファイルをダウンロードします curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # ランダムキーとパスワードを生成します local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10715,17 +10720,17 @@ linux_panel() { sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 管理者アカウント情報を追加します echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # コンテナを起動します docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10735,7 +10740,7 @@ linux_panel() { curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 元の変数を保持します source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10752,7 +10757,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10801,7 +10806,7 @@ linux_panel() { cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10810,12 +10815,231 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "インストール" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "アプリはアンインストールされています" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app + + ;; + 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -10828,35 +11052,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "バックエンドワークスペース" + echo -e "バックエンドワークスペース" + echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "現在既存のワークスペースのリスト" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" + echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" + echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" + echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" + echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" + echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" + echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" + echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" + echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" + echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -10864,7 +11088,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -10872,63 +11096,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -10940,21 +11164,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH常駐モード" + echo -e "SSH常駐モード${tmux_sshd_status}" + echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1。2をオンにします。オフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "選択を入力してください:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "ワークスペースを開始します$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -10970,29 +11194,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "カスタムワークスペース" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "バックグラウンドワークスペースにコマンドを注入します" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "ワークスペースを削除します" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -11017,54 +11241,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats「システムツール」 + echo -e "システムツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" + echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" + echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" + echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" + echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" + echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" + echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" + echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" + echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" + echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" + echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" + echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "ショートカットキーが設定されています" + send_stats "スクリプトのショートカットキーが設定されています" break_end linux_Settings done @@ -11072,34 +11296,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "ログインパスワードを設定します" + echo "ログインパスワードを設定します" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "ルートパスワードモード" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "Pyバージョン管理" + echo "Pythonバージョン管理" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" + echo "クエリの詳細:https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "スクリプトPy管理" break_end linux_Settings fi @@ -11132,7 +11356,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi @@ -11161,55 +11385,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + send_stats "スイッチスクリプトPyバージョン" ;; 5) root_use - send_stats "开放端口" + send_stats "オープンポート" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "すべてのポートが開いています" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSHポートを変更します" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 現在のSSHポート番号をお読みください local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 現在のSSHポート番号を印刷します + echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # ユーザーに新しいSSHポート番号を入力するように促します + read -e -p "新しいSSHポート番号を入力してください:" new_port - # 判断端口号是否在有效范围内 + # ポート番号が有効な範囲内にあるかどうかを判断します if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSHポート変更を終了します" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "ポート番号は無効です。1〜65535の数字を入力してください。" + send_stats "無効なSSHポート入力" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "入力が無効です。番号を入力してください。" + send_stats "無効なSSHポート入力" break_end fi done @@ -11228,8 +11452,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "新しいユーザーはルートを無効にします" + read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11244,49 +11468,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "操作が完了しました。" ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6の優先度を設定します" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6の優先度を設定します" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "優先ネットワークを選択します。" choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4の優先度に切り替えました" + send_stats "IPv4の優先度に切り替えました" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6の優先度に切り替えました" + send_stats "IPv6の優先度に切り替えました" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; *) @@ -11304,43 +11528,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "仮想メモリを設定します" while true; do clear - echo "设置虚拟内存" + echo "仮想メモリを設定します" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G仮想メモリが設定されています" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G仮想メモリが設定されています" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G仮想メモリが設定されています" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "カスタム仮想メモリが設定されています" ;; *) @@ -11353,8 +11577,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "ユーザー管理" + echo "ユーザーリスト" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11365,58 +11589,62 @@ EOF echo "" - echo "账户操作" + echo "アカウント操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3.最高の権限を与える4。最高の権限をキャンセルします" echo "------------------------" - echo "5. 删除账号" + echo "5.アカウントを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "操作が完了しました。" ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 新規ユーザーのsudo許可を付与します echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - echo "操作已完成。" + install sudo + + echo "操作が完了しました。" ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "ユーザー名を入力してください:" username + # 新規ユーザーのsudo許可を付与します echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "ユーザー名を入力してください:" username + # sudoersファイルからユーザーのsudo許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "削除するにはユーザー名を入力してください:" username + # ユーザーとそのホームディレクトリを削除します userdel -r "$username" ;; @@ -11429,50 +11657,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "ユーザー情報ジェネレーター" + echo "ランダムユーザー名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "ランダムユーザー名$i: $username" done echo "" - echo "随机姓名" + echo "ランダム名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5つのランダムユーザー名を生成します for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "ランダムなユーザー名$i: $user_name" done echo "" - echo "随机UUID" + echo "ランダムuuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "ランダムuuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" - echo "32位随机密码" + echo "32ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" @@ -11480,46 +11708,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "タイムゾーンを変更します" while true; do clear - echo "系统时间信息" + echo "システム時間情報" - # 获取当前系统时区 + # 現在のシステムタイムゾーンを取得します local timezone=$(current_timezone) - # 获取当前系统时间 + # 現在のシステム時間を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # タイムゾーンと時間を表示します + echo "現在のシステムタイムゾーン:$timezone" + echo "現在のシステム時間:$current_time" echo "" - echo "时区切换" + echo "タイムゾーンの切り替え" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "アジア" + echo "1。中国の上海時間2。中国の香港時間" + echo "3。日本の東京時間4。韓国のソウル時間" + echo "5。シンガポール時間6。インドのコルカタ時間" + echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" + echo "9。タイのバンコクでの時間" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "ヨーロッパ" + echo "11。英国のロンドン時間12。パリの時間フランスの時間" + echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" + echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "アメリカ" + echo "21。WesternTime22。東部時間" + echo "23。カナダ時間24。メキシコの時間" + echo "25。ブラジル時間26。アルゼンチン時間" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31。UTCグローバル標準時間" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -11562,21 +11790,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "ホスト名を変更します" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian、Ubuntu、Centosなどの他のシステム。 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11594,11 +11822,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "ホスト名は次のように変更されています。$new_hostname" + send_stats "ホスト名が変更されました" sleep 1 else - echo "已退出,未更改主机名。" + echo "終了すると、ホスト名は変更されていません。" break fi done @@ -11606,32 +11834,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "システムの更新ソースを変更します" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "更新ソース領域を選択します" + echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "中国本土のデフォルトソース" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "中国本土の教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "海外起源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -11639,62 +11867,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "タイミングタスク管理" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "タイミングされたタスクリスト" crontab -l echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1。毎月のタスク2。毎週のタスク" + echo "3。毎日のタスク4。時間ごとのタスク" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "時限タスクを追加します" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "削除する必要があるキーワードを入力してください。" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "タイミングタスクを削除します" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "タイミングタスクを編集します" ;; *) break # 跳出循环,退出菜单 @@ -11706,32 +11934,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "ローカルホストの解析" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "ネイティブホストのペルシングリスト" + echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" cat /etc/hosts echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1.新しい解析2を追加します。解析アドレスを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "ローカルホストの解析が追加されました" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "ローカルホストの解析と削除" ;; *) break # 跳出循环,退出菜单 @@ -11742,7 +11970,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -11754,20 +11982,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防衛プログラム$check_docker" + echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" + echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2。SSH傍受記録を表示します" + echo "3。リアルタイムログ監視" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) install_docker @@ -11790,7 +12018,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; *) break @@ -11803,47 +12031,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "電流制限シャットダウン機能" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "電流制限シャットダウン機能" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.shファイルが存在するかどうかを確認してください if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gbの値を取得します local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 新しい仮想メモリサイズを入力します + echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" + read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day cz_day=${cz_day:-1} cd ~ @@ -11856,15 +12084,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "現在の制限シャットダウンが設定されています" + send_stats "現在の制限シャットダウンが設定されています" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "現在の制限シャットダウン関数はオフになっています" ;; *) break @@ -11877,40 +12105,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "秘密キーログイン" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ルート秘密キーログインモード" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "キーペアが生成され、SSHログインのより安全な方法" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "新しいキーを生成します" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "既存の公開キーをインポートします" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "地元の秘密の鍵を表示します" echo "------------------------" - echo "公钥信息" + echo "公開鍵情報" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "秘密のキー情報" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -11926,18 +12154,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "電報警告" + echo "TG-BOTモニタリングと早期警告機能" + echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "しきい値に達した後、ユーザーはユーザーに送信されます" + echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "電報警告が有効になっています" cd ~ install nano tmux bc jq check_crontab_installed @@ -11959,7 +12187,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # 〜/.Profileファイルに追加します if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -11970,21 +12198,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT早期警告システムが開始されました" + echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSHの高リスクの脆弱性を修正します" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12028,7 +12256,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "コマンドラインの履歴" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12046,67 +12274,67 @@ EOF 39) clear - send_stats "命令行历史记录" + send_stats "コマンドラインの履歴" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) ;; 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "メッセージボード" + echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "ワンストップチューニング" + echo "ワンストップシステムの最適化" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "以下が操作され、最適化されます" + echo "1.システムを最新の状態に更新します" + echo "2。システムジャンクファイルをクリーンアップします" + echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "5.すべてのポートを開きます" + echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" + echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "ワンストップチューニングスタート" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12123,25 +12351,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" + echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac @@ -12149,7 +12377,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "システムを再起動します" server_reboot ;; 100) @@ -12165,32 +12393,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "プライバシーとセキュリティ" + echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "現在のステータス:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1。コレクションをオンにします" + echo "2。コレクションを閉じます" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "コレクションが有効になっています" + send_stats "プライバシーとセキュリティコレクションが有効になっています" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "コレクションは閉じた" + send_stats "プライバシーとセキュリティは収集のために閉鎖されています" ;; *) break @@ -12206,11 +12434,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "テックライオンスクリプトをアンインストールします" + echo "テックライオンスクリプトをアンインストールします" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -12218,16 +12446,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "スクリプトはアンインストールされています、さようなら!" break_end clear exit ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -12237,7 +12465,7 @@ EOF ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -12255,187 +12483,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "ファイルマネージャー" while true; do clear - echo "文件管理器" + echo "ファイルマネージャー" echo "------------------------" - echo "当前路径" + echo "現在のパス" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" + echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" + echo "15.ファイルを削除します" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" + echo "25。ファイルを別のサーバーに渡します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "ディレクトリ名を入力してください:" dirname + cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" + send_stats "ディレクトリに移動します" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "作成するにはディレクトリ名を入力してください。" dirname + mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" + send_stats "ディレクトリを作成します" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "ディレクトリ名を入力してください:" dirname + read -e -p "許可を入力してください(755など):" perm + chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ディレクトリ権限を変更します" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "現在のディレクトリ名を入力してください:" current_name + read -e -p "新しいディレクトリ名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" + send_stats "ディレクトリの名前を変更します" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "削除するには、ディレクトリ名を入力してください。" dirname + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" + send_stats "ディレクトリを削除します" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "前のメニューディレクトリに戻ります" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "作成するにはファイル名を入力してください。" filename + touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" + send_stats "ファイルを作成します" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "編集するにはファイル名を入力してください:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "ファイルを編集します" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "ファイル名を入力してください:" filename + read -e -p "許可を入力してください(755など):" perm + chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ファイル権限を変更します" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "現在のファイル名を入力してください:" current_name + read -e -p "新しいファイル名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" + send_stats "ファイルの名前を変更します" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "削除するには、ファイル名を入力してください。" filename + rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" + send_stats "ファイルを削除します" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" + send_stats "圧縮ファイル/ディレクトリ" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "ファイル名(.tar.gz)を入力してください:" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" + send_stats "ファイル/ディレクトリを解凍します" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + send_stats "ファイルまたはディレクトリを移動します" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -Rオプションを使用して、ディレクトリを再帰的にコピーします + cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" + send_stats "ファイルまたはディレクトリをコピーします" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "転送されるファイルパスを入力してください。" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "エラー:ファイルは存在しません。" + send_stats "ファイルの転送に失敗しました:ファイルは存在しません" continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "エラー:リモートサーバーIPを入力してください。" + send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "エラー:リモートサーバーのパスワードを入力してください。" + send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "ログインポートを入力してください(デフォルト22):" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 既知のホストの古いエントリをクリアします ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCPを使用してファイルを転送します scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "スクリプトは最新です$sh_v_new" break_end ~/kejilion.sh exit @@ -12733,15 +12961,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" + send_stats "自動スクリプトの更新をオンにします" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" + send_stats "スクリプト自動更新を閉じます" break_end ;; *) @@ -12763,41 +12991,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" +echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" +echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" +echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" +echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" +echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" +echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" +echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" +echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" +echo -e "${gl_kjlan}13. ${gl_bai}システムツール" +echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" +echo -e "${gl_kjlan}15. ${gl_bai}広告列" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "選択を入力してください:" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "システムの更新" ; linux_update ;; + 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "ワープ管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -12808,13 +13036,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "無効な入力!" ;; esac break_end done @@ -12822,47 +13050,47 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "Kコマンド参照ユースケース" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "以下は、Kコマンドリファレンスユースケースです。" +echo "スクリプトkを開始します" +echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" +echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" +echo "システムKアップデートを更新| Kアップデート" +echo "クリーンシステムガベージkクリーン| kきれい" +echo "システムパネルk dd |を再インストールしますk再インストール" +echo "BBR3コントロールパネルK BBR3 | K BBRV3" +echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" +echo "仮想メモリkスワップ2048を設定します" +echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" +echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" +echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" +echo "SSHリモート接続ツールK SSH | Kリモート接続" +echo "rsyncリモート同期ツールk rsync | Kリモート同期" +echo "ハードディスク管理ツールKディスク| Kハードディスク管理" +echo "イントラネット浸透(サーバー側)K FRP" +echo "イントラネット浸透(クライアント)K FRPC" +echo "ソフトウェアStart K Start SSHD | k sshdを開始します" +echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" +echo "ソフトウェア再起動k再起動sshd | k再起動sshd" +echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" +echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" +echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書の有効期限クエリK SSL PS" +echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" +echo "Docker Container Management K Docker PS | K Dockerコンテナ" +echo "Docker Image Management K Docker IMG | K Docker画像" +echo "LDNMPサイト管理k Web" +echo "LDNMPキャッシュクリーンアップK Webキャッシュ" +echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" +echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" +echo "ロードバランスkロードバランス| kロードバランシングをインストールします" +echo "ファイアウォールパネルk fhq | kファイアウォール" +echo "オープンポートK DKDK 8080 | Kオープンポート8080" +echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" +echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" +echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" } @@ -12870,19 +13098,19 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # パラメーターがない場合は、インタラクティブロジックを実行します kejilion_sh else - # 如果有参数,执行相应函数 + # パラメーターがある場合は、対応する関数を実行します case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "ソフトウェアをインストールします" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "ソフトウェアをアンインストールします" remove "$@" ;; update|更新) @@ -12916,7 +13144,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "タイム付きRSYNC同期" run_task "$@" ;; @@ -12935,7 +13163,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -12948,13 +13176,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "仮想メモリをすばやく設定します" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "タイムゾーンをすばやく設定します" set_timedate "$@" ;; @@ -12998,42 +13226,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "ソフトウェアステータスビュー" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "ソフトウェアスタートアップ" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "ソフトウェアの一時停止" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "ソフトウェアの再起動" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "ソフトウェアが起動します" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "証明書のステータスを確認してください" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" else k_info fi @@ -13043,15 +13271,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Dockerをすばやくインストールします" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "クイックコンテナ管理" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "クイックミラー管理" docker_image ;; *) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 3ee9acbaf..d5967e721 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -7679,7 +7681,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백엔드 로그인 경로 : /admin" + echo "백그라운드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" @@ -8514,7 +8516,10 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의" + echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" + echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9832,7 +9837,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10166,14 +10171,14 @@ linux_panel() { echo "설치" check_docker_app_ip echo "초기 사용자 이름 : 관리자" - echo "初始密码: ChangeMe" + echo "초기 비밀번호 : changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "앱이 업데이트되었습니다" } @@ -10496,7 +10501,7 @@ linux_panel() { docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd docker run -d \ --name libretv \ @@ -10525,7 +10530,7 @@ linux_panel() { docker_rum() { - read -e -p "设置MoonTV的登录密码: " app_passwd + read -e -p "MOONTV 로그인 비밀번호 설정 :" app_passwd docker run -d \ --name moontv \ @@ -10608,8 +10613,8 @@ linux_panel() { docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "설정${docker_name}로그인 사용자 이름 :" app_use + read -e -p "설정${docker_name}로그인 비밀번호 :" app_passwd docker run -d \ --name xunlei \ @@ -10702,11 +10707,11 @@ linux_panel() { install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # 임의의 키와 암호를 생성합니다 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10715,17 +10720,17 @@ linux_panel() { sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 관리자 계정 정보를 추가하십시오 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # 컨테이너를 시작하십시오 docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10735,7 +10740,7 @@ linux_panel() { curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 원래 변수를 유지하십시오 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10752,7 +10757,7 @@ linux_panel() { docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10801,7 +10806,7 @@ linux_panel() { cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10810,12 +10815,231 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "설치" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "앱이 제거되었습니다" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app + + ;; + 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -10828,35 +11052,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "백엔드 작업 공간" + echo -e "백엔드 작업 공간" + echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." + echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." + echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "현재 기존 작업 공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" + echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" + echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" + echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" + echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" + echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" + echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" + echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" + echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" + echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -10864,7 +11088,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -10872,63 +11096,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -10940,21 +11164,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH 거주 모드" + echo -e "SSH 거주 모드${tmux_sshd_status}" + echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 2를 켜십시오. 2를 끕니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "선택을 입력하십시오 :" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "작업 공간을 시작하십시오$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -10970,29 +11194,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "사용자 정의 작업 공간" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "배경 작업 공간에 명령을 주입합니다" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "작업 공간을 삭제합니다" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -11017,54 +11241,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # Send_stats "시스템 도구" + echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" + echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" + echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" + echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" + echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" + echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" + echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "바로 가기 키가 설정되어 있습니다" + send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings done @@ -11072,34 +11296,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "로그인 비밀번호를 설정하십시오" + echo "로그인 비밀번호를 설정하십시오" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "루트 비밀번호 모드" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "PY 버전 관리" + echo "파이썬 버전 관리" + echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" + echo "더 많은 버전 : https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "스크립트 PY 관리" break_end linux_Settings fi @@ -11132,7 +11356,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi @@ -11161,55 +11385,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + send_stats "스크립트 Py 버전을 스위치하십시오" ;; 5) root_use - send_stats "开放端口" + send_stats "포트 열기" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "모든 포트가 열려 있습니다" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSH 포트를 수정하십시오" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 현재 SSH 포트 번호를 읽으십시오 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 현재 SSH 포트 번호를 인쇄하십시오 + echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 + read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port - # 判断端口号是否在有效范围内 + # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH 포트가 수정되었습니다" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSH 포트 수정을 종료하십시오" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "입력이 유효하지 않으므로 번호를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi done @@ -11228,8 +11452,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "신규 사용자는 루트를 비활성화합니다" + read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11244,49 +11468,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6 우선 순위를 설정하십시오" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6 우선 순위를 설정하십시오" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "선호하는 네트워크를 선택하십시오." choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4 우선 순위로 전환되었습니다" + send_stats "IPv4 우선 순위로 전환되었습니다" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6 우선 순위로 전환되었습니다" + send_stats "IPv6 우선 순위로 전환되었습니다" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 마스터 JHB가 제공합니다." + send_stats "IPv6 수정" ;; *) @@ -11304,43 +11528,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "가상 메모리를 설정합니다" while true; do clear - echo "设置虚拟内存" + echo "가상 메모리를 설정합니다" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G 가상 메모리가 설정되었습니다" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G 가상 메모리가 설정되었습니다" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "사용자 정의 가상 메모리가 설정되었습니다" ;; *) @@ -11353,8 +11577,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "사용자 관리" + echo "사용자 목록" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11365,58 +11589,62 @@ EOF echo "" - echo "账户操作" + echo "계정 운영" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." echo "------------------------" - echo "5. 删除账号" + echo "5. 계정을 삭제하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 새로운 사용자에게 허가를 부여하십시오 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - echo "操作已完成。" + install sudo + + echo "작업이 완료되었습니다." ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # 새로운 사용자에게 허가를 부여하십시오 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "삭제하려면 사용자 이름을 입력하십시오." username + # 사용자와 홈 디렉토리를 삭제하십시오 userdel -r "$username" ;; @@ -11429,50 +11657,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "사용자 정보 생성기" + echo "임의의 사용자 이름" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "임의의 사용자 이름$i: $username" done echo "" - echo "随机姓名" + echo "임의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5 개의 임의의 사용자 이름을 생성합니다 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "임의의 사용자 이름$i: $user_name" done echo "" - echo "随机UUID" + echo "무작위 uuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "무작위 uuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" - echo "32位随机密码" + echo "32 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" @@ -11480,46 +11708,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "시간대를 변경하십시오" while true; do clear - echo "系统时间信息" + echo "시스템 시간 정보" - # 获取当前系统时区 + # 현재 시스템 시간대를 얻으십시오 local timezone=$(current_timezone) - # 获取当前系统时间 + # 현재 시스템 시간을 얻으십시오 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # 시간대와 시간을 보여줍니다 + echo "현재 시스템 시간대 :$timezone" + echo "현재 시스템 시간 :$current_time" echo "" - echo "时区切换" + echo "시간대 스위칭" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "아시아" + echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" + echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" + echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" + echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" + echo "9. 태국 방콕에서의 시간" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "유럽" + echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" + echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" + echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "미국" + echo "21. 서양 시간 22. 동부 시간" + echo "23. 캐나다 시간 24. 멕시코 시간" + echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC 글로벌 표준 시간" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -11562,21 +11790,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "호스트 이름을 수정하십시오" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian, Ubuntu, Centos 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11594,11 +11822,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" + send_stats "호스트 이름이 변경되었습니다" sleep 1 else - echo "已退出,未更改主机名。" + echo "종료, 호스트 이름이 변경되지 않았습니다." break fi done @@ -11606,32 +11834,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "시스템 업데이트 소스를 변경하십시오" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "업데이트 소스 영역을 선택하십시오" + echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "중국 본토의 기본 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "중국 본토의 교육 원" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "해외 출신" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "취소" ;; esac @@ -11639,62 +11867,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "타이밍 작업 관리" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "시간이 정한 작업 목록" crontab -l echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. 월간 작업 2. 주간 작업" + echo "3. 일일 작업 4. 시간당 작업" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "선택을 입력하십시오 :" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "시간이 정한 작업을 추가하십시오" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "타이밍 작업을 삭제하십시오" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "타이밍 작업 편집" ;; *) break # 跳出循环,退出菜单 @@ -11706,32 +11934,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "지역 호스트 구문 분석" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "기본 호스트 구문 분석 목록" + echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." cat /etc/hosts echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "로컬 호스트 구문 분석이 추가되었습니다" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "로컬 호스트 구문 분석 및 삭제" ;; *) break # 跳出循环,退出菜单 @@ -11742,7 +11970,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH 방어" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -11754,20 +11982,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH 방어 프로그램$check_docker" + echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" + echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. SSH 차단 레코드보기" + echo "3. 실시간 로그 모니터링" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램을 제거하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) install_docker @@ -11790,7 +12018,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2ban 방어 프로그램은 제거되었습니다" ;; *) break @@ -11803,47 +12031,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "현재 제한 종료 기능" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "현재 제한 종료 기능" + echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.sh 파일이 있는지 확인하십시오 if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gb의 값을 얻으십시오 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 새 가상 메모리 크기를 입력하십시오 + echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." + read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day cz_day=${cz_day:-1} cd ~ @@ -11856,15 +12084,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "전류 제한 종료가 설정되었습니다" + send_stats "전류 제한 종료가 설정되었습니다" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "전류 제한 종료 기능이 꺼졌습니다" ;; *) break @@ -11877,40 +12105,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "개인 키 로그인" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "루트 비공개 키 로그인 모드" + echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "새로운 키를 생성하십시오" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "기존 공개 키를 가져옵니다" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "로컬 비밀 키를보십시오" echo "------------------------" - echo "公钥信息" + echo "공개 키 정보" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "개인 키 정보" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -11926,18 +12154,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "전보 경고" + echo "TG-BOT 모니터링 및 조기 경고 기능" + echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." + echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." + echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "전보 경고가 활성화되었습니다" cd ~ install nano tmux bc jq check_crontab_installed @@ -11959,7 +12187,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # ~/.profile 파일에 추가하십시오 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -11970,21 +12198,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT 조기 경고 시스템이 시작되었습니다" + echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSH에서 고위험 취약점을 수정하십시오" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12028,7 +12256,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "명령 줄 기록" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12046,67 +12274,67 @@ EOF 39) clear - send_stats "命令行历史记录" + send_stats "명령 줄 기록" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) ;; 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "게시판" + echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "원 스톱 튜닝" + echo "원 스톱 시스템 최적화" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "다음은 작동하고 최적화됩니다" + echo "1. 시스템을 최신으로 업데이트하십시오" + echo "2. 시스템 정크 파일 정리" + echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" + echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "5. 모든 포트를 엽니 다" + echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" + echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" + echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "원 스톱 튜닝 시작" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12123,25 +12351,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" + echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac @@ -12149,7 +12377,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "시스템을 다시 시작하십시오" server_reboot ;; 100) @@ -12165,32 +12393,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "개인 정보 및 보안" + echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." + echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "현재 상태 :$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. 수집을 켭니다" + echo "2. 컬렉션을 닫습니다" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "수집이 활성화되었습니다" + send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "컬렉션이 닫혔습니다" + send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" ;; *) break @@ -12206,11 +12434,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "기술 라이온 스크립트를 제거하십시오" + echo "기술 라이온 스크립트를 제거하십시오" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -12218,16 +12446,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "대본은 제거되었습니다." break_end clear exit ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -12237,7 +12465,7 @@ EOF ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -12255,187 +12483,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "파일 관리자" while true; do clear - echo "文件管理器" + echo "파일 관리자" echo "------------------------" - echo "当前路径" + echo "현재 경로" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" + echo "15. 파일을 삭제하십시오" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" + echo "25. 파일을 다른 서버로 전달합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" + send_stats "디렉토리로 이동하십시오" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname + mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" + send_stats "디렉토리를 만듭니다" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "디렉토리 권한을 수정하십시오" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name + read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "디렉토리의 이름을 바꿉니다" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname + rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "디렉토리 삭제" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "이전 메뉴 디렉토리로 돌아갑니다" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "작성하려면 파일 이름을 입력하십시오." filename + touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" + send_stats "파일을 만듭니다" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "편집 할 파일 이름을 입력하십시오." filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "파일 편집" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "파일 이름을 입력하십시오 :" filename + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "파일 권한을 수정하십시오" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "현재 파일 이름을 입력하십시오 :" current_name + read -e -p "새 파일 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "파일의 이름을 바꿉니다" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "삭제하려면 파일 이름을 입력하십시오." filename + rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "파일 삭제" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" + send_stats "압축 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" + send_stats "압축 파일/디렉토리 해제" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" + send_stats "파일 또는 디렉토리를 이동하십시오" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 + cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" + send_stats "파일 또는 디렉토리를 복사합니다" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "오류 : 파일이 존재하지 않습니다." + send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "오류 : 원격 서버 IP를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "오류 : 원격 서버 비밀번호를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 알려진 호스트를위한 오래된 항목을 명확하게합니다 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCP를 사용하여 파일을 전송합니다 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "스크립트는 최신입니다$sh_v_new" break_end ~/kejilion.sh exit @@ -12733,15 +12961,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" + send_stats "자동 스크립트 업데이트를 켜십시오" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" + send_stats "스크립트 자동 업데이트를 닫습니다" break_end ;; *) @@ -12763,41 +12991,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" +echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" -echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" -echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" +echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" +echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" +echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" +echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" +echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" +echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" +echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" +echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" +echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" +echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" +echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" +echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" +echo -e "${gl_kjlan}15. ${gl_bai}광고 열" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "선택을 입력하십시오 :" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; + 3) clear ; send_stats "시스템 정리" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "워프 관리" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -12808,13 +13036,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "잘못된 입력!" ;; esac break_end done @@ -12822,47 +13050,47 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "K 명령 참조 사용 사례" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "다음은 K 명령 참조 유스 케이스입니다." +echo "스크립트 시작 k" +echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" +echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" +echo "업데이트 시스템 K 업데이트 | K 업데이트" +echo "깨끗한 시스템 쓰레기 K Clean | K 청소" +echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" +echo "BBR3 제어판 K BBR3 | K bbrv3" +echo "커널 튜닝 패널 K nhyh | K 커널 최적화" +echo "가상 메모리 K 스왑 2048을 설정하십시오" +echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" +echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" +echo "시스템 백업 기능 K 백업 | K bf | K 백업" +echo "SSH 원격 연결 도구 K SSH | K 원격 연결" +echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" +echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" +echo "인트라넷 침투 (서버 측) K frps" +echo "인트라넷 침투 (클라이언트) K frpc" +echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" +echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" +echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" +echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" +echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" +echo "도메인 이름 인증서 응용 프로그램 K SSL" +echo "도메인 이름 인증서 만료 쿼리 K SSL PS" +echo "도커 환경 설치 K 도커 설치 | K 도커 설치" +echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" +echo "Docker Image Management K Docker img | K Docker Image" +echo "LDNMP 사이트 관리 K 웹" +echo "LDNMP 캐시 정리 K 웹 캐시" +echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" +echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." +echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" +echo "방화벽 패널 K FHQ | K 방화벽" +echo "포트 k dkdk 8080 | k 오픈 포트 8080" +echo "포트 K GBDK 7800 | K 닫기 포트 7800" +echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" +echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" } @@ -12870,19 +13098,19 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 매개 변수가없는 경우 대화식 로직을 실행하십시오 kejilion_sh else - # 如果有参数,执行相应函数 + # 매개 변수가있는 경우 해당 함수를 실행하십시오 case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "소프트웨어를 설치하십시오" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "소프트웨어를 제거하십시오" remove "$@" ;; update|更新) @@ -12916,7 +13144,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "시간이 정한 RSYNC 동기화" run_task "$@" ;; @@ -12935,7 +13163,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -12948,13 +13176,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "가상 메모리를 신속하게 설정했습니다" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "시간대를 빠르게 설정하십시오" set_timedate "$@" ;; @@ -12998,42 +13226,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "소프트웨어 상태보기" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "소프트웨어 시작" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "소프트웨어 일시 정지" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "소프트웨어 재시작" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "소프트웨어 부츠" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "인증서 상태를 확인하십시오" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" else k_info fi @@ -13043,15 +13271,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Docker를 신속하게 설치하십시오" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "빠른 컨테이너 관리" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "빠른 미러 관리" docker_image ;; *) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 40c625d50..527605243 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.6" +sh_v="4.0.7" gl_hui='\e[37m' @@ -1428,7 +1428,9 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' - local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' + # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -8514,7 +8516,10 @@ linux_panel() { echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" + echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9832,7 +9837,7 @@ linux_panel() { docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10810,6 +10815,225 @@ linux_panel() { + 82) + + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 + + docker_rum() { + + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest + + } + + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 83) + + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 + + docker_rum() { + + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest + + } + + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 84) + + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 + + docker_rum() { + + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest + + } + + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 85) + + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" + + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + + docker compose up -d + + clear + echo "已經安裝完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } + + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "應用已卸載" + } + + docker_app_plus + + + ;; + + + 86) + + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 + + docker_rum() { + + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin + + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin + + + } + + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 87) + + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 + + docker_rum() { + + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv + + } + + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 88) + + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 + + docker_rum() { + + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest + + + } + + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app + + ;; + 0) kejilion @@ -11400,6 +11624,8 @@ EOF # 賦予新用戶sudo權限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + install sudo + echo "操作已完成。" ;; @@ -11407,6 +11633,8 @@ EOF read -e -p "請輸入用戶名:" username # 賦予新用戶sudo權限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers + + install sudo ;; 4) read -e -p "請輸入用戶名:" username From d93ae471483312461b34511674d166877002f49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:01:31 +0800 Subject: [PATCH 0045/1285] Update kejilion.sh --- cn/kejilion.sh | 3902 ++++++++++++++++++++++++------------------------ 1 file changed, 1961 insertions(+), 1941 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 65605db4e..a052b0438 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "命令收藏夹" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # 创建备份 create_backup() { @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "应用市场" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "搭建哪吒" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "搭建哪吒" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1. 使用" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1. 使用" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "搭建邮局" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name - } + clear + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + echo "" + echo "端口检测" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + else + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + fi + echo "" - ;; + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "访问地址: " + echo "https://$yuming" + fi - 9) - send_stats "搭建邮局" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + echo "------------------------" + echo "1. 安装 2. 更新 3. 卸载" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice - clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + case $choice in + 1) + check_disk_space 2 + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "先解析这些DNS记录" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "按任意键继续..." + read -n 1 -s -r -p "" + + install jq + install_docker - echo "" - echo "端口检测" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" - else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" - fi - echo "" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已经安装完成" + echo "------------------------" + echo "您可以使用以下地址访问poste.io:" + echo "https://$yuming" + echo "" + + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已经安装完成" + echo "------------------------" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "应用已卸载" + ;; - echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "先解析这些DNS记录" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "按任意键继续..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "poste.io已经安装完成" - echo "------------------------" - echo "您可以使用以下地址访问poste.io:" - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "已经安装完成" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "rocket.chat已经安装完成" + check_docker_app_ip + } - clear - echo "poste.io已经安装完成" - echo "------------------------" - echo "您可以使用以下地址访问poste.io:" - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "应用已卸载" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "已经安装完成" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "rocket.chat已经安装完成" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "应用已卸载" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "应用已卸载" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "应用已卸载" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "搭建雷池" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已经安装完成" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已经更新完成" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "搭建雷池" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已经安装完成" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已经更新完成" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "小雅全家桶" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "小雅全家桶" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名密码均为: admin" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "应用已卸载" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "已经安装完成" - check_docker_app_ip - echo "初始用户名密码均为: admin" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "应用已卸载" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVE开小鸡" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVE开小鸡" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "应用已卸载" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名: admin" + echo "初始密码: ChangeMe" + } - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "应用已更新" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "应用已卸载" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "应用已卸载" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "已经安装完成" - check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "应用已更新" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "应用已卸载" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "应用已卸载" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "应用已卸载" - } + } + + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker_app_plus + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 - ;; + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 - docker_rum() { + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker_rum() { - } + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + } - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - docker_rum() { + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + } - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } - 66) - yt_menu_pro - ;; + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + docker_rum() { - } + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + } - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + docker_rum() { - docker_rum() { + mkdir -p /home/docker/astrbot/data - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + } - } + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + docker_rum() { - docker_rum() { + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - mkdir -p /home/docker/astrbot/data + } - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 72|bitwarden) + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + docker_rum() { - docker_rum() { + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + } - } + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + ;; - 72) - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 - docker_rum() { + 73|libretv) - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - } + docker_rum() { - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + read -e -p "设置LibreTV的登录密码: " app_passwd + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest - ;; + } + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + 74|moontv) - docker_rum() { + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - read -e -p "设置LibreTV的登录密码: " app_passwd + docker_rum() { + + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "设置MoonTV的登录密码: " app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + ghcr.io/senshinya/moontv:latest - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + } + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 75) + ;; - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 - docker_rum() { + 75|melody) - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 + docker_rum() { - } + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + } - ;; - + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 76) - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 + ;; - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest - } + 76|dosgame) - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - ;; - - 77) + } - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + ;; - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + 77|xunlei) - } + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } - 78) + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" + ;; - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) - docker_app_uninstall() { - docker_app_install - } + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_plus - ;; + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } + docker_app_update() { + docker_app_install + } - 79) + docker_app_uninstall() { + docker_app_install + } - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 + docker_app_plus + ;; - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel - } + 79|beszel) - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - ;; + docker_rum() { + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + } - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - # 下载官方 docker-compose 和 env 文件 - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + ;; - # 生成随机密钥与密码 - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - # 追加管理员账号信息 - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # 下载官方 docker-compose 和 env 文件 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 启动容器 - docker compose up -d + # 生成随机密钥与密码 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - clear - echo "已经安装完成" - check_docker_app_ip + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - } + # 追加管理员账号信息 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # 保留原本的变量 - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "应用已卸载" - } + # 启动容器 + docker compose up -d - docker_app_plus + clear + echo "已经安装完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 保留原本的变量 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "应用已卸载" + } + + docker_app_plus - ;; + ;; - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - docker_app_install() { + docker_app_install() { - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - } + } - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - } + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 82) + 82|gpt-load) - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - } + } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 83) + 83|komari) - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - } + } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 84) + 84|wallos) - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip + clear + echo "已经安装完成" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "无效的输入!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "命令行历史记录" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13091,6 +13097,7 @@ echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav |k 命令收藏夹" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "软件状态查看" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "应用$@" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + From 1ce96d4d73f6c265ea8ca6ea889c146c9f470938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:05:11 +0800 Subject: [PATCH 0046/1285] Update kejilion.sh --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a052b0438..60ca8499d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13097,9 +13097,9 @@ echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav |k 命令收藏夹" - - +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } From bfaab5e1290c7ba7d170b7b36191c3ad92e03c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:05:56 +0800 Subject: [PATCH 0047/1285] Update kejilion.sh --- kejilion.sh | 3906 ++++++++++++++++++++++++++------------------------- 1 file changed, 1963 insertions(+), 1943 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 5f6a95541..2d4e3de54 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "命令收藏夹" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # 创建备份 create_backup() { @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "应用市场" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "搭建哪吒" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "搭建哪吒" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1. 使用" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1. 使用" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "搭建邮局" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name - } + clear + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + echo "" + echo "端口检测" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + else + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + fi + echo "" - ;; + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "访问地址: " + echo "https://$yuming" + fi - 9) - send_stats "搭建邮局" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + echo "------------------------" + echo "1. 安装 2. 更新 3. 卸载" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice - clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + case $choice in + 1) + check_disk_space 2 + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "先解析这些DNS记录" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "按任意键继续..." + read -n 1 -s -r -p "" + + install jq + install_docker - echo "" - echo "端口检测" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" - else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" - fi - echo "" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已经安装完成" + echo "------------------------" + echo "您可以使用以下地址访问poste.io:" + echo "https://$yuming" + echo "" + + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已经安装完成" + echo "------------------------" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "应用已卸载" + ;; - echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "先解析这些DNS记录" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "按任意键继续..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "poste.io已经安装完成" - echo "------------------------" - echo "您可以使用以下地址访问poste.io:" - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "已经安装完成" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "rocket.chat已经安装完成" + check_docker_app_ip + } - clear - echo "poste.io已经安装完成" - echo "------------------------" - echo "您可以使用以下地址访问poste.io:" - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "应用已卸载" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "应用已卸载" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "已经安装完成" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "rocket.chat已经安装完成" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "应用已卸载" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "应用已卸载" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "应用已卸载" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "搭建雷池" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已经安装完成" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已经更新完成" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "搭建雷池" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "输入你的选择: " choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已经安装完成" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已经更新完成" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "小雅全家桶" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "小雅全家桶" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名密码均为: admin" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "应用已卸载" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "已经安装完成" - check_docker_app_ip - echo "初始用户名密码均为: admin" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "应用已卸载" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVE开小鸡" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVE开小鸡" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "应用已卸载" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名: admin" + echo "初始密码: ChangeMe" + } - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "应用已更新" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "应用已卸载" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "应用已卸载" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "已经安装完成" - check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "应用已更新" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "应用已卸载" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "应用已卸载" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "应用已卸载" - } + } - docker_app_plus + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - ;; + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - } + docker_rum() { - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + } - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - docker_rum() { + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + } - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } - 66) - yt_menu_pro - ;; + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + docker_rum() { - } + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest + + } - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 + docker_rum() { - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + mkdir -p /home/docker/astrbot/data - docker_rum() { + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + } - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 + docker_rum() { - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - docker_rum() { + } - mkdir -p /home/docker/astrbot/data + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest - } + 72|bitwarden) - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 + docker_rum() { - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - docker_rum() { + } - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + ;; - 72) - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 + 73|libretv) - docker_rum() { + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + docker_rum() { - } + read -e -p "设置LibreTV的登录密码: " app_passwd - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest + } - ;; + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) + 74|moontv) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - docker_rum() { + docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "设置MoonTV的登录密码: " app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + ghcr.io/senshinya/moontv:latest + } - 75) + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 + ;; - docker_rum() { - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + 75|melody) + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 - } + docker_rum() { - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - ;; - + } - 76) + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest + ;; - } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + 76|dosgame) + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 - ;; + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - 77) + } - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + ;; - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + 77|xunlei) - } + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } - 78) + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" + ;; - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) - docker_app_uninstall() { - docker_app_install - } + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_plus - ;; + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } + docker_app_update() { + docker_app_install + } - 79) + docker_app_uninstall() { + docker_app_install + } - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 + docker_app_plus + ;; - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel - } + 79|beszel) - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - ;; + docker_rum() { + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + } - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - # 下载官方 docker-compose 和 env 文件 - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + ;; - # 生成随机密钥与密码 - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - # 追加管理员账号信息 - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # 下载官方 docker-compose 和 env 文件 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 启动容器 - docker compose up -d + # 生成随机密钥与密码 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - clear - echo "已经安装完成" - check_docker_app_ip + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - } + # 追加管理员账号信息 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # 保留原本的变量 - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "应用已卸载" - } + # 启动容器 + docker compose up -d - docker_app_plus + clear + echo "已经安装完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 保留原本的变量 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "应用已卸载" + } + + docker_app_plus - ;; + ;; - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - docker_app_install() { + docker_app_install() { - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - } + } - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - } + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 82) + 82|gpt-load) - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - } + } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 83) + 83|komari) - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - } + } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 84) + 84|wallos) - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip + clear + echo "已经安装完成" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "应用已卸载" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "应用已卸载" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "无效的输入!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "命令行历史记录" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13091,8 +13097,9 @@ echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" - - +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "软件状态查看" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "应用$@" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + From 0ad65beae28e99ad4213f1a205071a4cb586b066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:10:31 +0800 Subject: [PATCH 0048/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 6f035b0e1..5c3bc57e2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1261,4 +1261,9 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增SyncTV一起看片神器的安装及使用, 应用市场新增Owncast自托管直播平台的安装及使用, ------------------------ +2025-08-14 v4.0.8 +应用市场增加快速启动方式 命令行输入 k app 即可启动应用市场 +应用市场增加应用编号快速启动 k app 13 就是13号应用启动,也可以输入应用名称启动 k app dpanel +支持远程命令安装和管理应用,bash <(curl -sL kejilion.sh) app moontv。 +------------------------ From 2c04a4e5f50be5cb4aac194bcabfef61e0ff63a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:11:15 +0800 Subject: [PATCH 0049/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5c3bc57e2..ec42c8f37 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1264,6 +1264,6 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 2025-08-14 v4.0.8 应用市场增加快速启动方式 命令行输入 k app 即可启动应用市场 应用市场增加应用编号快速启动 k app 13 就是13号应用启动,也可以输入应用名称启动 k app dpanel -支持远程命令安装和管理应用,bash <(curl -sL kejilion.sh) app moontv。 +支持远程命令安装和管理应用,bash <(curl -sL kejilion.sh) app moontv | bash <(curl -sL kejilion.sh) app 1panel ------------------------ From 3bc5b40a3e8d58da38dbc91b860f2551d70ffd71 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 14 Aug 2025 10:14:56 +0000 Subject: [PATCH 0050/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-14=2010:14:56?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 3912 +++++++++++++++++++++++------------------------ jp/kejilion.sh | 3914 +++++++++++++++++++++++------------------------ kr/kejilion.sh | 3916 ++++++++++++++++++++++++------------------------ tw/kejilion.sh | 3906 +++++++++++++++++++++++------------------------ 4 files changed, 7864 insertions(+), 7784 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 1ae24ad56..3af7d8ae4 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -4980,7 +4980,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Detected operating systems:$os_name $os_version" + echo "Operating system detected:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -5360,7 +5360,7 @@ Kernel_optimize() { echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "A variety of system parameter tuning modes are provided, and users can choose and switch according to their own usage scenarios." - echo -e "${gl_huang}Tip:${gl_bai}Please use it with caution in the production environment!" + echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" echo "--------------------" echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." echo "2. Balanced optimization mode: Balance between performance and resource consumption, suitable for daily use." @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "Command Favorites" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # Create a backup create_backup() { @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "Application Market" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "Please enter your selection:" sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "Build Nezha" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "Build Nezha" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "Nezha Monitoring$check_docker $update_status" - echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" - echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "Nezha Monitoring$check_docker $update_status" + echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" + echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1. Use" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Enter your choice:" choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1. Use" - echo "------------------------" - echo "0. Return to the previous menu" - echo "------------------------" - read -e -p "Enter your choice:" choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "Build a post office" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name - } + clear + echo -e "Post Office Services$check_docker $update_status" + echo "poste.io is an open source mail server solution." + echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + echo "" + echo "Port detection" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}port$portCurrently available${gl_bai}" + else + echo -e "${gl_hong}port$portNot currently available${gl_bai}" + fi + echo "" - ;; + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "Access address:" + echo "https://$yuming" + fi - 9) - send_stats "Build a post office" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + echo "------------------------" + echo "1. Install 2. Update 3. Uninstall" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Enter your choice:" choice - clear - echo -e "Post Office Services$check_docker $update_status" - echo "poste.io is an open source mail server solution." - echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + case $choice in + 1) + check_disk_space 2 + read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "Parse these DNS records first" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "Press any key to continue..." + read -n 1 -s -r -p "" + + install jq + install_docker - echo "" - echo "Port detection" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}port$portCurrently available${gl_bai}" - else - echo -e "${gl_hong}port$portNot currently available${gl_bai}" - fi - echo "" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io has been installed" + echo "------------------------" + echo "You can access poste.io using the following address:" + echo "https://$yuming" + echo "" + + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "Access address:" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io has been installed" + echo "------------------------" + echo "You can access poste.io using the following address:" echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "The app has been uninstalled" + ;; - echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" - echo "------------------------" - echo "0. Return to the previous menu" - echo "------------------------" - read -e -p "Enter your choice:" choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "Parse these DNS records first" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "Press any key to continue..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "poste.io has been installed" - echo "------------------------" - echo "You can access poste.io using the following address:" - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "Installed" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "rocket.chat has been installed" + check_docker_app_ip + } - clear - echo "poste.io has been installed" - echo "------------------------" - echo "You can access poste.io using the following address:" - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "The app has been uninstalled" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "Installed" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "rocket.chat has been installed" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "The app has been uninstalled" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "The app has been uninstalled" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "Installed" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "The app has been uninstalled" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "Build a Thunder Pool" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "Thunder Pool Service$check_docker" + echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." + echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1. Install 2. Update 3. Reset Password 4. Uninstall" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Enter your choice:" choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "The Thunder Pool WAF panel has been installed" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "Thunder Pool WAF panel has been updated" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "Build a Thunder Pool" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "Thunder Pool Service$check_docker" - echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." - echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1. Install 2. Update 3. Reset Password 4. Uninstall" - echo "------------------------" - echo "0. Return to the previous menu" - echo "------------------------" - read -e -p "Enter your choice:" choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "The Thunder Pool WAF panel has been installed" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "Thunder Pool WAF panel has been updated" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "Xiaoya Family Bucket" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "Xiaoya Family Bucket" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "Installed" + check_docker_app_ip + echo "The initial username and password are: admin" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "The app has been uninstalled" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "Installed" - check_docker_app_ip - echo "The initial username and password are: admin" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "The app has been uninstalled" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVE Chicken" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVE Chicken" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "The app has been uninstalled" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "Installed" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "Installed" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "The app has been uninstalled" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "The app has been uninstalled" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "Installed" + check_docker_app_ip + echo "Initial username: admin" + echo "Initial password: ChangeMe" + } - docker compose up -d - clear - echo "Installed" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "Installed" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "The app has been updated" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "The app has been uninstalled" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "The app has been uninstalled" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "Installed" - check_docker_app_ip - echo "Initial username: admin" - echo "Initial password: ChangeMe" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "The app has been updated" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "The app has been uninstalled" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "The app has been uninstalled" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "Installed" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "The app has been uninstalled" - } + } - docker_app_plus + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - ;; + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - } + docker_rum() { - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + } - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - docker_rum() { + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + } - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } - 66) - yt_menu_pro - ;; + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + docker_rum() { - } + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest + + } - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 + docker_rum() { - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + mkdir -p /home/docker/astrbot/data - docker_rum() { + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + } - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 + docker_rum() { - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - docker_rum() { + } - mkdir -p /home/docker/astrbot/data + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest - } + 72|bitwarden) - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 + docker_rum() { - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - docker_rum() { + } - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + ;; - 72) - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 + 73|libretv) - docker_rum() { + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + docker_rum() { - } + read -e -p "Set the LibreTV login password:" app_passwd - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest + } - ;; + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) + 74|moontv) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - docker_rum() { + docker_rum() { - read -e -p "Set the LibreTV login password:" app_passwd + read -e -p "Set the MoonTV login password:" app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "Set the MoonTV login password:" app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + ghcr.io/senshinya/moontv:latest + } - 75) + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 + ;; - docker_rum() { - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + 75|melody) + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 - } + docker_rum() { - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - ;; - + } - 76) + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest + ;; - } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + 76|dosgame) + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 - ;; + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - 77) + } - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - docker_rum() { - read -e -p "set up${docker_name}Login username:" app_use - read -e -p "set up${docker_name}Login password:" app_passwd + ;; - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + 77|xunlei) - } + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + read -e -p "set up${docker_name}Login username:" app_use + read -e -p "set up${docker_name}Login password:" app_passwd + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } - 78) + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" + ;; - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) - docker_app_uninstall() { - docker_app_install - } + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_plus - ;; + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } + docker_app_update() { + docker_app_install + } - 79) + docker_app_uninstall() { + docker_app_install + } - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 + docker_app_plus + ;; - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel - } + 79|beszel) - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - ;; + docker_rum() { + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + } - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - # Download the official docker-compose and env files - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + ;; - # Generate random keys and passwords - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - # Add administrator account information - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # Download the official docker-compose and env files + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # Start the container - docker compose up -d + # Generate random keys and passwords + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - clear - echo "Installed" - check_docker_app_ip + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - } + # Add administrator account information + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # Keep the original variable - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "The app has been uninstalled" - } + # Start the container + docker compose up -d - docker_app_plus + clear + echo "Installed" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # Keep the original variable + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "The app has been uninstalled" + } + + docker_app_plus - ;; + ;; - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - docker_app_install() { + docker_app_install() { - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - } + } - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - } + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "The app has been uninstalled" - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "The app has been uninstalled" + } - docker_app_plus + docker_app_plus - ;; + ;; - 82) + 82|gpt-load) - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - } + } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 83) + 83|komari) - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - } + } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 84) + 84|wallos) - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "Installed" - check_docker_app_ip + clear + echo "Installed" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "The app has been uninstalled" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "The app has been uninstalled" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "Invalid input!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -11957,7 +11964,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "Command line history" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13091,8 +13097,9 @@ echo "Open port k dkdk 8080 |k Open port 8080" echo "Close port k gbdk 7800 |k Close port 7800" echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" - - +echo "Command favorites k fav | k command favorites" +echo "App Market Management k app" +echo "Application number quick management k app 26 | k app 1panel | k app npm" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "Software status view" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "Apply $@" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + diff --git a/jp/kejilion.sh b/jp/kejilion.sh index ad6c57515..6c0e6868c 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -285,7 +285,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1サービスは再開されました。" else - echo "错误:重启 $1サービスは失敗しました。" + echo "エラー:再起動$1サービスは失敗しました。" fi } @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "コマンドのお気に入り" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # バックアップを作成します create_backup() { @@ -6359,7 +6362,7 @@ schedule_task() { # 同じタスクが既に存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then - echo "エラー:このタスクのタイミング同期はすでに存在しています!" + echo "错误: 该任务的定时同步已存在!" return fi @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "アプリケーション市場" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "ネザを作る" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "ネザを作る" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "Nezhaの監視$check_docker $update_status" - echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" - echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "Nezhaの監視$check_docker $update_status" + echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" + echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1。使用します" + echo "------------------------" + echo "0。前のメニューに戻ります" + echo "------------------------" + read -e -p "あなたの選択を入力してください:" choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1。使用します" - echo "------------------------" - echo "0。前のメニューに戻ります" - echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "郵便局を建設します" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name - } + clear + echo -e "郵便局サービス$check_docker $update_status" + echo "Poste.ioはオープンソースメールサーバーソリューションです。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + echo "" + echo "ポート検出" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" + else + echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" + fi + echo "" - ;; + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "アクセスアドレス:" + echo "https://$yuming" + fi - 9) - send_stats "郵便局を建設します" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + echo "------------------------" + echo "1。インストール2。更新3。アンインストール" + echo "------------------------" + echo "0。前のメニューに戻ります" + echo "------------------------" + read -e -p "あなたの選択を入力してください:" choice - clear - echo -e "郵便局サービス$check_docker $update_status" - echo "Poste.ioはオープンソースメールサーバーソリューションです。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + case $choice in + 1) + check_disk_space 2 + read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "これらのDNSレコードを最初に解析します" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "任意のキーを押して続行します..." + read -n 1 -s -r -p "" + + install jq + install_docker - echo "" - echo "ポート検出" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" - else - echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" - fi - echo "" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "Poste.ioがインストールされています" + echo "------------------------" + echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "https://$yuming" + echo "" + + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "アクセスアドレス:" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "Poste.ioがインストールされています" + echo "------------------------" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "アプリはアンインストールされています" + ;; - echo "------------------------" - echo "1。インストール2。更新3。アンインストール" - echo "------------------------" - echo "0。前のメニューに戻ります" - echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "これらのDNSレコードを最初に解析します" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "任意のキーを押して続行します..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "Poste.ioがインストールされています" - echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "インストール" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "Rocket.chatがインストールされています" + check_docker_app_ip + } - clear - echo "Poste.ioがインストールされています" - echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "アプリはアンインストールされています" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "インストール" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "Rocket.chatがインストールされています" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "アプリはアンインストールされています" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "アプリはアンインストールされています" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "インストール" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "アプリはアンインストールされています" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "サンダープールを構築します" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "サンダープールサービス$check_docker" + echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" + echo "------------------------" + echo "0。前のメニューに戻ります" + echo "------------------------" + read -e -p "あなたの選択を入力してください:" choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "サンダープールWAFパネルがインストールされています" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "サンダープールWAFパネルが更新されました" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "サンダープールを構築します" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "サンダープールサービス$check_docker" - echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" - echo "------------------------" - echo "0。前のメニューに戻ります" - echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "サンダープールWAFパネルがインストールされています" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "サンダープールWAFパネルが更新されました" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "Xiaoyaファミリーバケット" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "Xiaoyaファミリーバケット" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "インストール" + check_docker_app_ip + echo "最初のユーザー名とパスワードは次のとおりです" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "アプリはアンインストールされています" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "インストール" - check_docker_app_ip - echo "最初のユーザー名とパスワードは次のとおりです" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "アプリはアンインストールされています" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVEチキン" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVEチキン" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "アプリはアンインストールされています" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "インストール" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "インストール" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "アプリはアンインストールされています" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "アプリはアンインストールされています" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "インストール" + check_docker_app_ip + echo "初期ユーザー名:admin" + echo "最初のパスワード:changeme" + } - docker compose up -d - clear - echo "インストール" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "インストール" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "アプリが更新されました" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "アプリはアンインストールされています" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "アプリはアンインストールされています" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "インストール" - check_docker_app_ip - echo "初期ユーザー名:admin" - echo "最初のパスワード:changeme" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "アプリが更新されました" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "アプリはアンインストールされています" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "アプリはアンインストールされています" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "インストール" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" - } + } - docker_app_plus + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - ;; + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - } + docker_rum() { - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + } - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - docker_rum() { + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + } - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } - 66) - yt_menu_pro - ;; + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + docker_rum() { - } + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest + + } - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 + docker_rum() { - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + mkdir -p /home/docker/astrbot/data - docker_rum() { + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + } - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 + docker_rum() { - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - docker_rum() { + } - mkdir -p /home/docker/astrbot/data + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest - } + 72|bitwarden) - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 + docker_rum() { - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - docker_rum() { + } - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + ;; - 72) - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 + 73|libretv) - docker_rum() { + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + docker_rum() { - } + read -e -p "libretvログインパスワードを設定します。" app_passwd - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest + } - ;; + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) + 74|moontv) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - docker_rum() { + docker_rum() { - read -e -p "libretvログインパスワードを設定します。" app_passwd + read -e -p "MOONTVログインパスワードを設定します。" app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "MOONTVログインパスワードを設定します。" app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + ghcr.io/senshinya/moontv:latest + } - 75) + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 + ;; - docker_rum() { - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + 75|melody) + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 - } + docker_rum() { - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - ;; - + } - 76) + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest + ;; - } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + 76|dosgame) + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 - ;; + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - 77) + } - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - docker_rum() { - read -e -p "設定${docker_name}ログインユーザー名:" app_use - read -e -p "設定${docker_name}ログインパスワード:" app_passwd + ;; - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + 77|xunlei) - } + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + read -e -p "設定${docker_name}ログインユーザー名:" app_use + read -e -p "設定${docker_name}ログインパスワード:" app_passwd + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } - 78) + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" + ;; - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) - docker_app_uninstall() { - docker_app_install - } + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_plus - ;; + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } + docker_app_update() { + docker_app_install + } - 79) + docker_app_uninstall() { + docker_app_install + } - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 + docker_app_plus + ;; - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel - } + 79|beszel) - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - ;; + docker_rum() { + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + } - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - # 公式のDocker-ComposeおよびEnvファイルをダウンロードします - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + ;; - # ランダムキーとパスワードを生成します - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - # 管理者アカウント情報を追加します - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # コンテナを起動します - docker compose up -d + # ランダムキーとパスワードを生成します + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - clear - echo "インストール" - check_docker_app_ip + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - } + # 管理者アカウント情報を追加します + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # 元の変数を保持します - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "アプリはアンインストールされています" - } + # コンテナを起動します + docker compose up -d - docker_app_plus + clear + echo "インストール" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 元の変数を保持します + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "アプリはアンインストールされています" + } + + docker_app_plus - ;; + ;; - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - docker_app_install() { + docker_app_install() { - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - } + } - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - } + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "アプリはアンインストールされています" - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "アプリはアンインストールされています" + } - docker_app_plus + docker_app_plus - ;; + ;; - 82) + 82|gpt-load) - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - } + } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 83) + 83|komari) - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - } + } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 84) + 84|wallos) - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "インストール" - check_docker_app_ip + clear + echo "インストール" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "アプリはアンインストールされています" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "アプリはアンインストールされています" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "無効な入力!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -11957,7 +11964,7 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost + read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts send_stats "ローカルホストの解析と削除" ;; @@ -12158,7 +12165,7 @@ EOF echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" read -e -p "必ず続行しますか? (y/n):" choice @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "コマンドラインの履歴" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13091,8 +13097,9 @@ echo "オープンポートK DKDK 8080 | Kオープンポート8080" echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" - - +echo "コマンドお気に入りk fav | Kコマンドのお気に入り" +echo "アプリ市場管理Kアプリ" +echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "ソフトウェアステータスビュー" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "$@を適用します" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d5967e721..9822eb994 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1664,7 +1664,7 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트합니다 + # 캐시 청소 여부를 사용자에게 프롬프트하십시오 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" @@ -4980,7 +4980,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "감지 된 운영 체제 :$os_name $os_version" + echo "운영 체제 감지 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "명령 즐겨 찾기" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # 백업을 만듭니다 create_backup() { @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "응용 프로그램 시장" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택을 입력하십시오 :" sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "Nezha를 구축하십시오" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "Nezha를 구축하십시오" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "Nezha 모니터링$check_docker $update_status" - echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" - echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "Nezha 모니터링$check_docker $update_status" + echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" + echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1. 사용" + echo "------------------------" + echo "0. 이전 메뉴로 돌아갑니다" + echo "------------------------" + read -e -p "선택을 입력하십시오 :" choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1. 사용" - echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" - echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "우체국을 건설하십시오" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name + + clear + echo -e "우체국 서비스$check_docker $update_status" + echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" - } + echo "" + echo "포트 감지" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" + else + echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" + fi + echo "" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "액세스 주소 :" + echo "https://$yuming" + fi - ;; + echo "------------------------" + echo "1. 설치 2. 업데이트 3. 제거" + echo "------------------------" + echo "0. 이전 메뉴로 돌아갑니다" + echo "------------------------" + read -e -p "선택을 입력하십시오 :" choice - 9) - send_stats "우체국을 건설하십시오" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + case $choice in + 1) + check_disk_space 2 + read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "이 DNS 레코드를 먼저 구문 분석하십시오" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "계속하려면 키를 누르십시오 ..." + read -n 1 -s -r -p "" + + install jq + install_docker - clear - echo -e "우체국 서비스$check_docker $update_status" - echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "Poste.io가 설치되었습니다" + echo "------------------------" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "https://$yuming" + echo "" - echo "" - echo "포트 감지" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" - else - echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" - fi - echo "" + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "액세스 주소 :" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "Poste.io가 설치되었습니다" + echo "------------------------" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "앱이 제거되었습니다" + ;; - echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" - echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" - echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "이 DNS 레코드를 먼저 구문 분석하십시오" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "계속하려면 키를 누르십시오 ..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "Poste.io가 설치되었습니다" - echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "설치" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "Rocket.chat이 설치되었습니다" + check_docker_app_ip + } - clear - echo "Poste.io가 설치되었습니다" - echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "앱이 제거되었습니다" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "설치" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "Rocket.chat이 설치되었습니다" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "앱이 제거되었습니다" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "앱이 제거되었습니다" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "설치" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "앱이 제거되었습니다" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "천둥 수영장을 건설하십시오" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "썬더 풀 서비스$check_docker" + echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" + echo "------------------------" + echo "0. 이전 메뉴로 돌아갑니다" + echo "------------------------" + read -e -p "선택을 입력하십시오 :" choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "Thunder Pool WAF 패널이 설치되었습니다" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "Thunder Pool WAF 패널이 업데이트되었습니다" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "천둥 수영장을 건설하십시오" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "썬더 풀 서비스$check_docker" - echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" - echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" - echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "Thunder Pool WAF 패널이 설치되었습니다" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "Thunder Pool WAF 패널이 업데이트되었습니다" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "Xiaoya 가족 버킷" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "Xiaoya 가족 버킷" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "설치" + check_docker_app_ip + echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "앱이 제거되었습니다" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "설치" - check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "앱이 제거되었습니다" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVE 치킨" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVE 치킨" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "앱이 제거되었습니다" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "설치" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "설치" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "앱이 제거되었습니다" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "앱이 제거되었습니다" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "설치" + check_docker_app_ip + echo "초기 사용자 이름 : 관리자" + echo "초기 비밀번호 : changeme" + } - docker compose up -d - clear - echo "설치" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "설치" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "앱이 업데이트되었습니다" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "앱이 제거되었습니다" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "앱이 제거되었습니다" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "설치" - check_docker_app_ip - echo "초기 사용자 이름 : 관리자" - echo "초기 비밀번호 : changeme" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "앱이 업데이트되었습니다" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "앱이 제거되었습니다" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "앱이 제거되었습니다" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "설치" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "앱이 제거되었습니다" - } + } - docker_app_plus + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - ;; + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - } + docker_rum() { - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 - docker_rum() { + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + } - } + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - 66) - yt_menu_pro - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - } + docker_rum() { - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } + } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + mkdir -p /home/docker/astrbot/data - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - } + } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/astrbot/data + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest + } - } + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 72|bitwarden) - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 - docker_rum() { + docker_rum() { - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - } + } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 72) + ;; - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 - docker_rum() { - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + 73|libretv) - } + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { + read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd - ;; + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest + } + + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + 74|moontv) - docker_rum() { + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd + docker_rum() { + + read -e -p "MOONTV 로그인 비밀번호 설정 :" app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "MOONTV 로그인 비밀번호 설정 :" app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + ghcr.io/senshinya/moontv:latest - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + } + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 75) + ;; - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 - docker_rum() { + 75|melody) - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 + docker_rum() { - } + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + } - ;; - + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 76) - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 + ;; - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest - } + 76|dosgame) - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - ;; + } - 77) + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 - docker_rum() { + ;; - read -e -p "설정${docker_name}로그인 사용자 이름 :" app_use - read -e -p "설정${docker_name}로그인 비밀번호 :" app_passwd + 77|xunlei) - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - } + docker_rum() { - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + read -e -p "설정${docker_name}로그인 사용자 이름 :" app_use + read -e -p "설정${docker_name}로그인 비밀번호 :" app_passwd - ;; + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - 78) + ;; - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_uninstall() { - docker_app_install - } + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } - docker_app_plus - ;; + docker_app_update() { + docker_app_install + } + docker_app_uninstall() { + docker_app_install + } - 79) + docker_app_plus + ;; - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel + 79|beszel) - } + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel + } - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + ;; - # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 암호를 생성합니다 - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 관리자 계정 정보를 추가하십시오 - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # 임의의 키와 암호를 생성합니다 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - # 컨테이너를 시작하십시오 - docker compose up -d + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - clear - echo "설치" - check_docker_app_ip + # 관리자 계정 정보를 추가하십시오 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # 원래 변수를 유지하십시오 - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + # 컨테이너를 시작하십시오 + docker compose up -d - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다" - } + clear + echo "설치" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 원래 변수를 유지하십시오 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "앱이 제거되었습니다" + } + + docker_app_plus - docker_app_plus + ;; - ;; + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + docker_app_install() { - docker_app_install() { + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + } - } + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + } - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "앱이 제거되었습니다" + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다" - } + docker_app_plus - docker_app_plus + ;; - ;; + 82|gpt-load) - 82) + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + docker_rum() { - docker_rum() { + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + } - } + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; + 83|komari) - 83) + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + docker_rum() { - docker_rum() { + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + } - } + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; + 84|wallos) - 84) + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + docker_rum() { - docker_rum() { + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest - - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "설치" - check_docker_app_ip + clear + echo "설치" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "앱이 제거되었습니다" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "앱이 제거되었습니다" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "잘못된 입력!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -11957,7 +11964,7 @@ EOF ;; 2) - read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost + read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "명령 줄 기록" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13058,7 +13064,7 @@ echo "스크립트 시작 k" echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" echo "업데이트 시스템 K 업데이트 | K 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | K 청소" +echo "깨끗한 시스템 쓰레기 K Clean | k 청소" echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" echo "BBR3 제어판 K BBR3 | K bbrv3" echo "커널 튜닝 패널 K nhyh | K 커널 최적화" @@ -13091,8 +13097,9 @@ echo "포트 k dkdk 8080 | k 오픈 포트 8080" echo "포트 K GBDK 7800 | K 닫기 포트 7800" echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" - - +echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" +echo "앱 시장 관리 K 앱" +echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "소프트웨어 상태보기" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "$@ 적용" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 527605243..fbbe65333 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.7" +sh_v="4.0.8" gl_hui='\e[37m' @@ -5648,7 +5648,10 @@ linux_trash() { done } - +linux_fav() { +send_stats "命令收藏夾" +bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) +} # 創建備份 create_backup() { @@ -8449,10 +8452,12 @@ linux_ldnmp() { linux_panel() { +local sub_choice="$1" +while true; do - while true; do + if [ -z "$sub_choice" ]; then clear echo -e "應用市場" echo -e "${gl_kjlan}------------------------" @@ -8524,2527 +8529,2529 @@ linux_panel() { echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice + fi - case $sub_choice in - 1) + case $sub_choice in + 1|bt) - local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" - local panelurl="https://www.bt.cn/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="宝塔面板" + local panelurl="https://www.bt.cn/new/index.html" - panel_app_install() { - if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec - } + panel_app_install() { + if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 2) + ;; + 2|aapanel) - local lujing="[ -d "/www/server/panel" ]" - local panelname="aapanel" - local panelurl="https://www.aapanel.com/new/index.html" + local lujing="[ -d "/www/server/panel" ]" + local panelname="aapanel" + local panelurl="https://www.aapanel.com/new/index.html" - panel_app_install() { - URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel - } + panel_app_install() { + URL=https://www.aapanel.com/script/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_7.0_en.sh "$URL";fi;bash install_7.0_en.sh aapanel + } - panel_app_manage() { - bt - } + panel_app_manage() { + bt + } - panel_app_uninstall() { - curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh - chmod +x bt-uninstall.sh - ./bt-uninstall.sh - } + panel_app_uninstall() { + curl -o bt-uninstall.sh http://download.bt.cn/install/bt-uninstall.sh > /dev/null 2>&1 && chmod +x bt-uninstall.sh && ./bt-uninstall.sh + chmod +x bt-uninstall.sh + ./bt-uninstall.sh + } - install_panel + install_panel - ;; - 3) + ;; + 3|1panel) - local lujing="command -v 1pctl" - local panelname="1Panel" - local panelurl="https://1panel.cn/" + local lujing="command -v 1pctl" + local panelname="1Panel" + local panelurl="https://1panel.cn/" - panel_app_install() { - install bash - bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" - } + panel_app_install() { + install bash + bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" + } - panel_app_manage() { - 1pctl user-info - 1pctl update password - } + panel_app_manage() { + 1pctl user-info + 1pctl update password + } - panel_app_uninstall() { - 1pctl uninstall - } + panel_app_uninstall() { + 1pctl uninstall + } - install_panel + install_panel - ;; - 4) + ;; + 4|npm) - local docker_name="npm" - local docker_img="jc21/nginx-proxy-manager:latest" - local docker_port=81 + local docker_name="npm" + local docker_img="jc21/nginx-proxy-manager:latest" + local docker_port=81 - docker_rum() { + docker_rum() { - docker run -d \ - --name=$docker_name \ - -p ${docker_port}:81 \ - -p 80:80 \ - -p 443:443 \ - -v /home/docker/npm/data:/data \ - -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ - --restart=always \ - $docker_img + docker run -d \ + --name=$docker_name \ + -p ${docker_port}:81 \ + -p 80:80 \ + -p 443:443 \ + -v /home/docker/npm/data:/data \ + -v /home/docker/npm/letsencrypt:/etc/letsencrypt \ + --restart=always \ + $docker_img - } + } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" - local app_size="1" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" + local app_size="1" - docker_app + docker_app - ;; + ;; - 5) + 5|openlist) - local docker_name="openlist" - local docker_img="openlistteam/openlist:latest-aria2" - local docker_port=5244 + local docker_name="openlist" + local docker_img="openlistteam/openlist:latest-aria2" + local docker_port=5244 - docker_rum() { + docker_rum() { - docker run -d \ - --restart=always \ - -v /home/docker/openlist:/opt/openlist/data \ - -p ${docker_port}:5244 \ - -e PUID=0 \ - -e PGID=0 \ - -e UMASK=022 \ - --name="openlist" \ - openlistteam/openlist:latest-aria2 + docker run -d \ + --restart=always \ + -v /home/docker/openlist:/opt/openlist/data \ + -p ${docker_port}:5244 \ + -e PUID=0 \ + -e PGID=0 \ + -e UMASK=022 \ + --name="openlist" \ + openlistteam/openlist:latest-aria2 - } + } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_use="docker exec -it openlist ./openlist admin random" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 6) + 6|webtop-ubuntu) - local docker_name="webtop-ubuntu" - local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" - local docker_port=3006 + local docker_name="webtop-ubuntu" + local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" + local docker_port=3006 - docker_rum() { + docker_rum() { - docker run -d \ - --name=webtop-ubuntu \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:ubuntu-kde + docker run -d \ + --name=webtop-ubuntu \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=ubuntu-abc \ + -e PASSWORD=ubuntuABC123 \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:ubuntu-kde - } + } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" - local app_size="2" - docker_app + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: ubuntu-abc\"" + local docker_passwd="echo \"密码: ubuntuABC123\"" + local app_size="2" + docker_app - ;; - 7) + ;; + 7|nezha) + clear + send_stats "搭建哪吒" + local docker_name="nezha-dashboard" + local docker_port=8008 + while true; do + check_docker_app + check_docker_image_update $docker_name clear - send_stats "搭建哪吒" - local docker_name="nezha-dashboard" - local docker_port=8008 - while true; do - check_docker_app - check_docker_image_update $docker_name - clear - echo -e "哪吒監控$check_docker $update_status" - echo "開源、輕量、易用的服務器監控與運維工具" - echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + echo -e "哪吒監控$check_docker $update_status" + echo "開源、輕量、易用的服務器監控與運維工具" + echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) + check_docker_app_ip + fi + echo "" + echo "------------------------" + echo "1. 使用" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "輸入你的選擇:" choice + + case $choice in + 1) + check_disk_space 1 + install unzip jq + install_docker + curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip - fi - echo "" - echo "------------------------" - echo "1. 使用" - echo "------------------------" - echo "0. 返回上一級選單" - echo "------------------------" - read -e -p "輸入你的選擇:" choice + ;; - case $choice in - 1) - check_disk_space 1 - install unzip jq - install_docker - curl -sL ${gh_proxy}raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && ./nezha.sh - local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) - check_docker_app_ip - ;; + *) + break + ;; - *) - break - ;; + esac + break_end + done + ;; - esac - break_end - done - ;; + 8|qb) + + local docker_name="qbittorrent" + local docker_img="lscr.io/linuxserver/qbittorrent:latest" + local docker_port=8081 + + docker_rum() { + + docker run -d \ + --name=qbittorrent \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e WEBUI_PORT=${docker_port} \ + -e TORRENTING_PORT=56881 \ + -p ${docker_port}:${docker_port} \ + -p 56881:56881 \ + -p 56881:56881/udp \ + -v /home/docker/qbittorrent/config:/config \ + -v /home/docker/qbittorrent/downloads:/downloads \ + --restart unless-stopped \ + lscr.io/linuxserver/qbittorrent:latest - 8) + } - local docker_name="qbittorrent" - local docker_img="lscr.io/linuxserver/qbittorrent:latest" - local docker_port=8081 + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_use="sleep 3" + local docker_passwd="docker logs qbittorrent" + local app_size="1" + docker_app - docker_rum() { + ;; - docker run -d \ - --name=qbittorrent \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e WEBUI_PORT=${docker_port} \ - -e TORRENTING_PORT=56881 \ - -p ${docker_port}:${docker_port} \ - -p 56881:56881 \ - -p 56881:56881/udp \ - -v /home/docker/qbittorrent/config:/config \ - -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ - lscr.io/linuxserver/qbittorrent:latest + 9|mail) + send_stats "搭建郵局" + clear + install telnet + local docker_name=“mailserver” + while true; do + check_docker_app + check_docker_image_update $docker_name - } + clear + echo -e "郵局服務$check_docker $update_status" + echo "poste.io 是一個開源的郵件服務器解決方案," + echo "視頻介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" - local docker_use="sleep 3" - local docker_passwd="docker logs qbittorrent" - local app_size="1" - docker_app + echo "" + echo "端口檢測" + port=25 + timeout=3 + if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then + echo -e "${gl_lv}端口$port當前可用${gl_bai}" + else + echo -e "${gl_hong}端口$port當前不可用${gl_bai}" + fi + echo "" - ;; + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + yuming=$(cat /home/docker/mail.txt) + echo "訪問地址:" + echo "https://$yuming" + fi - 9) - send_stats "搭建郵局" - clear - install telnet - local docker_name=“mailserver” - while true; do - check_docker_app - check_docker_image_update $docker_name + echo "------------------------" + echo "1. 安裝 2. 更新 3. 卸載" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "輸入你的選擇:" choice - clear - echo -e "郵局服務$check_docker $update_status" - echo "poste.io 是一個開源的郵件服務器解決方案," - echo "視頻介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + case $choice in + 1) + check_disk_space 2 + read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming + mkdir -p /home/docker + echo "$yuming" > /home/docker/mail.txt + echo "------------------------" + ip_address + echo "先解析這些DNS記錄" + echo "A mail $ipv4_address" + echo "CNAME imap $yuming" + echo "CNAME pop $yuming" + echo "CNAME smtp $yuming" + echo "MX @ $yuming" + echo "TXT @ v=spf1 mx ~all" + echo "TXT ? ?" + echo "" + echo "------------------------" + echo "按任意鍵繼續..." + read -n 1 -s -r -p "" + + install jq + install_docker - echo "" - echo "端口檢測" - port=25 - timeout=3 - if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口$port當前可用${gl_bai}" - else - echo -e "${gl_hong}端口$port當前不可用${gl_bai}" - fi - echo "" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.io + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已經安裝完成" + echo "------------------------" + echo "您可以使用以下地址訪問poste.io:" + echo "https://$yuming" + echo "" + + ;; - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + 2) + docker rm -f mailserver + docker rmi -f analogic/poste.i yuming=$(cat /home/docker/mail.txt) - echo "訪問地址:" + docker run \ + --net=host \ + -e TZ=Europe/Prague \ + -v /home/docker/mail:/data \ + --name "mailserver" \ + -h "$yuming" \ + --restart=always \ + -d analogic/poste.i + + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + clear + echo "poste.io已經安裝完成" + echo "------------------------" + echo "您可以使用以下地址訪問poste.io:" echo "https://$yuming" - fi + echo "" + ;; + 3) + docker rm -f mailserver + docker rmi -f analogic/poste.io + rm /home/docker/mail.txt + rm -rf /home/docker/mail + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "應用已卸載" + ;; - echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" - echo "------------------------" - echo "0. 返回上一級選單" - echo "------------------------" - read -e -p "輸入你的選擇:" choice + *) + break + ;; - case $choice in - 1) - check_disk_space 2 - read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming - mkdir -p /home/docker - echo "$yuming" > /home/docker/mail.txt - echo "------------------------" - ip_address - echo "先解析這些DNS記錄" - echo "A mail $ipv4_address" - echo "CNAME imap $yuming" - echo "CNAME pop $yuming" - echo "CNAME smtp $yuming" - echo "MX @ $yuming" - echo "TXT @ v=spf1 mx ~all" - echo "TXT ? ?" - echo "" - echo "------------------------" - echo "按任意鍵繼續..." - read -n 1 -s -r -p "" + esac + break_end + done - install jq - install_docker + ;; - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.io + 10|rocketchat) - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" + local docker_name="rocketchat" + local docker_port="3897" + local app_size="2" - clear - echo "poste.io已經安裝完成" - echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" - echo "https://$yuming" - echo "" + docker_app_install() { + docker run --name db -d --restart=always \ + -v /home/docker/mongo/dump:/dump \ + mongo:latest --replSet rs5 --oplogSize 256 + sleep 1 + docker exec -it db mongosh --eval "printjson(rs.initiate())" + sleep 5 + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - ;; + clear + ip_address + echo "已經安裝完成" + check_docker_app_ip + } - 2) - docker rm -f mailserver - docker rmi -f analogic/poste.i - yuming=$(cat /home/docker/mail.txt) - docker run \ - --net=host \ - -e TZ=Europe/Prague \ - -v /home/docker/mail:/data \ - --name "mailserver" \ - -h "$yuming" \ - --restart=always \ - -d analogic/poste.i - - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + docker_app_update() { + docker rm -f rocketchat + docker rmi -f rocket.chat:latest + docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat + clear + ip_address + echo "rocket.chat已經安裝完成" + check_docker_app_ip + } - clear - echo "poste.io已經安裝完成" - echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" - echo "https://$yuming" - echo "" - ;; - 3) - docker rm -f mailserver - docker rmi -f analogic/poste.io - rm /home/docker/mail.txt - rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "應用已卸載" - ;; + docker_app_uninstall() { + docker rm -f rocketchat + docker rmi -f rocket.chat + docker rm -f db + docker rmi -f mongo:latest + rm -rf /home/docker/mongo + echo "應用已卸載" + } - *) - break - ;; + docker_app_plus + ;; - esac - break_end - done - ;; - 10) + 11|zentao) + local docker_name="zentao-server" + local docker_img="idoop/zentao:latest" + local docker_port=82 - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" - local docker_name="rocketchat" - local docker_port="3897" - local app_size="2" - - docker_app_install() { - docker run --name db -d --restart=always \ - -v /home/docker/mongo/dump:/dump \ - mongo:latest --replSet rs5 --oplogSize 256 - sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" - sleep 5 - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "已經安裝完成" - check_docker_app_ip - } + docker_rum() { - docker_app_update() { - docker rm -f rocketchat - docker rmi -f rocket.chat:latest - docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat - clear - ip_address - echo "rocket.chat已經安裝完成" - check_docker_app_ip - } - - docker_app_uninstall() { - docker rm -f rocketchat - docker rmi -f rocket.chat - docker rm -f db - docker rmi -f mongo:latest - rm -rf /home/docker/mongo - echo "應用已卸載" - } - docker_app_plus - ;; + docker run -d -p ${docker_port}:80 \ + -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ + -e BIND_ADDRESS="false" \ + -v /home/docker/zentao-server/:/opt/zbox/ \ + --add-host smtp.exmail.qq.com:163.177.90.125 \ + --name zentao-server \ + --restart=always \ + idoop/zentao:latest + } - 11) - local docker_name="zentao-server" - local docker_img="idoop/zentao:latest" - local docker_port=82 + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" + local app_size="2" + docker_app + ;; - docker_rum() { + 12|qinglong) + local docker_name="qinglong" + local docker_img="whyour/qinglong:latest" + local docker_port=5700 + docker_rum() { - docker run -d -p ${docker_port}:80 \ - -e ADMINER_USER="root" -e ADMINER_PASSWD="password" \ - -e BIND_ADDRESS="false" \ - -v /home/docker/zentao-server/:/opt/zbox/ \ - --add-host smtp.exmail.qq.com:163.177.90.125 \ - --name zentao-server \ - --restart=always \ - idoop/zentao:latest + docker run -d \ + -v /home/docker/qinglong/data:/ql/data \ + -p ${docker_port}:5700 \ + --name qinglong \ + --hostname qinglong \ + --restart unless-stopped \ + whyour/qinglong:latest - } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" - local app_size="2" - docker_app + } - ;; + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 12) - local docker_name="qinglong" - local docker_img="whyour/qinglong:latest" - local docker_port=5700 + ;; + 13|cloudreve) + + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local docker_name="cloudreve" + local docker_port="5212" + local app_size="2" + + docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } - docker_rum() { + docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d + } - docker run -d \ - -v /home/docker/qinglong/data:/ql/data \ - -p ${docker_port}:5700 \ - --name qinglong \ - --hostname qinglong \ - --restart unless-stopped \ - whyour/qinglong:latest + docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "應用已卸載" + } - } + docker_app_plus + ;; - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + 14|easyimage) + local docker_name="easyimage" + local docker_img="ddsderek/easyimage:latest" + local docker_port=8014 + docker_rum() { + + docker run -d \ + --name easyimage \ + -p ${docker_port}:80 \ + -e TZ=Asia/Shanghai \ + -e PUID=1000 \ + -e PGID=1000 \ + -v /home/docker/easyimage/config:/app/web/config \ + -v /home/docker/easyimage/i:/app/web/i \ + --restart unless-stopped \ + ddsderek/easyimage:latest - ;; - 13) + } - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" - local docker_name="cloudreve" - local docker_port="5212" - local app_size="2" - - docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip - } + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 15|emby) + local docker_name="emby" + local docker_img="linuxserver/emby:latest" + local docker_port=8015 - docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d - } + docker_rum() { + docker run -d --name=emby --restart=always \ + -v /home/docker/emby/config:/config \ + -v /home/docker/emby/share1:/mnt/share1 \ + -v /home/docker/emby/share2:/mnt/share2 \ + -v /mnt/notify:/mnt/notify \ + -p ${docker_port}:8096 \ + -e UID=1000 -e GID=100 -e GIDLIST=100 \ + linuxserver/emby:latest - docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "應用已卸載" - } + } - docker_app_plus - ;; - 14) - local docker_name="easyimage" - local docker_img="ddsderek/easyimage:latest" - local docker_port=85 - docker_rum() { + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - --name easyimage \ - -p ${docker_port}:80 \ - -e TZ=Asia/Shanghai \ - -e PUID=1000 \ - -e PGID=1000 \ - -v /home/docker/easyimage/config:/app/web/config \ - -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ - ddsderek/easyimage:latest + 16|looking) + local docker_name="looking-glass" + local docker_img="wikihostinc/looking-glass-server" + local docker_port=8016 - } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 15) - local docker_name="emby" - local docker_img="linuxserver/emby:latest" - local docker_port=8096 + docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - docker_rum() { + } - docker run -d --name=emby --restart=always \ - -v /home/docker/emby/config:/config \ - -v /home/docker/emby/share1:/mnt/share1 \ - -v /home/docker/emby/share2:/mnt/share2 \ - -v /mnt/notify:/mnt/notify \ - -p ${docker_port}:8096 \ - -e UID=1000 -e GID=100 -e GIDLIST=100 \ - linuxserver/emby:latest + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } + ;; + 17|adguardhome) + local docker_name="adguardhome" + local docker_img="adguard/adguardhome" + local docker_port=8017 - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 16) - local docker_name="looking-glass" - local docker_img="wikihostinc/looking-glass-server" - local docker_port=89 + docker run -d \ + --name adguardhome \ + -v /home/docker/adguardhome/work:/opt/adguardhome/work \ + -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ + -p 53:53/tcp \ + -p 53:53/udp \ + -p ${docker_port}:3000/tcp \ + --restart always \ + adguard/adguardhome - docker_rum() { + } - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server - } + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + ;; - ;; - 17) - local docker_name="adguardhome" - local docker_img="adguard/adguardhome" - local docker_port=3000 + 18|onlyoffice) - docker_rum() { + local docker_name="onlyoffice" + local docker_img="onlyoffice/documentserver" + local docker_port=8018 - docker run -d \ - --name adguardhome \ - -v /home/docker/adguardhome/work:/opt/adguardhome/work \ - -v /home/docker/adguardhome/conf:/opt/adguardhome/conf \ - -p 53:53/tcp \ - -p 53:53/udp \ - -p ${docker_port}:3000/tcp \ - --restart always \ - adguard/adguardhome + docker_rum() { + docker run -d -p ${docker_port}:80 \ + --restart=always \ + --name onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ + -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ + onlyoffice/documentserver - } + } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - ;; + ;; + 19|safeline) + send_stats "搭建雷池" - 18) + local docker_name=safeline-mgt + local docker_port=9443 + while true; do + check_docker_app + clear + echo -e "雷池服務$check_docker" + echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" + echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + check_docker_app_ip + fi + echo "" - local docker_name="onlyoffice" - local docker_img="onlyoffice/documentserver" - local docker_port=8082 + echo "------------------------" + echo "1. 安裝 2. 更新 3. 重置密碼 4. 卸載" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "輸入你的選擇:" choice - docker_rum() { + case $choice in + 1) + install_docker + check_disk_space 5 + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已經安裝完成" + check_docker_app_ip + docker exec safeline-mgt resetadmin - docker run -d -p ${docker_port}:80 \ - --restart=always \ - --name onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \ - -v /home/docker/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \ - onlyoffice/documentserver + ;; + 2) + bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" + docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') + echo "" + local app_no=$sub_choice + grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + clear + echo "雷池WAF面板已經更新完成" + check_docker_app_ip + ;; + 3) + docker exec safeline-mgt resetadmin + ;; + 4) + cd /data/safeline + docker compose down --rmi all + local app_no=$sub_choice + sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" + echo "docker compose down && docker compose down --rmi all" + ;; + *) + break + ;; - } + esac + break_end + done - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + ;; - ;; + 20|portainer) + local docker_name="portainer" + local docker_img="portainer/portainer" + local docker_port=8020 - 19) - send_stats "搭建雷池" + docker_rum() { - local docker_name=safeline-mgt - local docker_port=9443 - while true; do - check_docker_app - clear - echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" - echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then - check_docker_app_ip - fi - echo "" + docker run -d \ + --name portainer \ + -p ${docker_port}:9000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/portainer:/data \ + --restart always \ + portainer/portainer - echo "------------------------" - echo "1. 安裝 2. 更新 3. 重置密碼 4. 卸載" - echo "------------------------" - echo "0. 返回上一級選單" - echo "------------------------" - read -e -p "輸入你的選擇:" choice + } - case $choice in - 1) - install_docker - check_disk_space 5 - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已經安裝完成" - check_docker_app_ip - docker exec safeline-mgt resetadmin - ;; + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - 2) - bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" - docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') - echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt - clear - echo "雷池WAF面板已經更新完成" - check_docker_app_ip - ;; - 3) - docker exec safeline-mgt resetadmin - ;; - 4) - cd /data/safeline - docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt - echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" - echo "docker compose down && docker compose down --rmi all" - ;; - *) - break - ;; + ;; - esac - break_end - done + 21|vscode) + local docker_name="vscode-web" + local docker_img="codercom/code-server" + local docker_port=8021 - ;; - 20) - local docker_name="portainer" - local docker_img="portainer/portainer" - local docker_port=9050 + docker_rum() { - docker_rum() { + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server - docker run -d \ - --name portainer \ - -p ${docker_port}:9000 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/portainer:/data \ - --restart always \ - portainer/portainer + } - } + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_use="sleep 3" + local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" + local app_size="1" + docker_app + ;; - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 22|uptime-kuma) + local docker_name="uptime-kuma" + local docker_img="louislam/uptime-kuma:latest" + local docker_port=8022 - 21) - local docker_name="vscode-web" - local docker_img="codercom/code-server" - local docker_port=8180 + docker_rum() { - docker_rum() { + docker run -d \ + --name=uptime-kuma \ + -p ${docker_port}:3001 \ + -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ + --restart=always \ + louislam/uptime-kuma:latest - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + } - } + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" - local docker_use="sleep 3" - local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" - local app_size="1" - docker_app - ;; - 22) - local docker_name="uptime-kuma" - local docker_img="louislam/uptime-kuma:latest" - local docker_port=3003 + 23|memos) + local docker_name="memos" + local docker_img="ghcr.io/usememos/memos:latest" + local docker_port=8023 + docker_rum() { - docker_rum() { + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest - docker run -d \ - --name=uptime-kuma \ - -p ${docker_port}:3001 \ - -v /home/docker/uptime-kuma/uptime-kuma-data:/app/data \ - --restart=always \ - louislam/uptime-kuma:latest + } - } + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 24|webtop) + local docker_name="webtop" + local docker_img="lscr.io/linuxserver/webtop:latest" + local docker_port=8024 + + docker_rum() { + + + docker run -d \ + --name=webtop \ + --security-opt seccomp=unconfined \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SUBFOLDER=/ \ + -e TITLE=Webtop \ + -e CUSTOM_USER=webtop-abc \ + -e PASSWORD=webtopABC123 \ + -e LC_ALL=zh_CN.UTF-8 \ + -e DOCKER_MODS=linuxserver/mods:universal-package-install \ + -e INSTALL_PACKAGES=font-noto-cjk \ + -p ${docker_port}:3000 \ + -v /home/docker/webtop/data:/config \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --shm-size="1gb" \ + --restart unless-stopped \ + lscr.io/linuxserver/webtop:latest - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 23) - local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" - local docker_port=5230 + } - docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_use="echo \"用户名: webtop-abc\"" + local docker_passwd="echo \"密码: webtopABC123\"" + local app_size="2" + docker_app + ;; - } + 25|nextcloud) + local docker_name="nextcloud" + local docker_img="nextcloud:latest" + local docker_port=8025 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 24) - local docker_name="webtop" - local docker_img="lscr.io/linuxserver/webtop:latest" - local docker_port=3083 + docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud - docker_rum() { + } + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="3" + docker_app + ;; - docker run -d \ - --name=webtop \ - --security-opt seccomp=unconfined \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e SUBFOLDER=/ \ - -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ - -e LC_ALL=zh_CN.UTF-8 \ - -e DOCKER_MODS=linuxserver/mods:universal-package-install \ - -e INSTALL_PACKAGES=font-noto-cjk \ - -p ${docker_port}:3000 \ - -v /home/docker/webtop/data:/config \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --shm-size="1gb" \ - --restart unless-stopped \ - lscr.io/linuxserver/webtop:latest + 26|qd) + local docker_name="qd" + local docker_img="qdtoday/qd:latest" + local docker_port=8026 + docker_rum() { - } + docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" - local app_size="2" - docker_app - ;; + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 25) - local docker_name="nextcloud" - local docker_img="nextcloud:latest" - local docker_port=8989 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 27|dockge) + local docker_name="dockge" + local docker_img="louislam/dockge:latest" + local docker_port=8027 - docker_rum() { + docker_rum() { - docker run -d --name nextcloud --restart=always -p ${docker_port}:80 -v /home/docker/nextcloud:/var/www/html -e NEXTCLOUD_ADMIN_USER=nextcloud -e NEXTCLOUD_ADMIN_PASSWORD=$rootpasswd nextcloud + docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge - } + } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="3" - docker_app - ;; + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 26) - local docker_name="qd" - local docker_img="qdtoday/qd:latest" - local docker_port=8923 + 28|speedtest) + local docker_name="speedtest" + local docker_img="ghcr.io/librespeed/speedtest" + local docker_port=8028 - docker_rum() { + docker_rum() { - docker run -d --name qd -p ${docker_port}:80 -v /home/docker/qd/config:/usr/src/app/config qdtoday/qd + docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest - } + } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 27) - local docker_name="dockge" - local docker_img="louislam/dockge:latest" - local docker_port=5003 + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 29|searxng) + local docker_name="searxng" + local docker_img="searxng/searxng" + local docker_port=8029 - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker_rum() { - } + docker run -d \ + --name searxng \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v "/home/docker/searxng:/etc/searxng" \ + searxng/searxng - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 28) - local docker_name="speedtest" - local docker_img="ghcr.io/librespeed/speedtest" - local docker_port=8028 + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 30|photoprism) + local docker_name="photoprism" + local docker_img="photoprism/photoprism:latest" + local docker_port=8030 + local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + + docker_rum() { + + docker run -d \ + --name photoprism \ + --restart always \ + --security-opt seccomp=unconfined \ + --security-opt apparmor=unconfined \ + -p ${docker_port}:2342 \ + -e PHOTOPRISM_UPLOAD_NSFW="true" \ + -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ + -v /home/docker/photoprism/storage:/photoprism/storage \ + -v /home/docker/photoprism/Pictures:/photoprism/originals \ + photoprism/photoprism - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + } - } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 29) - local docker_name="searxng" - local docker_img="searxng/searxng" - local docker_port=8029 - docker_rum() { + 31|s-pdf) + local docker_name="s-pdf" + local docker_img="frooodle/s-pdf:latest" + local docker_port=8031 - docker run -d \ - --name searxng \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - -v "/home/docker/searxng:/etc/searxng" \ - searxng/searxng + docker_rum() { - } + docker run -d \ + --name s-pdf \ + --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ + -v /home/docker/s-pdf/extraConfigs:/configs \ + -v /home/docker/s-pdf/logs:/logs \ + -e DOCKER_ENABLE_SECURITY=false \ + frooodle/s-pdf:latest + } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 30) - local docker_name="photoprism" - local docker_img="photoprism/photoprism:latest" - local docker_port=2342 - local rootpasswd=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + 32|drawio) + local docker_name="drawio" + local docker_img="jgraph/drawio" + local docker_port=8032 - docker_rum() { + docker_rum() { - docker run -d \ - --name photoprism \ - --restart always \ - --security-opt seccomp=unconfined \ - --security-opt apparmor=unconfined \ - -p ${docker_port}:2342 \ - -e PHOTOPRISM_UPLOAD_NSFW="true" \ - -e PHOTOPRISM_ADMIN_PASSWORD="$rootpasswd" \ - -v /home/docker/photoprism/storage:/photoprism/storage \ - -v /home/docker/photoprism/Pictures:/photoprism/originals \ - photoprism/photoprism + docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio - } + } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 33|sun-panel) + local docker_name="sun-panel" + local docker_img="hslr/sun-panel" + local docker_port=8033 - 31) - local docker_name="s-pdf" - local docker_img="frooodle/s-pdf:latest" - local docker_port=8020 + docker_rum() { - docker_rum() { + docker run -d --restart=always -p ${docker_port}:3002 \ + -v /home/docker/sun-panel/conf:/app/conf \ + -v /home/docker/sun-panel/uploads:/app/uploads \ + -v /home/docker/sun-panel/database:/app/database \ + --name sun-panel \ + hslr/sun-panel - docker run -d \ - --name s-pdf \ - --restart=always \ - -p ${docker_port}:8080 \ - -v /home/docker/s-pdf/trainingData:/usr/share/tesseract-ocr/5/tessdata \ - -v /home/docker/s-pdf/extraConfigs:/configs \ - -v /home/docker/s-pdf/logs:/logs \ - -e DOCKER_ENABLE_SECURITY=false \ - frooodle/s-pdf:latest - } - - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 32) - local docker_name="drawio" - local docker_img="jgraph/drawio" - local docker_port=7080 + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 34|pingvin-share) + local docker_name="pingvin-share" + local docker_img="stonith404/pingvin-share" + local docker_port=8034 - docker run -d --restart=always --name drawio -p ${docker_port}:8080 -v /home/docker/drawio:/var/lib/drawio jgraph/drawio + docker_rum() { - } + docker run -d \ + --name pingvin-share \ + --restart always \ + -p ${docker_port}:3000 \ + -v /home/docker/pingvin-share/data:/opt/app/backend/data \ + stonith404/pingvin-share + } + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 33) - local docker_name="sun-panel" - local docker_img="hslr/sun-panel" - local docker_port=3009 + 35|moments) + local docker_name="moments" + local docker_img="kingwrcy/moments:latest" + local docker_port=8035 - docker_rum() { + docker_rum() { - docker run -d --restart=always -p ${docker_port}:3002 \ - -v /home/docker/sun-panel/conf:/app/conf \ - -v /home/docker/sun-panel/uploads:/app/uploads \ - -v /home/docker/sun-panel/database:/app/database \ - --name sun-panel \ - hslr/sun-panel + docker run -d --restart unless-stopped \ + -p ${docker_port}:3000 \ + -v /home/docker/moments/data:/app/data \ + -v /etc/localtime:/etc/localtime:ro \ + -v /etc/timezone:/etc/timezone:ro \ + --name moments \ + kingwrcy/moments:latest + } - } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 34) - local docker_name="pingvin-share" - local docker_img="stonith404/pingvin-share" - local docker_port=3060 - docker_rum() { - docker run -d \ - --name pingvin-share \ - --restart always \ - -p ${docker_port}:3000 \ - -v /home/docker/pingvin-share/data:/opt/app/backend/data \ - stonith404/pingvin-share - } + 36|lobe-chat) + local docker_name="lobe-chat" + local docker_img="lobehub/lobe-chat:latest" + local docker_port=8036 - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -d -p ${docker_port}:3210 \ + --name lobe-chat \ + --restart=always \ + lobehub/lobe-chat + } - 35) - local docker_name="moments" - local docker_img="kingwrcy/moments:latest" - local docker_port=8035 + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - docker_rum() { + 37|myip) + local docker_name="myip" + local docker_img="jason5ng32/myip:latest" + local docker_port=8037 - docker run -d --restart unless-stopped \ - -p ${docker_port}:3000 \ - -v /home/docker/moments/data:/app/data \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - --name moments \ - kingwrcy/moments:latest - } + docker_rum() { + docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 36) - local docker_name="lobe-chat" - local docker_img="lobehub/lobe-chat:latest" - local docker_port=8036 + 38|xiaoya) + send_stats "小雅全家桶" + clear + install_docker + check_disk_space 1 + bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" + ;; - docker_rum() { + 39|bililive) - docker run -d -p ${docker_port}:3210 \ - --name lobe-chat \ - --restart=always \ - lobehub/lobe-chat - } + if [ ! -d /home/docker/bililive-go/ ]; then + mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 + wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 + fi - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + local docker_name="bililive-go" + local docker_img="chigusa/bililive-go" + local docker_port=8039 - 37) - local docker_name="myip" - local docker_img="jason5ng32/myip:latest" - local docker_port=8037 + docker_rum() { - docker_rum() { + docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go - docker run -d -p ${docker_port}:18966 --name myip jason5ng32/myip:latest + } - } + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; + 40|webssh) + local docker_name="webssh" + local docker_img="jrohy/webssh" + local docker_port=8040 + docker_rum() { + docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 38) - send_stats "小雅全家桶" - clear - install_docker - check_disk_space 1 - bash -c "$(curl --insecure -fsSL https://ddsrem.com/xiaoya_install.sh)" - ;; + 41|haozi) - 39) + local lujing="[ -d "/www/server/panel" ]" + local panelname="耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" - if [ ! -d /home/docker/bililive-go/ ]; then - mkdir -p /home/docker/bililive-go/ > /dev/null 2>&1 - wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 - fi + panel_app_install() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh + cd ~ + } - local docker_name="bililive-go" - local docker_img="chigusa/bililive-go" - local docker_port=8039 + panel_app_manage() { + panel-cli + } - docker_rum() { + panel_app_uninstall() { + mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh + cd ~ + } - docker run --restart=always --name bililive-go -v /home/docker/bililive-go/config.yml:/etc/bililive-go/config.yml -v /home/docker/bililive-go/Videos:/srv/bililive -p ${docker_port}:8080 -d chigusa/bililive-go + install_panel - } + ;; - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; - 40) - local docker_name="webssh" - local docker_img="jrohy/webssh" - local docker_port=8040 - docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh - } + 42|nexterm) + local docker_name="nexterm" + local docker_img="germannewsmaker/nexterm:latest" + local docker_port=8042 - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { - 41) + docker run -d \ + --name nexterm \ + -p ${docker_port}:6989 \ + -v /home/docker/nexterm:/app/data \ + --restart unless-stopped \ + germannewsmaker/nexterm:latest - local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + } - panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh - cd ~ - } + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - panel_app_manage() { - panel-cli - } + 43|hbbs) + local docker_name="hbbs" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh - cd ~ - } + docker_rum() { - install_panel + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs - ;; + } - 42) - local docker_name="nexterm" - local docker_img="germannewsmaker/nexterm:latest" - local docker_port=8042 + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="docker logs hbbs" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local app_size="1" + docker_app + ;; - docker_rum() { + 44|hbbr) + local docker_name="hbbr" + local docker_img="rustdesk/rustdesk-server" + local docker_port=0000 - docker run -d \ - --name nexterm \ - -p ${docker_port}:6989 \ - -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ - germannewsmaker/nexterm:latest + docker_rum() { - } + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } - 43) - local docker_name="hbbs" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { + 45|registry) + local docker_name="registry" + local docker_img="registry:2" + local docker_port=8045 - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker_rum() { - } + docker run -d \ + -p ${docker_port}:5000 \ + --name registry \ + -v /home/docker/registry:/var/lib/registry \ + -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ + --restart always \ + registry:2 + } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" - local app_size="1" - docker_app - ;; + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; - 44) - local docker_name="hbbr" - local docker_img="rustdesk/rustdesk-server" - local docker_port=0000 + 46|ghproxy) + local docker_name="ghproxy" + local docker_img="wjqserver/ghproxy:latest" + local docker_port=8046 - docker_rum() { + docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest - } + } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 45) - local docker_name="registry" - local docker_img="registry:2" - local docker_port=8045 + 47|prometheus|grafana) - docker_rum() { + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" + local docker_name="grafana" + local docker_port="8047" + local app_size="2" - docker run -d \ - -p ${docker_port}:5000 \ - --name registry \ - -v /home/docker/registry:/var/lib/registry \ - -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ - registry:2 + docker_app_install() { + prometheus_install + clear + ip_address + echo "已經安裝完成" + check_docker_app_ip + echo "初始用戶名密碼均為: admin" + } - } + docker_app_update() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest + docker_app_install + } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app - ;; + docker_app_uninstall() { + docker rm -f node-exporter prometheus grafana + docker rmi -f prom/node-exporter + docker rmi -f prom/prometheus:latest + docker rmi -f grafana/grafana:latest - 46) - local docker_name="ghproxy" - local docker_img="wjqserver/ghproxy:latest" - local docker_port=8046 + rm -rf /home/docker/monitoring + echo "應用已卸載" + } - docker_rum() { + docker_app_plus + ;; - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + 48|node-exporter) + local docker_name="node-exporter" + local docker_img="prom/node-exporter" + local docker_port=8048 - } + docker_rum() { - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name=node-exporter \ + -p ${docker_port}:9100 \ + --restart unless-stopped \ + prom/node-exporter - 47) + } + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" - local docker_name="grafana" - local docker_port="8047" - local app_size="2" + 49|cadvisor) + local docker_name="cadvisor" + local docker_img="gcr.io/cadvisor/cadvisor:latest" + local docker_port=8049 + + docker_rum() { + + docker run -d \ + --name=cadvisor \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + --volume=/:/rootfs:ro \ + --volume=/var/run:/var/run:rw \ + --volume=/sys:/sys:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + gcr.io/cadvisor/cadvisor:latest \ + -housekeeping_interval=10s \ + -docker_only=true - docker_app_install() { - prometheus_install - clear - ip_address - echo "已經安裝完成" - check_docker_app_ip - echo "初始用戶名密碼均為: admin" - } - - docker_app_update() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest - docker_app_install - } + } - docker_app_uninstall() { - docker rm -f node-exporter prometheus grafana - docker rmi -f prom/node-exporter - docker rmi -f prom/prometheus:latest - docker rmi -f grafana/grafana:latest + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - rm -rf /home/docker/monitoring - echo "應用已卸載" - } - docker_app_plus - ;; + 50|changedetection) + local docker_name="changedetection" + local docker_img="dgtlmoon/changedetection.io:latest" + local docker_port=8050 - 48) - local docker_name="node-exporter" - local docker_img="prom/node-exporter" - local docker_port=8048 + docker_rum() { - docker_rum() { + docker run -d --restart always -p ${docker_port}:5000 \ + -v /home/docker/datastore:/datastore \ + --name changedetection dgtlmoon/changedetection.io:latest - docker run -d \ - --name=node-exporter \ - -p ${docker_port}:9100 \ - --restart unless-stopped \ - prom/node-exporter + } + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 51|pve) + clear + send_stats "PVE開小雞" + check_disk_space 1 + curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh + ;; - 49) - local docker_name="cadvisor" - local docker_img="gcr.io/cadvisor/cadvisor:latest" - local docker_port=8049 - docker_rum() { + 52|dpanel) + local docker_name="dpanel" + local docker_img="dpanel/dpanel:lite" + local docker_port=8052 - docker run -d \ - --name=cadvisor \ - --restart unless-stopped \ - -p ${docker_port}:8080 \ - --volume=/:/rootfs:ro \ - --volume=/var/run:/var/run:rw \ - --volume=/sys:/sys:ro \ - --volume=/var/lib/docker/:/var/lib/docker:ro \ - gcr.io/cadvisor/cadvisor:latest \ - -housekeeping_interval=10s \ - -docker_only=true + docker_rum() { - } + docker run -it -d --name dpanel --restart=always \ + -p ${docker_port}:8080 -e APP_NAME=dpanel \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/docker/dpanel:/dpanel \ + dpanel/dpanel:lite - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + } + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 50) - local docker_name="changedetection" - local docker_img="dgtlmoon/changedetection.io:latest" - local docker_port=8050 + 53|llama3) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker_rum() { + docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ - -v /home/docker/datastore:/datastore \ - --name changedetection dgtlmoon/changedetection.io:latest + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - } + } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run llama3.2:1b" + local docker_passwd="" + local app_size="5" + docker_app + ;; + 54|amh) - 51) - clear - send_stats "PVE開小雞" - check_disk_space 1 - curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh - ;; + local lujing="[ -d "/www/server/panel" ]" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" + panel_app_install() { + cd ~ + wget https://dl.amh.sh/amh.sh && bash amh.sh + } - 52) - local docker_name="dpanel" - local docker_img="dpanel/dpanel:lite" - local docker_port=8052 + panel_app_manage() { + panel_app_install + } - docker_rum() { + panel_app_uninstall() { + panel_app_install + } - docker run -it -d --name dpanel --restart=always \ - -p ${docker_port}:8080 -e APP_NAME=dpanel \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /home/docker/dpanel:/dpanel \ - dpanel/dpanel:lite + install_panel + ;; - } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 55|frps) + frps_panel + ;; - 53) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 56|frpc) + frpc_panel + ;; - docker_rum() { + 57|deepseek) + local docker_name="ollama" + local docker_img="ghcr.io/open-webui/open-webui:ollama" + local docker_port=8053 - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker_rum() { - } + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run llama3.2:1b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + } - 54) + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" + local docker_passwd="" + local app_size="5" + docker_app + ;; - local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" - panel_app_install() { - cd ~ - wget https://dl.amh.sh/amh.sh && bash amh.sh - } + 58|dify) + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" + local docker_name="docker-nginx-1" + local docker_port="8058" + local app_size="3" - panel_app_manage() { - panel_app_install - } + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env - panel_app_uninstall() { - panel_app_install - } + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } - install_panel - ;; + docker_app_update() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + cd /home/docker/dify/ + git pull origin main + sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env + cd /home/docker/dify/docker/ && docker compose up -d + } + docker_app_uninstall() { + cd /home/docker/dify/docker/ && docker compose down --rmi all + rm -rf /home/docker/dify + echo "應用已卸載" + } - 55) - frps_panel - ;; + docker_app_plus - 56) - frpc_panel - ;; + ;; - 57) - local docker_name="ollama" - local docker_img="ghcr.io/open-webui/open-webui:ollama" - local docker_port=8053 + 59|new-api) + local app_name="New API" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local docker_name="new-api" + local docker_port="8059" + local app_size="3" - docker_rum() { + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" - local docker_passwd="" - local app_size="5" - docker_app - ;; + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + docker_app_update() { + cd /home/docker/new-api/ && docker compose down --rmi all + cd /home/docker/new-api/ + git pull origin main + sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ + -e 's/container_name: redis/container_name: redis-new-api/g' \ + -e 's/container_name: mysql/container_name: mysql-new-api/g' \ + docker-compose.yml - 58) - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" - local docker_name="docker-nginx-1" - local docker_port="8058" - local app_size="3" + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env + } - docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - cd /home/docker/dify/ - git pull origin main - sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env - cd /home/docker/dify/docker/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/dify/docker/ && docker compose down --rmi all - rm -rf /home/docker/dify - echo "應用已卸載" - } + docker_app_uninstall() { + cd /home/docker/new-api/ && docker compose down --rmi all + rm -rf /home/docker/new-api + echo "應用已卸載" + } - docker_app_plus + docker_app_plus - ;; + ;; - 59) - local app_name="New API" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" - local docker_name="new-api" - local docker_port="8059" - local app_size="3" - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + 60|jms) - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local docker_name="jms_web" + local docker_port="80" + local app_size="2" + docker_app_install() { + curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash + clear + echo "已經安裝完成" + check_docker_app_ip + echo "初始用戶名: admin" + echo "初始密碼: ChangeMe" + } - docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/new-api/ && docker compose down --rmi all - cd /home/docker/new-api/ - git pull origin main - sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ - -e 's/container_name: redis/container_name: redis-new-api/g' \ - -e 's/container_name: mysql/container_name: mysql-new-api/g' \ - docker-compose.yml - - docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip - } + docker_app_update() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh upgrade + echo "應用已更新" + } - docker_app_uninstall() { - cd /home/docker/new-api/ && docker compose down --rmi all - rm -rf /home/docker/new-api - echo "應用已卸載" - } - docker_app_plus + docker_app_uninstall() { + cd /opt/jumpserver-installer*/ + ./jmsctl.sh uninstall + cd /opt + rm -rf jumpserver-installer*/ + rm -rf jumpserver + echo "應用已卸載" + } - ;; + docker_app_plus + ;; + 61|libretranslate) + local docker_name="libretranslate" + local docker_img="libretranslate/libretranslate:latest" + local docker_port=8061 - 60) + docker_rum() { - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" - local docker_name="jms_web" - local docker_port="80" - local app_size="2" + docker run -d \ + -p ${docker_port}:5000 \ + --name libretranslate \ + libretranslate/libretranslate \ + --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru - docker_app_install() { - curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash - clear - echo "已經安裝完成" - check_docker_app_ip - echo "初始用戶名: admin" - echo "初始密碼: ChangeMe" - } + } + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_use="" + local docker_passwd="" + local app_size="5" + docker_app + ;; - docker_app_update() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh upgrade - echo "應用已更新" - } - docker_app_uninstall() { - cd /opt/jumpserver-installer*/ - ./jmsctl.sh uninstall - cd /opt - rm -rf jumpserver-installer*/ - rm -rf jumpserver - echo "應用已卸載" - } + 62|ragflow) + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: https://github.com/infiniflow/ragflow" + local docker_name="ragflow-server" + local docker_port="8062" + local app_size="8" - docker_app_plus - ;; + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } - 61) - local docker_name="libretranslate" - local docker_img="libretranslate/libretranslate:latest" - local docker_port=8061 + docker_app_update() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + cd /home/docker/ragflow/ + git pull origin main + cd /home/docker/ragflow/docker/ + sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml + docker compose up -d + } - docker_rum() { + docker_app_uninstall() { + cd /home/docker/ragflow/docker/ && docker compose down --rmi all + rm -rf /home/docker/ragflow + echo "應用已卸載" + } - docker run -d \ - -p ${docker_port}:5000 \ - --name libretranslate \ - libretranslate/libretranslate \ - --load-only ko,zt,zh,en,ja,pt,es,fr,de,ru + docker_app_plus - } + ;; - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" - local docker_use="" - local docker_passwd="" - local app_size="5" - docker_app - ;; + 63|open-webui) + local docker_name="open-webui" + local docker_img="ghcr.io/open-webui/open-webui:main" + local docker_port=8063 + docker_rum() { - 62) - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" - local docker_name="ragflow-server" - local docker_port="8062" - local app_size="8" + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main - docker_app_install() { - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - cd /home/docker/ragflow/ - git pull origin main - cd /home/docker/ragflow/docker/ - sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml - docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/ragflow/docker/ && docker compose down --rmi all - rm -rf /home/docker/ragflow - echo "應用已卸載" - } + } - docker_app_plus + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + ;; - ;; + 64|it-tools) + local docker_name="it-tools" + local docker_img="corentinth/it-tools:latest" + local docker_port=8064 + docker_rum() { + docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + } - 63) - local docker_name="open-webui" - local docker_img="ghcr.io/open-webui/open-webui:main" - local docker_port=8063 + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + 65|n8n) + local docker_name="n8n" + local docker_img="docker.n8n.io/n8nio/n8n" + local docker_port=8065 - } + docker_rum() { - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - ;; + add_yuming + mkdir -p /home/docker/n8n + chmod -R 777 /home/docker/n8n + + docker run -d --name n8n \ + --restart always \ + -p ${docker_port}:5678 \ + -v /home/docker/n8n:/home/node/.n8n \ + -e N8N_HOST=${yuming} \ + -e N8N_PORT=5678 \ + -e N8N_PROTOCOL=https \ + -e N8N_WEBHOOK_URL=https://${yuming}/ \ + docker.n8n.io/n8nio/n8n + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - 64) - local docker_name="it-tools" - local docker_img="corentinth/it-tools:latest" - local docker_port=8064 + } - docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest - } + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 66|yt) + yt_menu_pro + ;; - 65) - local docker_name="n8n" - local docker_img="docker.n8n.io/n8nio/n8n" - local docker_port=8065 + 67|ddns) + local docker_name="ddns-go" + local docker_img="jeessy/ddns-go" + local docker_port=8067 - docker_rum() { + docker_rum() { + docker run -d \ + --name ddns-go \ + --restart=always \ + -p ${docker_port}:9876 \ + -v /home/docker/ddns-go:/root \ + jeessy/ddns-go - add_yuming - mkdir -p /home/docker/n8n - chmod -R 777 /home/docker/n8n - - docker run -d --name n8n \ - --restart always \ - -p ${docker_port}:5678 \ - -v /home/docker/n8n:/home/node/.n8n \ - -e N8N_HOST=${yuming} \ - -e N8N_PORT=5678 \ - -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ - docker.n8n.io/n8nio/n8n + } - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } + 68|allinssl) + local docker_name="allinssl" + local docker_img="allinssl/allinssl:latest" + local docker_port=8068 - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker_rum() { + docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + } - 66) - yt_menu_pro - ;; + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local app_size="1" + docker_app + ;; - 67) - local docker_name="ddns-go" - local docker_img="jeessy/ddns-go" - local docker_port=8067 + 69|sftpgo) + local docker_name="sftpgo" + local docker_img="drakkan/sftpgo:latest" + local docker_port=8069 - docker_rum() { - docker run -d \ - --name ddns-go \ - --restart=always \ - -p ${docker_port}:9876 \ - -v /home/docker/ddns-go:/root \ - jeessy/ddns-go + docker_rum() { - } + mkdir -p /home/docker/sftpgo/data + mkdir -p /home/docker/sftpgo/config + chown -R 1000:1000 /home/docker/sftpgo - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + docker run -d \ + --name sftpgo \ + --restart=always \ + -p ${docker_port}:8080 \ + -p 22022:2022 \ + --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ + --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ + drakkan/sftpgo:latest + + } - 68) - local docker_name="allinssl" - local docker_img="allinssl/allinssl:latest" - local docker_port=8068 + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest - } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" - local app_size="1" - docker_app - ;; + 70|astrbot) + local docker_name="astrbot" + local docker_img="soulter/astrbot:latest" + local docker_port=8070 + docker_rum() { - 69) - local docker_name="sftpgo" - local docker_img="drakkan/sftpgo:latest" - local docker_port=8069 + mkdir -p /home/docker/astrbot/data - docker_rum() { + docker run -d \ + -p ${docker_port}:6185 \ + -p 6195:6195 \ + -p 6196:6196 \ + -p 6199:6199 \ + -p 11451:11451 \ + -v /home/docker/astrbot/data:/AstrBot/data \ + --restart unless-stopped \ + --name astrbot \ + soulter/astrbot:latest - mkdir -p /home/docker/sftpgo/data - mkdir -p /home/docker/sftpgo/config - chown -R 1000:1000 /home/docker/sftpgo + } - docker run -d \ - --name sftpgo \ - --restart=always \ - -p ${docker_port}:8080 \ - -p 22022:2022 \ - --mount type=bind,source=/home/docker/sftpgo/data,target=/srv/sftpgo \ - --mount type=bind,source=/home/docker/sftpgo/config,target=/var/lib/sftpgo \ - drakkan/sftpgo:latest + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_passwd="" + local app_size="1" + docker_app + ;; - } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + 71|navidrome) + local docker_name="navidrome" + local docker_img="deluan/navidrome:latest" + local docker_port=8071 + docker_rum() { - 70) - local docker_name="astrbot" - local docker_img="soulter/astrbot:latest" - local docker_port=8070 + docker run -d \ + --name navidrome \ + --restart=unless-stopped \ + --user $(id -u):$(id -g) \ + -v /home/docker/navidrome/music:/music \ + -v /home/docker/navidrome/data:/data \ + -p ${docker_port}:4533 \ + -e ND_LOGLEVEL=info \ + deluan/navidrome:latest - docker_rum() { + } - mkdir -p /home/docker/astrbot/data + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - docker run -d \ - -p ${docker_port}:6185 \ - -p 6195:6195 \ - -p 6196:6196 \ - -p 6199:6199 \ - -p 11451:11451 \ - -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ - --name astrbot \ - soulter/astrbot:latest - } + 72|bitwarden) - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" - local docker_passwd="" - local app_size="1" - docker_app - ;; + local docker_name="bitwarden" + local docker_img="vaultwarden/server" + local docker_port=8072 + docker_rum() { - 71) - local docker_name="navidrome" - local docker_img="deluan/navidrome:latest" - local docker_port=8071 + docker run -d \ + --name bitwarden \ + --restart always \ + -p ${docker_port}:80 \ + -v /home/docker/bitwarden/data:/data \ + vaultwarden/server - docker_rum() { + } - docker run -d \ - --name navidrome \ - --restart=unless-stopped \ - --user $(id -u):$(id -g) \ - -v /home/docker/navidrome/music:/music \ - -v /home/docker/navidrome/data:/data \ - -p ${docker_port}:4533 \ - -e ND_LOGLEVEL=info \ - deluan/navidrome:latest + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - ;; + ;; - 72) - local docker_name="bitwarden" - local docker_img="vaultwarden/server" - local docker_port=8072 + 73|libretv) - docker_rum() { + local docker_name="libretv" + local docker_img="bestzwei/libretv:latest" + local docker_port=8073 - docker run -d \ - --name bitwarden \ - --restart always \ - -p ${docker_port}:80 \ - -v /home/docker/bitwarden/data:/data \ - vaultwarden/server + docker_rum() { - } + read -e -p "設置LibreTV的登錄密碼:" app_passwd - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name libretv \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -e PASSWORD=${app_passwd} \ + bestzwei/libretv:latest + } - ;; + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; - 73) + 74|moontv) - local docker_name="libretv" - local docker_img="bestzwei/libretv:latest" - local docker_port=8073 + local docker_name="moontv" + local docker_img="ghcr.io/senshinya/moontv:latest" + local docker_port=8074 - docker_rum() { + docker_rum() { - read -e -p "設置LibreTV的登錄密碼:" app_passwd + read -e -p "設置MoonTV的登錄密碼:" app_passwd docker run -d \ - --name libretv \ + --name moontv \ --restart unless-stopped \ - -p ${docker_port}:8080 \ + -p ${docker_port}:3000 \ -e PASSWORD=${app_passwd} \ - bestzwei/libretv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; - - - 74) - - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - - docker_rum() { - - read -e -p "設置MoonTV的登錄密碼:" app_passwd - - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest - - } - - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app - - ;; + ghcr.io/senshinya/moontv:latest + } - 75) + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: https://github.com/senshinya/MoonTV" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="melody" - local docker_img="foamzou/melody:latest" - local docker_port=8075 + ;; - docker_rum() { - docker run -d \ - --name melody \ - --restart unless-stopped \ - -p ${docker_port}:5566 \ - -v /home/docker/melody/.profile:/app/backend/.profile \ - foamzou/melody:latest + 75|melody) + local docker_name="melody" + local docker_img="foamzou/melody:latest" + local docker_port=8075 - } + docker_rum() { - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker run -d \ + --name melody \ + --restart unless-stopped \ + -p ${docker_port}:5566 \ + -v /home/docker/melody/.profile:/app/backend/.profile \ + foamzou/melody:latest - ;; - + } - 76) + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - local docker_name="dosgame" - local docker_img="oldiy/dosgame-web-docker:latest" - local docker_port=8076 - docker_rum() { - docker run -d \ - --name dosgame \ - --restart unless-stopped \ - -p ${docker_port}:262 \ - oldiy/dosgame-web-docker:latest + ;; - } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" - local docker_use="" - local docker_passwd="" - local app_size="2" - docker_app + 76|dosgame) + local docker_name="dosgame" + local docker_img="oldiy/dosgame-web-docker:latest" + local docker_port=8076 - ;; + docker_rum() { + docker run -d \ + --name dosgame \ + --restart unless-stopped \ + -p ${docker_port}:262 \ + oldiy/dosgame-web-docker:latest - 77) + } - local docker_name="xunlei" - local docker_img="cnk3x/xunlei" - local docker_port=8077 + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app - docker_rum() { - read -e -p "設定${docker_name}的登錄用戶名:" app_use - read -e -p "設定${docker_name}的登錄密碼:" app_passwd + ;; - docker run -d \ - --name xunlei \ - --restart unless-stopped \ - --privileged \ - -e XL_DASHBOARD_USERNAME=${app_use} \ - -e XL_DASHBOARD_PASSWORD=${app_passwd} \ - -v /home/docker/xunlei/data:/xunlei/data \ - -v /home/docker/xunlei/downloads:/xunlei/downloads \ - -p ${docker_port}:2345 \ - cnk3x/xunlei + 77|xunlei) - } + local docker_name="xunlei" + local docker_img="cnk3x/xunlei" + local docker_port=8077 - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" - local docker_passwd="" - local app_size="1" - docker_app + docker_rum() { - ;; + read -e -p "設定${docker_name}的登錄用戶名:" app_use + read -e -p "設定${docker_name}的登錄密碼:" app_passwd + docker run -d \ + --name xunlei \ + --restart unless-stopped \ + --privileged \ + -e XL_DASHBOARD_USERNAME=${app_use} \ + -e XL_DASHBOARD_PASSWORD=${app_passwd} \ + -v /home/docker/xunlei/data:/xunlei/data \ + -v /home/docker/xunlei/downloads:/xunlei/downloads \ + -p ${docker_port}:2345 \ + cnk3x/xunlei + } - 78) + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_passwd="" + local app_size="1" + docker_app - local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" - local docker_name="panda-wiki-nginx" - local docker_port="2443" - local app_size="2" + ;; - docker_app_install() { - bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" - } - docker_app_update() { - docker_app_install - } + 78|PandaWiki) - docker_app_uninstall() { - docker_app_install - } + local app_name="PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local docker_name="panda-wiki-nginx" + local docker_port="2443" + local app_size="2" - docker_app_plus - ;; + docker_app_install() { + bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" + } + docker_app_update() { + docker_app_install + } - 79) + docker_app_uninstall() { + docker_app_install + } - local docker_name="beszel" - local docker_img="henrygd/beszel" - local docker_port=8079 + docker_app_plus + ;; - docker_rum() { - mkdir -p /home/docker/beszel && \ - docker run -d \ - --name beszel \ - --restart=unless-stopped \ - -v /home/docker/beszel:/beszel_data \ - -p ${docker_port}:8090 \ - henrygd/beszel - } + 79|beszel) - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_name="beszel" + local docker_img="henrygd/beszel" + local docker_port=8079 - ;; + docker_rum() { + mkdir -p /home/docker/beszel && \ + docker run -d \ + --name beszel \ + --restart=unless-stopped \ + -v /home/docker/beszel:/beszel_data \ + -p ${docker_port}:8090 \ + henrygd/beszel - 80) - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden-linkwarden-1" - local docker_port="8080" - local app_size="3" + } - docker_app_install() { - install git openssl - mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - # 下載官方 docker-compose 和 env 文件 - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" + ;; - # 生成隨機密鑰與密碼 - local ADMIN_EMAIL="admin@example.com" - local ADMIN_PASSWORD=$(openssl rand -hex 8) - sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env - sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env - sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env - sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env + 80|linkwarden) + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" + local docker_name="linkwarden" + local docker_port="8080" + local app_size="3" - # 追加管理員賬號信息 - echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env + docker_app_install() { + install git openssl + mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + # 下載官方 docker-compose 和 env 文件 + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 啟動容器 - docker compose up -d + # 生成隨機密鑰與密碼 + local ADMIN_EMAIL="admin@example.com" + local ADMIN_PASSWORD=$(openssl rand -hex 8) - clear - echo "已經安裝完成" - check_docker_app_ip + sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=http://localhost:${docker_port}/api/v1/auth|g" .env + sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$(openssl rand -hex 32)|g" .env + sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env + sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - } + # 追加管理員賬號信息 + echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env - docker_app_update() { - cd /home/docker/linkwarden && docker compose down --rmi all - curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml - curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - - # 保留原本的變量 - source .env - mv .env.new .env - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env - echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env - echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env - echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env - sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - - docker compose up -d - } + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - docker_app_uninstall() { - cd /home/docker/linkwarden && docker compose down --rmi all - rm -rf /home/docker/linkwarden - echo "應用已卸載" - } + # 啟動容器 + docker compose up -d - docker_app_plus + clear + echo "已經安裝完成" + check_docker_app_ip + + } + + docker_app_update() { + cd /home/docker/linkwarden && docker compose down --rmi all + curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml + curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" + + # 保留原本的變量 + source .env + mv .env.new .env + echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env + echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> .env + echo "MEILI_MASTER_KEY=$MEILI_MASTER_KEY" >> .env + echo "ADMIN_EMAIL=$ADMIN_EMAIL" >> .env + echo "ADMIN_PASSWORD=$ADMIN_PASSWORD" >> .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml + + docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/linkwarden && docker compose down --rmi all + rm -rf /home/docker/linkwarden + echo "應用已卸載" + } + + docker_app_plus - ;; + ;; - 81) - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" - local docker_name="jitsi" - local docker_port="8081" - local app_size="3" + 81|jitsi) + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" + local docker_name="jitsi" + local docker_port="8081" + local app_size="3" - docker_app_install() { + docker_app_install() { - add_yuming - mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" - cp env.example .env - ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} - sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env - docker compose up -d + add_yuming + mkdir -p /home/docker/jitsi && cd /home/docker/jitsi + wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) + unzip "$(ls -t | head -n 1)" + cd "$(ls -dt */ | head -n 1)" + cp env.example .env + ./gen-passwords.sh + mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env + sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + docker compose up -d - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" - } + } - docker_app_update() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - docker compose up -d + docker_app_update() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + docker compose up -d - } + } - docker_app_uninstall() { - cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all - rm -rf /home/docker/jitsi - echo "應用已卸載" - } + docker_app_uninstall() { + cd /home/docker/jitsi + cd "$(ls -dt */ | head -n 1)" + docker compose down --rmi all + rm -rf /home/docker/jitsi + echo "應用已卸載" + } - docker_app_plus + docker_app_plus - ;; + ;; - 82) + 82|gpt-load) - local docker_name="gpt-load" - local docker_img="tbphp/gpt-load:latest" - local docker_port=8082 + local docker_name="gpt-load" + local docker_img="tbphp/gpt-load:latest" + local docker_port=8082 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/gpt-load && \ - docker run -d --name gpt-load \ - -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ - -v "/home/docker/gpt-load/data":/app/data \ - tbphp/gpt-load:latest + mkdir -p /home/docker/gpt-load && \ + docker run -d --name gpt-load \ + -p ${docker_port}:3001 \ + -e AUTH_KEY=sk-123456 \ + -v "/home/docker/gpt-load/data":/app/data \ + tbphp/gpt-load:latest - } + } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 83) + 83|komari) - local docker_name="komari" - local docker_img="ghcr.io/komari-monitor/komari:latest" - local docker_port=8083 + local docker_name="komari" + local docker_img="ghcr.io/komari-monitor/komari:latest" + local docker_port=8083 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/komari && \ - docker run -d \ - --name komari \ - -p ${docker_port}:25774 \ - -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ - --restart=always \ - ghcr.io/komari-monitor/komari:latest + mkdir -p /home/docker/komari && \ + docker run -d \ + --name komari \ + -p ${docker_port}:25774 \ + -v /home/docker/komari:/app/data \ + -e ADMIN_USERNAME=admin \ + -e ADMIN_PASSWORD=1212156 \ + --restart=always \ + ghcr.io/komari-monitor/komari:latest - } + } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 84) + 84|wallos) - local docker_name="wallos" - local docker_img="bellamy/wallos:latest" - local docker_port=8084 + local docker_name="wallos" + local docker_img="bellamy/wallos:latest" + local docker_port=8084 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/wallos && \ - docker run -d --name wallos \ - -v /home/docker/wallos/db:/var/www/html/db \ - -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ - -e TZ=UTC \ - -p ${docker_port}:80 \ - --restart unless-stopped \ - bellamy/wallos:latest + mkdir -p /home/docker/wallos && \ + docker run -d --name wallos \ + -v /home/docker/wallos/db:/var/www/html/db \ + -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ + -e TZ=UTC \ + -p ${docker_port}:80 \ + --restart unless-stopped \ + bellamy/wallos:latest - } + } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 85) + 85|immich) - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" - local docker_port="8085" - local app_size="3" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: https://github.com/immich-app/immich" + local docker_name="immich" + local docker_port="8085" + local app_size="3" - docker_app_install() { - install git openssl - mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} + docker_app_install() { + install git openssl + mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} - wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml - wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml + wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml - docker compose up -d + docker compose up -d - clear - echo "已經安裝完成" - check_docker_app_ip + clear + echo "已經安裝完成" + check_docker_app_ip - } + } - docker_app_update() { - cd /home/docker/${docker_name} && docker compose down --rmi all - docker_app_install - } + docker_app_update() { + cd /home/docker/${docker_name} && docker compose down --rmi all + docker_app_install + } - docker_app_uninstall() { - cd /home/docker/${docker_name} && docker compose down --rmi all - rm -rf /home/docker/${docker_name} - echo "應用已卸載" - } + docker_app_uninstall() { + cd /home/docker/${docker_name} && docker compose down --rmi all + rm -rf /home/docker/${docker_name} + echo "應用已卸載" + } - docker_app_plus + docker_app_plus - ;; + ;; - 86) + 86|jellyfin) - local docker_name="jellyfin" - local docker_img="jellyfin/jellyfin" - local docker_port=8086 + local docker_name="jellyfin" + local docker_img="jellyfin/jellyfin" + local docker_port=8086 - docker_rum() { + docker_rum() { - mkdir -p /home/docker/jellyfin/media - chmod -R 777 /home/docker/jellyfin + mkdir -p /home/docker/jellyfin/media + chmod -R 777 /home/docker/jellyfin - docker run -d \ - --name jellyfin \ - --user root \ - --volume /home/docker/jellyfin/config:/config \ - --volume /home/docker/jellyfin/cache:/cache \ - --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ - -p ${docker_port}:8096 \ - -p 7359:7359/udp \ - --restart=unless-stopped \ - jellyfin/jellyfin + docker run -d \ + --name jellyfin \ + --user root \ + --volume /home/docker/jellyfin/config:/config \ + --volume /home/docker/jellyfin/cache:/cache \ + --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ + -p ${docker_port}:8096 \ + -p 7359:7359/udp \ + --restart=unless-stopped \ + jellyfin/jellyfin - } + } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 87) + 87|synctv) - local docker_name="synctv" - local docker_img="synctvorg/synctv" - local docker_port=8087 + local docker_name="synctv" + local docker_img="synctvorg/synctv" + local docker_port=8087 - docker_rum() { + docker_rum() { - docker run -d \ - --name synctv \ - -v /home/docker/synctv:/root/.synctv \ - -p ${docker_port}:8080 \ - --restart=always \ - synctvorg/synctv + docker run -d \ + --name synctv \ + -v /home/docker/synctv:/root/.synctv \ + -p ${docker_port}:8080 \ + --restart=always \ + synctvorg/synctv - } + } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" - local docker_passwd="" - local app_size="1" - docker_app + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_passwd="" + local app_size="1" + docker_app - ;; + ;; - 88) + 88|owncast) - local docker_name="owncast" - local docker_img="owncast/owncast:latest" - local docker_port=8088 + local docker_name="owncast" + local docker_img="owncast/owncast:latest" + local docker_port=8088 - docker_rum() { + docker_rum() { - docker run -d \ - --name owncast \ - -p ${docker_port}:8080 \ - -p 1935:1935 \ - -v /home/docker/owncast/data:/app/data \ - --restart=always \ - owncast/owncast:latest + docker run -d \ + --name owncast \ + -p ${docker_port}:8080 \ + -p 1935:1935 \ + -v /home/docker/owncast/data:/app/data \ + --restart=always \ + owncast/owncast:latest - } + } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" - local app_size="1" - docker_app + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local app_size="1" + docker_app - ;; + ;; - 0) - kejilion - ;; - *) - echo "無效的輸入!" - ;; - esac - break_end + 0) + kejilion + ;; + *) + ;; + esac + break_end + sub_choice="" - done +done } @@ -12274,8 +12281,7 @@ EOF 39) clear - send_stats "命令行歷史記錄" - bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) + linux_fav ;; 41) @@ -13091,8 +13097,9 @@ echo "開放端口 k dkdk 8080 |k 打開端口 8080" echo "關閉端口 k gbdk 7800 |k 關閉端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" - - +echo "命令收藏夾 k fav | k 命令收藏夾" +echo "應用市場管理 k app" +echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" } @@ -13224,6 +13231,10 @@ else iptables_panel ;; + 命令收藏夹|fav) + linux_fav + ;; + status|状态) shift send_stats "軟件狀態查看" @@ -13303,8 +13314,17 @@ else fi ;; + + app) + shift + send_stats "應用$@" + linux_panel "$@" + ;; + + *) k_info ;; esac fi + From 12d26f91cde9c12970a567e52700cf1aec5973f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 20:59:47 +0800 Subject: [PATCH 0051/1285] Update kejilion.sh --- cn/kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 60ca8499d..599c27ce1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d From 40049b73554076416f2640c03b42df6a1eb3ab27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 14 Aug 2025 21:00:19 +0800 Subject: [PATCH 0052/1285] Update kejilion.sh --- kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2d4e3de54..6c9203fc9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d From df27ae7496bd310a9843130efdabe0fcd2bda888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 07:31:28 +0800 Subject: [PATCH 0053/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 599c27ce1..adb506e2c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" From 312e08753b25554473b7d72b0cee356fac527ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 07:31:57 +0800 Subject: [PATCH 0054/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6c9203fc9..2553bb345 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" From 8e821dae9af79690054621dccc528a69ad94be0c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 15 Aug 2025 00:09:17 +0000 Subject: [PATCH 0055/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-15=2000:09:17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 20 ++++++++++---------- jp/kejilion.sh | 24 ++++++++++++------------ kr/kejilion.sh | 14 +++++++------- tw/kejilion.sh | 12 ++++++------ 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 3af7d8ae4..12a8a1e7d 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1624,7 +1624,7 @@ nginx_upgrade() { docker restart $ldnmp_pods > /dev/null 2>&1 send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + echo "renew${ldnmp_pods}Finished" } @@ -2720,7 +2720,7 @@ setup_docker_dir() { docker_app() { -send_stats "${docker_name}manage" +send_stats "${docker_name}Management" while true; do clear @@ -3377,7 +3377,7 @@ ldnmp_web_status() { echo "" echo "Site Directory" echo "------------------------" - echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "Data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "operate" @@ -3709,7 +3709,7 @@ delete_forwarding_service() { read -e -p "Please enter the service name that needs to be deleted:" service_name # Use sed to delete the service and its related configurations sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "Serve$service_nameDeleted successfully from frpc.toml" + echo "Service$service_nameDeleted successfully from frpc.toml" docker restart frpc @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 6c0e6868c..8cb98949f 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -5729,7 +5729,7 @@ restore_backup() { if [ $? -eq 0 ]; then echo "バックアップと復元を正常に!" else - echo "バックアップリカバリに失敗しました!" + echo "バックアップリカバリが失敗しました!" exit 1 fi } @@ -5901,7 +5901,7 @@ use_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "接続$name ($ip)..." + echo "に接続します$name ($ip)..." if [[ -f "$password_or_key" ]]; then # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" @@ -6282,7 +6282,7 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期の方向に従ってソースとターゲットのパスを調整します + # 同期方向に従ってソースとターゲットパスを調整します if [[ "$direction" == "pull" ]]; then echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" @@ -6362,7 +6362,7 @@ schedule_task() { # 同じタスクが既に存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "エラー:このタスクのタイミング同期はすでに存在しています!" return fi @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d @@ -12306,7 +12306,7 @@ EOF echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" - echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "9.基本的なツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice @@ -12752,7 +12752,7 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元します" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}バッチでタスクを実行します${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}Tech Lionスクリプトをインストールします${gl_kjlan}12. ${gl_bai}システムを更新します${gl_kjlan}13. ${gl_bai}システムを掃除します" + echo -e "${gl_kjlan}11. ${gl_bai}Tech Lionスクリプトをインストールします${gl_kjlan}12. ${gl_bai}システムを更新します${gl_kjlan}13. ${gl_bai}システムをきれいにします" echo -e "${gl_kjlan}14. ${gl_bai}Dockerをインストールします${gl_kjlan}15. ${gl_bai}BBR3をインストールします${gl_kjlan}16. ${gl_bai}1G仮想メモリをセットアップします" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定します${gl_kjlan}18. ${gl_bai}すべてのポートを開きます${gl_kjlan}51. ${gl_bai}カスタムコマンド" echo -e "${gl_kjlan}------------------------${gl_bai}" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 9822eb994..5130534f4 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d @@ -13064,7 +13064,7 @@ echo "스크립트 시작 k" echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" echo "업데이트 시스템 K 업데이트 | K 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | k 청소" +echo "깨끗한 시스템 쓰레기 K Clean | K 청소" echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" echo "BBR3 제어판 K BBR3 | K bbrv3" echo "커널 튜닝 패널 K nhyh | K 커널 최적화" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index fbbe65333..d5bcfe726 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -8532,7 +8532,7 @@ while true; do fi case $sub_choice in - 1|bt) + 1|bt|baota) local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" @@ -8580,7 +8580,7 @@ while true; do install_panel ;; - 3|1panel) + 3|1p|1panel) local lujing="command -v 1pctl" local panelname="1Panel" @@ -8746,7 +8746,7 @@ while true; do done ;; - 8|qb) + 8|qb|QB) local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" @@ -10706,7 +10706,7 @@ while true; do local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" - local docker_name="linkwarden" + local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -10914,7 +10914,7 @@ while true; do local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" - local docker_name="immich" + local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -10924,7 +10924,7 @@ while true; do wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml wget -O .env ${gh_proxy}github.com/immich-app/immich/releases/latest/download/example.env - sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/cloud/docker-compose.yml + sed -i "s/2283:2283/${docker_port}:2283/g" /home/docker/${docker_name}/docker-compose.yml docker compose up -d From 457c4a8e9d44600f5487d5c389cd66e98c03745c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:47:50 +0800 Subject: [PATCH 0056/1285] Update kejilion.sh --- cn/kejilion.sh | 191 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 52 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index adb506e2c..23a83d4a7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2760,8 +2760,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2775,8 +2775,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2791,8 +2791,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" send_stats "卸载$docker_name" ;; @@ -2872,19 +2872,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3549,21 +3549,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}安装" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}控制" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}卸载" ;; *) @@ -3862,6 +3862,7 @@ frps_main_ports() { frps_panel() { send_stats "FRP服务端" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3892,8 +3893,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经安装完成" ;; 2) @@ -3902,8 +3903,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经更新完成" ;; 3) @@ -3913,8 +3914,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; 5) @@ -3959,6 +3960,7 @@ frps_panel() { frpc_panel() { send_stats "FRP客户端" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3990,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经安装完成" ;; 2) @@ -3998,8 +4000,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经更新完成" ;; @@ -4009,8 +4011,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; @@ -4041,6 +4043,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4083,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." read ;; 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." read ;; 3) send_stats "正在卸载 yt-dlp..." echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成。按任意键继续..." read ;; 5) @@ -4911,7 +4914,6 @@ bbrv3() { echo "------------------------------------------------" echo "仅支持Debian/Ubuntu" echo "请备份数据,将为你升级Linux内核开启BBR3" - echo "VPS是512M内存的,请提前添加1G虚拟内存,防止因内存不足失联!" echo "------------------------------------------------" read -e -p "确定继续吗?(Y/N): " choice @@ -8533,7 +8535,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8561,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8586,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8610,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8642,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8673,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8714,8 @@ while true; do 7|nezha) clear send_stats "搭建哪吒" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8758,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8795,7 @@ while true; do send_stats "搭建邮局" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8863,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8876,8 +8888,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8891,8 +8903,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; @@ -8908,6 +8920,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8968,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +8999,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9028,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9064,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9092,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9120,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9142,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9175,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,6 +9204,7 @@ while true; do 19|safeline) send_stats "搭建雷池" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do @@ -9208,8 +9230,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9221,8 +9243,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经更新完成" check_docker_app_ip @@ -9233,8 +9255,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9271,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9299,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9322,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9349,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9369,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9410,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9431,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9451,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9471,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9491,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9516,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9549,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9576,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9597,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9622,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9647,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9675,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9697,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9732,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9752,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9770,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9795,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9820,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9841,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9861,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9887,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9908,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9947,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9972,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10003,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10034,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10058,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10079,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10102,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10110,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10131,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10170,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10223,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10261,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10287,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10326,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10346,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10365,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10341,6 +10405,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10429,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10448,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10480,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10512,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10542,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10572,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10602,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10632,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10662,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10688,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10724,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10752,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10780,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10853,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10904,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10933,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10965,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +10994,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11037,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11073,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11101,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 From 3b509a1c9e2c429108a6e4d1e0b2ef7a7d1e0b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:48:20 +0800 Subject: [PATCH 0057/1285] Update kejilion.sh --- kejilion.sh | 191 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 52 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2553bb345..1882d4dbc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2760,8 +2760,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2775,8 +2775,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2791,8 +2791,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" send_stats "卸载$docker_name" ;; @@ -2872,19 +2872,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3549,21 +3549,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}安装" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}控制" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}卸载" ;; *) @@ -3862,6 +3862,7 @@ frps_main_ports() { frps_panel() { send_stats "FRP服务端" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3892,8 +3893,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经安装完成" ;; 2) @@ -3902,8 +3903,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经更新完成" ;; 3) @@ -3913,8 +3914,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; 5) @@ -3959,6 +3960,7 @@ frps_panel() { frpc_panel() { send_stats "FRP客户端" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3990,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经安装完成" ;; 2) @@ -3998,8 +4000,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经更新完成" ;; @@ -4009,8 +4011,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; @@ -4041,6 +4043,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4083,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." read ;; 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." read ;; 3) send_stats "正在卸载 yt-dlp..." echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成。按任意键继续..." read ;; 5) @@ -4911,7 +4914,6 @@ bbrv3() { echo "------------------------------------------------" echo "仅支持Debian/Ubuntu" echo "请备份数据,将为你升级Linux内核开启BBR3" - echo "VPS是512M内存的,请提前添加1G虚拟内存,防止因内存不足失联!" echo "------------------------------------------------" read -e -p "确定继续吗?(Y/N): " choice @@ -8533,7 +8535,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8561,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8586,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8610,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8642,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8673,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8714,8 @@ while true; do 7|nezha) clear send_stats "搭建哪吒" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8758,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8795,7 @@ while true; do send_stats "搭建邮局" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8863,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8876,8 +8888,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8891,8 +8903,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" ;; @@ -8908,6 +8920,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8968,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +8999,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9028,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9064,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9092,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9120,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9142,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9175,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,6 +9204,7 @@ while true; do 19|safeline) send_stats "搭建雷池" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do @@ -9208,8 +9230,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9221,8 +9243,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经更新完成" check_docker_app_ip @@ -9233,8 +9255,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9271,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9299,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9322,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9349,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9369,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9410,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9431,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9451,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9471,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9491,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9516,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9549,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9576,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9597,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9622,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9647,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9675,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9697,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9732,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9752,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9770,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9795,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9820,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9841,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9861,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9887,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9908,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9947,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9972,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10003,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10034,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10058,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10079,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10102,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10110,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10131,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10170,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10223,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10261,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10287,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10326,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10346,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10365,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10341,6 +10405,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10429,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10448,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10480,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10512,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10542,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10572,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10602,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10632,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10662,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10688,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10724,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10752,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10780,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10853,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10904,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10933,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10965,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +10994,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11037,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11073,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11101,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 From 06b7a91c3728774b954883a7b500258101383a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:57:30 +0800 Subject: [PATCH 0058/1285] Update kejilion.sh --- kejilion.sh | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1882d4dbc..7c741397d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2761,7 +2761,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2776,7 +2776,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2873,12 +2873,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 2) docker_app_update - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall @@ -3550,13 +3550,13 @@ while true; do iptables_open panel_app_install - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}安装" ;; 2) panel_app_manage - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}控制" ;; @@ -3894,7 +3894,7 @@ frps_panel() { install_docker generate_frps_config - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经安装完成" ;; 2) @@ -3904,7 +3904,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经更新完成" ;; 3) @@ -3991,7 +3991,7 @@ frpc_panel() { install_docker configure_frpc - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经安装完成" ;; 2) @@ -4001,7 +4001,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经更新完成" ;; @@ -4084,7 +4084,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." read ;; 2) @@ -4092,7 +4092,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." read ;; 3) @@ -8864,7 +8864,7 @@ while true; do -d analogic/poste.io - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8889,7 +8889,7 @@ while true; do -d analogic/poste.i - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -9231,7 +9231,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9244,7 +9244,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From 86ad02a95e7844054ba4a179af3c5bffa4afe760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:59:19 +0800 Subject: [PATCH 0059/1285] Update kejilion.sh --- cn/kejilion.sh | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 23a83d4a7..746464522 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2761,7 +2761,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2776,7 +2776,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "$docker_name 已经安装完成" @@ -2873,12 +2873,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 2) docker_app_update - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt ;; 3) docker_app_uninstall @@ -3550,13 +3550,13 @@ while true; do iptables_open panel_app_install - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}安装" ;; 2) panel_app_manage - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt send_stats "${panelname}控制" ;; @@ -3894,7 +3894,7 @@ frps_panel() { install_docker generate_frps_config - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经安装完成" ;; 2) @@ -3904,7 +3904,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP服务端已经更新完成" ;; 3) @@ -3991,7 +3991,7 @@ frpc_panel() { install_docker configure_frpc - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经安装完成" ;; 2) @@ -4001,7 +4001,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "FRP客户端已经更新完成" ;; @@ -4084,7 +4084,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "安装完成。按任意键继续..." read ;; 2) @@ -4092,7 +4092,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt echo "更新完成。按任意键继续..." read ;; 3) @@ -8864,7 +8864,7 @@ while true; do -d analogic/poste.io - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -8889,7 +8889,7 @@ while true; do -d analogic/poste.i - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "poste.io已经安装完成" @@ -9231,7 +9231,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9244,7 +9244,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From fff796a7fe29a3d0043e6a5389a4009ceed919f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 16:12:41 +0800 Subject: [PATCH 0060/1285] Update kejilion.sh --- cn/kejilion.sh | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 746464522..83dd2fc6d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2717,6 +2717,13 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { @@ -2761,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name 已经安装完成" @@ -2776,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name 已经安装完成" @@ -2873,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall @@ -3550,13 +3557,13 @@ while true; do iptables_open panel_app_install - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}安装" ;; 2) panel_app_manage - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}控制" ;; @@ -3894,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服务端已经安装完成" ;; 2) @@ -3904,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服务端已经更新完成" ;; 3) @@ -3991,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客户端已经安装完成" ;; 2) @@ -4001,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客户端已经更新完成" ;; @@ -4084,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "安装完成。按任意键继续..." read ;; 2) @@ -4092,7 +4099,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "更新完成。按任意键继续..." read ;; 3) @@ -8864,7 +8871,7 @@ while true; do -d analogic/poste.io - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已经安装完成" @@ -8889,7 +8896,7 @@ while true; do -d analogic/poste.i - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已经安装完成" @@ -9231,7 +9238,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9244,7 +9251,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From 60879deb4af904db6cd762dc3003026a8df7551b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 16:13:18 +0800 Subject: [PATCH 0061/1285] Update kejilion.sh --- kejilion.sh | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7c741397d..9ea5f7ea3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2717,6 +2717,13 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { @@ -2761,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name 已经安装完成" @@ -2776,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name 已经安装完成" @@ -2873,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall @@ -3550,13 +3557,13 @@ while true; do iptables_open panel_app_install - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}安装" ;; 2) panel_app_manage - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}控制" ;; @@ -3894,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服务端已经安装完成" ;; 2) @@ -3904,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服务端已经更新完成" ;; 3) @@ -3991,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客户端已经安装完成" ;; 2) @@ -4001,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客户端已经更新完成" ;; @@ -4084,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "安装完成。按任意键继续..." read ;; 2) @@ -4092,7 +4099,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "更新完成。按任意键继续..." read ;; 3) @@ -8864,7 +8871,7 @@ while true; do -d analogic/poste.io - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已经安装完成" @@ -8889,7 +8896,7 @@ while true; do -d analogic/poste.i - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已经安装完成" @@ -9231,7 +9238,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9244,7 +9251,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - touch /home/docker/appno.txt; grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From 7d582e269d084c3421bd597f12f350d35b607223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 17:10:45 +0800 Subject: [PATCH 0062/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 83dd2fc6d..37a29051d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10390,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} From 930a44e83a596bf844ea33ccbf4ae8dca6d4a3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 15 Aug 2025 17:11:37 +0800 Subject: [PATCH 0063/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 9ea5f7ea3..6a4216cc9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10390,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} From dbd4d272a3833b1ccf85ee61a1f5ba8841a8d37c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 15 Aug 2025 12:28:25 +0000 Subject: [PATCH 0064/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-15=2012:28:25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 232 ++++++++++++++++++++++++++++------------ jp/kejilion.sh | 280 +++++++++++++++++++++++++++++++++---------------- kr/kejilion.sh | 276 ++++++++++++++++++++++++++++++++---------------- tw/kejilion.sh | 200 +++++++++++++++++++++++++---------- 4 files changed, 682 insertions(+), 306 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 12a8a1e7d..4aca50ce2 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1624,7 +1624,7 @@ nginx_upgrade() { docker restart $ldnmp_pods > /dev/null 2>&1 send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finished" + echo "renew${ldnmp_pods}Finish" } @@ -1740,7 +1740,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to the mode parameter + # Decide to turn on or off WAF according to mode parameters if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2717,10 +2717,17 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { -send_stats "${docker_name}Management" +send_stats "${docker_name}manage" while true; do clear @@ -2760,8 +2767,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_nameInstalled" @@ -2775,8 +2782,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_nameInstalled" @@ -2791,8 +2798,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -2872,19 +2879,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3377,7 +3384,7 @@ ldnmp_web_status() { echo "" echo "Site Directory" echo "------------------------" - echo -e "Data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "operate" @@ -3549,21 +3556,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}Install" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}control" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}uninstall" ;; *) @@ -3709,7 +3716,7 @@ delete_forwarding_service() { read -e -p "Please enter the service name that needs to be deleted:" service_name # Use sed to delete the service and its related configurations sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "Service$service_nameDeleted successfully from frpc.toml" + echo "Serve$service_nameDeleted successfully from frpc.toml" docker restart frpc @@ -3862,6 +3869,7 @@ frps_main_ports() { frps_panel() { send_stats "FRP server" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3892,8 +3900,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "The FRP server has been installed" ;; 2) @@ -3902,8 +3910,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "The FRP server has been updated" ;; 3) @@ -3913,8 +3921,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; 5) @@ -3959,6 +3967,7 @@ frps_panel() { frpc_panel() { send_stats "FRP Client" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "The FRP client has been installed" ;; 2) @@ -3998,8 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "The FRP client has been updated" ;; @@ -4009,8 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; @@ -4041,6 +4050,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4090,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "The installation is complete. Press any key to continue..." read ;; 2) send_stats "Update yt-dlp..." echo "Update yt-dlp..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "Update completed. Press any key to continue..." read ;; 3) send_stats "Uninstalling yt-dlp..." echo "Uninstalling yt-dlp..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "Uninstall is complete. Press any key to continue..." read ;; 5) @@ -4911,7 +4921,6 @@ bbrv3() { echo "------------------------------------------------" echo "Only support Debian/Ubuntu" echo "Please back up the data and will enable BBR3 for you to upgrade the Linux kernel." - echo "VPS has 512M memory, please add 1G virtual memory in advance to prevent missing contact due to insufficient memory!" echo "------------------------------------------------" read -e -p "Are you sure to continue? (Y/N):" choice @@ -4980,7 +4989,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Operating system detected:$os_name $os_version" + echo "Detected operating systems:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -5809,7 +5818,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Example to create a new connection:" + echo "Create a new connection example:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -5950,7 +5959,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can be connected to other Linux systems via SSH" + echo "Can connect to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -7508,7 +7517,7 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" - echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" + echo -e "${gl_huang}25. ${gl_bai}Install the Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" echo -e "${gl_huang}30. ${gl_bai}Customize static site" echo -e "${gl_huang}------------------------" @@ -7684,7 +7693,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "Backend login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -7915,7 +7924,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8533,7 +8542,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8568,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8593,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8617,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8649,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8680,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8721,8 @@ while true; do 7|nezha) clear send_stats "Build Nezha" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8765,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8802,7 @@ while true; do send_stats "Build a post office" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8870,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io has been installed" @@ -8876,8 +8895,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io has been installed" @@ -8891,8 +8910,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "The app has been uninstalled" ;; @@ -8908,6 +8927,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8975,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +9006,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9035,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9071,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9099,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9127,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9149,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9182,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,6 +9211,7 @@ while true; do 19|safeline) send_stats "Build a Thunder Pool" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do @@ -9208,8 +9237,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "The Thunder Pool WAF panel has been installed" check_docker_app_ip @@ -9221,8 +9250,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Thunder Pool WAF panel has been updated" check_docker_app_ip @@ -9233,8 +9262,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9278,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9306,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9329,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9356,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9376,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9417,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9438,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9458,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9478,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9498,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9523,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9556,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9583,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9604,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9629,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9654,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9682,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9704,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9739,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9759,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9777,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9802,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9827,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9848,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9868,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9894,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9915,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9954,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9979,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10010,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10041,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10065,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10086,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10109,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10117,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10138,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10177,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10230,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10268,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10294,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10333,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10353,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10372,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10319,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -10341,6 +10412,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10436,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10455,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10487,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10519,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10549,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10579,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10609,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10639,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10669,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10695,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10731,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10759,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10787,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10860,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10911,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10940,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10972,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +11001,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11044,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11080,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11108,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 @@ -11263,7 +11357,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" @@ -11294,7 +11388,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys are set" + echo "Shortcut keys have been set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -12306,7 +12400,7 @@ EOF echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" echo -e "8. Automatically optimize DNS address${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "9. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "9. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice @@ -12401,7 +12495,7 @@ EOF echo "Privacy and Security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" @@ -12538,7 +12632,7 @@ linux_file() { 5) # 删除目录 read -e -p "Please enter the directory name to delete:" dirname rm -rf "$dirname" && echo "Directory has been deleted" || echo "Deletion failed" - send_stats "Delete Directory" + send_stats "Delete directory" ;; 6) # 返回上一级选单目录 cd .. diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 8cb98949f..4da715382 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1740,7 +1740,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることにしました + # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2101,7 +2101,7 @@ web_security() { echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CFのグローバルAPIキーを入力してください。" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2129,7 +2129,7 @@ web_security() { echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CFのグローバルAPIキーを入力してください。" cftoken read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID cd ~ @@ -2717,6 +2717,13 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { @@ -2760,8 +2767,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_nameインストール" @@ -2775,8 +2782,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_nameインストール" @@ -2791,8 +2798,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" send_stats "アンインストール$docker_name" ;; @@ -2872,19 +2879,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3549,21 +3556,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}インストール" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}コントロール" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}アンインストール" ;; *) @@ -3682,7 +3689,7 @@ add_forwarding_service() { read -e -p "イントラネットポートを入力してください:" local_port read -e -p "外部ネットワークポートを入力してください:" remote_port - # ユーザー入力を構成ファイルに書き込みます + # 構成ファイルにユーザー入力を書き込みます cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3862,6 +3869,7 @@ frps_main_ports() { frps_panel() { send_stats "FRPサーバー" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3869,7 +3877,7 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRPサーバー$check_frp $update_status" - echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" + echo "FRPイントラネット浸透サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then @@ -3892,8 +3900,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRPサーバーがインストールされています" ;; 2) @@ -3902,8 +3910,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRPサーバーが更新されました" ;; 3) @@ -3913,8 +3921,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; 5) @@ -3959,6 +3967,7 @@ frps_panel() { frpc_panel() { send_stats "FRPクライアント" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRPクライアントがインストールされています" ;; 2) @@ -3998,8 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRPクライアントが更新されました" ;; @@ -4009,8 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; @@ -4041,6 +4050,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4090,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) send_stats "yt-dlpを更新..." echo "yt-dlpを更新..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) send_stats "yt-dlpのアンインストール..." echo "yt-dlpのアンインストール..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) @@ -4511,7 +4521,7 @@ echo -e "${gl_lv}ルートログインがセットアップされます!${gl_b root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能では、ルートユーザーを実行する必要があります!" && break_end && kejilion } @@ -4860,7 +4870,7 @@ bbrv3() { echo "" echo "カーネル管理" echo "------------------------" - echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" + echo "1。BBRV3カーネルを更新します2。BBRV3カーネルをアンインストールします" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -4911,7 +4921,6 @@ bbrv3() { echo "------------------------------------------------" echo "Debian/Ubuntuのみをサポートします" echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" - echo "VPSには512mのメモリがあります。メモリが不十分なため、接触の欠落を防ぐために、事前に1G仮想メモリを追加してください!" echo "------------------------------------------------" read -e -p "必ず続行しますか? (y/n):" choice @@ -5364,7 +5373,7 @@ Kernel_optimize() { echo "--------------------" echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを同時に改善します。" + echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" @@ -5729,7 +5738,7 @@ restore_backup() { if [ $? -eq 0 ]; then echo "バックアップと復元を正常に!" else - echo "バックアップリカバリが失敗しました!" + echo "バックアップリカバリに失敗しました!" exit 1 fi } @@ -5809,7 +5818,7 @@ list_connections() { # 新しい接続を追加します add_connection() { send_stats "新しい接続を追加します" - echo "新しい接続を作成する例:" + echo "新しい接続例を作成します:" echo "- 接続名:my_server" echo "- IPアドレス:192.168.1.100" echo "- ユーザー名:root" @@ -5901,7 +5910,7 @@ use_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "に接続します$name ($ip)..." + echo "接続$name ($ip)..." if [[ -f "$password_or_key" ]]; then # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" @@ -6282,7 +6291,7 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期方向に従ってソースとターゲットパスを調整します + # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" @@ -6360,7 +6369,7 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクが既に存在するかどうかを確認してください + # 同じタスクがすでに存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then echo "エラー:このタスクのタイミング同期はすでに存在しています!" return @@ -6640,7 +6649,7 @@ linux_tools() { clear echo "ツールがインストールされており、使用方法は次のとおりです。" ffmpeg --help - send_stats "ffmpegをインストールします" + send_stats "FFMPEGをインストールします" ;; 11) @@ -6970,7 +6979,7 @@ linux_docker() { 3) send_stats "インターネットに参加してください" read -e -p "出口ネットワーク名:" dockernetwork - read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames + read -e -p "これらのコンテナはネットワークを出ます(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7162,7 +7171,7 @@ linux_test() { case $sub_choice in 1) clear - send_stats "CHATGPTはステータス検出のロックを解除します" + send_stats "CHATGPTステータス検出のロックを解除します" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) @@ -7684,7 +7693,7 @@ linux_ldnmp() { echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "バックエンドログインパス: /admin" echo "------------------------" echo "ユーザー名:admin" echo "パスワード:管理者" @@ -7915,7 +7924,7 @@ linux_ldnmp() { ;; 2) echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8304,7 +8313,7 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" + echo "1.更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" echo "------------------------" echo "5。完全な環境を更新します" echo "------------------------" @@ -8499,7 +8508,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHub加速ステーション${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" @@ -8533,7 +8542,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8568,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8593,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8617,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8649,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8680,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8721,8 @@ while true; do 7|nezha) clear send_stats "ネザを作る" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8765,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8802,7 @@ while true; do send_stats "郵便局を建設します" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8870,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Poste.ioがインストールされています" @@ -8876,8 +8895,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Poste.ioがインストールされています" @@ -8891,8 +8910,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アプリはアンインストールされています" ;; @@ -8908,6 +8927,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8975,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +9006,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9035,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9071,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9099,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9127,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9149,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9182,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,6 +9211,7 @@ while true; do 19|safeline) send_stats "サンダープールを構築します" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do @@ -9208,8 +9237,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip @@ -9221,8 +9250,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "サンダープールWAFパネルが更新されました" check_docker_app_ip @@ -9233,8 +9262,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9278,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9306,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9329,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9356,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9376,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9417,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9438,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9458,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9478,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9498,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9523,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9556,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9583,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9604,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9629,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9654,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9682,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9704,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9739,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9759,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9777,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9802,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9827,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9848,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9868,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9894,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9915,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9954,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9979,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10010,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10041,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10065,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10086,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10109,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10117,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10138,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10177,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10230,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10268,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10294,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10333,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10353,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10372,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10319,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -10341,6 +10412,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10436,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10455,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10487,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10519,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10549,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10579,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10609,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10639,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10669,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10695,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10731,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10759,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10787,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10860,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10911,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10940,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10972,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +11001,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11044,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11080,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11108,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 @@ -11259,13 +11353,13 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" + echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度を設定します" echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" + echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHハイリスクの脆弱性を修正します" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" @@ -11287,7 +11381,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian + read -e -p "ショートカットキーを入力してください(0を入力して終了してください):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -11747,7 +11841,7 @@ EOF echo "------------------------" echo "アメリカ" echo "21。WesternTime22。東部時間" - echo "23。カナダ時間24。メキシコの時間" + echo "23. 加拿大时间 24. 墨西哥时间" echo "25。ブラジル時間26。アルゼンチン時間" echo "------------------------" echo "31。UTCグローバル標準時間" @@ -11920,7 +12014,7 @@ EOF break # 跳出 ;; esac - send_stats "時限タスクを追加します" + send_stats "タイムされたタスクを追加します" ;; 2) read -e -p "削除する必要があるキーワードを入力してください。" kquest @@ -12073,7 +12167,7 @@ EOF case "$Limiting" in 1) # 新しい仮想メモリサイズを入力します - echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" + echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源を停止して、トラフィックエラーやオーバーフローを避けることができます。" read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb @@ -12099,7 +12193,7 @@ EOF crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "現在の制限シャットダウン関数はオフになっています" + echo "電流制限シャットダウン機能はオフになっています" ;; *) break @@ -12120,7 +12214,7 @@ EOF echo "------------------------------------------------" echo "キーペアが生成され、SSHログインのより安全な方法" echo "------------------------" - echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" + echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -12306,7 +12400,7 @@ EOF echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" - echo -e "9.基本的なツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice @@ -12401,7 +12495,7 @@ EOF echo "プライバシーとセキュリティ" echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" echo "--------------------" @@ -12525,7 +12619,7 @@ linux_file() { ;; 3) # 修改目录权限 read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可を入力してください(755など):" perm + read -e -p "許可(755など)を入力してください。" perm chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" send_stats "ディレクトリ権限を変更します" ;; @@ -12557,7 +12651,7 @@ linux_file() { ;; 13) # 修改文件权限 read -e -p "ファイル名を入力してください:" filename - read -e -p "許可を入力してください(755など):" perm + read -e -p "許可(755など)を入力してください。" perm chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" send_stats "ファイル権限を変更します" ;; @@ -12589,7 +12683,7 @@ linux_file() { read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" + send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリが存在しません" continue fi @@ -12752,7 +12846,7 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元します" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}バッチでタスクを実行します${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}Tech Lionスクリプトをインストールします${gl_kjlan}12. ${gl_bai}システムを更新します${gl_kjlan}13. ${gl_bai}システムをきれいにします" + echo -e "${gl_kjlan}11. ${gl_bai}Tech Lionスクリプトをインストールします${gl_kjlan}12. ${gl_bai}システムを更新します${gl_kjlan}13. ${gl_bai}システムを掃除します" echo -e "${gl_kjlan}14. ${gl_bai}Dockerをインストールします${gl_kjlan}15. ${gl_bai}BBR3をインストールします${gl_kjlan}16. ${gl_bai}1G仮想メモリをセットアップします" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定します${gl_kjlan}18. ${gl_bai}すべてのポートを開きます${gl_kjlan}51. ${gl_bai}カスタムコマンド" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -12868,7 +12962,7 @@ echo "------------------------" echo -e "${gl_lan}dmit四半期あたり28ドルUS CN2GIA 1コア2Gメモリ20Gハードドライブ800gトラフィック${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://www.dmit.io/aff.php?aff = 4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS月額6.9 $ 6.9東京ソフトバンク2コア1Gメモリ20gハードドライブ1Tトラフィック${gl_bai}" +echo -e "${gl_zi}V.PS月額6.9 $ 6.9東京ソフトバンク2コア1Gメモリ20gハードドライブ1tトラフィック${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?faffid=1355 &? affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}より人気のあるVPSオファー${gl_bai}" @@ -13087,11 +13181,11 @@ echo "ドメイン名証明書の有効期限クエリK SSL PS" echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" echo "Docker Container Management K Docker PS | K Dockerコンテナ" echo "Docker Image Management K Docker IMG | K Docker画像" -echo "LDNMPサイト管理k Web" +echo "LDNMPサイト管理K Web" echo "LDNMPキャッシュクリーンアップK Webキャッシュ" echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" -echo "ロードバランスkロードバランス| kロードバランシングをインストールします" +echo "ロードバランシングkロードバランス| kロードバランシングをインストールします" echo "ファイアウォールパネルk fhq | kファイアウォール" echo "オープンポートK DKDK 8080 | Kオープンポート8080" echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" @@ -13151,7 +13245,7 @@ else rsync_run) shift - send_stats "タイム付きRSYNC同期" + send_stats "タイミング付きRSYNC同期" run_task "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 5130534f4..3be3371ea 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 명령을 실행할 함수를 정의합니다 +# 명령을 실행하는 함수를 정의합니다 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -334,7 +334,7 @@ enable() { break_end() { - echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" + echo -e "${gl_lv}操作完成${gl_bai}" echo "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" echo "" @@ -520,7 +520,7 @@ while true; do echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "새 컨테이너를 만듭니다" @@ -644,7 +644,7 @@ while true; do echo "도커 이미지 목록" docker image ls echo "" - echo "미러 작동" + echo "거울 작동" echo "------------------------" echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" @@ -1234,7 +1234,7 @@ iptables_panel() { ;; 17) - read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오 :" country_code manage_country_rules unblock $country_code send_stats "나라를 정리하십시오$country_codeIP" ;; @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -1664,7 +1664,7 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트하십시오 + # 캐시 청소 여부를 사용자에게 프롬프트합니다 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" @@ -1723,7 +1723,7 @@ web_del() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. + # 删除数据库前检查是否存在,避免报错 echo "데이터베이스 삭제 :$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -2717,6 +2717,13 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { @@ -2760,8 +2767,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name설치" @@ -2775,8 +2782,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name설치" @@ -2791,8 +2798,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" send_stats "제거하십시오$docker_name" ;; @@ -2872,19 +2879,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3549,21 +3556,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}설치하다" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}제어" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}제거하십시오" ;; *) @@ -3862,6 +3869,7 @@ frps_main_ports() { frps_panel() { send_stats "FRP 서버" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3892,8 +3900,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP 서버가 설치되었습니다" ;; 2) @@ -3902,8 +3910,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP 서버가 업데이트되었습니다" ;; 3) @@ -3913,12 +3921,12 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; 5) - echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" + echo "반전 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" send_stats "외부 도메인 이름에 대한 FRP 액세스" add_yuming read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port @@ -3938,7 +3946,7 @@ frps_panel() { 8) send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3959,6 +3967,7 @@ frps_panel() { frpc_panel() { send_stats "FRP 클라이언트" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP 클라이언트가 설치되었습니다" ;; 2) @@ -3998,8 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP 클라이언트가 업데이트되었습니다" ;; @@ -4009,8 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; @@ -4041,6 +4050,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4090,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 2) send_stats "yt-dlp 업데이트 ..." echo "yt-dlp 업데이트 ..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 3) send_stats "yt-dlp 제거 ..." echo "yt-dlp 제거 ..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 5) @@ -4125,7 +4135,7 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "배치 다운로드가 완료되었습니다. 키를 눌러 계속하십시오 ..." ;; + read -e -p "배치 다운로드가 완료되었고, 키를 눌러 계속하십시오 ..." ;; 7) send_stats "맞춤형 비디오 다운로드" read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom @@ -4911,7 +4921,6 @@ bbrv3() { echo "------------------------------------------------" echo "데비안/우분투 만 지원합니다" echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." - echo "VPS는 512m 메모리를 가지고 있습니다. 메모리가 충분하지 않아 접점 누락을 방지하기 위해 1G 가상 메모리를 미리 추가하십시오!" echo "------------------------------------------------" read -e -p "계속할거야? (Y/N) :" choice @@ -4980,7 +4989,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "운영 체제 감지 :$os_name $os_version" + echo "감지 된 운영 체제 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -5809,7 +5818,7 @@ list_connections() { # 새 연결을 추가하십시오 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결을 만드는 예 :" + echo "새 연결 예제 :" echo "- 연결 이름 : my_server" echo "-IP 주소 : 192.168.1.100" echo "- 사용자 이름 : 루트" @@ -6087,11 +6096,11 @@ format_partition() { fi # 형식 파티션 - echo "파티션 서식 /dev /$PARTITION~을 위한$FS_TYPE ..." + echo "파티션 형식 /dev /$PARTITION~을 위한$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 형식이 성공적이었습니다!" + echo "파티션 형식이 성공했습니다!" else echo "파티션 형식이 실패했습니다!" fi @@ -6866,7 +6875,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" + echo -e "${gl_kjlan}20. ${gl_bai}도커 환경을 제거하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7136,7 +7145,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}네트워크 속도 측정" - echo -e "${gl_kjlan}11. ${gl_bai}Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + echo -e "${gl_kjlan}11. ${gl_bai}Besttrace Three Network Backhaul 지연 라우팅 테스트" echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" @@ -7330,7 +7339,7 @@ linux_Oracle() { read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용 백분율 범위 (예 : 10-20) [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 사용량 백분율 범위 (예 : 10-20)를 입력하십시오 [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util @@ -7513,7 +7522,7 @@ linux_ldnmp() { echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" - echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" + echo -e "${gl_huang}33. ${gl_bai}시간이 정한 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" @@ -7842,7 +7851,7 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드합니다" echo "-------------" echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download @@ -7915,7 +7924,7 @@ linux_ldnmp() { ;; 2) echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8194,7 +8203,7 @@ linux_ldnmp() { 33) clear - send_stats "시간이 지정된 원격 백업" + send_stats "시간이 정한 원격 백업" read -e -p "원격 서버 IP를 입력하십시오." useip read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd @@ -8483,7 +8492,7 @@ while true; do echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" - echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" + echo -e "${gl_kjlan}19. ${color19}Thunder Pool Waf 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" @@ -8511,7 +8520,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" + echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" echo -e "${gl_kjlan}------------------------" @@ -8533,7 +8542,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8568,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8593,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8617,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8649,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8680,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8721,8 @@ while true; do 7|nezha) clear send_stats "Nezha를 구축하십시오" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8765,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8802,7 @@ while true; do send_stats "우체국을 건설하십시오" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8870,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Poste.io가 설치되었습니다" @@ -8876,8 +8895,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Poste.io가 설치되었습니다" @@ -8891,8 +8910,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" ;; @@ -8908,6 +8927,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8975,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +9006,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9035,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9071,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9099,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9127,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9149,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9182,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,13 +9211,14 @@ while true; do 19|safeline) send_stats "천둥 수영장을 건설하십시오" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." + echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip @@ -9208,8 +9237,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Thunder Pool WAF 패널이 설치되었습니다" check_docker_app_ip @@ -9221,8 +9250,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip @@ -9233,8 +9262,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9278,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9306,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9329,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9356,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9376,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9417,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9438,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9458,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9478,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9498,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9523,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9556,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9583,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9604,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9629,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9654,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9682,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9704,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9739,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9759,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9777,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9802,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9827,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9848,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9868,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9894,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9915,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9954,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9979,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10010,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10041,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10065,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10086,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10109,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10117,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10138,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10177,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10230,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10268,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10294,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10333,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10353,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10372,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10319,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -10341,6 +10412,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10436,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10455,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10487,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10519,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10549,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10579,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10609,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10639,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10669,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10695,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10731,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10759,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10787,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10860,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10911,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10940,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10972,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +11001,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11044,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11080,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11108,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 @@ -11203,7 +11297,7 @@ linux_work() { 22) read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME tmux_run - send_stats "사용자 정의 작업 공간" + send_stats "맞춤형 작업 공간" ;; @@ -11252,7 +11346,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" - echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" + echo -e "${gl_kjlan}3. ${gl_bai}루트 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" @@ -11263,7 +11357,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" @@ -11294,7 +11388,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" + echo "바로 가기 키가 설정되었습니다" send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings @@ -11459,7 +11553,7 @@ EOF ;; 9) root_use - send_stats "신규 사용자는 루트를 비활성화합니다" + send_stats "새로운 사용자가 루트를 비활성화합니다" read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username if [ "$new_username" == "0" ]; then break_end @@ -11731,7 +11825,7 @@ EOF echo "현재 시스템 시간 :$current_time" echo "" - echo "시간대 스위칭" + echo "시간대 전환" echo "------------------------" echo "아시아" echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" @@ -11743,7 +11837,7 @@ EOF echo "유럽" echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" - echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" + echo "15. 네덜란드의 위트레흐트 시간 16. 스페인의 마드리드 시간" echo "------------------------" echo "미국" echo "21. 서양 시간 22. 동부 시간" @@ -12559,7 +12653,7 @@ linux_file() { read -e -p "파일 이름을 입력하십시오 :" filename read -e -p "권한을 입력하십시오 (예 : 755) :" perm chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "파일 권한을 수정하십시오" + send_stats "파일 권한을 수정합니다" ;; 14) # 重命名文件 read -e -p "현재 파일 이름을 입력하십시오 :" current_name @@ -12622,7 +12716,7 @@ linux_file() { # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사합니다" + send_stats "파일 또는 디렉토리를 복사하십시오" ;; @@ -12856,7 +12950,7 @@ echo "------------------------" echo -e "${gl_lan}Leica Cloud Hong Kong CN2 Gia 한국 이중 ISP US CN2 GIA 할인${gl_bai}" echo -e "${gl_bai}웹 사이트 : https://www.lcayun.com/aff/zexuqbim${gl_bai}" echo "------------------------" -echo -e "${gl_lan}Racknerd $ 10.99 미국 1 코어 1G 메모리 20G 하드 드라이브 1T 트래픽 월에 한 달에 트래픽${gl_bai}" +echo -e "${gl_lan}Racknerd $ 10.99 미국 1 코어 1G 메모리 20g 하드 드라이브 1T 트래픽 월${gl_bai}" echo -e "${gl_bai}웹 사이트 : https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 52.7 달러 미국 1 코어 4G 메모리 50G 하드 드라이브 4T 트래픽 월${gl_bai}" @@ -13020,7 +13114,7 @@ echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립 echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" +echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택을 입력하십시오 :" choice @@ -13242,7 +13336,7 @@ else ;; start|启动) shift - send_stats "소프트웨어 시작" + send_stats "소프트웨어 스타트 업" start "$@" ;; stop|停止) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index d5bcfe726..7860f9ecf 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -2717,6 +2717,13 @@ setup_docker_dir() { } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker/appno.txt + +} + docker_app() { @@ -2760,8 +2767,8 @@ while true; do docker_rum setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name已經安裝完成" @@ -2775,8 +2782,8 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" docker_rum - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "$docker_name已經安裝完成" @@ -2791,8 +2798,8 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "應用已卸載" send_stats "解除安裝$docker_name" ;; @@ -2872,19 +2879,19 @@ docker_app_plus() { docker_app_install setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 2) docker_app_update - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) ;; 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt ;; 5) @@ -3549,21 +3556,21 @@ while true; do install wget iptables_open panel_app_install - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}安裝" ;; 2) panel_app_manage - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) send_stats "${panelname}控制" ;; 3) panel_app_uninstall - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "${panelname}解除安裝" ;; *) @@ -3862,6 +3869,7 @@ frps_main_ports() { frps_panel() { send_stats "FRP服務端" + local app_id="55" local docker_name="frps" local docker_port=8056 while true; do @@ -3892,8 +3900,8 @@ frps_panel() { install jq grep ss install_docker generate_frps_config - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服務端已經安裝完成" ;; 2) @@ -3902,8 +3910,8 @@ frps_panel() { docker rm -f frps && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP服務端已經更新完成" ;; 3) @@ -3913,8 +3921,8 @@ frps_panel() { rm -rf /home/frp close_port 8055 8056 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; 5) @@ -3959,6 +3967,7 @@ frps_panel() { frpc_panel() { send_stats "FRP客戶端" + local app_id="56" local docker_name="frpc" local docker_port=8055 while true; do @@ -3988,8 +3997,8 @@ frpc_panel() { install jq grep ss install_docker configure_frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客戶端已經安裝完成" ;; 2) @@ -3998,8 +4007,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine >/dev/null 2>&1 [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "FRP客戶端已經更新完成" ;; @@ -4009,8 +4018,8 @@ frpc_panel() { docker rm -f frpc && docker rmi kjlion/frp:alpine rm -rf /home/frp close_port 8055 - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; @@ -4041,6 +4050,7 @@ frpc_panel() { yt_menu_pro() { + local app_id="66" local VIDEO_DIR="/home/yt-dlp" local URL_FILE="$VIDEO_DIR/urls.txt" local ARCHIVE_FILE="$VIDEO_DIR/archive.txt" @@ -4080,24 +4090,24 @@ yt_menu_pro() { install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "安裝完成。按任意鍵繼續..." read ;; 2) send_stats "正在更新 yt-dlp..." echo "正在更新 yt-dlp..." yt-dlp -U - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) echo "更新完成。按任意鍵繼續..." read ;; 3) send_stats "正在卸載 yt-dlp..." echo "正在卸載 yt-dlp..." rm -f /usr/local/bin/yt-dlp - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成。按任意鍵繼續..." read ;; 5) @@ -4911,7 +4921,6 @@ bbrv3() { echo "------------------------------------------------" echo "僅支持Debian/Ubuntu" echo "請備份數據,將為你升級Linux內核開啟BBR3" - echo "VPS是512M內存的,請提前添加1G虛擬內存,防止因內存不足失聯!" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -8533,7 +8542,7 @@ while true; do case $sub_choice in 1|bt|baota) - + local app_id="1" local lujing="[ -d "/www/server/panel" ]" local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" @@ -8559,6 +8568,8 @@ while true; do ;; 2|aapanel) + + local app_id="2" local lujing="[ -d "/www/server/panel" ]" local panelname="aapanel" local panelurl="https://www.aapanel.com/new/index.html" @@ -8582,6 +8593,7 @@ while true; do ;; 3|1p|1panel) + local app_id="3" local lujing="command -v 1pctl" local panelname="1Panel" local panelurl="https://1panel.cn/" @@ -8605,6 +8617,7 @@ while true; do ;; 4|npm) + local app_id="4" local docker_name="npm" local docker_img="jc21/nginx-proxy-manager:latest" local docker_port=81 @@ -8636,6 +8649,7 @@ while true; do 5|openlist) + local app_id="5" local docker_name="openlist" local docker_img="openlistteam/openlist:latest-aria2" local docker_port=5244 @@ -8666,6 +8680,7 @@ while true; do 6|webtop-ubuntu) + local app_id="6" local docker_name="webtop-ubuntu" local docker_img="lscr.io/linuxserver/webtop:ubuntu-kde" local docker_port=3006 @@ -8706,6 +8721,8 @@ while true; do 7|nezha) clear send_stats "搭建哪吒" + + local app_id="7" local docker_name="nezha-dashboard" local docker_port=8008 while true; do @@ -8748,6 +8765,7 @@ while true; do 8|qb|QB) + local app_id="8" local docker_name="qbittorrent" local docker_img="lscr.io/linuxserver/qbittorrent:latest" local docker_port=8081 @@ -8784,6 +8802,7 @@ while true; do send_stats "搭建郵局" clear install telnet + local app_id="9" local docker_name=“mailserver” while true; do check_docker_app @@ -8851,8 +8870,8 @@ while true; do --restart=always \ -d analogic/poste.io - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已經安裝完成" @@ -8876,8 +8895,8 @@ while true; do --restart=always \ -d analogic/poste.i - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "poste.io已經安裝完成" @@ -8891,8 +8910,8 @@ while true; do docker rmi -f analogic/poste.io rm /home/docker/mail.txt rm -rf /home/docker/mail - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "應用已卸載" ;; @@ -8908,6 +8927,7 @@ while true; do 10|rocketchat) + local app_id="10" local app_name="Rocket.Chat聊天系统" local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," local app_url="官方介绍: https://www.rocket.chat/" @@ -8955,6 +8975,7 @@ while true; do 11|zentao) + local app_id="11" local docker_name="zentao-server" local docker_img="idoop/zentao:latest" local docker_port=82 @@ -8985,6 +9006,7 @@ while true; do ;; 12|qinglong) + local app_id="12" local docker_name="qinglong" local docker_img="whyour/qinglong:latest" local docker_port=5700 @@ -9013,6 +9035,7 @@ while true; do ;; 13|cloudreve) + local app_id="13" local app_name="cloudreve网盘" local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" @@ -9048,6 +9071,7 @@ while true; do ;; 14|easyimage) + local app_id="14" local docker_name="easyimage" local docker_img="ddsderek/easyimage:latest" local docker_port=8014 @@ -9075,6 +9099,7 @@ while true; do ;; 15|emby) + local app_id="15" local docker_name="emby" local docker_img="linuxserver/emby:latest" local docker_port=8015 @@ -9102,6 +9127,7 @@ while true; do ;; 16|looking) + local app_id="16" local docker_name="looking-glass" local docker_img="wikihostinc/looking-glass-server" local docker_port=8016 @@ -9123,6 +9149,7 @@ while true; do ;; 17|adguardhome) + local app_id="17" local docker_name="adguardhome" local docker_img="adguard/adguardhome" local docker_port=8017 @@ -9155,6 +9182,7 @@ while true; do 18|onlyoffice) + local app_id="18" local docker_name="onlyoffice" local docker_img="onlyoffice/documentserver" local docker_port=8018 @@ -9183,6 +9211,7 @@ while true; do 19|safeline) send_stats "搭建雷池" + local app_id="19" local docker_name=safeline-mgt local docker_port=9443 while true; do @@ -9208,8 +9237,8 @@ while true; do install_docker check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已經安裝完成" check_docker_app_ip @@ -9221,8 +9250,8 @@ while true; do bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - local app_no=$sub_choice - grep -qxF "${app_no}" /home/docker/appno.txt || echo "${app_no}" >> /home/docker/appno.txt + + mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear echo "雷池WAF面板已經更新完成" check_docker_app_ip @@ -9233,8 +9262,8 @@ while true; do 4) cd /data/safeline docker compose down --rmi all - local app_no=$sub_choice - sed -i "/\b${app_no}\b/d" /home/docker/appno.txt + + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" echo "docker compose down && docker compose down --rmi all" ;; @@ -9249,6 +9278,7 @@ while true; do ;; 20|portainer) + local app_id="20" local docker_name="portainer" local docker_img="portainer/portainer" local docker_port=8020 @@ -9276,6 +9306,7 @@ while true; do ;; 21|vscode) + local app_id="21" local docker_name="vscode-web" local docker_img="codercom/code-server" local docker_port=8021 @@ -9298,6 +9329,7 @@ while true; do 22|uptime-kuma) + local app_id="22" local docker_name="uptime-kuma" local docker_img="louislam/uptime-kuma:latest" local docker_port=8022 @@ -9324,6 +9356,7 @@ while true; do ;; 23|memos) + local app_id="23" local docker_name="memos" local docker_img="ghcr.io/usememos/memos:latest" local docker_port=8023 @@ -9343,6 +9376,7 @@ while true; do ;; 24|webtop) + local app_id="24" local docker_name="webtop" local docker_img="lscr.io/linuxserver/webtop:latest" local docker_port=8024 @@ -9383,6 +9417,7 @@ while true; do ;; 25|nextcloud) + local app_id="25" local docker_name="nextcloud" local docker_img="nextcloud:latest" local docker_port=8025 @@ -9403,6 +9438,7 @@ while true; do ;; 26|qd) + local app_id="26" local docker_name="qd" local docker_img="qdtoday/qd:latest" local docker_port=8026 @@ -9422,6 +9458,7 @@ while true; do ;; 27|dockge) + local app_id="27" local docker_name="dockge" local docker_img="louislam/dockge:latest" local docker_port=8027 @@ -9441,6 +9478,7 @@ while true; do ;; 28|speedtest) + local app_id="28" local docker_name="speedtest" local docker_img="ghcr.io/librespeed/speedtest" local docker_port=8028 @@ -9460,6 +9498,7 @@ while true; do ;; 29|searxng) + local app_id="29" local docker_name="searxng" local docker_img="searxng/searxng" local docker_port=8029 @@ -9484,6 +9523,7 @@ while true; do ;; 30|photoprism) + local app_id="30" local docker_name="photoprism" local docker_img="photoprism/photoprism:latest" local docker_port=8030 @@ -9516,6 +9556,7 @@ while true; do 31|s-pdf) + local app_id="31" local docker_name="s-pdf" local docker_img="frooodle/s-pdf:latest" local docker_port=8031 @@ -9542,6 +9583,7 @@ while true; do ;; 32|drawio) + local app_id="32" local docker_name="drawio" local docker_img="jgraph/drawio" local docker_port=8032 @@ -9562,6 +9604,7 @@ while true; do ;; 33|sun-panel) + local app_id="33" local docker_name="sun-panel" local docker_img="hslr/sun-panel" local docker_port=8033 @@ -9586,6 +9629,7 @@ while true; do ;; 34|pingvin-share) + local app_id="34" local docker_name="pingvin-share" local docker_img="stonith404/pingvin-share" local docker_port=8034 @@ -9610,6 +9654,7 @@ while true; do 35|moments) + local app_id="35" local docker_name="moments" local docker_img="kingwrcy/moments:latest" local docker_port=8035 @@ -9637,6 +9682,7 @@ while true; do 36|lobe-chat) + local app_id="36" local docker_name="lobe-chat" local docker_img="lobehub/lobe-chat:latest" local docker_port=8036 @@ -9658,6 +9704,7 @@ while true; do ;; 37|myip) + local app_id="37" local docker_name="myip" local docker_img="jason5ng32/myip:latest" local docker_port=8037 @@ -9692,6 +9739,7 @@ while true; do wget -O /home/docker/bililive-go/config.yml ${gh_proxy}raw.githubusercontent.com/hr3lxphr6j/bililive-go/master/config.yml > /dev/null 2>&1 fi + local app_id="39" local docker_name="bililive-go" local docker_img="chigusa/bililive-go" local docker_port=8039 @@ -9711,6 +9759,7 @@ while true; do ;; 40|webssh) + local app_id="40" local docker_name="webssh" local docker_img="jrohy/webssh" local docker_port=8040 @@ -9728,6 +9777,7 @@ while true; do 41|haozi) + local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="耗子面板" local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" @@ -9752,6 +9802,7 @@ while true; do 42|nexterm) + local app_id="42" local docker_name="nexterm" local docker_img="germannewsmaker/nexterm:latest" local docker_port=8042 @@ -9776,6 +9827,7 @@ while true; do ;; 43|hbbs) + local app_id="43" local docker_name="hbbs" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9796,6 +9848,7 @@ while true; do ;; 44|hbbr) + local app_id="44" local docker_name="hbbr" local docker_img="rustdesk/rustdesk-server" local docker_port=0000 @@ -9815,6 +9868,7 @@ while true; do ;; 45|registry) + local app_id="45" local docker_name="registry" local docker_img="registry:2" local docker_port=8045 @@ -9840,6 +9894,7 @@ while true; do ;; 46|ghproxy) + local app_id="46" local docker_name="ghproxy" local docker_img="wjqserver/ghproxy:latest" local docker_port=8046 @@ -9860,6 +9915,7 @@ while true; do 47|prometheus|grafana) + local app_id="47" local app_name="普罗米修斯监控" local app_text="Prometheus+Grafana企业级监控系统" local app_url="官网介绍: https://prometheus.io" @@ -9898,6 +9954,7 @@ while true; do ;; 48|node-exporter) + local app_id="48" local docker_name="node-exporter" local docker_img="prom/node-exporter" local docker_port=8048 @@ -9922,6 +9979,7 @@ while true; do ;; 49|cadvisor) + local app_id="49" local docker_name="cadvisor" local docker_img="gcr.io/cadvisor/cadvisor:latest" local docker_port=8049 @@ -9952,6 +10010,7 @@ while true; do 50|changedetection) + local app_id="50" local docker_name="changedetection" local docker_img="dgtlmoon/changedetection.io:latest" local docker_port=8050 @@ -9982,6 +10041,7 @@ while true; do 52|dpanel) + local app_id="52" local docker_name="dpanel" local docker_img="dpanel/dpanel:lite" local docker_port=8052 @@ -10005,6 +10065,7 @@ while true; do ;; 53|llama3) + local app_id="53" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10025,6 +10086,7 @@ while true; do 54|amh) + local app_id="54" local lujing="[ -d "/www/server/panel" ]" local panelname="AMH面板" local panelurl="官方地址: https://amh.sh/index.htm?amh" @@ -10047,7 +10109,7 @@ while true; do 55|frps) - frps_panel + frps_panel ;; 56|frpc) @@ -10055,6 +10117,7 @@ while true; do ;; 57|deepseek) + local app_id="57" local docker_name="ollama" local docker_img="ghcr.io/open-webui/open-webui:ollama" local docker_port=8053 @@ -10075,6 +10138,7 @@ while true; do 58|dify) + local app_id="58" local app_name="Dify知识库" local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" local app_url="官方网站: https://docs.dify.ai/zh-hans" @@ -10113,7 +10177,8 @@ while true; do ;; 59|new-api) - local app_name="New API" + local app_id="59" + local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" local app_url="官方网站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" @@ -10165,6 +10230,7 @@ while true; do 60|jms) + local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" local app_url="官方介绍: https://github.com/jumpserver/jumpserver" @@ -10202,6 +10268,7 @@ while true; do ;; 61|libretranslate) + local app_id="61" local docker_name="libretranslate" local docker_img="libretranslate/libretranslate:latest" local docker_port=8061 @@ -10227,6 +10294,7 @@ while true; do 62|ragflow) + local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方网站: https://github.com/infiniflow/ragflow" @@ -10265,6 +10333,7 @@ while true; do 63|open-webui) + local app_id="63" local docker_name="open-webui" local docker_img="ghcr.io/open-webui/open-webui:main" local docker_port=8063 @@ -10284,6 +10353,7 @@ while true; do ;; 64|it-tools) + local app_id="64" local docker_name="it-tools" local docker_img="corentinth/it-tools:latest" local docker_port=8064 @@ -10302,6 +10372,7 @@ while true; do 65|n8n) + local app_id="65" local docker_name="n8n" local docker_img="docker.n8n.io/n8nio/n8n" local docker_port=8065 @@ -10319,7 +10390,7 @@ while true; do -e N8N_HOST=${yuming} \ -e N8N_PORT=5678 \ -e N8N_PROTOCOL=https \ - -e N8N_WEBHOOK_URL=https://${yuming}/ \ + -e WEBHOOK_URL=https://${yuming}/ \ docker.n8n.io/n8nio/n8n ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -10341,6 +10412,7 @@ while true; do 67|ddns) + local app_id="67" local docker_name="ddns-go" local docker_img="jeessy/ddns-go" local docker_port=8067 @@ -10364,6 +10436,7 @@ while true; do ;; 68|allinssl) + local app_id="68" local docker_name="allinssl" local docker_img="allinssl/allinssl:latest" local docker_port=8068 @@ -10382,6 +10455,7 @@ while true; do 69|sftpgo) + local app_id="69" local docker_name="sftpgo" local docker_img="drakkan/sftpgo:latest" local docker_port=8069 @@ -10413,6 +10487,7 @@ while true; do 70|astrbot) + local app_id="70" local docker_name="astrbot" local docker_img="soulter/astrbot:latest" local docker_port=8070 @@ -10444,6 +10519,7 @@ while true; do 71|navidrome) + local app_id="71" local docker_name="navidrome" local docker_img="deluan/navidrome:latest" local docker_port=8071 @@ -10473,6 +10549,7 @@ while true; do 72|bitwarden) + local app_id="72" local docker_name="bitwarden" local docker_img="vaultwarden/server" local docker_port=8072 @@ -10502,6 +10579,7 @@ while true; do 73|libretv) + local app_id="73" local docker_name="libretv" local docker_img="bestzwei/libretv:latest" local docker_port=8073 @@ -10531,6 +10609,7 @@ while true; do 74|moontv) + local app_id="74" local docker_name="moontv" local docker_img="ghcr.io/senshinya/moontv:latest" local docker_port=8074 @@ -10560,6 +10639,7 @@ while true; do 75|melody) + local app_id="75" local docker_name="melody" local docker_img="foamzou/melody:latest" local docker_port=8075 @@ -10589,6 +10669,7 @@ while true; do 76|dosgame) + local app_id="76" local docker_name="dosgame" local docker_img="oldiy/dosgame-web-docker:latest" local docker_port=8076 @@ -10614,6 +10695,7 @@ while true; do 77|xunlei) + local app_id="77" local docker_name="xunlei" local docker_img="cnk3x/xunlei" local docker_port=8077 @@ -10649,6 +10731,7 @@ while true; do 78|PandaWiki) + local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" local app_url="官方介绍: https://github.com/chaitin/PandaWiki" @@ -10676,6 +10759,7 @@ while true; do 79|beszel) + local app_id="79" local docker_name="beszel" local docker_img="henrygd/beszel" local docker_port=8079 @@ -10703,6 +10787,8 @@ while true; do 80|linkwarden) + + local app_id="80" local app_name="linkwarden书签管理" local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" local app_url="官方网站: https://linkwarden.app/" @@ -10774,6 +10860,7 @@ while true; do 81|jitsi) + local app_id="81" local app_name="JitsiMeet视频会议" local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" @@ -10824,6 +10911,7 @@ while true; do 82|gpt-load) + local app_id="82" local docker_name="gpt-load" local docker_img="tbphp/gpt-load:latest" local docker_port=8082 @@ -10852,6 +10940,7 @@ while true; do 83|komari) + local app_id="83" local docker_name="komari" local docker_img="ghcr.io/komari-monitor/komari:latest" local docker_port=8083 @@ -10883,6 +10972,7 @@ while true; do 84|wallos) + local app_id="84" local docker_name="wallos" local docker_img="bellamy/wallos:latest" local docker_port=8084 @@ -10911,6 +11001,7 @@ while true; do 85|immich) + local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官网介绍: https://github.com/immich-app/immich" @@ -10953,6 +11044,7 @@ while true; do 86|jellyfin) + local app_id="86" local docker_name="jellyfin" local docker_img="jellyfin/jellyfin" local docker_port=8086 @@ -10988,6 +11080,7 @@ while true; do 87|synctv) + local app_id="87" local docker_name="synctv" local docker_img="synctvorg/synctv" local docker_port=8087 @@ -11015,6 +11108,7 @@ while true; do 88|owncast) + local app_id="88" local docker_name="owncast" local docker_img="owncast/owncast:latest" local docker_port=8088 From 205923edcb026e4cbd221cbd3fe5a1e3bbe7cd6d Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 17 Aug 2025 04:16:15 +0000 Subject: [PATCH 0065/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-17=2004:16:15?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 22 +- jp/kejilion.sh | 4436 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 4374 +++++++++++++++++++++++------------------------ 3 files changed, 4416 insertions(+), 4416 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 4aca50ce2..cd73886fb 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1740,7 +1740,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to mode parameters + # Decide to turn on or off WAF according to the mode parameter if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -4989,7 +4989,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Detected operating systems:$os_name $os_version" + echo "Operating system detected:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -5818,7 +5818,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Create a new connection example:" + echo "Example to create a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -5959,7 +5959,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can connect to other Linux systems via SSH" + echo "Can be connected to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -7517,7 +7517,7 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" - echo -e "${gl_huang}25. ${gl_bai}Install the Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" + echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" echo -e "${gl_huang}30. ${gl_bai}Customize static site" echo -e "${gl_huang}------------------------" @@ -7693,7 +7693,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Backend login path: /admin" + echo "Background login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -7924,7 +7924,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -11357,7 +11357,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" @@ -11388,7 +11388,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys have been set" + echo "Shortcut keys are set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -12400,7 +12400,7 @@ EOF echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" echo -e "8. Automatically optimize DNS address${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "9. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "9. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice @@ -12632,7 +12632,7 @@ linux_file() { 5) # 删除目录 read -e -p "Please enter the directory name to delete:" dirname rm -rf "$dirname" && echo "Directory has been deleted" || echo "Deletion failed" - send_stats "Delete directory" + send_stats "Delete Directory" ;; 6) # 返回上一级选单目录 cd .. diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4da715382..b449d9342 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# コマンドを実行する関数を定義します +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! -# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 -# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# ユーザーに条件に同意するように促します +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" - echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" - echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "上記の条件に同意しますか? (y/n):" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "ライセンスの同意" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "許可の拒否" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}インストール$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" - echo "現在利用可能なスペース:$((available_space_mb/1024))g" - echo "最小需要スペース:${required_gb}G" - echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" - send_stats "ディスクスペースが不十分です" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}アンインストール$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi done } -# さまざまな分布に適したUniversal SystemCTL関数 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# サービスを再起動します +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1サービスは再開されました。" + echo "$1 服务已重启。" else - echo "エラー:再起動$1サービスは失敗しました。" + echo "错误:重启 $1 服务失败。" fi } -# サービスを開始します +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1サービスが開始されました。" + echo "$1 服务已启动。" else - echo "エラー:開始$1サービスは失敗しました。" + echo "错误:启动 $1 服务失败。" fi } -# サービスを停止します +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1サービスは停止しました。" + echo "$1 服务已停止。" else - echo "エラー:停止します$1サービスは失敗しました。" + echo "错误:停止 $1 服务失败。" fi } -# サービスのステータスを確認します +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1サービスステータスが表示されます。" + echo "$1 服务状态已显示。" else - echo "エラー:表示できません$1サービスステータス。" + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME電源を入れるように設定します。" + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}操作が完了しました${gl_bai}" - echo "任意のキーを押して続行します..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Dockerコンテナ管理" - echo "Dockerコンテナリスト" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "コンテナ操作" + echo "容器操作" echo "------------------------" - echo "1.新しいコンテナを作成します" + echo "1. 创建新的容器" echo "------------------------" - echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" - echo "3.指定された容器を停止します7。すべての容器を停止します" - echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" - echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11。指定されたコンテナを入力します12。コンテナログを表示します" - echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいコンテナを作成します" - read -e -p "作成コマンドを入力してください:" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "指定された容器を起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "指定された容器を停止します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "指定されたコンテナを削除します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "指定された容器を再起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "すべてのコンテナを起動します" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "すべてのコンテナを停止します" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "すべてのコンテナを削除します" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "すべてのコンテナを再起動します" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "コンテナを入力します" - read -e -p "コンテナ名を入力してください:" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "コンテナログを表示します" - read -e -p "コンテナ名を入力してください:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "コンテナネットワークを表示します" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "コンテナの占有を表示します" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "コンテナポートアクセスを許可します" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "コンテナポートアクセスをブロックします" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker画像管理" - echo "Docker画像リスト" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "ミラー操作" + echo "镜像操作" echo "------------------------" - echo "1.指定された画像を取得する3。指定された画像を削除します" - echo "2。指定された画像4を更新します。すべての画像を削除します" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "鏡を引っ張ります" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}画像を取得する:$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "画像を更新します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}更新された画像:$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "ミラーを削除します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "すべての画像を削除します" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "サポートされていない分布:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "オペレーティングシステムを決定することはできません。" + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 現在の構成には既にIPv6設定があるかどうかを確認してください + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 構成を更新し、IPv6を有効にします + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 現在の構成をお読みください + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 現在のIPv6ステータスを確認してください + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のクロージングルールを削除します + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # オープンルールを追加します + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートが開かれました$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "ポートが開かれました" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のオープンルールを削除します + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 緊密なルールを追加します + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "ポートは閉じた$port" + echo "已关闭端口 $port" fi done - # 既存のルールを削除する(ある場合) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 最初に新しいルールを挿入します + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "ポートは閉じた" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存のブロッキングルールを削除します + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 許可ルールを追加します + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IPをリリースしました$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "IPをリリースしました" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存の許可ルールを削除します + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # ブロッキングルールを追加します + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IPブロック$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IPブロック" + send_stats "已阻止IP" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 防御DDOをオンにします + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS防御をオンにします" + send_stats "开启DDoS防御" } -# DDOS防御をオフにします +# 关闭DDoS防御 disable_ddos_defense() { - # 防御DDOをオフにします + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS防御をオフにします" + send_stats "关闭DDoS防御" } -# 国家IPルールを管理する機能 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # IPSETが存在しない場合は作成します + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # iptablesでIPをブロックします + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "正常にブロックされました$country_codeIPアドレス" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 許可された国のIPSETを作成する(存在しない場合) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 既存の国家ルールを削除します + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 指定された国のIPのみが許可されています + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "正常に許可されています$country_codeIPアドレス" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 国のiptablesルールを削除します + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # Ipsetを破壊します + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "正常に持ち上げられました$country_codeIPアドレスの制限" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高度なファイアウォール管理" - send_stats "高度なファイアウォール管理" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "ファイアウォール管理" + echo "防火墙管理" echo "------------------------" - echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5。IPホワイトリスト6。IPブラックリスト" - echo "7.指定されたIPをクリアします" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. ping 12を許可します。Pingを無効にします" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" - echo "17.指定国でのIP制限をリリースします" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "オープンポート番号を入力してください:" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "指定されたポートを開きます" + send_stats "开放指定端口" ;; 2) - read -e -p "閉じたポート番号を入力してください:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "指定されたポートを閉じます" + send_stats "关闭指定端口" ;; 3) - # すべてのポートを開きます + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを開きます" + send_stats "开放所有端口" ;; 4) - # すべてのポートを閉じます + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを閉じます" + send_stats "关闭所有端口" ;; 5) - # IPホワイトリスト - read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IPブラックリスト - read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 指定されたIPをクリアします - read -e -p "クリアされたIPを入力してください:" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "指定されたIPをクリアします" + send_stats "清除指定IP" ;; 11) - # pingを許可します + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "pingを許可します" + send_stats "允许PING" ;; 12) - # pingを無効にします + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "pingを無効にします" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "許可された国$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "国をブロックします$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "国をきれいにします$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 現在のシステムですべてのスワップパーティションを取得します + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 反復して、すべてのスワップパーティションを削除します + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfileが使用されなくなったことを確認してください + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 古い /swapfileを削除します + # 删除旧的 /swapfile rm -f /swapfile - # 新しいスワップパーティションを作成します + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 仮想メモリを作成する必要があるかどうかを判断します +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginxバージョンを取得します + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQLバージョンを取得します + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHPバージョンを取得します + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redisバージョンを取得します + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 必要なディレクトリとファイルを作成します + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.ymlファイルをダウンロードして置き換えます + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.ymlファイルに置き換えます + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされています" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "更新タスクが更新されました" + echo "续签任务已更新" } @@ -1453,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}証明書ストレージパス${gl_bai}" - echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" - echo "サイト情報証明書の有効期限" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "ドメイン名証明書の成功したアプリケーション" + send_stats "域名证书申请成功" else - send_stats "ドメイン名証明書のアプリケーションは失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" - echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" - echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" - echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" - echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" - echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" - echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "もう一度展開してみてください$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "ドメイン名の再利用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1623,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1643,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "ログイン情報:" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "起動する$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ゾーン_idsを配列に変換します + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # キャッシュをクリーニングするかどうかをユーザーに促します - read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" - read -e -p "API_TOKENを入力してください:" API_TOKEN - read -e -p "CFユーザー名を入力してください:" EMAIL - read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 各ZONE_IDをループして、Clear Cacheコマンドを実行します + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "キャッシュクリアリクエストが送信されました。" + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "サイトキャッシュをクリーンアップします" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1703,28 @@ web_cache() { web_del() { - send_stats "サイトデータを削除します" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "ドメイン名の削除:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # ドメイン名をデータベース名に変換します + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します - echo "データベースの削除:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAFをオンにしてください:コメントを削除します + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # WAFを閉じる:コメントを追加します + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotliをオンにする:コメントを削除します + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる:コメントを追加します + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTDをオンにしてください:コメントを削除します + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # ZSTDを閉じる:コメントを追加します + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1945,11 @@ nginx_zstd() { else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP環境防御" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" - echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21。CloudFlareモード22。5秒シールドの高負荷" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31。WAF32をオンにしてください。WAFをオフにします" - echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2097,11 +2097,11 @@ web_security() { ;; 21) - send_stats "CloudFlareモード" - echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください。" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CFパラメーターを取得します:" - echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" - echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください。" cftoken - read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負荷自動シールドオープニングスクリプトが追加されました" + echo "高负载自动开盾脚本已添加" else - echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "サイトWAFが有効になっています" - send_stats "サイトWAFが有効になっています" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "サイトWAFは閉鎖されています" - send_stats "サイトWAFは閉鎖されています" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processesの設定値を取得します +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 値に応じてモード情報を設定します +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotliが有効であり、コメントされていないかどうかを確認してください + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIPが有効になっており、コメントされていないかどうかを確認してください + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP環境を最適化します" - echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1。標準モード2。高性能モード(推奨2H4g以上)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" - echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" - echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "サイト標準モード" + send_stats "站点标准模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP環境は標準モードに設定されています" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "サイトの高性能モード" + send_stats "站点高性能模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP環境は、高性能モードに設定されています" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker = "$ {gl_lv} $ {gl_bai}インストール" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "アクセスアドレス:" +echo "访问地址:" ip_address @@ -2434,31 +2434,31 @@ check_docker_image_update() { return fi - # コンテナの作成時間と画像名を取得します + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # ミラーウェアハウスとタグを抽出します + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # デフォルトのラベルは最新です + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 公式画像のサポートを追加します + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIから画像公開時間を取得します + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 買収の時間を確認します + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # タイムスタンプを比較します + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2487,34 @@ block_container_port() { install iptables - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2524,7 @@ block_container_port() { fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2545,17 @@ clear_container_rules() { install iptables - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2564,17 @@ clear_container_rules() { - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2585,7 @@ clear_container_rules() { fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:block_host_port <ポート番号> <承認IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2626,27 @@ block_host_port() { - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 確立された関連接続および関連する接続のトラフィックを許可します + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2747,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "インストール$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新します$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" - send_stats "アンインストール$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# セッションが存在するかどうかを確認する関数 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 存在しないセッション名が見つかるまでループします +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 新しいTMUXセッションを作成します +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "再起動" + echo "已重启" reboot ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -3127,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再度インストールできません" - echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP環境をインストールします" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx環境をインストールします" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginxがインストールされています" -echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "LDNMP環境を最初にインストールしてください" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "最初にNGINX環境をインストールしてください" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webnameインストール情報は次のとおりです。" + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "発生防止ポートを入力してください。" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMPサイト管理" - echo "LDNMP環境" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "サイト:${output}証明書の有効期限" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "データベース:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "サイトディレクトリ" + echo "站点目录" echo "------------------------" - echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" - echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" - echo "5.アクセスログを表示6。エラーログを表示します" - echo "7.グローバル構成の編集8。サイト構成の編集" - echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20.指定されたサイトデータを削除します" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "サイトドメイン名を変更します" - echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" - read -e -p "古いドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # MySQLの交換 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3438,7 @@ ldnmp_web_status() { done done - # ウェブサイトディレクトリの交換 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "関連するサイトを作成します" - echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" - read -e -p "既存のドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "アクセスログを表示します" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "エラーログを表示します" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "グローバル構成を編集します" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "サイト構成を編集します" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "サイトデータを表示します" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3540,16 +3540,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" - echo "公式ウェブサイトの紹介:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1。インストール2。管理3。アンインストール" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}インストール" + send_stats "${panelname}安装" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}コントロール" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}アンインストール" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRPサーバーをインストールします" - # ランダムポートと資格情報を生成します + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3637,17 @@ EOF donlond_frp frps - # 出力生成情報 + # 输出生成的信息 ip_address echo "------------------------" - echo "クライアントの展開に必要なパラメーター" - echo "サービスIP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRPパネル情報" - echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" - echo "FRPパネルのユーザー名:$dashboard_user" - echo "FRPパネルパスワード:$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3657,9 @@ EOF configure_frpc() { - send_stats "FRPクライアントをインストールします" - read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr - read -e -p "外部ネットワークドッキングトークンを入力してください:" token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "FRPイントラネットサービスを追加します" - # ユーザーにサービス名と転送情報を入力するように促します - read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "イントラネットポートを入力してください:" local_port - read -e -p "外部ネットワークポートを入力してください:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # 構成ファイルにユーザー入力を書き込みます + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 出力生成情報 - echo "仕える$service_nameFRPC.TOMLに正常に追加されました" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "FRPイントラネットサービスを削除します" - # ユーザーに削除する必要があるサービス名を入力するように促します - read -e -p "削除する必要があるサービス名を入力してください:" service_name - # SEDを使用して、サービスとその関連構成を削除します + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "仕える$service_nameFRPC.TOMLから削除されました" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーを印刷します + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3756,11 @@ list_forwarding_services() { type } - # 現在のサービス名を更新します + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 前の値をクリアします + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3789,7 +3789,7 @@ list_forwarding_services() { } END { - # 最後のサービスの情報を印刷します + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3802,17 @@ list_forwarding_services() { -# FRPサーバーポートを取得します +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# アクセスアドレスを生成します +# 生成访问地址 generate_access_urls() { - # 最初にすべてのポートを取得します + # 首先获取所有端口 get_frp_ports - # 8055/8056以外のポートがあるかどうかを確認してください + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3821,18 @@ generate_access_urls() { fi done - # 有効なポートがある場合にのみタイトルとコンテンツを表示します + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRPサービス外部アクセスアドレス:" + echo "FRP服务对外访问地址:" - # IPv4アドレスを処理します + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # IPv6アドレスを処理する(存在する場合) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3841,7 @@ generate_access_urls() { done fi - # HTTPS構成の処理 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRPサーバー" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPサーバー$check_frp $update_status" - echo "FRPイントラネット浸透サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00。サービスのステータスを更新します0。前のメニューに戻ります" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPサーバーがインストールされています" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPサーバーが更新されました" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 5) - echo "ドメイン名アクセスへの逆イントラネット侵入サービス" - send_stats "FRP外部ドメイン名へのアクセス" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します" - read -e -p "リリースするポートを入力してください:" frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" - read -e -p "ブロックする必要があるポートを入力してください。" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRPサービスステータスを更新します" - echo "FRPサービスステータスは更新されました" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRPクライアント" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPクライアント$check_frp $update_status" - echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPクライアントがインストールされています" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPクライアントが更新されました" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 4) @@ -4066,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "YT-DLPダウンロードツール" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" - echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードされたビデオリスト:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" - echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "オプション番号を入力してください:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "YT-DLPのインストール..." - echo "YT-DLPのインストール..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "インストールが完了しました。任意のキーを押して続行します..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlpを更新..." - echo "yt-dlpを更新..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新が完了しました。任意のキーを押して続行します..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlpのアンインストール..." - echo "yt-dlpのアンインストール..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。任意のキーを押して続行します..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "単一のビデオダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "バッチビデオのダウンロード" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "バッチダウンロードを開始します..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "カスタムビデオのダウンロード" - read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "実行が完了したら、キーを押して続行します..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3ダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "ビデオを削除します" - read -e -p "削除ビデオの名前を入力してください:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4195,7 @@ set_timedate() { -# DPKG割り込みの問題を修正します +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}システムの更新...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi } @@ -4231,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." apk cache clean - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APKキャッシュを削除してください..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "未使用の依存関係をクリーンアップ..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." pkg clean -y - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi return @@ -4340,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "DNSを最適化します" +send_stats "优化DNS" while true; do clear - echo "DNSアドレスを最適化します" + echo "优化DNS地址" echo "------------------------" - echo "現在のDNSアドレス" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1。外国DNS最適化:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2。国内のDNS最適化:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3。DNS構成を手動で編集します" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "外国のDNS最適化" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内のDNS最適化" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "DNS構成を手動で編集します" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthenticationが見つかった場合は、はいに設定します + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 発見された場合、pubkeyauthenticationはyesに設定されています + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # バックアップSSH構成ファイル + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSHポートは次のように変更されています。$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "ルートパスワードを設定します" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能では、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "システムを再インストールします" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "再インストールするシステムを選択してください:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "Debian 13を再インストールします" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "Debian 12を再インストールします" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Debian 11を再インストールします" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Debian 10を再インストールします" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "Ubuntu 24.04を再インストールします" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "Ubuntu 22.04を再インストールします" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04を再インストールします" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "Ubuntu 18.04を再インストールします" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4661,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10を再インストールします" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9を再インストールします" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "alma10を再インストールします" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "alma9を再インストールします" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10を再インストールします" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9を再インストールします" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42を再インストールします" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41を再インストールします" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "CENTOS10を再インストールします" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "CENTOS9を再インストールします" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "アルパインを再インストールします" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "アーチを再インストールします" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "Kaliを再インストールします" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "Openeulerを再インストールします" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "OpenSuseを再インストールします" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "飛ぶ牛をリロードします" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4790,7 @@ dd_xitong() { 41) - send_stats "Windows11を再インストールします" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Windows 10を再インストールします" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7を再インストールします" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22を再インストールします" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Windows Server 19を再インストールします" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Windows Server 16を再インストールします" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11アームを再インストールします" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3管理" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "XanmodのBBRV3カーネルをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1。BBRV3カーネルを更新します2。BBRV3カーネルをアンインストールします" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmodカーネルが更新されました。再起動後に有効になります" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4916,13 @@ bbrv3() { else clear - echo "BBR3加速度をセットアップします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Debian/Ubuntuのみをサポートします" - echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "オペレーティングシステムの種類を決定できません" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4957,17 @@ bbrv3() { bbr_on - echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4976,40 @@ bbrv3() { elrepo_install() { - # Elrepo GPG公開キーをインポートします - echo "Elrepo GPG公開キーをインポートしてください..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # システムバージョンを検出します + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # サポートされているオペレーティングシステムで実行されていることを確認してください + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "サポートされていないオペレーティングシステム:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 検出されたオペレーティングシステム情報を印刷します - echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "サポートされていないシステムバージョン:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします - echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "レッドハットカーネル管理" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo Kernelをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hatカーネルを更新します" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" - send_stats "レッドハットカーネルをアンインストールします" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5060,26 @@ elrepo() { else clear - echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" - echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hatカーネルをアップグレードします" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "スキャンするディレクトリを指定してください。" + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # マウントパラメーターを構築します + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # CLAMSCANコマンドパラメーターを作成します + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Dockerコマンドを実行します + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "ウイルススキャン管理" + send_stats "病毒扫描管理" while true; do clear - echo "クラマブウイルススキャンツール" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" - echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "フルディスクスキャン" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要なディレクトリスキャン" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "カスタムディレクトリスキャン" - read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5194,21 @@ clamav() { -# 高性能モード最適化関数 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# イコライゼーションモード最適化関数 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# デフォルト設定関数を復元します +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# ウェブサイトの構築最適化機能 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" - echo "Linuxシステムにおけるカーネルパラメーターの最適化" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" - echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" - echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" - echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" - echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" - echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能モードの最適化" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "バランスモードの最適化" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "ウェブサイトの最適化モデル" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "ライブストリーミング最適化" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "ゲームサーバーの最適化" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "デフォルト設定を復元します" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "サポートされていないシステム:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "サポートされていないシステム、システムタイプは認識できません。" + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "システム言語を切り替えます" +send_stats "切换系统语言" while true; do clear - echo "現在のシステム言語:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1。英語2。簡素化された中国語3。伝統的な中国語" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えます" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "簡素化された中国人に切り替えます" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "伝統的な中国人に切り替えます" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5530,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "コマンドラインの美化ツール" + send_stats "命令行美化工具" while true; do clear - echo "コマンドラインの美化ツール" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムリサイクルステーション" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5605,17 @@ linux_trash() { fi clear - echo -e "現在のリサイクルビン${trash_status}" - echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" - echo "3。コンテンツを復元4。リサイクルビンをクリアします" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "復元するにはファイル名を入力してください。" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreホームディレクトリに復元されました。" + echo "$file_to_restore 已还原到主目录。" else - echo "ファイルは存在しません。" + echo "文件不存在。" fi ;; 4) - read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "リサイクルビンがクリアされました。" + echo "回收站已清空。" fi ;; *) @@ -5658,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "コマンドのお気に入り" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成します +# 创建备份 create_backup() { - send_stats "バックアップを作成します" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # ユーザーにバックアップディレクトリを入力するように求めます - echo "バックアップ例を作成します:" - echo "- 単一のディレクトリをバックアップします: /var /www" - echo "- バックアップ複数のディレクトリ: /etc /home /var /log" - echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" - read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # ユーザーが入力したディレクトリをスペースごとに配列に分離します + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # バックアップファイルプレフィックスを生成します + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # ディレクトリ名を抽出し、スラッシュを削除します + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 最後のアンダースコアを削除します + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # バックアップファイル名を生成します + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # ユーザーが選択したディレクトリを印刷します - echo "選択したバックアップディレクトリは次のとおりです。" + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # バックアップを作成します - echo "バックアップを作成します$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # コマンドが成功しているかどうかを確認してください + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "バックアップの作成に失敗しました!" + echo "备份创建失败!" exit 1 fi } -# バックアップを復元します +# 恢复备份 restore_backup() { - send_stats "バックアップを復元します" - # 復元するバックアップを選択します - read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - echo "バックアップの回復$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "バックアップと復元を正常に!" + echo "备份恢复成功!" else - echo "バックアップリカバリに失敗しました!" + echo "备份恢复失败!" exit 1 fi } -# バックアップをリストします +# 列出备份 list_backups() { - echo "利用可能なバックアップ:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# バックアップを削除します +# 删除备份 delete_backup() { - send_stats "バックアップを削除します" + send_stats "删除备份" - read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - # バックアップを削除します + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "バックアップは正常に削除されました!" + echo "备份删除成功!" else - echo "バックアップの削除が失敗しました!" + echo "备份删除失败!" exit 1 fi } -# バックアップメインメニュー +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "システムバックアップ機能" - echo "システムバックアップ機能" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5806,56 @@ linux_backup() { -# 接続リストを表示します +# 显示连接列表 list_connections() { - echo "接続の保存:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 新しい接続を追加します +# 添加新连接 add_connection() { - send_stats "新しい接続を追加します" - echo "新しい接続例を作成します:" - echo "- 接続名:my_server" - echo "- IPアドレス:192.168.1.100" - echo "- ユーザー名:root" - echo "- ポート:22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "接続名を入力してください:" name - read -e -p "IPアドレスを入力してください:" ip - read -e -p "ユーザー名(デフォルト:root)を入力してください:" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "ポート番号を入力してください(デフォルト:22):" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "選択(1/2)を入力してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5864,89 @@ add_connection() { fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "接続が保存されます!" + echo "连接已保存!" } -# 接続を削除します +# 删除连接 delete_connection() { - send_stats "接続を削除します" - read -e -p "削除するには、接続番号を入力してください。" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 接続がキーファイルを使用している場合、キーファイルを削除します + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "接続が削除されました!" + echo "连接已删除!" } -# 接続を使用します +# 使用连接 use_connection() { - send_stats "接続を使用します" - read -e -p "使用するには、接続番号を入力してください。" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "接続$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # キーに接続します + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1。キーファイルパスは正しいですか?$password_or_key" - echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" - echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # パスワードで接続します + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1.ユーザー名とパスワードが正しいかどうか。" - echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" - echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSHリモート接続ツール" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSHリモート接続ツール" - echo "SSHを介して他のLinuxシステムに接続できます" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5988,156 @@ ssh_manager() { -# 利用可能なハードディスクパーティションをリストします +# 列出可用的硬盘分区 list_partitions() { - echo "利用可能なハードディスクパーティション:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントします +# 挂载分区 mount_partition() { - send_stats "パーティションをマウントします" - read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションはすでに取り付けられています!" + echo "分区已经挂载!" return fi - # マウントポイントを作成します + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントします + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "パーティションマウントに正常に:$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "パーティションマウントは失敗しました!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# パーティションをアンインストールします +# 卸载分区 unmount_partition() { - send_stats "パーティションをアンインストールします" - read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "パーティションはマウントされていません!" + echo "分区未挂载!" return fi - # パーティションをアンインストールします + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティションのアンインストールに正常に:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "パーティションのアンインストールに失敗しました!" + echo "分区卸载失败!" fi } -# マウントされたパーティションをリストします +# 列出已挂载的分区 list_mounted_partitions() { - echo "マウントされたパーティション:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# フォーマットパーティション +# 格式化分区 format_partition() { - send_stats "フォーマットパーティション" - read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションがマウントされました。最初にアンインストールしてください!" + echo "分区已经挂载,请先卸载!" return fi - # ファイルシステムタイプを選択します - echo "ファイルシステムタイプを選択してください:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "選択を入力してください:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "無効な選択!"; return ;; + *) echo "无效的选择!"; return ;; esac - # フォーマットを確認します - read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作はキャンセルされました。" + echo "操作已取消。" return fi - # フォーマットパーティション - echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティション形式は成功しました!" + echo "分区格式化成功!" else - echo "パーティションのフォーマットが失敗しました!" + echo "分区格式化失败!" fi } -# パーティションステータスを確認します +# 检查分区状态 check_partition() { - send_stats "パーティションステータスを確認します" - read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションステータスを確認します - echo "パーティション /dev /$PARTITION状態:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# メインメニュー +# 主菜单 disk_manager() { - send_stats "ハードディスク管理機能" + send_stats "硬盘管理功能" while true; do clear - echo "ハードディスクパーティション管理" - echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" - echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } -# タスクリストを表示します +# 显示任务列表 list_tasks() { - echo "保存された同期タスク:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 新しいタスクを追加します +# 添加新任务 add_task() { - send_stats "新しい同期タスクを追加します" - echo "新しい同期タスクを作成する例:" - echo "- タスク名:backup_www" - echo "- ローカルディレクトリ: /var /www" - echo "- リモートアドレス:user@192.168.1.100" - echo "- リモートディレクトリ: /バックアップ /www" - echo "- ポート番号(デフォルト22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "タスク名を入力してください:" name - read -e -p "ローカルディレクトリを入力してください:" local_path - read -e -p "リモートディレクトリを入力してください:" remote_path - read -e -p "リモートユーザー@IPを入力してください:" remote - read -e -p "SSHポートを入力してください(デフォルト22):" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "(1/2)を選択してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "無効なキーコンテンツ!" + echo "无效的密钥内容!" return fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac - echo "同期モードを選択してください:" - echo "1。標準モード(-AVZ)" - echo "2。ターゲットファイル(-avz - delete)を削除します" - read -e -p "(1/2)を選択してください:" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "タスクが節約されました!" + echo "任务已保存!" } -# タスクを削除します +# 删除任务 delete_task() { - send_stats "同期タスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:対応するタスクは見つかりませんでした。" + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # タスクがキーファイルを使用している場合、キーファイルを削除します + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "削除されたタスク!" + echo "任务已删除!" } run_task() { - send_stats "同期タスクを実行します" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # パラメーターを分析します + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6278,51 @@ run_task() { num="$1" fi - # 着信タスク番号がない場合は、ユーザーに入力するように促します + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "実行するタスク番号を入力してください:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:タスクは見つかりませんでした!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期の方向に従ってソースとターゲットのパスを調整します + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "同期をローカルに引く:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH接続の共通パラメーターを追加します + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "エラー:キーファイルが存在しません:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6330,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同期は完了です!" + echo "同步完成!" else - echo "同期は失敗しました!以下を確認してください。" - echo "1。ネットワーク接続は正常ですか?" - echo "2。リモートホストにアクセスできますか?" - echo "3。認証情報は正しいですか?" - echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 時限タスクを作成します +# 创建定时任务 schedule_task() { - send_stats "同期タイミングタスクを追加します" + send_stats "添加同步定时任务" - read -e -p "定期的に同期するには、タスク番号を入力してください。" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi - echo "時限実行間隔を選択してください:" - echo "1)1時間に1回実行します" - echo "2)1日1回実行します" - echo "3)週に1回実行します" - read -e -p "オプションを入力してください(1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "エラー:有効なオプションを入力してください!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクがすでに存在するかどうかを確認してください + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "エラー:このタスクのタイミング同期はすでに存在しています!" + echo "错误: 该任务的定时同步已存在!" return fi - # ユーザーにクロンタブを作成します + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "タイミングタスクが作成されました。$cron_job" + echo "定时任务已创建: $cron_job" } -# スケジュールされたタスクを表示します +# 查看定时任务 view_tasks() { - echo "現在のタイミングタスク:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# タイミングタスクを削除します +# 删除定时任务 delete_task_schedule() { - send_stats "同期タイミングタスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numタイミングタスク" + echo "已删除任务编号 $num 的定时任务" } -# タスク管理メインメニュー +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "RSYNCリモート同期ツール" - echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1.新しいタスクを作成します2。タスクを削除します" - echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6。タイミングタスクを削除します" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "システム情報クエリ" + send_stats "系统信息查询" ip_address @@ -6498,41 +6498,41 @@ linux_ps() { echo "" - echo -e "システム情報クエリ" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" - echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" - echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" - echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" - echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" - echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats「基本ツール」 - echo -e "基本的なツール" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" - echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" - echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" - echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" - echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" - echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" - echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" curl --help - send_stats "カールをインストールします" + send_stats "安装curl" ;; 2) clear install wget clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" wget --help - send_stats "WGETをインストールします" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" sudo --help - send_stats "sudoをインストールします" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" socat -h - send_stats "SOCATをインストールします" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "HTOPをインストールします" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "IFTOPをインストールします" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" unzip - send_stats "unzipをインストールします" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tar --help - send_stats "タールをインストールします" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmuxをインストールします" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "FFMPEGをインストールします" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "BTOPをインストールします" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "レンジャーをインストールします" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDUをインストールします" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZFをインストールします" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIMをインストールします" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "ナノをインストールします" + send_stats "安装nano" ;; @@ -6713,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "gitをインストールします" + send_stats "安装git" ;; 21) @@ -6721,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrixをインストールします" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "SLをインストールします" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "バステットをインストールします" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "nsnakeをインストールします" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Ninvadersをインストールします" + send_stats "安装ninvaders" ;; 31) clear - send_stats "すべてをインストールします" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "すべてをアンインストールします" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "指定されたソフトウェアをインストールします" + send_stats "安装指定软件" ;; 42) clear - read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "指定されたソフトウェアをアンインストールします" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6789,7 @@ linux_tools() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -6803,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR管理" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "AlpineはBBR3を有効にします" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6854,37 +6854,37 @@ linux_docker() { while true; do clear - # send_stats「Docker Management」 + # send_stats "docker管理" echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" - echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" - echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Docker環境をインストールします" + send_stats "安装docker环境" install_add_docker ;; @@ -6895,22 +6895,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Dockerグローバルステータス" - echo "Dockerバージョン" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6925,8 +6925,8 @@ linux_docker() { 5) while true; do clear - send_stats "Dockerネットワーク管理" - echo "Dockerネットワークリスト" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -6950,36 +6950,36 @@ linux_docker() { done echo "" - echo "ネットワーク操作" + echo "网络操作" echo "------------------------" - echo "1.ネットワークを作成します" - echo "2。インターネットに参加してください" - echo "3。ネットワークを終了します" - echo "4.ネットワークを削除します" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ネットワークを作成します" - read -e -p "新しいネットワーク名を設定します:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "インターネットに参加してください" - read -e -p "ネットワーク名に参加してください:" dockernetwork - read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "インターネットに参加してください" - read -e -p "出口ネットワーク名:" dockernetwork - read -e -p "これらのコンテナはネットワークを出ます(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6988,8 +6988,8 @@ linux_docker() { ;; 4) - send_stats "ネットワークを削除します" - read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7003,29 +7003,29 @@ linux_docker() { 6) while true; do clear - send_stats "Dockerボリューム管理" - echo "Dockerボリュームリスト" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "ボリューム操作" + echo "卷操作" echo "------------------------" - echo "1.新しいボリュームを作成します" - echo "2。指定されたボリュームを削除します" - echo "3.すべてのボリュームを削除します" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいボリュームを作成します" - read -e -p "新しいボリューム名を設定します:" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7034,7 +7034,7 @@ linux_docker() { ;; 3) - send_stats "すべてのボリュームを削除します" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7043,7 +7043,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7056,7 +7056,7 @@ linux_docker() { ;; 7) clear - send_stats "Dockerクリーニング" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7065,13 +7065,13 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "Dockerソース" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7084,19 +7084,19 @@ linux_docker() { 11) clear - send_stats "Docker V6が開いています" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker V6レベル" + send_stats "Docker v6 关" docker_ipv6_off ;; 20) clear - send_stats "Dockerアンインストール" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7108,7 +7108,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7117,7 +7117,7 @@ linux_docker() { kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7134,151 +7134,151 @@ linux_test() { while true; do clear - # send_stats「テストスクリプトコレクション」 - echo -e "テストスクリプトコレクション" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" - echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" - echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" - echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ネットワーク速度測定" - echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" - echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" - echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" - echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}包括的なテスト" - echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "CHATGPTステータス検出のロックを解除します" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "リージョンストリーミングメディアのロック解除テスト" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "YeahWUストリーミングメディアのロック解除検出" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "XYKT_IP品質の身体検査スクリプト" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "MTR_TRACE 3ネットワークリターンラインテスト" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "SuperSpeed Three-Net速度測定" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace高速バックホールテストスクリプト" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" - echo "参照できるIPのリスト" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "北京テレコム:219.141.136.12" - echo "北京ユニコム:202.106.50.1" - echo "北京モバイル:221.179.155.161" - echo "上海通信:202.96.209.133" - echo "上海ユニコム:210.22.97.1" - echo "上海モバイル:211.136.112.200" - echo "広州通信:58.60.188.222" - echo "広州ユニコム:210.21.196.6" - echo "広州モバイル:120.196.165.24" - echo "成都通信:61.139.2.69" - echo "成都ユニコム:119.6.6.6" - echo "成都モバイル:211.137.96.205" - echo "Hunan Telecom:36.111.200.100" - echo "Hunan Unicom:42.48.16.100" - echo "Hunan Mobile:39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "指定されたIPを入力してください:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3ネットワークラインテスト" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC多機能速度テストスクリプト" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "ネットワーク品質のテストスクリプト" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABSパフォーマンステスト" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "ベンチパフォーマンステスト" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX Fusion Monster Review" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7288,7 +7288,7 @@ linux_test() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7304,51 +7304,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Scriptコレクション" - echo -e "Oracle Cloud Scriptコレクション" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" - echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" - echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" - echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "必ずインストールしますか? (y/n):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # デフォルト値を設定します + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 - read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Dockerコンテナを実行します + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7356,14 +7356,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloudインストールアクティブスクリプト" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7371,20 +7371,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - read -e -p "必ず続行しますか? (y/n):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7396,28 +7396,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "再インストールされたパスワードを入力してください:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud再インストールシステムスクリプト" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "この機能は開発段階にあるので、お楽しみに!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7427,15 +7427,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7456,7 +7456,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7477,7 +7477,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7505,31 +7505,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp webサイトビルディング" - echo -e "${gl_huang}LDNMP Webサイトビルディング" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" - echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" - echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" - echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" - echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" - echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7543,10 +7543,10 @@ linux_ldnmp() { 3) clear - # ディスクフォーラム + # Discuz论坛 webname="Discuz论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7569,21 +7569,21 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao Cloudデスクトップ + # 可道云桌面 webname="可道云桌面" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7605,20 +7605,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" - echo "Redisホスト:Redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7644,24 +7644,24 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベースプレフィックス:mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "インストールが成功した後、バックグラウンドアドレスにログインします" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 一本足のカウントカード + # 独脚数卡 webname="独脚数卡" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7682,34 +7682,34 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "Redisアドレス:Redis" - echo "Redisパスワード:デフォルトで記入されていません" - echo "Redisポート:6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "ウェブサイトURL:https://$yuming" - echo "バックエンドログインパス: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "ユーザー名:admin" - echo "パスワード:管理者" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" - echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # フララムフォーラム + # flarum论坛 webname="flarum论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7746,12 +7746,12 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:flarum_" - echo "管理者情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -7759,8 +7759,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7784,11 +7784,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースプレフィックス:typecho_" - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -7797,8 +7797,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7823,18 +7823,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7851,10 +7851,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7864,20 +7864,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7888,15 +7888,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "インストールされた拡張機能" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7906,25 +7906,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7934,10 +7934,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "データベースインポートテーブルデータ" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "データベースのインポートが完了しました" + echo "数据库导入完成" ;; *) echo @@ -7949,12 +7949,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:$prefix" - echo "管理者ログイン情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -7967,10 +7967,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "ジャンプドメイン名を入力してください:" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -7992,7 +7992,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8003,11 +8003,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" - read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8027,8 +8027,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8050,8 +8050,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8068,8 +8068,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8102,8 +8102,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8120,10 +8120,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8133,12 +8133,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8163,21 +8163,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境バックアップ" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "バックアップファイルが作成されました: /home /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8185,9 +8185,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" + echo "文件已传送至远程服务器home目录。" else - echo "転送されるファイルは見つかりませんでした。" + echo "未找到要传送的文件。" fi break ;; @@ -8195,7 +8195,7 @@ linux_ldnmp() { break ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8203,9 +8203,9 @@ linux_ldnmp() { 33) clear - send_stats "タイミングのリモートバックアップ" - read -e -p "リモートサーバーIPを入力してください:" useip - read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8215,18 +8215,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1。毎週のバックアップ2。毎日のバックアップ" - read -e -p "選択を入力してください:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8240,19 +8240,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP環境修復" - echo "利用可能なサイトバックアップ" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8262,7 +8262,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8271,7 +8271,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージは見つかりませんでした。" + echo "没有找到压缩包。" fi ;; @@ -8289,11 +8289,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP環境を更新します" - echo "LDNMP環境を更新します" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "コンポーネントの新しいバージョンを発見します" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8313,13 +8313,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1.更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5。完全な環境を更新します" + echo "5. 更新完整环境" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8328,7 +8328,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8339,13 +8339,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8378,8 +8378,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8390,15 +8390,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境を完全に更新します" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8424,7 +8424,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP環境をアンインストールします" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8438,7 +8438,7 @@ linux_ldnmp() { ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8448,7 +8448,7 @@ linux_ldnmp() { ;; *) - echo "無効な入力!" + echo "无效的输入!" esac break_end @@ -8468,12 +8468,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "アプリケーション市場" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # ループで色を設定します + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8482,62 +8482,62 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" - echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" - echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" - echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" - echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" - echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHub加速ステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" - echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" - echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" - echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" - echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" - echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" - echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" - echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" - echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8720,7 +8720,7 @@ while true; do ;; 7|nezha) clear - send_stats "ネザを作る" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -8729,20 +8729,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezhaの監視$check_docker $update_status" - echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" - echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1。使用します" + echo "1. 使用" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -8799,7 +8799,7 @@ while true; do ;; 9|mail) - send_stats "郵便局を建設します" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -8809,43 +8809,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "郵便局サービス$check_docker $update_status" - echo "Poste.ioはオープンソースメールサーバーソリューションです。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "ポート検出" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "アクセスアドレス:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "これらのDNSレコードを最初に解析します" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8855,7 +8855,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "任意のキーを押して続行します..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -8874,9 +8874,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -8899,9 +8899,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -8912,7 +8912,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; *) @@ -8946,7 +8946,7 @@ while true; do clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -8956,7 +8956,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chatがインストールされています" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -8966,7 +8966,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9050,7 +9050,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -9064,7 +9064,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9209,7 +9209,7 @@ while true; do ;; 19|safeline) - send_stats "サンダープールを構築します" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -9217,20 +9217,20 @@ while true; do while true; do check_docker_app clear - echo -e "サンダープールサービス$check_docker" - echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9240,7 +9240,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "サンダープールWAFパネルがインストールされています" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9253,7 +9253,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "サンダープールWAFパネルが更新されました" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9264,7 +9264,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9672,7 +9672,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9725,7 +9725,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoyaファミリーバケット" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -9927,9 +9927,9 @@ while true; do prometheus_install clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "最初のユーザー名とパスワードは次のとおりです" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -9947,7 +9947,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10034,7 +10034,7 @@ while true; do 51|pve) clear - send_stats "PVEチキン" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10154,7 +10154,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10169,7 +10169,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10197,7 +10197,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10212,7 +10212,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10220,7 +10220,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10241,17 +10241,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "初期ユーザー名:admin" - echo "最初のパスワード:changeme" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "アプリが更新されました" + echo "应用已更新" } @@ -10261,7 +10261,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10308,7 +10308,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10324,7 +10324,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10586,7 +10586,7 @@ while true; do docker_rum() { - read -e -p "libretvログインパスワードを設定します。" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10616,7 +10616,7 @@ while true; do docker_rum() { - read -e -p "MOONTVログインパスワードを設定します。" app_passwd + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ --name moontv \ @@ -10702,8 +10702,8 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}ログインユーザー名:" app_use - read -e -p "設定${docker_name}ログインパスワード:" app_passwd + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -10800,11 +10800,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # ランダムキーとパスワードを生成します + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10813,17 +10813,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 管理者アカウント情報を追加します + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # コンテナを起動します + # 启动容器 docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10833,7 +10833,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 元の変数を保持します + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10850,7 +10850,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10900,7 +10900,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11020,7 +11020,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -11033,7 +11033,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11153,35 +11153,35 @@ linux_work() { while true; do clear - send_stats "バックエンドワークスペース" - echo -e "バックエンドワークスペース" - echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" - echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "現在既存のワークスペースのリスト" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" - echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" - echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" - echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" - echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" - echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" - echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" - echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" - echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" - echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11189,7 +11189,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11197,63 +11197,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11265,21 +11265,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常駐モード" - echo -e "SSH常駐モード${tmux_sshd_status}" - echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1。2をオンにします。オフにします" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "ワークスペースを開始します$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11295,29 +11295,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "カスタムワークスペース" + send_stats "自定义工作区" ;; 23) - read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "バックグラウンドワークスペースにコマンドを注入します" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "ワークスペースを削除します" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -11342,54 +11342,54 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 - echo -e "システムツール" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" - echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" - echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" - echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度を設定します" - echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" - echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHハイリスクの脆弱性を修正します" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" - echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" - echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" - echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" - echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "ショートカットキーを入力してください(0を入力して終了してください):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "ショートカットキーが設定されています" - send_stats "スクリプトのショートカットキーが設定されています" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11397,34 +11397,34 @@ linux_Settings() { 2) clear - send_stats "ログインパスワードを設定します" - echo "ログインパスワードを設定します" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "ルートパスワードモード" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "Pyバージョン管理" - echo "Pythonバージョン管理" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" - echo "クエリの詳細:https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "スクリプトPy管理" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -11457,7 +11457,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi @@ -11486,55 +11486,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スイッチスクリプトPyバージョン" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "オープンポート" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "すべてのポートが開いています" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSHポートを変更します" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 現在のSSHポート番号をお読みください + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 現在のSSHポート番号を印刷します - echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # ユーザーに新しいSSHポート番号を入力するように促します - read -e -p "新しいSSHポート番号を入力してください:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # ポート番号が有効な範囲内にあるかどうかを判断します + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSHポートが変更されました" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSHポート変更を終了します" + send_stats "退出SSH端口修改" break else - echo "ポート番号は無効です。1〜65535の数字を入力してください。" - send_stats "無効なSSHポート入力" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "入力が無効です。番号を入力してください。" - send_stats "無効なSSHポート入力" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -11553,8 +11553,8 @@ EOF ;; 9) root_use - send_stats "新しいユーザーはルートを無効にします" - read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11569,49 +11569,49 @@ EOF passwd -l root - echo "操作が完了しました。" + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6の優先度を設定します" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6の優先度を設定します" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "優先ネットワークを選択します。" choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4の優先度に切り替えました" - send_stats "IPv4の優先度に切り替えました" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6の優先度に切り替えました" - send_stats "IPv6の優先度に切り替えました" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -11629,43 +11629,43 @@ EOF 12) root_use - send_stats "仮想メモリを設定します" + send_stats "设置虚拟内存" while true; do clear - echo "仮想メモリを設定します" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G仮想メモリが設定されています" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G仮想メモリが設定されています" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G仮想メモリが設定されています" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "カスタム仮想メモリが設定されています" + send_stats "已设置自定义虚拟内存" ;; *) @@ -11678,8 +11678,8 @@ EOF 13) while true; do root_use - send_stats "ユーザー管理" - echo "ユーザーリスト" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11690,62 +11690,62 @@ EOF echo "" - echo "アカウント操作" + echo "账户操作" echo "------------------------" - echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3.最高の権限を与える4。最高の権限をキャンセルします" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5.アカウントを削除します" + echo "5. 删除账号" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作が完了しました。" + echo "操作已完成。" ;; 2) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 新規ユーザーのsudo許可を付与します + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作が完了しました。" + echo "操作已完成。" ;; 3) - read -e -p "ユーザー名を入力してください:" username - # 新規ユーザーのsudo許可を付与します + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudo許可を削除します + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "削除するにはユーザー名を入力してください:" username - # ユーザーとそのホームディレクトリを削除します + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -11758,50 +11758,50 @@ EOF 14) clear - send_stats "ユーザー情報ジェネレーター" - echo "ランダムユーザー名" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "ランダムユーザー名$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "ランダム名" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5つのランダムユーザー名を生成します + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "ランダムなユーザー名$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "ランダムuuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "ランダムuuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16ビットランダムパスワード" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32ビットランダムパスワード" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -11809,46 +11809,46 @@ EOF 15) root_use - send_stats "タイムゾーンを変更します" + send_stats "换时区" while true; do clear - echo "システム時間情報" + echo "系统时间信息" - # 現在のシステムタイムゾーンを取得します + # 获取当前系统时区 local timezone=$(current_timezone) - # 現在のシステム時間を取得します + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # タイムゾーンと時間を表示します - echo "現在のシステムタイムゾーン:$timezone" - echo "現在のシステム時間:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "タイムゾーンの切り替え" + echo "时区切换" echo "------------------------" - echo "アジア" - echo "1。中国の上海時間2。中国の香港時間" - echo "3。日本の東京時間4。韓国のソウル時間" - echo "5。シンガポール時間6。インドのコルカタ時間" - echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。タイのバンコクでの時間" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "ヨーロッパ" - echo "11。英国のロンドン時間12。パリの時間フランスの時間" - echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" - echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "アメリカ" - echo "21。WesternTime22。東部時間" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" echo "23. 加拿大时间 24. 墨西哥时间" - echo "25。ブラジル時間26。アルゼンチン時間" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31。UTCグローバル標準時間" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11891,21 +11891,21 @@ EOF 18) root_use - send_stats "ホスト名を変更します" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian、Ubuntu、Centosなどの他のシステム。 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11923,11 +11923,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "ホスト名は次のように変更されています。$new_hostname" - send_stats "ホスト名が変更されました" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "終了すると、ホスト名は変更されていません。" + echo "已退出,未更改主机名。" break fi done @@ -11935,32 +11935,32 @@ EOF 19) root_use - send_stats "システムの更新ソースを変更します" + send_stats "换系统更新源" clear - echo "更新ソース領域を選択します" - echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "中国本土のデフォルトソース" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国本土の教育源" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外起源" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -11968,62 +11968,62 @@ EOF ;; 20) - send_stats "タイミングタスク管理" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "タイミングされたタスクリスト" + echo "定时任务列表" crontab -l echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1。毎月のタスク2。毎週のタスク" - echo "3。毎日のタスク4。時間ごとのタスク" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "選択を入力してください:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "タイムされたタスクを追加します" + send_stats "添加定时任务" ;; 2) - read -e -p "削除する必要があるキーワードを入力してください。" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "タイミングタスクを削除します" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "タイミングタスクを編集します" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12035,32 +12035,32 @@ EOF 21) root_use - send_stats "ローカルホストの解析" + send_stats "本地host解析" while true; do clear - echo "ネイティブホストのペルシングリスト" - echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.新しい解析2を追加します。解析アドレスを削除します" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホストの解析が追加されました" + send_stats "本地host解析新增" ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "ローカルホストの解析と削除" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12071,7 +12071,7 @@ EOF 22) root_use - send_stats "SSH防御" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12083,20 +12083,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防衛プログラム$check_docker" - echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" - echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "2。SSH傍受記録を表示します" - echo "3。リアルタイムログ監視" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12119,7 +12119,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12132,47 +12132,47 @@ EOF 23) root_use - send_stats "電流制限シャットダウン機能" + send_stats "限流关机功能" while true; do clear - echo "電流制限シャットダウン機能" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.shファイルが存在するかどうかを確認してください + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gbの値を取得します + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 新しい仮想メモリサイズを入力します - echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源を停止して、トラフィックエラーやオーバーフローを避けることができます。" - read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12185,15 +12185,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "現在の制限シャットダウンが設定されています" - send_stats "現在の制限シャットダウンが設定されています" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "電流制限シャットダウン機能はオフになっています" + echo "已关闭限流关机功能" ;; *) break @@ -12206,40 +12206,40 @@ EOF 24) root_use - send_stats "秘密キーログイン" + send_stats "私钥登录" while true; do clear - echo "ルート秘密キーログインモード" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "キーペアが生成され、SSHログインのより安全な方法" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "新しいキーを生成します" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "既存の公開キーをインポートします" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "地元の秘密の鍵を表示します" + send_stats "查看本机密钥" echo "------------------------" - echo "公開鍵情報" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "秘密のキー情報" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12255,18 +12255,18 @@ EOF 25) root_use - send_stats "電報警告" - echo "TG-BOTモニタリングと早期警告機能" - echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" - echo "しきい値に達した後、ユーザーはユーザーに送信されます" - echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" - read -e -p "必ず続行しますか? (y/n):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "電報警告が有効になっています" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12288,7 +12288,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 〜/.Profileファイルに追加します + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12299,21 +12299,21 @@ EOF source ~/.profile clear - echo "TG-BOT早期警告システムが開始されました" - echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSHの高リスクの脆弱性を修正します" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12357,7 +12357,7 @@ EOF ;; 37) clear - send_stats "コマンドラインの履歴" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12380,61 +12380,61 @@ EOF 41) clear - send_stats "メッセージボード" - echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "ワンストップチューニング" - echo "ワンストップシステムの最適化" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "以下が操作され、最適化されます" - echo "1.システムを最新の状態に更新します" - echo "2。システムジャンクファイルをクリーンアップします" - echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" - echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" - echo -e "5.すべてのポートを開きます" - echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" - echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" - echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" - echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングスタート" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12451,25 +12451,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" - echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -12477,7 +12477,7 @@ EOF 99) clear - send_stats "システムを再起動します" + send_stats "重启系统" server_reboot ;; 100) @@ -12493,32 +12493,32 @@ EOF local status_message="无法确定的状态" fi - echo "プライバシーとセキュリティ" - echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "現在のステータス:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1。コレクションをオンにします" - echo "2。コレクションを閉じます" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "コレクションが有効になっています" - send_stats "プライバシーとセキュリティコレクションが有効になっています" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "コレクションは閉じた" - send_stats "プライバシーとセキュリティは収集のために閉鎖されています" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -12534,11 +12534,11 @@ EOF 102) clear - send_stats "テックライオンスクリプトをアンインストールします" - echo "テックライオンスクリプトをアンインストールします" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" - read -e -p "必ず続行しますか? (y/n):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -12546,16 +12546,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "スクリプトはアンインストールされています、さようなら!" + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -12565,7 +12565,7 @@ EOF ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -12583,187 +12583,187 @@ EOF linux_file() { root_use - send_stats "ファイルマネージャー" + send_stats "文件管理器" while true; do clear - echo "ファイルマネージャー" + echo "文件管理器" echo "------------------------" - echo "現在のパス" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" - echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" - echo "15.ファイルを削除します" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" - echo "25。ファイルを別のサーバーに渡します" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "ディレクトリ名を入力してください:" dirname - cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" - send_stats "ディレクトリに移動します" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "作成するにはディレクトリ名を入力してください。" dirname - mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" - send_stats "ディレクトリを作成します" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可(755など)を入力してください。" perm - chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ディレクトリ権限を変更します" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "現在のディレクトリ名を入力してください:" current_name - read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" - send_stats "ディレクトリの名前を変更します" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "削除するには、ディレクトリ名を入力してください。" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" - send_stats "ディレクトリを削除します" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "前のメニューディレクトリに戻ります" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "作成するにはファイル名を入力してください。" filename - touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" - send_stats "ファイルを作成します" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "編集するにはファイル名を入力してください:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "ファイルを編集します" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "ファイル名を入力してください:" filename - read -e -p "許可(755など)を入力してください。" perm - chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ファイル権限を変更します" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "現在のファイル名を入力してください:" current_name - read -e -p "新しいファイル名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" - send_stats "ファイルの名前を変更します" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "削除するには、ファイル名を入力してください。" filename - rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" - send_stats "ファイルを削除します" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" - send_stats "圧縮ファイル/ディレクトリ" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "ファイル名(.tar.gz)を入力してください:" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" - send_stats "ファイル/ディレクトリを解凍します" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリが存在しません" + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" - send_stats "ファイルまたはディレクトリを移動します" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -Rオプションを使用して、ディレクトリを再帰的にコピーします - cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" - send_stats "ファイルまたはディレクトリをコピーします" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "転送されるファイルパスを入力してください。" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "エラー:ファイルは存在しません。" - send_stats "ファイルの転送に失敗しました:ファイルは存在しません" + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" - send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "エラー:リモートサーバーのパスワードを入力してください。" - send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "ログインポートを入力してください(デフォルト22):" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 既知のホストの古いエントリをクリアします + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCPを使用してファイルを転送します + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "スクリプトは最新です$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13061,15 +13061,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" - send_stats "自動スクリプトの更新をオンにします" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" - send_stats "スクリプト自動更新を閉じます" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13091,41 +13091,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" -echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" -echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" -echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" -echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" -echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" -echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" -echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" -echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" -echo -e "${gl_kjlan}13. ${gl_bai}システムツール" -echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" -echo -e "${gl_kjlan}15. ${gl_bai}広告列" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "選択を入力してください:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "システムの更新" ; linux_update ;; - 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "ワープ管理" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13136,13 +13136,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "無効な入力!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13150,68 +13150,68 @@ done k_info() { -send_stats "Kコマンド参照ユースケース" +send_stats "k命令参考用例" echo "-------------------" -echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "以下は、Kコマンドリファレンスユースケースです。" -echo "スクリプトkを開始します" -echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" -echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" -echo "システムKアップデートを更新| Kアップデート" -echo "クリーンシステムガベージkクリーン| kきれい" -echo "システムパネルk dd |を再インストールしますk再インストール" -echo "BBR3コントロールパネルK BBR3 | K BBRV3" -echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" -echo "仮想メモリkスワップ2048を設定します" -echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" -echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" -echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" -echo "SSHリモート接続ツールK SSH | Kリモート接続" -echo "rsyncリモート同期ツールk rsync | Kリモート同期" -echo "ハードディスク管理ツールKディスク| Kハードディスク管理" -echo "イントラネット浸透(サーバー側)K FRP" -echo "イントラネット浸透(クライアント)K FRPC" -echo "ソフトウェアStart K Start SSHD | k sshdを開始します" -echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" -echo "ソフトウェア再起動k再起動sshd | k再起動sshd" -echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" -echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" -echo "ドメイン名証明書アプリケーションK SSL" -echo "ドメイン名証明書の有効期限クエリK SSL PS" -echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" -echo "Docker Container Management K Docker PS | K Dockerコンテナ" -echo "Docker Image Management K Docker IMG | K Docker画像" -echo "LDNMPサイト管理K Web" -echo "LDNMPキャッシュクリーンアップK Webキャッシュ" -echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" -echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" -echo "ロードバランシングkロードバランス| kロードバランシングをインストールします" -echo "ファイアウォールパネルk fhq | kファイアウォール" -echo "オープンポートK DKDK 8080 | Kオープンポート8080" -echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" -echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" -echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" -echo "コマンドお気に入りk fav | Kコマンドのお気に入り" -echo "アプリ市場管理Kアプリ" -echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # パラメーターがない場合は、インタラクティブロジックを実行します + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # パラメーターがある場合は、対応する関数を実行します + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "ソフトウェアをインストールします" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "ソフトウェアをアンインストールします" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13245,7 +13245,7 @@ else rsync_run) shift - send_stats "タイミング付きRSYNC同期" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13264,7 +13264,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13277,13 +13277,13 @@ else swap) shift - send_stats "仮想メモリをすばやく設定します" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "タイムゾーンをすばやく設定します" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13331,42 +13331,42 @@ else status|状态) shift - send_stats "ソフトウェアステータスビュー" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "ソフトウェアスタートアップ" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "ソフトウェアの一時停止" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "ソフトウェアの再起動" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "ソフトウェアが起動します" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "証明書のステータスを確認してください" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" else k_info fi @@ -13376,15 +13376,15 @@ else shift case $1 in install|安装) - send_stats "Dockerをすばやくインストールします" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "クイックコンテナ管理" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "クイックミラー管理" + send_stats "快捷镜像管理" docker_image ;; *) @@ -13411,7 +13411,7 @@ else app) shift - send_stats "$@を適用します" + send_stats "应用$@" linux_panel "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 3be3371ea..1bebba7ec 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 명령을 실행하는 함수를 정의합니다 +# 명령을 실행할 함수를 정의합니다 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -334,8 +334,8 @@ enable() { break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "계속하려면 키를 누르십시오 ..." + echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,55 +500,55 @@ install_docker() { docker_ps() { while true; do clear - send_stats "도커 컨테이너 관리" - echo "도커 컨테이너 목록" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "컨테이너 작동" + echo "容器操作" echo "------------------------" - echo "1. 새 컨테이너를 만듭니다" + echo "1. 创建新的容器" echo "------------------------" - echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" - echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" - echo "4. 지정된 컨테이너를 삭제합니다. 8. 모든 컨테이너를 삭제하십시오" - echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" - echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "새 컨테이너를 만듭니다" - read -e -p "창조 명령을 입력하십시오 :" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "지정된 컨테이너를 시작하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너를 중지하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "지정된 컨테이너를 삭제하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "지정된 컨테이너를 다시 시작하십시오" + send_stats "重启指定容器" read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker restart $dockername ;; 6) - send_stats "모든 컨테이너를 시작하십시오" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) @@ -556,7 +556,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "모든 컨테이너를 삭제하십시오" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "모든 컨테이너를 다시 시작하십시오" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "컨테이너를 입력하십시오" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "컨테이너 로그를 봅니다" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "컨테이너 네트워크를 봅니다" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "컨테이너 점유를 봅니다" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "컨테이너 포트 액세스를 허용합니다" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "컨테이너 포트 액세스 차단" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "도커 이미지 관리" - echo "도커 이미지 목록" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "거울 작동" + echo "镜像操作" echo "------------------------" - echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" - echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "거울을 당기십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "이미지를 업데이트하십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "거울을 삭제하십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "모든 이미지를 삭제합니다" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "지원되지 않는 분포 :$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "운영 체제를 결정할 수 없습니다." + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}Crontab이 설치되고 Cron 서비스가 실행 중입니다.${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 구성 파일이 존재하는지 확인하고 파일을 작성하고 기본 설정이 존재하지 않는 경우 작성하십시오. + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 구성 업데이트 및 IPv6을 활성화하십시오 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 원래 구성과 새로운 구성을 비교합니다 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}IPv6 액세스가 현재 활성화되어 있습니다${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 구성 파일이 있는지 확인하십시오 + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}구성 파일이 존재하지 않습니다${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 현재 구성을 읽으십시오 + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 현재 IPv6 상태를 확인하십시오 + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 원래 구성과 새로운 구성을 비교합니다 + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6 액세스는 현재 닫힙니다${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6 액세스가 성공적으로 닫혔습니다${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 마감 규칙을 삭제하십시오 + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 열린 규칙을 추가하십시오 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "포트가 열렸습니다$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "포트가 열렸습니다" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 열린 규칙을 삭제합니다 + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 가까운 규칙을 추가하십시오 + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "포트 폐쇄$port" + echo "已关闭端口 $port" fi done - # 기존 규칙 삭제 (있는 경우) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 새로운 규칙을 먼저 삽입하십시오 + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "포트 폐쇄" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 차단 규칙을 삭제하십시오 + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 허용 규칙을 추가하십시오 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP 출시$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "IP 출시" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 허용 규칙을 삭제합니다 + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 차단 규칙을 추가하십시오 + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP 차단$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IP 차단" + send_stats "已阻止IP" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 방어 DDO를 켜십시오 + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS 방어를 켜십시오" + send_stats "开启DDoS防御" } -# DDOS 방어를 끕니다 +# 关闭DDoS防御 disable_ddos_defense() { - # 방어 DDO를 끄십시오 + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS 방어를 끕니다" + send_stats "关闭DDoS防御" } -# 국가 IP 규칙을 관리하는 기능 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # IPSET가 존재하지 않는 경우 작성하십시오 + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IP 영역 파일을 다운로드하십시오 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # IPSET에 IP를 추가하십시오 + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # iptables와 함께 IP를 차단하십시오 + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "성공적으로 차단되었습니다$country_codeIP 주소" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 허용 국가에 대한 IPSET 만들기 (존재하지 않는 경우) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IP 영역 파일을 다운로드하십시오 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 기존 국가 규칙을 삭제합니다 + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # IPSET에 IP를 추가하십시오 + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 지정된 국가의 IP 만 허용됩니다 + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "성공적으로 만 허용됩니다$country_codeIP 주소" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 국가의 iptables 규칙을 삭제하십시오 + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # ipset을 파괴하십시오 + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "성공적으로 해제했습니다$country_codeIP 주소 제한" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "고급 방화벽 관리" - send_stats "고급 방화벽 관리" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "방화벽 관리" + echo "防火墙管理" echo "------------------------" - echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." - echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 지우십시오" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. 핑 허용 12. 핑을 비활성화하십시오" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15. 지정된 국가 IP 16. 지정된 국가 IP 만 허용됩니다." - echo "17. 지정된 국가에서 IP 제한을 해제합니다" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "열린 포트 번호를 입력하십시오 :" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "지정된 포트를 엽니 다" + send_stats "开放指定端口" ;; 2) - read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "지정된 포트를 닫습니다" + send_stats "关闭指定端口" ;; 3) - # 모든 포트를 엽니 다 + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 엽니 다" + send_stats "开放所有端口" ;; 4) - # 모든 포트를 닫습니다 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 닫습니다" + send_stats "关闭所有端口" ;; 5) - # IP 화이트리스트 - read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IP 블랙리스트 - read -e -p "차단 된 IP 또는 IP 세그먼트를 입력하십시오." c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 지정된 IP를 지우십시오 - read -e -p "청산 된 IP를 입력하십시오 :" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "지정된 IP를 지우십시오" + send_stats "清除指定IP" ;; 11) - # 핑을 허용하십시오 + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 허용하십시오" + send_stats "允许PING" ;; 12) - # 핑을 비활성화합니다 + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 비활성화합니다" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "차단 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "허용 국가$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "허용 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "나라를 차단하십시오$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오 :" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "나라를 정리하십시오$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 모든 스왑 파티션을 반복하고 삭제하십시오 + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfile이 더 이상 사용되지 않도록하십시오 + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 이전 /스왑 파일을 삭제하십시오 + # 删除旧的 /swapfile rm -f /swapfile - # 새 스왑 파티션을 만듭니다 + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "가상 메모리 크기가 크기가 커졌습니다${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야하는지 확인하십시오 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginx 버전을 얻으십시오 + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQL 버전을 얻으십시오 + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHP 버전을 얻으십시오 + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전을 얻으십시오 + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 필요한 디렉토리 및 파일을 만듭니다 + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.yml 파일을 다운로드하여 교체하십시오 + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일로 교체하십시오 + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP 환경이 설치되었습니다" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "갱신 작업이 업데이트되었습니다" + echo "续签任务已更新" } @@ -1453,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming공개 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}인증서 저장 경로${gl_bai}" - echo "공개 키 :/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL 인증서를 신속하게 신청하고 만료 전에 서명을 자동으로 갱신하십시오.${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}응용 인증서 만료${gl_bai}" - echo "사이트 정보 인증서 만료 시간" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" + send_stats "域名证书申请成功" else - send_stats "도메인 이름 인증서 신청에 실패했습니다" - echo -e "${gl_hong}알아채다:${gl_bai}인증서 응용 프로그램이 실패했습니다. 가능한 이유를 확인하고 다시 시도하십시오." - echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." - echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." - echo -e "3. 네트워크 구성 문제 ➠ CloudFlare Warp 및 기타 가상 네트워크를 사용하는 경우 임시로 종료하십시오." - echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" - echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." - echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "다시 배포를 시도하십시오$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "도메인 이름 재사용" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1623,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1643,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "로그인 정보 :" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "시작$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 구성 파일이 있는지 확인하십시오 + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # Zone_ids를 배열로 변환합니다 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트합니다 - read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" - read -e -p "API_Token을 입력하십시오 :" API_TOKEN - read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL - read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 각 Zone_ID를 루프하고 CLEAR CACHE 명령을 실행하십시오. + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "Zone_ID의 캐시 지우기 :$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "캐시 클리어 요청이 전송되었습니다." + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "사이트 캐시를 정리하십시오" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1703,28 @@ web_cache() { web_del() { - send_stats "사이트 데이터 삭제" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하십시오 (여러 도메인 이름이 공간별로 분리됩니다)." yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "도메인 이름 삭제 :$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 도메인 이름을 데이터베이스 이름으로 변환합니다 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') # 删除数据库前检查是否存在,避免报错 - echo "데이터베이스 삭제 :$dbname" + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 모드 매개 변수에 따라 WAF를 켜거나 끄기로 결정 + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAF 켜기 : 주석을 제거하십시오 + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # waf 닫기 : 댓글을 추가하십시오 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotli를 켜십시오 : 주석을 제거하십시오 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotli를 닫습니다 : 주석을 추가하십시오 + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTD를 켜십시오 : 주석을 제거하십시오 + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Zstd를 닫습니다 : 주석을 추가하십시오 + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1945,11 @@ nginx_zstd() { else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP 환경 방어" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "서버 웹 사이트 방어 프로그램${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 安装防御程序" echo "------------------------" - echo "5. SSH 차단 레코드보기 6. 웹 사이트 차단 레코드보기" - echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11. 인터셉트 매개 변수 구성 12. 차단 된 모든 IP를 지우십시오" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31. WAF 32를 켜십시오. WAF를 끄십시오" - echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2097,11 +2097,11 @@ web_security() { ;; 21) - send_stats "CloudFlare 모드" - echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CF 매개 변수 가져 오기 :" - echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" - echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken - read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "고 부하 자동 방패 오프닝 스크립트가 추가되었습니다" + echo "高负载自动开盾脚本已添加" else - echo "자동 방패 스크립트가 이미 존재합니다. 추가 할 필요가 없습니다." + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "사이트 waf가 활성화되어 있습니다" - send_stats "사이트 waf가 활성화되어 있습니다" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "사이트 waf가 닫혔습니다" - send_stats "사이트 waf가 닫혔습니다" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 현재 Worker_Processes 설정 값을 얻으십시오 +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 값에 따라 모드 정보를 설정합니다 +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTD가 활성화되어 있고 주석이 없는지 확인하십시오 (전체 라인은 ZSTD 켜기로 시작합니다.) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotli가 활성화되어 있고 댓글이 없는지 확인하십시오 + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP 환경을 최적화하십시오" - echo -e "LDNMP 환경을 최적화하십시오${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" - echo "5. BR 압축 켜기 6. BR 압축 끄기" - echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "사이트 표준 모드" + send_stats "站点标准模式" - # nginx 튜닝 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP 환경은 표준 모드로 설정되었습니다" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "사이트 고성능 모드" + send_stats "站点高性能模式" - # nginx 튜닝 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP 환경은 고성능 모드로 설정되었습니다" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker = "$ {gl_lv} $ {gl_bai} 설치" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "액세스 주소 :" +echo "访问地址:" ip_address @@ -2434,31 +2434,31 @@ check_docker_image_update() { return fi - # 컨테이너 생성 시간과 이미지 이름을 얻으십시오 + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 거울 창고 및 태그 추출 + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 기본 레이블이 최신입니다 + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 공식 이미지에 대한 지원을 추가하십시오 + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub API에서 이미지 게시 시간을 얻으십시오 + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득 시간을 확인하십시오 + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 타임 스탬프를 비교하십시오 + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2487,34 @@ block_container_port() { install iptables - # 다른 모든 IP를 점검하고 차단하십시오 + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 다른 모든 IP를 점검하고 차단하십시오 + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2524,7 @@ block_container_port() { fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2545,17 @@ clear_container_rules() { install iptables - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2564,17 @@ clear_container_rules() { - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2585,7 @@ clear_container_rules() { fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." - echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP 액세스를 거부했습니다 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2626,27 @@ block_host_port() { - # 다른 모든 IP 액세스를 거부했습니다 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 확립 및 관련 연결을 위해 트래픽을 허용합니다 + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." - echo "사용법 : CLEAR_HOST_PORT_RULES <포트 번호> <승인 IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2727,7 +2727,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}관리하다" +send_stats "${docker_name}管理" while true; do clear @@ -2747,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name설치" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "설치하다$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name설치" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "고쳐 쓰다$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" - send_stats "제거하십시오$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}도메인 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}도메인 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 세션이 존재하는지 확인하는 기능 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 존재하지 않는 세션 이름이 발견 될 때까지 루프 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 새로운 TMUX 세션을 만듭니다 +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "다시 시작" + echo "已重启" reboot ;; *) - echo "취소" + echo "已取消" ;; esac @@ -3127,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP 환경을 다시 설치할 수 없습니다" - echo -e "${gl_huang}힌트:${gl_bai}웹 사이트 구성 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP 환경을 설치하십시오" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx 환경을 설치하십시오" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginx가 설치되었습니다" -echo -e "현재 버전 :${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "먼저 LDNMP 환경을 설치하십시오" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "Nginx 환경을 먼저 설치하십시오" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신 것$webname세워짐!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "당신 것$webname세워짐!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "반세대 IP를 입력하십시오 :" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "반세대 포트를 입력하십시오 :" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP 사이트 관리" - echo "LDNMP 환경" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "대지:${output}인증서 만료 시간" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "데이터 베이스:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "사이트 디렉토리" + echo "站点目录" echo "------------------------" - echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" - echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" - echo "5. 액세스 로그보기 6. 오류 로그보기" - echo "7. 글로벌 구성 편집 8. 사이트 구성 편집" - echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서보기" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20. 지정된 사이트 데이터를 삭제합니다" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "도메인 이름 인증서를 신청하십시오" - read -e -p "도메인 이름을 입력하십시오 :" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "사이트 도메인 이름을 변경하십시오" - echo -e "${gl_hong}적극 권장 :${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" - read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # MySQL 교체 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3438,7 @@ ldnmp_web_status() { done done - # 웹 사이트 디렉토리 교체 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "관련 사이트를 만듭니다" - echo -e "액세스 용 기존 사이트의 새 도메인 이름을 연결하십시오." - read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "액세스 로그를 봅니다" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "오류 로그를 봅니다" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "글로벌 구성 편집" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "사이트 구성 편집" - read -e -p "사이트 구성을 편집하려면 편집 할 도메인 이름을 입력하십시오." yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "사이트 데이터를 봅니다" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3535,21 +3535,21 @@ fi install_panel() { -send_stats "${panelname}관리하다" +send_stats "${panelname}管理" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}요즘 인기 있고 강력한 운영 및 유지 관리 패널입니다." - echo "공식 웹 사이트 소개 :$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. 설치 2. 관리 3. 제거" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}설치하다" + send_stats "${panelname}安装" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}제어" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}제거하십시오" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRP 서버를 설치하십시오" - # 임의의 포트 및 자격 증명을 생성합니다 + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3637,17 @@ EOF donlond_frp frps - # 출력 생성 정보 + # 输出生成的信息 ip_address echo "------------------------" - echo "클라이언트 배포에 필요한 매개 변수" - echo "서비스 IP :$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRP 패널 정보" - echo "FRP 패널 주소 : http : //$ipv4_address:$dashboard_port" - echo "FRP 패널 사용자 이름 :$dashboard_user" - echo "FRP 패널 비밀번호 :$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3657,9 @@ EOF configure_frpc() { - send_stats "FRP 클라이언트를 설치하십시오" - read -e -p "외부 네트워크 도킹 IP를 입력하십시오." server_addr - read -e -p "외부 네트워크 도킹 토큰을 입력하십시오." token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 추가하십시오" - # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 - read -e -p "서비스 이름을 입력하십시오 :" service_name - read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "인트라넷 포트를 입력하십시오 :" local_port - read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # 구성 파일에 사용자 입력을 쓰십시오 + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 출력 생성 정보 - echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 삭제하십시오" - # 삭제 해야하는 서비스 이름을 입력하라는 메시지 - read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name - # SED를 사용하여 서비스 및 관련 구성을 삭제하십시오. + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 헤더를 인쇄하십시오 + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 서비스 정보가있는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3756,11 @@ list_forwarding_services() { type } - # 현재 서비스 이름을 업데이트하십시오 + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 이전 값을 지우십시오 + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3789,7 +3789,7 @@ list_forwarding_services() { } END { - # 마지막 서비스에 대한 정보를 인쇄하십시오 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3802,17 @@ list_forwarding_services() { -# FRP 서버 포트를 가져옵니다 +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 액세스 주소를 생성합니다 +# 生成访问地址 generate_access_urls() { - # 모든 포트를 먼저 얻으십시오 + # 首先获取所有端口 get_frp_ports - # 8055/8056 이외의 포트가 있는지 확인하십시오 + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3821,18 @@ generate_access_urls() { fi done - # 유효한 포트가있을 때만 제목과 콘텐츠 표시 + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRP 서비스 외부 액세스 주소 :" + echo "FRP服务对外访问地址:" - # 프로세스 IPv4 주소 + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # Process IPv6 주소 (현재 경우) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3841,7 @@ generate_access_urls() { done fi - # HTTPS 구성 처리 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP 서버" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 서버$check_frp $update_status" - echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 인트라넷 서비스에 대한 도메인 이름 액세스 6. 도메인 이름 액세스 삭제" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00. 서비스 상태 새로 고침 0. 이전 메뉴로 돌아갑니다." + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 서버가 설치되었습니다" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 서버가 업데이트되었습니다" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; 5) - echo "반전 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" - send_stats "외부 도메인 이름에 대한 FRP 액세스" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용" - read -e -p "해제 할 포트를 입력하십시오." frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." - read -e -p "차단 해야하는 포트를 입력하십시오." frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRP 서비스 상태를 새로 고치십시오" - echo "FRP 서비스 상태가 새로 고쳐졌습니다" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP 클라이언트" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버로 도킹, 도킹 후 인터넷 액세스에 인트라넷 침투 서비스를 만들 수 있습니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 구성 수동으로 서비스 구성" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 클라이언트가 설치되었습니다" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 클라이언트가 업데이트되었습니다" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; 4) @@ -4066,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "YT-DLP 다운로드 도구" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLP는 YouTube, Bilibili, Twitter 등을 포함한 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." - echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "다운로드 된 비디오 목록 :" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. 단일 비디오 다운로드 6. 배치 비디오 다운로드 7. 사용자 정의 매개 변수 다운로드" - echo "8. MP3 오디오 9. 비디오 디렉토리 삭제 10. 쿠키 관리 (개발 중)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "옵션 번호를 입력하십시오 :" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "yt-dlp 설치 ..." - echo "yt-dlp 설치 ..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlp 업데이트 ..." - echo "yt-dlp 업데이트 ..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlp 제거 ..." - echo "yt-dlp 제거 ..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "단일 비디오 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "다운로드가 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "배치 비디오 다운로드" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "이제 배치 다운로드를 시작하십시오 ..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "배치 다운로드가 완료되었고, 키를 눌러 계속하십시오 ..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "맞춤형 비디오 다운로드" - read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "오디오 다운로드가 완료되었습니다. 키를 누르면 계속하십시오 ..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "비디오 삭제" - read -e -p "삭제 비디오의 이름을 입력하십시오." rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4195,7 @@ set_timedate() { -# DPKG 인터럽트 문제를 수정하십시오 +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi } @@ -4231,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}시스템 정리 ...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "패키지 관리자 캐시 청소 ..." + echo "清理包管理器缓存..." apk cache clean - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APK 캐시 삭제 ..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "사용하지 않는 의존성 정리 ..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "패키지 관리자 캐시 청소 ..." + echo "清理包管理器缓存..." pkg clean -y - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi return @@ -4340,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "DNS 최적화" +send_stats "优化DNS" while true; do clear - echo "DNS 주소를 최적화합니다" + echo "优化DNS地址" echo "------------------------" - echo "현재 DNS 주소" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 외국 DNS 최적화 :" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 국내 DNS 최적화 :" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 구성을 수동으로 편집합니다" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "외국 DNS 최적화" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "국내 DNS 최적화" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "DNS 구성을 수동으로 편집합니다" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthentication이 발견되면 예로 설정하십시오 + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 발견 된 경우 PubKeyAuthentication이 예로 설정됩니다 + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthentication 또는 PubKeyAuthentication이 일치하지 않는 경우 기본값을 설정하십시오. + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 백업 SSH 구성 파일 + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 포트는 다음으로 수정되었습니다.$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "개인 키 정보가 생성되었습니다. 복사하고 저장하십시오.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인 파일" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}루트 프라이빗 키 로그인이 활성화되고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "SSH 공개 키 내용을 입력하십시오 (일반적으로 'SSH-RSA'또는 'SSH-ED25519'로 시작) :" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}오류 : 공개 키 컨텐츠가 입력되지 않았습니다.${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}공개 키가 성공적으로 가져 왔고 루트 개인 키 로그인이 활성화되었고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "루트 비밀번호를 설정하십시오" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능은 루트 사용자가 실행해야합니다!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "시스템을 다시 설치하십시오" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}Teddysun.com${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "시스템을 다시 설치하십시오" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "데비안 13을 다시 설치하십시오" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "데비안 12를 다시 설치하십시오" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "데비안 11을 다시 설치하십시오" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "데비안 10을 다시 설치하십시오" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "우분투 24.04를 다시 설치하십시오" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "우분투 22.04를 다시 설치하십시오" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04를 다시 설치하십시오" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "우분투 18.04를 다시 설치하십시오" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4661,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10을 다시 설치하십시오" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9를 다시 설치하십시오" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "Alma10을 다시 설치하십시오" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "Alma9를 다시 설치하십시오" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10을 다시 설치하십시오" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9를 다시 설치하십시오" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42를 다시 설치하십시오" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41을 다시 설치하십시오" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "CentOS10을 다시 설치하십시오" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9를 다시 설치하십시오" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "알파인을 다시 설치하십시오" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "아치를 다시 설치하십시오" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "칼리를 다시 설치하십시오" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "Openeuler를 다시 설치하십시오" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "재설치 OpenSuse" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "비행 소부소" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4790,7 @@ dd_xitong() { 41) - send_stats "Windows 11을 다시 설치하십시오" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Windows 10을 다시 설치하십시오" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7을 다시 설치하십시오" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22를 다시 설치하십시오" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Windows Server 19를 다시 설치하십시오" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Windows Server 16을 다시 설치하십시오" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11 Arm을 다시 설치하십시오" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3 관리" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "Xanmod의 BBRV3 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. BBRV3 커널 업데이트 2. BBRV3 커널 제거" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmod 커널이 업데이트되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmod 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4916,13 @@ bbrv3() { else clear - echo "BBR3 가속도를 설정하십시오" - echo "비디오 소개 : https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "데비안/우분투 만 지원합니다" - echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경은이를 지원하지 않으며 데비안 및 우분투 시스템 만 지원합니다." + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "운영 체제 유형을 결정할 수 없습니다" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4957,17 @@ bbrv3() { bbr_on - echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4976,40 @@ bbrv3() { elrepo_install() { - # Elrepo GPG 공개 키를 가져 오십시오 - echo "Elrepo GPG 공개 키를 가져 오십시오 ..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 시스템 버전을 감지하십시오 + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 지원되는 운영 체제에서 실행하십시오 + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "지원되지 않는 운영 체제 :$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 감지 된 운영 체제 정보를 인쇄합니다 - echo "감지 된 운영 체제 :$os_name $os_version" - # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepo 저장소 구성 (버전 9)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "지원되지 않는 시스템 버전 :$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오. - echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepo 저장소 구성이 설치되어 최신 메인 라인 커널로 업데이트됩니다." + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "레드 모자 커널 관리" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hat 커널을 업데이트하십시오" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepo 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" - send_stats "빨간 모자 커널을 제거하십시오" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5060,26 @@ elrepo() { else clear - echo "데이터를 백업하고 Linux 커널을 업그레이드합니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" - echo "Linux 커널을 업그레이드하면 시스템 성능 및 보안이 향상 될 수 있습니다. 조건이 허용되고 생산 환경을 조심스럽게 업그레이드하는 경우 시도하는 것이 좋습니다!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hat 커널을 업그레이드하십시오" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}바이러스 데이터베이스 업데이트 ...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔 할 디렉토리를 지정하십시오." + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}스캔 디렉토리 $@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # 마운트 매개 변수를 빌드하십시오 + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # Clamscan 명령 매개 변수를 작성하십시오 + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Docker 명령을 실행하십시오 + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ scan이 완료되고 바이러스 보고서가 저장됩니다${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}바이러스가 있다면 제발${gl_huang}scan.log${gl_lv}파일에서 찾은 키워드를 검색하여 바이러스의 위치를 확인하십시오.${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "바이러스 스캔 관리" + send_stats "病毒扫描管理" while true; do clear - echo "Clamav 바이러스 스캐닝 도구" - echo "비디오 소개 : https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "오픈 소스 바이러스 백신 소프트웨어 도구로 주로 다양한 유형의 맬웨어를 감지하고 제거하는 데 사용됩니다." - echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리를 스캔하십시오${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "전체 디스크 스캔" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5168,7 @@ clamav() { ;; 2) - send_stats "중요한 디렉토리 스캔" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "사용자 정의 디렉토리 스캔" - read -e -p "스캔 할 디렉토리를 입력하십시오." directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5194,21 @@ clamav() { -# 고성능 모드 최적화 기능 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}전환하십시오${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 이퀄라이제이션 모드 최적화 기능 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 기본 설정 기능을 복원하십시오 +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}기본 설정으로 복원하십시오 ...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}파일 디스크립터 복원 ...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}네트워크 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}캐시 관리 복원 ...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}다른 최적화를 복원 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 웹 사이트 구축 최적화 기능 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux 커널 튜닝 관리" - echo "Linux 시스템에서 커널 매개 변수의 최적화" - echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." - echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." - echo "2. 균형 최적화 모드 : 매일 사용하기에 적합한 성능과 자원 소비 사이의 균형." - echo "3. 웹 사이트 최적화 모드 : 웹 사이트 서버에 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." - echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." - echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." - echo "6. 기본 설정을 복원하십시오. 시스템 설정을 기본 구성으로 복원하십시오." + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "고성능 모드 최적화" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "균형 모드 최적화" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "웹 사이트 최적화 모델" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "라이브 스트리밍 최적화" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "게임 서버 최적화" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "기본 설정을 복원하십시오" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "지원되지 않는 시스템 :$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "지원되지 않는 시스템, 시스템 유형을 인식 할 수 없습니다." + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "스위치 시스템 언어" +send_stats "切换系统语言" while true; do clear - echo "현재 시스템 언어 :$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1. 영어 2. 중국어 3. 전통 중국어" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "영어로 전환하십시오" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "단순화 된 중국어로 전환하십시오" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "전통적인 중국어로 전환하십시오" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 볼 수 있도록 SSH를 다시 연결하십시오!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5530,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "명령 라인 미화 도구" + send_stats "命令行美化工具" while true; do clear - echo "명령 라인 미화 도구" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "시스템 재활용 스테이션" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5605,17 @@ linux_trash() { fi clear - echo -e "현재 재활용 쓰레기통${trash_status}" - echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "재활용 쓰레기통은 비어 있습니다" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1. 재활용 빈을 활성화합니다. 2. 재활용 쓰레기통을 닫습니다." - echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "Recycle Bin이 활성화되고 삭제 된 파일이 Recycle Bin으로 이동됩니다." + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "재활용 빈이 닫히고 파일이 직접 삭제됩니다." + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "복원 할 파일 이름을 입력하십시오." file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore홈 디렉토리로 복원되었습니다." + echo "$file_to_restore 已还原到主目录。" else - echo "파일이 존재하지 않습니다." + echo "文件不存在。" fi ;; 4) - read -e -p "재활용 쓰레기통을 지우셨습니까? [Y/N] :" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "재활용 쓰레기통이 지워졌습니다." + echo "回收站已清空。" fi ;; *) @@ -5658,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "명령 즐겨 찾기" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 백업을 만듭니다 +# 创建备份 create_backup() { - send_stats "백업을 만듭니다" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 - echo "백업 예제 :" - echo "- 단일 디렉토리를 백업 : /var /www" - echo "- 여러 디렉토리 백업 : /etc /home /var /log" - echo "- Direct Enter는 기본 디렉토리 ( /etc /usr /home)를 사용합니다." - read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # 사용자가 디렉토리를 입력하지 않으면 기본 디렉토리를 사용하십시오. + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 사용자가 입력 한 디렉토리를 공백 별 배열로 분리합니다. + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 백업 파일 접두사를 생성합니다 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 디렉토리 이름을 추출하고 슬래시를 제거하십시오 + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 마지막 밑줄을 제거하십시오 + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # 백업 파일 이름을 생성합니다 + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 사용자가 선택한 디렉토리를 인쇄하십시오 - echo "선택한 백업 디렉토리는 다음과 같습니다." + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 백업을 만듭니다 - echo "백업 생성$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 명령이 성공했는지 확인하십시오 + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "백업은 성공적으로 생성되었습니다.$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "백업 생성이 실패했습니다!" + echo "备份创建失败!" exit 1 fi } -# 백업을 복원하십시오 +# 恢复备份 restore_backup() { - send_stats "백업을 복원하십시오" - # 복원하려는 백업을 선택하십시오 - read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - echo "백업 복구$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "백업 및 복원을 성공적으로 복원하십시오!" + echo "备份恢复成功!" else - echo "백업 복구 실패!" + echo "备份恢复失败!" exit 1 fi } -# 백업을 나열합니다 +# 列出备份 list_backups() { - echo "사용 가능한 백업 :" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# 백업을 삭제하십시오 +# 删除备份 delete_backup() { - send_stats "백업을 삭제하십시오" + send_stats "删除备份" - read -e -p "삭제하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - # 백업을 삭제하십시오 + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "백업이 성공적으로 삭제되었습니다!" + echo "备份删除成功!" else - echo "백업 삭제가 실패했습니다!" + echo "备份删除失败!" exit 1 fi } -# 백업 메인 메뉴 +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "시스템 백업 기능" - echo "시스템 백업 기능" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. 백업 만들기 2. 백업 복원 3. 백업 삭제" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5806,56 @@ linux_backup() { -# 연결 목록 표시 +# 显示连接列表 list_connections() { - echo "저장된 연결 :" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 새 연결을 추가하십시오 +# 添加新连接 add_connection() { - send_stats "새 연결을 추가하십시오" - echo "새 연결 예제 :" - echo "- 연결 이름 : my_server" - echo "-IP 주소 : 192.168.1.100" - echo "- 사용자 이름 : 루트" - echo "- 포트 : 22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "연결 이름을 입력하십시오 :" name - read -e -p "IP 주소를 입력하십시오 :" ip - read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "인증 방법을 선택하십시오 :" - echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택 (1/2)을 입력하십시오 :" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5864,89 @@ add_connection() { fi ;; *) - echo "잘못된 선택!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "연결이 저장됩니다!" + echo "连接已保存!" } -# 연결을 삭제하십시오 +# 删除连接 delete_connection() { - send_stats "연결을 삭제하십시오" - read -e -p "삭제하려면 연결 번호를 입력하십시오." num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "연결이 삭제되었습니다!" + echo "连接已删除!" } -# 연결을 사용하십시오 +# 使用连接 use_connection() { - send_stats "연결을 사용하십시오" - read -e -p "사용할 연결 번호를 입력하십시오." num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "연결$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 키와 연결하십시오 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 키 파일 경로가 정확합니까?$password_or_key" - echo "2. 키 파일 권한이 올바른지 여부 (600이어야 함)." - echo "3. 대상 서버가 키를 사용하여 로그인 할 수 있는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # 비밀번호로 연결하십시오 + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." - echo "설치 방법 :" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 사용자 이름과 비밀번호가 올바른지 여부." - echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." - echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSH 원격 연결 도구" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 구성 파일과 키 디렉토리가 존재하는지 확인하고 존재하지 않으면 작성하십시오. + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 원격 연결 도구" - echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1. 새 연결 만들기 2. 연결 사용 3. 연결 삭제" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5988,156 @@ ssh_manager() { -# 사용 가능한 하드 디스크 파티션을 나열하십시오 +# 列出可用的硬盘分区 list_partitions() { - echo "사용 가능한 하드 디스크 파티션 :" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 파티션을 장착하십시오 +# 挂载分区 mount_partition() { - send_stats "파티션을 장착하십시오" - read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션은 이미 장착되어 있습니다!" + echo "分区已经挂载!" return fi - # 마운트 포인트를 만듭니다 + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 파티션을 장착하십시오 + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "파티션 마운트 성공적으로 :$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "파티션 마운트 실패!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# 파티션을 제거하십시오 +# 卸载分区 unmount_partition() { - send_stats "파티션을 제거하십시오" - read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "파티션이 장착되지 않았습니다!" + echo "分区未挂载!" return fi - # 파티션을 제거하십시오 + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 분할 해제 성공 :$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "파티션 제거 실패!" + echo "分区卸载失败!" fi } -# 목록 장착 파티션 +# 列出已挂载的分区 list_mounted_partitions() { - echo "마운트 파티션 :" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 형식 파티션 +# 格式化分区 format_partition() { - send_stats "형식 파티션" - read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 장착되었습니다. 먼저 제거하십시오!" + echo "分区已经挂载,请先卸载!" return fi - # 파일 시스템 유형을 선택하십시오 - echo "파일 시스템 유형을 선택하십시오 :" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "선택을 입력하십시오 :" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "잘못된 선택!"; return ;; + *) echo "无效的选择!"; return ;; esac - # 형식을 확인하십시오 - read -e -p "파티션 형식 확인 /dev /$PARTITION~을 위한$FS_TYPE그게? (Y/N) :" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "작업이 취소되었습니다." + echo "操作已取消。" return fi - # 형식 파티션 - echo "파티션 형식 /dev /$PARTITION~을 위한$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 형식이 성공했습니다!" + echo "分区格式化成功!" else - echo "파티션 형식이 실패했습니다!" + echo "分区格式化失败!" fi } -# 파티션 상태를 확인하십시오 +# 检查分区状态 check_partition() { - send_stats "파티션 상태를 확인하십시오" - read -e -p "파티션 이름을 입력하여 확인하십시오 (예 : SDA1) :" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션 상태를 확인하십시오 - echo "파티션 /개발자 /$PARTITION상태:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# 메인 메뉴 +# 主菜单 disk_manager() { - send_stats "하드 디스크 관리 기능" + send_stats "硬盘管理功能" while true; do clear - echo "하드 디스크 파티션 관리" - echo -e "${gl_huang}이 기능은 테스트 기간 동안 내부적으로 테스트되므로 생산 환경에서 사용하지 마십시오.${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" - echo "4. 파티션 형식 5. 파티션 상태를 확인하십시오" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } -# 작업 목록 표시 +# 显示任务列表 list_tasks() { - echo "저장된 동기화 작업 :" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 새로운 작업을 추가하십시오 +# 添加新任务 add_task() { - send_stats "새 동기화 작업을 추가하십시오" - echo "새 동기화 작업 작성 예 :" - echo "- 작업 이름 : Backup_www" - echo "- 로컬 디렉토리 : /var /www" - echo "- 원격 주소 : user@192.168.1.100" - echo "- 원격 디렉토리 : /백업 /www" - echo "- 포트 번호 (기본 22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "작업 이름을 입력하십시오 :" name - read -e -p "로컬 디렉토리를 입력하십시오 :" local_path - read -e -p "원격 디렉토리를 입력하십시오 :" remote_path - read -e -p "원격 사용자 @IP를 입력하십시오 :" remote - read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "인증 방법을 선택하십시오 :" - echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택하십시오 (1/2) :" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "잘못된 키 컨텐츠!" + echo "无效的密钥内容!" return fi ;; *) - echo "잘못된 선택!" + echo "无效的选择!" return ;; esac - echo "동기화 모드를 선택하십시오 :" - echo "1. 표준 모드 (-avz)" - echo "2. 대상 파일 삭제 (-avz-delete)" - read -e -p "선택하십시오 (1/2) :" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "유효하지 않은 선택, 기본값 -AVZ를 사용하십시오"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "작업을 저장했습니다!" + echo "任务已保存!" } -# 작업을 삭제하십시오 +# 删除任务 delete_task() { - send_stats "동기화 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 해당 작업을 찾을 수 없었습니다." + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "작업이 삭제되었습니다!" + echo "任务已删除!" } run_task() { - send_stats "동기화 작업을 수행하십시오" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 매개 변수를 분석하십시오 + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6278,51 @@ run_task() { num="$1" fi - # 들어오는 작업 번호가없는 경우 사용자에게 입력하라는 메시지를 표시하십시오. + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "실행할 작업 번호를 입력하십시오." num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 작업이 찾을 수 없었습니다!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 동기화 방향에 따라 소스 및 대상 경로를 조정하십시오 + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "동기화를 원격 끝으로 푸시합니다.$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH 연결 공통 매개 변수를 추가하십시오 + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." - echo "설치 방법 :" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 키 파일이 존재하는지 여부와 권한이 올바른지 확인 + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "오류 : 키 파일이 존재하지 않습니다.$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "경고 : 키 파일 권한이 잘못되었고 수리 중입니다 ..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6330,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "동기화가 완료되었습니다!" + echo "同步完成!" else - echo "동기화 실패! 다음을 확인하십시오." - echo "1. 네트워크 연결이 정상입니까?" - echo "2. 원격 호스트가 액세스 할 수 있습니까?" - echo "3. 인증 정보가 정확합니까?" - echo "4. 로컬 및 원격 디렉토리에 올바른 액세스 권한이 있습니까?" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 시간이 정한 작업을 만듭니다 +# 创建定时任务 schedule_task() { - send_stats "동기화 타이밍 작업을 추가하십시오" + send_stats "添加同步定时任务" - read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi - echo "시간이 정한 실행 간격을 선택하십시오." - echo "1) 한 시간에 한 번 실행하십시오" - echo "2) 하루에 한 번 수행하십시오" - echo "3) 일주일에 한 번 실행하십시오" - read -e -p "옵션을 입력하십시오 (1/2/3) :" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "오류 : 유효한 옵션을 입력하십시오!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 동일한 작업이 이미 존재하는지 확인하십시오 + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "오류 :이 작업의 타이밍 동기화가 이미 존재합니다!" + echo "错误: 该任务的定时同步已存在!" return fi - # 사용자에게 크론AB를 만듭니다 + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "타이밍 작업이 만들어졌습니다.$cron_job" + echo "定时任务已创建: $cron_job" } -# 예정된 작업을 봅니다 +# 查看定时任务 view_tasks() { - echo "현재 타이밍 작업 :" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 타이밍 작업을 삭제하십시오 +# 删除定时任务 delete_task_schedule() { - send_stats "동기화 타이밍 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "삭제 된 작업 번호$num타이밍 작업" + echo "已删除任务编号 $num 的定时任务" } -# 작업 관리 메인 메뉴 +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "RSYNC 원격 동기화 도구" - echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 새 작업 생성 2. 작업을 삭제하십시오" - echo "3. 원격 끝에 로컬 동기화 수행 4. 로컬 엔드에 대한 원격 동기화 수행" - echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "시스템 정보 쿼리" + send_stats "系统信息查询" ip_address @@ -6498,41 +6498,41 @@ linux_ps() { echo "" - echo -e "시스템 정보 쿼리" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}호스트 이름 :${gl_bai}$hostname" - echo -e "${gl_kjlan}시스템 버전 :${gl_bai}$os_info" - echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU 모델 :${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU 코어 수 :${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" - echo -e "${gl_kjlan}물리적 기억 :${gl_bai}$mem_info" - echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" - echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}네트워크 알고리즘 :${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 주소 :${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6 주소 :${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS 주소 :${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}지리적 위치 :${gl_bai}$country $city" - echo -e "${gl_kjlan}시스템 시간 :${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "기본 도구" - echo -e "기본 도구" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" - echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" - echo -e "${gl_kjlan}9. ${gl_bai}Tmux 다중 채널 배경 달리기 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" - echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" - echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" curl --help - send_stats "컬을 설치하십시오" + send_stats "安装curl" ;; 2) clear install wget clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" wget --help - send_stats "wget을 설치하십시오" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" sudo --help - send_stats "Sudo를 설치하십시오" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" socat -h - send_stats "Socat을 설치하십시오" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "HTOP를 설치하십시오" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "iftop을 설치하십시오" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" unzip - send_stats "압축을 설치하십시오" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" tar --help - send_stats "타르를 설치하십시오" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmux를 설치하십시오" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "FFMPEG를 설치하십시오" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "Btop을 설치하십시오" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "레인저를 설치하십시오" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDU를 설치하십시오" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZF를 설치하십시오" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIM을 설치하십시오" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "나노를 설치하십시오" + send_stats "安装nano" ;; @@ -6713,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "git을 설치하십시오" + send_stats "安装git" ;; 21) @@ -6721,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix를 설치하십시오" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "SL을 설치하십시오" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "Bastet을 설치하십시오" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "NSNAKE를 설치하십시오" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Ninvaders를 설치하십시오" + send_stats "安装ninvaders" ;; 31) clear - send_stats "모두 설치하십시오" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "모든 설치 (게임 및 화면 보호기 제외)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "모든 것을 제거하십시오" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "설치된 도구 이름 (WGET CURL SUDO HTOP)을 입력하십시오." installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "지정된 소프트웨어를 설치하십시오" + send_stats "安装指定软件" ;; 42) clear - read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "지정된 소프트웨어를 제거하십시오" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6789,7 @@ linux_tools() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -6803,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR 관리" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "현재 TCP 차단 알고리즘 :$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" - echo "BBR 관리" + echo "BBR管理" echo "------------------------" - echo "1. BBRV3 켜기 2. BBRV3 끄기 (재시작)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "알파인 활성화 BBR3" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6854,37 +6854,37 @@ linux_docker() { while true; do clear - # Send_stats "Docker Management" - echo -e "도커 관리" + # send_stats "docker管理" + echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경을 설치하고 업데이트하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Docker Global Status를 봅니다${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" - echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" - echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너 및 미러 네트워크 데이터 볼륨을 청소하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" - echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}도커 환경을 제거하십시오" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Docker 환경을 설치하십시오" + send_stats "安装docker环境" install_add_docker ;; @@ -6895,22 +6895,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "도커 글로벌 상태" - echo "도커 버전" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "도커 이미지 :${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6925,8 +6925,8 @@ linux_docker() { 5) while true; do clear - send_stats "도커 네트워크 관리" - echo "도커 네트워크 목록" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -6950,36 +6950,36 @@ linux_docker() { done echo "" - echo "네트워크 작동" + echo "网络操作" echo "------------------------" - echo "1. 네트워크를 만듭니다" - echo "2. 인터넷에 가입하십시오" - echo "3. 네트워크를 종료하십시오" - echo "4. 네트워크를 삭제합니다" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "네트워크를 만듭니다" - read -e -p "새 네트워크 이름 설정 :" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "인터넷에 가입하십시오" - read -e -p "네트워크 이름에 가입 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "인터넷에 가입하십시오" - read -e -p "종료 네트워크 이름 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다 (여러 컨테이너 이름은 공간별로 분리됩니다)." dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6988,8 +6988,8 @@ linux_docker() { ;; 4) - send_stats "네트워크를 삭제하십시오" - read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7003,29 +7003,29 @@ linux_docker() { 6) while true; do clear - send_stats "도커 볼륨 관리" - echo "도커 볼륨 목록" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "볼륨 작동" + echo "卷操作" echo "------------------------" - echo "1. 새 볼륨을 만듭니다" - echo "2. 지정된 볼륨을 삭제합니다" - echo "3. 모든 볼륨을 삭제하십시오" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "새 볼륨을 만듭니다" - read -e -p "새 볼륨 이름 설정 :" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "볼륨 삭제 이름을 입력하십시오 (공백으로 여러 볼륨 이름을 분리하십시오)." dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7034,7 +7034,7 @@ linux_docker() { ;; 3) - send_stats "모든 볼륨을 삭제하십시오" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7043,7 +7043,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7056,7 +7056,7 @@ linux_docker() { ;; 7) clear - send_stats "도커 청소" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7065,13 +7065,13 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "도커 소스" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7084,19 +7084,19 @@ linux_docker() { 11) clear - send_stats "Docker V6 열기" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker V6 레벨" + send_stats "Docker v6 关" docker_ipv6_off ;; 20) clear - send_stats "Docker는 제거합니다" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7108,7 +7108,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7117,7 +7117,7 @@ linux_docker() { kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7134,151 +7134,151 @@ linux_test() { while true; do clear - # Send_stats "테스트 스크립트 컬렉션" - echo -e "스크립트 수집 테스트" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGpt는 상태 감지를 잠금 해제합니다" - echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" - echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}네트워크 속도 측정" - echo -e "${gl_kjlan}11. ${gl_bai}Besttrace Three Network Backhaul 지연 라우팅 테스트" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC 다기능 속도 테스트 스크립트" - echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}하드웨어 성능 테스트" - echo -e "${gl_kjlan}21. ${gl_bai}YABS 성능 테스트" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}포괄적 인 테스트" - echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "ChatGpt는 상태 감지를 잠금 해제합니다" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "지역 스트리밍 미디어 잠금 해제 테스트" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "YEAHWU 스트리밍 미디어 잠금 해제 탐지" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_ip 품질 신체 검사 스크립트" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "MTR_TRACE 3 개의 네트워크 리턴 라인 테스트" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed 3 Net 속도 측정" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace 빠른 백홀 테스트 스크립트" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo "참조 할 수있는 IP 목록" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "베이징 통신 : 219.141.136.12" - echo "베이징 유니폼 : 202.106.50.1" - echo "베이징 모바일 : 221.179.155.161" - echo "상하이 통신 : 202.96.209.133" - echo "상하이 유니폼 : 210.22.97.1" - echo "상하이 모바일 : 211.136.112.200" - echo "광저우 통신 : 58.60.188.222" - echo "광저우 유니폼 : 210.21.196.6" - echo "광저우 모바일 : 120.196.165.24" - echo "청두 통신 : 61.139.2.69" - echo "청두 유니폼 : 119.6.6.6" - echo "청두 모바일 : 211.137.96.205" - echo "Hunan Telecom : 36.111.200.100" - echo "후난 유니폼 : 42.48.16.100" - echo "후난 모바일 : 39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "지정된 IP를 입력하십시오." testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3 네트워크 라인 테스트" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC 다기능 속도 테스트 스크립트" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "네트워크 품질 테스트 스크립트" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABS 성능 테스트" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPU 성능 테스트 스크립트" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "벤치 성능 테스트" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX 퓨전 몬스터 검토" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7288,7 +7288,7 @@ linux_test() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7304,51 +7304,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud 스크립트 컬렉션" - echo -e "Oracle Cloud 스크립트 컬렉션" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}유휴 기계 활성 스크립트를 설치하십시오" - echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" - echo -e "${gl_kjlan}4. ${gl_bai}형사 R 스크립트 시작" - echo -e "${gl_kjlan}5. ${gl_bai}루트 비밀번호 로그인 모드를 켭니다" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6 복구 도구" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "활성 스크립트 : CPU는 10-20% 메모리를 점유합니다." - read -e -p "설치 하시겠습니까? (Y/N) :" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # 기본값을 설정합니다 + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율 백분율을 입력하라는 메시지를 표시하고 입력 한 경우 기본값을 사용하십시오. - read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용량 백분율 범위 (예 : 10-20)를 입력하십시오 [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "스피드 테스트 간격 시간 (초)을 입력하십시오 [기본값 :$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 도커 컨테이너를 실행하십시오 + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7356,14 +7356,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloud 설치 활성 스크립트" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7371,20 +7371,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "시스템을 다시 설치하십시오" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - read -e -p "계속할거야? (Y/N) :" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "다시 설치할 시스템을 선택하십시오 : 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7396,28 +7396,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "다시 설치 한 비밀번호를 입력하십시오." vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud 회복 시스템 스크립트" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "이 기능은 개발 단계에 있으므로 계속 지켜봐 주시기 바랍니다!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7427,15 +7427,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7456,7 +7456,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7477,7 +7477,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7505,31 +7505,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp 웹 사이트 빌딩" - echo -e "${gl_huang}LDNMP 웹 사이트 구축" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPress를 설치하십시오${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" - echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginx 만 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" - echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" - echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" - echo -e "${gl_huang}33. ${gl_bai}시간이 정한 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" - echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7543,10 +7543,10 @@ linux_ldnmp() { 3) clear - # Discuz 포럼 + # Discuz论坛 webname="Discuz论坛" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7569,21 +7569,21 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao 클라우드 데스크탑 + # 可道云桌面 webname="可道云桌面" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7605,20 +7605,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" - echo "Redis 호스트 : Redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7644,24 +7644,24 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사 : MAC_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "설치가 성공한 후 배경 주소에 로그인하십시오." + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 한 다리 카운팅 카드 + # 独脚数卡 webname="独脚数卡" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7682,34 +7682,34 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "Redis 주소 : Redis" - echo "Redis Password : 기본적으로 채워지지 않습니다" - echo "Redis Port : 6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "웹 사이트 URL : https : //$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "사용자 이름 : 관리자" - echo "비밀번호 : 관리자" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "로그인 할 때 오른쪽 상단에 빨간색 Error0이 나타나면 다음 명령을 사용하십시오." - echo "나는 또한 유니콘 번호 카드가 너무 귀찮다는 것에 대해 매우 화가 났으며 그러한 문제가있을 것입니다!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # Flarum 포럼 + # flarum论坛 webname="flarum论坛" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7746,12 +7746,12 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : flarum_" - echo "관리자 정보는 직접 설정됩니다" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -7759,8 +7759,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7784,11 +7784,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 접두사 : typecho_" - echo "데이터베이스 주소 : MySQL" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -7797,8 +7797,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7823,18 +7823,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7851,10 +7851,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드합니다" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7864,20 +7864,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php가있는 경로" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 Index.php의 경로를 입력하십시오.$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택하십시오" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1. PHP의 최신 버전 | 2. PHP7.4 :" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7888,15 +7888,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장자를 설치하십시오" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "설치된 확장" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7906,25 +7906,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "계속하려면 모든 키를 누르면 의사 정적 내용 등과 같은 사이트 구성을 자세히 설정할 수 있습니다." + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 작성하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7934,10 +7934,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "데이터베이스 가져 오기 테이블 데이터" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "데이터베이스 가져 오기가 완료되었습니다" + echo "数据库导入完成" ;; *) echo @@ -7949,12 +7949,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 :$prefix" - echo "관리자 로그인 정보는 직접 설정됩니다" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -7967,10 +7967,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -7992,7 +7992,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8003,11 +8003,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "도메인 이름 형식 :${gl_huang}google.com${gl_bai}" - read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8027,8 +8027,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8050,8 +8050,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8068,8 +8068,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8102,8 +8102,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8120,10 +8120,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8133,12 +8133,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 index.html로가는 경로를 입력하십시오.$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8163,21 +8163,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP 환경 백업" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "백업 파일이 작성되었습니다 : /home /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8185,9 +8185,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." + echo "文件已传送至远程服务器home目录。" else - echo "전송할 파일은 찾을 수 없었습니다." + echo "未找到要传送的文件。" fi break ;; @@ -8195,7 +8195,7 @@ linux_ldnmp() { break ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8203,9 +8203,9 @@ linux_ldnmp() { 33) clear - send_stats "시간이 정한 원격 백업" - read -e -p "원격 서버 IP를 입력하십시오." useip - read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8215,18 +8215,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 주간 백업 2. 매일 백업" - read -e -p "선택을 입력하십시오 :" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "주간 백업의 요일을 선택하십시오 (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "매일 백업 시간을 선택하십시오 (시간, 0-23) :" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8240,19 +8240,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP 환경 복원" - echo "사용 가능한 사이트 백업" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8262,7 +8262,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8271,7 +8271,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "압축 패키지가 발견되지 않았습니다." + echo "没有找到压缩包。" fi ;; @@ -8289,11 +8289,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP 환경을 업데이트하십시오" - echo "LDNMP 환경을 업데이트하십시오" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "구성 요소의 새 버전을 발견하십시오" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8313,13 +8313,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. 전체 환경을 업데이트하십시오" + echo "5. 更新完整环境" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8328,7 +8328,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 8.0 8.3 8.4 9.0) (최신 버전을 얻으려면 입력) :" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8339,13 +8339,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 7.4 8.0 8.1 8.2 8.3) (최신 버전을 얻으려면 입력) :" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8378,8 +8378,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8390,15 +8390,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP 환경을 완전히 업데이트하십시오" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8424,7 +8424,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP 환경을 제거하십시오" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8438,7 +8438,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8448,7 +8448,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" esac break_end @@ -8468,12 +8468,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "응용 프로그램 시장" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 루프로 색상을 설정하십시오 + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8482,62 +8482,62 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" - echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" - echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" - echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" - echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" - echo -e "${gl_kjlan}19. ${color19}Thunder Pool Waf 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" - echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" - echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" - echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" - echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" - echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" - echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" - echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" - echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" - echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" - echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" - echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" - echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8720,7 +8720,7 @@ while true; do ;; 7|nezha) clear - send_stats "Nezha를 구축하십시오" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -8729,20 +8729,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha 모니터링$check_docker $update_status" - echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" - echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 사용" + echo "1. 使用" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -8799,7 +8799,7 @@ while true; do ;; 9|mail) - send_stats "우체국을 건설하십시오" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -8809,43 +8809,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우체국 서비스$check_docker $update_status" - echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "포트 감지" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "액세스 주소 :" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "이 DNS 레코드를 먼저 구문 분석하십시오" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8855,7 +8855,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "계속하려면 키를 누르십시오 ..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -8874,9 +8874,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -8899,9 +8899,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -8912,7 +8912,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; *) @@ -8946,7 +8946,7 @@ while true; do clear ip_address - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -8956,7 +8956,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chat이 설치되었습니다" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -8966,7 +8966,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -9050,7 +9050,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -9064,7 +9064,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -9209,7 +9209,7 @@ while true; do ;; 19|safeline) - send_stats "천둥 수영장을 건설하십시오" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -9217,20 +9217,20 @@ while true; do while true; do check_docker_app clear - echo -e "썬더 풀 서비스$check_docker" - echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9240,7 +9240,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Thunder Pool WAF 패널이 설치되었습니다" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9253,7 +9253,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Thunder Pool WAF 패널이 업데이트되었습니다" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9264,7 +9264,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9672,7 +9672,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9725,7 +9725,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya 가족 버킷" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -9927,9 +9927,9 @@ while true; do prometheus_install clear ip_address - echo "설치" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -9947,7 +9947,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10034,7 +10034,7 @@ while true; do 51|pve) clear - send_stats "PVE 치킨" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10154,7 +10154,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10169,7 +10169,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10197,7 +10197,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10212,7 +10212,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10220,7 +10220,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10241,17 +10241,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "설치" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름 : 관리자" - echo "초기 비밀번호 : changeme" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "앱이 업데이트되었습니다" + echo "应用已更新" } @@ -10261,7 +10261,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10308,7 +10308,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10324,7 +10324,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10586,7 +10586,7 @@ while true; do docker_rum() { - read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10616,7 +10616,7 @@ while true; do docker_rum() { - read -e -p "MOONTV 로그인 비밀번호 설정 :" app_passwd + read -e -p "设置MoonTV的登录密码: " app_passwd docker run -d \ --name moontv \ @@ -10702,8 +10702,8 @@ while true; do docker_rum() { - read -e -p "설정${docker_name}로그인 사용자 이름 :" app_use - read -e -p "설정${docker_name}로그인 비밀번호 :" app_passwd + read -e -p "设置${docker_name}的登录用户名: " app_use + read -e -p "设置${docker_name}的登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -10800,11 +10800,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 암호를 생성합니다 + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10813,17 +10813,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 관리자 계정 정보를 추가하십시오 + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 컨테이너를 시작하십시오 + # 启动容器 docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10833,7 +10833,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 원래 변수를 유지하십시오 + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10850,7 +10850,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10900,7 +10900,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11020,7 +11020,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -11033,7 +11033,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11153,35 +11153,35 @@ linux_work() { while true; do clear - send_stats "백엔드 작업 공간" - echo -e "백엔드 작업 공간" - echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." - echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." - echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "현재 기존 작업 공간 목록" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" - echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" - echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" - echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" - echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" - echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" - echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11189,7 +11189,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11197,63 +11197,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11265,21 +11265,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH 거주 모드" - echo -e "SSH 거주 모드${tmux_sshd_status}" - echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. 2를 켜십시오. 2를 끕니다" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11295,29 +11295,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "맞춤형 작업 공간" + send_stats "自定义工作区" ;; 23) - read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "배경 작업 공간에 명령을 주입합니다" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "작업 공간을 삭제합니다" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -11342,54 +11342,54 @@ linux_Settings() { while true; do clear - # Send_stats "시스템 도구" - echo -e "시스템 도구" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" - echo -e "${gl_kjlan}3. ${gl_bai}루트 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" - echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" - echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" - echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" - echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" - echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" - echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되었습니다" - send_stats "스크립트 바로 가기 키가 설정되었습니다" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11397,34 +11397,34 @@ linux_Settings() { 2) clear - send_stats "로그인 비밀번호를 설정하십시오" - echo "로그인 비밀번호를 설정하십시오" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "루트 비밀번호 모드" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "PY 버전 관리" - echo "파이썬 버전 관리" - echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" - echo "더 많은 버전 : https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "스크립트 PY 관리" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -11457,7 +11457,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi @@ -11486,55 +11486,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 Py 버전을 스위치하십시오" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "포트 열기" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "모든 포트가 열려 있습니다" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSH 포트를 수정하십시오" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 현재 SSH 포트 번호를 읽으십시오 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 현재 SSH 포트 번호를 인쇄하십시오 - echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 - read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # 포트 번호가 유효한 범위 내에 있는지 확인 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH 포트가 수정되었습니다" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH 포트 수정을 종료하십시오" + send_stats "退出SSH端口修改" break else - echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "입력이 유효하지 않으므로 번호를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -11553,8 +11553,8 @@ EOF ;; 9) root_use - send_stats "새로운 사용자가 루트를 비활성화합니다" - read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11569,49 +11569,49 @@ EOF passwd -l root - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6 우선 순위를 설정하십시오" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6 우선 순위를 설정하십시오" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선호하는 네트워크를 선택하십시오." choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4 우선 순위로 전환되었습니다" - send_stats "IPv4 우선 순위로 전환되었습니다" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6 우선 순위로 전환되었습니다" - send_stats "IPv6 우선 순위로 전환되었습니다" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -11629,43 +11629,43 @@ EOF 12) root_use - send_stats "가상 메모리를 설정합니다" + send_stats "设置虚拟内存" while true; do clear - echo "가상 메모리를 설정합니다" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G 가상 메모리가 설정되었습니다" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G 가상 메모리가 설정되었습니다" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "사용자 정의 가상 메모리가 설정되었습니다" + send_stats "已设置自定义虚拟内存" ;; *) @@ -11678,8 +11678,8 @@ EOF 13) while true; do root_use - send_stats "사용자 관리" - echo "사용자 목록" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11690,62 +11690,62 @@ EOF echo "" - echo "계정 운영" + echo "账户操作" echo "------------------------" - echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. 계정을 삭제하십시오" + echo "5. 删除账号" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 2) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 새로운 사용자에게 허가를 부여하십시오 + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 3) - read -e -p "사용자 이름을 입력하십시오 :" username - # 새로운 사용자에게 허가를 부여하십시오 + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "사용자 이름을 입력하십시오 :" username - # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자와 홈 디렉토리를 삭제하십시오 + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -11758,50 +11758,50 @@ EOF 14) clear - send_stats "사용자 정보 생성기" - echo "임의의 사용자 이름" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "임의의 사용자 이름$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "임의 이름" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5 개의 임의의 사용자 이름을 생성합니다 + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "임의의 사용자 이름$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "무작위 uuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "무작위 uuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16 비트 랜덤 비밀번호" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32 비트 랜덤 비밀번호" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -11809,46 +11809,46 @@ EOF 15) root_use - send_stats "시간대를 변경하십시오" + send_stats "换时区" while true; do clear - echo "시스템 시간 정보" + echo "系统时间信息" - # 현재 시스템 시간대를 얻으십시오 + # 获取当前系统时区 local timezone=$(current_timezone) - # 현재 시스템 시간을 얻으십시오 + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 시간대와 시간을 보여줍니다 - echo "현재 시스템 시간대 :$timezone" - echo "현재 시스템 시간 :$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "시간대 전환" + echo "时区切换" echo "------------------------" - echo "아시아" - echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" - echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" - echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" - echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" - echo "9. 태국 방콕에서의 시간" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "유럽" - echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" - echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" - echo "15. 네덜란드의 위트레흐트 시간 16. 스페인의 마드리드 시간" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "미국" - echo "21. 서양 시간 22. 동부 시간" - echo "23. 캐나다 시간 24. 멕시코 시간" - echo "25. 브라질 시간 26. 아르헨티나 시간" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC 글로벌 표준 시간" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11891,21 +11891,21 @@ EOF 18) root_use - send_stats "호스트 이름을 수정하십시오" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, Centos 등과 같은 다른 시스템 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11923,11 +11923,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" - send_stats "호스트 이름이 변경되었습니다" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "종료, 호스트 이름이 변경되지 않았습니다." + echo "已退出,未更改主机名。" break fi done @@ -11935,32 +11935,32 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스를 변경하십시오" + send_stats "换系统更新源" clear - echo "업데이트 소스 영역을 선택하십시오" - echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "중국 본토의 기본 소스" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "중국 본토의 교육 원" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "해외 출신" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "취소" + echo "已取消" ;; esac @@ -11968,62 +11968,62 @@ EOF ;; 20) - send_stats "타이밍 작업 관리" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "시간이 정한 작업 목록" + echo "定时任务列表" crontab -l echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. 월간 작업 2. 주간 작업" - echo "3. 일일 작업 4. 시간당 작업" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "선택을 입력하십시오 :" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "시간이 정한 작업을 추가하십시오" + send_stats "添加定时任务" ;; 2) - read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "타이밍 작업을 삭제하십시오" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "타이밍 작업 편집" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12035,32 +12035,32 @@ EOF 21) root_use - send_stats "지역 호스트 구문 분석" + send_stats "本地host解析" while true; do clear - echo "기본 호스트 구문 분석 목록" - echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "로컬 호스트 구문 분석이 추가되었습니다" + send_stats "本地host解析新增" ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "로컬 호스트 구문 분석 및 삭제" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12071,7 +12071,7 @@ EOF 22) root_use - send_stats "SSH 방어" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12083,20 +12083,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH 방어 프로그램$check_docker" - echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" - echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 安装防御程序" echo "------------------------" - echo "2. SSH 차단 레코드보기" - echo "3. 실시간 로그 모니터링" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12119,7 +12119,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12132,47 +12132,47 @@ EOF 23) root_use - send_stats "현재 제한 종료 기능" + send_stats "限流关机功能" while true; do clear - echo "현재 제한 종료 기능" - echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.sh 파일이 있는지 확인하십시오 + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gb의 값을 얻으십시오 + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 새 가상 메모리 크기를 입력하십시오 - echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." - read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12185,15 +12185,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "전류 제한 종료가 설정되었습니다" - send_stats "전류 제한 종료가 설정되었습니다" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 종료 기능이 꺼졌습니다" + echo "已关闭限流关机功能" ;; *) break @@ -12206,40 +12206,40 @@ EOF 24) root_use - send_stats "개인 키 로그인" + send_stats "私钥登录" while true; do clear - echo "루트 비공개 키 로그인 모드" - echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "새로운 키를 생성하십시오" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "기존 공개 키를 가져옵니다" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "로컬 비밀 키를보십시오" + send_stats "查看本机密钥" echo "------------------------" - echo "공개 키 정보" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "개인 키 정보" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12255,18 +12255,18 @@ EOF 25) root_use - send_stats "전보 경고" - echo "TG-BOT 모니터링 및 조기 경고 기능" - echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." - echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." - echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속할거야? (Y/N) :" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "전보 경고가 활성화되었습니다" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12288,7 +12288,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # ~/.profile 파일에 추가하십시오 + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12299,21 +12299,21 @@ EOF source ~/.profile clear - echo "TG-BOT 조기 경고 시스템이 시작되었습니다" - echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSH에서 고위험 취약점을 수정하십시오" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12357,7 +12357,7 @@ EOF ;; 37) clear - send_stats "명령 줄 기록" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12380,61 +12380,61 @@ EOF 41) clear - send_stats "게시판" - echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "원 스톱 튜닝" - echo "원 스톱 시스템 최적화" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "다음은 작동하고 최적화됩니다" - echo "1. 시스템을 최신으로 업데이트하십시오" - echo "2. 시스템 정크 파일 정리" - echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" - echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니 다" - echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" - echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" - echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" - echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "원 스톱 튜닝 시작" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12451,25 +12451,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" - echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -12477,7 +12477,7 @@ EOF 99) clear - send_stats "시스템을 다시 시작하십시오" + send_stats "重启系统" server_reboot ;; 100) @@ -12493,32 +12493,32 @@ EOF local status_message="无法确定的状态" fi - echo "개인 정보 및 보안" - echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." - echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "현재 상태 :$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. 수집을 켭니다" - echo "2. 컬렉션을 닫습니다" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 활성화되었습니다" - send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "컬렉션이 닫혔습니다" - send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -12534,11 +12534,11 @@ EOF 102) clear - send_stats "기술 라이온 스크립트를 제거하십시오" - echo "기술 라이온 스크립트를 제거하십시오" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." - read -e -p "계속할거야? (Y/N) :" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -12546,16 +12546,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "대본은 제거되었습니다." + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -12565,7 +12565,7 @@ EOF ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -12583,187 +12583,187 @@ EOF linux_file() { root_use - send_stats "파일 관리자" + send_stats "文件管理器" while true; do clear - echo "파일 관리자" + echo "文件管理器" echo "------------------------" - echo "현재 경로" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" - echo "15. 파일을 삭제하십시오" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" - echo "25. 파일을 다른 서버로 전달합니다" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" - send_stats "디렉토리로 이동하십시오" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname - mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" - send_stats "디렉토리를 만듭니다" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "디렉토리 권한을 수정하십시오" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name - read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "디렉토리의 이름을 바꿉니다" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname - rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "디렉토리 삭제" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "이전 메뉴 디렉토리로 돌아갑니다" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "작성하려면 파일 이름을 입력하십시오." filename - touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" - send_stats "파일을 만듭니다" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "편집 할 파일 이름을 입력하십시오." filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "파일 편집" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "파일 이름을 입력하십시오 :" filename - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "파일 권한을 수정합니다" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "현재 파일 이름을 입력하십시오 :" current_name - read -e -p "새 파일 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "파일의 이름을 바꿉니다" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "파일 삭제" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" - send_stats "압축 파일/디렉토리" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" - send_stats "압축 파일/디렉토리 해제" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" - send_stats "파일 또는 디렉토리를 이동하십시오" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 - cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사하십시오" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "오류 : 파일이 존재하지 않습니다." - send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "오류 : 원격 서버 비밀번호를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 알려진 호스트를위한 오래된 항목을 명확하게합니다 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCP를 사용하여 파일을 전송합니다 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트는 최신입니다$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13061,15 +13061,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" - send_stats "자동 스크립트 업데이트를 켜십시오" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" - send_stats "스크립트 자동 업데이트를 닫습니다" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13091,41 +13091,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" -echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" -echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" -echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" -echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" -echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" -echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" -echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" -echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" -echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" -echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" -echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" -echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" -echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" -echo -e "${gl_kjlan}15. ${gl_bai}광고 열" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" +echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "선택을 입력하십시오 :" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; - 3) clear ; send_stats "시스템 정리" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "워프 관리" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13136,13 +13136,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "잘못된 입력!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13150,68 +13150,68 @@ done k_info() { -send_stats "K 명령 참조 사용 사례" +send_stats "k命令参考用例" echo "-------------------" -echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "다음은 K 명령 참조 유스 케이스입니다." -echo "스크립트 시작 k" -echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" -echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" -echo "업데이트 시스템 K 업데이트 | K 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | K 청소" -echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" -echo "BBR3 제어판 K BBR3 | K bbrv3" -echo "커널 튜닝 패널 K nhyh | K 커널 최적화" -echo "가상 메모리 K 스왑 2048을 설정하십시오" -echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" -echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" -echo "시스템 백업 기능 K 백업 | K bf | K 백업" -echo "SSH 원격 연결 도구 K SSH | K 원격 연결" -echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" -echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" -echo "인트라넷 침투 (서버 측) K frps" -echo "인트라넷 침투 (클라이언트) K frpc" -echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" -echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" -echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" -echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" -echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" -echo "도메인 이름 인증서 응용 프로그램 K SSL" -echo "도메인 이름 인증서 만료 쿼리 K SSL PS" -echo "도커 환경 설치 K 도커 설치 | K 도커 설치" -echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" -echo "Docker Image Management K Docker img | K Docker Image" -echo "LDNMP 사이트 관리 K 웹" -echo "LDNMP 캐시 정리 K 웹 캐시" -echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" -echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." -echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" -echo "방화벽 패널 K FHQ | K 방화벽" -echo "포트 k dkdk 8080 | k 오픈 포트 8080" -echo "포트 K GBDK 7800 | K 닫기 포트 7800" -echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" -echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" -echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" -echo "앱 시장 관리 K 앱" -echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # 매개 변수가없는 경우 대화식 로직을 실행하십시오 + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # 매개 변수가있는 경우 해당 함수를 실행하십시오 + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "소프트웨어를 설치하십시오" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "소프트웨어를 제거하십시오" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13245,7 +13245,7 @@ else rsync_run) shift - send_stats "시간이 정한 RSYNC 동기화" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13264,7 +13264,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13277,13 +13277,13 @@ else swap) shift - send_stats "가상 메모리를 신속하게 설정했습니다" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "시간대를 빠르게 설정하십시오" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13331,42 +13331,42 @@ else status|状态) shift - send_stats "소프트웨어 상태보기" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "소프트웨어 스타트 업" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "소프트웨어 일시 정지" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 재시작" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "소프트웨어 부츠" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "인증서 상태를 확인하십시오" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" else k_info fi @@ -13376,15 +13376,15 @@ else shift case $1 in install|安装) - send_stats "Docker를 신속하게 설치하십시오" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "빠른 컨테이너 관리" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "빠른 미러 관리" + send_stats "快捷镜像管理" docker_image ;; *) @@ -13411,7 +13411,7 @@ else app) shift - send_stats "$@ 적용" + send_stats "应用$@" linux_panel "$@" ;; From c8a3f37ace60f614d07812240e452c615ddfebe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:37:03 +0800 Subject: [PATCH 0066/1285] Update kejilion.sh --- cn/kejilion.sh | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 37a29051d..698bd8d1d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.9" gl_hui='\e[37m' @@ -8535,6 +8535,8 @@ while true; do echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -11135,6 +11137,73 @@ while true; do ;; + b) + clear + send_stats "全部应用备份" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + case "$choice" in + [Yy]) + read -e -p "请输入远端服务器IP: " remote_ip + if [ -z "$remote_ip" ]; then + echo "错误: 请输入远端服务器IP。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "文件已传送至远程服务器/根目录。" + else + echo "未找到要传送的文件。" + fi + break + ;; + *) + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + else + echo "没有找到压缩包。" + fi + + ;; 0) kejilion From c1e9e879da00bbb0c189c5305cfa4fc2c6030281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:37:38 +0800 Subject: [PATCH 0067/1285] Update kejilion.sh --- kejilion.sh | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 6a4216cc9..024294583 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.9" gl_hui='\e[37m' @@ -8535,6 +8535,8 @@ while true; do echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -11135,6 +11137,73 @@ while true; do ;; + b) + clear + send_stats "全部应用备份" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + case "$choice" in + [Yy]) + read -e -p "请输入远端服务器IP: " remote_ip + if [ -z "$remote_ip" ]; then + echo "错误: 请输入远端服务器IP。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "文件已传送至远程服务器/根目录。" + else + echo "未找到要传送的文件。" + fi + break + ;; + *) + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + else + echo "没有找到压缩包。" + fi + + ;; 0) kejilion From e6a5c8d91d6aa5135af742c4ddf564e6a35651ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:41:41 +0800 Subject: [PATCH 0068/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ec42c8f37..7e025c3d9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1262,8 +1262,12 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增Owncast自托管直播平台的安装及使用, ------------------------ 2025-08-14 v4.0.8 -应用市场增加快速启动方式 命令行输入 k app 即可启动应用市场 -应用市场增加应用编号快速启动 k app 13 就是13号应用启动,也可以输入应用名称启动 k app dpanel -支持远程命令安装和管理应用,bash <(curl -sL kejilion.sh) app moontv | bash <(curl -sL kejilion.sh) app 1panel +应用市场增加快速启动方式 命令行输入 k app 即可启动应用市场。 +应用市场增加应用编号快速启动 k app 13 就是13号应用启动,也可以输入应用名称启动 k app dpanel。 +支持远程命令安装和管理应用,bash <(curl -sL kejilion.sh) app moontv | bash <(curl -sL kejilion.sh) app 1panel。 +------------------------ +2025-08-18 v4.0.9 +应用市场增加全部应用数据备份和还原的功能。支持迁移到其他服务器的操作。 +-全部的应用备份还原不包含宝塔1panel等建站面板的数据。 ------------------------ From 73ad6520d60e3cabb7dabe5685528461d9f84640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:36:09 +0800 Subject: [PATCH 0069/1285] Update kejilion.sh --- cn/kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 698bd8d1d..9666c3c24 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10920,10 +10920,12 @@ while true; do docker_rum() { + read -e -p "设置${docker_name}的登录密钥(字母和数字组合): " app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=sk-${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10931,7 +10933,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app From 756a441c6ec636eb33846e20c6dba53c6c4597b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:37:09 +0800 Subject: [PATCH 0070/1285] Update kejilion.sh --- kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 024294583..185c38657 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10920,10 +10920,12 @@ while true; do docker_rum() { + read -e -p "设置${docker_name}的登录密钥(字母和数字组合): " app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=sk-${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10931,7 +10933,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app From 06c804d2e4028c0d210f0073069898601584f49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:40:06 +0800 Subject: [PATCH 0071/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 185c38657..b2343aedb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10920,12 +10920,12 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(字母和数字组合): " app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-${app_passwd} \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest From ecbee7dd45e3c76cf7dac185a87f5efa7f955969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:40:48 +0800 Subject: [PATCH 0072/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9666c3c24..0afa72fff 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10920,12 +10920,12 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(字母和数字组合): " app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-${app_passwd} \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest From abce72cd8aa52ab79c092373d8ca4921ebedeea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:43:42 +0800 Subject: [PATCH 0073/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 7e025c3d9..c12724914 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1269,5 +1269,6 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 2025-08-18 v4.0.9 应用市场增加全部应用数据备份和还原的功能。支持迁移到其他服务器的操作。 -全部的应用备份还原不包含宝塔1panel等建站面板的数据。 +应用市场gpt-load安装时修改成自定义登录密钥。 ------------------------ From c75872209af20f601a8941c558c24c0c9524dc07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:19:56 +0800 Subject: [PATCH 0074/1285] Update kejilion.sh --- cn/kejilion.sh | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0afa72fff..f3d69febb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8534,6 +8534,7 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11139,6 +11140,94 @@ while true; do ;; + + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) clear send_stats "全部应用备份" From 056791d6f2eda45d54ccec71997b2c285652fc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:20:46 +0800 Subject: [PATCH 0075/1285] Update kejilion.sh --- kejilion.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index b2343aedb..7a0d51a2a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8534,6 +8534,7 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11139,6 +11140,94 @@ while true; do ;; + + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) clear send_stats "全部应用备份" From a46cd2638506d95b5edf111a66170099c9806b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:23:03 +0800 Subject: [PATCH 0076/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c12724914..771ee19e2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1270,5 +1270,7 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场增加全部应用数据备份和还原的功能。支持迁移到其他服务器的操作。 -全部的应用备份还原不包含宝塔1panel等建站面板的数据。 应用市场gpt-load安装时修改成自定义登录密钥。 +应用市场新增FileCodeBox文件快递的安装及使用, +应用市场新增matrix去中心化聊天协议安装及使用, ------------------------ From 94820a6e6ce6c3ab385175acb45e0c9ef5a99506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:53:21 +0800 Subject: [PATCH 0077/1285] Update kejilion.sh --- cn/kejilion.sh | 55 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3d69febb..3f0050bdc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10610,32 +10610,53 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" - read -e -p "设置MoonTV的登录密码: " app_passwd + docker_app_install() { + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "应用已卸载" + } + + docker_app_plus ;; From bd18ecbf7c774657aa0bdbca0ca6a6a0630b0bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:54:54 +0800 Subject: [PATCH 0078/1285] Update kejilion.sh --- kejilion.sh | 55 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7a0d51a2a..be3f594b3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10610,32 +10610,53 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" - read -e -p "设置MoonTV的登录密码: " app_passwd + docker_app_install() { + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "应用已卸载" + } + + docker_app_plus ;; From 6522d67af33d5a4d936226c33a6edf3a85d1d591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:56:53 +0800 Subject: [PATCH 0079/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 771ee19e2..6d428e9ab 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1270,7 +1270,8 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场增加全部应用数据备份和还原的功能。支持迁移到其他服务器的操作。 -全部的应用备份还原不包含宝塔1panel等建站面板的数据。 应用市场gpt-load安装时修改成自定义登录密钥。 -应用市场新增FileCodeBox文件快递的安装及使用, -应用市场新增matrix去中心化聊天协议安装及使用, +应用市场新增FileCodeBox文件快递的安装及使用。 +应用市场新增matrix去中心化聊天协议安装及使用。 +应用市场修复moontv采用全新架构安装及使用。 ------------------------ From 5f4783833685fb0e6abd3037daed36fb092ade42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:59:28 +0800 Subject: [PATCH 0080/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 6d428e9ab..0cff0050a 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1272,6 +1272,6 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场gpt-load安装时修改成自定义登录密钥。 应用市场新增FileCodeBox文件快递的安装及使用。 应用市场新增matrix去中心化聊天协议安装及使用。 -应用市场修复moontv采用全新架构安装及使用。 +应用市场重构moontv,采用全新架构安装及使用。 ------------------------ From f6c7e121f4d1acbd20237a95ed29933cc48af311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:02:38 +0800 Subject: [PATCH 0081/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3f0050bdc..339018c55 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -8536,7 +8536,7 @@ while true; do echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" From 80631d408da802975ff85b755d4ac23c9ea81c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:03:09 +0800 Subject: [PATCH 0082/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 339018c55..e47269aa3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From f54859730ed696ca727f721d81d26e57d29c232a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:09:02 +0800 Subject: [PATCH 0083/1285] Update kejilion.sh --- cn/kejilion.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e47269aa3..bfe6ec681 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8690,7 +8690,8 @@ while true; do docker_rum() { - + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8699,8 +8700,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8714,8 +8715,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -9386,7 +9387,8 @@ while true; do docker_rum() { - + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9395,8 +9397,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9407,7 +9409,6 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } @@ -10726,8 +10727,8 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ From e14a3edbc9a2f7454e5bf234f8eda397ca87e1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:10:10 +0800 Subject: [PATCH 0084/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bfe6ec681..10b760959 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9414,8 +9414,8 @@ while true; do local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; From 479804bc485e9efebb1a83505a29cd4e46d469e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:10:48 +0800 Subject: [PATCH 0085/1285] Update kejilion.sh --- kejilion.sh | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index be3f594b3..cd18cc7b9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8536,7 +8536,7 @@ while true; do echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${color88}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8690,7 +8690,8 @@ while true; do docker_rum() { - + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8699,8 +8700,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8714,8 +8715,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -9386,7 +9387,8 @@ while true; do docker_rum() { - + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9395,8 +9397,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9407,14 +9409,13 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; @@ -10726,8 +10727,8 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ From 4c28aea09651ad0ff54112e2ccbb6f5ffa9f8b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:12:36 +0800 Subject: [PATCH 0086/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 0cff0050a..95851a40c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1273,5 +1273,6 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增FileCodeBox文件快递的安装及使用。 应用市场新增matrix去中心化聊天协议安装及使用。 应用市场重构moontv,采用全新架构安装及使用。 +应用市场Ubuntu等远程桌面程序允许自定义用户名和密码进行安装及使用。 ------------------------ From cdb73ad745b21196d20d314b225f1c80fdd88ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:24:57 +0800 Subject: [PATCH 0087/1285] Update kejilion.sh --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 10b760959..eb5f5db4c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10626,6 +10626,8 @@ while true; do docker_app_install() { read -e -p "设置登录用户名: " admin read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma + mkdir -p /home/docker/moontv mkdir -p /home/docker/moontv/config @@ -10636,7 +10638,7 @@ while true; do sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear From b4a3c9a1607cd85fc2b18a6a55e69661abe29cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:26:38 +0800 Subject: [PATCH 0088/1285] Update kejilion.sh --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index cd18cc7b9..e52a9539e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10626,6 +10626,8 @@ while true; do docker_app_install() { read -e -p "设置登录用户名: " admin read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma + mkdir -p /home/docker/moontv mkdir -p /home/docker/moontv/config @@ -10636,7 +10638,7 @@ while true; do sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear From ba842d73dd214426eaf623ead6c52099ef9ca7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:31:52 +0800 Subject: [PATCH 0089/1285] Update kejilion.sh --- cn/kejilion.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index eb5f5db4c..4a8bb24c6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.9" +sh_v="4.0.10" gl_hui='\e[37m' @@ -8536,6 +8536,8 @@ while true; do echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -11251,6 +11253,84 @@ while true; do + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear From a550ee3be7664767b4b0b490c230020fdb39fa64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:32:22 +0800 Subject: [PATCH 0090/1285] Update kejilion.sh --- kejilion.sh | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index e52a9539e..ff076970f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.9" +sh_v="4.0.10" gl_hui='\e[37m' @@ -8536,6 +8536,8 @@ while true; do echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -11251,6 +11253,84 @@ while true; do + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear From a472c0f133104572f44ce6ddea557c90a9a040a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:34:21 +0800 Subject: [PATCH 0091/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 95851a40c..097b5ba1d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1275,4 +1275,7 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场重构moontv,采用全新架构安装及使用。 应用市场Ubuntu等远程桌面程序允许自定义用户名和密码进行安装及使用。 ------------------------ - +2025-08-21 v4.0.10 +应用市场新增gitea私有代码仓库的安装及使用, +应用市场新增filebrowser文件管理器的安装及使用, +------------------------ From 5227c710788de247e218cd600d76e1f0e68a6136 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 11:25:23 +0000 Subject: [PATCH 0092/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-21=2011:25:23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 342 +++- jp/kejilion.sh | 4746 +++++++++++++++++++++++++----------------------- kr/kejilion.sh | 4690 +++++++++++++++++++++++++---------------------- tw/kejilion.sh | 334 +++- 4 files changed, 5584 insertions(+), 4528 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index cd73886fb..fef2761c3 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.10" gl_hui='\e[37m' @@ -2121,7 +2121,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -7924,7 +7924,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8497,7 +8497,7 @@ while true; do echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed Speed Test Tool" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" @@ -8534,6 +8534,11 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tools" echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" echo -e "${gl_kjlan}87. ${color87}SyncTV movie watching artifact${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser File Manager" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8687,7 +8692,8 @@ while true; do docker_rum() { - + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8696,8 +8702,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8711,8 +8717,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -9383,7 +9389,8 @@ while true; do docker_rum() { - + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9392,8 +9399,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9404,14 +9411,13 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; @@ -10607,32 +10613,55 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" + + docker_app_install() { + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password + read -e -p "Enter the authorization code:" shouquanma + + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv + + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } - read -e -p "Set the MoonTV login password:" app_passwd - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "The app has been uninstalled" } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker_app_plus ;; @@ -10702,8 +10731,8 @@ while true; do docker_rum() { - read -e -p "set up${docker_name}Login username:" app_use - read -e -p "set up${docker_name}Login password:" app_passwd + read -e -p "Set login username:" app_use + read -e -p "Set login password:" app_passwd docker run -d \ --name xunlei \ @@ -10918,10 +10947,12 @@ while true; do docker_rum() { + read -e -p "set up${docker_name}The login key (sk-staring letters and numbers combinations) such as: sk-159kejilionyyds163:" app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10929,7 +10960,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app @@ -11136,6 +11167,239 @@ while true; do ;; + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "Create an initial user or administrator. Please set the following username and password and whether you are an administrator." + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) + clear + send_stats "All applications backup" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "The backup file has been created: /$backup_filename" + read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice + case "$choice" in + [Yy]) + read -e -p "Please enter the remote server IP:" remote_ip + if [ -z "$remote_ip" ]; then + echo "Error: Please enter the remote server IP." + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "The file has been transferred to the remote server/root directory." + else + echo "The file to be transferred was not found." + fi + break + ;; + *) + echo "Note: Currently, the backup only includes docker projects, and does not include data backup of website building panels such as Pagoda and 1panel." + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "All applications restore" + echo "Available app backups" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # If the user does not enter the file name, use the latest compressed package + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." + else + echo "No compression package was found." + fi + + ;; + 0) kejilion ;; @@ -11832,7 +12096,7 @@ EOF echo "3. Tokyo time in Japan 4. Seoul time in South Korea" echo "5. Singapore time 6. Kolkata time in India" echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Time in Bangkok, Thailand" + echo "9. Bangkok Time, Thailand" echo "------------------------" echo "Europe" echo "11. London time in the UK 12. Paris time in France" @@ -12058,7 +12322,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -12495,7 +12759,7 @@ EOF echo "Privacy and Security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index b449d9342..acf73106d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.10" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# コマンドを実行する関数を定義します run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! +# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 +# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# ユーザーに条件に同意するように促します UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" + echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" + echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "上記の条件に同意しますか? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "ライセンスの同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "許可の拒否" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}インストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" + echo "現在利用可能なスペース:$((available_space_mb/1024))g" + echo "最小需要スペース:${required_gb}G" + echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" + send_stats "ディスクスペースが不十分です" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}アンインストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# さまざまな分布に適したUniversal SystemCTL関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# サービスを再起動します restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1サービスは再開されました。" else - echo "错误:重启 $1 服务失败。" + echo "エラー:再起動$1サービスに失敗しました。" fi } -# 启动服务 +# サービスを開始します start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1サービスが開始されました。" else - echo "错误:启动 $1 服务失败。" + echo "エラー:開始$1サービスに失敗しました。" fi } -# 停止服务 +# サービスを停止します stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1サービスは停止しました。" else - echo "错误:停止 $1 服务失败。" + echo "エラー:停止します$1サービスに失敗しました。" fi } -# 查看服务状态 +# サービスのステータスを確認します status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1サービスステータスが表示されます。" else - echo "错误:无法显示 $1 服务状态。" + echo "エラー:表示できません$1サービスステータス。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME電源を入れるように設定します。" } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}操作が完了しました${gl_bai}" + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "Dockerコンテナ管理" + echo "Dockerコンテナリスト" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "コンテナ操作" echo "------------------------" - echo "1. 创建新的容器" + echo "1.新しいコンテナを作成します" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" + echo "3.指定された容器を停止します7。すべての容器を停止します" + echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" + echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11。指定されたコンテナを入力します12。コンテナログを表示します" + echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "新しいコンテナを作成します" + read -e -p "作成コマンドを入力してください:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を停止します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定されたコンテナを削除します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を再起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "すべてのコンテナを起動します" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "すべてのコンテナを停止します" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "すべてのコンテナを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "すべてのコンテナを再起動します" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "コンテナを入力します" + read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "コンテナログを表示します" + read -e -p "コンテナ名を入力してください:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "コンテナネットワークを表示します" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "コンテナの占有を表示します" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスを許可します" + read -e -p "コンテナ名を入力してください:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスをブロックします" + read -e -p "コンテナ名を入力してください:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "Docker画像管理" + echo "Docker画像リスト" docker image ls echo "" - echo "镜像操作" + echo "ミラー操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1.指定された画像を取得する3。指定された画像を削除します" + echo "2。指定された画像4を更新します。すべての画像を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "鏡を引っ張ります" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}画像を取得する:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "画像を更新します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}更新された画像:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "ミラーを削除します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "すべての画像を削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "サポートされていない分布:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "オペレーティングシステムを決定することはできません。" return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 現在の構成には既にIPv6設定があるかどうかを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 構成を更新し、IPv6を有効にします if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 元の構成と新しい構成を比較します if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" return fi - # 读取当前配置 + # 現在の構成を読み取ります local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 現在のIPv6ステータスを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 元の構成と新しい構成を比較します if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 既存のクロージングルールを削除します iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # オープンルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "ポートが開かれました$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "ポートが開かれました" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 既存のオープンルールを削除します iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 緊密なルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "ポートは閉じた$port" fi done - # 删除已存在的规则(如果有) + # 既存のルールを削除する(ある場合) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 最初に新しいルールを挿入します iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "ポートは閉じた" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 既存のブロッキングルールを削除します iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 許可ルールを追加します if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "IPをリリースしました$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "IPをリリースしました" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 既存の許可ルールを削除します iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # ブロッキングルールを追加します if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IPブロック$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IPブロック" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 防御DDOをオンにします iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDOS防御をオンにします" } -# 关闭DDoS防御 +# DDOS防御をオフにします disable_ddos_defense() { - # 关闭防御 DDoS + # 防御DDOをオフにします iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDOS防御をオフにします" } -# 管理国家IP规则的函数 +# 国家IPルールを管理する機能 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # IPSETが存在しない場合は作成します if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # iptablesでIPをブロックします iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "正常にブロックされました$country_codeIPアドレス" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 許可された国のIPSETを作成する(存在しない場合) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 删除现有的国家规则 + # 既存の国家ルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 指定された国のIPのみが許可されています iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "正常に許可されています$country_codeIPアドレス" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 国のiptablesルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # Ipsetを破壊します if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "正常に持ち上げられました$country_codeIPアドレスの制限" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "高度なファイアウォール管理" + send_stats "高度なファイアウォール管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "ファイアウォール管理" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1.指定されたポート2を開きます。指定されたポートを閉じます" + echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5。IPホワイトリスト6。IPブラックリスト" + echo "7.指定されたIPをクリアします" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. ping 12を許可します。Pingを無効にします" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" + echo "17.指定国でのIP制限をリリースします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "オープンポート番号を入力してください:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "指定されたポートを開きます" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "閉じたポート番号を入力してください:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "指定されたポートを閉じます" ;; 3) - # 开放所有端口 + # すべてのポートを開きます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "すべてのポートを開きます" ;; 4) - # 关闭所有端口 + # すべてのポートを閉じます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "すべてのポートを閉じます" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IPホワイトリスト + read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IPブラックリスト + read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 指定されたIPをクリアします + read -e -p "クリアされたIPを入力してください:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "指定されたIPをクリアします" ;; 11) - # 允许 PING + # pingを許可します iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "pingを許可します" ;; 12) - # 禁用 PING + # pingを無効にします iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "pingを無効にします" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "許可された国$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "国をブロックします$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "国をきれいにします$country_codeIP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 現在のシステムですべてのスワップパーティションを取得します local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 反復して、すべてのスワップパーティションを削除します for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfileが使用されなくなったことを確認してください swapoff /swapfile - # 删除旧的 /swapfile + # 古い /swapfileを削除します rm -f /swapfile - # 创建新的 swap 分区 + # 新しいスワップパーティションを作成します fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 仮想メモリを作成する必要があるかどうかを判断します [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginxバージョンを取得します local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # MySQLバージョンを取得します local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHPバージョンを取得します local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redisバージョンを取得します local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 必要なディレクトリとファイルを作成します cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.ymlファイルをダウンロードして置き換えます wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.ymlファイルに置き換えます sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP環境がインストールされています" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "更新タスクが更新されました" } @@ -1453,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}証明書ストレージパス${gl_bai}" + echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" + echo "サイト情報証明書の有効期限" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "ドメイン名証明書の成功したアプリケーション" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "ドメイン名証明書のアプリケーションは失敗しました" + echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" + echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" + echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" + echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" + echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" + echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" + echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" break_end clear - echo "请再次尝试部署 $webname" + echo "もう一度展開してみてください$webname" add_yuming install_ssltls certs_status @@ -1549,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "ドメイン名の再利用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1623,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" } @@ -1643,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "ログイン情報:" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "起動する$ldnmp_pods" } @@ -1657,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # ゾーン_idsを配列に変換します ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # キャッシュをクリーニングするかどうかをユーザーに促します + read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + read -e -p "CFユーザ​​ー名を入力してください:" EMAIL + read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "ゾーン_IDのキャッシュのクリア:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "キャッシュクリアリクエストが送信されました。" } web_cache() { - send_stats "清理站点缓存" + send_stats "サイトキャッシュをクリーンアップします" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "サイトデータを削除します" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "ドメイン名の削除:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # ドメイン名をデータベース名に変換します dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します + echo "データベースの削除:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # モードパラメーターに従ってWAFをオンまたはオフにすることにしました if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # WAFを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotliをオンにする:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotliを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # ZSTDをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # ZSTDを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi @@ -1990,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP環境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" + echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21。CloudFlareモード22。5秒シールドの高負荷" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31。WAF32をオンにしてください。WAFをオフにします" + echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; 11) @@ -2097,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "CloudFlareモード" + echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "5秒シールドでの高負荷" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が自動的に5秒間オフになります。${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CFパラメーターを取得します:" + echo -e "CFの背景の右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" + echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID cd ~ install jq bc @@ -2147,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "高負荷自動シールドオープニングスクリプトが追加されました" else - echo "自动开盾脚本已存在,无需添加" + echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "サイトWAFが有効になっています" + send_stats "サイトWAFが有効になっています" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "サイトWAFは閉鎖されています" + send_stats "サイトWAFは閉鎖されています" ;; 33) @@ -2189,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 現在のworker_processesの設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 値に応じてモード情報を設定します if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Brotliが有効であり、コメントされていないかどうかを確認してください if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # GZIPが有効になっており、コメントされていないかどうかを確認してください if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP環境を最適化します" + echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1。標準モード2。高性能モード(推奨2H4g以上)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" + echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" + echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "サイト標準モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境は標準モードに設定されています" ;; 2) - send_stats "站点高性能模式" + send_stats "サイトの高性能モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP環境は、高性能モードに設定されています" ;; 3) @@ -2386,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker = "$ {gl_lv} $ {gl_bai}インストール" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" # fi # } @@ -2396,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "アクセスアドレス:" ip_address @@ -2434,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # コンテナの作成時間と画像名を取得します local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # ミラーウェアハウスとタグを抽出します local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # デフォルトのラベルは最新です [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 公式画像のサポートを追加します [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Docker Hub APIから画像公開時間を取得します local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 買収の時間を確認します if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # タイムスタンプを比較します if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2535,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2599,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:block_host_port <ポート番号> <承認IP>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 確立された関連接続および関連する接続のトラフィックを許可します if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2658,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2747,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "インストール$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "更新します$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "アプリはアンインストールされています" + send_stats "アンインストール$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# セッションが存在するかどうかを確認する関数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 存在しないセッション名が見つかるまでループします while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 新しいTMUXセッションを作成します tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "再起動" reboot ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -3127,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP環境を再度インストールできません" + echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" break_end linux_ldnmp fi @@ -3138,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP環境をインストールします" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Nginx環境をインストールします" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "Nginxがインストールされています" +echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "LDNMP環境を最初にインストールしてください" ldnmp_install_all fi @@ -3191,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "最初にNGINX環境をインストールしてください" nginx_install_all fi @@ -3202,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webnameインストール情報は次のとおりです。" } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" } @@ -3223,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "発生防止ポートを入力してください。" port fi nginx_install_status install_ssltls @@ -3297,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3357,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMPサイト管理" + echo "LDNMP環境" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "サイト:${output}証明書の有効期限" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "データベース:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "サイトディレクトリ" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" + echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" + echo "5.アクセスログを表示6。エラーログを表示します" + echo "7.グローバル構成の編集8。サイト構成の編集" + echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20.指定されたサイトデータを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "ドメイン名証明書を申請します" + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "サイトドメイン名を変更します" + echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" + read -e -p "古いドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status - # mysql替换 + # MySQLの交換 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # ウェブサイトディレクトリの交換 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "関連するサイトを作成します" + echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" + read -e -p "既存のドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status @@ -3476,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "アクセスログを表示します" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "エラーログを表示します" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "グローバル構成を編集します" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "サイト構成を編集します" + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "サイトデータを表示します" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3540,16 +3540,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" + echo "公式ウェブサイトの紹介:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1。インストール2。管理3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}インストール" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}控制" + send_stats "${panelname}コントロール" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}アンインストール" ;; *) break @@ -3615,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRPサーバーをインストールします" + # ランダムポートと資格情報を生成します local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 出力生成情報 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "クライアントの展開に必要なパラメーター" + echo "サービスIP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRPパネル情報" + echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" + echo "FRPパネルのユーザー名:$dashboard_user" + echo "FRPパネルパスワード:$dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRPクライアントをインストールします" + read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr + read -e -p "外部ネットワークドッキングトークンを入力してください:" token echo mkdir -p /home/frp @@ -3679,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRPイントラネットサービスを追加します" + # ユーザーにサービス名と転送情報を入力するように促します + read -e -p "サービス名を入力してください:" service_name + read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "イントラネットポートを入力してください:" local_port + read -e -p "外部ネットワークポートを入力してください:" remote_port - # 将用户输入写入配置文件 + # ユーザー入力を構成ファイルに書き込みます cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 出力生成情報 + echo "仕える$service_nameFRPC.TOMLに正常に追加されました" docker restart frpc @@ -3711,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRPイントラネットサービスを削除します" + # ユーザーに削除する必要があるサービス名を入力するように促します + read -e -p "削除する必要があるサービス名を入力してください:" service_name + # SEDを使用して、サービスとその関連構成を削除します sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "仕える$service_nameFRPC.TOMLから削除されました" docker restart frpc @@ -3726,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # ヘッダーを印刷します printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3756,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 現在のサービス名を更新します if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 前の値をクリアします local_ip="" local_port="" remote_port="" @@ -3789,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 最後のサービスの情報を印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRPサーバーポートを取得します get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# アクセスアドレスを生成します generate_access_urls() { - # 首先获取所有端口 + # 最初にすべてのポートを取得します get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056以外のポートがあるかどうかを確認してください local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 有効なポートがある場合にのみタイトルとコンテンツを表示します if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRPサービス外部アクセスアドレス:" - # 处理 IPv4 地址 + # IPv4アドレスを処理します for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # IPv6アドレスを処理する(存在する場合) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRPサーバー" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRPサーバー$check_frp $update_status" + echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00。サービスのステータスを更新します0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3902,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "FRPサーバーがインストールされています" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "FRPサーバーが更新されました" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "ドメイン名アクセスへの逆イントラネット侵入サービス" + send_stats "FRP外部ドメイン名へのアクセス" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IPアクセスを許可します" + read -e -p "リリースするポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IPアクセスをブロックします" + echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" + read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRPサービスステータスを更新します" + echo "FRPサービスステータスは更新されました" ;; *) @@ -3966,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRPクライアント" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRPクライアント$check_frp $update_status" + echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3999,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "FRPクライアントがインストールされています" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "FRPクライアントが更新されました" ;; 3) @@ -4020,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 4) @@ -4066,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "YT-DLPダウンロードツール" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" + echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "ダウンロードされたビデオリスト:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" + echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "オプション番号を入力してください:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "YT-DLPのインストール..." + echo "YT-DLPのインストール..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlpを更新..." + echo "yt-dlpを更新..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlpのアンインストール..." + echo "yt-dlpのアンインストール..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "単一のビデオダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; 6) - send_stats "批量视频下载" + send_stats "バッチビデオのダウンロード" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "バッチダウンロードを開始します..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "カスタムビデオのダウンロード" + read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "実行が完了したら、キーを押して続行します..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3ダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "ビデオを削除します" + read -e -p "削除ビデオの名前を入力してください:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# DPKG割り込みの問題を修正します fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}システムの更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi } @@ -4231,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." apk cache clean - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APKキャッシュを削除してください..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "未使用の依存関係をクリーンアップ..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." pkg clean -y - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi return @@ -4340,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNSを最適化します" while true; do clear - echo "优化DNS地址" + echo "DNSアドレスを最適化します" echo "------------------------" - echo "当前DNS地址" + echo "現在のDNSアドレス" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1。外国DNS最適化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2。国内のDNS最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3。DNS構成を手動で編集します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "外国のDNS最適化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "国内のDNS最適化" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS構成を手動で編集します" ;; *) break @@ -4403,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # PasswordAuthenticationが見つかった場合は、はいに設定します if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 発見された場合、pubkeyauthenticationはyesに設定されています if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # バックアップSSH構成ファイル cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSHポートは次のように変更されています。$new_port" sleep 1 @@ -4459,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" return 1 fi @@ -4499,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } @@ -4508,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "ルートパスワードを設定します" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "システムを再インストールします" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "Debian 13を再インストールします" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "Debian 12を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "Debian 11を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "Debian 10を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "Ubuntu 24.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "Ubuntu 22.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Ubuntu 20.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "Ubuntu 18.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Rockylinux10を再インストールします" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Rockylinux9を再インストールします" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "alma10を再インストールします" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "alma9を再インストールします" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Oracle10を再インストールします" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Oracle9を再インストールします" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Fedora42を再インストールします" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Fedora41を再インストールします" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "CENTOS10を再インストールします" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "CENTOS9を再インストールします" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "アルパインを再インストールします" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "アーチを再インストールします" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "Kaliを再インストールします" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Openeulerを再インストールします" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "OpenSuseを再インストールします" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "飛ぶ牛をリロードします" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Windows11を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Windows 10を再インストールします" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows 7を再インストールします" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Windows Server 22を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Windows Server 19を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Windows Server 16を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Windows11アームを再インストールします" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "BBRV3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "XanmodのBBRV3カーネルをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) @@ -4884,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "Xanmodカーネルが更新されました。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" server_reboot ;; @@ -4916,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3加速度をセットアップします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "Debian/Ubuntuのみをサポートします" + echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -4930,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "オペレーティングシステムの種類を決定できません" break_end linux_Settings fi @@ -4946,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4957,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -4976,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Elrepo GPG公開キーをインポートします + echo "Elrepo GPG公開キーをインポートしてください..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # システムバージョンを検出します local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # サポートされているオペレーティングシステムで実行されていることを確認してください if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "サポートされていないオペレーティングシステム:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 検出されたオペレーティングシステム情報を印刷します + echo "検出されたオペレーティングシステム:$os_name $os_version" + # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "サポートされていないシステムバージョン:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします + echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" server_reboot } @@ -5017,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "レッドハットカーネル管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "Elrepo Kernelをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hatカーネルを更新します" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" + send_stats "レッドハットカーネルをアンインストールします" server_reboot ;; @@ -5060,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" + echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hatカーネルをアップグレードします" server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -5090,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "スキャンするディレクトリを指定してください。" return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" - # 构建 mount 参数 + # マウントパラメーターを構築します local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # CLAMSCANコマンドパラメーターを作成します local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Dockerコマンドを実行します docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" } @@ -5143,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "ウイルススキャン管理" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "クラマブウイルススキャンツール" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" + echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "フルディスクスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "重要なディレクトリスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "カスタムディレクトリスキャン" + read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# 高性能モード最適化関数 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# イコライゼーションモード最適化関数 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# デフォルト設定関数を復元します restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# ウェブサイトの構築最適化機能 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linuxカーネルチューニング管理" + echo "Linuxシステムにおけるカーネルパラメーターの最適化" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" + echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" + echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" + echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" + echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" + echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" + echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "高性能モードの最適化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "バランスモードの最適化" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "ウェブサイトの最適化モデル" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "ライブストリーミング最適化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "ゲームサーバーの最適化" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "デフォルト設定を復元します" ;; *) break @@ -5446,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end @@ -5455,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "サポートされていないシステム:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "サポートされていないシステム、システムタイプは認識できません。" break_end fi } @@ -5475,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "システム言語を切り替えます" while true; do clear - echo "当前系统语言: $LANG" + echo "現在のシステム言語:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1。英語2。簡素化された中国語3。伝統的な中国語" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "英語に切り替えます" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "簡素化された中国人に切り替えます" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "伝統的な中国人に切り替えます" ;; *) break @@ -5519,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" hash -r break_end @@ -5530,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "コマンドラインの美化ツール" while true; do clear - echo "命令行美化工具" + echo "コマンドラインの美化ツール" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5590,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "システムリサイクルステーション" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "現在のリサイクルビン${trash_status}" + echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" + echo "3。コンテンツを復元4。リサイクルビンをクリアします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5623,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" sleep 2 ;; 2) @@ -5631,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "復元するにはファイル名を入力してください。" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restoreホームディレクトリに復元されました。" else - echo "文件不存在。" + echo "ファイルは存在しません。" fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "リサイクルビンがクリアされました。" fi ;; *) @@ -5658,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# バックアップを作成します create_backup() { - send_stats "创建备份" + send_stats "バックアップを作成します" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # ユーザーにバックアップディレクトリを入力するように求めます + echo "バックアップ例を作成します:" + echo "- 単一のディレクトリをバックアップします: /var /www" + echo "- バックアップ複数のディレクトリ: /etc /home /var /log" + echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" + read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input - # 如果用户没有输入目录,则使用默认目录 + # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # ユーザーが入力したディレクトリをスペースごとに配列に分離します IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # バックアップファイルプレフィックスを生成します local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # ディレクトリ名を抽出し、スラッシュを削除します dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 最後のアンダースコアを削除します local PREFIX=${PREFIX%_} - # 生成备份文件名 + # バックアップファイル名を生成します local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # ユーザーが選択したディレクトリを印刷します + echo "選択したバックアップディレクトリは次のとおりです。" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # バックアップを作成します + echo "バックアップを作成します$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # コマンドが成功しているかどうかを確認してください if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "バックアップの作成に失敗しました!" exit 1 fi } -# 恢复备份 +# バックアップを復元します restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "バックアップを復元します" + # 復元するバックアップを選択します + read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "バックアップの回復$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "バックアップと復元を正常に!" else - echo "备份恢复失败!" + echo "バックアップリカバリに失敗しました!" exit 1 fi } -# 列出备份 +# バックアップをリストします list_backups() { - echo "可用的备份:" + echo "利用可能なバックアップ:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# バックアップを削除します delete_backup() { - send_stats "删除备份" + send_stats "バックアップを削除します" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - # 删除备份 + # バックアップを削除します rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "バックアップは正常に削除されました!" else - echo "备份删除失败!" + echo "バックアップの削除が失敗しました!" exit 1 fi } -# 备份主菜单 +# バックアップメインメニュー linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "システムバックアップ機能" + echo "システムバックアップ機能" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -5806,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# 接続リストを表示します list_connections() { - echo "已保存的连接:" + echo "接続の保存:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 新しい接続を追加します add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "新しい接続を追加します" + echo "新しい接続を作成する例:" + echo "- 接続名:my_server" + echo "- IPアドレス:192.168.1.100" + echo "- ユーザー名:root" + echo "- ポート:22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "接続名を入力してください:" name + read -e -p "IPアドレスを入力してください:" ip + read -e -p "ユーザー名(デフォルト:root)を入力してください:" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "ポート番号を入力してください(デフォルト:22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "選択(1/2)を入力してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "接続が保存されます!" } -# 删除连接 +# 接続を削除します delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "接続を削除します" + read -e -p "削除するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続​​は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 接続がキーファイルを使用している場合、キーファイルを削除します if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "接続が削除されました!" } -# 使用连接 +# 接続を使用します use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "接続を使用します" + read -e -p "使用するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続​​は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "接続$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "接続に失敗しました!以下を確認してください。" + echo "1。キーファイルパスは正しいですか?$password_or_key" + echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" + echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" fi else - # 使用密码连接 + # パスワードで接続します if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "接続に失敗しました!以下を確認してください。" + echo "1.ユーザー名とパスワードが正しいかどうか。" + echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" + echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSHリモート接続ツール" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSHリモート接続ツール" + echo "SSHを介して他のLinuxシステムに接続できます" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac done } @@ -5988,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 利用可能なハードディスクパーティションをリストします list_partitions() { - echo "可用的硬盘分区:" + echo "利用可能なハードディスクパーティション:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# パーティションをマウントします mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをマウントします" + read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "パーティションはすでに取り付けられています!" return fi - # 创建挂载点 + # マウントポイントを作成します MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # パーティションをマウントします mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "パーティションマウントに正常に:$MOUNT_POINT" else - echo "分区挂载失败!" + echo "パーティションマウントは失敗しました!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# パーティションをアンインストールします unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをアンインストールします" + read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "パーティションはマウントされていません!" return fi - # 卸载分区 + # パーティションをアンインストールします umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "パーティションのアンインストールに正常に:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "パーティションのアンインストールに失敗しました!" fi } -# 列出已挂载的分区 +# マウントされたパーティションをリストします list_mounted_partitions() { - echo "已挂载的分区:" + echo "マウントされたパーティション:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# フォーマットパーティション format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "フォーマットパーティション" + read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "パーティションがマウントされました。最初にアンインストールしてください!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # ファイルシステムタイプを選択します + echo "ファイルシステムタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "選択を入力してください:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "無効な選択!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # フォーマットを確認します + read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "操作はキャンセルされました。" return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # フォーマットパーティション + echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "パーティション形式は成功しました!" else - echo "分区格式化失败!" + echo "パーティションのフォーマットが失敗しました!" fi } -# 检查分区状态 +# パーティションステータスを確認します check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "パーティションステータスを確認します" + read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # パーティションステータスを確認します + echo "パーティション /dev /$PARTITION状態:" fsck "/dev/$PARTITION" } -# 主菜单 +# メインメニュー disk_manager() { - send_stats "硬盘管理功能" + send_stats "ハードディスク管理機能" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "ハードディスクパーティション管理" + echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" + echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } -# 显示任务列表 +# タスクリストを表示します list_tasks() { - echo "已保存的同步任务:" + echo "保存された同期タスク:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 新しいタスクを追加します add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "新しい同期タスクを追加します" + echo "新しい同期タスクを作成する例:" + echo "- タスク名:backup_www" + echo "- ローカルディレクトリ: /var /www" + echo "- リモートアドレス:user@192.168.1.100" + echo "- リモートディレクトリ: /バックアップ /www" + echo "- ポート番号(デフォルト22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "タスク名を入力してください:" name + read -e -p "ローカルディレクトリを入力してください:" local_path + read -e -p "リモートディレクトリを入力してください:" remote_path + read -e -p "リモートユーザー@IPを入力してください:" remote + read -e -p "SSHポートを入力してください(デフォルト22):" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "(1/2)を選択してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "無効なキーコンテンツ!" return fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "同期モードを選択してください:" + echo "1。標準モード(-AVZ)" + echo "2。ターゲットファイル(-avz - delete)を削除します" + read -e -p "(1/2)を選択してください:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "タスクが節約されました!" } -# 删除任务 +# タスクを削除します delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "エラー:対応するタスクは見つかりませんでした。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # タスクがキーファイルを使用している場合、キーファイルを削除します if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "削除されたタスク!" } run_task() { - send_stats "执行同步任务" + send_stats "同期タスクを実行します" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # パラメーターを分析します local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 着信タスク番号がない場合は、ユーザーに入力するように促します if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "実行するタスク番号を入力してください:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "エラー:タスクは見つかりませんでした!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH接続の共通パラメーターを追加します local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "エラー:キーファイルが存在しません:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." chmod 600 "$password_or_key" fi @@ -6330,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "同期は完了です!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "同期は失敗しました!以下を確認してください。" + echo "1。ネットワーク接続は正常ですか?" + echo "2。リモートホストにアクセスできますか?" + echo "3。認証情報は正しいですか?" + echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" fi } -# 创建定时任务 +# 時限タスクを作成します schedule_task() { - send_stats "添加同步定时任务" + send_stats "同期タイミングタスクを追加します" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "定期的に同期するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "時限実行間隔を選択してください:" + echo "1)1時間に1回実行します" + echo "2)1日1回実行します" + echo "3)週に1回実行します" + read -e -p "オプションを入力してください(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "エラー:有効なオプションを入力してください!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 同じタスクがすでに存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "エラー:このタスクのタイミング同期はすでに存在しています!" return fi - # 创建到用户的 crontab + # ユーザーにクロンタブを作成します (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "タイミングタスクが作成されました。$cron_job" } -# 查看定时任务 +# スケジュールされたタスクを表示します view_tasks() { - echo "当前的定时任务:" + echo "現在のタイミングタスク:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# タイミングタスクを削除します delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タイミングタスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "削除されたタスク番号$numタイミングタスク" } -# 任务管理主菜单 +# タスク管理メインメニュー rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "RSYNCリモート同期ツール" + echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1.新しいタスクを作成します2。タスクを削除します" + echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" + echo "5.タイミングタスクを作成6.タイミングタスクを削除します" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -6448,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "システム情報クエリ" ip_address @@ -6498,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "システム情報クエリ" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" + echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" + echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" + echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" + echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" + echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" echo @@ -6545,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats「基本ツール」 + echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" + echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" + echo -e "${gl_kjlan}7. ${gl_bai}zip zip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" + echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" + echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" + echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" + echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" + echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" curl --help - send_stats "安装curl" + send_stats "カールをインストールします" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" wget --help - send_stats "安装wget" + send_stats "WGETをインストールします" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" sudo --help - send_stats "安装sudo" + send_stats "sudoをインストールします" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" socat -h - send_stats "安装socat" + send_stats "SOCATをインストールします" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "HTOPをインストールします" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "IFTOPをインストールします" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" unzip - send_stats "安装unzip" + send_stats "unzipをインストールします" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tar --help - send_stats "安装tar" + send_stats "タールをインストールします" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tmux --help - send_stats "安装tmux" + send_stats "tmuxをインストールします" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "ffmpegをインストールします" ;; 11) @@ -6657,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "BTOPをインストールします" ;; 12) clear @@ -6666,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "レンジャーをインストールします" ;; 13) clear @@ -6675,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "NCDUをインストールします" ;; 14) clear @@ -6684,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "FZFをインストールします" ;; 15) clear @@ -6693,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "VIMをインストールします" ;; 16) clear @@ -6702,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "ナノをインストールします" ;; @@ -6713,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "gitをインストールします" ;; 21) @@ -6721,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrixをインストールします" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "SLをインストールします" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "バステットをインストールします" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "nsnakeをインストールします" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Ninvadersをインストールします" ;; 31) clear - send_stats "全部安装" + send_stats "すべてをインストールします" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "すべてをアンインストールします" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname install $installname - send_stats "安装指定软件" + send_stats "指定されたソフトウェアをインストールします" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename remove $removename - send_stats "卸载指定软件" + send_stats "指定されたソフトウェアをアンインストールします" ;; 0) @@ -6789,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -6803,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "AlpineはBBR3を有効にします" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6854,37 +6854,37 @@ linux_docker() { while true; do clear - # send_stats "docker管理" + # send_stats「Docker Management」 echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" + echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" + echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Docker環境をインストールします" install_add_docker ;; @@ -6895,22 +6895,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "Dockerグローバルステータス" + echo "Dockerバージョン" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6925,8 +6925,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "Dockerネットワーク管理" + echo "Dockerネットワークリスト" echo "------------------------------------------------------------" docker network ls echo "" @@ -6950,36 +6950,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "ネットワーク操作" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1.ネットワークを作成します" + echo "2。インターネットに参加してください" + echo "3。ネットワークを終了します" + echo "4.ネットワークを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "ネットワークを作成します" + read -e -p "新しいネットワーク名を設定します:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "ネットワーク名に参加してください:" dockernetwork + read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "出口ネットワーク名:" dockernetwork + read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6988,8 +6988,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "ネットワークを削除します" + read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork docker network rm $dockernetwork ;; @@ -7003,29 +7003,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "Dockerボリューム管理" + echo "Dockerボリュームリスト" docker volume ls echo "" - echo "卷操作" + echo "ボリューム操作" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1.新しいボリュームを作成します" + echo "2。指定されたボリュームを削除します" + echo "3.すべてのボリュームを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "新しいボリュームを作成します" + read -e -p "新しいボリューム名を設定します:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7034,7 +7034,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "すべてのボリュームを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7043,7 +7043,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7056,7 +7056,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "Dockerクリーニング" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7065,13 +7065,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "Dockerソース" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7084,19 +7084,19 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker V6が開いています" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker V6レベル" docker_ipv6_off ;; 20) clear - send_stats "Docker卸载" + send_stats "Dockerアンインストール" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7108,7 +7108,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7117,7 +7117,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7134,151 +7134,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats「テストスクリプトコレクション」 + echo -e "テストスクリプトコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" + echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" + echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" + echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}ネットワーク速度測定" + echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" + echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" + echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" + echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" + echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" + echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" + echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" + echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}包括的なテスト" + echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "CHATGPTはステータス検出のロックを解除します" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "リージョンストリーミングメディアのロック解除テスト" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "YeahWUストリーミングメディアのロック解除検出" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "XYKT_IP品質の身体検査スクリプト" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "MTR_TRACE 3ネットワークリターンラインテスト" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "SuperSpeed Three-Net速度測定" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace高速バックホールテストスクリプト" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" + echo "参照できるIPのリスト" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "北京テレコム:219.141.136.12" + echo "北京ユニコム:202.106.50.1" + echo "北京モバイル:221.179.155.161" + echo "上海通信:202.96.209.133" + echo "上海ユニコム:210.22.97.1" + echo "上海モバイル:211.136.112.200" + echo "広州通信:58.60.188.222" + echo "広州ユニコム:210.21.196.6" + echo "広州モバイル:120.196.165.24" + echo "成都通信:61.139.2.69" + echo "成都ユニコム:119.6.6.6" + echo "成都モバイル:211.137.96.205" + echo "Hunan Telecom:36.111.200.100" + echo "Hunan Unicom:42.48.16.100" + echo "Hunan Mobile:39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "指定されたIPを入力してください:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "Ludashi2020 3ネットワークラインテスト" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "I-ABC多機能速度テストスクリプト" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "ネットワーク品質のテストスクリプト" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "YABSパフォーマンステスト" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "ベンチパフォーマンステスト" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "SpiritySDX Fusion Monster Review" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7288,7 +7288,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7304,51 +7304,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud Scriptコレクション" + echo -e "Oracle Cloud Scriptコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" + echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" + echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" + echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" + echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" + read -e -p "必ずインストールしますか? (y/n):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # デフォルト値を設定します local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 + read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # Dockerコンテナを実行します docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7356,14 +7356,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloudインストールアクティブスクリプト" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7371,20 +7371,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" ;; 3) clear - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7396,28 +7396,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "再インストールされたパスワードを入力してください:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud再インストールシステムスクリプト" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "この機能は開発段階にあるので、お楽しみに!" ;; 5) clear @@ -7427,15 +7427,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7456,7 +7456,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" fi } @@ -7477,7 +7477,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" fi fi @@ -7505,31 +7505,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "ldnmp webサイトビルディング" + echo -e "${gl_huang}LDNMP Webサイトビルディング" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" + echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" + echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" + echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" + echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" + echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" + echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -7543,10 +7543,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # ディスクフォーラム webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7569,21 +7569,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:discuz_" ;; 4) clear - # 可道云桌面 + # ケダオクラウドデスクトップ webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7605,20 +7605,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "データベースアドレス:mysql" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" + echo "Redisホスト:Redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7644,24 +7644,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベースプレフィックス:mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "インストールが成功した後、バックグラウンドアドレスにログインします" echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 一本足のカウントカード webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7682,34 +7682,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "Redisアドレス:Redis" + echo "Redisパスワード:デフォルトで記入されていません" + echo "Redisポート:6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "ウェブサイトURL:https://$yuming" + echo "バックグラウンドログインパス: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "ユーザー名:admin" + echo "パスワード:管理者" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" + echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # フララムフォーラム webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7746,12 +7746,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:flarum_" + echo "管理者情報は自分で設定されます" ;; @@ -7759,8 +7759,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7784,11 +7784,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "データベースプレフィックス:typecho_" + echo "データベースアドレス:mysql" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" ;; @@ -7797,8 +7797,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7823,18 +7823,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:mysql" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7851,10 +7851,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7864,20 +7864,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7888,15 +7888,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" echo "-------------" - echo "已经安装的扩展" + echo "インストールされた拡張機能" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7906,25 +7906,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7934,10 +7934,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "データベースインポートテーブルデータ" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "データベースのインポートが完了しました" ;; *) echo @@ -7949,12 +7949,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "データベースアドレス:mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:$prefix" + echo "管理者ログイン情報は自分で設定されます" ;; @@ -7967,10 +7967,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "ジャンプドメイン名を入力してください:" reverseproxy nginx_install_status install_ssltls certs_status @@ -7992,7 +7992,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8003,11 +8003,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" + read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8027,8 +8027,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8050,8 +8050,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8068,8 +8068,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8102,8 +8102,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8120,10 +8120,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8133,12 +8133,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8163,21 +8163,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境バックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "バックアップファイルが作成されました: /home /$backup_filename" + read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "エラー:リモートサーバーIPを入力してください。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8185,9 +8185,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" else - echo "未找到要传送的文件。" + echo "転送されるファイルは見つかりませんでした。" fi break ;; @@ -8195,7 +8195,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac done @@ -8203,9 +8203,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "タイミングのリモートバックアップ" + read -e -p "リモートサーバーIPを入力してください:" useip + read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8215,18 +8215,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1。毎週のバックアップ2。毎日のバックアップ" + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "毎週のバックアップの曜日を選択します(0-6、0は日曜日を表します):" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8240,19 +8240,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP環境修復" + echo "利用可能なサイトバックアップ" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8262,7 +8262,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8271,7 +8271,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "圧縮パッケージは見つかりませんでした。" fi ;; @@ -8289,11 +8289,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP環境を更新します" + echo "LDNMP環境を更新します" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "コンポーネントの新しいバージョンを発見します" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8313,13 +8313,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" echo "------------------------" - echo "5. 更新完整环境" + echo "5。完全な環境を更新します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8328,7 +8328,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version local version=${version:-latest} cd /home/web/ @@ -8339,13 +8339,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8378,8 +8378,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 4) @@ -8390,15 +8390,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP環境を完全に更新します" cd /home/web/ docker compose down --rmi all @@ -8424,7 +8424,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP環境をアンインストールします" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8438,7 +8438,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -8448,7 +8448,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "無効な入力!" esac break_end @@ -8468,12 +8468,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "アプリケーション市場" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # ループで色を設定します for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8482,62 +8482,67 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" + echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" + echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" + echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" + echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" + echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" + echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" + echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" + echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" + echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" + echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" + echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" + echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" + echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" + echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" + echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" + echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" + echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" + echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" + echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice fi case $sub_choice in @@ -8687,7 +8692,8 @@ while true; do docker_rum() { - + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8696,8 +8702,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8711,8 +8717,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -8720,7 +8726,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "ネザを作る" local app_id="7" local docker_name="nezha-dashboard" @@ -8729,20 +8735,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezhaの監視$check_docker $update_status" + echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" + echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1。使用します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -8811,41 +8817,41 @@ while true; do clear echo -e "邮局服务 $check_docker $update_status" echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" - echo "端口检测" + echo "ポート検出" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "アクセスアドレス:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "これらのDNSレコードを最初に解析します" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8855,7 +8861,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" install jq @@ -8874,9 +8880,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" @@ -8899,9 +8905,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" ;; @@ -8912,7 +8918,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; *) @@ -8946,7 +8952,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -8956,7 +8962,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chatがインストールされています" check_docker_app_ip } @@ -8966,7 +8972,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9050,7 +9056,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -9064,7 +9070,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9209,7 +9215,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "サンダープールを構築します" local app_id="19" local docker_name=safeline-mgt @@ -9217,20 +9223,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "サンダープールサービス$check_docker" + echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -9240,7 +9246,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9253,7 +9259,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "サンダープールWAFパネルが更新されました" check_docker_app_ip ;; 3) @@ -9264,7 +9270,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9383,7 +9389,8 @@ while true; do docker_rum() { - + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9392,8 +9399,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9404,14 +9411,13 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; @@ -9672,7 +9678,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9725,7 +9731,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoyaファミリーバケツ" clear install_docker check_disk_space 1 @@ -9927,9 +9933,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "最初のユーザー名とパスワードは次のとおりです" } docker_app_update() { @@ -9947,7 +9953,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10034,7 +10040,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVEチキン" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10154,7 +10160,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10169,7 +10175,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10197,7 +10203,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10212,7 +10218,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10220,7 +10226,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10241,17 +10247,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "初期ユーザー名:admin" + echo "最初のパスワード:changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "アプリが更新されました" } @@ -10261,7 +10267,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10308,7 +10314,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10324,7 +10330,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10586,7 +10592,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretvログインパスワードを設定します。" app_passwd docker run -d \ --name libretv \ @@ -10607,32 +10613,55 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" - read -e -p "设置MoonTV的登录密码: " app_passwd + docker_app_install() { + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "承認コードを入力してください:" shouquanma + + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv + + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "アプリはアンインストールされています" + } + + docker_app_plus ;; @@ -10702,8 +10731,8 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "ログインユーザー名を設定します:" app_use + read -e -p "ログインパスワードの設定:" app_passwd docker run -d \ --name xunlei \ @@ -10800,11 +10829,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 公式のDocker-ComposeおよびEnvファイルをダウンロードします curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # ランダムキーとパスワードを生成します local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10813,17 +10842,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 管理者アカウント情報を追加します echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # コンテナを起動します docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10833,7 +10862,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 元の変数を保持します source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10850,7 +10879,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10900,7 +10929,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10918,10 +10947,12 @@ while true; do docker_rum() { + read -e -p "設定${docker_name}SK-159KEJILIONYYDS163などのログインキー(SKターニング文字と数字の組み合わせ):" app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10929,7 +10960,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app @@ -11020,7 +11051,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11033,7 +11064,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11136,6 +11167,239 @@ while true; do ;; + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "初期ユーザーまたは管理者を作成します。次のユーザー名とパスワード、およびあなたが管理者であるかどうかを設定してください。" + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) + clear + send_stats "すべてのアプリケーションバックアップ" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "バックアップファイルが作成されました: /$backup_filename" + read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + case "$choice" in + [Yy]) + read -e -p "リモートサーバーIPを入力してください:" remote_ip + if [ -z "$remote_ip" ]; then + echo "エラー:リモートサーバーIPを入力してください。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "ファイルは、リモートサーバー/ルートディレクトリに転送されました。" + else + echo "転送されるファイルは見つかりませんでした。" + fi + break + ;; + *) + echo "注:現在、バックアップにはDockerプロジェクトのみが含まれており、Pagodaや1PanelなどのWebサイトビルディングパネルのデータバックアップは含まれていません。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "すべてのアプリケーションが復元されます" + echo "利用可能なアプリバックアップ" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "アプリケーションデータが復元されました。指定されたアプリケーションメニューを手動で入力し、アプリケーションを更新してアプリケーションを復元してください。" + else + echo "圧縮パッケージは見つかりませんでした。" + fi + + ;; + 0) kejilion ;; @@ -11153,35 +11417,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "バックエンドワークスペース" + echo -e "バックエンドワークスペース" + echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "現在既存のワークスペースのリスト" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" + echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" + echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" + echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" + echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" + echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" + echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" + echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" + echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" + echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -11189,7 +11453,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -11197,63 +11461,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -11265,21 +11529,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH常駐モード" + echo -e "SSH常駐モード${tmux_sshd_status}" + echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1。2をオンにします。オフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "選択を入力してください:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "ワークスペースを開始します$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11295,29 +11559,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "カスタムワークスペース" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "バックグラウンドワークスペースにコマンドを注入します" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "ワークスペースを削除します" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -11342,54 +11606,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats「システムツール」 + echo -e "システムツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" + echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" + echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" + echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" + echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" + echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" + echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" + echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" + echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" + echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" + echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" + echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "ショートカットキーが設定されています" + send_stats "スクリプトのショートカットキーが設定されています" break_end linux_Settings done @@ -11397,28 +11661,28 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "ログインパスワードを設定します" + echo "ログインパスワードを設定します" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "ルートパスワードモード" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "Pyバージョン管理" + echo "Pythonバージョン管理" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" + echo "クエリの詳細:https://www.python.org/downloads/" echo "------------" read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v @@ -11457,7 +11721,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi @@ -11486,55 +11750,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "开放端口" + send_stats "オープンポート" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "すべてのポートが開いています" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSHポートを変更します" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 現在のSSHポート番号をお読みください local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 現在のSSHポート番号を印刷します + echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # ユーザーに新しいSSHポート番号を入力するように促します + read -e -p "新しいSSHポート番号を入力してください:" new_port - # 判断端口号是否在有效范围内 + # ポート番号が有効な範囲内にあるかどうかを判断します if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSHポート変更を終了します" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "ポート番号は無効です。1〜65535の数字を入力してください。" + send_stats "無効なSSHポート入力" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "入力が無効です。番号を入力してください。" + send_stats "無効なSSHポート入力" break_end fi done @@ -11553,8 +11817,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "新しいユーザーはルートを無効にします" + read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11569,49 +11833,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "操作が完了しました。" ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6の優先度を設定します" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6の優先度を設定します" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "優先ネットワークを選択します。" choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4の優先度に切り替えました" + send_stats "IPv4の優先度に切り替えました" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6の優先度に切り替えました" + send_stats "IPv6の優先度に切り替えました" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; *) @@ -11629,43 +11893,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "仮想メモリを設定します" while true; do clear - echo "设置虚拟内存" + echo "仮想メモリを設定します" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G仮想メモリが設定されています" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G仮想メモリが設定されています" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G仮想メモリが設定されています" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "カスタム仮想メモリが設定されています" ;; *) @@ -11678,8 +11942,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "ユーザー管理" + echo "ユーザーリスト" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11690,62 +11954,62 @@ EOF echo "" - echo "账户操作" + echo "アカウント操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3.最高の権限を与える4。最高の権限をキャンセルします" echo "------------------------" - echo "5. 删除账号" + echo "5.アカウントを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "操作が完了しました。" ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 新規ユーザーのsudo許可を付与します echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作已完成。" + echo "操作が完了しました。" ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "ユーザー名を入力してください:" username + # 新規ユーザーのsudo許可を付与します echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "ユーザー名を入力してください:" username + # sudoersファイルからユーザーのsudo許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "削除するにはユーザー名を入力してください:" username + # ユーザーとそのホームディレクトリを削除します userdel -r "$username" ;; @@ -11758,50 +12022,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "ユーザー情報ジェネレーター" + echo "ランダムユーザー名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "ランダムユーザー名$i: $username" done echo "" - echo "随机姓名" + echo "ランダム名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5つのランダムユーザー名を生成します for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "ランダムなユーザー名$i: $user_name" done echo "" - echo "随机UUID" + echo "ランダムuuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "ランダムuuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" - echo "32位随机密码" + echo "32ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" @@ -11809,46 +12073,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "タイムゾーンを変更します" while true; do clear - echo "系统时间信息" + echo "システム時間情報" - # 获取当前系统时区 + # 現在のシステムタイムゾーンを取得します local timezone=$(current_timezone) - # 获取当前系统时间 + # 現在のシステム時間を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # タイムゾーンと時間を表示します + echo "現在のシステムタイムゾーン:$timezone" + echo "現在のシステム時間:$current_time" echo "" - echo "时区切换" + echo "タイムゾーンの切り替え" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "アジア" + echo "1。中国の上海時間2。中国の香港時間" + echo "3。日本の東京時間4。韓国のソウル時間" + echo "5。シンガポール時間6。インドのコルカタ時間" + echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" + echo "9。タイのバンコクでの時間" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "ヨーロッパ" + echo "11。英国のロンドン時間12。パリの時間フランスの時間" + echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" + echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" echo "------------------------" - echo "美洲" + echo "アメリカ" echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "23。カナダ時間24。メキシコの時間" + echo "25。ブラジル時間26。アルゼンチン時間" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31。UTCグローバル標準時間" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -11891,21 +12155,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "ホスト名を変更します" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian、Ubuntu、Centosなどの他のシステム。 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11923,11 +12187,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "ホスト名は次のように変更されています。$new_hostname" + send_stats "ホスト名が変更されました" sleep 1 else - echo "已退出,未更改主机名。" + echo "終了すると、ホスト名は変更されていません。" break fi done @@ -11935,32 +12199,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "システムの更新ソースを変更します" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "更新ソース領域を選択します" + echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "中国本土のデフォルトソース" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "中国本土の教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "海外起源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -11968,62 +12232,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "タイミングタスク管理" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "タイミングされたタスクリスト" crontab -l echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1。毎月のタスク2。毎週のタスク" + echo "3。毎日のタスク4。時間ごとのタスク" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "時限タスクを追加します" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "削除する必要があるキーワードを入力してください。" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "タイミングタスクを削除します" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "タイミングタスクを編集します" ;; *) break # 跳出循环,退出菜单 @@ -12035,32 +12299,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "ローカルホストの解析" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "ネイティブホストのペルシングリスト" + echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" cat /etc/hosts echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1.新しい解析2を追加します。解析アドレスを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "ローカルホストの解析が追加されました" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "ローカルホストの解析と削除" ;; *) break # 跳出循环,退出菜单 @@ -12071,7 +12335,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12083,20 +12347,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防衛プログラム$check_docker" + echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" + echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2。SSH傍受記録を表示します" + echo "3。リアルタイムログ監視" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) install_docker @@ -12119,7 +12383,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; *) break @@ -12132,47 +12396,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "電流制限シャットダウン機能" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "電流制限シャットダウン機能" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.shファイルが存在するかどうかを確認してください if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gbの値を取得します local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 新しい仮想メモリサイズを入力します + echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" + read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day cz_day=${cz_day:-1} cd ~ @@ -12185,15 +12449,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "現在の制限シャットダウンが設定されています" + send_stats "現在の制限シャットダウンが設定されています" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "現在の制限シャットダウン関数はオフになっています" ;; *) break @@ -12206,40 +12470,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "秘密キーログイン" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ルート秘密キーログインモード" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "キーペアが生成され、SSHログインのより安全な方法" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "新しいキーを生成します" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "既存の公開キーをインポートします" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "地元の秘密の鍵を表示します" echo "------------------------" - echo "公钥信息" + echo "公開鍵情報" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "秘密のキー情報" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12255,18 +12519,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "電報警告" + echo "TG-BOTモニタリングと早期警告機能" + echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "しきい値に達した後、ユーザーはユーザーに送信されます" + echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "電報警告が有効になっています" cd ~ install nano tmux bc jq check_crontab_installed @@ -12288,7 +12552,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # 〜/.Profileファイルに追加します if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12299,21 +12563,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT早期警告システムが開始されました" + echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSHの高リスクの脆弱性を修正します" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12357,7 +12621,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "コマンドラインの履歴" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12380,61 +12644,61 @@ EOF 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "メッセージボード" + echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "ワンストップチューニング" + echo "ワンストップシステムの最適化" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "以下が操作され、最適化されます" + echo "1.システムを最新の状態に更新します" + echo "2。システムジャンクファイルをクリーンアップします" + echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "5.すべてのポートを開きます" + echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" + echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "ワンストップチューニングスタート" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12451,25 +12715,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" + echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac @@ -12477,7 +12741,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "システムを再起動します" server_reboot ;; 100) @@ -12493,32 +12757,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "プライバシーとセキュリティ" + echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "現在のステータス:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1。コレクションをオンにします" + echo "2。コレクションを閉じます" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "コレクションが有効になっています" + send_stats "プライバシーとセキュリティコレクションが有効になっています" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "コレクションは閉じた" + send_stats "プライバシーとセキュリティは収集のために閉鎖されています" ;; *) break @@ -12534,11 +12798,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "テックライオンスクリプトをアンインストールします" + echo "テックライオンスクリプトをアンインストールします" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -12546,16 +12810,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "スクリプトはアンインストールされています、さようなら!" break_end clear exit ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -12565,7 +12829,7 @@ EOF ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -12583,187 +12847,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "ファイルマネージャー" while true; do clear - echo "文件管理器" + echo "ファイルマネージャー" echo "------------------------" - echo "当前路径" + echo "現在のパス" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1。ディレクトリを入力します2。ディレクトリを作成3。ディレクトリアクセス許可を変更する4。ディレクトリの名前を変更します" + echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" + echo "15.ファイルを削除します" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" + echo "25。ファイルを別のサーバーに渡します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "ディレクトリ名を入力してください:" dirname + cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" + send_stats "ディレクトリに移動します" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "作成するにはディレクトリ名を入力してください。" dirname + mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" + send_stats "ディレクトリを作成します" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "ディレクトリ名を入力してください:" dirname + read -e -p "許可を入力してください(755など):" perm + chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ディレクトリ権限を変更します" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "現在のディレクトリ名を入力してください:" current_name + read -e -p "新しいディレクトリ名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" + send_stats "ディレクトリの名前を変更します" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "削除するには、ディレクトリ名を入力してください。" dirname + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" + send_stats "ディレクトリを削除します" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "前のメニューディレクトリに戻ります" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "作成するにはファイル名を入力してください。" filename + touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" + send_stats "ファイルを作成します" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "編集するにはファイル名を入力してください:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "ファイルを編集します" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "ファイル名を入力してください:" filename + read -e -p "許可を入力してください(755など):" perm + chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ファイル権限を変更します" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "現在のファイル名を入力してください:" current_name + read -e -p "新しいファイル名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" + send_stats "ファイルの名前を変更します" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "削除するには、ファイル名を入力してください。" filename + rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" + send_stats "ファイルを削除します" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" + send_stats "圧縮ファイル/ディレクトリ" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "ファイル名(.tar.gz)を入力してください:" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" + send_stats "ファイル/ディレクトリを解凍します" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリは移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + send_stats "ファイルまたはディレクトリを移動します" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -Rオプションを使用して、ディレクトリを再帰的にコピーします + cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" + send_stats "ファイルまたはディレクトリをコピーします" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "転送されるファイルパスを入力してください。" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "エラー:ファイルは存在しません。" + send_stats "ファイルの転送に失敗しました:ファイルは存在しません" continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "エラー:リモートサーバーIPを入力してください。" + send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "エラー:リモートサーバーのパスワードを入力してください。" + send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "ログインポートを入力してください(デフォルト22):" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 既知のホストの古いエントリをクリアします ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCPを使用してファイルを転送します scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "スクリプトは最新です$sh_v_new" break_end ~/kejilion.sh exit @@ -13061,15 +13325,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" + send_stats "自動スクリプトの更新をオンにします" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" + send_stats "スクリプト自動更新を閉じます" break_end ;; *) @@ -13091,41 +13355,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" +echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" +echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" +echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" +echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" +echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" +echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" +echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" +echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" +echo -e "${gl_kjlan}13. ${gl_bai}システムツール" +echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" +echo -e "${gl_kjlan}15. ${gl_bai}広告列" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "選択を入力してください:" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "システムの更新" ; linux_update ;; + 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "ワープ管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13136,13 +13400,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "無効な入力!" ;; esac break_end done @@ -13150,68 +13414,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "Kコマンド参照ユースケース" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "以下は、Kコマンドリファレンスユースケースです。" +echo "スクリプトkを開始します" +echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" +echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" +echo "システムKアップデートを更新| Kアップデート" +echo "クリーンシステムガベージkクリーン| kきれい" +echo "システムパネルk dd |を再インストールしますk再インストール" +echo "BBR3コントロールパネルK BBR3 | K BBRV3" +echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" +echo "仮想メモリkスワップ2048を設定します" +echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" +echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" +echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" +echo "SSHリモート接続ツールK SSH | Kリモート接続" +echo "rsyncリモート同期ツールk rsync | Kリモート同期" +echo "ハードディスク管理ツールKディスク| Kハードディスク管理" +echo "イントラネット浸透(サーバー側)K FRP" +echo "イントラネット浸透(クライアント)K FRPC" +echo "ソフトウェアStart K Start SSHD | k sshdを開始します" +echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" +echo "ソフトウェア再起動k再起動sshd | k再起動sshd" +echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" +echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" +echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書の有効期限クエリK SSL PS" +echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" +echo "Docker Container Management K Docker PS | K Dockerコンテナ" +echo "Docker Image Management K Docker IMG | K Docker画像" +echo "LDNMPサイト管理k Web" +echo "LDNMPキャッシュクリーンアップK Webキャッシュ" +echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" +echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" +echo "ロードバランスkロードバランス| kロードバランシングをインストールします" +echo "ファイアウォールパネルk fhq | kファイアウォール" +echo "オープンポートK DKDK 8080 | Kオープンポート8080" +echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" +echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" +echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" +echo "コマンドお気に入りk fav | Kコマンドのお気に入り" +echo "アプリ市場管理Kアプリ" +echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # パラメーターがない場合は、インタラクティブロジックを実行します kejilion_sh else - # 如果有参数,执行相应函数 + # パラメーターがある場合は、対応する関数を実行します case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "ソフトウェアをインストールします" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "ソフトウェアをアンインストールします" remove "$@" ;; update|更新) @@ -13245,7 +13509,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "タイム付きRSYNC同期" run_task "$@" ;; @@ -13264,7 +13528,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13277,13 +13541,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "仮想メモリをすばやく設定します" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "タイムゾーンをすばやく設定します" set_timedate "$@" ;; @@ -13331,42 +13595,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "ソフトウェアステータスビュー" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "ソフトウェアスタートアップ" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "ソフトウェアの一時停止" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "ソフトウェアの再起動" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "ソフトウェアが起動します" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "証明書のステータスを確認してください" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" else k_info fi @@ -13376,15 +13640,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Dockerをすばやくインストールします" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "クイックコンテナ管理" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "クイックミラー管理" docker_image ;; *) @@ -13411,7 +13675,7 @@ else app) shift - send_stats "应用$@" + send_stats "$@を適用します" linux_panel "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 1bebba7ec..114edc060 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.10" gl_hui='\e[37m' @@ -335,7 +335,7 @@ enable() { break_end() { echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" - echo "按任意键继续..." + echo "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" echo "" clear @@ -425,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,55 +500,55 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "도커 컨테이너 관리" + echo "도커 컨테이너 목록" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "컨테이너 작동" echo "------------------------" - echo "1. 创建新的容器" + echo "1. 새 컨테이너를 만듭니다" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" + echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" + echo "4. 지정된 컨테이너를 삭제합니다. 8. 모든 컨테이너를 삭제하십시오" + echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" + echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "새 컨테이너를 만듭니다" + read -e -p "창조 명령을 입력하십시오 :" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 시작하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너를 중지하십시오" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 삭제하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" + send_stats "지정된 컨테이너를 다시 시작하십시오" read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "모든 컨테이너를 시작하십시오" docker start $(docker ps -a -q) ;; 7) @@ -556,7 +556,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "모든 컨테이너를 삭제하십시오" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "모든 컨테이너를 다시 시작하십시오" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너를 입력하십시오" + read -e -p "컨테이너 이름을 입력하십시오 :" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너 로그를 봅니다" + read -e -p "컨테이너 이름을 입력하십시오 :" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "컨테이너 네트워크를 봅니다" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "컨테이너 점유를 봅니다" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 액세스를 허용합니다" + read -e -p "컨테이너 이름을 입력하십시오 :" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 액세스 차단" + read -e -p "컨테이너 이름을 입력하십시오 :" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "도커 이미지 관리" + echo "도커 이미지 목록" docker image ls echo "" - echo "镜像操作" + echo "미러 작동" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" + echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "거울을 당기십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "이미지를 업데이트하십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "거울을 삭제하십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "모든 이미지를 삭제합니다" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -754,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "지원되지 않는 분포 :$ID" return ;; esac else - echo "无法确定操作系统。" + echo "운영 체제를 결정할 수 없습니다." return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}Crontab이 설치되고 Cron 서비스가 실행 중입니다.${gl_bai}" } @@ -775,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 구성 파일이 존재하는지 확인하고 파일을 작성하고 기본 설정이 존재하지 않는 경우 작성하십시오. if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 구성 업데이트 및 IPv6을 활성화하십시오 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 원래 구성과 새로운 구성을 비교합니다 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 현재 활성화되어 있습니다${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}구성 파일이 존재하지 않습니다${gl_bai}" return fi - # 读取当前配置 + # 현재 구성을 읽으십시오 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 현재 IPv6 상태를 확인하십시오 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 원래 구성과 새로운 구성을 비교합니다 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스는 현재 닫힙니다${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 성공적으로 닫혔습니다${gl_bai}" fi } @@ -870,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "하나 이상의 포트 번호를 제공하십시오" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 기존 마감 규칙을 삭제하십시오 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # 열린 규칙을 추가하십시오 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "포트가 열렸습니다$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "포트가 열렸습니다" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "하나 이상의 포트 번호를 제공하십시오" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 기존 열린 규칙을 삭제합니다 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 가까운 규칙을 추가하십시오 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "포트 폐쇄$port" fi done - # 删除已存在的规则(如果有) + # 기존 규칙 삭제 (있는 경우) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 새로운 규칙을 먼저 삽입하십시오 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "포트 폐쇄" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 기존 차단 규칙을 삭제하십시오 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 허용 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "IP 출시$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "IP 출시" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 기존 허용 규칙을 삭제합니다 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # 차단 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IP 차단$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IP 차단" } @@ -990,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 방어 DDO를 켜십시오 iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDOS 방어를 켜십시오" } -# 关闭DDoS防御 +# DDOS 방어를 끕니다 disable_ddos_defense() { - # 关闭防御 DDoS + # 방어 DDO를 끄십시오 iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDOS 방어를 끕니다" } -# 管理国家IP规则的函数 +# 국가 IP 규칙을 관리하는 기능 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # IPSET가 존재하지 않는 경우 작성하십시오 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IP 영역 파일을 다운로드하십시오 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" exit 1 fi - # 将 IP 添加到 ipset + # IPSET에 IP를 추가하십시오 while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # iptables와 함께 IP를 차단하십시오 iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "성공적으로 차단되었습니다$country_codeIP 주소" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 허용 국가에 대한 IPSET 만들기 (존재하지 않는 경우) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IP 영역 파일을 다운로드하십시오 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" exit 1 fi - # 删除现有的国家规则 + # 기존 국가 규칙을 삭제합니다 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # IPSET에 IP를 추가하십시오 while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 지정된 국가의 IP 만 허용됩니다 iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "성공적으로 만 허용됩니다$country_codeIP 주소" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 국가의 iptables 규칙을 삭제하십시오 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # ipset을 파괴하십시오 if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "성공적으로 해제했습니다$country_codeIP 주소 제한" ;; *) @@ -1116,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "고급 방화벽 관리" + send_stats "고급 방화벽 관리" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "방화벽 관리" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." + echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5. IP 화이트리스트 6. IP 블랙리스트" + echo "7. 지정된 IP를 지우십시오" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. 핑 허용 12. 핑을 비활성화하십시오" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15. 지정된 국가 IP 16. 지정된 국가 IP 만 허용됩니다." + echo "17. 지정된 국가에서 IP 제한을 해제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "열린 포트 번호를 입력하십시오 :" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "지정된 포트를 엽니 다" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "지정된 포트를 닫습니다" ;; 3) - # 开放所有端口 + # 모든 포트를 엽니 다 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "모든 포트를 엽니 다" ;; 4) - # 关闭所有端口 + # 모든 포트를 닫습니다 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "모든 포트를 닫습니다" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IP 화이트리스트 + read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IP 블랙리스트 + read -e -p "차단 된 IP 또는 IP 세그먼트를 입력하십시오." c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 지정된 IP를 지우십시오 + read -e -p "청산 된 IP를 입력하십시오 :" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "지정된 IP를 지우십시오" ;; 11) - # 允许 PING + # 핑을 허용하십시오 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "핑을 허용하십시오" ;; 12) - # 禁用 PING + # 핑을 비활성화합니다 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "핑을 비활성화합니다" ;; 13) enable_ddos_defense @@ -1223,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "차단 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "허용 국가$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "허용 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "나라를 차단하십시오$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "나라를 정리하십시오$country_codeIP" ;; *) @@ -1257,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 모든 스왑 파티션을 반복하고 삭제하십시오 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfile이 더 이상 사용되지 않도록하십시오 swapoff /swapfile - # 删除旧的 /swapfile + # 이전 /스왑 파일을 삭제하십시오 rm -f /swapfile - # 创建新的 swap 分区 + # 새 스왑 파티션을 만듭니다 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "가상 메모리 크기가 크기가 커졌습니다${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 가상 메모리를 만들어야하는지 확인하십시오 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginx 버전을 얻으십시오 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # MySQL 버전을 얻으십시오 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHP 버전을 얻으십시오 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redis 버전을 얻으십시오 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 필요한 디렉토리 및 파일을 만듭니다 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.yml 파일을 다운로드하여 교체하십시오 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.yml 파일로 교체하십시오 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP 환경이 설치되었습니다" echo "------------------------" ldnmp_v @@ -1416,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "갱신 작업이 업데이트되었습니다" } @@ -1453,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming공개 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}인증서 저장 경로${gl_bai}" + echo "공개 키 :/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL 인증서를 신속하게 신청하고 만료 전에 서명을 자동으로 갱신하십시오.${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}응용 인증서 만료${gl_bai}" + echo "사이트 정보 인증서 만료 시간" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "도메인 이름 인증서 신청에 실패했습니다" + echo -e "${gl_hong}알아채다:${gl_bai}인증서 응용 프로그램이 실패했습니다. 가능한 이유를 확인하고 다시 시도하십시오." + echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." + echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." + echo -e "3. 네트워크 구성 문제 ➠ CloudFlare Warp 및 기타 가상 네트워크를 사용하는 경우 임시로 종료하십시오." + echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" + echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." + echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." break_end clear - echo "请再次尝试部署 $webname" + echo "다시 배포를 시도하십시오$webname" add_yuming install_ssltls certs_status @@ -1549,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "도메인 이름 재사용" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -1623,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" } @@ -1643,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "로그인 정보 :" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "시작$ldnmp_pods" } @@ -1657,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오 if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # 캐시 청소 여부를 사용자에게 프롬프트합니다 + read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" + read -e -p "API_Token을 입력하십시오 :" API_TOKEN + read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL + read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 각 Zone_ID를 루프하고 CLEAR CACHE 명령을 실행하십시오. for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "Zone_ID의 캐시 지우기 :$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "캐시 클리어 요청이 전송되었습니다." } web_cache() { - send_stats "清理站点缓存" + send_stats "사이트 캐시를 정리하십시오" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "사이트 데이터 삭제" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하십시오 (여러 도메인 이름이 공간별로 분리됩니다)." yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "도메인 이름 삭제 :$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # 도메인 이름을 데이터베이스 이름으로 변환합니다 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. + echo "데이터베이스 삭제 :$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # 모드 매개 변수에 따라 WAF를 켜거나 끄기로 결정 if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAF 켜기 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # waf 닫기 : 댓글을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 오래된 정의를 삭제하십시오 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 오래된 정의를 삭제하십시오 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotli를 켜십시오 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotli를 닫습니다 : 주석을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # ZSTD를 켜십시오 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # Zstd를 닫습니다 : 주석을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi @@ -1990,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP 환경 방어" while true; do check_waf_status check_cf_mode @@ -2004,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "서버 웹 사이트 방어 프로그램${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5. SSH 차단 레코드보기 6. 웹 사이트 차단 레코드보기" + echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11. 인터셉트 매개 변수 구성 12. 차단 된 모든 IP를 지우십시오" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31. WAF 32를 켜십시오. WAF를 끄십시오" + echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램을 제거하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2ban 방어 프로그램은 제거되었습니다" ;; 11) @@ -2097,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "CloudFlare 모드" + echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CF 계정 번호를 입력하십시오." cfuser + read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "5 초 방패의 높은 하중" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CF 매개 변수 가져 오기 :" + echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" + echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CF 계정 번호를 입력하십시오." cfuser + read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID cd ~ install jq bc @@ -2147,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "고 부하 자동 방패 오프닝 스크립트가 추가되었습니다" else - echo "自动开盾脚本已存在,无需添加" + echo "자동 방패 스크립트가 이미 존재합니다. 추가 할 필요가 없습니다." fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "사이트 waf가 활성화되어 있습니다" + send_stats "사이트 waf가 활성화되어 있습니다" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "사이트 waf가 닫혔습니다" + send_stats "사이트 waf가 닫혔습니다" ;; 33) @@ -2189,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 현재 Worker_Processes 설정 값을 얻으십시오 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 값에 따라 모드 정보를 설정합니다 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # ZSTD가 활성화되어 있고 주석이 없는지 확인하십시오 (전체 라인은 ZSTD 켜기로 시작합니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Brotli가 활성화되어 있고 댓글이 없는지 확인하십시오 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP 환경을 최적화하십시오" + echo -e "LDNMP 환경을 최적화하십시오${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" + echo "5. BR 압축 켜기 6. BR 압축 끄기" + echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "사이트 표준 모드" - # nginx调优 + # nginx 튜닝 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP 환경은 표준 모드로 설정되었습니다" ;; 2) - send_stats "站点高性能模式" + send_stats "사이트 고성능 모드" - # nginx调优 + # nginx 튜닝 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP 환경은 고성능 모드로 설정되었습니다" ;; 3) @@ -2386,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker = "$ {gl_lv} $ {gl_bai} 설치" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" # fi # } @@ -2396,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "액세스 주소 :" ip_address @@ -2434,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # 컨테이너 생성 시간과 이미지 이름을 얻으십시오 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # 거울 창고 및 태그 추출 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # 기본 레이블이 최신입니다 [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 공식 이미지에 대한 지원을 추가하십시오 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Docker Hub API에서 이미지 게시 시간을 얻으십시오 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 획득 시간을 확인하십시오 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # 타임 스탬프를 비교하십시오 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소를 가져옵니다 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 다른 모든 IP를 점검하고 차단하십시오 if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP를 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 다른 모든 IP를 점검하고 차단하십시오 if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP를 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" save_iptables_rules } @@ -2535,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소를 가져옵니다 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 지정된 IP를 공개하기위한 규칙을 지우십시오 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 지정된 IP를 공개하기위한 규칙을 지우십시오 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+포트는 서비스에 액세스 할 수있었습니다" save_iptables_rules } @@ -2599,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 다른 모든 IP 액세스를 거부했습니다 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP 액세스를 허용합니다 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스를 허용합니다 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 다른 모든 IP 액세스를 거부했습니다 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP 액세스를 허용합니다 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스를 허용합니다 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 확립 및 관련 연결을 위해 트래픽을 허용합니다 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" save_iptables_rules } @@ -2658,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "사용법 : CLEAR_HOST_PORT_RULES <포트 번호> <승인 IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP 액세스를 차단하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 기본 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP 액세스를 차단하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 기본 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+포트는 서비스에 액세스 할 수있었습니다" save_iptables_rules } @@ -2727,7 +2727,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}管理" +send_stats "${docker_name}관리하다" while true; do clear @@ -2747,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "설치하다$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "고쳐 쓰다$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "앱이 제거되었습니다" + send_stats "제거하십시오$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 액세스 설정" + send_stats "${docker_name}도메인 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 액세스를 차단하십시오${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 액세스 설정" + send_stats "${docker_name}도메인 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 액세스를 차단하십시오${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# 세션이 존재하는지 확인하는 기능 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 존재하지 않는 세션 이름이 발견 될 때까지 루프 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 새로운 TMUX 세션을 만듭니다 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "다시 시작" reboot ;; *) - echo "已取消" + echo "취소" ;; esac @@ -3127,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP 환경을 다시 설치할 수 없습니다" + echo -e "${gl_huang}힌트:${gl_bai}웹 사이트 구성 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" break_end linux_ldnmp fi @@ -3138,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP 환경을 설치하십시오" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Nginx 환경을 설치하십시오" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "Nginx가 설치되었습니다" +echo -e "현재 버전 :${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "먼저 LDNMP 환경을 설치하십시오" ldnmp_install_all fi @@ -3191,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "Nginx 환경을 먼저 설치하십시오" nginx_install_all fi @@ -3202,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "당신 것$webname세워짐!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webname설치 정보는 다음과 같습니다." } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "당신 것$webname세워짐!" echo "https://$yuming" } @@ -3223,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "반세대 IP를 입력하십시오 :" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "반세대 포트를 입력하십시오 :" port fi nginx_install_status install_ssltls @@ -3297,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port fi nginx_install_status @@ -3357,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMP 사이트 관리" + echo "LDNMP 환경" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "대지:${output}인증서 만료 시간" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "데이터 베이스:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "사이트 디렉토리" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" + echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" + echo "5. 액세스 로그보기 6. 오류 로그보기" + echo "7. 글로벌 구성 편집 8. 사이트 구성 편집" + echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서보기" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. 지정된 사이트 데이터를 삭제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "도메인 이름 인증서를 신청하십시오" + read -e -p "도메인 이름을 입력하십시오 :" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "사이트 도메인 이름을 변경하십시오" + echo -e "${gl_hong}적극 권장 :${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" + read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming + read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot install_ssltls certs_status - # mysql替换 + # MySQL 교체 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # 웹 사이트 디렉토리 교체 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "관련 사이트를 만듭니다" + echo -e "액세스 용 기존 사이트의 새 도메인 이름을 연결하십시오." + read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming + read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot install_ssltls certs_status @@ -3476,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "액세스 로그를 봅니다" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "오류 로그를 봅니다" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "글로벌 구성 편집" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "사이트 구성 편집" + read -e -p "사이트 구성을 편집하려면 편집 할 도메인 이름을 입력하십시오." yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "사이트 데이터를 봅니다" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3535,21 +3535,21 @@ fi install_panel() { -send_stats "${panelname}管理" +send_stats "${panelname}관리하다" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}요즘 인기 있고 강력한 운영 및 유지 관리 패널입니다." + echo "공식 웹 사이트 소개 :$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 설치 2. 관리 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}설치하다" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}控制" + send_stats "${panelname}제어" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}제거하십시오" ;; *) break @@ -3615,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRP 서버를 설치하십시오" + # 임의의 포트 및 자격 증명을 생성합니다 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 출력 생성 정보 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "클라이언트 배포에 필요한 매개 변수" + echo "서비스 IP :$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRP 패널 정보" + echo "FRP 패널 주소 : http : //$ipv4_address:$dashboard_port" + echo "FRP 패널 사용자 이름 :$dashboard_user" + echo "FRP 패널 비밀번호 :$dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRP 클라이언트를 설치하십시오" + read -e -p "외부 네트워크 도킹 IP를 입력하십시오." server_addr + read -e -p "외부 네트워크 도킹 토큰을 입력하십시오." token echo mkdir -p /home/frp @@ -3679,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRP 인트라넷 서비스를 추가하십시오" + # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 + read -e -p "서비스 이름을 입력하십시오 :" service_name + read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "인트라넷 포트를 입력하십시오 :" local_port + read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port - # 将用户输入写入配置文件 + # 구성 파일에 사용자 입력을 쓰십시오 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 출력 생성 정보 + echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다" docker restart frpc @@ -3711,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRP 인트라넷 서비스를 삭제하십시오" + # 삭제 해야하는 서비스 이름을 입력하라는 메시지 + read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name + # SED를 사용하여 서비스 및 관련 구성을 삭제하십시오. sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" docker restart frpc @@ -3726,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # 헤더를 인쇄하십시오 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 서비스 정보가있는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3756,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 현재 서비스 이름을 업데이트하십시오 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 이전 값을 지우십시오 local_ip="" local_port="" remote_port="" @@ -3789,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 마지막 서비스에 대한 정보를 인쇄하십시오 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRP 서버 포트를 가져옵니다 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# 액세스 주소를 생성합니다 generate_access_urls() { - # 首先获取所有端口 + # 모든 포트를 먼저 얻으십시오 get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056 이외의 포트가 있는지 확인하십시오 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 유효한 포트가있을 때만 제목과 콘텐츠 표시 if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP 서비스 외부 액세스 주소 :" - # 处理 IPv4 地址 + # 프로세스 IPv4 주소 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # Process IPv6 주소 (현재 경우) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS 구성 처리 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRP 서버" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP 서버$check_frp $update_status" + echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." + echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5. 인트라넷 서비스에 대한 도메인 이름 액세스 6. 도메인 이름 액세스 삭제" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. 서비스 상태 새로 고침 0. 이전 메뉴로 돌아갑니다." echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) install jq grep ss @@ -3902,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "FRP 서버가 설치되었습니다" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "FRP 서버가 업데이트되었습니다" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" + send_stats "외부 도메인 이름에 대한 FRP 액세스" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IP 액세스 허용" + read -e -p "해제 할 포트를 입력하십시오." frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IP 액세스를 차단하십시오" + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." + read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRP 서비스 상태를 새로 고치십시오" + echo "FRP 서비스 상태가 새로 고쳐졌습니다" ;; *) @@ -3966,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRP 클라이언트" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP 클라이언트$check_frp $update_status" + echo "서버로 도킹, 도킹 후 인터넷 액세스에 인트라넷 침투 서비스를 만들 수 있습니다." + echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 구성 수동으로 서비스 구성" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) install jq grep ss @@ -3999,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "FRP 클라이언트가 설치되었습니다" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "FRP 클라이언트가 업데이트되었습니다" ;; 3) @@ -4020,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; 4) @@ -4066,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "YT-DLP 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "YT-DLP는 YouTube, Bilibili, Twitter 등을 포함한 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." + echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "다운로드 된 비디오 목록 :" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. 단일 비디오 다운로드 6. 배치 비디오 다운로드 7. 사용자 정의 매개 변수 다운로드" + echo "8. MP3 오디오 9. 비디오 디렉토리 삭제 10. 쿠키 관리 (개발 중)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "옵션 번호를 입력하십시오 :" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "yt-dlp 설치 ..." + echo "yt-dlp 설치 ..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlp 업데이트 ..." + echo "yt-dlp 업데이트 ..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlp 제거 ..." + echo "yt-dlp 제거 ..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "단일 비디오 다운로드" + read -e -p "비디오 링크를 입력하십시오 :" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "다운로드가 완료되면 키를 눌러 계속하십시오 ..." ;; 6) - send_stats "批量视频下载" + send_stats "배치 비디오 다운로드" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "이제 배치 다운로드를 시작하십시오 ..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "배치 다운로드가 완료되었습니다. 키를 눌러 계속하십시오 ..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "맞춤형 비디오 다운로드" + read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3 다운로드" + read -e -p "비디오 링크를 입력하십시오 :" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "오디오 다운로드가 완료되었습니다. 키를 누르면 계속하십시오 ..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "비디오 삭제" + read -e -p "삭제 비디오의 이름을 입력하십시오." rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# DPKG 인터럽트 문제를 수정하십시오 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi } @@ -4231,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}시스템 정리 ...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 청소 ..." apk cache clean - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APK 캐시 삭제 ..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "사용하지 않는 의존성 정리 ..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 청소 ..." pkg clean -y - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi return @@ -4340,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNS 최적화" while true; do clear - echo "优化DNS地址" + echo "DNS 주소를 최적화합니다" echo "------------------------" - echo "当前DNS地址" + echo "현재 DNS 주소" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1. 외국 DNS 최적화 :" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2. 국내 DNS 최적화 :" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3. DNS 구성을 수동으로 편집합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "외국 DNS 최적화" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "국내 DNS 최적화" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS 구성을 수동으로 편집합니다" ;; *) break @@ -4403,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # PasswordAuthentication이 발견되면 예로 설정하십시오 if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 발견 된 경우 PubKeyAuthentication이 예로 설정됩니다 if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # PasswordAuthentication 또는 PubKeyAuthentication이 일치하지 않는 경우 기본값을 설정하십시오. if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # 백업 SSH 구성 파일 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSH 포트는 다음으로 수정되었습니다.$new_port" sleep 1 @@ -4459,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "개인 키 정보가 생성되었습니다. 복사하고 저장하십시오.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인 파일" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}루트 프라이빗 키 로그인이 활성화되고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH 공개 키 내용을 입력하십시오 (일반적으로 'SSH-RSA'또는 'SSH-ED25519'로 시작) :" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}오류 : 공개 키 컨텐츠가 입력되지 않았습니다.${gl_bai}" return 1 fi @@ -4499,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}공개 키가 성공적으로 가져 왔고 루트 개인 키 로그인이 활성화되었고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" } @@ -4508,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "루트 비밀번호를 설정하십시오" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능은 루트 사용자가 실행해야합니다!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "시스템을 다시 설치하십시오" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}Teddysun.com${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "시스템을 다시 설치하십시오" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." + echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "데비안 13을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "데비안 12를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "데비안 11을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "데비안 10을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "우분투 24.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "우분투 22.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Ubuntu 20.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "우분투 18.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Rockylinux10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Rockylinux9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "Alma10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "Alma9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Oracle10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Oracle9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Fedora42를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Fedora41을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "CentOS10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "CentOS9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "알파인을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "아치를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "칼리를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Openeuler를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "재설치 OpenSuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "비행 소부소" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Windows 11을 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Windows 10을 다시 설치하십시오" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows 7을 다시 설치하십시오" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Windows Server 22를 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Windows Server 19를 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Windows Server 16을 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Windows11 Arm을 다시 설치하십시오" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "BBRV3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "Xanmod의 BBRV3 커널을 설치했습니다" + echo "현재 커널 버전 :$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. BBRV3 커널 업데이트 2. BBRV3 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) @@ -4884,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3 단계 : 저장소를 추가합니다 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "Xanmod 커널이 업데이트되었습니다. 다시 시작한 후에도 적용됩니다" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "Xanmod 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" server_reboot ;; @@ -4916,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3 가속도를 설정하십시오" + echo "비디오 소개 : https://www.bilibili.com/video/bv14k421x7bs?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "데비안/우분투 만 지원합니다" + echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -4930,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "현재 환경은이를 지원하지 않으며 데비안 및 우분투 시스템 만 지원합니다." break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "운영 체제 유형을 결정할 수 없습니다" break_end linux_Settings fi @@ -4946,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3 단계 : 저장소를 추가합니다 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4957,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac fi @@ -4976,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Elrepo GPG 공개 키를 가져 오십시오 + echo "Elrepo GPG 공개 키를 가져 오십시오 ..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # 시스템 버전을 감지하십시오 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 지원되는 운영 체제에서 실행하십시오 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "지원되지 않는 운영 체제 :$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 감지 된 운영 체제 정보를 인쇄합니다 + echo "감지 된 운영 체제 :$os_name $os_version" + # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Elrepo 저장소 구성 (버전 9)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "지원되지 않는 시스템 버전 :$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오. + echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "Elrepo 저장소 구성이 설치되어 최신 메인 라인 커널로 업데이트됩니다." server_reboot } @@ -5017,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "레드 모자 커널 관리" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "Elrepo 커널을 설치했습니다" + echo "현재 커널 버전 :$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hat 커널을 업데이트하십시오" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "Elrepo 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" + send_stats "빨간 모자 커널을 제거하십시오" server_reboot ;; @@ -5060,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "데이터를 백업하고 Linux 커널을 업그레이드합니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" + echo "Linux 커널을 업그레이드하면 시스템 성능 및 보안이 향상 될 수 있습니다. 조건이 허용되고 생산 환경을 조심스럽게 업그레이드하는 경우 시도하는 것이 좋습니다!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hat 커널을 업그레이드하십시오" server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac fi @@ -5090,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}바이러스 데이터베이스 업데이트 ...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "스캔 할 디렉토리를 지정하십시오." return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}스캔 디렉토리 $@...${gl_bai}" - # 构建 mount 参数 + # 마운트 매개 변수를 빌드하십시오 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # Clamscan 명령 매개 변수를 작성하십시오 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Docker 명령을 실행하십시오 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@ scan이 완료되고 바이러스 보고서가 저장됩니다${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}바이러스가 있다면 제발${gl_huang}scan.log${gl_lv}파일에서 찾은 키워드를 검색하여 바이러스의 위치를 ​​확인하십시오.${gl_bai}" } @@ -5143,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "바이러스 스캔 관리" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "Clamav 바이러스 스캐닝 도구" + echo "비디오 소개 : https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "오픈 소스 바이러스 백신 소프트웨어 도구로 주로 다양한 유형의 맬웨어를 감지하고 제거하는 데 사용됩니다." + echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리를 스캔하십시오${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "전체 디스크 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "중요한 디렉토리 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "사용자 정의 디렉토리 스캔" + read -e -p "스캔 할 디렉토리를 입력하십시오." directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# 고성능 모드 최적화 기능 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}전환하십시오${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # NUMA 밸런싱을 비활성화합니다 sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# 이퀄라이제이션 모드 최적화 기능 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 투명 페이지를 복원하십시오 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # NUMA 밸런싱을 복원하십시오 sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# 기본 설정 기능을 복원하십시오 restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}기본 설정으로 복원하십시오 ...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 디스크립터 복원 ...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 복원 ...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 복원 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 복원 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}다른 최적화를 복원 ...${gl_bai}" + # 투명 페이지를 복원하십시오 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # NUMA 밸런싱을 복원하십시오 sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# 웹 사이트 구축 최적화 기능 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # NUMA 밸런싱을 비활성화합니다 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux 커널 튜닝 관리" + echo "Linux 시스템에서 커널 매개 변수의 최적화" + echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." + echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." + echo "2. 균형 최적화 모드 : 매일 사용하기에 적합한 성능과 자원 소비 사이의 균형." + echo "3. 웹 사이트 최적화 모드 : 웹 사이트 서버에 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." + echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." + echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." + echo "6. 기본 설정을 복원하십시오. 시스템 설정을 기본 구성으로 복원하십시오." echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "고성능 모드 최적화" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "균형 모드 최적화" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "웹 사이트 최적화 모델" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "라이브 스트리밍 최적화" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "게임 서버 최적화" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "기본 설정을 복원하십시오" ;; *) break @@ -5446,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end @@ -5455,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "지원되지 않는 시스템 :$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "지원되지 않는 시스템, 시스템 유형을 인식 할 수 없습니다." break_end fi } @@ -5475,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "스위치 시스템 언어" while true; do clear - echo "当前系统语言: $LANG" + echo "현재 시스템 언어 :$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. 영어 2. 중국어 3. 전통 중국어" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "영어로 전환하십시오" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "단순화 된 중국어로 전환하십시오" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "전통적인 중국어로 전환하십시오" ;; *) break @@ -5519,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 볼 수 있도록 SSH를 다시 ​​연결하십시오!${gl_bai}" hash -r break_end @@ -5530,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "명령 라인 미화 도구" while true; do clear - echo "命令行美化工具" + echo "명령 라인 미화 도구" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -5590,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "시스템 재활용 스테이션" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "현재 재활용 쓰레기통${trash_status}" + echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "재활용 쓰레기통은 비어 있습니다" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1. 재활용 빈을 활성화합니다. 2. 재활용 쓰레기통을 닫습니다." + echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -5623,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "Recycle Bin이 활성화되고 삭제 된 파일이 Recycle Bin으로 이동됩니다." sleep 2 ;; 2) @@ -5631,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "재활용 빈이 닫히고 파일이 직접 삭제됩니다." sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "복원 할 파일 이름을 입력하십시오." file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restore홈 디렉토리로 복원되었습니다." else - echo "文件不存在。" + echo "파일이 존재하지 않습니다." fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "재활용 쓰레기통을 지우셨습니까? [Y/N] :" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "재활용 쓰레기통이 지워졌습니다." fi ;; *) @@ -5658,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "명령 즐겨 찾기" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# 백업을 만듭니다 create_backup() { - send_stats "创建备份" + send_stats "백업을 만듭니다" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 + echo "백업 예제 :" + echo "- 단일 디렉토리를 백업 : /var /www" + echo "- 여러 디렉토리 백업 : /etc /home /var /log" + echo "- Direct Enter는 기본 디렉토리 ( /etc /usr /home)를 사용합니다." + read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input - # 如果用户没有输入目录,则使用默认目录 + # 사용자가 디렉토리를 입력하지 않으면 기본 디렉토리를 사용하십시오. if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 사용자가 입력 한 디렉토리를 공백 별 배열로 분리합니다. IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 백업 파일 접두사를 생성합니다 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # 디렉토리 이름을 추출하고 슬래시를 제거하십시오 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 마지막 밑줄을 제거하십시오 local PREFIX=${PREFIX%_} - # 生成备份文件名 + # 백업 파일 이름을 생성합니다 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # 사용자가 선택한 디렉토리를 인쇄하십시오 + echo "선택한 백업 디렉토리는 다음과 같습니다." for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # 백업을 만듭니다 + echo "백업 생성$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # 명령이 성공했는지 확인하십시오 if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "백업은 성공적으로 생성되었습니다.$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "백업 생성이 실패했습니다!" exit 1 fi } -# 恢复备份 +# 백업을 복원하십시오 restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "백업을 복원하십시오" + # 복원하려는 백업을 선택하십시오 + read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "백업 복구$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "백업 및 복원을 성공적으로 복원하십시오!" else - echo "备份恢复失败!" + echo "백업 복구 실패!" exit 1 fi } -# 列出备份 +# 백업을 나열합니다 list_backups() { - echo "可用的备份:" + echo "사용 가능한 백업 :" ls -1 "$BACKUP_DIR" } -# 删除备份 +# 백업을 삭제하십시오 delete_backup() { - send_stats "删除备份" + send_stats "백업을 삭제하십시오" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "삭제하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - # 删除备份 + # 백업을 삭제하십시오 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "백업이 성공적으로 삭제되었습니다!" else - echo "备份删除失败!" + echo "백업 삭제가 실패했습니다!" exit 1 fi } -# 备份主菜单 +# 백업 메인 메뉴 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "시스템 백업 기능" + echo "시스템 백업 기능" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1. 백업 만들기 2. 백업 복원 3. 백업 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } @@ -5806,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# 연결 목록 표시 list_connections() { - echo "已保存的连接:" + echo "저장된 연결 :" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 새 연결을 추가하십시오 add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "새 연결을 추가하십시오" + echo "새 연결을 만드는 예 :" + echo "- 연결 이름 : my_server" + echo "-IP 주소 : 192.168.1.100" + echo "- 사용자 이름 : 루트" + echo "- 포트 : 22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "연결 이름을 입력하십시오 :" name + read -e -p "IP 주소를 입력하십시오 :" ip + read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "인증 방법을 선택하십시오 :" + echo "1. 비밀번호" + echo "2. 키" + read -e -p "선택 (1/2)을 입력하십시오 :" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "비밀번호를 입력하십시오 :" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함 된 경우 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 주요 내용인지 확인하십시오 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "잘못된 선택!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "연결이 저장됩니다!" } -# 删除连接 +# 연결을 삭제하십시오 delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "연결을 삭제하십시오" + read -e -p "삭제하려면 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류 : 해당 연결을 찾을 수 없었습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "연결이 삭제되었습니다!" } -# 使用连接 +# 연결을 사용하십시오 use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "연결을 사용하십시오" + read -e -p "사용할 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류 : 해당 연결을 찾을 수 없었습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "연결$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 키와 연결하십시오 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "연결 실패! 다음을 확인하십시오." + echo "1. 키 파일 경로가 정확합니까?$password_or_key" + echo "2. 키 파일 권한이 올바른지 여부 (600이어야 함)." + echo "3. 대상 서버가 키를 사용하여 로그인 할 수 있는지 여부." fi else - # 使用密码连接 + # 비밀번호로 연결하십시오 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "설치 방법 :" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "연결 실패! 다음을 확인하십시오." + echo "1. 사용자 이름과 비밀번호가 올바른지 여부." + echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." + echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSH 원격 연결 도구" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 구성 파일과 키 디렉토리가 존재하는지 확인하고 존재하지 않으면 작성하십시오. if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSH 원격 연결 도구" + echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. 새 연결 만들기 2. 연결 사용 3. 연결 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "잘못된 선택, 다시 시도하십시오." ;; esac done } @@ -5988,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 사용 가능한 하드 디스크 파티션을 나열하십시오 list_partitions() { - echo "可用的硬盘分区:" + echo "사용 가능한 하드 디스크 파티션 :" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# 파티션을 장착하십시오 mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "파티션을 장착하십시오" + read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "파티션은 이미 장착되어 있습니다!" return fi - # 创建挂载点 + # 마운트 포인트를 만듭니다 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # 파티션을 장착하십시오 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "파티션 마운트 성공적으로 :$MOUNT_POINT" else - echo "分区挂载失败!" + echo "파티션 마운트 실패!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# 파티션을 제거하십시오 unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "파티션을 제거하십시오" + read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "파티션이 장착되지 않았습니다!" return fi - # 卸载分区 + # 파티션을 제거하십시오 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "파티션 분할 해제 성공 :$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "파티션 제거 실패!" fi } -# 列出已挂载的分区 +# 목록 장착 파티션 list_mounted_partitions() { - echo "已挂载的分区:" + echo "마운트 파티션 :" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# 형식 파티션 format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "형식 파티션" + read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "파티션이 장착되었습니다. 먼저 제거하십시오!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # 파일 시스템 유형을 선택하십시오 + echo "파일 시스템 유형을 선택하십시오 :" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "선택을 입력하십시오 :" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "잘못된 선택!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # 형식을 확인하십시오 + read -e -p "파티션 형식 확인 /dev /$PARTITION~을 위한$FS_TYPE그게? (Y/N) :" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "작업이 취소되었습니다." return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # 형식 파티션 + echo "파티션 서식 /dev /$PARTITION~을 위한$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "파티션 형식이 성공적이었습니다!" else - echo "分区格式化失败!" + echo "파티션 형식이 실패했습니다!" fi } -# 检查分区状态 +# 파티션 상태를 확인하십시오 check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "파티션 상태를 확인하십시오" + read -e -p "파티션 이름을 입력하여 확인하십시오 (예 : SDA1) :" PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # 파티션 상태를 확인하십시오 + echo "파티션 /개발자 /$PARTITION상태:" fsck "/dev/$PARTITION" } -# 主菜单 +# 메인 메뉴 disk_manager() { - send_stats "硬盘管理功能" + send_stats "하드 디스크 관리 기능" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "하드 디스크 파티션 관리" + echo -e "${gl_huang}이 기능은 테스트 기간 동안 내부적으로 테스트되므로 생산 환경에서 사용하지 마십시오.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" + echo "4. 파티션 형식 5. 파티션 상태를 확인하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } -# 显示任务列表 +# 작업 목록 표시 list_tasks() { - echo "已保存的同步任务:" + echo "저장된 동기화 작업 :" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 새로운 작업을 추가하십시오 add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "새 동기화 작업을 추가하십시오" + echo "새 동기화 작업 작성 예 :" + echo "- 작업 이름 : Backup_www" + echo "- 로컬 디렉토리 : /var /www" + echo "- 원격 주소 : user@192.168.1.100" + echo "- 원격 디렉토리 : /백업 /www" + echo "- 포트 번호 (기본 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "작업 이름을 입력하십시오 :" name + read -e -p "로컬 디렉토리를 입력하십시오 :" local_path + read -e -p "원격 디렉토리를 입력하십시오 :" remote_path + read -e -p "원격 사용자 @IP를 입력하십시오 :" remote + read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "인증 방법을 선택하십시오 :" + echo "1. 비밀번호" + echo "2. 키" + read -e -p "선택하십시오 (1/2) :" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "비밀번호를 입력하십시오 :" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 주요 내용인지 확인하십시오 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "잘못된 키 컨텐츠!" return fi ;; *) - echo "无效的选择!" + echo "잘못된 선택!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "동기화 모드를 선택하십시오 :" + echo "1. 표준 모드 (-avz)" + echo "2. 대상 파일 삭제 (-avz-delete)" + read -e -p "선택하십시오 (1/2) :" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "유효하지 않은 선택, 기본값 -AVZ를 사용하십시오"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "작업을 저장했습니다!" } -# 删除任务 +# 작업을 삭제하십시오 delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 작업을 삭제합니다" + read -e -p "삭제하려면 작업 번호를 입력하십시오." num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "오류 : 해당 작업을 찾을 수 없었습니다." return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "작업이 삭제되었습니다!" } run_task() { - send_stats "执行同步任务" + send_stats "동기화 작업을 수행하십시오" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # 매개 변수를 분석하십시오 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 들어오는 작업 번호가없는 경우 사용자에게 입력하라는 메시지를 표시하십시오. if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "실행할 작업 번호를 입력하십시오." num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "오류 : 작업이 찾을 수 없었습니다!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 동기화 방향에 따라 소스 및 대상 경로를 조정하십시오 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "동기화를 원격 끝으로 푸시합니다.$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH 연결 공통 매개 변수를 추가하십시오 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "설치 방법 :" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # 키 파일이 존재하는지 여부와 권한이 올바른지 확인 if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "오류 : 키 파일이 존재하지 않습니다.$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "경고 : 키 파일 권한이 잘못되었고 수리 중입니다 ..." chmod 600 "$password_or_key" fi @@ -6330,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "동기화가 완료되었습니다!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "동기화 실패! 다음을 확인하십시오." + echo "1. 네트워크 연결이 정상입니까?" + echo "2. 원격 호스트가 액세스 할 수 있습니까?" + echo "3. 인증 정보가 정확합니까?" + echo "4. 로컬 및 원격 디렉토리에 올바른 액세스 권한이 있습니까?" fi } -# 创建定时任务 +# 시간이 정한 작업을 만듭니다 schedule_task() { - send_stats "添加同步定时任务" + send_stats "동기화 타이밍 작업을 추가하십시오" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류 : 유효한 작업 번호를 입력하십시오!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "시간이 정한 실행 간격을 선택하십시오." + echo "1) 한 시간에 한 번 실행하십시오" + echo "2) 하루에 한 번 수행하십시오" + echo "3) 일주일에 한 번 실행하십시오" + read -e -p "옵션을 입력하십시오 (1/2/3) :" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "오류 : 유효한 옵션을 입력하십시오!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 동일한 작업이 이미 존재하는지 확인하십시오 if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "오류 :이 작업의 타이밍 동기화가 이미 존재합니다!" return fi - # 创建到用户的 crontab + # 사용자에게 크론AB를 만듭니다 (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "타이밍 작업이 만들어졌습니다.$cron_job" } -# 查看定时任务 +# 예정된 작업을 봅니다 view_tasks() { - echo "当前的定时任务:" + echo "현재 타이밍 작업 :" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# 타이밍 작업을 삭제하십시오 delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 타이밍 작업을 삭제합니다" + read -e -p "삭제하려면 작업 번호를 입력하십시오." num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류 : 유효한 작업 번호를 입력하십시오!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "삭제 된 작업 번호$num타이밍 작업" } -# 任务管理主菜单 +# 작업 관리 메인 메뉴 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "RSYNC 원격 동기화 도구" + echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1. 새 작업 생성 2. 작업을 삭제하십시오" + echo "3. 원격 끝에 로컬 동기화 수행 4. 로컬 엔드에 대한 원격 동기화 수행" + echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "잘못된 선택, 다시 시도하십시오." ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } @@ -6448,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "시스템 정보 쿼리" ip_address @@ -6498,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "시스템 정보 쿼리" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}호스트 이름 :${gl_bai}$hostname" + echo -e "${gl_kjlan}시스템 버전 :${gl_bai}$os_info" + echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU 모델 :${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU 코어 수 :${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" + echo -e "${gl_kjlan}물리적 기억 :${gl_bai}$mem_info" + echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" + echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}네트워크 알고리즘 :${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4 주소 :${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6 주소 :${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS 주소 :${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}지리적 위치 :${gl_bai}$country $city" + echo -e "${gl_kjlan}시스템 시간 :${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" echo @@ -6545,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats "기본 도구" + echo -e "기본 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" + echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" + echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" + echo -e "${gl_kjlan}9. ${gl_bai}Tmux 다중 채널 배경 달리기 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" + echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" + echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." curl --help - send_stats "安装curl" + send_stats "컬을 설치하십시오" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." wget --help - send_stats "安装wget" + send_stats "wget을 설치하십시오" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." sudo --help - send_stats "安装sudo" + send_stats "Sudo를 설치하십시오" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." socat -h - send_stats "安装socat" + send_stats "Socat을 설치하십시오" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "HTOP를 설치하십시오" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "Iftop을 설치하십시오" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." unzip - send_stats "安装unzip" + send_stats "압축을 설치하십시오" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." tar --help - send_stats "安装tar" + send_stats "타르를 설치하십시오" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." tmux --help - send_stats "安装tmux" + send_stats "tmux를 설치하십시오" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." ffmpeg --help - send_stats "安装ffmpeg" + send_stats "FFMPEG를 설치하십시오" ;; 11) @@ -6657,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "Btop을 설치하십시오" ;; 12) clear @@ -6666,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "레인저를 설치하십시오" ;; 13) clear @@ -6675,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "NCDU를 설치하십시오" ;; 14) clear @@ -6684,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "FZF를 설치하십시오" ;; 15) clear @@ -6693,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "VIM을 설치하십시오" ;; 16) clear @@ -6702,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "나노를 설치하십시오" ;; @@ -6713,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "git을 설치하십시오" ;; 21) @@ -6721,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrix를 설치하십시오" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "SL을 설치하십시오" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "Bastet을 설치하십시오" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "NSNAKE를 설치하십시오" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Ninvaders를 설치하십시오" ;; 31) clear - send_stats "全部安装" + send_stats "모두 설치하십시오" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "모든 설치 (게임 및 스크린 세이버 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "모든 것을 제거하십시오" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "설치된 도구 이름 (WGET CURL SUDO HTOP)을 입력하십시오." installname install $installname - send_stats "安装指定软件" + send_stats "지정된 소프트웨어를 설치하십시오" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename remove $removename - send_stats "卸载指定软件" + send_stats "지정된 소프트웨어를 제거하십시오" ;; 0) @@ -6789,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -6803,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR 관리" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "현재 TCP 차단 알고리즘 :$congestion_algorithm $queue_algorithm" echo "" - echo "BBR管理" + echo "BBR 관리" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. BBRV3 켜기 2. BBRV3 끄기 (재시작)" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "알파인 활성화 BBR3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6854,37 +6854,37 @@ linux_docker() { while true; do clear - # send_stats "docker管理" - echo -e "Docker管理" + # Send_stats "Docker Management" + echo -e "도커 관리" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경을 설치하고 업데이트하십시오${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Docker Global Status를 봅니다${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" + echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" + echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너 및 미러 네트워크 데이터 볼륨을 청소하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" + echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Docker 환경을 설치하십시오" install_add_docker ;; @@ -6895,22 +6895,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "도커 글로벌 상태" + echo "도커 버전" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "도커 이미지 :${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -6925,8 +6925,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "도커 네트워크 관리" + echo "도커 네트워크 목록" echo "------------------------------------------------------------" docker network ls echo "" @@ -6950,36 +6950,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "네트워크 작동" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1. 네트워크를 만듭니다" + echo "2. 인터넷에 가입하십시오" + echo "3. 네트워크를 종료하십시오" + echo "4. 네트워크를 삭제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "네트워크를 만듭니다" + read -e -p "새 네트워크 이름 설정 :" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "인터넷에 가입하십시오" + read -e -p "네트워크 이름에 가입 :" dockernetwork + read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "인터넷에 가입하십시오" + read -e -p "종료 네트워크 이름 :" dockernetwork + read -e -p "해당 컨테이너는 네트워크를 종료합니다 (여러 컨테이너 이름은 공간별로 분리됩니다)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -6988,8 +6988,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "네트워크를 삭제하십시오" + read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork docker network rm $dockernetwork ;; @@ -7003,29 +7003,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "도커 볼륨 관리" + echo "도커 볼륨 목록" docker volume ls echo "" - echo "卷操作" + echo "볼륨 작동" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1. 새 볼륨을 만듭니다" + echo "2. 지정된 볼륨을 삭제합니다" + echo "3. 모든 볼륨을 삭제하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "새 볼륨을 만듭니다" + read -e -p "새 볼륨 이름 설정 :" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "볼륨 삭제 이름을 입력하십시오 (공백으로 여러 볼륨 이름을 분리하십시오)." dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7034,7 +7034,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "모든 볼륨을 삭제하십시오" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7043,7 +7043,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7056,7 +7056,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "도커 청소" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7065,13 +7065,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "도커 소스" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7084,19 +7084,19 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker V6 열기" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker V6 레벨" docker_ipv6_off ;; 20) clear - send_stats "Docker卸载" + send_stats "Docker는 제거합니다" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7108,7 +7108,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7117,7 +7117,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7134,151 +7134,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # Send_stats "테스트 스크립트 컬렉션" + echo -e "스크립트 수집 테스트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGpt는 상태 감지를 잠금 해제합니다" + echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" + echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}네트워크 속도 측정" + echo -e "${gl_kjlan}11. ${gl_bai}Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" + echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" + echo -e "${gl_kjlan}17. ${gl_bai}I-ABC 다기능 속도 테스트 스크립트" + echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}하드웨어 성능 테스트" + echo -e "${gl_kjlan}21. ${gl_bai}YABS 성능 테스트" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}포괄적 인 테스트" + echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "ChatGpt는 상태 감지를 잠금 해제합니다" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "지역 스트리밍 미디어 잠금 해제 테스트" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "YEAHWU 스트리밍 미디어 잠금 해제 탐지" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "xykt_ip 품질 신체 검사 스크립트" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "MTR_TRACE 3 개의 네트워크 리턴 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "Superspeed 3 Net 속도 측정" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace 빠른 백홀 테스트 스크립트" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" + echo "참조 할 수있는 IP 목록" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "베이징 통신 : 219.141.136.12" + echo "베이징 유니폼 : 202.106.50.1" + echo "베이징 모바일 : 221.179.155.161" + echo "상하이 통신 : 202.96.209.133" + echo "상하이 유니폼 : 210.22.97.1" + echo "상하이 모바일 : 211.136.112.200" + echo "광저우 통신 : 58.60.188.222" + echo "광저우 유니폼 : 210.21.196.6" + echo "광저우 모바일 : 120.196.165.24" + echo "청두 통신 : 61.139.2.69" + echo "청두 유니폼 : 119.6.6.6" + echo "청두 모바일 : 211.137.96.205" + echo "Hunan Telecom : 36.111.200.100" + echo "후난 유니폼 : 42.48.16.100" + echo "후난 모바일 : 39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "지정된 IP를 입력하십시오." testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "Ludashi2020 3 네트워크 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "I-ABC 다기능 속도 테스트 스크립트" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "네트워크 품질 테스트 스크립트" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "YABS 성능 테스트" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "IICU/GB5 CPU 성능 테스트 스크립트" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "벤치 성능 테스트" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "SpiritySDX 퓨전 몬스터 검토" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7288,7 +7288,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7304,51 +7304,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud 스크립트 컬렉션" + echo -e "Oracle Cloud 스크립트 컬렉션" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}유휴 기계 활성 스크립트를 설치하십시오" + echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" + echo -e "${gl_kjlan}4. ${gl_bai}형사 R 스크립트 시작" + echo -e "${gl_kjlan}5. ${gl_bai}루트 비밀번호 로그인 모드를 켭니다" + echo -e "${gl_kjlan}6. ${gl_bai}IPv6 복구 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "활성 스크립트 : CPU는 10-20% 메모리를 점유합니다." + read -e -p "설치 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # 기본값을 설정합니다 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # 사용자에게 CPU 코어 수와 점유율 백분율을 입력하라는 메시지를 표시하고 입력 한 경우 기본값을 사용하십시오. + read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 사용 백분율 범위 (예 : 10-20) [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "스피드 테스트 간격 시간 (초)을 입력하십시오 [기본값 :$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # 도커 컨테이너를 실행하십시오 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7356,14 +7356,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloud 설치 활성 스크립트" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7371,20 +7371,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" ;; 3) clear - echo "重装系统" + echo "시스템을 다시 설치하십시오" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "다시 설치할 시스템을 선택하십시오 : 1. Debian12 | 2. Ubuntu20.04 :" sys_choice case "$sys_choice" in 1) @@ -7396,28 +7396,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "유효하지 않은 선택, 다시 입력하십시오." ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "다시 설치 한 비밀번호를 입력하십시오." vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud 회복 시스템 스크립트" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "이 기능은 개발 단계에 있으므로 계속 지켜봐 주시기 바랍니다!" ;; 5) clear @@ -7427,15 +7427,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 마스터 JHB가 제공합니다." + send_stats "IPv6 수정" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7456,7 +7456,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" fi } @@ -7477,7 +7477,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" fi fi @@ -7505,31 +7505,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "ldnmp 웹 사이트 빌딩" + echo -e "${gl_huang}LDNMP 웹 사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPress를 설치하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginx 만 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" + echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" + echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" + echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" + echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" + echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -7543,10 +7543,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # Discuz 포럼 webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7569,21 +7569,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 : discuz_" ;; 4) clear - # 可道云桌面 + # Kedao 클라우드 데스크탑 webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7605,20 +7605,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "데이터베이스 주소 : MySQL" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름 :$dbname" + echo "Redis 호스트 : Redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7644,24 +7644,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 접두사 : MAC_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "설치가 성공한 후 배경 주소에 로그인하십시오." echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 한 다리 카운팅 카드 webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7682,34 +7682,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "Redis 주소 : Redis" + echo "Redis Password : 기본적으로 채워지지 않습니다" + echo "Redis Port : 6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "웹 사이트 URL : https : //$yuming" + echo "백그라운드 로그인 경로 : /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "사용자 이름 : 관리자" + echo "비밀번호 : 관리자" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "로그인 할 때 오른쪽 상단에 빨간색 Error0이 나타나면 다음 명령을 사용하십시오." + echo "나는 또한 유니콘 번호 카드가 너무 귀찮다는 것에 대해 매우 화가 났으며 그러한 문제가있을 것입니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # Flarum 포럼 webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7746,12 +7746,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 : flarum_" + echo "관리자 정보는 직접 설정됩니다" ;; @@ -7759,8 +7759,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7784,11 +7784,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "데이터베이스 접두사 : typecho_" + echo "데이터베이스 주소 : MySQL" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름 :$dbname" ;; @@ -7797,8 +7797,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7823,18 +7823,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7851,10 +7851,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -7864,20 +7864,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.php가있는 경로" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/와 유사한 Index.php의 경로를 입력하십시오.$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택하십시오" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. PHP의 최신 버전 | 2. PHP7.4 :" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -7888,15 +7888,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "유효하지 않은 선택, 다시 입력하십시오." ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장자를 설치하십시오" echo "-------------" - echo "已经安装的扩展" + echo "설치된 확장" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -7906,25 +7906,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "계속하려면 모든 키를 누르면 의사 정적 내용 등과 같은 사이트 구성을 자세히 설정할 수 있습니다." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 작성하고 데이터베이스 백업이 있습니다." use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -7934,10 +7934,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "데이터베이스 가져 오기 테이블 데이터" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "데이터베이스 가져 오기가 완료되었습니다" ;; *) echo @@ -7949,12 +7949,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 :$prefix" + echo "관리자 로그인 정보는 직접 설정됩니다" ;; @@ -7967,10 +7967,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy nginx_install_status install_ssltls certs_status @@ -7992,7 +7992,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8003,11 +8003,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "도메인 이름 형식 :${gl_huang}google.com${gl_bai}" + read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8027,8 +8027,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8050,8 +8050,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8068,8 +8068,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8102,8 +8102,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8120,10 +8120,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8133,12 +8133,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/와 유사한 index.html로가는 경로를 입력하십시오.$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8163,21 +8163,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP 환경 백업" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "백업 파일이 작성되었습니다 : /home /$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "오류 : 원격 서버 IP를 입력하십시오." continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8185,9 +8185,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." else - echo "未找到要传送的文件。" + echo "전송할 파일은 찾을 수 없었습니다." fi break ;; @@ -8195,7 +8195,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac done @@ -8203,9 +8203,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "시간이 지정된 원격 백업" + read -e -p "원격 서버 IP를 입력하십시오." useip + read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8215,18 +8215,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1. 주간 백업 2. 매일 백업" + read -e -p "선택을 입력하십시오 :" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "주간 백업의 요일을 선택하십시오 (0-6, 0은 일요일을 나타냅니다) :" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "매일 백업 시간을 선택하십시오 (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8240,19 +8240,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP 환경 복원" + echo "사용 가능한 사이트 백업" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8262,7 +8262,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8271,7 +8271,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "압축 패키지가 발견되지 않았습니다." fi ;; @@ -8289,11 +8289,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP 환경을 업데이트하십시오" + echo "LDNMP 환경을 업데이트하십시오" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "구성 요소의 새 버전을 발견하십시오" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8313,13 +8313,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" echo "------------------------" - echo "5. 更新完整环境" + echo "5. 전체 환경을 업데이트하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8328,7 +8328,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 8.0 8.3 8.4 9.0) (최신 버전을 얻으려면 입력) :" version local version=${version:-latest} cd /home/web/ @@ -8339,13 +8339,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 7.4 8.0 8.1 8.2 8.3) (최신 버전을 얻으려면 입력) :" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8378,8 +8378,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 4) @@ -8390,15 +8390,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP 환경을 완전히 업데이트하십시오" cd /home/web/ docker compose down --rmi all @@ -8424,7 +8424,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP 환경을 제거하십시오" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8438,7 +8438,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -8448,7 +8448,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" esac break_end @@ -8468,12 +8468,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "응용 프로그램 시장" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # 루프로 색상을 설정하십시오 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8482,62 +8482,67 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" + echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" + echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" + echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" + echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" + echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" + echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" + echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" + echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" + echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" + echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" + echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" + echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" + echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" + echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" + echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" + echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" + echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" + echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" + echo -e "${gl_kjlan}89. ${color89}filecodebox 파일 Express${gl_kjlan}90. ${color90}매트릭스 분산 채팅 프로토콜" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice fi case $sub_choice in @@ -8687,7 +8692,8 @@ while true; do docker_rum() { - + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8696,8 +8702,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8711,8 +8717,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -8720,7 +8726,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "Nezha를 구축하십시오" local app_id="7" local docker_name="nezha-dashboard" @@ -8729,20 +8735,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezha 모니터링$check_docker $update_status" + echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" + echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1. 사용" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -8799,7 +8805,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "우체국을 건설하십시오" clear install telnet local app_id="9" @@ -8809,43 +8815,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "우체국 서비스$check_docker $update_status" + echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" - echo "端口检测" + echo "포트 감지" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "액세스 주소 :" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "이 DNS 레코드를 먼저 구문 분석하십시오" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -8855,7 +8861,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install jq @@ -8874,9 +8880,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" echo "" @@ -8899,9 +8905,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" echo "" ;; @@ -8912,7 +8918,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; *) @@ -8946,7 +8952,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -8956,7 +8962,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chat이 설치되었습니다" check_docker_app_ip } @@ -8966,7 +8972,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -9050,7 +9056,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -9064,7 +9070,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -9209,7 +9215,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "천둥 수영장을 건설하십시오" local app_id="19" local docker_name=safeline-mgt @@ -9217,20 +9223,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "썬더 풀 서비스$check_docker" + echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -9240,7 +9246,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "Thunder Pool WAF 패널이 설치되었습니다" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9253,7 +9259,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip ;; 3) @@ -9264,7 +9270,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9383,7 +9389,8 @@ while true; do docker_rum() { - + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9392,8 +9399,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9404,14 +9411,13 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; @@ -9672,7 +9678,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -9725,7 +9731,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoya 가족 버킷" clear install_docker check_disk_space 1 @@ -9927,9 +9933,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "설치" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" } docker_app_update() { @@ -9947,7 +9953,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10034,7 +10040,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVE 치킨" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10154,7 +10160,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10169,7 +10175,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10197,7 +10203,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10212,7 +10218,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10220,7 +10226,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10241,17 +10247,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "설치" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "초기 사용자 이름 : 관리자" + echo "초기 비밀번호 : changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "앱이 업데이트되었습니다" } @@ -10261,7 +10267,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10308,7 +10314,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10324,7 +10330,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10586,7 +10592,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd docker run -d \ --name libretv \ @@ -10607,32 +10613,55 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" + + docker_app_install() { + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "인증 코드를 입력하십시오." shouquanma + + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv + + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } + - read -e -p "设置MoonTV的登录密码: " app_passwd + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d + } - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "앱이 제거되었습니다" } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker_app_plus ;; @@ -10702,8 +10731,8 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录用户名: " app_use - read -e -p "设置${docker_name}的登录密码: " app_passwd + read -e -p "로그인 사용자 이름 설정 :" app_use + read -e -p "로그인 비밀번호 설정 :" app_passwd docker run -d \ --name xunlei \ @@ -10800,11 +10829,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # 임의의 키와 암호를 생성합니다 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -10813,17 +10842,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 관리자 계정 정보를 추가하십시오 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # 컨테이너를 시작하십시오 docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10833,7 +10862,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 원래 변수를 유지하십시오 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -10850,7 +10879,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10900,7 +10929,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10918,10 +10947,12 @@ while true; do docker_rum() { + read -e -p "설정${docker_name}SK-159KEJILIONYYDS163 :와 같은 로그인 키 (SK 별 문자 및 숫자 조합) :" app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10929,7 +10960,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app @@ -11020,7 +11051,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11033,7 +11064,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11136,6 +11167,239 @@ while true; do ;; + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) + clear + send_stats "모든 응용 프로그램 백업" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "백업 파일이 작성되었습니다 : /$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + case "$choice" in + [Yy]) + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + if [ -z "$remote_ip" ]; then + echo "오류 : 원격 서버 IP를 입력하십시오." + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." + else + echo "전송할 파일은 찾을 수 없었습니다." + fi + break + ;; + *) + echo "참고 : 현재 백업에는 Docker 프로젝트 만 포함되어 있으며 Pagoda 및 1Panel과 같은 웹 사이트 구축 패널의 데이터 백업은 포함되지 않습니다." + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "모든 응용 프로그램이 복원됩니다" + echo "사용 가능한 앱 백업" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." + else + echo "압축 패키지가 발견되지 않았습니다." + fi + + ;; + 0) kejilion ;; @@ -11153,35 +11417,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "백엔드 작업 공간" + echo -e "백엔드 작업 공간" + echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." + echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." + echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "현재 기존 작업 공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" + echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" + echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" + echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" + echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" + echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" + echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" + echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" + echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" + echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -11189,7 +11453,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -11197,63 +11461,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -11265,21 +11529,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH 거주 모드" + echo -e "SSH 거주 모드${tmux_sshd_status}" + echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 2를 켜십시오. 2를 끕니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "선택을 입력하십시오 :" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "작업 공간을 시작하십시오$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11295,29 +11559,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "사용자 정의 작업 공간" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "배경 작업 공간에 명령을 주입합니다" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "작업 공간을 삭제합니다" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -11342,54 +11606,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # Send_stats "시스템 도구" + echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" + echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" + echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" + echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" + echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" + echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" + echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "바로 가기 키가 설정되어 있습니다" + send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings done @@ -11397,34 +11661,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "로그인 비밀번호를 설정하십시오" + echo "로그인 비밀번호를 설정하십시오" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "루트 비밀번호 모드" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "PY 버전 관리" + echo "파이썬 버전 관리" + echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" + echo "더 많은 버전 : https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "스크립트 PY 관리" break_end linux_Settings fi @@ -11457,7 +11721,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi @@ -11486,55 +11750,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + send_stats "스크립트 Py 버전을 스위치하십시오" ;; 5) root_use - send_stats "开放端口" + send_stats "포트 열기" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "모든 포트가 열려 있습니다" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSH 포트를 수정하십시오" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 현재 SSH 포트 번호를 읽으십시오 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 현재 SSH 포트 번호를 인쇄하십시오 + echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 + read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port - # 判断端口号是否在有效范围内 + # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH 포트가 수정되었습니다" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSH 포트 수정을 종료하십시오" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "입력이 유효하지 않으므로 번호를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi done @@ -11553,8 +11817,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "신규 사용자는 루트를 비활성화합니다" + read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -11569,49 +11833,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6 우선 순위를 설정하십시오" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6 우선 순위를 설정하십시오" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "선호하는 네트워크를 선택하십시오." choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4 우선 순위로 전환되었습니다" + send_stats "IPv4 우선 순위로 전환되었습니다" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6 우선 순위로 전환되었습니다" + send_stats "IPv6 우선 순위로 전환되었습니다" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 마스터 JHB가 제공합니다." + send_stats "IPv6 수정" ;; *) @@ -11629,43 +11893,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "가상 메모리를 설정합니다" while true; do clear - echo "设置虚拟内存" + echo "가상 메모리를 설정합니다" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G 가상 메모리가 설정되었습니다" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G 가상 메모리가 설정되었습니다" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "사용자 정의 가상 메모리가 설정되었습니다" ;; *) @@ -11678,8 +11942,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "사용자 관리" + echo "사용자 목록" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -11690,62 +11954,62 @@ EOF echo "" - echo "账户操作" + echo "계정 운영" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." echo "------------------------" - echo "5. 删除账号" + echo "5. 계정을 삭제하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 새로운 사용자에게 허가를 부여하십시오 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # 새로운 사용자에게 허가를 부여하십시오 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "삭제하려면 사용자 이름을 입력하십시오." username + # 사용자와 홈 디렉토리를 삭제하십시오 userdel -r "$username" ;; @@ -11758,50 +12022,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "사용자 정보 생성기" + echo "임의의 사용자 이름" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "임의의 사용자 이름$i: $username" done echo "" - echo "随机姓名" + echo "임의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5 개의 임의의 사용자 이름을 생성합니다 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "임의의 사용자 이름$i: $user_name" done echo "" - echo "随机UUID" + echo "무작위 uuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "무작위 uuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" - echo "32位随机密码" + echo "32 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" @@ -11809,46 +12073,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "시간대를 변경하십시오" while true; do clear - echo "系统时间信息" + echo "시스템 시간 정보" - # 获取当前系统时区 + # 현재 시스템 시간대를 얻으십시오 local timezone=$(current_timezone) - # 获取当前系统时间 + # 현재 시스템 시간을 얻으십시오 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # 시간대와 시간을 보여줍니다 + echo "현재 시스템 시간대 :$timezone" + echo "현재 시스템 시간 :$current_time" echo "" - echo "时区切换" + echo "시간대 스위칭" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "아시아" + echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" + echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" + echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" + echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" + echo "9. 태국 방콕에서의 시간" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "유럽" + echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" + echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" + echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "미국" + echo "21. 서양 시간 22. 동부 시간" + echo "23. 캐나다 시간 24. 멕시코 시간" + echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC 글로벌 표준 시간" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -11891,21 +12155,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "호스트 이름을 수정하십시오" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian, Ubuntu, Centos 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -11923,11 +12187,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" + send_stats "호스트 이름이 변경되었습니다" sleep 1 else - echo "已退出,未更改主机名。" + echo "종료, 호스트 이름이 변경되지 않았습니다." break fi done @@ -11935,32 +12199,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "시스템 업데이트 소스를 변경하십시오" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "업데이트 소스 영역을 선택하십시오" + echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "중국 본토의 기본 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "중국 본토의 교육 원" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "해외 출신" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "취소" ;; esac @@ -11968,62 +12232,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "타이밍 작업 관리" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "시간이 정한 작업 목록" crontab -l echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. 월간 작업 2. 주간 작업" + echo "3. 일일 작업 4. 시간당 작업" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "선택을 입력하십시오 :" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "시간이 정한 작업을 추가하십시오" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "타이밍 작업을 삭제하십시오" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "타이밍 작업 편집" ;; *) break # 跳出循环,退出菜单 @@ -12035,32 +12299,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "지역 호스트 구문 분석" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "기본 호스트 구문 분석 목록" + echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." cat /etc/hosts echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "로컬 호스트 구문 분석이 추가되었습니다" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "로컬 호스트 구문 분석 및 삭제" ;; *) break # 跳出循环,退出菜单 @@ -12071,7 +12335,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH 방어" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12083,20 +12347,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH 방어 프로그램$check_docker" + echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" + echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. SSH 차단 레코드보기" + echo "3. 실시간 로그 모니터링" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램을 제거하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) install_docker @@ -12119,7 +12383,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2ban 방어 프로그램은 제거되었습니다" ;; *) break @@ -12132,47 +12396,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "현재 제한 종료 기능" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "현재 제한 종료 기능" + echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.sh 파일이 있는지 확인하십시오 if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gb의 값을 얻으십시오 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 새 가상 메모리 크기를 입력하십시오 + echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." + read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day cz_day=${cz_day:-1} cd ~ @@ -12185,15 +12449,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "전류 제한 종료가 설정되었습니다" + send_stats "전류 제한 종료가 설정되었습니다" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "전류 제한 종료 기능이 꺼졌습니다" ;; *) break @@ -12206,40 +12470,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "개인 키 로그인" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "루트 비공개 키 로그인 모드" + echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "새로운 키를 생성하십시오" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "기존 공개 키를 가져옵니다" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "로컬 비밀 키를보십시오" echo "------------------------" - echo "公钥信息" + echo "공개 키 정보" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "개인 키 정보" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12255,18 +12519,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "전보 경고" + echo "TG-BOT 모니터링 및 조기 경고 기능" + echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." + echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." + echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "전보 경고가 활성화되었습니다" cd ~ install nano tmux bc jq check_crontab_installed @@ -12288,7 +12552,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # ~/.profile 파일에 추가하십시오 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12299,21 +12563,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT 조기 경고 시스템이 시작되었습니다" + echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSH에서 고위험 취약점을 수정하십시오" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12357,7 +12621,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "명령 줄 기록" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12380,61 +12644,61 @@ EOF 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "게시판" + echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "원 스톱 튜닝" + echo "원 스톱 시스템 최적화" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "다음은 작동하고 최적화됩니다" + echo "1. 시스템을 최신으로 업데이트하십시오" + echo "2. 시스템 정크 파일 정리" + echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" + echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "5. 모든 포트를 엽니 다" + echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" + echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" + echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "원 스톱 튜닝 시작" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -12451,25 +12715,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" + echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac @@ -12477,7 +12741,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "시스템을 다시 시작하십시오" server_reboot ;; 100) @@ -12493,32 +12757,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" + echo "개인 정보 및 보안" echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "현재 상태 :$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. 수집을 켭니다" + echo "2. 컬렉션을 닫습니다" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "수집이 활성화되었습니다" + send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "컬렉션이 닫혔습니다" + send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" ;; *) break @@ -12534,11 +12798,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "기술 라이온 스크립트를 제거하십시오" + echo "기술 라이온 스크립트를 제거하십시오" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -12546,16 +12810,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "대본은 제거되었습니다." break_end clear exit ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -12565,7 +12829,7 @@ EOF ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -12583,187 +12847,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "파일 관리자" while true; do clear - echo "文件管理器" + echo "파일 관리자" echo "------------------------" - echo "当前路径" + echo "현재 경로" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" + echo "15. 파일을 삭제하십시오" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" + echo "25. 파일을 다른 서버로 전달합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" + send_stats "디렉토리로 이동하십시오" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname + mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" + send_stats "디렉토리를 만듭니다" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "디렉토리 권한을 수정하십시오" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name + read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "디렉토리의 이름을 바꿉니다" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname + rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "디렉토리 삭제" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "이전 메뉴 디렉토리로 돌아갑니다" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "작성하려면 파일 이름을 입력하십시오." filename + touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" + send_stats "파일을 만듭니다" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "편집 할 파일 이름을 입력하십시오." filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "파일 편집" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "파일 이름을 입력하십시오 :" filename + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "파일 권한을 수정하십시오" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "현재 파일 이름을 입력하십시오 :" current_name + read -e -p "새 파일 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "파일의 이름을 바꿉니다" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "삭제하려면 파일 이름을 입력하십시오." filename + rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "파일 삭제" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" + send_stats "압축 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" + send_stats "압축 파일/디렉토리 해제" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "이동 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" + send_stats "파일 또는 디렉토리를 이동하십시오" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 + cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" + send_stats "파일 또는 디렉토리를 복사합니다" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "오류 : 파일이 존재하지 않습니다." + send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "오류 : 원격 서버 IP를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "오류 : 원격 서버 비밀번호를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 알려진 호스트를위한 오래된 항목을 명확하게합니다 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCP를 사용하여 파일을 전송합니다 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "스크립트는 최신입니다$sh_v_new" break_end ~/kejilion.sh exit @@ -13061,15 +13325,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" + send_stats "자동 스크립트 업데이트를 켜십시오" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" + send_stats "스크립트 자동 업데이트를 닫습니다" break_end ;; *) @@ -13091,41 +13355,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" +echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" -echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" -echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" +echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" +echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" +echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" +echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" +echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" +echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" +echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" +echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" +echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" +echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" +echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" +echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" +echo -e "${gl_kjlan}15. ${gl_bai}광고 열" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "선택을 입력하십시오 :" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; + 3) clear ; send_stats "시스템 정리" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "워프 관리" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13136,13 +13400,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "잘못된 입력!" ;; esac break_end done @@ -13150,68 +13414,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "K 명령 참조 사용 사례" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "다음은 K 명령 참조 유스 케이스입니다." +echo "스크립트 시작 k" +echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" +echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" +echo "업데이트 시스템 K 업데이트 | K 업데이트" +echo "깨끗한 시스템 쓰레기 K Clean | K 청소" +echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" +echo "BBR3 제어판 K BBR3 | K bbrv3" +echo "커널 튜닝 패널 K nhyh | K 커널 최적화" +echo "가상 메모리 K 스왑 2048을 설정하십시오" +echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" +echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" +echo "시스템 백업 기능 K 백업 | K bf | K 백업" +echo "SSH 원격 연결 도구 K SSH | K 원격 연결" +echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" +echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" +echo "인트라넷 침투 (서버 측) K frps" +echo "인트라넷 침투 (클라이언트) K frpc" +echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" +echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" +echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" +echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" +echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" +echo "도메인 이름 인증서 응용 프로그램 K SSL" +echo "도메인 이름 인증서 만료 쿼리 K SSL PS" +echo "도커 환경 설치 K 도커 설치 | K 도커 설치" +echo "Docker Container Management K Docker PS | K 도커 컨테이너" +echo "Docker Image Management K Docker img | K Docker Image" +echo "LDNMP 사이트 관리 K 웹" +echo "LDNMP 캐시 정리 K 웹 캐시" +echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" +echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." +echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" +echo "방화벽 패널 K FHQ | K 방화벽" +echo "포트 k dkdk 8080 | k 오픈 포트 8080" +echo "포트 K GBDK 7800 | K 닫기 포트 7800" +echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" +echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" +echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" +echo "앱 시장 관리 K 앱" +echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 매개 변수가없는 경우 대화식 로직을 실행하십시오 kejilion_sh else - # 如果有参数,执行相应函数 + # 매개 변수가있는 경우 해당 함수를 실행하십시오 case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "소프트웨어를 설치하십시오" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "소프트웨어를 제거하십시오" remove "$@" ;; update|更新) @@ -13245,7 +13509,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "시간이 정한 RSYNC 동기화" run_task "$@" ;; @@ -13264,7 +13528,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13277,13 +13541,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "가상 메모리를 신속하게 설정했습니다" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "시간대를 빠르게 설정하십시오" set_timedate "$@" ;; @@ -13331,42 +13595,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "소프트웨어 상태보기" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "소프트웨어 시작" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "소프트웨어 일시 정지" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "소프트웨어 재시작" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "소프트웨어 부츠" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "인증서 상태를 확인하십시오" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" else k_info fi @@ -13376,15 +13640,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Docker를 신속하게 설치하십시오" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "빠른 컨테이너 관리" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "빠른 미러 관리" docker_image ;; *) @@ -13411,7 +13675,7 @@ else app) shift - send_stats "应用$@" + send_stats "$@ 적용" linux_panel "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 7860f9ecf..61a4f8c73 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.8" +sh_v="4.0.10" gl_hui='\e[37m' @@ -3682,7 +3682,7 @@ add_forwarding_service() { send_stats "添加frp內網服務" # 提示用戶輸入服務名稱和轉發信息 read -e -p "請輸入服務名稱:" service_name - read -e -p "請輸入轉發類型 (tcp/udp) [回車默認tcp]:" service_type + read -e -p "請輸入轉發類型 (tcp/udp) [回​​車默認tcp]:" service_type local service_type=${service_type:-tcp} read -e -p "請輸入內網IP [回車默認127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -8534,6 +8534,11 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8687,7 +8692,8 @@ while true; do docker_rum() { - + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -8696,8 +8702,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=ubuntu-abc \ - -e PASSWORD=ubuntuABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -p ${docker_port}:3000 \ -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -8711,8 +8717,8 @@ while true; do local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: ubuntu-abc\"" - local docker_passwd="echo \"密码: ubuntuABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app @@ -9383,7 +9389,8 @@ while true; do docker_rum() { - + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -9392,8 +9399,8 @@ while true; do -e TZ=Etc/UTC \ -e SUBFOLDER=/ \ -e TITLE=Webtop \ - -e CUSTOM_USER=webtop-abc \ - -e PASSWORD=webtopABC123 \ + -e CUSTOM_USER=${admin} \ + -e PASSWORD=${admin_password} \ -e LC_ALL=zh_CN.UTF-8 \ -e DOCKER_MODS=linuxserver/mods:universal-package-install \ -e INSTALL_PACKAGES=font-noto-cjk \ @@ -9404,14 +9411,13 @@ while true; do --restart unless-stopped \ lscr.io/linuxserver/webtop:latest - } local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" - local docker_use="echo \"用户名: webtop-abc\"" - local docker_passwd="echo \"密码: webtopABC123\"" + local docker_use="" + local docker_passwd="" local app_size="2" docker_app ;; @@ -10607,32 +10613,55 @@ while true; do ;; + 74|moontv) local app_id="74" - local docker_name="moontv" - local docker_img="ghcr.io/senshinya/moontv:latest" - local docker_port=8074 - docker_rum() { + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local docker_name="moontv-core" + local docker_port="8074" + local app_size="2" + + docker_app_install() { + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "輸入授權碼:" shouquanma + + + mkdir -p /home/docker/moontv + mkdir -p /home/docker/moontv/config + mkdir -p /home/docker/moontv/data + cd /home/docker/moontv + + curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml + sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + cd /home/docker/moontv/ + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } - read -e -p "設置MoonTV的登錄密碼:" app_passwd - docker run -d \ - --name moontv \ - --restart unless-stopped \ - -p ${docker_port}:3000 \ - -e PASSWORD=${app_passwd} \ - ghcr.io/senshinya/moontv:latest + docker_app_update() { + cd /home/docker/moontv/ && docker compose down --rmi all + cd /home/docker/moontv/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/moontv/ && docker compose down --rmi all + rm -rf /home/docker/moontv + echo "應用已卸載" } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/senshinya/MoonTV" - local docker_use="" - local docker_passwd="" - local app_size="1" - docker_app + docker_app_plus ;; @@ -10702,8 +10731,8 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登錄用戶名:" app_use - read -e -p "設定${docker_name}的登錄密碼:" app_passwd + read -e -p "設置登錄用戶名:" app_use + read -e -p "設置登錄密碼:" app_passwd docker run -d \ --name xunlei \ @@ -10918,10 +10947,12 @@ while true; do docker_rum() { + read -e -p "設定${docker_name}的登錄密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ -p ${docker_port}:3001 \ - -e AUTH_KEY=sk-123456 \ + -e AUTH_KEY=${app_passwd} \ -v "/home/docker/gpt-load/data":/app/data \ tbphp/gpt-load:latest @@ -10929,7 +10960,7 @@ while true; do local docker_describe="高性能AI接口透明代理服务" local docker_url="官网介绍: https://www.gpt-load.com/" - local docker_use="echo \"默认管理密钥: sk-123456\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app @@ -11136,6 +11167,239 @@ while true; do ;; + + 89|file-code-box) + + local app_id="89" + local docker_name="file-code-box" + local docker_img="lanol/filecodebox:latest" + local docker_port=8089 + + docker_rum() { + + docker run -d \ + --name file-code-box \ + -p ${docker_port}:12345 \ + -v /home/docker/file-code-box/data:/app/data \ + --restart unless-stopped \ + lanol/filecodebox:latest + + } + + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + + 90|matrix) + + local app_id="90" + local docker_name="matrix" + local docker_img="matrixdotorg/synapse:latest" + local docker_port=8090 + + docker_rum() { + + add_yuming + + if [ ! -d /home/docker/matrix/data ]; then + docker run -it --rm \ + -v /home/docker/matrix/data:/data \ + -e SYNAPSE_SERVER_NAME=${yuming} \ + -e SYNAPSE_REPORT_STATS=yes \ + --name matrix \ + matrixdotorg/synapse:latest generate + fi + + docker run -d \ + --name matrix \ + -v /home/docker/matrix/data:/data \ + -p ${docker_port}:8008 \ + --restart unless-stopped \ + matrixdotorg/synapse:latest + + echo "創建初始用戶或管理員。請設置以下內容用戶名和密碼以及是否為管理員。" + docker exec -it matrix register_new_matrix_user \ + http://localhost:8008 \ + -c /data/homeserver.yaml + + sed -i '/^enable_registration:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration: true' /home/docker/matrix/data/homeserver.yaml + sed -i '/^enable_registration_without_verification:/d' /home/docker/matrix/data/homeserver.yaml + sed -i '/^# vim:ft=yaml/i enable_registration_without_verification: true' /home/docker/matrix/data/homeserver.yaml + + docker restart matrix + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + } + + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 91|gitea) + + local app_id="91" + + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: https://github.com/go-gitea/gitea" + local docker_name="gitea" + local docker_port="8091" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/gitea + mkdir -p /home/docker/gitea/gitea + mkdir -p /home/docker/gitea/data + mkdir -p /home/docker/gitea/postgres + cd /home/docker/gitea + + curl -o /home/docker/gitea/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/gitea-docker-compose.yml + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/gitea/docker-compose.yml + cd /home/docker/gitea/ + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/gitea/ && docker compose down --rmi all + cd /home/docker/gitea/ && docker compose up -d + } + + + docker_app_uninstall() { + cd /home/docker/gitea/ && docker compose down --rmi all + rm -rf /home/docker/gitea + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + + 92|filebrowser) + + local app_id="92" + local docker_name="filebrowser" + local docker_img="hurlenko/filebrowser" + local docker_port=8092 + + docker_rum() { + + docker run -d \ + --name filebrowser \ + --restart unless-stopped \ + -p ${docker_port}:8080 \ + -v /home/docker/filebrowser/data:/data \ + -v /home/docker/filebrowser/config:/config \ + -e FB_BASEURL=/filebrowser \ + hurlenko/filebrowser + + } + + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" + local docker_use="docker logs filebrowser" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + b) + clear + send_stats "全部應用備份" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "備份文件已創建: /$backup_filename" + read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice + case "$choice" in + [Yy]) + read -e -p "請輸入遠端服務器IP:" remote_ip + if [ -z "$remote_ip" ]; then + echo "錯誤: 請輸入遠端服務器IP。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "文件已傳送至遠程服務器/根目錄。" + else + echo "未找到要傳送的文件。" + fi + break + ;; + *) + echo "注意: 目前備份僅包含docker項目,不包含寶塔,1panel等建站面板的數據備份。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "全部應用還原" + echo "可用的應用備份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 如果用戶沒有輸入文件名,使用最新的壓縮包 + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "應用數據已還原,目前請手動進入指定應用菜單,更新應用,即可還原應用。" + else + echo "沒有找到壓縮包。" + fi + + ;; + 0) kejilion ;; @@ -11295,7 +11559,7 @@ linux_work() { ;; 22) - read -e -p "請輸入你創建或進入的工作區名稱,如1001 kj001 work1:" SESSION_NAME + read -e -p "請輸入你創建或進入的工作區名稱,如1​​001 kj001 work1:" SESSION_NAME tmux_run send_stats "自定義工作區" ;; From 987220f7f54f0436e9d4396a4dd566bca0a89e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:11:01 +0800 Subject: [PATCH 0093/1285] Update kejilion.sh --- cn/kejilion.sh | 389 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 316 insertions(+), 73 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4a8bb24c6..cad5a9a25 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}请使用 root 权限运行脚本!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Docker 未安装!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}jq 未安装!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}当前备份列表:${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + } + + + + # ---------------------------- + # 备份 + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + + # 记录已打包过的 Compose 项目路径,避免重复打包 + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}备份容器: $c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "未检测到 compose 目录,请手动输入路径: " project_dir + fi + + # 如果该 Compose 项目已经打包过,跳过 + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + else + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + fi + else + # 普通容器备份卷 + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "打包卷: $path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # 端口 + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # 环境变量 + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # 卷映射 + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # 镜像 + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # 还原 + # ---------------------------- + restore_docker() { + list_backups + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" + + install_docker + + # --------- 优先还原 Compose 项目 --------- + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + + # 检查该 compose 项目的容器是否已经在运行 + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + continue + fi + + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + fi + done + + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}处理容器: $container${NC}" + + # 检查容器是否已经存在且正在运行 + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + + # 端口映射 + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # 环境变量 + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # 卷映射 + 卷数据恢复 + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "恢复卷数据: $VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # 删除已存在但未运行的容器 + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + docker rm -f "$container" + fi + + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + } + + + # ---------------------------- + # 迁移 + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}传输备份中...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # 使用密钥登录 + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # 删除备份 + # ---------------------------- + delete_backup() { + list_backups + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # 主菜单 + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "Docker 备份 / 迁移 / 还原 工具 v1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\n1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" + echo -e "0. 返回主菜单 / 退出" + read -p "请选择: " choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}无效选项${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}备份/还原/迁移Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker v6 开" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Docker卸载" @@ -8538,8 +8851,6 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" - echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -9815,8 +10126,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11330,76 +11643,6 @@ while true; do ;; - - - b) - clear - send_stats "全部应用备份" - - local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" - cd / && tar czvf "$backup_filename" home - - while true; do - clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice - case "$choice" in - [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi - local latest_tar=$(ls -t /app*.tar.gz | head -1) - if [ -n "$latest_tar" ]; then - ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" - sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" - else - echo "未找到要传送的文件。" - fi - break - ;; - *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" - break - ;; - esac - done - - ;; - - r) - root_use - send_stats "全部应用还原" - echo "可用的应用备份" - echo "-------------------------" - ls -lt /app*.gz | awk '{print $NF}' - echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename - - if [ "$filename" == "0" ]; then - break_end - linux_panel - fi - - # 如果用户没有输入文件名,使用最新的压缩包 - if [ -z "$filename" ]; then - local filename=$(ls -t /app*.tar.gz | head -1) - fi - - if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" - cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" - else - echo "没有找到压缩包。" - fi - - ;; - 0) kejilion ;; From dc9fba201f5010c1ebedad00d1041a6251e6834a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:11:32 +0800 Subject: [PATCH 0094/1285] Implement Docker backup and restore features Add Docker backup, restore, and migration functions --- kejilion.sh | 389 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 316 insertions(+), 73 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ff076970f..b9640481a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}请使用 root 权限运行脚本!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Docker 未安装!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}jq 未安装!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}当前备份列表:${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + } + + + + # ---------------------------- + # 备份 + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + + # 记录已打包过的 Compose 项目路径,避免重复打包 + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}备份容器: $c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "未检测到 compose 目录,请手动输入路径: " project_dir + fi + + # 如果该 Compose 项目已经打包过,跳过 + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + else + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + fi + else + # 普通容器备份卷 + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "打包卷: $path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # 端口 + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # 环境变量 + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # 卷映射 + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # 镜像 + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # 还原 + # ---------------------------- + restore_docker() { + list_backups + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" + + install_docker + + # --------- 优先还原 Compose 项目 --------- + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + + # 检查该 compose 项目的容器是否已经在运行 + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + continue + fi + + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + fi + done + + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}处理容器: $container${NC}" + + # 检查容器是否已经存在且正在运行 + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + + # 端口映射 + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # 环境变量 + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # 卷映射 + 卷数据恢复 + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "恢复卷数据: $VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # 删除已存在但未运行的容器 + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + docker rm -f "$container" + fi + + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + } + + + # ---------------------------- + # 迁移 + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}传输备份中...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # 使用密钥登录 + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # 删除备份 + # ---------------------------- + delete_backup() { + list_backups + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # 主菜单 + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "Docker 备份 / 迁移 / 还原 工具 v1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\n1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" + echo -e "0. 返回主菜单 / 退出" + read -p "请选择: " choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}无效选项${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}备份/还原/迁移Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker v6 开" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Docker卸载" @@ -8538,8 +8851,6 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" - echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -9815,8 +10126,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11330,76 +11643,6 @@ while true; do ;; - - - b) - clear - send_stats "全部应用备份" - - local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" - cd / && tar czvf "$backup_filename" home - - while true; do - clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice - case "$choice" in - [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi - local latest_tar=$(ls -t /app*.tar.gz | head -1) - if [ -n "$latest_tar" ]; then - ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" - sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" - else - echo "未找到要传送的文件。" - fi - break - ;; - *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" - break - ;; - esac - done - - ;; - - r) - root_use - send_stats "全部应用还原" - echo "可用的应用备份" - echo "-------------------------" - ls -lt /app*.gz | awk '{print $NF}' - echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename - - if [ "$filename" == "0" ]; then - break_end - linux_panel - fi - - # 如果用户没有输入文件名,使用最新的压缩包 - if [ -z "$filename" ]; then - local filename=$(ls -t /app*.tar.gz | head -1) - fi - - if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" - cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" - else - echo "没有找到压缩包。" - fi - - ;; - 0) kejilion ;; From 2e81378127f8eb165258f666c169dd5326bc19ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:18:17 +0800 Subject: [PATCH 0095/1285] Update changelog for version 4.1.0 --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 097b5ba1d..8cce2f0e0 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1279,3 +1279,8 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 应用市场新增gitea私有代码仓库的安装及使用, 应用市场新增filebrowser文件管理器的安装及使用, ------------------------ +2025-08-24 v4.1.0 +docker管理增加全局备份还原迁移功能。 +修复部分应用的部署不成功问题, +------------------------ + From 540792e8bff9854d3c9af9fd6266fdb42157ce9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:18:50 +0800 Subject: [PATCH 0096/1285] Implement application backup and restore options Add backup and restore functionality for applications. --- cn/kejilion.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cad5a9a25..508ee0c6f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8851,6 +8851,8 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -11643,6 +11645,76 @@ while true; do ;; + + b) + clear + send_stats "全部应用备份" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + case "$choice" in + [Yy]) + read -e -p "请输入远端服务器IP: " remote_ip + if [ -z "$remote_ip" ]; then + echo "错误: 请输入远端服务器IP。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "文件已传送至远程服务器/根目录。" + else + echo "未找到要传送的文件。" + fi + break + ;; + *) + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + else + echo "没有找到压缩包。" + fi + + ;; + + 0) kejilion ;; From 7beb25a757e2073462525532d0a80b0b7f009e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:19:21 +0800 Subject: [PATCH 0097/1285] Implement application data backup and restore Add backup and restore functionality for applications --- kejilion.sh | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index b9640481a..9878c10a8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8851,6 +8851,8 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " sub_choice @@ -11643,6 +11645,76 @@ while true; do ;; + + b) + clear + send_stats "全部应用备份" + + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home + + while true; do + clear + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + case "$choice" in + [Yy]) + read -e -p "请输入远端服务器IP: " remote_ip + if [ -z "$remote_ip" ]; then + echo "错误: 请输入远端服务器IP。" + continue + fi + local latest_tar=$(ls -t /app*.tar.gz | head -1) + if [ -n "$latest_tar" ]; then + ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" + sleep 2 # 添加等待时间 + scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + echo "文件已传送至远程服务器/根目录。" + else + echo "未找到要传送的文件。" + fi + break + ;; + *) + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + break + ;; + esac + done + + ;; + + r) + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then + break_end + linux_panel + fi + + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then + local filename=$(ls -t /app*.tar.gz | head -1) + fi + + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + else + echo "没有找到压缩包。" + fi + + ;; + + 0) kejilion ;; From 8193b81c5f73fc012c4027ce0cb569d54a651082 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 24 Aug 2025 07:14:44 +0000 Subject: [PATCH 0098/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-24=2007:14:44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 331 +++++++++++++++++++++++++++++++++++++++++-- jp/kejilion.sh | 373 +++++++++++++++++++++++++++++++++++++++++++++---- kr/kejilion.sh | 341 ++++++++++++++++++++++++++++++++++++++++++-- tw/kejilion.sh | 319 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 1312 insertions(+), 52 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index fef2761c3..8b8f2673f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -2121,7 +2121,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -5959,7 +5959,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can be connected to other Linux systems via SSH" + echo "Can connect to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}Please use root permissions to run the script!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Docker not installed!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}jq not installed!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}Current backup list:${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "No backup" + } + + + + # ---------------------------- + # Backup + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}Backing up Docker container...${NC}" + read -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}No container found${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "# Automatically generated restore script" >> "$RESTORE_SCRIPT" + + # Record the path of the packaged Compose project to avoid duplicate packaging + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}Backup container:$c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}Detected$cYes docker-compose container${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "The compose directory is not detected, please enter the path manually:" project_dir + fi + + # If the Compose project has been packaged, skip it + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "# docker-compose recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}Compose project [$project_name] Packed:${project_dir}${NC}" + else + echo -e "${RED}docker-compose.yml not found, skip this container...${NC}" + fi + else + # Normal container backup volume + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "Packing rolls:$path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # port + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # Environment variables + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # Volume Mapping + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # Mirror + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\n# Restore container:$c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}Backup is complete:${BACKUP_DIR}${NC}" + echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # reduction + # ---------------------------- + restore_docker() { + list_backups + read -p "Please enter the backup directory to restore:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + + echo -e "${BLUE}Start the restore operation...${NC}" + + install_docker + + # ------------------------- + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "The original path was not found, please enter the restore directory path:" original_path + + # Check if the container for the compose project is already running + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" + continue + fi + + read -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "Please enter a new restore path:" original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}Compose project [$project_name] Decompressed to:$original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}Compose project [$project_name] Restore is complete!${NC}" + fi + done + + # ------------------------- + echo -e "${BLUE}Check and restore a normal Docker container...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}Processing container:$container${NC}" + + # Check if the container already exists and is running + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}Container [$container] is running, skip restore...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information was not found, skip:$container${NC}"; continue; } + + # Port Mapping + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # Environment variables + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # Volume Mapping + Volume Data Recovery + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "Recover volume data:$VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # Delete existing but not running containers + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}Container [$container] Exist but not running, delete the old container...${NC}" + docker rm -f "$container" + fi + + # Start the container + echo "Execute the restore command: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for normal containers was found${NC}" + } + + + # ---------------------------- + # migrate + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "Please enter the backup directory to migrate:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + + read -p "Target server IP:" TARGET_IP + read -p "Target server SSH username:" TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}Transfer backup...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # Log in with a key + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # Delete backup + # ---------------------------- + delete_backup() { + list_backups + read -p "Please enter the backup directory to delete:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # Main Menu + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "Docker Backup/Migration/Restore Tool v1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\n1. Backup docker project" + echo -e "2. Migrate docker projects" + echo -e "3. Restore the docker project" + echo -e "4. Delete the backup file of the docker project" + echo -e "0. Return to main menu / Exit" + read -p "Please select:" choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}Invalid option${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}Backup/restore/migrate Docker environment" echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker v6 open" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Docker uninstall" @@ -7924,7 +8237,7 @@ linux_ldnmp() { ;; 2) echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter to skip remote download:" url_download_db + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -9815,8 +10128,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11331,7 +11646,6 @@ while true; do ;; - b) clear send_stats "All applications backup" @@ -11400,6 +11714,7 @@ while true; do ;; + 0) kejilion ;; @@ -12096,7 +12411,7 @@ EOF echo "3. Tokyo time in Japan 4. Seoul time in South Korea" echo "5. Singapore time 6. Kolkata time in India" echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Bangkok Time, Thailand" + echo "9. Time in Bangkok, Thailand" echo "------------------------" echo "Europe" echo "11. London time in the UK 12. Paris time in France" @@ -12322,7 +12637,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -12759,7 +13074,7 @@ EOF echo "Privacy and Security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index acf73106d..ba7180fb0 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -285,7 +285,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1サービスは再開されました。" else - echo "エラー:再起動$1サービスに失敗しました。" + echo "エラー:再起動$1サービスは失敗しました。" fi } @@ -295,7 +295,7 @@ start() { if [ $? -eq 0 ]; then echo "$1サービスが開始されました。" else - echo "エラー:開始$1サービスに失敗しました。" + echo "エラー:開始$1サービスは失敗しました。" fi } @@ -305,7 +305,7 @@ stop() { if [ $? -eq 0 ]; then echo "$1サービスは停止しました。" else - echo "エラー:停止します$1サービスに失敗しました。" + echo "エラー:停止します$1サービスは失敗しました。" fi } @@ -816,7 +816,7 @@ docker_ipv6_off() { return fi - # 現在の構成を読み取ります + # 現在の構成をお読みください local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # JQを使用して、構成ファイルの更新を処理します @@ -1668,7 +1668,7 @@ cf_purge_cache() { read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "API_TOKENを入力してください:" API_TOKEN read -e -p "CFユーザ​​ー名を入力してください:" EMAIL read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS @@ -1679,7 +1679,7 @@ cf_purge_cache() { # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_IDのキャッシュのクリア:$ZONE_ID" + echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -2121,10 +2121,10 @@ web_security() { 22) send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が自動的に5秒間オフになります。${gl_bai}" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" echo "CFパラメーターを取得します:" - echo -e "CFの背景の右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" + echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -6369,7 +6369,7 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクがすでに存在するかどうかを確認してください + # 同じタスクが既に存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then echo "エラー:このタスクのタイミング同期はすでに存在しています!" return @@ -6418,7 +6418,7 @@ rsync_manager() { echo echo "1.新しいタスクを作成します2。タスクを削除します" echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6.タイミングタスクを削除します" + echo "5.タイミングタスクを作成6。タイミングタスクを削除します" echo "---------------------------------" echo "0。前のメニューに戻ります" echo "---------------------------------" @@ -6551,7 +6551,7 @@ linux_tools() { echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}zip zip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" + echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}ルートアクセス許可を使用してスクリプトを実行してください!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Dockerがインストールされていません!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}JQがインストールされていません!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}現在のバックアップリスト:${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" + } + + + + # ---------------------------- + # バックアップ + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" + read -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナは見つかりません${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "#自動的に生成された復元スクリプト" >> "$RESTORE_SCRIPT" + + # パッケージ化されたプロジェクトのパスを記録して、パッケージの重複を避ける + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}バックアップコンテナ:$c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}検出されました$cはい、Docker-Composeコンテナ${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir + fi + + # Composeプロジェクトがパッケージ化されている場合は、スキップしてください + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}プロジェクトを作成する[$project_name]バックアップ、複製パッケージをスキップ...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "#docker-compose Recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}プロジェクトを作成する[$project_name]パック:${project_dir}${NC}" + else + echo -e "${RED}docker-compose.ymlが見つかりません、このコンテナをスキップしてください...${NC}" + fi + else + # 通常のコンテナバックアップボリューム + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "梱包ロール:$path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # ポート + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # 環境変数 + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # ボリュームマッピング + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # 鏡 + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\ n#復元コンテナ:$c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" + echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # 削減 + # ---------------------------- + restore_docker() { + list_backups + read -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + + echo -e "${BLUE}復元操作を開始します...${NC}" + + install_docker + + # ------------------------------ + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path + + # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}プロジェクトを作成する[$project_name]すでにコンテナが走っています、復元をスキップします...${NC}" + continue + fi + + read -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "新しい復元パスを入力してください:" original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}プロジェクトを作成する[$project_name]減圧:$original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}プロジェクトを作成する[$project_name]復元が完了しました!${NC}" + fi + done + + # ------------------------------ + echo -e "${BLUE}通常のDockerコンテナを確認して復元します...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}コンテナの処理:$container${NC}" + + # 容器が既に存在し、実行中かどうかを確認してください + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container]走っています、復元をスキップします...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報は見つかりませんでした、スキップ:$container${NC}"; continue; } + + # ポートマッピング + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # 環境変数 + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # ボリュームマッピング +ボリュームデータリカバリ + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "ボリュームデータの回復:$VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # 既存のが実行されていないコンテナを削除します + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container]存在しますが、実行していません。古いコンテナを削除してください...${NC}" + docker rm -f "$container" + fi + + # コンテナを起動します + echo "restoreコマンドを実行します:docker run -d - name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}通常のコンテナのバックアップ情報は見つかりませんでした${NC}" + } + + + # ---------------------------- + # 移動します + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + + read -p "ターゲットサーバーIP:" TARGET_IP + read -p "ターゲットサーバーSSHユーザー名:" TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}バックアップを転送...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # キーでログインします + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # バックアップを削除します + # ---------------------------- + delete_backup() { + list_backups + read -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # メインメニュー + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "Dockerバックアップ/移行/復元ツールv1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\ n1。バックアップDockerプロジェクト" + echo -e "2。Dockerプロジェクトを移行します" + echo -e "3. Dockerプロジェクトを復元します" + echo -e "4. Dockerプロジェクトのバックアップファイルを削除します" + echo -e "0。メインメニュー /終了に戻ります" + read -p "選択してください:" choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}無効なオプション${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}Docker環境をバックアップ/復元/移行します" echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker V6が開いています" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Dockerアンインストール" @@ -7580,7 +7893,7 @@ linux_ldnmp() { 4) clear - # ケダオクラウドデスクトップ + # Kedao Cloudデスクトップ webname="可道云桌面" send_stats "インストール$webname" echo "展開を開始します$webname" @@ -7924,7 +8237,7 @@ linux_ldnmp() { ;; 2) echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8221,7 +8534,7 @@ linux_ldnmp() { case $dingshi in 1) check_crontab_installed - read -e -p "毎週のバックアップの曜日を選択します(0-6、0は日曜日を表します):" weekday + read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) @@ -8805,7 +9118,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "郵便局を建設します" clear install telnet local app_id="9" @@ -8815,8 +9128,8 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," + echo -e "郵便局サービス$check_docker $update_status" + echo "Poste.ioはオープンソースメールサーバーソリューションです。" echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" @@ -9731,7 +10044,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoyaファミリーバケツ" + send_stats "Xiaoyaファミリーバケット" clear install_docker check_disk_space 1 @@ -9815,8 +10128,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11331,7 +11646,6 @@ while true; do ;; - b) clear send_stats "すべてのアプリケーションバックアップ" @@ -11400,6 +11714,7 @@ while true; do ;; + 0) kejilion ;; @@ -11684,11 +11999,11 @@ linux_Settings() { echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" echo "クエリの詳細:https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "スクリプトPy管理" break_end linux_Settings fi @@ -11751,7 +12066,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + send_stats "スイッチスクリプトPyバージョン" ;; @@ -12003,7 +12318,7 @@ EOF ;; 4) read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudo許可を削除します + # sudoersファイルからユーザーのsudoアクセス許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; @@ -12104,7 +12419,7 @@ EOF echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" echo "------------------------" echo "アメリカ" - echo "21. 美国西部时间 22. 美国东部时间" + echo "21。WesternTime22。東部時間" echo "23。カナダ時間24。メキシコの時間" echo "25。ブラジル時間26。アルゼンチン時間" echo "------------------------" @@ -12523,7 +12838,7 @@ EOF echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" read -e -p "必ず続行しますか? (y/n):" choice @@ -12759,7 +13074,7 @@ EOF echo "プライバシーとセキュリティ" echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" echo "--------------------" @@ -12857,7 +13172,7 @@ linux_file() { echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1。ディレクトリを入力します2。ディレクトリを作成3。ディレクトリアクセス許可を変更する4。ディレクトリの名前を変更します" + echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" echo "------------------------" echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" @@ -12958,7 +13273,7 @@ linux_file() { continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリは移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" send_stats "ファイルまたはディレクトリを移動します" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 114edc060..7ce8db11c 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1185,7 +1185,7 @@ iptables_panel() { 5) # IP 화이트리스트 - read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip + read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) @@ -2121,7 +2121,7 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" @@ -4989,7 +4989,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "감지 된 운영 체제 :$os_name $os_version" + echo "운영 체제 감지 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -5845,7 +5845,7 @@ add_connection() { echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함 된 경우 입력이 끝납니다. + # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6617,7 +6617,7 @@ linux_tools() { install iftop clear iftop - send_stats "Iftop을 설치하십시오" + send_stats "iftop을 설치하십시오" ;; 7) clear @@ -6760,7 +6760,7 @@ linux_tools() { 32) clear - send_stats "모든 설치 (게임 및 스크린 세이버 제외)" + send_stats "모든 설치 (게임 및 화면 보호기 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}루트 권한을 사용하여 스크립트를 실행하십시오!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Docker가 설치되지 않았습니다!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}JQ가 설치되지 않았습니다!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}현재 백업 목록 :${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" + } + + + + # ---------------------------- + # 지원 + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" + read -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너가 없습니다${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "# 자동으로 생성 된 복원 스크립트" >> "$RESTORE_SCRIPT" + + # 중복 포장을 피하기 위해 패키지 작곡 프로젝트의 경로를 기록하십시오. + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}백업 컨테이너 :$c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}감지$c예, Docker-compose 컨테이너${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir + fi + + # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}작곡 프로젝트 [$project_name] 백업, 중복 포장을 건너 뛰십시오 ...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "# Docker-Compose Recovery :$project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}작곡 프로젝트 [$project_name] 포장 :${project_dir}${NC}" + else + echo -e "${RED}docker-compose.yml을 찾을 수 없고이 컨테이너를 건너 뛰십시오 ...${NC}" + fi + else + # 일반 컨테이너 백업 볼륨 + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "포장 롤 :$path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # 포트 + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # 환경 변수 + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # 볼륨 매핑 + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # 거울 + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\ n# 복원 컨테이너 :$c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}백업이 완료되었습니다.${BACKUP_DIR}${NC}" + echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # 절감 + # ---------------------------- + restore_docker() { + list_backups + read -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + + echo -e "${BLUE}복원 작업 시작 ...${NC}" + + install_docker + + # ----------------------------- + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path + + # Compose 프로젝트 용 컨테이너가 이미 실행 중인지 확인하십시오. + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" + continue + fi + + read -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "새로운 복원 경로를 입력하십시오 :" original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}작곡 프로젝트 [$project_name] 압축 압축 : :$original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원이 완료되었습니다!${NC}" + fi + done + + # ----------------------------- + echo -e "${BLUE}일반적인 도커 컨테이너를 확인하고 복원하십시오 ...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}처리 컨테이너 :$container${NC}" + + # 컨테이너가 이미 존재하고 실행 중인지 확인하십시오 + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}컨테이너 [$container]는 실행 중입니다. 회복을 건너 뛰십시오 ...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}거울 정보는 찾을 수 없었습니다.$container${NC}"; continue; } + + # 포트 매핑 + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # 환경 변수 + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # 볼륨 매핑 + 볼륨 데이터 복구 + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "볼륨 데이터 복구 :$VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # 기존이지만 실행되지 않은 컨테이너를 삭제하십시오 + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}컨테이너 [$container] 존재하지만 실행되지 않고 오래된 컨테이너를 삭제합니다 ...${NC}" + docker rm -f "$container" + fi + + # 컨테이너를 시작하십시오 + echo "복원 명령 실행 : docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" + } + + + # ---------------------------- + # 마이그레이션 + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + + read -p "대상 서버 IP :" TARGET_IP + read -p "대상 서버 SSH 사용자 이름 :" TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}백업 전송 ...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # 키로 로그인하십시오 + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # 백업을 삭제하십시오 + # ---------------------------- + delete_backup() { + list_backups + read -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # 메인 메뉴 + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "도커 백업/마이그레이션/복원 도구 v1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\ n1. 백업 도커 프로젝트" + echo -e "2. Docker 프로젝트를 마이그레이션합니다" + echo -e "3. Docker 프로젝트를 복원하십시오" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" + echo -e "0. 메인 메뉴 / 종료로 돌아갑니다" + read -p "선택하십시오 :" choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}잘못된 옵션${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}백업/복원/Docker 환경을 마이그레이션합니다" echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker V6 열기" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Docker는 제거합니다" @@ -7924,7 +8237,7 @@ linux_ldnmp() { ;; 2) echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download_db + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -9815,8 +10128,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11331,7 +11646,6 @@ while true; do ;; - b) clear send_stats "모든 응용 프로그램 백업" @@ -11400,6 +11714,7 @@ while true; do ;; + 0) kejilion ;; @@ -12758,7 +13073,7 @@ EOF fi echo "개인 정보 및 보안" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." echo "------------------------------------------------" echo -e "현재 상태 :$status_message" @@ -12954,7 +13269,7 @@ linux_file() { read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then echo "오류 : 대상 경로를 입력하십시오." - send_stats "이동 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." + send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." continue fi @@ -13443,7 +13758,7 @@ echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타 echo "도메인 이름 인증서 응용 프로그램 K SSL" echo "도메인 이름 인증서 만료 쿼리 K SSL PS" echo "도커 환경 설치 K 도커 설치 | K 도커 설치" -echo "Docker Container Management K Docker PS | K 도커 컨테이너" +echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" echo "Docker Image Management K Docker img | K Docker Image" echo "LDNMP 사이트 관리 K 웹" echo "LDNMP 캐시 정리 K 웹 캐시" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 61a4f8c73..46bf61d4d 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.0.10" +sh_v="4.1.0" gl_hui='\e[37m' @@ -6850,6 +6850,310 @@ linux_bbr() { +docker_ssh_migration() { + + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[1;33m' + BLUE='\033[0;36m' + NC='\033[0m' + + BACKUP_ROOT="/tmp" + DATE_STR=$(date +%Y%m%d_%H%M%S) + + check_root() { + [[ "$EUID" -ne 0 ]] && { echo -e "${RED}請使用 root 權限運行腳本!${NC}"; exit 1; } + } + + ensure_docker() { + command -v docker &>/dev/null || { echo -e "${RED}Docker 未安裝!${NC}"; exit 1; } + } + + ensure_jq() { + command -v jq &>/dev/null || { echo -e "${RED}jq 未安裝!${NC}"; exit 1; } + } + + is_compose_container() { + local container=$1 + docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 + } + + list_backups() { + echo -e "${BLUE}當前備份列表:${NC}" + ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" + } + + + + # ---------------------------- + # 備份 + # ---------------------------- + backup_docker() { + echo -e "${YELLOW}正在備份 Docker 容器...${NC}" + read -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers + local TARGET_CONTAINERS=() + if [ -z "$containers" ]; then + mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') + else + read -ra TARGET_CONTAINERS <<< "$containers" + fi + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}沒有找到容器${NC}"; return; } + + local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" + mkdir -p "$BACKUP_DIR" + + local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" + echo "#!/bin/bash" > "$RESTORE_SCRIPT" + echo "set -e" >> "$RESTORE_SCRIPT" + echo "# 自動生成的還原腳本" >> "$RESTORE_SCRIPT" + + # 記錄已打包過的 Compose 項目路徑,避免重複打包 + declare -A PACKED_COMPOSE_PATHS=() + + for c in "${TARGET_CONTAINERS[@]}"; do + echo -e "${GREEN}備份容器:$c${NC}" + local inspect_file="${BACKUP_DIR}/${c}_inspect.json" + docker inspect "$c" > "$inspect_file" + + if is_compose_container "$c"; then + echo -e "${BLUE}檢測到$c是 docker-compose 容器${NC}" + local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') + local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') + + if [ -z "$project_dir" ]; then + read -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir + fi + + # 如果該 Compose 項目已經打包過,跳過 + if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then + echo -e "${YELLOW}Compose 項目 [$project_name] 已備份過,跳過重複打包...${NC}" + continue + fi + + if [ -f "$project_dir/docker-compose.yml" ]; then + echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" + echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" + tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . + echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" + echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" + PACKED_COMPOSE_PATHS["$project_dir"]=1 + echo -e "${GREEN}Compose 項目 [$project_name] 已打包:${project_dir}${NC}" + else + echo -e "${RED}未找到 docker-compose.yml,跳過此容器...${NC}" + fi + else + # 普通容器備份卷 + local VOL_PATHS + VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') + for path in $VOL_PATHS; do + echo "打包卷:$path" + tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" + done + + # 端口 + local PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) + for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done + + # 環境變量 + local ENV_VARS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") + for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done + + # 卷映射 + local VOL_ARGS="" + for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done + + # 鏡像 + local IMAGE + IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") + + echo -e "\n# 還原容器:$c" >> "$RESTORE_SCRIPT" + echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" + fi + done + + chmod +x "$RESTORE_SCRIPT" + echo -e "${GREEN}備份完成:${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用還原腳本:${RESTORE_SCRIPT}${NC}" + } + + # ---------------------------- + # 還原 + # ---------------------------- + restore_docker() { + list_backups + read -p "請輸入要還原的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + + echo -e "${BLUE}開始執行還原操作...${NC}" + + install_docker + + # --------- 優先還原 Compose 項目 --------- + for f in "$BACKUP_DIR"/backup_type_*; do + [[ ! -f "$f" ]] && continue + if grep -q "compose" "$f"; then + project_name=$(basename "$f" | sed 's/backup_type_//') + path_file="$BACKUP_DIR/compose_path_${project_name}.txt" + [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" + [[ -z "$original_path" ]] && read -p "未找到原始路徑,請輸入還原目錄路徑:" original_path + + # 檢查該 compose 項目的容器是否已經在運行 + running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) + if [[ "$running_count" -gt 0 ]]; then + echo -e "${YELLOW}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${NC}" + continue + fi + + read -p "確認還原 Compose 項目 [$project_name] 到路徑 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "請輸入新的還原路徑:" original_path + + mkdir -p "$original_path" + tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" + echo -e "${GREEN}Compose 項目 [$project_name] 已解壓到:$original_path${NC}" + + cd "$original_path" || exit 1 + docker compose down || true + docker compose up -d + echo -e "${GREEN}Compose 項目 [$project_name] 還原完成!${NC}" + fi + done + + # --------- 繼續還原普通容器 --------- + echo -e "${BLUE}檢查並還原普通 Docker 容器...${NC}" + local has_container=false + for json in "$BACKUP_DIR"/*_inspect.json; do + [[ ! -f "$json" ]] && continue + has_container=true + container=$(basename "$json" | sed 's/_inspect.json//') + echo -e "${GREEN}處理容器:$container${NC}" + + # 檢查容器是否已經存在且正在運行 + if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 已在運行,跳過還原...${NC}" + continue + fi + + IMAGE=$(jq -r '.[0].Config.Image' "$json") + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到鏡像信息,跳過:$container${NC}"; continue; } + + # 端口映射 + PORT_ARGS="" + mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") + for p in "${PORTS[@]}"; do + [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" + done + + # 環境變量 + ENV_ARGS="" + mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") + for e in "${ENVS[@]}"; do + ENV_ARGS="$ENV_ARGS -e \"$e\"" + done + + # 卷映射 + 卷數據恢復 + VOL_ARGS="" + mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") + for v in "${VOLS[@]}"; do + VOL_SRC=$(echo "$v" | cut -d':' -f1) + VOL_DST=$(echo "$v" | cut -d':' -f2) + mkdir -p "$VOL_SRC" + VOL_ARGS="$VOL_ARGS -v $VOL_SRC:$VOL_DST" + + VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" + if [[ -f "$VOL_FILE" ]]; then + echo "恢復卷數據:$VOL_SRC" + tar -xzf "$VOL_FILE" -C / + fi + done + + # 刪除已存在但未運行的容器 + if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then + echo -e "${YELLOW}容器 [$container] 存在但未運行,刪除舊容器...${NC}" + docker rm -f "$container" + fi + + # 啟動容器 + echo "執行還原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + done + + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的備份信息${NC}" + } + + + # ---------------------------- + # 遷移 + # ---------------------------- + migrate_docker() { + ensure_jq + list_backups + read -p "請輸入要遷移的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + + read -p "目標服務器IP:" TARGET_IP + read -p "目標服務器SSH用戶名:" TARGET_USER + + LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + + echo -e "${YELLOW}傳輸備份中...${NC}" + if [[ -z "$TARGET_PASS" ]]; then + # 使用密鑰登錄 + scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + fi + + } + + # ---------------------------- + # 刪除備份 + # ---------------------------- + delete_backup() { + list_backups + read -p "請輸入要刪除的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + rm -rf "$BACKUP_DIR" + echo -e "${GREEN}已刪除備份:${BACKUP_DIR}${NC}" + } + + # ---------------------------- + # 主菜單 + # ---------------------------- + main_menu() { + + check_root + ensure_docker + ensure_jq + while true; do + clear + echo -e "\n${BLUE}-----------------------------------------${NC}" + echo -e "Docker 備份 / 遷移 / 還原 工具 v1.4" + echo -e "${BLUE}-----------------------------------------${NC}" + list_backups + echo -e "\n1. 備份docker項目" + echo -e "2. 遷移docker項目" + echo -e "3. 還原docker項目" + echo -e "4. 刪除docker項目的備份文件" + echo -e "0. 返回主菜單 / 退出" + read -p "請選擇:" choice + case $choice in + 1) backup_docker ;; + 2) migrate_docker ;; + 3) restore_docker ;; + 4) delete_backup ;; + 0) exit 0 ;; + *) echo -e "${RED}無效選項${NC}" ;; + esac + done + } + + main_menu +} + + + + + linux_docker() { while true; do @@ -6875,6 +7179,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}19. ${gl_bai}備份/還原/遷移Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}卸載Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" @@ -7082,6 +7387,9 @@ linux_docker() { restart docker ;; + + + 11) clear send_stats "Docker v6 開" @@ -7094,6 +7402,11 @@ linux_docker() { docker_ipv6_off ;; + 19) + docker_ssh_migration + ;; + + 20) clear send_stats "Docker卸載" @@ -9815,8 +10128,10 @@ while true; do docker_rum() { + ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \ --name nexterm \ + -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ --restart unless-stopped \ @@ -11331,7 +11646,6 @@ while true; do ;; - b) clear send_stats "全部應用備份" @@ -11400,6 +11714,7 @@ while true; do ;; + 0) kejilion ;; From 18e0297481d07189c2aa43a8370082f44ee37a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 15:43:33 +0800 Subject: [PATCH 0099/1285] Update kejilion.sh --- cn/kejilion.sh | 62 +++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 508ee0c6f..6e94b9d43 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}请使用 root 权限运行脚本!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Docker 未安装!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}jq 未安装!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}正在备份 Docker 容器...${NC}" read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # 备份 /home/docker 下的所有文件(不含子目录) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}开始执行还原操作...${NC}" + install tar jq gzip install_docker # --------- 优先还原 Compose 项目 --------- @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + + # 还原 /home/docker 下的文件 + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C /home/docker/ + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + else + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # 主菜单 # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "Docker 备份 / 迁移 / 还原 工具 v1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "Docker备份/迁移/还原工具" + echo "------------------------" list_backups - echo -e "\n1. 备份docker项目" + echo -e "" + echo "------------------------" + echo -e "1. 备份docker项目" echo -e "2. 迁移docker项目" echo -e "3. 还原docker项目" echo -e "4. 删除docker项目的备份文件" - echo -e "0. 返回主菜单 / 退出" + echo "------------------------" + echo -e "0. 返回上一级菜单" + echo "------------------------" read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}无效选项${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/还原/迁移Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" From fdd6fd400d2476f4b3f146a7590b9f19dffccefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 15:44:09 +0800 Subject: [PATCH 0100/1285] Refactor backup and restore functions in kejilion.sh --- kejilion.sh | 62 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9878c10a8..f2b4d8e2e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}请使用 root 权限运行脚本!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Docker 未安装!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}jq 未安装!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}正在备份 Docker 容器...${NC}" read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # 备份 /home/docker 下的所有文件(不含子目录) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}开始执行还原操作...${NC}" + install tar jq gzip install_docker # --------- 优先还原 Compose 项目 --------- @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + + # 还原 /home/docker 下的文件 + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C /home/docker/ + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + else + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # 主菜单 # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "Docker 备份 / 迁移 / 还原 工具 v1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "Docker备份/迁移/还原工具" + echo "------------------------" list_backups - echo -e "\n1. 备份docker项目" + echo -e "" + echo "------------------------" + echo -e "1. 备份docker项目" echo -e "2. 迁移docker项目" echo -e "3. 还原docker项目" echo -e "4. 删除docker项目的备份文件" - echo -e "0. 返回主菜单 / 退出" + echo "------------------------" + echo -e "0. 返回上一级菜单" + echo "------------------------" read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}无效选项${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/还原/迁移Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" From ef7c9f7b365239d24cfbe7c7bcfccfa2c78704d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:10:31 +0800 Subject: [PATCH 0101/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6e94b9d43..2796c8638 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7089,7 +7089,7 @@ docker_ssh_migration() { if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker - tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C /home/docker/ + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" From f334bc55c193dada50e26f3f49d6ef4db8ea35c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:10:54 +0800 Subject: [PATCH 0102/1285] Restore home_docker_files to root instead of /home/docker Change extraction path for home_docker_files backup. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index f2b4d8e2e..196fcbb8c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7089,7 +7089,7 @@ docker_ssh_migration() { if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker - tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C /home/docker/ + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" From c1a8432d6a0012faab73c79ae69a8df414f0ea00 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 24 Aug 2025 08:41:10 +0000 Subject: [PATCH 0103/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-24=2008:41:10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 62 +++++++++++++++++++++++++++++++------------------- jp/kejilion.sh | 62 +++++++++++++++++++++++++++++++------------------- kr/kejilion.sh | 62 +++++++++++++++++++++++++++++++------------------- tw/kejilion.sh | 62 +++++++++++++++++++++++++++++++------------------- 4 files changed, 156 insertions(+), 92 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 8b8f2673f..1c21c147f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}Please use root permissions to run the script!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Docker not installed!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}jq not installed!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}Backing up Docker container...${NC}" read -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # Backup all files under /home/docker (excluding subdirectories) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}Backup the files under /home/docker...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}The file under /home/docker has been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}Backup is complete:${BACKUP_DIR}${NC}" echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}Start the restore operation...${NC}" + install tar jq gzip install_docker # ------------------------- @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}Compose project [$project_name] Decompressed to:$original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}Compose project [$project_name] Restore is complete!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for normal containers was found${NC}" + + # Restore the file under /home/docker + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}Restore the file under /home/docker...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / + echo -e "${GREEN}The file under /home/docker has been restored${NC}" + else + echo -e "${YELLOW}No backup of the file under /home/docker was found, skip...${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # Main Menu # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "Docker Backup/Migration/Restore Tool v1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "Docker backup/migration/restore tool" + echo "------------------------" list_backups - echo -e "\n1. Backup docker project" + echo -e "" + echo "------------------------" + echo -e "1. Backup the docker project" echo -e "2. Migrate docker projects" echo -e "3. Restore the docker project" echo -e "4. Delete the backup file of the docker project" - echo -e "0. Return to main menu / Exit" + echo "------------------------" + echo -e "0. Return to the previous menu" + echo "------------------------" read -p "Please select:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}Invalid option${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Backup/restore/migrate Docker environment" + echo -e "${gl_kjlan}19. ${gl_bai}Backup/Migration/Restore Docker Environment" echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index ba7180fb0..d2122269f 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}ルートアクセス許可を使用してスクリプトを実行してください!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Dockerがインストールされていません!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}JQがインストールされていません!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" read -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # /home /dockerのすべてのファイルをバックアップします(サブディレクトリを除く) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}/home /dockerの下のファイルをバックアップ...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}/home /dockerの下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}復元操作を開始します...${NC}" + install tar jq gzip install_docker # ------------------------------ @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}プロジェクトを作成する[$project_name]減圧:$original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}プロジェクトを作成する[$project_name]復元が完了しました!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}通常のコンテナのバックアップ情報は見つかりませんでした${NC}" + + # /home /dockerの下でファイルを復元します + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}/home /dockerの下でファイルを復元します...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / + echo -e "${GREEN}/home /dockerの下のファイルが復元されました${NC}" + else + echo -e "${YELLOW}/home /dockerの下のファイルのバックアップは見つかりませんでした、スキップ...${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # メインメニュー # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "Dockerバックアップ/移行/復元ツールv1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "Dockerバックアップ/移行/復元ツール" + echo "------------------------" list_backups - echo -e "\ n1。バックアップDockerプロジェクト" + echo -e "" + echo "------------------------" + echo -e "1。Dockerプロジェクトをバックアップします" echo -e "2。Dockerプロジェクトを移行します" echo -e "3. Dockerプロジェクトを復元します" echo -e "4. Dockerプロジェクトのバックアップファイルを削除します" - echo -e "0。メインメニュー /終了に戻ります" + echo "------------------------" + echo -e "0。前のメニューに戻ります" + echo "------------------------" read -p "選択してください:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}無効なオプション${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Docker環境をバックアップ/復元/移行します" + echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 7ce8db11c..33e749951 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}루트 권한을 사용하여 스크립트를 실행하십시오!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Docker가 설치되지 않았습니다!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}JQ가 설치되지 않았습니다!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" read -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # /home /docker 아래의 모든 파일을 백업 (하위 디렉터 제외) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}/home /docker 아래 파일을 백업 ...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}/home /docker의 파일은 다음과 같이 포장되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}백업이 완료되었습니다.${BACKUP_DIR}${NC}" echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}복원 작업 시작 ...${NC}" + install tar jq gzip install_docker # ----------------------------- @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}작곡 프로젝트 [$project_name] 압축 압축 : :$original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원이 완료되었습니다!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" + + # /home /docker에서 파일을 복원하십시오 + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}/home /docker에서 파일을 복원 ...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / + echo -e "${GREEN}/home /docker의 파일이 복원되었습니다${NC}" + else + echo -e "${YELLOW}/home /docker 아래 파일의 백업이 발견되지 않았습니다.${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # 메인 메뉴 # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "도커 백업/마이그레이션/복원 도구 v1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "도커 백업/마이그레이션/복원 도구" + echo "------------------------" list_backups - echo -e "\ n1. 백업 도커 프로젝트" + echo -e "" + echo "------------------------" + echo -e "1. Docker 프로젝트를 백업하십시오" echo -e "2. Docker 프로젝트를 마이그레이션합니다" echo -e "3. Docker 프로젝트를 복원하십시오" echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" - echo -e "0. 메인 메뉴 / 종료로 돌아갑니다" + echo "------------------------" + echo -e "0. 이전 메뉴로 돌아갑니다" + echo "------------------------" read -p "선택하십시오 :" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}잘못된 옵션${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}백업/복원/Docker 환경을 마이그레이션합니다" + echo -e "${gl_kjlan}19. ${gl_bai}백업/마이그레이션/복원 Docker 환경" echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 46bf61d4d..ece6e3e4e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -6861,17 +6861,6 @@ docker_ssh_migration() { BACKUP_ROOT="/tmp" DATE_STR=$(date +%Y%m%d_%H%M%S) - check_root() { - [[ "$EUID" -ne 0 ]] && { echo -e "${RED}請使用 root 權限運行腳本!${NC}"; exit 1; } - } - - ensure_docker() { - command -v docker &>/dev/null || { echo -e "${RED}Docker 未安裝!${NC}"; exit 1; } - } - - ensure_jq() { - command -v jq &>/dev/null || { echo -e "${RED}jq 未安裝!${NC}"; exit 1; } - } is_compose_container() { local container=$1 @@ -6891,6 +6880,10 @@ docker_ssh_migration() { backup_docker() { echo -e "${YELLOW}正在備份 Docker 容器...${NC}" read -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers + + install tar jq gzip + install_docker + local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -6973,9 +6966,19 @@ docker_ssh_migration() { fi done + + # 備份 /home/docker 下的所有文件(不含子目錄) + if [ -d "/home/docker" ]; then + echo -e "${BLUE}備份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + echo -e "${GREEN}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + fi + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}備份完成:${BACKUP_DIR}${NC}" echo -e "${GREEN}可用還原腳本:${RESTORE_SCRIPT}${NC}" + + } # ---------------------------- @@ -6988,6 +6991,7 @@ docker_ssh_migration() { echo -e "${BLUE}開始執行還原操作...${NC}" + install tar jq gzip install_docker # --------- 優先還原 Compose 項目 --------- @@ -7013,7 +7017,7 @@ docker_ssh_migration() { tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" echo -e "${GREEN}Compose 項目 [$project_name] 已解壓到:$original_path${NC}" - cd "$original_path" || exit 1 + cd "$original_path" || return docker compose down || true docker compose up -d echo -e "${GREEN}Compose 項目 [$project_name] 還原完成!${NC}" @@ -7080,6 +7084,18 @@ docker_ssh_migration() { done [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的備份信息${NC}" + + # 還原 /home/docker 下的文件 + if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then + echo -e "${BLUE}正在還原 /home/docker 下的文件...${NC}" + mkdir -p /home/docker + tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / + echo -e "${GREEN}/home/docker 下的文件已還原完成${NC}" + else + echo -e "${YELLOW}未找到 /home/docker 下文件的備份,跳過...${NC}" + fi + + } @@ -7120,28 +7136,28 @@ docker_ssh_migration() { # 主菜單 # ---------------------------- main_menu() { - - check_root - ensure_docker - ensure_jq while true; do clear - echo -e "\n${BLUE}-----------------------------------------${NC}" - echo -e "Docker 備份 / 遷移 / 還原 工具 v1.4" - echo -e "${BLUE}-----------------------------------------${NC}" + echo "------------------------" + echo -e "Docker備份/遷移/還原工具" + echo "------------------------" list_backups - echo -e "\n1. 備份docker項目" + echo -e "" + echo "------------------------" + echo -e "1. 備份docker項目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" echo -e "4. 刪除docker項目的備份文件" - echo -e "0. 返回主菜單 / 退出" + echo "------------------------" + echo -e "0. 返回上一級菜單" + echo "------------------------" read -p "請選擇:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; - 0) exit 0 ;; + 0) return ;; *) echo -e "${RED}無效選項${NC}" ;; esac done @@ -7179,7 +7195,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}備份/還原/遷移Docker環境" + echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}卸載Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" From c6f2838b32a05ff13313a7b08988791b1d99bb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:19:19 +0800 Subject: [PATCH 0104/1285] Update kejilion.sh --- cn/kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2796c8638..f52159593 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6869,7 +6869,7 @@ docker_ssh_migration() { list_backups() { echo -e "${BLUE}当前备份列表:${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -6878,7 +6878,9 @@ docker_ssh_migration() { # 备份 # ---------------------------- backup_docker() { + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip @@ -6985,7 +6987,6 @@ docker_ssh_migration() { # 还原 # ---------------------------- restore_docker() { - list_backups read -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7103,8 +7104,7 @@ docker_ssh_migration() { # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups + install jq read -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } From 3fa8c4873c91dd2693c5505ece3d14fc78fbc846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:19:55 +0800 Subject: [PATCH 0105/1285] Fix backup listing and improve Docker commands --- kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 196fcbb8c..ce66c8c40 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6869,7 +6869,7 @@ docker_ssh_migration() { list_backups() { echo -e "${BLUE}当前备份列表:${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -6878,7 +6878,9 @@ docker_ssh_migration() { # 备份 # ---------------------------- backup_docker() { + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip @@ -6985,7 +6987,6 @@ docker_ssh_migration() { # 还原 # ---------------------------- restore_docker() { - list_backups read -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7103,8 +7104,7 @@ docker_ssh_migration() { # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups + install jq read -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } From 4d4ab6b62ed36abb367fee91b201f0d2fd7f39b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:26:30 +0800 Subject: [PATCH 0106/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f52159593..614148815 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7125,7 +7125,6 @@ docker_ssh_migration() { # 删除备份 # ---------------------------- delete_backup() { - list_backups read -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" @@ -7160,6 +7159,7 @@ docker_ssh_migration() { 0) return ;; *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } From 689b41fa0d8ad029ed1e722066b7ebea7d99b2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:27:10 +0800 Subject: [PATCH 0107/1285] Remove list_backups call from delete_backup Removed the call to list_backups in delete_backup function. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index ce66c8c40..ed85aa4cf 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7125,7 +7125,6 @@ docker_ssh_migration() { # 删除备份 # ---------------------------- delete_backup() { - list_backups read -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" @@ -7160,6 +7159,7 @@ docker_ssh_migration() { 0) return ;; *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } From bbfb7ce9c44a271bc7e761875a5f91be3a477c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:37:33 +0800 Subject: [PATCH 0108/1285] Fix tar command to use -T instead of --files-from --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ed85aa4cf..945d42223 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6972,10 +6972,10 @@ docker_ssh_migration() { # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi - + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" From 44a86ad82d9892683242d50a4350535af92b32bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:38:04 +0800 Subject: [PATCH 0109/1285] Fix tar command to use -T option for file list --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 614148815..daab6b3b7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6972,10 +6972,10 @@ docker_ssh_migration() { # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi - + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" From 565ec3f2417fb42b9cc43119033d8822bd9d5504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:23:07 +0800 Subject: [PATCH 0110/1285] Update kejilion.sh --- cn/kejilion.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index daab6b3b7..1717e479a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6878,6 +6878,7 @@ docker_ssh_migration() { # 备份 # ---------------------------- backup_docker() { + send_stats "Docker备份" echo -e "${YELLOW}正在备份 Docker 容器...${NC}" docker ps --format '{{.Names}}' @@ -6975,7 +6976,7 @@ docker_ssh_migration() { find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi - + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" @@ -6987,6 +6988,8 @@ docker_ssh_migration() { # 还原 # ---------------------------- restore_docker() { + + send_stats "Docker还原" read -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7104,6 +7107,7 @@ docker_ssh_migration() { # 迁移 # ---------------------------- migrate_docker() { + send_stats "Docker迁移" install jq read -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7125,6 +7129,7 @@ docker_ssh_migration() { # 删除备份 # ---------------------------- delete_backup() { + send_stats "Docker备份文件删除" read -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" @@ -7135,6 +7140,7 @@ docker_ssh_migration() { # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" From 64c48165c89084184e9f175d429a5bf7e68e43fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:23:38 +0800 Subject: [PATCH 0111/1285] Add send_stats calls for Docker operations --- kejilion.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 945d42223..672fa0e1b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6878,6 +6878,7 @@ docker_ssh_migration() { # 备份 # ---------------------------- backup_docker() { + send_stats "Docker备份" echo -e "${YELLOW}正在备份 Docker 容器...${NC}" docker ps --format '{{.Names}}' @@ -6975,7 +6976,7 @@ docker_ssh_migration() { find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi - + chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" @@ -6987,6 +6988,8 @@ docker_ssh_migration() { # 还原 # ---------------------------- restore_docker() { + + send_stats "Docker还原" read -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7104,6 +7107,7 @@ docker_ssh_migration() { # 迁移 # ---------------------------- migrate_docker() { + send_stats "Docker迁移" install jq read -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } @@ -7125,6 +7129,7 @@ docker_ssh_migration() { # 删除备份 # ---------------------------- delete_backup() { + send_stats "Docker备份文件删除" read -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" @@ -7135,6 +7140,7 @@ docker_ssh_migration() { # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" From 27da8bb5e46119d9f805cd56362f6d33b527718a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:03:39 +0800 Subject: [PATCH 0112/1285] Update kejilion.sh --- cn/kejilion.sh | 112 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1717e479a..a39befbd3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.1" gl_hui='\e[37m' @@ -8872,6 +8872,8 @@ while true; do echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11667,6 +11669,114 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="Dufs 极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="Gopeed 分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + b) clear From 961eb960104423e6054435340e9fb29f2af469e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:04:16 +0800 Subject: [PATCH 0113/1285] Update version and add new applications to script --- kejilion.sh | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 672fa0e1b..30e374169 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.1" gl_hui='\e[37m' @@ -8872,6 +8872,8 @@ while true; do echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11667,6 +11669,114 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="Dufs 极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="Gopeed 分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + b) clear From 10ae667b075dadd905989d45e4ad4a66f26bc18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:06:51 +0800 Subject: [PATCH 0114/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8cce2f0e0..0def2dff2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1283,4 +1283,10 @@ LDNMP建站flarum论坛安装时增加插件市场的安装,后期可以在后 docker管理增加全局备份还原迁移功能。 修复部分应用的部署不成功问题, ------------------------ +2025-08-25 v4.1.1 +应用市场新增Dufs极简静态文件服务器的安装及使用。 +应用市场新增gopeed分布式高速下载工具的安装及使用。 +应用市场新增paperless文档管理平台的安装及使用。 + +------------------------ From 3e894c9a8fe8196c5aa69f949d90c0e4b4b90dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:07:28 +0800 Subject: [PATCH 0115/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 0def2dff2..e700d4f8f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1287,6 +1287,4 @@ docker管理增加全局备份还原迁移功能。 应用市场新增Dufs极简静态文件服务器的安装及使用。 应用市场新增gopeed分布式高速下载工具的安装及使用。 应用市场新增paperless文档管理平台的安装及使用。 - ------------------------ - From 40becc2cb287c9525f2986c021e0492e230552e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 26 Aug 2025 17:59:45 +0800 Subject: [PATCH 0116/1285] Update kejilion.sh --- cn/kejilion.sh | 85 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a39befbd3..04423c9e9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8874,6 +8874,7 @@ while true; do echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -8998,6 +8999,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -10977,9 +10981,9 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear @@ -11687,7 +11691,7 @@ while true; do } - local docker_describe="Dufs 极简静态文件服务器,支持上传下载" + local docker_describe="极简静态文件服务器,支持上传下载" local docker_url="官网介绍: https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" @@ -11718,7 +11722,7 @@ while true; do } - local docker_describe="Gopeed 分布式高速下载工具,支持多种协议" + local docker_describe="分布式高速下载工具,支持多种协议" local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -11776,6 +11780,77 @@ while true; do ;; + 97|wgs|wireguard) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=${docker_port} \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e SERVER_ALLOWEDIPS_PEER_myPhone="192.168.1.0/24,192.168.2.0/24,192.168.100.0/24" \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 5 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 3 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) From 34193e4f6b34a10dfff5d654b1893fbf64fb00a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:00:52 +0800 Subject: [PATCH 0117/1285] Add WireGuard setup and configuration options --- kejilion.sh | 85 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 30e374169..7a111b4f1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8874,6 +8874,7 @@ while true; do echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -8998,6 +8999,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -10977,9 +10981,9 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear @@ -11687,7 +11691,7 @@ while true; do } - local docker_describe="Dufs 极简静态文件服务器,支持上传下载" + local docker_describe="极简静态文件服务器,支持上传下载" local docker_url="官网介绍: https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" @@ -11718,7 +11722,7 @@ while true; do } - local docker_describe="Gopeed 分布式高速下载工具,支持多种协议" + local docker_describe="分布式高速下载工具,支持多种协议" local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -11776,6 +11780,77 @@ while true; do ;; + 97|wgs|wireguard) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=${docker_port} \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e SERVER_ALLOWEDIPS_PEER_myPhone="192.168.1.0/24,192.168.2.0/24,192.168.100.0/24" \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 5 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 3 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) From 533eaef84ef653e2acae644cb9573fc90ffb2b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:59:23 +0800 Subject: [PATCH 0118/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 04423c9e9..916ca615f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10981,8 +10981,8 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d From 5c984f5fbea761410174b1c9bf070e24893d2ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:59:54 +0800 Subject: [PATCH 0119/1285] Reorder sed command for admin replacement --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7a111b4f1..cf59cec96 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10981,8 +10981,8 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d From a29b5fd861eb7e8538ddd65aafaa50ae1e3b918d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:18:49 +0800 Subject: [PATCH 0120/1285] Update kejilion.sh --- cn/kejilion.sh | 73 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 916ca615f..b756fd8a8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.1" +sh_v="4.1.2" gl_hui='\e[37m' @@ -11780,7 +11780,7 @@ while true; do ;; - 97|wgs|wireguard) + 97|wgs) local app_id="97" local docker_name="wireguard" @@ -11817,7 +11817,7 @@ while true; do lscr.io/linuxserver/wireguard:latest - sleep 5 + sleep 3 docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' docker exec wireguard sh -c ' for d in /config/peer_*; do @@ -11851,6 +11851,73 @@ while true; do ;; + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + b) From 578279d323c6d6bf60ed01afda8a4f715e68a51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:19:28 +0800 Subject: [PATCH 0121/1285] Update wireguard version and add wireguardc support --- kejilion.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index cf59cec96..35261dd18 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.1" +sh_v="4.1.2" gl_hui='\e[37m' @@ -11780,7 +11780,7 @@ while true; do ;; - 97|wgs|wireguard) + 97|wgs) local app_id="97" local docker_name="wireguard" @@ -11817,7 +11817,7 @@ while true; do lscr.io/linuxserver/wireguard:latest - sleep 5 + sleep 3 docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' docker exec wireguard sh -c ' for d in /config/peer_*; do @@ -11851,6 +11851,73 @@ while true; do ;; + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + b) From 2cb43e2209bdd125b69f26543f81741fef507d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:22:11 +0800 Subject: [PATCH 0122/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e700d4f8f..4b6de42ef 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1288,3 +1288,6 @@ docker管理增加全局备份还原迁移功能。 应用市场新增gopeed分布式高速下载工具的安装及使用。 应用市场新增paperless文档管理平台的安装及使用。 ------------------------ +2025-08-27 v4.1.2 +应用市场新增WireGuard异地隧道组网工具的安装及使用。 +------------------------ From 42927bdf4dd45d6053d99c85d961aea04aa9cd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:14:48 +0800 Subject: [PATCH 0123/1285] Update kejilion.sh --- cn/kejilion.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b756fd8a8..1acdb1219 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11828,10 +11828,21 @@ while true; do done ' + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' - sleep 3 + sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' - sleep 3 + sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" From efcb06f7212e48fcd9a09b3d62c7c5c37f1e868d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:15:15 +0800 Subject: [PATCH 0124/1285] Update kejilion.sh --- kejilion.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 35261dd18..af6611e1d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11828,10 +11828,21 @@ while true; do done ' + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' - sleep 3 + sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' - sleep 3 + sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" From b4bd58927e11267eee805e62de55ae73abbeab21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:56:11 +0800 Subject: [PATCH 0125/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1acdb1219..2edf92098 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8874,7 +8874,7 @@ while true; do echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" From 1cef7452110783d854876f786b9f6b121b9a4966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:57:13 +0800 Subject: [PATCH 0126/1285] Remove SERVER_ALLOWEDIPS_PEER_myPhone variable --- cn/kejilion.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2edf92098..d4ec53511 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11809,7 +11809,6 @@ while true; do -e INTERNAL_SUBNET=10.13.13.0 \ -e ALLOWEDIPS=10.13.13.0/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ - -e SERVER_ALLOWEDIPS_PEER_myPhone="192.168.1.0/24,192.168.2.0/24,192.168.100.0/24" \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ @@ -14285,4 +14284,3 @@ else ;; esac fi - From cc2b0ba25254d525413cb89f4ec2a7b5d227ea8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:57:59 +0800 Subject: [PATCH 0127/1285] Fix formatting and cleanup in kejilion.sh --- kejilion.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index af6611e1d..f77a9c71b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8874,7 +8874,7 @@ while true; do echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11809,7 +11809,6 @@ while true; do -e INTERNAL_SUBNET=10.13.13.0 \ -e ALLOWEDIPS=10.13.13.0/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ - -e SERVER_ALLOWEDIPS_PEER_myPhone="192.168.1.0/24,192.168.2.0/24,192.168.100.0/24" \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ @@ -14285,4 +14284,3 @@ else ;; esac fi - From 253672ae1a8172876ae54f9d0a773700e87b1266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:01:55 +0800 Subject: [PATCH 0128/1285] Update kejilion.sh --- cn/kejilion.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d4ec53511..6a3ca736e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -11794,6 +11793,8 @@ while true; do PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + stop_containers_or_kill_process 51820 &>/dev/null + ip_address docker run -d \ --name=wireguard \ From 9602d5bcc73f0dd7740c2b53c1d4f98ea34b62de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:03:00 +0800 Subject: [PATCH 0129/1285] Refactor port handling functions in kejilion.sh --- kejilion.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f77a9c71b..663577f40 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -11794,6 +11793,8 @@ while true; do PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + stop_containers_or_kill_process 51820 &>/dev/null + ip_address docker run -d \ --name=wireguard \ From f51a8826775b6280728f513d29bf080eaff0ad0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:10:49 +0800 Subject: [PATCH 0130/1285] Change SERVERPORT to a fixed value of 51820 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6a3ca736e..bf1361ecf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11805,7 +11805,7 @@ while true; do -e PGID=1000 \ -e TZ=Etc/UTC \ -e SERVERURL=${ipv4_address} \ - -e SERVERPORT=${docker_port} \ + -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ -e INTERNAL_SUBNET=10.13.13.0 \ -e ALLOWEDIPS=10.13.13.0/24 \ From c3a784790ca2baf95d47936a6bd1959a43346673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:11:26 +0800 Subject: [PATCH 0131/1285] Change SERVERPORT environment variable to 51820 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 663577f40..f70cab559 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11805,7 +11805,7 @@ while true; do -e PGID=1000 \ -e TZ=Etc/UTC \ -e SERVERURL=${ipv4_address} \ - -e SERVERPORT=${docker_port} \ + -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ -e INTERNAL_SUBNET=10.13.13.0 \ -e ALLOWEDIPS=10.13.13.0/24 \ From fc5a789c1cfbef5201b5d1abed45401dd62362af Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 27 Aug 2025 10:38:13 +0000 Subject: [PATCH 0132/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-27=2010:38:13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 4986 +++++++++++++++++++++++++----------------------- jp/kejilion.sh | 4974 ++++++++++++++++++++++++----------------------- kr/kejilion.sh | 4986 +++++++++++++++++++++++++----------------------- tw/kejilion.sh | 4762 +++++++++++++++++++++++---------------------- 4 files changed, 10390 insertions(+), 9318 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 1c21c147f..cab3eb64a 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.2" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# Define a function to execute commands +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# Functions that collect function buried point information, record the current script version number, usage time, system version, CPU architecture, the country of the machine and the function name used by the user. They absolutely do not involve any sensitive information, please rest assured! Please believe me! -# Why do we need to design this function? The purpose is to better understand the functions that users like to use, and further optimize the functions to launch more functions that meet user needs. -# For the full text, you can search for the send_stats function call location, transparent and open source, and you can refuse to use it if you have any concerns. +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# Prompt the user to agree to the terms +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Welcome to the Tech lion script toolbox${gl_bai}" - echo "For the first time using the script, please read and agree to the user license agreement." - echo "User License Agreement: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "Do you agree to the above terms? (y/n):" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "License consent" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "Rejection of permission" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "Package parameters are not provided!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}Installing$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "Unknown package manager!" + echo "未知的包管理器!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}hint:${gl_bai}Insufficient disk space!" - echo "Current available space: $((available_space_mb/1024))G" - echo "Minimum demand space:${required_gb}G" - echo "The installation cannot be continued. Please clean the disk space and try again." - send_stats "Insufficient disk space" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "Package parameters are not provided!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}Uninstalling$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "Unknown package manager!" + echo "未知的包管理器!" return 1 fi done } -# Universal systemctl function, suitable for various distributions +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# Restart the service +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1The service has been restarted." + echo "$1 服务已重启。" else - echo "Error: Restart$1Service failed." + echo "错误:重启 $1 服务失败。" fi } -# Start the service +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1The service has been started." + echo "$1 服务已启动。" else - echo "Error: Start$1Service failed." + echo "错误:启动 $1 服务失败。" fi } -# Stop service +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1Service has been stopped." + echo "$1 服务已停止。" else - echo "Error: Stop$1Service failed." + echo "错误:停止 $1 服务失败。" fi } -# Check service status +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1The service status is displayed." + echo "$1 服务状态已显示。" else - echo "Error: Unable to display$1Service status." + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAMESet to power on." + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}Operation completed${gl_bai}" - echo "Press any key to continue..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -425,7 +424,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Installing docker environment...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +499,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker container management" - echo "Docker container list" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "Container operation" + echo "容器操作" echo "------------------------" - echo "1. Create a new container" + echo "1. 创建新的容器" echo "------------------------" - echo "2. Start the specified container 6. Start all containers" - echo "3. Stop the specified container 7. Stop all containers" - echo "4. Delete the specified container 8. Delete all containers" - echo "5. Restart the specified container 9. Restart all containers" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11. Enter the specified container 12. View the container log" - echo "13. View container network 14. View container occupancy" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15. Turn on container port access 16. Turn off container port access" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Create a new container" - read -e -p "Please enter the creation command:" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "Start the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "Stop the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "Delete the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "Restart the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "Start all containers" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "Stop all containers" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "Delete all containers" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +564,28 @@ while true; do [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "Restart all containers" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "Enter the container" - read -e -p "Please enter the container name:" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "View container log" - read -e -p "Please enter the container name:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "View container network" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +603,14 @@ while true; do break_end ;; 14) - send_stats "View container occupancy" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "Allow container port access" - read -e -p "Please enter the container name:" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +619,8 @@ while true; do ;; 16) - send_stats "Block container port access" - read -e -p "Please enter the container name:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +639,44 @@ done docker_image() { while true; do clear - send_stats "Docker image management" - echo "Docker image list" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "Mirror operation" + echo "镜像操作" echo "------------------------" - echo "1. Get the specified image 3. Delete the specified image" - echo "2. Update the specified image 4. Delete all images" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Pull the mirror" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}Getting the image:$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "Update the image" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}Updated image:$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "Delete the mirror" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "Delete all images" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +685,7 @@ while true; do [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +753,16 @@ install_crontab() { service cron start ;; *) - echo "Unsupported distributions:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "The operating system cannot be determined." + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}crontab is installed and the cron service is running.${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +774,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # Check if the configuration file exists, create the file and write the default settings if it does not exist + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # Use jq to handle updates of configuration files + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # Check whether the current configuration already has ipv6 settings + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # Update configuration and enable IPv6 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # Comparing original configuration with new configuration + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}IPv6 access is currently enabled${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +809,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # Check if the configuration file exists + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}The configuration file does not exist${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # Read the current configuration + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # Use jq to handle updates of configuration files + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # Check the current ipv6 status + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # Comparing original configuration with new configuration + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6 access is currently closed${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6 access has been successfully closed${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +869,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "Please provide at least one port number" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # Delete existing closing rules + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # Add Open Rules + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "The port has been opened$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "The port has been opened" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "Please provide at least one port number" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # Delete existing open rules + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a close rule + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "Port closed$port" + echo "已关闭端口 $port" fi done - # Delete existing rules (if any) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # Insert new rules to first + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "Port closed" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "Please provide at least one IP address or IP segment" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # Delete existing blocking rules + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # Add allow rules + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "Released IP$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "Released IP" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "Please provide at least one IP address or IP segment" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # Delete existing allow rules + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # Add blocking rules + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP blocked$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IP blocked" + send_stats "已阻止IP" } @@ -990,7 +989,7 @@ block_ip() { enable_ddos_defense() { - # Turn on defense DDoS + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +999,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "Turn on DDoS defense" + send_stats "开启DDoS防御" } -# Turn off DDoS Defense +# 关闭DDoS防御 disable_ddos_defense() { - # Turn off defense DDoS + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1014,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "Turn off DDoS Defense" + send_stats "关闭DDoS防御" } -# Functions that manage national IP rules +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1032,73 @@ manage_country_rules() { case "$action" in block) - # Create if ipset does not exist + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # Download IP area file + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "Error: Download$country_codeIP zone file failed" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # Add IP to ipset + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # Block IP with iptables + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "Blocked successfully$country_codeIP address" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # Create an ipset for allowed countries (if not exist) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # Download IP area file + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "Error: Download$country_codeIP zone file failed" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # Delete existing national rules + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # Add IP to ipset + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # Only IPs in designated countries are allowed + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "Successfully only allowed$country_codeIP address" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # Delete the iptables rules for the country + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # Destroy ipset + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "Successfully lifted$country_codeIP address restrictions" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1115,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "Advanced Firewall Management" - send_stats "Advanced Firewall Management" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "Firewall Management" + echo "防火墙管理" echo "------------------------" - echo "1. Open the specified port 2. Close the specified port" - echo "3. Open all ports 4. Close all ports" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5. IP whitelist 6. IP blacklist" - echo "7. Clear the specified IP" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. Allow PING 12. Disable PING" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13. Start DDOS Defense 14. Turn off DDOS Defense" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15. Block specified country IP 16. Only specified country IPs are allowed" - echo "17. Release IP restrictions in designated countries" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "Please enter the open port number:" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "Open a specified port" + send_stats "开放指定端口" ;; 2) - read -e -p "Please enter the closed port number:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "Close the specified port" + send_stats "关闭指定端口" ;; 3) - # Open all ports + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1163,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "Open all ports" + send_stats "开放所有端口" ;; 4) - # Close all ports + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1179,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "Close all ports" + send_stats "关闭所有端口" ;; 5) - # IP whitelist - read -e -p "Please enter the IP or IP segment to release:" o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IP blacklist - read -e -p "Please enter the blocked IP or IP segment:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # Clear the specified IP - read -e -p "Please enter the cleared IP:" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "Clear the specified IP" + send_stats "清除指定IP" ;; 11) - # Allow PING + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "Allow PING" + send_stats "允许PING" ;; 12) - # Disable PING + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "Disable PING" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1222,20 @@ iptables_panel() { ;; 15) - read -e -p "Please enter the blocked country code (such as CN, US, JP):" country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "Allowed countries$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "Please enter the allowed country code (such as CN, US, JP):" country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "Block the country$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "Please enter the cleared country code (such as CN, US, JP):" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "Clear the country$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1256,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # Get all swap partitions in the current system + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # Iterate over and delete all swap partitions + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # Make sure /swapfile is no longer used + # 确保 /swapfile 不再被使用 swapoff /swapfile - # Delete the old /swapfile + # 删除旧的 /swapfile rm -f /swapfile - # Create a new swap partition + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1287,7 @@ add_swap() { rc-update add local fi - echo -e "The virtual memory size has been resized to${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1297,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# Determine whether virtual memory needs to be created +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1313,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # Get nginx version + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # Get the mysql version + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # Get the php version + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Get the redis version + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1340,7 @@ ldnmp_v() { install_ldnmp_conf() { - # Create necessary directories and files + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1349,11 @@ install_ldnmp_conf() { default_server_ssl - # Download the docker-compose.yml file and replace it + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # Replace in docker-compose.yml file + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1398,7 @@ install_ldnmp() { clear - echo "LDNMP environment has been installed" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1415,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "Renewal task has been updated" + echo "续签任务已更新" } @@ -1453,15 +1452,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yumingPublic key information${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yumingPrivate key information${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}Certificate storage path${gl_bai}" - echo "Public key: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "Private key: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1469,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}Quickly apply for an SSL certificate, automatically renew your signature before expiration${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1485,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}The expiration of the applied certificate${gl_bai}" - echo "Site information Certificate expiration time" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1525,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "Successful application for domain name certificate" + send_stats "域名证书申请成功" else - send_stats "Application for domain name certificate failed" - echo -e "${gl_hong}Notice:${gl_bai}The certificate application failed. Please check the following possible reasons and try again:" - echo -e "1. Domain name spelling error ➠ Please check whether the domain name is entered correctly" - echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to this server IP" - echo -e "3. Network configuration issues ➠ If you use Cloudflare Warp and other virtual networks, please temporarily shut down" - echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open to ensure verification is accessible" - echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" - echo -e "6. Domestic registration restrictions ➠ Please confirm whether the domain name is registered in mainland China" + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "Please try deploying again$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1548,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "Domain name reuse" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1557,8 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "Please enter your IP or the resolved domain name:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1623,8 +1622,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1643,11 +1642,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "Login information:" - echo "username:$dbuse" - echo "password:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "start up$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1656,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # Check if the configuration file exists + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # Read API_TOKEN and zone_id from configuration files + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # Convert ZONE_IDS to an array + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # Prompt the user whether to clean the cache - read -e -p "Need to clean Cloudflare's cache? (y/n):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF information is saved in$CONFIG_FILE, you can modify CF information later" - read -e -p "Please enter your API_TOKEN:" API_TOKEN - read -e -p "Please enter your CF username:" EMAIL - read -e -p "Please enter zone_id (multiple separated by spaces):" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # Loop through each zone_id and execute the clear cache command + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "Clearing cache for zone_id:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1686,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "The cache clear request has been sent." + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "Clean up site cache" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1702,28 @@ web_cache() { web_del() { - send_stats "Delete site data" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "To delete site data, please enter your domain name (multiple domain names are separated by spaces):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "Deleting the domain name:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # Convert domain name to database name + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # Check whether the database exists before deleting it to avoid errors - echo "Deleting the database:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1739,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to the mode parameter + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # Turn on WAF: Remove comments + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # Close WAF: Add Comments + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "Invalid parameter: Use 'on' or 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Check nginx images and handle them according to the situation + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1802,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # Delete old definition + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # Insert a new definition before the line with "Happy publishing" + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1829,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # Delete old definition + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # Insert a new definition before the line with "Happy publishing" + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1857,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Turn on Brotli: Remove comments + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1871,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Close Brotli: Add comments + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1887,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "Invalid parameter: Use 'on' or 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Check nginx images and handle them according to the situation + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1913,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # Turn on Zstd: Remove comments + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1928,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Close Zstd: Add comments + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1944,11 @@ nginx_zstd() { else - echo "Invalid parameter: Use 'on' or 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Check nginx images and handle them according to the situation + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1975,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "Invalid parameter: Use 'on' or 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1989,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP environment defense" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2003,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "Server website defense program${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. Install the defense program" + echo "1. 安装防御程序" echo "------------------------" - echo "5. View SSH interception record 6. View website interception record" - echo "7. View the list of defense rules 8. View real-time monitoring of logs" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11. Configure intercept parameters 12. Clear all blocked IPs" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. cloudflare mode 22. High load on 5 seconds shield" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31. Turn on WAF 32. Turn off WAF" - echo "33. Turn on DDOS Defense 34. Turn off DDOS Defense" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9. Uninstall the defense program" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2081,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban defense program has been uninstalled" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2097,11 +2096,11 @@ web_security() { ;; 21) - send_stats "cloudflare mode" - echo "Go to the upper right corner of the cf background, select the API token on the left, and obtain the Global API Key" + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "Enter CF account number:" cfuser - read -e -p "Enter the Global API Key for CF:" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2115,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "Cloudflare mode is configured to view intercept records in the cf background, site-security-events" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "Get CF parameters:" - echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" - echo -e "Go to the bottom right of the cf background domain name summary page to get${gl_huang}Region ID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "Enter CF account number:" cfuser - read -e -p "Enter the Global API Key for CF:" cftoken - read -e -p "Enter the region ID of the domain name in CF:" cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2146,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "High load automatic shield opening script has been added" + echo "高负载自动开盾脚本已添加" else - echo "Automatic shield script already exists, no need to add it" + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "Site WAF is enabled" - send_stats "Site WAF is enabled" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "Site WAF has been closed" - send_stats "Site WAF has been closed" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2188,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# Get the current worker_processes setting value +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# Set mode information according to value +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2207,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # Check whether zstd is enabled and not commented (the whole line starts with zstd on;) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Check if brotli is enabled and not commented + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # Check if gzip is enabled and not commented + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2237,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "Optimize LDNMP environment" - echo -e "Optimize LDNMP environment${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. Standard mode 2. High performance mode (recommended 2H4G or above)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3. Turn on gzip compression 4. Turn off gzip compression" - echo "5. Turn on br compression 6. Turn off br compression" - echo "7. Turn on zstd compression 8. Turn off zstd compression" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Site standard mode" + send_stats "站点标准模式" - # nginx tuning + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php tuning + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php tuning + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2275,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql tuning + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2287,23 @@ web_optimization() { optimize_balanced - echo "LDNMP environment has been set to standard mode" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "Site high performance mode" + send_stats "站点高性能模式" - # nginx tuning + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php tuning + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php tuning + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2315,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql tuning + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2325,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP environment has been set to high performance mode" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2385,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}${gl_bai} installed" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker="${gl_hui}${gl_bai} is not installed" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2395,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "Access address:" +echo "访问地址:" ip_address @@ -2434,31 +2433,31 @@ check_docker_image_update() { return fi - # Get the container creation time and image name + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # Extract mirror warehouses and tags + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # The default label is latest + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # Add support for official images + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Get image publishing time from Docker Hub API + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # Verify the time of acquisition + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # Compare timestamps + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2476,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # Get the IP address of the container + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2486,34 @@ block_container_port() { install iptables - # Check and block all other IPs + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Check and release the specified IP + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Check and release the local network 127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # Check and block all other IPs + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Check and release the specified IP + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Check and release the local network 127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2523,7 @@ block_container_port() { fi - echo "IP+ ports have been blocked from accessing the service" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2534,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # Get the IP address of the container + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2544,17 @@ clear_container_rules() { install iptables - # Clear rules that block all other IPs + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules for releasing the specified IP + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Clear the rules for release local network 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2563,17 @@ clear_container_rules() { - # Clear rules that block all other IPs + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules for releasing the specified IP + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Clear the rules for release local network 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2584,7 @@ clear_container_rules() { fi - echo "IP+ports have been allowed to access the service" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2598,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "Error: Please provide the port number and the IP that is allowed to access." - echo "Usage: block_host_port " + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # Denied all other IP access + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # Allow specified IP access + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # Allow local access + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2625,27 @@ block_host_port() { - # Denied all other IP access + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # Allow specified IP access + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # Allow local access + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Allow traffic for established and related connections + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ ports have been blocked from accessing the service" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2657,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "Error: Please provide the port number and the IP that is allowed to access." - echo "Usage: clear_host_port_rules " + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # Clear rules that block all other IP access + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # Clear rules that allow native access + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Clear rules that allow specified IP access + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # Clear rules that block all other IP access + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # Clear rules that allow native access + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Clear rules that allow specified IP access + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ports have been allowed to access the service" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2727,7 +2726,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}manage" +send_stats "${docker_name}管理" while true; do clear @@ -2747,18 +2746,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. Add domain name access 6. Delete domain name access" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2770,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameInstalled" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "Install$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2785,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameInstalled" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "renew$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2799,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" - send_stats "uninstall$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}Domain access settings" - send_stats "${docker_name}Domain access settings" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "Allow IP access${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "Block IP access${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2859,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. Add domain name access 6. Delete domain name access" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2894,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}Domain access settings" - send_stats "${docker_name}Domain access settings" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "Allow IP access${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "Block IP access${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2994,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# Functions that check whether the session exists +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# Loop until a non-existent session name is found +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# Create a new tmux session +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3079,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "Restarted" + echo "已重启" reboot ;; *) - echo "Canceled" + echo "已取消" ;; esac @@ -3127,8 +3126,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "Unable to install LDNMP environment again" - echo -e "${gl_huang}hint:${gl_bai}The website construction environment is installed. No need to install again!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3137,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "Install LDNMP environment" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}The LDNMP environment is not installed, start installing the LDNMP environment...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3154,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Install nginx environment" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginx is not installed, start installing nginx environment...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3168,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx has been installed" -echo -e "Current version:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3180,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "Please install the LDNMP environment first" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3190,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "Please install nginx environment first" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3201,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "Yours$webnameBuilt!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webnameThe installation information is as follows:" + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "Yours$webnameBuilt!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3222,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3263,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "Please enter your anti-generation IP:" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "Please enter your anti-generation port:" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3296,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3356,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP site management" - echo "LDNMP environment" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "Site:${output}Certificate expiration time" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3374,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "database:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "Site Directory" + echo "站点目录" echo "------------------------" - echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "operate" + echo "操作" echo "------------------------" - echo "1. Apply for/update the domain name certificate 2. Change the site domain name" - echo "3. Clean up the site cache 4. Create an associated site" - echo "5. View access log 6. View error log" - echo "7. Edit global configuration 8. Edit site configuration" - echo "9. Manage site database 10. View site analysis report" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20. Delete the specified site data" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Apply for a domain name certificate" - read -e -p "Please enter your domain name:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3411,15 @@ ldnmp_web_status() { ;; 2) - send_stats "Change the site domain name" - echo -e "${gl_hong}Highly recommended:${gl_bai}First back up the entire site data and then change the site domain name!" - read -e -p "Please enter the old domain name:" oddyuming - read -e -p "Please enter the new domain name:" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # mysql replacement + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3437,7 @@ ldnmp_web_status() { done done - # Website directory replacement + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3458,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "Create an associated site" - echo -e "Associate a new domain name for the existing site for access" - read -e -p "Please enter the existing domain name:" oddyuming - read -e -p "Please enter the new domain name:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3475,25 @@ ldnmp_web_status() { ;; 5) - send_stats "View access log" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "View error log" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "Edit global configuration" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "Edit site configuration" - read -e -p "To edit the site configuration, please enter the domain name you want to edit:" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3503,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "View site data" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3535,21 +3534,21 @@ fi install_panel() { -send_stats "${panelname}manage" +send_stats "${panelname}管理" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}It is a popular and powerful operation and maintenance management panel nowadays." - echo "Official website introduction:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. Install 2. Management 3. Uninstall" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3557,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}Install" + send_stats "${panelname}安装" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}control" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}uninstall" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3614,8 @@ donlond_frp() { generate_frps_config() { - send_stats "Install the frp server" - # Generate random ports and credentials + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3636,17 @@ EOF donlond_frp frps - # Output generated information + # 输出生成的信息 ip_address echo "------------------------" - echo "Parameters required for client deployment" - echo "Service IP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRP panel information" - echo "FRP panel address: http://$ipv4_address:$dashboard_port" - echo "FRP panel username:$dashboard_user" - echo "FRP panel password:$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3656,9 @@ EOF configure_frpc() { - send_stats "Install the frp client" - read -e -p "Please enter the external network docking IP:" server_addr - read -e -p "Please enter the external network docking token:" token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3678,17 @@ EOF } add_forwarding_service() { - send_stats "Add FRP intranet service" - # Prompt the user to enter the service name and forwarding information - read -e -p "Please enter the service name:" service_name - read -e -p "Please enter the forwarding type (tcp/udp) [Enter default tcp]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "Please enter the intranet IP [Enter default 127.0.0.1]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "Please enter the intranet port:" local_port - read -e -p "Please enter the external network port:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # Write user input to configuration file + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3698,8 @@ remote_port = ${remote_port} EOF - # Output generated information - echo "Serve$service_nameAdded successfully to frpc.toml" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3710,12 @@ EOF delete_forwarding_service() { - send_stats "Delete the frp intranet service" - # Prompt the user to enter the service name that needs to be deleted - read -e -p "Please enter the service name that needs to be deleted:" service_name - # Use sed to delete the service and its related configurations + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "Serve$service_nameDeleted successfully from frpc.toml" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3725,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # Print the header + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3746,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # If there is service information, print the current service before processing the new service + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3755,11 @@ list_forwarding_services() { type } - # Update the current service name + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # Clear the previous value + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3789,7 +3788,7 @@ list_forwarding_services() { } END { - # Print the information for the last service + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3801,17 @@ list_forwarding_services() { -# Get the FRP server port +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# Generate access address +# 生成访问地址 generate_access_urls() { - # Get all ports first + # 首先获取所有端口 get_frp_ports - # Check if there are ports other than 8055/8056 + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3820,18 @@ generate_access_urls() { fi done - # Show title and content only when there is a valid port + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRP service external access address:" + echo "FRP服务对外访问地址:" - # Process IPv4 address + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # Process IPv6 addresses (if present) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3840,7 @@ generate_access_urls() { done fi - # Handling HTTPS configuration + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3867,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP server" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3875,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP server$check_frp $update_status" - echo "Build an FRP intranet penetration service environment to expose devices without public IP to the Internet" - echo "Official website introduction: https://github.com/fatedier/frp/" - echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. Domain name access for intranet service 6. Delete domain name access" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00. Refresh service status 0. Return to the previous menu" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3901,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "The FRP server has been installed" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3911,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "The FRP server has been updated" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3922,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "应用已卸载" ;; 5) - echo "Reverse intranet penetration service into domain name access" - send_stats "FRP access to external domain names" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "Please enter your intranet penetration service port:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "Allow IP access" - read -e -p "Please enter the port to be released:" frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "Block IP access" - echo "If you have accessed the anti-generation domain name, you can use this function to block IP+ port access, which is more secure." - read -e -p "Please enter the port you need to block:" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "Refresh the FRP service status" - echo "FRP service status has been refreshed" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3965,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP Client" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3973,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP Client$check_frp $update_status" - echo "Docking with the server, after docking, you can create intranet penetration service to the Internet access" - echo "Official website introduction: https://github.com/fatedier/frp/" - echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3984,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. Add external services 5. Delete external services 6. Configure services manually" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3998,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "The FRP client has been installed" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4008,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "The FRP client has been updated" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4019,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "应用已卸载" ;; 4) @@ -4066,68 +4065,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp download tool" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp is a powerful video download tool that supports thousands of sites including YouTube, Bilibili, Twitter, etc." - echo -e "Official website address: https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "Downloaded video list:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(None yet)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. Single video download 6. Batch video download 7. Custom parameter download" - echo "8. Download as MP3 audio 9. Delete the video directory 10. Cookie management (under development)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "Please enter the option number:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "Installing yt-dlp..." - echo "Installing yt-dlp..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "The installation is complete. Press any key to continue..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "Update yt-dlp..." - echo "Update yt-dlp..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "Update completed. Press any key to continue..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "Uninstalling yt-dlp..." - echo "Uninstalling yt-dlp..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "Uninstall is complete. Press any key to continue..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "Single video download" - read -e -p "Please enter the video link:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "After the download is complete, press any key to continue..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "Batch video download" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# Enter multiple video link addresses\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "Now start batch download..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4134,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "The batch download is completed, press any key to continue..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "Custom video download" - read -e -p "Please enter the full yt-dlp parameter (excluding yt-dlp):" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "After the execution is completed, press any key to continue..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3 download" - read -e -p "Please enter the video link:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "The audio download is completed, press any key to continue..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "Delete video" - read -e -p "Please enter the name of the delete video:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4194,7 @@ set_timedate() { -# Fix dpkg interrupt problem +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4203,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}System update...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4222,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "Unknown package manager!" + echo "未知的包管理器!" return fi } @@ -4231,7 +4230,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}Cleaning up the system...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4259,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "Clean the package manager cache..." + echo "清理包管理器缓存..." apk cache clean - echo "Delete the system log..." + echo "删除系统日志..." rm -rf /var/log/* - echo "Delete APK cache..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "Delete temporary files..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4283,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "Delete the system log..." + echo "删除系统日志..." rm -rf /var/log/* - echo "Delete temporary files..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "Clean up unused dependencies..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "Clean the package manager cache..." + echo "清理包管理器缓存..." pkg clean -y - echo "Delete the system log..." + echo "删除系统日志..." rm -rf /var/log/* - echo "Delete temporary files..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "Unknown package manager!" + echo "未知的包管理器!" return fi return @@ -4340,26 +4339,26 @@ fi set_dns_ui() { root_use -send_stats "Optimize DNS" +send_stats "优化DNS" while true; do clear - echo "Optimize DNS address" + echo "优化DNS地址" echo "------------------------" - echo "Current DNS address" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. Foreign DNS optimization:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. Domestic DNS optimization:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. Manually edit DNS configuration" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4366,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "Foreign DNS optimization" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4374,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "Domestic DNS optimization" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "Manually edit DNS configuration" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4402,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # If PasswordAuthentication is found, set to yes + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # If found PubkeyAuthentication is set to yes + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4416,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # If neither PasswordAuthentication nor PubkeyAuthentication matches, set the default value + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4427,7 @@ correct_ssh_config() { new_ssh_port() { - # Backup SSH configuration files + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4440,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "The SSH port has been modified to:$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4458,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "The private key information has been generated. Be sure to copy and save it.${gl_huang}${ipv4_address}_ssh.key${gl_bai}File for future SSH login" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4470,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login is enabled, ROOT password login has been closed, reconnection will take effect${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "Please enter your SSH public key contents (usually starting with 'ssh-rsa' or 'ssh-ed25519'):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}Error: The public key content was not entered.${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4498,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}The public key has been successfully imported, the ROOT private key login has been enabled, the ROOT password login has been closed, and the reconnection will take effect${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4507,26 @@ import_sshkey() { add_sshpasswd() { -echo "Set your ROOT password" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login is set up!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "Reinstall the system" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4537,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "Initial username after reinstallation:${gl_huang}root${gl_bai}Initial password:${gl_huang}LeitboGi0ro${gl_bai}Initial port:${gl_huang}22${gl_bai}" - echo -e "Press any key to continue..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "Initial username after reinstallation:${gl_huang}Administrator${gl_bai}Initial password:${gl_huang}Teddysun.com${gl_bai}Initial port:${gl_huang}3389${gl_bai}" - echo -e "Press any key to continue..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "Initial username after reinstallation:${gl_huang}root${gl_bai}Initial password:${gl_huang}123@@@${gl_bai}Initial port:${gl_huang}22${gl_bai}" - echo -e "Press any key to continue..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "Initial username after reinstallation:${gl_huang}Administrator${gl_bai}Initial password:${gl_huang}123@@@${gl_bai}Initial port:${gl_huang}3389${gl_bai}" - echo -e "Press any key to continue..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "Reinstall the system" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." - echo -e "${gl_hui}Thanks to the script support of leitbogioro and bin456789!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4587,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos Feiniu public beta version" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please select the system to reinstall:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "Reinstall debian 13" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4609,49 @@ dd_xitong() { ;; 2) - send_stats "Reinstall debian 12" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Reinstall debian 11" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Reinstall debian 10" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "Reinstall ubuntu 24.04" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "Reinstall ubuntu 22.04" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Reinstall ubuntu 20.04" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "Reinstall ubuntu 18.04" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4660,7 @@ dd_xitong() { 21) - send_stats "Reinstall rockylinux10" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4668,7 @@ dd_xitong() { ;; 22) - send_stats "Reinstall rockylinux9" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4676,7 @@ dd_xitong() { ;; 23) - send_stats "Reinstall alma10" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4684,7 @@ dd_xitong() { ;; 24) - send_stats "Reinstall alma9" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4692,7 @@ dd_xitong() { ;; 25) - send_stats "Reinstall oracle10" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4700,7 @@ dd_xitong() { ;; 26) - send_stats "Reinstall oracle9" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4708,7 @@ dd_xitong() { ;; 27) - send_stats "Reinstall fedora42" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4716,7 @@ dd_xitong() { ;; 28) - send_stats "Reinstall fedora41" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4724,7 @@ dd_xitong() { ;; 29) - send_stats "Reinstall centos10" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4732,7 @@ dd_xitong() { ;; 30) - send_stats "Reinstall centos9" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4740,7 @@ dd_xitong() { ;; 31) - send_stats "Reinstall alpine" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4748,7 @@ dd_xitong() { ;; 32) - send_stats "Reinstall arch" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4756,7 @@ dd_xitong() { ;; 33) - send_stats "Reinstall kali" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4764,7 @@ dd_xitong() { ;; 34) - send_stats "Reinstall openeuler" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4772,7 @@ dd_xitong() { ;; 35) - send_stats "Reinstall opensuse" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4780,7 @@ dd_xitong() { ;; 36) - send_stats "Reload flying cow" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4789,7 @@ dd_xitong() { 41) - send_stats "Reinstall windows11" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4797,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Reinstall Windows 10" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Reinstall Windows 7" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4811,21 @@ dd_xitong() { ;; 44) - send_stats "Reinstall windows server 22" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Reinstall windows server 19" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Reinstall windows server 16" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4833,7 @@ dd_xitong() { ;; 47) - send_stats "Reinstall windows11 ARM" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4850,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3 management" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4863,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "You have installed xanmod's BBRv3 kernel" - echo "Current kernel version:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "Kernel Management" + echo "内核管理" echo "------------------------" - echo "1. Update the BBRv3 kernel 2. Uninstall the BBRv3 kernel" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4883,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # Step 3: Add a repository + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4892,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "The XanMod kernel has been updated. Take effect after restart" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4902,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "The XanMod kernel is uninstalled. Take effect after restart" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4915,13 @@ bbrv3() { else clear - echo "Set up BBR3 acceleration" - echo "Video introduction: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Only support Debian/Ubuntu" - echo "Please back up the data and will enable BBR3 for you to upgrade the Linux kernel." + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4929,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "The current environment does not support it, only supports Debian and Ubuntu systems" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "Unable to determine the operating system type" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4945,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # Step 3: Add a repository + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4956,17 @@ bbrv3() { bbr_on - echo "XanMod kernel is installed and BBR3 is enabled successfully. Take effect after restart" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4975,40 @@ bbrv3() { elrepo_install() { - # Import ELRepo GPG public key - echo "Import the ELRepo GPG public key..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # Detect system version + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # Make sure we run on a supported operating system + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "Unsupported operating systems:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # Print detected operating system information - echo "Operating system detected:$os_name $os_version" - # Install the corresponding ELRepo warehouse configuration according to the system version + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Install ELRepo repository configuration (version 8)..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Install ELRepo repository configuration (version 9)..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Install ELRepo repository configuration (version 10)..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "Unsupported system versions:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Enable the ELRepo kernel repository and install the latest mainline kernel - echo "Enable the ELRepo kernel repository and install the latest mainline kernel..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "The ELRepo repository configuration is installed and updated to the latest mainline kernel." + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5016,37 @@ elrepo_install() { elrepo() { root_use - send_stats "Red Hat Kernel Management" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "You have installed the elrepo kernel" - echo "Current kernel version:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "Kernel Management" + echo "内核管理" echo "------------------------" - echo "1. Update the elrepo kernel 2. Uninstall the elrepo kernel" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Update the Red Hat kernel" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "The elrepo kernel is uninstalled. Take effect after restart" - send_stats "Uninstall the Red Hat kernel" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5059,26 @@ elrepo() { else clear - echo "Please back up the data and will upgrade the Linux kernel for you" - echo "Video introduction: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Only support Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" - echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if conditions permit and upgrade the production environment with caution!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Upgrade the Red Hat kernel" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5089,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}Update the virus database...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5099,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "Please specify the directory to scan." + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}Scanning directory $@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # Build mount parameters + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # Build clamscan command parameters + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5120,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Execute Docker commands + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5129,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ Scan is completed, virus report is stored${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}If there is a virus, please${gl_huang}scan.log${gl_lv}Search for FOUND keyword in the file to confirm the location of the virus${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5142,23 @@ clamav_scan() { clamav() { root_use - send_stats "Virus Scan Management" + send_stats "病毒扫描管理" while true; do clear - echo "clamav virus scanning tool" - echo "Video introduction: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "It is an open source antivirus software tool, mainly used to detect and remove various types of malware." - echo "Including viruses, Trojan horses, spyware, malicious scripts and other harmful software." + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1. Full disk scan${gl_bai} ${gl_huang}2. Scan the important directory${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Full disk scan" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5167,7 @@ clamav() { ;; 2) - send_stats "Important directory scan" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5175,8 @@ clamav() { break_end ;; 3) - send_stats "Custom directory scanning" - read -e -p "Please enter the directory to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5193,21 @@ clamav() { -# High-performance mode optimization function +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}Switch to${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}Optimize network settings...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5219,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}Optimize cache management...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable large transparent pages to reduce latency + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # Disable NUMA balancing + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# Equalization mode optimization function +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}Switch to equalization mode...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}Optimize network settings...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5260,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}Optimize cache management...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Restore transparent page + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # Restore NUMA balancing + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# Restore the default settings function +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}Restore to default settings...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}Restore file descriptor...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}Restore virtual memory...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}Restore network settings...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5301,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}Restore cache management...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}Restore CPU settings...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}Restore other optimizations...${gl_bai}" - # Restore transparent page + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # Restore NUMA balancing + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# Website building optimization function +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}Switch to the website building optimization mode...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}Optimize network settings...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5343,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}Optimize cache management...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable large transparent pages to reduce latency + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # Disable NUMA balancing + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5363,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux kernel tuning management" - echo "Optimization of kernel parameters in Linux system" - echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "A variety of system parameter tuning modes are provided, and users can choose and switch according to their own usage scenarios." - echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." - echo "2. Balanced optimization mode: Balance between performance and resource consumption, suitable for daily use." - echo "3. Website optimization mode: Optimize for the website server to improve concurrent connection processing capabilities, response speed and overall performance." - echo "4. Live broadcast optimization mode: Optimize the special needs of live broadcast streaming to reduce latency and improve transmission performance." - echo "5. Game server optimization mode: Optimize for game servers to improve concurrent processing capabilities and response speed." - echo "6. Restore the default settings: Restore the system settings to the default configuration." + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "High performance mode optimization" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "Balanced mode optimization" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "Live streaming optimization" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "Game server optimization" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "Restore default settings" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5445,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5454,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "Unsupported systems:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "Unsupported systems, system type cannot be recognized." + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5474,29 @@ update_locale() { linux_language() { root_use -send_stats "Switch system language" +send_stats "切换系统语言" while true; do clear - echo "Current system language:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1. English 2. Simplified Chinese 3. Traditional Chinese" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "Switch to English" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "Switch to Simplified Chinese" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "Switch to Traditional Chinese" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5518,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}Change is completed. Reconnect SSH to view changes!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5530,10 +5529,10 @@ break_end shell_bianse() { root_use - send_stats "Command line beautification tool" + send_stats "命令行美化工具" while true; do clear - echo "Command line beautification tool" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5542,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5589,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "System Recycling Station" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5604,17 @@ linux_trash() { fi clear - echo -e "Current recycling bin${trash_status}" - echo -e "After enabling, the files deleted by rm will first enter the recycling bin to prevent the mistaken deletion of important files!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "The recycling bin is empty" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1. Enable the Recycle Bin 2. Close the Recycle Bin" - echo "3. Restore content 4. Clear the recycling bin" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5622,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "The Recycle Bin is enabled and deleted files will be moved to the Recycle Bin." + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,23 +5630,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "The recycling bin is closed and the file will be deleted directly." + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "Enter the file name to restore:" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreRestored to the home directory." + echo "$file_to_restore 已还原到主目录。" else - echo "The file does not exist." + echo "文件不存在。" fi ;; 4) - read -e -p "Confirm to clear the recycling bin? [y/n]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "The recycling bin has been cleared." + echo "回收站已清空。" fi ;; *) @@ -5658,23 +5657,23 @@ linux_trash() { } linux_fav() { -send_stats "Command Favorites" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# 创建备份 create_backup() { - send_stats "Create a backup" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # Prompt the user to enter the backup directory - echo "Create a backup example:" - echo "- Backup a single directory: /var/www" - echo "- Backup multiple directories: /etc /home /var/log" - echo "- Direct Enter will use the default directory (/etc /usr /home)" - read -r -p "Please enter the directory to back up (multiple directories are separated by spaces, and if you enter directly, use the default directory):" input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # If the user does not enter a directory, use the default directory + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5681,119 @@ create_backup() { "/home" # 用户数据 ) else - # Separate the directory entered by the user into an array by spaces + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # Generate backup file prefix + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # Extract directory name and remove slashes + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # Remove the last underscore + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # Generate backup file name + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # Print the directory selected by the user - echo "The backup directory you selected is:" + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # Create a backup - echo "Creating a backup$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # Check if the command is successful + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "The backup was created successfully:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "Backup creation failed!" + echo "备份创建失败!" exit 1 fi } -# Restore backup +# 恢复备份 restore_backup() { - send_stats "Restore backup" - # Select the backup you want to restore - read -e -p "Please enter the backup file name to restore:" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # Check if the backup file exists + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "The backup file does not exist!" + echo "备份文件不存在!" exit 1 fi - echo "Recovering backup$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "Backup and restore successfully!" + echo "备份恢复成功!" else - echo "Backup recovery failed!" + echo "备份恢复失败!" exit 1 fi } -# List backups +# 列出备份 list_backups() { - echo "Available backups:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# Delete backup +# 删除备份 delete_backup() { - send_stats "Delete backup" + send_stats "删除备份" - read -e -p "Please enter the backup file name to delete:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # Check if the backup file exists + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "The backup file does not exist!" + echo "备份文件不存在!" exit 1 fi - # Delete backup + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "The backup was deleted successfully!" + echo "备份删除成功!" else - echo "Backup deletion failed!" + echo "备份删除失败!" exit 1 fi } -# Backup main menu +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "System backup function" - echo "System backup function" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. Create a backup 2. Restore a backup 3. Delete the backup" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "Press Enter to continue..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5805,56 @@ linux_backup() { -# Show connection list +# 显示连接列表 list_connections() { - echo "Saved connection:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# Add a new connection +# 添加新连接 add_connection() { - send_stats "Add a new connection" - echo "Example to create a new connection:" - echo "- Connection name: my_server" - echo "- IP address: 192.168.1.100" - echo "- Username: root" - echo "- Port: 22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "Please enter the connection name:" name - read -e -p "Please enter your IP address:" ip - read -e -p "Please enter the username (default: root):" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "Please enter the port number (default: 22):" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "Please select the authentication method:" - echo "1. Password" - echo "2. Key" - read -e -p "Please enter the selection (1/2):" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "Please enter your password:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "Please paste the key content (press press Enter twice after pasting):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # If the input is empty and the key content already contains the beginning, the input ends + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or the key content has been entered, continue to add + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # Check if it is the key content + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5863,89 @@ add_connection() { fi ;; *) - echo "Invalid choice!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "The connection is saved!" + echo "连接已保存!" } -# Delete a connection +# 删除连接 delete_connection() { - send_stats "Delete a connection" - read -e -p "Please enter the connection number to delete:" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "Error: The corresponding connection was not found." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # If the connection is using a key file, delete the key file + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "The connection has been deleted!" + echo "连接已删除!" } -# Use connection +# 使用连接 use_connection() { - send_stats "Use connection" - read -e -p "Please enter the connection number to use:" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "Error: The corresponding connection was not found." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "Connecting to$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # Connect with a key + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "Connection failed! Please check the following:" - echo "1. Is the key file path correct?$password_or_key" - echo "2. Whether the key file permissions are correct (should be 600)." - echo "3. Whether the target server allows login using the key." + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # Connect with a password + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "Error: sshpass is not installed, please install sshpass first." - echo "Installation method:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "Connection failed! Please check the following:" - echo "1. Whether the username and password are correct." - echo "2. Whether the target server allows password login." - echo "3. Whether the SSH service of the target server is running normally." + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "ssh remote connection tool" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # Check if the configuration file and key directory exist, and if it does not exist, create it + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5957,21 @@ ssh_manager() { while true; do clear - echo "SSH Remote Connection Tool" - echo "Can connect to other Linux systems via SSH" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1. Create a new connection 2. Use a connection 3. Delete a connection" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "Invalid selection, please try again." ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5987,156 @@ ssh_manager() { -# List available hard disk partitions +# 列出可用的硬盘分区 list_partitions() { - echo "Available hard disk partitions:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# Mount the partition +# 挂载分区 mount_partition() { - send_stats "Mount the partition" - read -e -p "Please enter the partition name to be mounted (for example, sda1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # Check if the partition exists + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "The partition does not exist!" + echo "分区不存在!" return fi - # Check if the partition is already mounted + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "The partition is already mounted!" + echo "分区已经挂载!" return fi - # Create a mount point + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # Mount the partition + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "Partition mount successfully:$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "Partition mount failed!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# Uninstall the partition +# 卸载分区 unmount_partition() { - send_stats "Uninstall the partition" - read -e -p "Please enter the partition name (for example, sda1):" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # Check if the partition is already mounted + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "The partition is not mounted!" + echo "分区未挂载!" return fi - # Uninstall the partition + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "Partition uninstallation successfully:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "Partition uninstallation failed!" + echo "分区卸载失败!" fi } -# List mounted partitions +# 列出已挂载的分区 list_mounted_partitions() { - echo "Mounted partition:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# Format partition +# 格式化分区 format_partition() { - send_stats "Format partition" - read -e -p "Please enter the partition name to format (for example, sda1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # Check if the partition exists + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "The partition does not exist!" + echo "分区不存在!" return fi - # Check if the partition is already mounted + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "The partition has been mounted, please uninstall it first!" + echo "分区已经挂载,请先卸载!" return fi - # Select a file system type - echo "Please select the file system type:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "Please enter your selection:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "Invalid choice!"; return ;; + *) echo "无效的选择!"; return ;; esac - # Confirm formatting - read -e -p "Confirm formatting partition /dev/$PARTITIONfor$FS_TYPEIs it? (y/n):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "The operation has been cancelled." + echo "操作已取消。" return fi - # Format partition - echo "Formatting partition /dev/$PARTITIONfor$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "The partition format was successful!" + echo "分区格式化成功!" else - echo "Partition formatting failed!" + echo "分区格式化失败!" fi } -# Check partition status +# 检查分区状态 check_partition() { - send_stats "Check partition status" - read -e -p "Please enter the partition name to check (for example sda1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # Check if the partition exists + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "The partition does not exist!" + echo "分区不存在!" return fi - # Check partition status - echo "Check partition /dev/$PARTITIONStatus:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# Main Menu +# 主菜单 disk_manager() { - send_stats "Hard disk management function" + send_stats "硬盘管理功能" while true; do clear - echo "Hard disk partition management" - echo -e "${gl_huang}This function is internally tested during the test period, please do not use it in the production environment.${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. Mount the partition 2. Uninstall the partition 3. View mounted partition" - echo "4. Format the partition 5. Check the partition status" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6145,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Press Enter to continue..." + read -e -p "按回车键继续..." done } -# Show task list +# 显示任务列表 list_tasks() { - echo "Saved synchronization tasks:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# Add a new task +# 添加新任务 add_task() { - send_stats "Add a new synchronization task" - echo "Create a new synchronization task example:" - echo "- Task name: backup_www" - echo "- Local Directory: /var/www" - echo "- Remote address: user@192.168.1.100" - echo "- Remote Directory: /backup/www" - echo "- Port number (default 22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "Please enter the task name:" name - read -e -p "Please enter the local directory:" local_path - read -e -p "Please enter the remote directory:" remote_path - read -e -p "Please enter the remote user @IP:" remote - read -e -p "Please enter the SSH port (default 22):" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "Please select the authentication method:" - echo "1. Password" - echo "2. Key" - read -e -p "Please select (1/2):" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "Please enter your password:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "Please paste the key content (press press Enter twice after pasting):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # If the input is empty and the key content already contains the beginning, the input ends + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or the key content has been entered, continue to add + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # Check if it is the key content + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6210,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "Invalid key content!" + echo "无效的密钥内容!" return fi ;; *) - echo "Invalid choice!" + echo "无效的选择!" return ;; esac - echo "Please select the synchronization mode:" - echo "1. Standard mode (-avz)" - echo "2. Delete the target file (-avz --delete)" - read -e -p "Please select (1/2):" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "Invalid selection, use default -avz"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "Task saved!" + echo "任务已保存!" } -# Delete a task +# 删除任务 delete_task() { - send_stats "Delete synchronization tasks" - read -e -p "Please enter the task number to delete:" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "Error: The corresponding task was not found." + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # If the task is using a key file, delete the key file + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "Task deleted!" + echo "任务已删除!" } run_task() { - send_stats "Perform synchronization tasks" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # Analyze parameters + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6277,51 @@ run_task() { num="$1" fi - # If there is no incoming task number, prompt the user to enter + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "Please enter the task number to be executed:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "Error: The task was not found!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # Adjust source and target path according to synchronization direction + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "Pulling synchronization to local:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "Push synchronization to the remote end:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # Add SSH connection common parameters + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "Error: sshpass is not installed, please install sshpass first." - echo "Installation method:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # Check whether the key file exists and whether the permissions are correct + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "Error: The key file does not exist:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "Warning: The key file permissions are incorrect, and are being repaired..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6330,32 +6329,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "Synchronization is complete!" + echo "同步完成!" else - echo "Synchronization failed! Please check the following:" - echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" - echo "3. Is the authentication information correct?" - echo "4. Do local and remote directories have correct access permissions" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# Create a timed task +# 创建定时任务 schedule_task() { - send_stats "Add synchronization timing tasks" + send_stats "添加同步定时任务" - read -e -p "Please enter the task number to be synchronized regularly:" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "Error: Please enter a valid task number!" + echo "错误: 请输入有效的任务编号!" return fi - echo "Please select the timed execution interval:" - echo "1) Execute once an hour" - echo "2) Perform once a day" - echo "3) Execute once a week" - read -e -p "Please enter options (1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6362,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "Error: Please enter a valid option!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # Check if the same task already exists + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "Error: The timing synchronization of this task already exists!" + echo "错误: 该任务的定时同步已存在!" return fi - # Create a crontab to the user + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "The timing task has been created:$cron_job" + echo "定时任务已创建: $cron_job" } -# View scheduled tasks +# 查看定时任务 view_tasks() { - echo "Current timing tasks:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# Delete timing tasks +# 删除定时任务 delete_task_schedule() { - send_stats "Delete synchronization timing tasks" - read -e -p "Please enter the task number to delete:" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "Error: Please enter a valid task number!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "Deleted task number$numTiming tasks" + echo "已删除任务编号 $num 的定时任务" } -# Task Management Main Menu +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync remote synchronization tool" - echo "Synchronization between remote directories supports incremental synchronization, efficient and stable." + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. Create a new task 2. Delete a task" - echo "3. Perform local synchronization to the remote end 4. Perform remote synchronization to the local end" - echo "5. Create a timing task 6. Delete a timing task" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6430,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "Invalid selection, please try again." ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "Press Enter to continue..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6447,7 @@ rsync_manager() { linux_ps() { clear - send_stats "System information query" + send_stats "系统信息查询" ip_address @@ -6498,41 +6497,41 @@ linux_ps() { echo "" - echo -e "System information query" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Host Name:${gl_bai}$hostname" - echo -e "${gl_kjlan}System version:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux version:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU architecture:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU model:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}Number of CPU cores:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU frequency:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU occupancy:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}System load:${gl_bai}$load" - echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" - echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" - echo -e "${gl_kjlan}Hard disk occupation:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" - echo -e "${gl_kjlan}Total send:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Operator:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 address:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6 address:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS address:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}Geographical location:${gl_bai}$country $city" - echo -e "${gl_kjlan}System time:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Runtime:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6544,111 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" - echo -e "Basic tools" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo super management permission tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" - echo -e "${gl_kjlan}5. ${gl_bai}htop system monitoring tool${gl_kjlan}6. ${gl_bai}iftop network traffic monitoring tool" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP compression decompression tool${gl_kjlan}8. ${gl_bai}tar GZ compression decompression tool" - echo -e "${gl_kjlan}9. ${gl_bai}tmux multi-channel background running tool${gl_kjlan}10. ${gl_bai}ffmpeg video encoding live streaming tool" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tools${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}range file management tool" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk occupation viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" - echo -e "${gl_kjlan}15. ${gl_bai}vim text editor${gl_kjlan}16. ${gl_bai}nano text editor${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git version control system" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screen Guarantee${gl_kjlan}22. ${gl_bai}Train screen security" - echo -e "${gl_kjlan}26. ${gl_bai}Tetris game${gl_kjlan}27. ${gl_bai}Snake-eating game" - echo -e "${gl_kjlan}28. ${gl_bai}Space Invader Game" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}All installations (excluding screen savers and games)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Uninstall all" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Install the specified tool${gl_kjlan}42. ${gl_bai}Uninstall the specified tool" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" curl --help - send_stats "Install curl" + send_stats "安装curl" ;; 2) clear install wget clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" wget --help - send_stats "Install wget" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" sudo --help - send_stats "Install sudo" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" socat -h - send_stats "Install socat" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "Install htop" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "Install iftop" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" unzip - send_stats "Install unzip" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" tar --help - send_stats "Install tar" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" tmux --help - send_stats "Install tmux" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "The tool has been installed and the usage method is as follows:" + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "Install ffmpeg" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6656,7 @@ linux_tools() { install btop clear btop - send_stats "Install btop" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6665,7 @@ linux_tools() { clear ranger cd ~ - send_stats "Install ranger" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6674,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "Install ncdu" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6683,7 @@ linux_tools() { clear fzf cd ~ - send_stats "Install fzf" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6692,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "Install vim" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6701,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "Install nano" + send_stats "安装nano" ;; @@ -6713,7 +6712,7 @@ linux_tools() { clear git --help cd ~ - send_stats "Install git" + send_stats "安装git" ;; 21) @@ -6721,67 +6720,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "Install cmatrix" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "Install sl" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "Install bastet" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "Install nsnake" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Install ninvaders" + send_stats "安装ninvaders" ;; 31) clear - send_stats "Install all" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "Install all (excluding games and screen savers)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "Uninstall all" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "Please enter the installed tool name (wget curl sudo htop):" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "Install the specified software" + send_stats "安装指定软件" ;; 42) clear - read -e -p "Please enter the uninstalled tool name (htop ufw tmux cmatrix):" removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "Uninstall the specified software" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6788,7 @@ linux_tools() { ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -6803,27 +6802,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr management" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "Current TCP blocking algorithm:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" - echo "BBR Management" + echo "BBR管理" echo "------------------------" - echo "1. Turn on BBRv3 2. Turn off BBRv3 (restarts)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "Alpine enable bbr3" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6868,18 +6867,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}Current backup list:${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "No backup" + echo -e "${BLUE}当前备份列表:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } # ---------------------------- - # Backup + # 备份 # ---------------------------- backup_docker() { - echo -e "${YELLOW}Backing up Docker container...${NC}" - read -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers + send_stats "Docker备份" + + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6890,7 +6892,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}No container found${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6898,28 +6900,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# Automatically generated restore script" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # Record the path of the packaged Compose project to avoid duplicate packaging + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}Backup container:$c${NC}" + echo -e "${GREEN}备份容器: $c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}Detected$cYes docker-compose container${NC}" + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "The compose directory is not detected, please enter the path manually:" project_dir + read -p "未检测到 compose 目录,请手动输入路径: " project_dir fi - # If the Compose project has been packaged, skip it + # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" continue fi @@ -6927,136 +6929,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose project [$project_name] Packed:${project_dir}${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" else - echo -e "${RED}docker-compose.yml not found, skip this container...${NC}" + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" fi else - # Normal container backup volume + # 普通容器备份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "Packing rolls:$path" + echo "打包卷: $path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # port + # 端口 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # Environment variables + # 环境变量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # Volume Mapping + # 卷映射 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # 镜像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# Restore container:$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # Backup all files under /home/docker (excluding subdirectories) + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}Backup the files under /home/docker...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - - echo -e "${GREEN}The file under /home/docker has been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}Backup is complete:${BACKUP_DIR}${NC}" - echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # reduction + # 还原 # ---------------------------- restore_docker() { - list_backups - read -p "Please enter the backup directory to restore:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } - echo -e "${BLUE}Start the restore operation...${NC}" + send_stats "Docker还原" + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" install tar jq gzip install_docker - # ------------------------- + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "The original path was not found, please enter the restore directory path:" original_path + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path - # Check if the container for the compose project is already running + # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" continue fi - read -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "Please enter a new restore path:" original_path + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose project [$project_name] Decompressed to:$original_path${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose project [$project_name] Restore is complete!${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" fi done - # ------------------------- - echo -e "${BLUE}Check and restore a normal Docker container...${NC}" + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}Processing container:$container${NC}" + echo -e "${GREEN}处理容器: $container${NC}" - # Check if the container already exists and is running + # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}Container [$container] is running, skip restore...${NC}" + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information was not found, skip:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } - # Port Mapping + # 端口映射 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # Environment variables + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # Volume Mapping + Volume Data Recovery + # 卷映射 + 卷数据恢复 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7067,32 +7070,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "Recover volume data:$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # Delete existing but not running containers + # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}Container [$container] Exist but not running, delete the old container...${NC}" + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" docker rm -f "$container" fi - # Start the container - echo "Execute the restore command: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for normal containers was found${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" - # Restore the file under /home/docker + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}Restore the file under /home/docker...${NC}" + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}The file under /home/docker has been restored${NC}" + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else - echo -e "${YELLOW}No backup of the file under /home/docker was found, skip...${NC}" + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" fi @@ -7100,66 +7103,68 @@ docker_ssh_migration() { # ---------------------------- - # migrate + # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups - read -p "Please enter the backup directory to migrate:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + send_stats "Docker迁移" + install jq + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "Target server IP:" TARGET_IP - read -p "Target server SSH username:" TARGET_USER + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}Transfer backup...${NC}" + echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with a key + # 使用密钥登录 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # Delete backup + # 删除备份 # ---------------------------- delete_backup() { - list_backups - read -p "Please enter the backup directory to delete:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + send_stats "Docker备份文件删除" + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" } # ---------------------------- - # Main Menu + # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" - echo -e "Docker backup/migration/restore tool" + echo -e "Docker备份/迁移/还原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. Backup the docker project" - echo -e "2. Migrate docker projects" - echo -e "3. Restore the docker project" - echo -e "4. Delete the backup file of the docker project" + echo -e "1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. Return to the previous menu" + echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "Please select:" choice + read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}Invalid option${NC}" ;; + *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } @@ -7174,38 +7179,38 @@ linux_docker() { while true; do clear - # send_stats "docker management" - echo -e "Docker Management" + # send_stats "docker管理" + echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Install and update Docker environment${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}View Docker global status${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker container management${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker image management" - echo -e "${gl_kjlan}5. ${gl_bai}Docker Network Management" - echo -e "${gl_kjlan}6. ${gl_bai}Docker volume management" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}Clean useless docker containers and mirror network data volumes" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Replace Docker source" - echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" - echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Backup/Migration/Restore Docker Environment" - echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Install docker environment" + send_stats "安装docker环境" install_add_docker ;; @@ -7216,22 +7221,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Docker global status" - echo "Docker version" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker image:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker container:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker volume:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker Network:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7246,8 +7251,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker Network Management" - echo "Docker network list" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -7271,36 +7276,36 @@ linux_docker() { done echo "" - echo "Network operation" + echo "网络操作" echo "------------------------" - echo "1. Create a network" - echo "2. Join the Internet" - echo "3. Exit the network" - echo "4. Delete the network" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Create a network" - read -e -p "Set a new network name:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "Join the Internet" - read -e -p "Join the network name:" dockernetwork - read -e -p "Those containers are added to the network (multiple container names are separated by spaces):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "Join the Internet" - read -e -p "Exit network name:" dockernetwork - read -e -p "Those containers exit the network (multiple container names are separated by spaces):" dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7309,8 +7314,8 @@ linux_docker() { ;; 4) - send_stats "Delete the network" - read -e -p "Please enter the network name to delete:" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7324,29 +7329,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker volume management" - echo "Docker volume list" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "Volume operation" + echo "卷操作" echo "------------------------" - echo "1. Create a new volume" - echo "2. Delete the specified volume" - echo "3. Delete all volumes" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "Create a new volume" - read -e -p "Set the new volume name:" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "Enter the delete volume name (please separate multiple volume names with spaces):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7355,7 +7360,7 @@ linux_docker() { ;; 3) - send_stats "Delete all volumes" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7364,7 +7369,7 @@ linux_docker() { [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7377,7 +7382,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker cleaning" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7386,13 +7391,13 @@ linux_docker() { [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "Docker source" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7408,13 +7413,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 open" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 level" + send_stats "Docker v6 关" docker_ipv6_off ;; @@ -7425,7 +7430,7 @@ linux_docker() { 20) clear - send_stats "Docker uninstall" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7437,7 +7442,7 @@ linux_docker() { [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7446,7 +7451,7 @@ linux_docker() { kejilion ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -7463,151 +7468,151 @@ linux_test() { while true; do clear - # send_stats "Test script collection" - echo -e "Test script collection" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP and unlock status detection" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT Unlock Status Detection" - echo -e "${gl_kjlan}2. ${gl_bai}Region streaming media unlock test" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu streaming media unlock detection" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality physical examination script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Network speed measurement" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace three network backhaul delay routing test" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace Three-network backhaul line test" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed three-net speed measurement" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace Specifies IP backhaul test script" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three-network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunction speed test script" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality Network Quality Physical Examination Script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Hardware performance testing" - echo -e "${gl_kjlan}21. ${gl_bai}yabs performance testing" - echo -e "${gl_kjlan}22. ${gl_bai}iicu/gb5 CPU performance test script" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Comprehensive test" - echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" - echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT unlock status detection" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region streaming media unlock test" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu streaming media unlock detection" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP quality physical examination script" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "Besttrace three network backhaul delay routing test" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace three network return line test" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed three-net speed measurement" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace fast backhaul test script" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace specifies IP backhaul test script" - echo "List of IPs that can be referenced" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "Beijing Telecom: 219.141.136.12" - echo "Beijing Unicom: 202.106.50.1" - echo "Beijing Mobile: 221.179.155.161" - echo "Shanghai Telecom: 202.96.209.133" - echo "Shanghai Unicom: 210.22.97.1" - echo "Shanghai Mobile: 211.136.112.200" - echo "Guangzhou Telecom: 58.60.188.222" - echo "Guangzhou Unicom: 210.21.196.6" - echo "Guangzhou Mobile: 120.196.165.24" - echo "Chengdu Telecom: 61.139.2.69" - echo "Chengdu Unicom: 119.6.6.6" - echo "Chengdu Mobile: 211.137.96.205" - echo "Hunan Telecom: 36.111.200.100" - echo "Hunan Unicom: 42.48.16.100" - echo "Hunan Mobile: 39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "Enter a specified IP:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020 three-network line test" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc multifunction speed test script" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "Network quality test script" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs performance testing" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "iicu/gb5 CPU performance test script" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench performance test" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "Spiritysdx Fusion Monster Review" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7617,7 +7622,7 @@ linux_test() { ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -7633,51 +7638,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Script Collection" - echo -e "Oracle Cloud Script Collection" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Install idle machine active script" - echo -e "${gl_kjlan}2. ${gl_bai}Uninstall idle machine active script" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD reinstall system script" - echo -e "${gl_kjlan}4. ${gl_bai}Detective R start script" - echo -e "${gl_kjlan}5. ${gl_bai}Turn on ROOT password login mode" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6 recovery tool" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "Active script: CPU occupies 10-20% memory occupies 20%" - read -e -p "Are you sure to install it? (Y/N):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # Set default values + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # Prompt the user to enter the number of CPU cores and occupancy percentage, and if entered, use the default value. - read -e -p "Please enter the number of CPU cores [default:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "Please enter the CPU usage percentage range (for example, 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "Please enter the memory usage percentage [default:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "Please enter the Speedtest interval time (seconds) [default:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Run Docker container + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7685,14 +7690,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloud Installation Active Script" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7700,20 +7705,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud Uninstall Active Script" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "Reinstall the system" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." - read -e -p "Are you sure to continue? (Y/N):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "Please select the system to reinstall: 1. Debian12 | 2. Ubuntu20.04:" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7725,28 +7730,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "Invalid selection, please re-enter." + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "Please enter your reinstalled password:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud Reinstall System Script" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "This feature is in the development stage, so stay tuned!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7756,15 +7761,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "This function is provided by the master jhb, thanks to him!" - send_stats "ipv6 fix" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -7785,7 +7790,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}The environment has been installed${gl_bai}container:${gl_lv}$container_count${gl_bai}Mirror:${gl_lv}$image_count${gl_bai}network:${gl_lv}$network_count${gl_bai}roll:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7806,7 +7811,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}The environment is installed${gl_bai}Site:$outputdatabase:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7834,31 +7839,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP website building" - echo -e "${gl_huang}LDNMP website building" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}Install LDNMP environment${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install the Kadao Cloud Desktop" - echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Film and Television Station${gl_huang}6. ${gl_bai}Install a Unicorn Digital Card Network" - echo -e "${gl_huang}7. ${gl_bai}Install the flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" - echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Customize dynamic site" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" - echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" - echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" - echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" - echo -e "${gl_huang}30. ${gl_bai}Customize static site" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up the entire site data" - echo -e "${gl_huang}33. ${gl_bai}Timed remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environment${gl_huang}36. ${gl_bai}Optimize LDNMP environment" - echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall LDNMP environment" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}Return to main menu" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7872,10 +7877,10 @@ linux_ldnmp() { 3) clear - # Discuz Forum + # Discuz论坛 webname="Discuz论坛" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,21 +7903,21 @@ linux_ldnmp() { ldnmp_web_on - echo "Database address: mysql" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Table prefix: discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao Cloud Desktop + # 可道云桌面 webname="可道云桌面" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7934,20 +7939,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "Database address: mysql" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Database name:$dbname" - echo "redis host: redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,24 +7978,24 @@ linux_ldnmp() { ldnmp_web_on - echo "Database address: mysql" - echo "Database port: 3306" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Database prefix: mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "Log in to the background address after installation is successful" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # One-legged counting card + # 独脚数卡 webname="独脚数卡" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,34 +8016,34 @@ linux_ldnmp() { ldnmp_web_on - echo "Database address: mysql" - echo "Database port: 3306" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "redis address: redis" - echo "Redis password: Not filled in by default" - echo "Redis port: 6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "Username: admin" - echo "Password: admin" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "If red error0 appears in the upper right corner when logging in, please use the following command:" - echo "I am also very angry that the unicorn number card is so troublesome, and there will be such problems!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # Flarum Forum + # flarum论坛 webname="flarum论坛" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8075,12 +8080,12 @@ linux_ldnmp() { ldnmp_web_on - echo "Database address: mysql" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Table prefix: flarum_" - echo "Administrator information is set by yourself" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -8088,8 +8093,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8113,11 +8118,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "Database prefix: typecho_" - echo "Database address: mysql" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Database name:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -8126,8 +8131,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8152,18 +8157,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "Database address: mysql" - echo "Database port: 3306" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8180,10 +8185,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] Upload PHP source code" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" - read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8193,20 +8198,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] The path where index.php is located" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "Please enter the path of index.php, similar to (/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] Please select the PHP version" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1. The latest version of php | 2. php7.4:" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8217,15 +8222,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "Invalid selection, please re-enter." + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] Install the specified extension" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "Installed extensions" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8235,25 +8240,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] Edit site configuration" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "Press any key to continue, and you can set the site configuration in detail, such as pseudo-static contents, etc." + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] Database Management" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1. I build a new site 2. I build an old site and have a database backup:" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8263,10 +8268,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "Database import table data" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "Database import completed" + echo "数据库导入完成" ;; *) echo @@ -8278,12 +8283,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "Database address: mysql" - echo "Database name:$dbname" - echo "username:$dbuse" - echo "password:$dbusepasswd" - echo "Table prefix:$prefix" - echo "Administrator login information is set by yourself" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -8296,10 +8301,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "Please enter the jump domain name:" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -8321,7 +8326,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ ports have been blocked from accessing the service" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8332,11 +8337,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "Domain name format:${gl_huang}google.com${gl_bai}" - read -e -p "Please enter your anti-generation domain name:" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8356,8 +8361,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8379,8 +8384,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8397,8 +8402,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8431,8 +8436,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "Install$webname" - echo "Start deployment$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8449,10 +8454,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] Upload static source code" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" - read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,12 +8467,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] The path where index.html is located" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "Please enter the path to index.html, similar to (/home/web/html/$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8492,21 +8497,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP environment backup" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "The backup file has been created: /home/$backup_filename" - read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "Please enter the remote server IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8514,9 +8519,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "The file has been transferred to the remote server home directory." + echo "文件已传送至远程服务器home目录。" else - echo "The file to be transferred was not found." + echo "未找到要传送的文件。" fi break ;; @@ -8524,7 +8529,7 @@ linux_ldnmp() { break ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8532,9 +8537,9 @@ linux_ldnmp() { 33) clear - send_stats "Timed remote backup" - read -e -p "Enter the remote server IP:" useip - read -e -p "Enter the remote server password:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8544,18 +8549,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. Weekly backup 2. Daily backup" - read -e -p "Please enter your selection:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "Select the day of the week for your weekly backup (0-6, 0 represents Sunday):" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "Select the time for daily backup (hours, 0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8569,19 +8574,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP environment restoration" - echo "Available site backups" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # If the user does not enter the file name, use the latest compressed package + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8591,7 +8596,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8600,7 +8605,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "No compression package was found." + echo "没有找到压缩包。" fi ;; @@ -8618,11 +8623,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "Update LDNMP environment" - echo "Update LDNMP environment" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "Discover new version of components" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8642,13 +8647,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. Update nginx 2. Update mysql 3. Update php 4. Update redis" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. Update the complete environment" + echo "5. 更新完整环境" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8657,7 +8662,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "Please enter${ldnmp_pods}Version number (such as: 8.0 8.3 8.4 9.0) (Enter to get the latest version):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8668,13 +8673,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "Please enter${ldnmp_pods}Version number (such as: 7.4 8.0 8.1 8.2 8.3) (Enter to get the latest version):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8707,8 +8712,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8719,15 +8724,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "Completely update the LDNMP environment" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8753,7 +8758,7 @@ linux_ldnmp() { 38) root_use - send_stats "Uninstall LDNMP environment" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8767,7 +8772,7 @@ linux_ldnmp() { ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8777,7 +8782,7 @@ linux_ldnmp() { ;; *) - echo "Invalid input!" + echo "无效的输入!" esac break_end @@ -8797,12 +8802,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "Application Market" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # Set the color with loop + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8811,67 +8816,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager Visual Panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" - echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" - echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" - echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome Adware${gl_kjlan}18. ${color18}onlyoffice online office OFFICE" - echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" - echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" - echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" - echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI Chat Aggregation Website" - echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" - echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}Mouse Management Panel${gl_kjlan}42. ${color42}Nexte remote connection tool" - echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}Prometheus Monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE Chicken Panel${gl_kjlan}52. ${color52}DPanel Container Management Panel" - echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" - echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" - echo -e "${gl_kjlan}65. ${color65}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" - echo -e "${gl_kjlan}67. ${color67}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL Certificate Management Platform" - echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot Chat Robot Framework" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden Password Manager${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV Private Movie" - echo -e "${gl_kjlan}75. ${color75}Melody Music Elf${gl_kjlan}76. ${color76}Online DOS old games" - echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki Intelligent Document Management System" - echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" - echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tools" - echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" - echo -e "${gl_kjlan}87. ${color87}SyncTV movie watching artifact${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser File Manager" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8990,6 +8998,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -9021,8 +9032,8 @@ while true; do docker_rum() { - read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9055,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "Build Nezha" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -9064,20 +9075,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha Monitoring$check_docker $update_status" - echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" - echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. Use" + echo "1. 使用" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9134,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "Build a post office" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -9144,43 +9155,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "Post Office Services$check_docker $update_status" - echo "poste.io is an open source mail server solution." - echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "Port detection" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}port$portCurrently available${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}port$portNot currently available${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "Access address:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "Parse these DNS records first" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9190,7 +9201,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "Press any key to continue..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -9209,9 +9220,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io has been installed" + echo "poste.io已经安装完成" echo "------------------------" - echo "You can access poste.io using the following address:" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -9234,9 +9245,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io has been installed" + echo "poste.io已经安装完成" echo "------------------------" - echo "You can access poste.io using the following address:" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -9247,7 +9258,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "应用已卸载" ;; *) @@ -9281,7 +9292,7 @@ while true; do clear ip_address - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -9291,7 +9302,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat has been installed" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -9301,7 +9312,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -9385,7 +9396,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -9399,7 +9410,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -9544,7 +9555,7 @@ while true; do ;; 19|safeline) - send_stats "Build a Thunder Pool" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -9552,20 +9563,20 @@ while true; do while true; do check_docker_app clear - echo -e "Thunder Pool Service$check_docker" - echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." - echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Reset Password 4. Uninstall" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9575,7 +9586,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "The Thunder Pool WAF panel has been installed" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9588,7 +9599,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Thunder Pool WAF panel has been updated" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9599,7 +9610,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9718,8 +9729,8 @@ while true; do docker_rum() { - read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10007,7 +10018,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10060,7 +10071,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya Family Bucket" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -10264,9 +10275,9 @@ while true; do prometheus_install clear ip_address - echo "Installed" + echo "已经安装完成" check_docker_app_ip - echo "The initial username and password are: admin" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -10284,7 +10295,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -10371,7 +10382,7 @@ while true; do 51|pve) clear - send_stats "PVE Chicken" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10491,7 +10502,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -10506,7 +10517,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -10534,7 +10545,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -10549,7 +10560,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -10557,7 +10568,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -10578,17 +10589,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip - echo "Initial username: admin" - echo "Initial password: ChangeMe" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "The app has been updated" + echo "应用已更新" } @@ -10598,7 +10609,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -10645,7 +10656,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -10661,7 +10672,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -10923,7 +10934,7 @@ while true; do docker_rum() { - read -e -p "Set the LibreTV login password:" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10957,9 +10968,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password - read -e -p "Enter the authorization code:" shouquanma + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma mkdir -p /home/docker/moontv @@ -10969,13 +10980,13 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -10989,7 +11000,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -11062,8 +11073,8 @@ while true; do docker_rum() { - read -e -p "Set login username:" app_use - read -e -p "Set login password:" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -11160,11 +11171,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # Download the official docker-compose and env files + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # Generate random keys and passwords + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11173,17 +11184,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # Add administrator account information + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # Start the container + # 启动容器 docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -11193,7 +11204,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # Keep the original variable + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11210,7 +11221,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -11260,7 +11271,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -11278,7 +11289,7 @@ while true; do docker_rum() { - read -e -p "set up${docker_name}The login key (sk-staring letters and numbers combinations) such as: sk-159kejilionyyds163:" app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11382,7 +11393,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -11395,7 +11406,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -11556,7 +11567,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "Create an initial user or administrator. Please set the following username and password and whether you are an administrator." + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11608,7 +11619,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "Installed" + echo "已经安装完成" check_docker_app_ip } @@ -11622,7 +11633,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "The app has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -11661,24 +11672,282 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + stop_containers_or_kill_process 51820 &>/dev/null + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=51820 \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 2 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 2 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear - send_stats "All applications backup" + send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "The backup file has been created: /$backup_filename" - read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "Please enter the remote server IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11686,14 +11955,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "The file has been transferred to the remote server/root directory." + echo "文件已传送至远程服务器/根目录。" else - echo "The file to be transferred was not found." + echo "未找到要传送的文件。" fi break ;; *) - echo "Note: Currently, the backup only includes docker projects, and does not include data backup of website building panels such as Pagoda and 1panel." + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" break ;; esac @@ -11703,29 +11972,29 @@ while true; do r) root_use - send_stats "All applications restore" - echo "Available app backups" + send_stats "全部应用还原" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # If the user does not enter the file name, use the latest compressed package + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else - echo "No compression package was found." + echo "没有找到压缩包。" fi ;; @@ -11748,35 +12017,35 @@ linux_work() { while true; do clear - send_stats "Backend workspace" - echo -e "Backend workspace" - echo -e "The system will provide you with a workspace that can be run on the backend, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, tasks in the workspace will not be interrupted, and tasks in the background will be resident." - echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and press d alone to exit the workspace!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "List of currently existing workspaces" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Workspace No. 1" - echo -e "${gl_kjlan}2. ${gl_bai}Workspace No. 2" - echo -e "${gl_kjlan}3. ${gl_bai}Workspace No. 3" - echo -e "${gl_kjlan}4. ${gl_bai}Workspace No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" - echo -e "${gl_kjlan}6. ${gl_bai}Workspace No. 6" - echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" - echo -e "${gl_kjlan}8. ${gl_bai}Workspace No. 8" - echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}Create/enter the workspace" - echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" - echo -e "${gl_kjlan}24. ${gl_bai}Delete the specified workspace" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11784,7 +12053,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11792,63 +12061,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "Start the workspace$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11860,21 +12129,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH resident mode" - echo -e "SSH resident mode${tmux_sshd_status}" - echo "After SSH connection is enabled, it will directly enter the resident mode and return to the previous working state." + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. Turn on 2. Turn off" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "Start the workspace$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# Automatically enter the tmux session\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11890,29 +12159,29 @@ linux_work() { ;; 22) - read -e -p "Please enter the name of the workspace you created or entered, such as 1001 kj001 work1:" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "Custom workspace" + send_stats "自定义工作区" ;; 23) - read -e -p "Please enter the command you want to execute in the background, such as: curl -fsSL https://get.docker.com | sh:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "Inject commands into the background workspace" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "Please enter the name of the workspace you want to delete:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "Delete the workspace" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -11937,54 +12206,54 @@ linux_Settings() { while true; do clear - # send_stats "System Tools" - echo -e "System Tools" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Modify the login password" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" - echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify the SSH connection port" - echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}One-click reinstallation system${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account to create a new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" - echo -e "${gl_kjlan}13. ${gl_bai}User Management${gl_kjlan}14. ${gl_bai}User/Password Generator" - echo -e "${gl_kjlan}15. ${gl_bai}System time zone adjustment${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" - echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" - echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" - echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tool${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}File Manager" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}Switch system language${gl_kjlan}32. ${gl_bai}Command line beautification tool${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Set up a system recycling bin${gl_kjlan}34. ${gl_bai}System backup and recovery" - echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" - echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" - echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and Security" - echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "Please enter your shortcut key (enter 0 to exit):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys are set" - send_stats "Script shortcut keys have been set" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11992,34 +12261,34 @@ linux_Settings() { 2) clear - send_stats "Set your login password" - echo "Set your login password" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "root password mode" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "py version management" - echo "Python version management" - echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This feature seamlessly installs any version officially supported by python!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "Recommended version: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "Query more versions: https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "Enter the python version number you want to install (enter 0 to exit):" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "Script PY Management" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -12052,7 +12321,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "Unknown package manager!" + echo "未知的包管理器!" return fi @@ -12081,55 +12350,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" - send_stats "Switch script PY version" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "Open port" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "All ports are open" + echo "端口已全部开放" ;; 6) root_use - send_stats "Modify SSH port" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # Read the current SSH port number + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # Print the current SSH port number - echo -e "The current SSH port number is:${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "Numbers with port numbers ranging from 1 to 65535. (Enter 0 to exit)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # Prompt the user to enter a new SSH port number - read -e -p "Please enter the new SSH port number:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # Determine whether the port number is within the valid range + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH port has been modified" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "Exit SSH port modification" + send_stats "退出SSH端口修改" break else - echo "The port number is invalid, please enter a number between 1 and 65535." - send_stats "Invalid SSH port input" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "The input is invalid, please enter the number." - send_stats "Invalid SSH port input" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -12148,8 +12417,8 @@ EOF ;; 9) root_use - send_stats "New users disable root" - read -e -p "Please enter the new username (enter 0 to exit):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12164,49 +12433,49 @@ EOF passwd -l root - echo "The operation has been completed." + echo "操作已完成。" ;; 10) root_use - send_stats "Set v4/v6 priority" + send_stats "设置v4/v6优先级" while true; do clear - echo "Set v4/v6 priority" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "Current network priority settings:${gl_huang}IPv4${gl_bai}priority" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "Current network priority settings:${gl_huang}IPv6${gl_bai}priority" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 priority 2. IPv6 priority 3. IPv6 repair tool" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Choose a preferred network:" choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "Switched to IPv4 priority" - send_stats "Switched to IPv4 priority" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "This function is provided by the master jhb, thanks to him!" - send_stats "ipv6 fix" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -12224,43 +12493,43 @@ EOF 12) root_use - send_stats "Set up virtual memory" + send_stats "设置虚拟内存" while true; do clear - echo "Set up virtual memory" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "Current virtual memory:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. Assign 1024M 2. Assign 2048M 3. Assign 4096M 4. Custom size" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G virtual memory has been set" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G virtual memory has been set" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G virtual memory has been set" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "Please enter the virtual memory size (unit M):" new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "Custom virtual memory has been set" + send_stats "已设置自定义虚拟内存" ;; *) @@ -12273,8 +12542,8 @@ EOF 13) while true; do root_use - send_stats "User Management" - echo "User List" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12285,62 +12554,62 @@ EOF echo "" - echo "Account operation" + echo "账户操作" echo "------------------------" - echo "1. Create a normal account 2. Create a premium account" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3. Give the highest permissions 4. Cancel the highest permissions" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. Delete the account" + echo "5. 删除账号" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # Prompt the user to enter a new username - read -e -p "Please enter a new username:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # Create a new user and set a password + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "The operation has been completed." + echo "操作已完成。" ;; 2) - # Prompt the user to enter a new username - read -e -p "Please enter a new username:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # Create a new user and set a password + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # Grant new users sudo permissions + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "The operation has been completed." + echo "操作已完成。" ;; 3) - read -e -p "Please enter your username:" username - # Grant new users sudo permissions + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "Please enter your username:" username - # Remove user's sudo permissions from sudoers file + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "Please enter the username to delete:" username - # Delete the user and its home directory + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -12353,50 +12622,50 @@ EOF 14) clear - send_stats "User Information Generator" - echo "Random username" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "Random username$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "Random name" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # Generate 5 random user names + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "Random user name$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "Random UUID" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "Random UUID$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16-bit random password" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "Random password$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32-bit random password" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "Random password$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -12404,46 +12673,46 @@ EOF 15) root_use - send_stats "Change time zone" + send_stats "换时区" while true; do clear - echo "System time information" + echo "系统时间信息" - # Get the current system time zone + # 获取当前系统时区 local timezone=$(current_timezone) - # Get the current system time + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # Show time zone and time - echo "Current system time zone:$timezone" - echo "Current system time:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "Time zone switching" + echo "时区切换" echo "------------------------" - echo "Asia" - echo "1. Shanghai time in China 2. Hong Kong time in China" - echo "3. Tokyo time in Japan 4. Seoul time in South Korea" - echo "5. Singapore time 6. Kolkata time in India" - echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Time in Bangkok, Thailand" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "Europe" - echo "11. London time in the UK 12. Paris time in France" - echo "13. Berlin time, Germany 14. Moscow time, Russia" - echo "15. Utrecht time in the Netherlands 16. Madrid time in Spain" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "America" - echo "21. Western Time 22. Eastern Time" - echo "23. Canadian time 24. Mexican time" - echo "25. Brazil time 26. Argentina time" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC Global Standard Time" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -12486,21 +12755,21 @@ EOF 18) root_use - send_stats "Modify the host name" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "Current host name:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "Please enter the new host name (enter 0 to exit):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Other systems, such as Debian, Ubuntu, CentOS, etc. + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12518,11 +12787,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "The host name has been changed to:$new_hostname" - send_stats "Host name has been changed" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "Exited, hostname not changed." + echo "已退出,未更改主机名。" break fi done @@ -12530,32 +12799,32 @@ EOF 19) root_use - send_stats "Change the system update source" + send_stats "换系统更新源" clear - echo "Select the update source area" - echo "Connect to LinuxMirrors to switch system update source" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas Regions" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "Default source in mainland China" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "Source of education in mainland China" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "Overseas origin" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "Canceled" + echo "已取消" ;; esac @@ -12563,62 +12832,62 @@ EOF ;; 20) - send_stats "Timing task management" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "Timed task list" + echo "定时任务列表" crontab -l echo "" - echo "operate" + echo "操作" echo "------------------------" - echo "1. Add timing tasks 2. Delete timing tasks 3. Edit timing tasks" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "Please enter the execution command for the new task:" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. Monthly Tasks 2. Weekly Tasks" - echo "3. Daily tasks 4. Hourly tasks" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "Please enter your selection:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "Choose what day of each month to perform tasks? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "Choose what week to perform the task? (0-6, 0 represents Sunday):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "Choose what time to perform tasks every day? (Hours, 0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "Enter what minute of the hour to perform the task? (mins, 0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "Add timed tasks" + send_stats "添加定时任务" ;; 2) - read -e -p "Please enter the keywords that need to be deleted:" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "Delete timing tasks" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "Edit timing tasks" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12630,32 +12899,32 @@ EOF 21) root_use - send_stats "Local host parsing" + send_stats "本地host解析" while true; do clear - echo "Native host parsing list" - echo "If you add parse matches here, dynamic parsing will no longer be used" + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "operate" + echo "操作" echo "------------------------" - echo "1. Add a new parsing 2. Delete the parsing address" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "Please enter a new parsing record Format: 110.25.5.33 kejilion.pro:" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "Local host parsing has been added" + send_stats "本地host解析新增" ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "Local host parsing and deletion" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12666,7 +12935,7 @@ EOF 22) root_use - send_stats "ssh defense" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12678,20 +12947,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH Defense Program$check_docker" - echo "fail2ban is an SSH tool to prevent brute force" - echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. Install the defense program" + echo "1. 安装防御程序" echo "------------------------" - echo "2. View SSH interception records" - echo "3. Real-time log monitoring" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9. Uninstall the defense program" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12714,7 +12983,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban defense program has been uninstalled" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12727,47 +12996,47 @@ EOF 23) root_use - send_stats "Current limit shutdown function" + send_stats "限流关机功能" while true; do clear - echo "Current limit shutdown function" - echo "Video introduction: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "Current traffic usage, restarting the server traffic calculation will be cleared!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" - echo -e "${gl_kjlan}Total send:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # Check if the Limiting_Shut_down.sh file exists + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # Get the value of threshold_gb + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}The current set entry-station current limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}The current outbound current limit threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limit shutdown function is not enabled${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "The system will detect whether the actual traffic reaches the threshold every minute, and the server will be automatically shut down after it arrives!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. Turn on the current limit shutdown function 2. Deactivate the current limit shutdown function" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # Enter the new virtual memory size - echo "If the actual server has 100G traffic, the threshold can be set to 95G and shut down the power in advance to avoid traffic errors or overflows." - read -e -p "Please enter the incoming traffic threshold (unit is G, default is 100G):" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "Please enter the traffic reset date (default reset on the 1st of each month):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12780,15 +13049,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "Current limit shutdown has been set" - send_stats "Current limit shutdown has been set" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "Current limit shutdown function has been turned off" + echo "已关闭限流关机功能" ;; *) break @@ -12801,40 +13070,40 @@ EOF 24) root_use - send_stats "Private key login" + send_stats "私钥登录" while true; do clear - echo "ROOT private key login mode" - echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "A key pair will be generated, a more secure way to SSH login" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. Generate a new key 2. Import an existing key 3. View the native key" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "Generate a new key" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "Import an existing public key" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "View the local secret key" + send_stats "查看本机密钥" echo "------------------------" - echo "Public key information" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "Private key information" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12850,18 +13119,18 @@ EOF 25) root_use - send_stats "Telegram warning" - echo "TG-bot monitoring and early warning function" - echo "Video introduction: https://youtu.be/vLL-eb3Z_TY" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "You need to configure the tg robot API and the user ID to receive early warnings to realize real-time monitoring and early warning of native CPU, memory, hard disk, traffic, and SSH login" - echo "After reaching the threshold, the user will be sent to the user" - echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate-${gl_bai}" - read -e -p "Are you sure to continue? (Y/N):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "Telegram warning is enabled" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12883,7 +13152,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # Add to ~/.profile file + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12894,21 +13163,21 @@ EOF source ~/.profile clear - echo "TG-bot early warning system has been started" - echo -e "${gl_hui}You can also place the TG-check-notify.sh warning file in the root directory on other machines and use it directly!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "Fix high-risk vulnerabilities in SSH" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12952,7 +13221,7 @@ EOF ;; 37) clear - send_stats "Command line history" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12975,61 +13244,61 @@ EOF 41) clear - send_stats "Message board" - echo "The technology lion message board has been moved to the official community! Please leave a message in the official community!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "One-stop tuning" - echo "One-stop system optimization" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "The following will be operated and optimized" - echo "1. Update the system to the latest" - echo "2. Clean up system junk files" - echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" - echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" - echo -e "5. Open all ports" - echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" - echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" - echo -e "8. Automatically optimize DNS address${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "9. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "One-stop tuning start" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. Update the system to the latest" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. Clean up system junk files" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. Set up virtual memory${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. Set the SSH port number to${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. Open all ports" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. Open${gl_huang}BBR${gl_bai}accelerate" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set the time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13046,25 +13315,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. Automatically optimize DNS address${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Optimization of kernel parameters for Linux system" - echo -e "${gl_lv}One-stop system tuning has been completed${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -13072,7 +13341,7 @@ EOF 99) clear - send_stats "Restart the system" + send_stats "重启系统" server_reboot ;; 100) @@ -13088,32 +13357,32 @@ EOF local status_message="无法确定的状态" fi - echo "Privacy and Security" - echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "Current status:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. Turn on collection" - echo "2. Close the collection" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "Collection has been enabled" - send_stats "Privacy and security collection has been enabled" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "Collection closed" - send_stats "Privacy and Security have been closed for collection" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -13129,11 +13398,11 @@ EOF 102) clear - send_stats "Uninstall tech lion script" - echo "Uninstall tech lion script" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Will completely uninstall the kejilion script and will not affect your other functions" - read -e -p "Are you sure to continue? (Y/N):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -13141,16 +13410,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "The script has been uninstalled, goodbye!" + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -13160,7 +13429,7 @@ EOF ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -13178,187 +13447,187 @@ EOF linux_file() { root_use - send_stats "File Manager" + send_stats "文件管理器" while true; do clear - echo "File Manager" + echo "文件管理器" echo "------------------------" - echo "Current path" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. Enter the directory 2. Create the directory 3. Modify the directory permissions 4. Rename the directory" - echo "5. Delete the directory 6. Return to the previous menu directory" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. Create a file 12. Edit a file 13. Modify file permissions 14. Rename a file" - echo "15. Delete the file" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. Compress file directory 22. Unzip file directory 23. Move file directory 24. Copy file directory" - echo "25. Pass the file to another server" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "Please enter the directory name:" dirname - cd "$dirname" 2>/dev/null || echo "Unable to enter the directory" - send_stats "Go to the directory" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "Please enter the directory name to create:" dirname - mkdir -p "$dirname" && echo "Directory created" || echo "Creation failed" - send_stats "Create a directory" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "Please enter the directory name:" dirname - read -e -p "Please enter permissions (such as 755):" perm - chmod "$perm" "$dirname" && echo "Permissions have been modified" || echo "Modification failed" - send_stats "Modify directory permissions" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "Please enter the current directory name:" current_name - read -e -p "Please enter the new directory name:" new_name - mv "$current_name" "$new_name" && echo "Directory has been renamed" || echo "Rename failed" - send_stats "Rename the directory" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "Please enter the directory name to delete:" dirname - rm -rf "$dirname" && echo "Directory has been deleted" || echo "Deletion failed" - send_stats "Delete Directory" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "Return to the previous menu directory" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "Please enter the file name to create:" filename - touch "$filename" && echo "File created" || echo "Creation failed" - send_stats "Create a file" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "Please enter the file name to edit:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "Edit files" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "Please enter the file name:" filename - read -e -p "Please enter permissions (such as 755):" perm - chmod "$perm" "$filename" && echo "Permissions have been modified" || echo "Modification failed" - send_stats "Modify file permissions" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "Please enter the current file name:" current_name - read -e -p "Please enter a new file name:" new_name - mv "$current_name" "$new_name" && echo "File renamed" || echo "Rename failed" - send_stats "Rename the file" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "Please enter the file name to delete:" filename - rm -f "$filename" && echo "File deleted" || echo "Deletion failed" - send_stats "Delete files" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "Please enter the file/directory name to be compressed:" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "Compressed to$name.tar.gz" || echo "Compression failed" - send_stats "Compressed files/directories" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "Please enter the file name (.tar.gz):" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "Decompressed$filename" || echo "Decompression failed" - send_stats "Unzip files/directories" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "Please enter the file or directory path to move:" src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "Error: The file or directory does not exist." - send_stats "Failed to move a file or directory: The file or directory does not exist" + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "Please enter the target path (including the new file name or directory name):" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "Error: Please enter the target path." - send_stats "Moving file or directory failed: The destination path is not specified" + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "The file or directory has been moved to$dest_path" || echo "Failed to move files or directories" - send_stats "Move files or directories" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "Please enter the file or directory path to copy:" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "Error: The file or directory does not exist." - send_stats "Failed to copy a file or directory: The file or directory does not exist" + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "Please enter the target path (including the new file name or directory name):" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "Error: Please enter the target path." - send_stats "Failed to copy file or directory: Destination path not specified" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # Use the -r option to copy the directory recursively - cp -r "$src_path" "$dest_path" && echo "The file or directory has been copied to$dest_path" || echo "Failed to copy a file or directory" - send_stats "Copy files or directories" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "Please enter the file path to be transferred:" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "Error: The file does not exist." - send_stats "Failed to transfer the file: The file does not exist" + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "Please enter the remote server IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." - send_stats "File transfer failed: Remote server IP was not entered" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "Please enter the remote server username (default root):" remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "Please enter the remote server password:" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "Error: Please enter the remote server password." - send_stats "File transfer failed: Remote server password not entered" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "Please enter the login port (default 22):" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # Clear old entries for known hosts + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # Transfer files using scp + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "The script is up to date$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13656,15 +13925,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" - send_stats "Turn on automatic script update" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}Automatic update is closed${gl_bai}" - send_stats "Close script automatic update" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13686,41 +13955,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "Technology lion script toolbox v$sh_v" -echo -e "Command line input${gl_huang}k${gl_kjlan}Quickly start scripts${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}System information query" -echo -e "${gl_kjlan}2. ${gl_bai}System update" -echo -e "${gl_kjlan}3. ${gl_bai}System Cleanup" -echo -e "${gl_kjlan}4. ${gl_bai}Basic tools" -echo -e "${gl_kjlan}5. ${gl_bai}BBR Management" -echo -e "${gl_kjlan}6. ${gl_bai}Docker Management" -echo -e "${gl_kjlan}7. ${gl_bai}WARP Management" -echo -e "${gl_kjlan}8. ${gl_bai}Test script collection" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Script Collection" -echo -e "${gl_huang}10. ${gl_bai}LDNMP website building" -echo -e "${gl_kjlan}11. ${gl_bai}Application Market" -echo -e "${gl_kjlan}12. ${gl_bai}Backend workspace" -echo -e "${gl_kjlan}13. ${gl_bai}System Tools" -echo -e "${gl_kjlan}14. ${gl_bai}Server cluster control" -echo -e "${gl_kjlan}15. ${gl_bai}Advertising column" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" +echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu server opening script" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}Script update" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}Exit script" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "Please enter your selection:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "System update" ; linux_update ;; - 3) clear ; send_stats "System Cleanup" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp management" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13731,13 +14000,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu server opening script" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "Invalid input!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13745,68 +14014,68 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k命令参考用例" echo "-------------------" -echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "The following is the k command reference use case:" -echo "Start script k" -echo "Install software package k install nano wget | k add nano wget | k Install nano wget" -echo "Uninstall the package k remove nano wget | k del nano wget | k uninstall nano wget | k Uninstall nano wget" -echo "Update system k update | k update" -echo "Clean system garbage k clean | k clean" -echo "Reinstall the system panel k dd | k Reinstall" -echo "bbr3 control panel k bbr3 | k bbrv3" -echo "Kernel Tuning Panel k nhyh | k kernel optimization" -echo "Set virtual memory k swap 2048" -echo "Set virtual time zone k time Asia/Shanghai | k time zone Asia/Shanghai" -echo "System Recycling Bin k trash | k hsz | k Recycling Bin" -echo "System backup function k backup | k bf | k backup" -echo "ssh remote connection tool k ssh | k remote connection" -echo "rsync remote synchronization tool k rsync | k remote synchronization" -echo "Hard disk management tool k disk | k hard disk management" -echo "Intranet penetration (server side) k frps" -echo "Intranet penetration (client) k frpc" -echo "Software start k start sshd | k start sshd" -echo "Software stop k stop sshd | k stop sshd" -echo "Software restart k restart sshd | k restart sshd" -echo "Software status view k status sshd | k status sshd" -echo "Software boot k enable docker | k autostart docke | k startup docker" -echo "Domain name certificate application k ssl" -echo "Domain name certificate expiration query k ssl ps" -echo "docker environment installation k docker install |k docker installation" -echo "docker container management k docker ps |k docker container" -echo "docker image management k docker img |k docker image" -echo "LDNMP site management k web" -echo "LDNMP cache cleanup k web cache" -echo "Install WordPress k wp |k wordpress |k wp xxx.com" -echo "Install the reverse proxy k fd |k rp |k anti-generation |k fd xxx.com" -echo "Install load balancing k loadbalance |k load balancing" -echo "Firewall panel k fhq |k firewall" -echo "Open port k dkdk 8080 |k Open port 8080" -echo "Close port k gbdk 7800 |k Close port 7800" -echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" -echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" -echo "Command favorites k fav | k command favorites" -echo "App Market Management k app" -echo "Application number quick management k app 26 | k app 1panel | k app npm" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # If there are no parameters, run interactive logic + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # If there are parameters, execute the corresponding function + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "Install software" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "Uninstall the software" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13840,7 +14109,7 @@ else rsync_run) shift - send_stats "Timed rsync synchronization" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13859,7 +14128,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ ports have been blocked from accessing the service" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13872,13 +14141,13 @@ else swap) shift - send_stats "Quickly set up virtual memory" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "Quickly set time zone" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13926,42 +14195,42 @@ else status|状态) shift - send_stats "Software status view" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "Software startup" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "Software pause" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "Software restart" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "Software boots up" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "Check the certificate status" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "Quickly apply for a certificate" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "Quickly apply for a certificate" + send_stats "快速申请证书" else k_info fi @@ -13971,15 +14240,15 @@ else shift case $1 in install|安装) - send_stats "Quickly install docker" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "Quick container management" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "Quick mirror management" + send_stats "快捷镜像管理" docker_image ;; *) @@ -14006,7 +14275,7 @@ else app) shift - send_stats "Apply $@" + send_stats "应用$@" linux_panel "$@" ;; @@ -14016,4 +14285,3 @@ else ;; esac fi - diff --git a/jp/kejilion.sh b/jp/kejilion.sh index d2122269f..cab3eb64a 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.2" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# コマンドを実行する関数を定義します +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! -# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 -# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# ユーザーに条件に同意するように促します +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" - echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" - echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "上記の条件に同意しますか? (y/n):" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "ライセンスの同意" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "許可の拒否" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}インストール$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" - echo "現在利用可能なスペース:$((available_space_mb/1024))g" - echo "最小需要スペース:${required_gb}G" - echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" - send_stats "ディスクスペースが不十分です" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}アンインストール$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return 1 fi done } -# さまざまな分布に適したUniversal SystemCTL関数 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# サービスを再起動します +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1サービスは再開されました。" + echo "$1 服务已重启。" else - echo "エラー:再起動$1サービスは失敗しました。" + echo "错误:重启 $1 服务失败。" fi } -# サービスを開始します +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1サービスが開始されました。" + echo "$1 服务已启动。" else - echo "エラー:開始$1サービスは失敗しました。" + echo "错误:启动 $1 服务失败。" fi } -# サービスを停止します +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1サービスは停止しました。" + echo "$1 服务已停止。" else - echo "エラー:停止します$1サービスは失敗しました。" + echo "错误:停止 $1 服务失败。" fi } -# サービスのステータスを確認します +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1サービスステータスが表示されます。" + echo "$1 服务状态已显示。" else - echo "エラー:表示できません$1サービスステータス。" + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME電源を入れるように設定します。" + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}操作が完了しました${gl_bai}" - echo "任意のキーを押して続行します..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -425,7 +424,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +499,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Dockerコンテナ管理" - echo "Dockerコンテナリスト" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "コンテナ操作" + echo "容器操作" echo "------------------------" - echo "1.新しいコンテナを作成します" + echo "1. 创建新的容器" echo "------------------------" - echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" - echo "3.指定された容器を停止します7。すべての容器を停止します" - echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" - echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11。指定されたコンテナを入力します12。コンテナログを表示します" - echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいコンテナを作成します" - read -e -p "作成コマンドを入力してください:" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "指定された容器を起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "指定された容器を停止します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "指定されたコンテナを削除します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "指定された容器を再起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "すべてのコンテナを起動します" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "すべてのコンテナを停止します" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "すべてのコンテナを削除します" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +564,28 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "すべてのコンテナを再起動します" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "コンテナを入力します" - read -e -p "コンテナ名を入力してください:" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "コンテナログを表示します" - read -e -p "コンテナ名を入力してください:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "コンテナネットワークを表示します" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +603,14 @@ while true; do break_end ;; 14) - send_stats "コンテナの占有を表示します" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "コンテナポートアクセスを許可します" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +619,8 @@ while true; do ;; 16) - send_stats "コンテナポートアクセスをブロックします" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +639,44 @@ done docker_image() { while true; do clear - send_stats "Docker画像管理" - echo "Docker画像リスト" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "ミラー操作" + echo "镜像操作" echo "------------------------" - echo "1.指定された画像を取得する3。指定された画像を削除します" - echo "2。指定された画像4を更新します。すべての画像を削除します" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "鏡を引っ張ります" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}画像を取得する:$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "画像を更新します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}更新された画像:$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "ミラーを削除します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "すべての画像を削除します" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +685,7 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +753,16 @@ install_crontab() { service cron start ;; *) - echo "サポートされていない分布:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "オペレーティングシステムを決定することはできません。" + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +774,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 現在の構成には既にIPv6設定があるかどうかを確認してください + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 構成を更新し、IPv6を有効にします + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +809,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 現在の構成をお読みください + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQを使用して、構成ファイルの更新を処理します + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 現在のIPv6ステータスを確認してください + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較します + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +869,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のクロージングルールを削除します + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # オープンルールを追加します + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートが開かれました$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "ポートが開かれました" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のオープンルールを削除します + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 緊密なルールを追加します + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "ポートは閉じた$port" + echo "已关闭端口 $port" fi done - # 既存のルールを削除する(ある場合) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 最初に新しいルールを挿入します + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "ポートは閉じた" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存のブロッキングルールを削除します + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 許可ルールを追加します + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IPをリリースしました$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "IPをリリースしました" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存の許可ルールを削除します + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # ブロッキングルールを追加します + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IPブロック$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IPブロック" + send_stats "已阻止IP" } @@ -990,7 +989,7 @@ block_ip() { enable_ddos_defense() { - # 防御DDOをオンにします + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +999,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS防御をオンにします" + send_stats "开启DDoS防御" } -# DDOS防御をオフにします +# 关闭DDoS防御 disable_ddos_defense() { - # 防御DDOをオフにします + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1014,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS防御をオフにします" + send_stats "关闭DDoS防御" } -# 国家IPルールを管理する機能 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1032,73 @@ manage_country_rules() { case "$action" in block) - # IPSETが存在しない場合は作成します + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # iptablesでIPをブロックします + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "正常にブロックされました$country_codeIPアドレス" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 許可された国のIPSETを作成する(存在しない場合) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IPエリアファイルをダウンロードします + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 既存の国家ルールを削除します + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # IPSETにIPを追加します + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 指定された国のIPのみが許可されています + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "正常に許可されています$country_codeIPアドレス" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 国のiptablesルールを削除します + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # Ipsetを破壊します + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "正常に持ち上げられました$country_codeIPアドレスの制限" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1115,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高度なファイアウォール管理" - send_stats "高度なファイアウォール管理" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "ファイアウォール管理" + echo "防火墙管理" echo "------------------------" - echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5。IPホワイトリスト6。IPブラックリスト" - echo "7.指定されたIPをクリアします" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. ping 12を許可します。Pingを無効にします" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" - echo "17.指定国でのIP制限をリリースします" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "オープンポート番号を入力してください:" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "指定されたポートを開きます" + send_stats "开放指定端口" ;; 2) - read -e -p "閉じたポート番号を入力してください:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "指定されたポートを閉じます" + send_stats "关闭指定端口" ;; 3) - # すべてのポートを開きます + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1163,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを開きます" + send_stats "开放所有端口" ;; 4) - # すべてのポートを閉じます + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1179,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを閉じます" + send_stats "关闭所有端口" ;; 5) - # IPホワイトリスト - read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IPブラックリスト - read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 指定されたIPをクリアします - read -e -p "クリアされたIPを入力してください:" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "指定されたIPをクリアします" + send_stats "清除指定IP" ;; 11) - # pingを許可します + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "pingを許可します" + send_stats "允许PING" ;; 12) - # pingを無効にします + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "pingを無効にします" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1222,20 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "許可された国$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "国をブロックします$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "国をきれいにします$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1256,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 現在のシステムですべてのスワップパーティションを取得します + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 反復して、すべてのスワップパーティションを削除します + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfileが使用されなくなったことを確認してください + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 古い /swapfileを削除します + # 删除旧的 /swapfile rm -f /swapfile - # 新しいスワップパーティションを作成します + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1287,7 @@ add_swap() { rc-update add local fi - echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1297,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 仮想メモリを作成する必要があるかどうかを判断します +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1313,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginxバージョンを取得します + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQLバージョンを取得します + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHPバージョンを取得します + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redisバージョンを取得します + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1340,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 必要なディレクトリとファイルを作成します + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1349,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.ymlファイルをダウンロードして置き換えます + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.ymlファイルに置き換えます + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1398,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされています" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1415,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "更新タスクが更新されました" + echo "续签任务已更新" } @@ -1453,15 +1452,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}証明書ストレージパス${gl_bai}" - echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1469,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1485,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" - echo "サイト情報証明書の有効期限" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1525,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "ドメイン名証明書の成功したアプリケーション" + send_stats "域名证书申请成功" else - send_stats "ドメイン名証明書のアプリケーションは失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" - echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" - echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" - echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" - echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" - echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" - echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "もう一度展開してみてください$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1548,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "ドメイン名の再利用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1557,8 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1623,8 +1622,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1643,11 +1642,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "ログイン情報:" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "起動する$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1656,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 構成ファイルが存在するかどうかを確認します + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ゾーン_idsを配列に変換します + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # キャッシュをクリーニングするかどうかをユーザーに促します - read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" - read -e -p "API_TOKENを入力してください:" API_TOKEN - read -e -p "CFユーザ​​ー名を入力してください:" EMAIL - read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 各ZONE_IDをループして、Clear Cacheコマンドを実行します + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1686,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "キャッシュクリアリクエストが送信されました。" + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "サイトキャッシュをクリーンアップします" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1702,28 @@ web_cache() { web_del() { - send_stats "サイトデータを削除します" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "ドメイン名の削除:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # ドメイン名をデータベース名に変換します + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します - echo "データベースの削除:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1739,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることにしました + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAFをオンにしてください:コメントを削除します + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # WAFを閉じる:コメントを追加します + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1802,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1829,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1857,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotliをオンにする:コメントを削除します + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1871,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる:コメントを追加します + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1887,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1913,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTDをオンにしてください:コメントを削除します + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1928,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # ZSTDを閉じる:コメントを追加します + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1944,11 @@ nginx_zstd() { else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1975,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1989,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP環境防御" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2003,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" - echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21。CloudFlareモード22。5秒シールドの高負荷" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31。WAF32をオンにしてください。WAFをオフにします" - echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2081,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2097,11 +2096,11 @@ web_security() { ;; 21) - send_stats "CloudFlareモード" - echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2115,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CFパラメーターを取得します:" - echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" - echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken - read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2146,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負荷自動シールドオープニングスクリプトが追加されました" + echo "高负载自动开盾脚本已添加" else - echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "サイトWAFが有効になっています" - send_stats "サイトWAFが有効になっています" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "サイトWAFは閉鎖されています" - send_stats "サイトWAFは閉鎖されています" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2188,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processesの設定値を取得します +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 値に応じてモード情報を設定します +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2207,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotliが有効であり、コメントされていないかどうかを確認してください + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIPが有効になっており、コメントされていないかどうかを確認してください + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2237,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP環境を最適化します" - echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1。標準モード2。高性能モード(推奨2H4g以上)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" - echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" - echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "サイト標準モード" + send_stats "站点标准模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2275,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2287,23 @@ web_optimization() { optimize_balanced - echo "LDNMP環境は標準モードに設定されています" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "サイトの高性能モード" + send_stats "站点高性能模式" - # nginxチューニング + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHPチューニング + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2315,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2325,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP環境は、高性能モードに設定されています" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2385,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker = "$ {gl_lv} $ {gl_bai}インストール" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2395,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "アクセスアドレス:" +echo "访问地址:" ip_address @@ -2434,31 +2433,31 @@ check_docker_image_update() { return fi - # コンテナの作成時間と画像名を取得します + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # ミラーウェアハウスとタグを抽出します + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # デフォルトのラベルは最新です + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 公式画像のサポートを追加します + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIから画像公開時間を取得します + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 買収の時間を確認します + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # タイムスタンプを比較します + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2476,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2486,34 @@ block_container_port() { install iptables - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 他のすべてのIPSを確認してブロックします + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2523,7 @@ block_container_port() { fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2534,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2544,17 @@ clear_container_rules() { install iptables - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2563,17 @@ clear_container_rules() { - # 他のすべてのIPをブロックするルールを明確にします + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2584,7 @@ clear_container_rules() { fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2598,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:block_host_port <ポート番号> <承認IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2625,27 @@ block_host_port() { - # 他のすべてのIPアクセスを拒否しました + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 確立された関連接続および関連する接続のトラフィックを許可します + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2657,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2747,18 +2746,18 @@ while true; do fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2770,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "インストール$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2785,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_nameインストール" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新します$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2799,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" - send_stats "アンインストール$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2859,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2894,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2994,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# セッションが存在するかどうかを確認する関数 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 存在しないセッション名が見つかるまでループします +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 新しいTMUXセッションを作成します +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3079,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "再起動" + echo "已重启" reboot ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -3127,8 +3126,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再度インストールできません" - echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3137,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP環境をインストールします" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3154,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx環境をインストールします" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3168,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginxがインストールされています" -echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3180,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "LDNMP環境を最初にインストールしてください" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3190,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "最初にNGINX環境をインストールしてください" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3201,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webnameインストール情報は次のとおりです。" + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "あなたの$webname建てられた!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3222,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3263,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "発生防止ポートを入力してください。" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3296,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3356,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMPサイト管理" - echo "LDNMP環境" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "サイト:${output}証明書の有効期限" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3374,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "データベース:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "サイトディレクトリ" + echo "站点目录" echo "------------------------" - echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" - echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" - echo "5.アクセスログを表示6。エラーログを表示します" - echo "7.グローバル構成の編集8。サイト構成の編集" - echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20.指定されたサイトデータを削除します" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3411,15 @@ ldnmp_web_status() { ;; 2) - send_stats "サイトドメイン名を変更します" - echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" - read -e -p "古いドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # MySQLの交換 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3437,7 @@ ldnmp_web_status() { done done - # ウェブサイトディレクトリの交換 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3458,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "関連するサイトを作成します" - echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" - read -e -p "既存のドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3475,25 @@ ldnmp_web_status() { ;; 5) - send_stats "アクセスログを表示します" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "エラーログを表示します" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "グローバル構成を編集します" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "サイト構成を編集します" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3503,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "サイトデータを表示します" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3540,16 +3539,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" - echo "公式ウェブサイトの紹介:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1。インストール2。管理3。アンインストール" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3557,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}インストール" + send_stats "${panelname}安装" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}コントロール" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}アンインストール" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3614,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRPサーバーをインストールします" - # ランダムポートと資格情報を生成します + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3636,17 @@ EOF donlond_frp frps - # 出力生成情報 + # 输出生成的信息 ip_address echo "------------------------" - echo "クライアントの展開に必要なパラメーター" - echo "サービスIP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRPパネル情報" - echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" - echo "FRPパネルのユーザー名:$dashboard_user" - echo "FRPパネルパスワード:$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3656,9 @@ EOF configure_frpc() { - send_stats "FRPクライアントをインストールします" - read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr - read -e -p "外部ネットワークドッキングトークンを入力してください:" token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3678,17 @@ EOF } add_forwarding_service() { - send_stats "FRPイントラネットサービスを追加します" - # ユーザーにサービス名と転送情報を入力するように促します - read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "イントラネットポートを入力してください:" local_port - read -e -p "外部ネットワークポートを入力してください:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # ユーザー入力を構成ファイルに書き込みます + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3698,8 @@ remote_port = ${remote_port} EOF - # 出力生成情報 - echo "仕える$service_nameFRPC.TOMLに正常に追加されました" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3710,12 @@ EOF delete_forwarding_service() { - send_stats "FRPイントラネットサービスを削除します" - # ユーザーに削除する必要があるサービス名を入力するように促します - read -e -p "削除する必要があるサービス名を入力してください:" service_name - # SEDを使用して、サービスとその関連構成を削除します + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "仕える$service_nameFRPC.TOMLから削除されました" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3725,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーを印刷します + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3746,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3755,11 @@ list_forwarding_services() { type } - # 現在のサービス名を更新します + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 前の値をクリアします + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3789,7 +3788,7 @@ list_forwarding_services() { } END { - # 最後のサービスの情報を印刷します + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3801,17 @@ list_forwarding_services() { -# FRPサーバーポートを取得します +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# アクセスアドレスを生成します +# 生成访问地址 generate_access_urls() { - # 最初にすべてのポートを取得します + # 首先获取所有端口 get_frp_ports - # 8055/8056以外のポートがあるかどうかを確認してください + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3820,18 @@ generate_access_urls() { fi done - # 有効なポートがある場合にのみタイトルとコンテンツを表示します + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRPサービス外部アクセスアドレス:" + echo "FRP服务对外访问地址:" - # IPv4アドレスを処理します + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # IPv6アドレスを処理する(存在する場合) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3840,7 @@ generate_access_urls() { done fi - # HTTPS構成の処理 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3867,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRPサーバー" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3875,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPサーバー$check_frp $update_status" - echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00。サービスのステータスを更新します0。前のメニューに戻ります" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3901,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPサーバーがインストールされています" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3911,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPサーバーが更新されました" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3922,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 5) - echo "ドメイン名アクセスへの逆イントラネット侵入サービス" - send_stats "FRP外部ドメイン名へのアクセス" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IPアクセスを許可します" - read -e -p "リリースするポートを入力してください:" frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" - read -e -p "ブロックする必要があるポートを入力してください。" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRPサービスステータスを更新します" - echo "FRPサービスステータスは更新されました" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3965,7 @@ frps_panel() { frpc_panel() { - send_stats "FRPクライアント" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3973,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRPクライアント$check_frp $update_status" - echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3984,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3998,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPクライアントがインストールされています" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4008,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRPクライアントが更新されました" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4019,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; 4) @@ -4066,68 +4065,68 @@ yt_menu_pro() { fi clear - send_stats "YT-DLPダウンロードツール" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" - echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードされたビデオリスト:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" - echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "オプション番号を入力してください:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "YT-DLPのインストール..." - echo "YT-DLPのインストール..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "インストールが完了しました。任意のキーを押して続行します..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlpを更新..." - echo "yt-dlpを更新..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新が完了しました。任意のキーを押して続行します..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlpのアンインストール..." - echo "yt-dlpのアンインストール..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。任意のキーを押して続行します..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "単一のビデオダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "バッチビデオのダウンロード" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "バッチダウンロードを開始します..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4134,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "カスタムビデオのダウンロード" - read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "実行が完了したら、キーを押して続行します..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3ダウンロード" - read -e -p "ビデオリンクを入力してください:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "ビデオを削除します" - read -e -p "削除ビデオの名前を入力してください:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4194,7 @@ set_timedate() { -# DPKG割り込みの問題を修正します +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4203,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}システムの更新...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4222,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi } @@ -4231,7 +4230,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4259,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." apk cache clean - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APKキャッシュを削除してください..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4283,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "未使用の依存関係をクリーンアップ..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "清理包管理器缓存..." pkg clean -y - echo "システムログを削除してください..." + echo "删除系统日志..." rm -rf /var/log/* - echo "一時ファイルを削除します..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi return @@ -4340,26 +4339,26 @@ fi set_dns_ui() { root_use -send_stats "DNSを最適化します" +send_stats "优化DNS" while true; do clear - echo "DNSアドレスを最適化します" + echo "优化DNS地址" echo "------------------------" - echo "現在のDNSアドレス" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1。外国DNS最適化:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2。国内のDNS最適化:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3。DNS構成を手動で編集します" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4366,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "外国のDNS最適化" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4374,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内のDNS最適化" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "DNS構成を手動で編集します" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4402,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthenticationが見つかった場合は、はいに設定します + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 発見された場合、pubkeyauthenticationはyesに設定されています + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4416,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4427,7 @@ correct_ssh_config() { new_ssh_port() { - # バックアップSSH構成ファイル + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4440,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSHポートは次のように変更されています。$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4458,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4470,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4498,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4507,26 @@ import_sshkey() { add_sshpasswd() { -echo "ルートパスワードを設定します" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "システムを再インストールします" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4537,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4587,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "再インストールするシステムを選択してください:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "Debian 13を再インストールします" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4609,49 @@ dd_xitong() { ;; 2) - send_stats "Debian 12を再インストールします" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Debian 11を再インストールします" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Debian 10を再インストールします" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "Ubuntu 24.04を再インストールします" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "Ubuntu 22.04を再インストールします" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04を再インストールします" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "Ubuntu 18.04を再インストールします" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4660,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10を再インストールします" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4668,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9を再インストールします" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4676,7 @@ dd_xitong() { ;; 23) - send_stats "alma10を再インストールします" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4684,7 @@ dd_xitong() { ;; 24) - send_stats "alma9を再インストールします" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4692,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10を再インストールします" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4700,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9を再インストールします" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4708,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42を再インストールします" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4716,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41を再インストールします" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4724,7 @@ dd_xitong() { ;; 29) - send_stats "CENTOS10を再インストールします" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4732,7 @@ dd_xitong() { ;; 30) - send_stats "CENTOS9を再インストールします" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4740,7 @@ dd_xitong() { ;; 31) - send_stats "アルパインを再インストールします" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4748,7 @@ dd_xitong() { ;; 32) - send_stats "アーチを再インストールします" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4756,7 @@ dd_xitong() { ;; 33) - send_stats "Kaliを再インストールします" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4764,7 @@ dd_xitong() { ;; 34) - send_stats "Openeulerを再インストールします" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4772,7 @@ dd_xitong() { ;; 35) - send_stats "OpenSuseを再インストールします" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4780,7 @@ dd_xitong() { ;; 36) - send_stats "飛ぶ牛をリロードします" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4789,7 @@ dd_xitong() { 41) - send_stats "Windows11を再インストールします" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4797,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Windows 10を再インストールします" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7を再インストールします" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4811,21 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22を再インストールします" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Windows Server 19を再インストールします" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Windows Server 16を再インストールします" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4833,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11アームを再インストールします" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4850,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3管理" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4863,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "XanmodのBBRV3カーネルをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4883,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4892,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmodカーネルが更新されました。再起動後に有効になります" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4902,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4915,13 @@ bbrv3() { else clear - echo "BBR3加速度をセットアップします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Debian/Ubuntuのみをサポートします" - echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4929,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "オペレーティングシステムの種類を決定できません" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4945,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4956,17 @@ bbrv3() { bbr_on - echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4975,40 @@ bbrv3() { elrepo_install() { - # Elrepo GPG公開キーをインポートします - echo "Elrepo GPG公開キーをインポートしてください..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # システムバージョンを検出します + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # サポートされているオペレーティングシステムで実行されていることを確認してください + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "サポートされていないオペレーティングシステム:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 検出されたオペレーティングシステム情報を印刷します - echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "サポートされていないシステムバージョン:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします - echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5016,37 @@ elrepo_install() { elrepo() { root_use - send_stats "レッドハットカーネル管理" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo Kernelをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "カーネル管理" + echo "内核管理" echo "------------------------" - echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hatカーネルを更新します" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" - send_stats "レッドハットカーネルをアンインストールします" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5059,26 @@ elrepo() { else clear - echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" - echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hatカーネルをアップグレードします" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5089,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5099,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "スキャンするディレクトリを指定してください。" + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # マウントパラメーターを構築します + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # CLAMSCANコマンドパラメーターを作成します + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5120,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Dockerコマンドを実行します + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5129,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5142,23 @@ clamav_scan() { clamav() { root_use - send_stats "ウイルススキャン管理" + send_stats "病毒扫描管理" while true; do clear - echo "クラマブウイルススキャンツール" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" - echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "フルディスクスキャン" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5167,7 @@ clamav() { ;; 2) - send_stats "重要なディレクトリスキャン" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5175,8 @@ clamav() { break_end ;; 3) - send_stats "カスタムディレクトリスキャン" - read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5193,21 @@ clamav() { -# 高性能モード最適化関数 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5219,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# イコライゼーションモード最適化関数 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5260,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# デフォルト設定関数を復元します +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5301,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" - # 透明なページを復元します + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# ウェブサイトの構築最適化機能 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5343,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5363,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" - echo "Linuxシステムにおけるカーネルパラメーターの最適化" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" - echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" - echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" - echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" - echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" - echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能モードの最適化" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "バランスモードの最適化" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "ウェブサイトの最適化モデル" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "ライブストリーミング最適化" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "ゲームサーバーの最適化" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "デフォルト設定を復元します" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5445,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5454,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "サポートされていないシステム:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "サポートされていないシステム、システムタイプは認識できません。" + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5474,29 @@ update_locale() { linux_language() { root_use -send_stats "システム言語を切り替えます" +send_stats "切换系统语言" while true; do clear - echo "現在のシステム言語:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1。英語2。簡素化された中国語3。伝統的な中国語" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えます" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "簡素化された中国人に切り替えます" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "伝統的な中国人に切り替えます" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5518,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5530,10 +5529,10 @@ break_end shell_bianse() { root_use - send_stats "コマンドラインの美化ツール" + send_stats "命令行美化工具" while true; do clear - echo "コマンドラインの美化ツール" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5542,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5589,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムリサイクルステーション" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5604,17 @@ linux_trash() { fi clear - echo -e "現在のリサイクルビン${trash_status}" - echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" - echo "3。コンテンツを復元4。リサイクルビンをクリアします" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5622,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,23 +5630,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "復元するにはファイル名を入力してください。" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreホームディレクトリに復元されました。" + echo "$file_to_restore 已还原到主目录。" else - echo "ファイルは存在しません。" + echo "文件不存在。" fi ;; 4) - read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "リサイクルビンがクリアされました。" + echo "回收站已清空。" fi ;; *) @@ -5658,23 +5657,23 @@ linux_trash() { } linux_fav() { -send_stats "コマンドのお気に入り" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成します +# 创建备份 create_backup() { - send_stats "バックアップを作成します" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # ユーザーにバックアップディレクトリを入力するように求めます - echo "バックアップ例を作成します:" - echo "- 単一のディレクトリをバックアップします: /var /www" - echo "- バックアップ複数のディレクトリ: /etc /home /var /log" - echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" - read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5681,119 @@ create_backup() { "/home" # 用户数据 ) else - # ユーザーが入力したディレクトリをスペースごとに配列に分離します + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # バックアップファイルプレフィックスを生成します + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # ディレクトリ名を抽出し、スラッシュを削除します + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 最後のアンダースコアを削除します + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # バックアップファイル名を生成します + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # ユーザーが選択したディレクトリを印刷します - echo "選択したバックアップディレクトリは次のとおりです。" + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # バックアップを作成します - echo "バックアップを作成します$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # コマンドが成功しているかどうかを確認してください + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "バックアップの作成に失敗しました!" + echo "备份创建失败!" exit 1 fi } -# バックアップを復元します +# 恢复备份 restore_backup() { - send_stats "バックアップを復元します" - # 復元するバックアップを選択します - read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - echo "バックアップの回復$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "バックアップと復元を正常に!" + echo "备份恢复成功!" else - echo "バックアップリカバリに失敗しました!" + echo "备份恢复失败!" exit 1 fi } -# バックアップをリストします +# 列出备份 list_backups() { - echo "利用可能なバックアップ:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# バックアップを削除します +# 删除备份 delete_backup() { - send_stats "バックアップを削除します" + send_stats "删除备份" - read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "备份文件不存在!" exit 1 fi - # バックアップを削除します + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "バックアップは正常に削除されました!" + echo "备份删除成功!" else - echo "バックアップの削除が失敗しました!" + echo "备份删除失败!" exit 1 fi } -# バックアップメインメニュー +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "システムバックアップ機能" - echo "システムバックアップ機能" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5805,56 @@ linux_backup() { -# 接続リストを表示します +# 显示连接列表 list_connections() { - echo "接続の保存:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 新しい接続を追加します +# 添加新连接 add_connection() { - send_stats "新しい接続を追加します" - echo "新しい接続を作成する例:" - echo "- 接続名:my_server" - echo "- IPアドレス:192.168.1.100" - echo "- ユーザー名:root" - echo "- ポート:22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "接続名を入力してください:" name - read -e -p "IPアドレスを入力してください:" ip - read -e -p "ユーザー名(デフォルト:root)を入力してください:" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "ポート番号を入力してください(デフォルト:22):" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "選択(1/2)を入力してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5863,89 @@ add_connection() { fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "接続が保存されます!" + echo "连接已保存!" } -# 接続を削除します +# 删除连接 delete_connection() { - send_stats "接続を削除します" - read -e -p "削除するには、接続番号を入力してください。" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続​​は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 接続がキーファイルを使用している場合、キーファイルを削除します + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "接続が削除されました!" + echo "连接已删除!" } -# 接続を使用します +# 使用连接 use_connection() { - send_stats "接続を使用します" - read -e -p "使用するには、接続番号を入力してください。" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続​​は見つかりませんでした。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "接続$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # キーに接続します + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1。キーファイルパスは正しいですか?$password_or_key" - echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" - echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # パスワードで接続します + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1.ユーザー名とパスワードが正しいかどうか。" - echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" - echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSHリモート接続ツール" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5957,21 @@ ssh_manager() { while true; do clear - echo "SSHリモート接続ツール" - echo "SSHを介して他のLinuxシステムに接続できます" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5987,156 @@ ssh_manager() { -# 利用可能なハードディスクパーティションをリストします +# 列出可用的硬盘分区 list_partitions() { - echo "利用可能なハードディスクパーティション:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントします +# 挂载分区 mount_partition() { - send_stats "パーティションをマウントします" - read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションはすでに取り付けられています!" + echo "分区已经挂载!" return fi - # マウントポイントを作成します + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントします + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "パーティションマウントに正常に:$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "パーティションマウントは失敗しました!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# パーティションをアンインストールします +# 卸载分区 unmount_partition() { - send_stats "パーティションをアンインストールします" - read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "パーティションはマウントされていません!" + echo "分区未挂载!" return fi - # パーティションをアンインストールします + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティションのアンインストールに正常に:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "パーティションのアンインストールに失敗しました!" + echo "分区卸载失败!" fi } -# マウントされたパーティションをリストします +# 列出已挂载的分区 list_mounted_partitions() { - echo "マウントされたパーティション:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# フォーマットパーティション +# 格式化分区 format_partition() { - send_stats "フォーマットパーティション" - read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションがマウントされました。最初にアンインストールしてください!" + echo "分区已经挂载,请先卸载!" return fi - # ファイルシステムタイプを選択します - echo "ファイルシステムタイプを選択してください:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "選択を入力してください:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "無効な選択!"; return ;; + *) echo "无效的选择!"; return ;; esac - # フォーマットを確認します - read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作はキャンセルされました。" + echo "操作已取消。" return fi - # フォーマットパーティション - echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティション形式は成功しました!" + echo "分区格式化成功!" else - echo "パーティションのフォーマットが失敗しました!" + echo "分区格式化失败!" fi } -# パーティションステータスを確認します +# 检查分区状态 check_partition() { - send_stats "パーティションステータスを確認します" - read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # パーティションが存在するかどうかを確認します + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "分区不存在!" return fi - # パーティションステータスを確認します - echo "パーティション /dev /$PARTITION状態:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# メインメニュー +# 主菜单 disk_manager() { - send_stats "ハードディスク管理機能" + send_stats "硬盘管理功能" while true; do clear - echo "ハードディスクパーティション管理" - echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" - echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6145,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } -# タスクリストを表示します +# 显示任务列表 list_tasks() { - echo "保存された同期タスク:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 新しいタスクを追加します +# 添加新任务 add_task() { - send_stats "新しい同期タスクを追加します" - echo "新しい同期タスクを作成する例:" - echo "- タスク名:backup_www" - echo "- ローカルディレクトリ: /var /www" - echo "- リモートアドレス:user@192.168.1.100" - echo "- リモートディレクトリ: /バックアップ /www" - echo "- ポート番号(デフォルト22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "タスク名を入力してください:" name - read -e -p "ローカルディレクトリを入力してください:" local_path - read -e -p "リモートディレクトリを入力してください:" remote_path - read -e -p "リモートユーザー@IPを入力してください:" remote - read -e -p "SSHポートを入力してください(デフォルト22):" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" - read -e -p "(1/2)を選択してください:" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6210,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "無効なキーコンテンツ!" + echo "无效的密钥内容!" return fi ;; *) - echo "無効な選択!" + echo "无效的选择!" return ;; esac - echo "同期モードを選択してください:" - echo "1。標準モード(-AVZ)" - echo "2。ターゲットファイル(-avz - delete)を削除します" - read -e -p "(1/2)を選択してください:" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "タスクが節約されました!" + echo "任务已保存!" } -# タスクを削除します +# 删除任务 delete_task() { - send_stats "同期タスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:対応するタスクは見つかりませんでした。" + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # タスクがキーファイルを使用している場合、キーファイルを削除します + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "削除されたタスク!" + echo "任务已删除!" } run_task() { - send_stats "同期タスクを実行します" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # パラメーターを分析します + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6277,51 @@ run_task() { num="$1" fi - # 着信タスク番号がない場合は、ユーザーに入力するように促します + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "実行するタスク番号を入力してください:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:タスクは見つかりませんでした!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期の方向に従ってソースとターゲットのパスを調整します + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "同期をローカルに引く:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH接続の共通パラメーターを追加します + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "エラー:キーファイルが存在しません:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6330,32 +6329,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同期は完了です!" + echo "同步完成!" else - echo "同期は失敗しました!以下を確認してください。" - echo "1。ネットワーク接続は正常ですか?" - echo "2。リモートホストにアクセスできますか?" - echo "3。認証情報は正しいですか?" - echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 時限タスクを作成します +# 创建定时任务 schedule_task() { - send_stats "同期タイミングタスクを追加します" + send_stats "添加同步定时任务" - read -e -p "定期的に同期するには、タスク番号を入力してください。" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi - echo "時限実行間隔を選択してください:" - echo "1)1時間に1回実行します" - echo "2)1日1回実行します" - echo "3)週に1回実行します" - read -e -p "オプションを入力してください(1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6362,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "エラー:有効なオプションを入力してください!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクが既に存在するかどうかを確認してください + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "エラー:このタスクのタイミング同期はすでに存在しています!" + echo "错误: 该任务的定时同步已存在!" return fi - # ユーザーにクロンタブを作成します + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "タイミングタスクが作成されました。$cron_job" + echo "定时任务已创建: $cron_job" } -# スケジュールされたタスクを表示します +# 查看定时任务 view_tasks() { - echo "現在のタイミングタスク:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# タイミングタスクを削除します +# 删除定时任务 delete_task_schedule() { - send_stats "同期タイミングタスクを削除します" - read -e -p "削除するには、タスク番号を入力してください。" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numタイミングタスク" + echo "已删除任务编号 $num 的定时任务" } -# タスク管理メインメニュー +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "RSYNCリモート同期ツール" - echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1.新しいタスクを作成します2。タスクを削除します" - echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6。タイミングタスクを削除します" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6430,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6447,7 @@ rsync_manager() { linux_ps() { clear - send_stats "システム情報クエリ" + send_stats "系统信息查询" ip_address @@ -6498,41 +6497,41 @@ linux_ps() { echo "" - echo -e "システム情報クエリ" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" - echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" - echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" - echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" - echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" - echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6544,111 @@ linux_tools() { while true; do clear - # send_stats「基本ツール」 - echo -e "基本的なツール" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" - echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" - echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" - echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" - echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" - echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" - echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" curl --help - send_stats "カールをインストールします" + send_stats "安装curl" ;; 2) clear install wget clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" wget --help - send_stats "WGETをインストールします" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" sudo --help - send_stats "sudoをインストールします" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" socat -h - send_stats "SOCATをインストールします" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "HTOPをインストールします" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "IFTOPをインストールします" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" unzip - send_stats "unzipをインストールします" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tar --help - send_stats "タールをインストールします" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmuxをインストールします" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "ffmpegをインストールします" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6656,7 @@ linux_tools() { install btop clear btop - send_stats "BTOPをインストールします" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6665,7 @@ linux_tools() { clear ranger cd ~ - send_stats "レンジャーをインストールします" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6674,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDUをインストールします" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6683,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZFをインストールします" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6692,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIMをインストールします" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6701,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "ナノをインストールします" + send_stats "安装nano" ;; @@ -6713,7 +6712,7 @@ linux_tools() { clear git --help cd ~ - send_stats "gitをインストールします" + send_stats "安装git" ;; 21) @@ -6721,67 +6720,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrixをインストールします" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "SLをインストールします" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "バステットをインストールします" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "nsnakeをインストールします" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Ninvadersをインストールします" + send_stats "安装ninvaders" ;; 31) clear - send_stats "すべてをインストールします" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "すべてをアンインストールします" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "指定されたソフトウェアをインストールします" + send_stats "安装指定软件" ;; 42) clear - read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "指定されたソフトウェアをアンインストールします" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6788,7 @@ linux_tools() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -6803,27 +6802,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR管理" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "AlpineはBBR3を有効にします" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6868,18 +6867,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}現在のバックアップリスト:${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" + echo -e "${BLUE}当前备份列表:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } # ---------------------------- - # バックアップ + # 备份 # ---------------------------- backup_docker() { - echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" - read -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers + send_stats "Docker备份" + + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6890,7 +6892,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナは見つかりません${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6898,28 +6900,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "#自動的に生成された復元スクリプト" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # パッケージ化されたプロジェクトのパスを記録して、パッケージの重複を避ける + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}バックアップコンテナ:$c${NC}" + echo -e "${GREEN}备份容器: $c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cはい、Docker-Composeコンテナ${NC}" + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir + read -p "未检测到 compose 目录,请手动输入路径: " project_dir fi - # Composeプロジェクトがパッケージ化されている場合は、スキップしてください + # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトを作成する[$project_name]バックアップ、複製パッケージをスキップ...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" continue fi @@ -6927,136 +6929,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "#docker-compose Recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトを作成する[$project_name]パック:${project_dir}${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" else - echo -e "${RED}docker-compose.ymlが見つかりません、このコンテナをスキップしてください...${NC}" + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" fi else - # 通常のコンテナバックアップボリューム + # 普通容器备份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包ロール:$path" + echo "打包卷: $path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # ポート + # 端口 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 環境変数 + # 环境变量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # ボリュームマッピング + # 卷映射 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 鏡 + # 镜像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\ n#復元コンテナ:$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # /home /dockerのすべてのファイルをバックアップします(サブディレクトリを除く) + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home /dockerの下のファイルをバックアップ...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - - echo -e "${GREEN}/home /dockerの下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" - echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 削減 + # 还原 # ---------------------------- restore_docker() { - list_backups - read -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - echo -e "${BLUE}復元操作を開始します...${NC}" + send_stats "Docker还原" + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" install tar jq gzip install_docker - # ------------------------------ + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path - # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します + # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}プロジェクトを作成する[$project_name]すでにコンテナが走っています、復元をスキップします...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" continue fi - read -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "新しい復元パスを入力してください:" original_path + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}プロジェクトを作成する[$project_name]減圧:$original_path${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}プロジェクトを作成する[$project_name]復元が完了しました!${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" fi done - # ------------------------------ - echo -e "${BLUE}通常のDockerコンテナを確認して復元します...${NC}" + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}コンテナの処理:$container${NC}" + echo -e "${GREEN}处理容器: $container${NC}" - # 容器が既に存在し、実行中かどうかを確認してください + # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container]走っています、復元をスキップします...${NC}" + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報は見つかりませんでした、スキップ:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } - # ポートマッピング + # 端口映射 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 環境変数 + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # ボリュームマッピング +ボリュームデータリカバリ + # 卷映射 + 卷数据恢复 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7067,32 +7070,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "ボリュームデータの回復:$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 既存のが実行されていないコンテナを削除します + # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container]存在しますが、実行していません。古いコンテナを削除してください...${NC}" + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" docker rm -f "$container" fi - # コンテナを起動します - echo "restoreコマンドを実行します:docker run -d - name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}通常のコンテナのバックアップ情報は見つかりませんでした${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" - # /home /dockerの下でファイルを復元します + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home /dockerの下でファイルを復元します...${NC}" + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home /dockerの下のファイルが復元されました${NC}" + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else - echo -e "${YELLOW}/home /dockerの下のファイルのバックアップは見つかりませんでした、スキップ...${NC}" + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" fi @@ -7100,66 +7103,68 @@ docker_ssh_migration() { # ---------------------------- - # 移動します + # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups - read -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + send_stats "Docker迁移" + install jq + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "ターゲットサーバーIP:" TARGET_IP - read -p "ターゲットサーバーSSHユーザー名:" TARGET_USER + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}バックアップを転送...${NC}" + echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログインします + # 使用密钥登录 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # バックアップを削除します + # 删除备份 # ---------------------------- delete_backup() { - list_backups - read -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + send_stats "Docker备份文件删除" + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" } # ---------------------------- - # メインメニュー + # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" - echo -e "Dockerバックアップ/移行/復元ツール" + echo -e "Docker备份/迁移/还原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1。Dockerプロジェクトをバックアップします" - echo -e "2。Dockerプロジェクトを移行します" - echo -e "3. Dockerプロジェクトを復元します" - echo -e "4. Dockerプロジェクトのバックアップファイルを削除します" + echo -e "1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0。前のメニューに戻ります" + echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "選択してください:" choice + read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}無効なオプション${NC}" ;; + *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } @@ -7174,38 +7179,38 @@ linux_docker() { while true; do clear - # send_stats「Docker Management」 + # send_stats "docker管理" echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" - echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" - echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" - echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Docker環境をインストールします" + send_stats "安装docker环境" install_add_docker ;; @@ -7216,22 +7221,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Dockerグローバルステータス" - echo "Dockerバージョン" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7246,8 +7251,8 @@ linux_docker() { 5) while true; do clear - send_stats "Dockerネットワーク管理" - echo "Dockerネットワークリスト" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -7271,36 +7276,36 @@ linux_docker() { done echo "" - echo "ネットワーク操作" + echo "网络操作" echo "------------------------" - echo "1.ネットワークを作成します" - echo "2。インターネットに参加してください" - echo "3。ネットワークを終了します" - echo "4.ネットワークを削除します" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "ネットワークを作成します" - read -e -p "新しいネットワーク名を設定します:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "インターネットに参加してください" - read -e -p "ネットワーク名に参加してください:" dockernetwork - read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "インターネットに参加してください" - read -e -p "出口ネットワーク名:" dockernetwork - read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7309,8 +7314,8 @@ linux_docker() { ;; 4) - send_stats "ネットワークを削除します" - read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7324,29 +7329,29 @@ linux_docker() { 6) while true; do clear - send_stats "Dockerボリューム管理" - echo "Dockerボリュームリスト" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "ボリューム操作" + echo "卷操作" echo "------------------------" - echo "1.新しいボリュームを作成します" - echo "2。指定されたボリュームを削除します" - echo "3.すべてのボリュームを削除します" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "新しいボリュームを作成します" - read -e -p "新しいボリューム名を設定します:" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7355,7 +7360,7 @@ linux_docker() { ;; 3) - send_stats "すべてのボリュームを削除します" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7364,7 +7369,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7377,7 +7382,7 @@ linux_docker() { ;; 7) clear - send_stats "Dockerクリーニング" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7386,13 +7391,13 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "Dockerソース" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7408,13 +7413,13 @@ linux_docker() { 11) clear - send_stats "Docker V6が開いています" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker V6レベル" + send_stats "Docker v6 关" docker_ipv6_off ;; @@ -7425,7 +7430,7 @@ linux_docker() { 20) clear - send_stats "Dockerアンインストール" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7437,7 +7442,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7446,7 +7451,7 @@ linux_docker() { kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7463,151 +7468,151 @@ linux_test() { while true; do clear - # send_stats「テストスクリプトコレクション」 - echo -e "テストスクリプトコレクション" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" - echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" - echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" - echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ネットワーク速度測定" - echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" - echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" - echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" - echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}包括的なテスト" - echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "CHATGPTはステータス検出のロックを解除します" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "リージョンストリーミングメディアのロック解除テスト" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "YeahWUストリーミングメディアのロック解除検出" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "XYKT_IP品質の身体検査スクリプト" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "MTR_TRACE 3ネットワークリターンラインテスト" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "SuperSpeed Three-Net速度測定" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace高速バックホールテストスクリプト" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" - echo "参照できるIPのリスト" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "北京テレコム:219.141.136.12" - echo "北京ユニコム:202.106.50.1" - echo "北京モバイル:221.179.155.161" - echo "上海通信:202.96.209.133" - echo "上海ユニコム:210.22.97.1" - echo "上海モバイル:211.136.112.200" - echo "広州通信:58.60.188.222" - echo "広州ユニコム:210.21.196.6" - echo "広州モバイル:120.196.165.24" - echo "成都通信:61.139.2.69" - echo "成都ユニコム:119.6.6.6" - echo "成都モバイル:211.137.96.205" - echo "Hunan Telecom:36.111.200.100" - echo "Hunan Unicom:42.48.16.100" - echo "Hunan Mobile:39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "指定されたIPを入力してください:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3ネットワークラインテスト" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC多機能速度テストスクリプト" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "ネットワーク品質のテストスクリプト" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABSパフォーマンステスト" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "ベンチパフォーマンステスト" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX Fusion Monster Review" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7617,7 +7622,7 @@ linux_test() { ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7633,51 +7638,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Scriptコレクション" - echo -e "Oracle Cloud Scriptコレクション" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" - echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" - echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" - echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "必ずインストールしますか? (y/n):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # デフォルト値を設定します + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 - read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Dockerコンテナを実行します + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7685,14 +7690,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloudインストールアクティブスクリプト" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7700,20 +7705,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "システムを再インストールします" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - read -e -p "必ず続行しますか? (y/n):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7725,28 +7730,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "再インストールされたパスワードを入力してください:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud再インストールシステムスクリプト" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "この機能は開発段階にあるので、お楽しみに!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7756,15 +7761,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -7785,7 +7790,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7806,7 +7811,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7834,31 +7839,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp webサイトビルディング" - echo -e "${gl_huang}LDNMP Webサイトビルディング" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" - echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" - echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" - echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" - echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" - echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7872,10 +7877,10 @@ linux_ldnmp() { 3) clear - # ディスクフォーラム + # Discuz论坛 webname="Discuz论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,21 +7903,21 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao Cloudデスクトップ + # 可道云桌面 webname="可道云桌面" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7934,20 +7939,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" - echo "Redisホスト:Redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,24 +7978,24 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベースプレフィックス:mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "インストールが成功した後、バックグラウンドアドレスにログインします" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 一本足のカウントカード + # 独脚数卡 webname="独脚数卡" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,34 +8016,34 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "Redisアドレス:Redis" - echo "Redisパスワード:デフォルトで記入されていません" - echo "Redisポート:6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "ユーザー名:admin" - echo "パスワード:管理者" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" - echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # フララムフォーラム + # flarum论坛 webname="flarum论坛" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8075,12 +8080,12 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:flarum_" - echo "管理者情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -8088,8 +8093,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8113,11 +8118,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースプレフィックス:typecho_" - echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -8126,8 +8131,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8152,18 +8157,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8180,10 +8185,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8193,20 +8198,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8217,15 +8222,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "選択の無効な、再入力してください。" + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "インストールされた拡張機能" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8235,25 +8240,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8263,10 +8268,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "データベースインポートテーブルデータ" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "データベースのインポートが完了しました" + echo "数据库导入完成" ;; *) echo @@ -8278,12 +8283,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" - echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:$prefix" - echo "管理者ログイン情報は自分で設定されます" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -8296,10 +8301,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "ジャンプドメイン名を入力してください:" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -8321,7 +8326,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8332,11 +8337,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" - read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8356,8 +8361,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8379,8 +8384,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8397,8 +8402,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8431,8 +8436,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "インストール$webname" - echo "展開を開始します$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8449,10 +8454,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,12 +8467,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8492,21 +8497,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境バックアップ" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "バックアップファイルが作成されました: /home /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8514,9 +8519,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" + echo "文件已传送至远程服务器home目录。" else - echo "転送されるファイルは見つかりませんでした。" + echo "未找到要传送的文件。" fi break ;; @@ -8524,7 +8529,7 @@ linux_ldnmp() { break ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8532,9 +8537,9 @@ linux_ldnmp() { 33) clear - send_stats "タイミングのリモートバックアップ" - read -e -p "リモートサーバーIPを入力してください:" useip - read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8544,18 +8549,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1。毎週のバックアップ2。毎日のバックアップ" - read -e -p "選択を入力してください:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8569,19 +8574,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP環境修復" - echo "利用可能なサイトバックアップ" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8591,7 +8596,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8600,7 +8605,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージは見つかりませんでした。" + echo "没有找到压缩包。" fi ;; @@ -8618,11 +8623,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP環境を更新します" - echo "LDNMP環境を更新します" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "コンポーネントの新しいバージョンを発見します" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8642,13 +8647,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5。完全な環境を更新します" + echo "5. 更新完整环境" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8657,7 +8662,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8668,13 +8673,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8707,8 +8712,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8719,15 +8724,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境を完全に更新します" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8753,7 +8758,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP環境をアンインストールします" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8767,7 +8772,7 @@ linux_ldnmp() { ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8777,7 +8782,7 @@ linux_ldnmp() { ;; *) - echo "無効な入力!" + echo "无效的输入!" esac break_end @@ -8797,12 +8802,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "アプリケーション市場" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # ループで色を設定します + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8811,67 +8816,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" - echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" - echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" - echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" - echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" - echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" - echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" - echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" - echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" - echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" - echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" - echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" - echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" - echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" - echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8990,6 +8998,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -9021,8 +9032,8 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9055,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "ネザを作る" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -9064,20 +9075,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezhaの監視$check_docker $update_status" - echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" - echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1。使用します" + echo "1. 使用" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9134,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "郵便局を建設します" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -9144,43 +9155,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "郵便局サービス$check_docker $update_status" - echo "Poste.ioはオープンソースメールサーバーソリューションです。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "ポート検出" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "アクセスアドレス:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "これらのDNSレコードを最初に解析します" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9190,7 +9201,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "任意のキーを押して続行します..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -9209,9 +9220,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -9234,9 +9245,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.ioがインストールされています" + echo "poste.io已经安装完成" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -9247,7 +9258,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "应用已卸载" ;; *) @@ -9281,7 +9292,7 @@ while true; do clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -9291,7 +9302,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chatがインストールされています" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -9301,7 +9312,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9385,7 +9396,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -9399,7 +9410,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -9544,7 +9555,7 @@ while true; do ;; 19|safeline) - send_stats "サンダープールを構築します" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -9552,20 +9563,20 @@ while true; do while true; do check_docker_app clear - echo -e "サンダープールサービス$check_docker" - echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9575,7 +9586,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "サンダープールWAFパネルがインストールされています" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9588,7 +9599,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "サンダープールWAFパネルが更新されました" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9599,7 +9610,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9718,8 +9729,8 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10007,7 +10018,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10060,7 +10071,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoyaファミリーバケット" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -10264,9 +10275,9 @@ while true; do prometheus_install clear ip_address - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "最初のユーザー名とパスワードは次のとおりです" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -10284,7 +10295,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10371,7 +10382,7 @@ while true; do 51|pve) clear - send_stats "PVEチキン" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10491,7 +10502,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10506,7 +10517,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10534,7 +10545,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10549,7 +10560,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10557,7 +10568,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10578,17 +10589,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip - echo "初期ユーザー名:admin" - echo "最初のパスワード:changeme" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "アプリが更新されました" + echo "应用已更新" } @@ -10598,7 +10609,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10645,7 +10656,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10661,7 +10672,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -10923,7 +10934,7 @@ while true; do docker_rum() { - read -e -p "libretvログインパスワードを設定します。" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10957,9 +10968,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password - read -e -p "承認コードを入力してください:" shouquanma + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma mkdir -p /home/docker/moontv @@ -10969,13 +10980,13 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -10989,7 +11000,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11062,8 +11073,8 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" app_use - read -e -p "ログインパスワードの設定:" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -11160,11 +11171,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # ランダムキーとパスワードを生成します + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11173,17 +11184,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 管理者アカウント情報を追加します + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # コンテナを起動します + # 启动容器 docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -11193,7 +11204,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 元の変数を保持します + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11210,7 +11221,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11260,7 +11271,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11278,7 +11289,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}SK-159KEJILIONYYDS163などのログインキー(SKターニング文字と数字の組み合わせ):" app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11382,7 +11393,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -11395,7 +11406,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11556,7 +11567,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "初期ユーザーまたは管理者を作成します。次のユーザー名とパスワード、およびあなたが管理者であるかどうかを設定してください。" + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11608,7 +11619,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "インストール" + echo "已经安装完成" check_docker_app_ip } @@ -11622,7 +11633,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "アプリはアンインストールされています" + echo "应用已卸载" } docker_app_plus @@ -11661,24 +11672,282 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + stop_containers_or_kill_process 51820 &>/dev/null + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=51820 \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 2 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 2 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear - send_stats "すべてのアプリケーションバックアップ" + send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "バックアップファイルが作成されました: /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11686,14 +11955,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "ファイルは、リモートサーバー/ルートディレクトリに転送されました。" + echo "文件已传送至远程服务器/根目录。" else - echo "転送されるファイルは見つかりませんでした。" + echo "未找到要传送的文件。" fi break ;; *) - echo "注:現在、バックアップにはDockerプロジェクトのみが含まれており、Pagodaや1PanelなどのWebサイトビルディングパネルのデータバックアップは含まれていません。" + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" break ;; esac @@ -11703,29 +11972,29 @@ while true; do r) root_use - send_stats "すべてのアプリケーションが復元されます" - echo "利用可能なアプリバックアップ" + send_stats "全部应用还原" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "アプリケーションデータが復元されました。指定されたアプリケーションメニューを手動で入力し、アプリケーションを更新してアプリケーションを復元してください。" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else - echo "圧縮パッケージは見つかりませんでした。" + echo "没有找到压缩包。" fi ;; @@ -11748,35 +12017,35 @@ linux_work() { while true; do clear - send_stats "バックエンドワークスペース" - echo -e "バックエンドワークスペース" - echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" - echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "現在既存のワークスペースのリスト" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" - echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" - echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" - echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" - echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" - echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" - echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" - echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" - echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" - echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11784,7 +12053,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11792,63 +12061,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11860,21 +12129,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常駐モード" - echo -e "SSH常駐モード${tmux_sshd_status}" - echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1。2をオンにします。オフにします" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "ワークスペースを開始します$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11890,29 +12159,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "カスタムワークスペース" + send_stats "自定义工作区" ;; 23) - read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "バックグラウンドワークスペースにコマンドを注入します" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "ワークスペースを削除します" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -11937,54 +12206,54 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 - echo -e "システムツール" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" - echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" - echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" - echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" - echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" - echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" - echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" - echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" - echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" - echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "ショートカットキーが設定されています" - send_stats "スクリプトのショートカットキーが設定されています" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11992,34 +12261,34 @@ linux_Settings() { 2) clear - send_stats "ログインパスワードを設定します" - echo "ログインパスワードを設定します" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "ルートパスワードモード" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "Pyバージョン管理" - echo "Pythonバージョン管理" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" - echo "クエリの詳細:https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "スクリプトPy管理" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -12052,7 +12321,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "不明なパッケージマネージャー!" + echo "未知的包管理器!" return fi @@ -12081,55 +12350,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スイッチスクリプトPyバージョン" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "オープンポート" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "すべてのポートが開いています" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSHポートを変更します" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 現在のSSHポート番号をお読みください + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 現在のSSHポート番号を印刷します - echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # ユーザーに新しいSSHポート番号を入力するように促します - read -e -p "新しいSSHポート番号を入力してください:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # ポート番号が有効な範囲内にあるかどうかを判断します + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSHポートが変更されました" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSHポート変更を終了します" + send_stats "退出SSH端口修改" break else - echo "ポート番号は無効です。1〜65535の数字を入力してください。" - send_stats "無効なSSHポート入力" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "入力が無効です。番号を入力してください。" - send_stats "無効なSSHポート入力" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -12148,8 +12417,8 @@ EOF ;; 9) root_use - send_stats "新しいユーザーはルートを無効にします" - read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12164,49 +12433,49 @@ EOF passwd -l root - echo "操作が完了しました。" + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6の優先度を設定します" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6の優先度を設定します" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "優先ネットワークを選択します。" choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4の優先度に切り替えました" - send_stats "IPv4の優先度に切り替えました" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6の優先度に切り替えました" - send_stats "IPv6の優先度に切り替えました" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -12224,43 +12493,43 @@ EOF 12) root_use - send_stats "仮想メモリを設定します" + send_stats "设置虚拟内存" while true; do clear - echo "仮想メモリを設定します" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G仮想メモリが設定されています" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G仮想メモリが設定されています" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G仮想メモリが設定されています" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "カスタム仮想メモリが設定されています" + send_stats "已设置自定义虚拟内存" ;; *) @@ -12273,8 +12542,8 @@ EOF 13) while true; do root_use - send_stats "ユーザー管理" - echo "ユーザーリスト" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12285,62 +12554,62 @@ EOF echo "" - echo "アカウント操作" + echo "账户操作" echo "------------------------" - echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3.最高の権限を与える4。最高の権限をキャンセルします" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5.アカウントを削除します" + echo "5. 删除账号" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作が完了しました。" + echo "操作已完成。" ;; 2) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 新しいユーザーを作成し、パスワードを設定します + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 新規ユーザーのsudo許可を付与します + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作が完了しました。" + echo "操作已完成。" ;; 3) - read -e -p "ユーザー名を入力してください:" username - # 新規ユーザーのsudo許可を付与します + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudoアクセス許可を削除します + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "削除するにはユーザー名を入力してください:" username - # ユーザーとそのホームディレクトリを削除します + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -12353,50 +12622,50 @@ EOF 14) clear - send_stats "ユーザー情報ジェネレーター" - echo "ランダムユーザー名" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "ランダムユーザー名$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "ランダム名" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5つのランダムユーザー名を生成します + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "ランダムなユーザー名$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "ランダムuuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "ランダムuuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16ビットランダムパスワード" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32ビットランダムパスワード" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "ランダムなパスワード$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -12404,46 +12673,46 @@ EOF 15) root_use - send_stats "タイムゾーンを変更します" + send_stats "换时区" while true; do clear - echo "システム時間情報" + echo "系统时间信息" - # 現在のシステムタイムゾーンを取得します + # 获取当前系统时区 local timezone=$(current_timezone) - # 現在のシステム時間を取得します + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # タイムゾーンと時間を表示します - echo "現在のシステムタイムゾーン:$timezone" - echo "現在のシステム時間:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "タイムゾーンの切り替え" + echo "时区切换" echo "------------------------" - echo "アジア" - echo "1。中国の上海時間2。中国の香港時間" - echo "3。日本の東京時間4。韓国のソウル時間" - echo "5。シンガポール時間6。インドのコルカタ時間" - echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。タイのバンコクでの時間" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "ヨーロッパ" - echo "11。英国のロンドン時間12。パリの時間フランスの時間" - echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" - echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "アメリカ" - echo "21。WesternTime22。東部時間" - echo "23。カナダ時間24。メキシコの時間" - echo "25。ブラジル時間26。アルゼンチン時間" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31。UTCグローバル標準時間" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -12486,21 +12755,21 @@ EOF 18) root_use - send_stats "ホスト名を変更します" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian、Ubuntu、Centosなどの他のシステム。 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12518,11 +12787,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "ホスト名は次のように変更されています。$new_hostname" - send_stats "ホスト名が変更されました" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "終了すると、ホスト名は変更されていません。" + echo "已退出,未更改主机名。" break fi done @@ -12530,32 +12799,32 @@ EOF 19) root_use - send_stats "システムの更新ソースを変更します" + send_stats "换系统更新源" clear - echo "更新ソース領域を選択します" - echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "中国本土のデフォルトソース" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国本土の教育源" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外起源" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "キャンセル" + echo "已取消" ;; esac @@ -12563,62 +12832,62 @@ EOF ;; 20) - send_stats "タイミングタスク管理" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "タイミングされたタスクリスト" + echo "定时任务列表" crontab -l echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1。毎月のタスク2。毎週のタスク" - echo "3。毎日のタスク4。時間ごとのタスク" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "選択を入力してください:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "時限タスクを追加します" + send_stats "添加定时任务" ;; 2) - read -e -p "削除する必要があるキーワードを入力してください。" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "タイミングタスクを削除します" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "タイミングタスクを編集します" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12630,32 +12899,32 @@ EOF 21) root_use - send_stats "ローカルホストの解析" + send_stats "本地host解析" while true; do clear - echo "ネイティブホストのペルシングリスト" - echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "動作します" + echo "操作" echo "------------------------" - echo "1.新しい解析2を追加します。解析アドレスを削除します" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホストの解析が追加されました" + send_stats "本地host解析新增" ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "ローカルホストの解析と削除" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12666,7 +12935,7 @@ EOF 22) root_use - send_stats "SSH防御" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12678,20 +12947,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防衛プログラム$check_docker" - echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" - echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 安装防御程序" echo "------------------------" - echo "2。SSH傍受記録を表示します" - echo "3。リアルタイムログ監視" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 卸载防御程序" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12714,7 +12983,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12727,47 +12996,47 @@ EOF 23) root_use - send_stats "電流制限シャットダウン機能" + send_stats "限流关机功能" while true; do clear - echo "電流制限シャットダウン機能" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.shファイルが存在するかどうかを確認してください + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gbの値を取得します + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 新しい仮想メモリサイズを入力します - echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" - read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12780,15 +13049,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "現在の制限シャットダウンが設定されています" - send_stats "現在の制限シャットダウンが設定されています" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "現在の制限シャットダウン関数はオフになっています" + echo "已关闭限流关机功能" ;; *) break @@ -12801,40 +13070,40 @@ EOF 24) root_use - send_stats "秘密キーログイン" + send_stats "私钥登录" while true; do clear - echo "ルート秘密キーログインモード" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "キーペアが生成され、SSHログインのより安全な方法" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "新しいキーを生成します" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "既存の公開キーをインポートします" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "地元の秘密の鍵を表示します" + send_stats "查看本机密钥" echo "------------------------" - echo "公開鍵情報" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "秘密のキー情報" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12850,18 +13119,18 @@ EOF 25) root_use - send_stats "電報警告" - echo "TG-BOTモニタリングと早期警告機能" - echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" - echo "しきい値に達した後、ユーザーはユーザーに送信されます" - echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" - read -e -p "必ず続行しますか? (y/n):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "電報警告が有効になっています" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12883,7 +13152,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 〜/.Profileファイルに追加します + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12894,21 +13163,21 @@ EOF source ~/.profile clear - echo "TG-BOT早期警告システムが開始されました" - echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSHの高リスクの脆弱性を修正します" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12952,7 +13221,7 @@ EOF ;; 37) clear - send_stats "コマンドラインの履歴" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12975,61 +13244,61 @@ EOF 41) clear - send_stats "メッセージボード" - echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "ワンストップチューニング" - echo "ワンストップシステムの最適化" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "以下が操作され、最適化されます" - echo "1.システムを最新の状態に更新します" - echo "2。システムジャンクファイルをクリーンアップします" - echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" - echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" - echo -e "5.すべてのポートを開きます" - echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" - echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" - echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" - echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングスタート" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13046,25 +13315,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" - echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -13072,7 +13341,7 @@ EOF 99) clear - send_stats "システムを再起動します" + send_stats "重启系统" server_reboot ;; 100) @@ -13088,32 +13357,32 @@ EOF local status_message="无法确定的状态" fi - echo "プライバシーとセキュリティ" - echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用される機能の名前を収集します。" + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "現在のステータス:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1。コレクションをオンにします" - echo "2。コレクションを閉じます" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "コレクションが有効になっています" - send_stats "プライバシーとセキュリティコレクションが有効になっています" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "コレクションは閉じた" - send_stats "プライバシーとセキュリティは収集のために閉鎖されています" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -13129,11 +13398,11 @@ EOF 102) clear - send_stats "テックライオンスクリプトをアンインストールします" - echo "テックライオンスクリプトをアンインストールします" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" - read -e -p "必ず続行しますか? (y/n):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -13141,16 +13410,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "スクリプトはアンインストールされています、さようなら!" + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "キャンセル" + echo "已取消" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -13160,7 +13429,7 @@ EOF ;; *) - echo "無効な入力!" + echo "无效的输入!" ;; esac break_end @@ -13178,187 +13447,187 @@ EOF linux_file() { root_use - send_stats "ファイルマネージャー" + send_stats "文件管理器" while true; do clear - echo "ファイルマネージャー" + echo "文件管理器" echo "------------------------" - echo "現在のパス" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" - echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" - echo "15.ファイルを削除します" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" - echo "25。ファイルを別のサーバーに渡します" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "ディレクトリ名を入力してください:" dirname - cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" - send_stats "ディレクトリに移動します" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "作成するにはディレクトリ名を入力してください。" dirname - mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" - send_stats "ディレクトリを作成します" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可を入力してください(755など):" perm - chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ディレクトリ権限を変更します" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "現在のディレクトリ名を入力してください:" current_name - read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" - send_stats "ディレクトリの名前を変更します" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "削除するには、ディレクトリ名を入力してください。" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" - send_stats "ディレクトリを削除します" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "前のメニューディレクトリに戻ります" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "作成するにはファイル名を入力してください。" filename - touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" - send_stats "ファイルを作成します" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "編集するにはファイル名を入力してください:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "ファイルを編集します" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "ファイル名を入力してください:" filename - read -e -p "許可を入力してください(755など):" perm - chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" - send_stats "ファイル権限を変更します" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "現在のファイル名を入力してください:" current_name - read -e -p "新しいファイル名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" - send_stats "ファイルの名前を変更します" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "削除するには、ファイル名を入力してください。" filename - rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" - send_stats "ファイルを削除します" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" - send_stats "圧縮ファイル/ディレクトリ" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "ファイル名(.tar.gz)を入力してください:" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" - send_stats "ファイル/ディレクトリを解凍します" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" - send_stats "ファイルまたはディレクトリを移動します" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -Rオプションを使用して、ディレクトリを再帰的にコピーします - cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" - send_stats "ファイルまたはディレクトリをコピーします" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "転送されるファイルパスを入力してください。" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "エラー:ファイルは存在しません。" - send_stats "ファイルの転送に失敗しました:ファイルは存在しません" + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" - send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "エラー:リモートサーバーのパスワードを入力してください。" - send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "ログインポートを入力してください(デフォルト22):" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 既知のホストの古いエントリをクリアします + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCPを使用してファイルを転送します + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "スクリプトは最新です$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13656,15 +13925,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" - send_stats "自動スクリプトの更新をオンにします" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" - send_stats "スクリプト自動更新を閉じます" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13686,41 +13955,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" -echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" -echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" -echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" -echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" -echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" -echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" -echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" -echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" -echo -e "${gl_kjlan}13. ${gl_bai}システムツール" -echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" -echo -e "${gl_kjlan}15. ${gl_bai}広告列" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "選択を入力してください:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "システムの更新" ; linux_update ;; - 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "ワープ管理" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13731,13 +14000,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "無効な入力!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13745,68 +14014,68 @@ done k_info() { -send_stats "Kコマンド参照ユースケース" +send_stats "k命令参考用例" echo "-------------------" -echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "以下は、Kコマンドリファレンスユースケースです。" -echo "スクリプトkを開始します" -echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" -echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" -echo "システムKアップデートを更新| Kアップデート" -echo "クリーンシステムガベージkクリーン| kきれい" -echo "システムパネルk dd |を再インストールしますk再インストール" -echo "BBR3コントロールパネルK BBR3 | K BBRV3" -echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" -echo "仮想メモリkスワップ2048を設定します" -echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" -echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" -echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" -echo "SSHリモート接続ツールK SSH | Kリモート接続" -echo "rsyncリモート同期ツールk rsync | Kリモート同期" -echo "ハードディスク管理ツールKディスク| Kハードディスク管理" -echo "イントラネット浸透(サーバー側)K FRP" -echo "イントラネット浸透(クライアント)K FRPC" -echo "ソフトウェアStart K Start SSHD | k sshdを開始します" -echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" -echo "ソフトウェア再起動k再起動sshd | k再起動sshd" -echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" -echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" -echo "ドメイン名証明書アプリケーションK SSL" -echo "ドメイン名証明書の有効期限クエリK SSL PS" -echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" -echo "Docker Container Management K Docker PS | K Dockerコンテナ" -echo "Docker Image Management K Docker IMG | K Docker画像" -echo "LDNMPサイト管理k Web" -echo "LDNMPキャッシュクリーンアップK Webキャッシュ" -echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" -echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" -echo "ロードバランスkロードバランス| kロードバランシングをインストールします" -echo "ファイアウォールパネルk fhq | kファイアウォール" -echo "オープンポートK DKDK 8080 | Kオープンポート8080" -echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" -echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" -echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" -echo "コマンドお気に入りk fav | Kコマンドのお気に入り" -echo "アプリ市場管理Kアプリ" -echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # パラメーターがない場合は、インタラクティブロジックを実行します + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # パラメーターがある場合は、対応する関数を実行します + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "ソフトウェアをインストールします" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "ソフトウェアをアンインストールします" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13840,7 +14109,7 @@ else rsync_run) shift - send_stats "タイム付きRSYNC同期" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13859,7 +14128,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13872,13 +14141,13 @@ else swap) shift - send_stats "仮想メモリをすばやく設定します" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "タイムゾーンをすばやく設定します" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13926,42 +14195,42 @@ else status|状态) shift - send_stats "ソフトウェアステータスビュー" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "ソフトウェアスタートアップ" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "ソフトウェアの一時停止" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "ソフトウェアの再起動" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "ソフトウェアが起動します" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "証明書のステータスを確認してください" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" else k_info fi @@ -13971,15 +14240,15 @@ else shift case $1 in install|安装) - send_stats "Dockerをすばやくインストールします" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "クイックコンテナ管理" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "クイックミラー管理" + send_stats "快捷镜像管理" docker_image ;; *) @@ -14006,7 +14275,7 @@ else app) shift - send_stats "$@を適用します" + send_stats "应用$@" linux_panel "$@" ;; @@ -14016,4 +14285,3 @@ else ;; esac fi - diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 33e749951..cab3eb64a 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.2" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# 명령을 실행할 함수를 정의합니다 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! -# 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. -# 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 사용자에게 이용 약관에 동의하라는 메시지 +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolbox에 오신 것을 환영합니다${gl_bai}" - echo "스크립트를 처음 사용하면 사용자 라이센스 계약을 읽고 동의하십시오." - echo "사용자 라이센스 계약 : https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "위의 용어에 동의하십니까? (Y/N) :" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "라이센스 동의" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "허가 거부" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "패키지 매개 변수는 제공되지 않습니다!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}설치$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}힌트:${gl_bai}불충분 한 디스크 공간!" - echo "현재 사용 가능한 공간 : $ ((uvery_space_mb/1024)) g" - echo "최소 수요 공간 :${required_gb}G" - echo "설치를 계속할 수 없습니다. 디스크 공간을 청소하고 다시 시도하십시오." - send_stats "불충분 한 디스크 공간" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "패키지 매개 변수는 제공되지 않습니다!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}제거$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return 1 fi done } -# 다양한 분포에 적합한 범용 SystemCTL 기능 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 서비스를 다시 시작하십시오 +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 다시 시작되었습니다." + echo "$1 服务已重启。" else - echo "오류 : 다시 시작합니다$1서비스가 실패했습니다." + echo "错误:重启 $1 服务失败。" fi } -# 서비스를 시작하십시오 +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 시작되었습니다." + echo "$1 服务已启动。" else - echo "오류 : 시작$1서비스가 실패했습니다." + echo "错误:启动 $1 服务失败。" fi } -# 서비스 중지 +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 중단되었습니다." + echo "$1 服务已停止。" else - echo "오류 : 중지$1서비스가 실패했습니다." + echo "错误:停止 $1 服务失败。" fi } -# 서비스 상태를 확인하십시오 +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1서비스 상태가 표시됩니다." + echo "$1 服务状态已显示。" else - echo "오류 : 표시 할 수 없습니다$1서비스 상태." + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME전원 켜기로 설정합니다." + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" - echo "계속하려면 키를 누르십시오 ..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -425,7 +424,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -500,63 +499,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "도커 컨테이너 관리" - echo "도커 컨테이너 목록" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "컨테이너 작동" + echo "容器操作" echo "------------------------" - echo "1. 새 컨테이너를 만듭니다" + echo "1. 创建新的容器" echo "------------------------" - echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" - echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" - echo "4. 지정된 컨테이너를 삭제합니다. 8. 모든 컨테이너를 삭제하십시오" - echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" - echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "새 컨테이너를 만듭니다" - read -e -p "창조 명령을 입력하십시오 :" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "지정된 컨테이너를 시작하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "지정된 컨테이너를 중지하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "지정된 컨테이너를 삭제하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "지정된 컨테이너를 다시 시작하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "모든 컨테이너를 시작하십시오" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "모든 컨테이너를 중지하십시오" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "모든 컨테이너를 삭제하십시오" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +564,28 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "모든 컨테이너를 다시 시작하십시오" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "컨테이너를 입력하십시오" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "컨테이너 로그를 봅니다" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "컨테이너 네트워크를 봅니다" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +603,14 @@ while true; do break_end ;; 14) - send_stats "컨테이너 점유를 봅니다" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "컨테이너 포트 액세스를 허용합니다" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +619,8 @@ while true; do ;; 16) - send_stats "컨테이너 포트 액세스 차단" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +639,44 @@ done docker_image() { while true; do clear - send_stats "도커 이미지 관리" - echo "도커 이미지 목록" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "미러 작동" + echo "镜像操作" echo "------------------------" - echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" - echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "거울을 당기십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "이미지를 업데이트하십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "거울을 삭제하십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "모든 이미지를 삭제합니다" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +685,7 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +753,16 @@ install_crontab() { service cron start ;; *) - echo "지원되지 않는 분포 :$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "운영 체제를 결정할 수 없습니다." + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}Crontab이 설치되고 Cron 서비스가 실행 중입니다.${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +774,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 구성 파일이 존재하는지 확인하고 파일을 작성하고 기본 설정이 존재하지 않는 경우 작성하십시오. + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 구성 업데이트 및 IPv6을 활성화하십시오 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 원래 구성과 새로운 구성을 비교합니다 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}IPv6 액세스가 현재 활성화되어 있습니다${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +809,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 구성 파일이 있는지 확인하십시오 + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}구성 파일이 존재하지 않습니다${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 현재 구성을 읽으십시오 + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 현재 IPv6 상태를 확인하십시오 + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 원래 구성과 새로운 구성을 비교합니다 + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6 액세스는 현재 닫힙니다${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6 액세스가 성공적으로 닫혔습니다${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,117 +869,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 마감 규칙을 삭제하십시오 + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 열린 규칙을 추가하십시오 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "포트가 열렸습니다$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "포트가 열렸습니다" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 열린 규칙을 삭제합니다 + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 가까운 규칙을 추가하십시오 + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "포트 폐쇄$port" + echo "已关闭端口 $port" fi done - # 기존 규칙 삭제 (있는 경우) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 새로운 규칙을 먼저 삽입하십시오 + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "포트 폐쇄" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 차단 규칙을 삭제하십시오 + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 허용 규칙을 추가하십시오 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP 출시$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "IP 출시" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 허용 규칙을 삭제합니다 + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 차단 규칙을 추가하십시오 + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP 차단$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IP 차단" + send_stats "已阻止IP" } @@ -990,7 +989,7 @@ block_ip() { enable_ddos_defense() { - # 방어 DDO를 켜십시오 + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +999,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS 방어를 켜십시오" + send_stats "开启DDoS防御" } -# DDOS 방어를 끕니다 +# 关闭DDoS防御 disable_ddos_defense() { - # 방어 DDO를 끄십시오 + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1014,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS 방어를 끕니다" + send_stats "关闭DDoS防御" } -# 국가 IP 규칙을 관리하는 기능 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,73 +1032,73 @@ manage_country_rules() { case "$action" in block) - # IPSET가 존재하지 않는 경우 작성하십시오 + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IP 영역 파일을 다운로드하십시오 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # IPSET에 IP를 추가하십시오 + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # iptables와 함께 IP를 차단하십시오 + # 使用 iptables 阻止 IP iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "성공적으로 차단되었습니다$country_codeIP 주소" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 허용 국가에 대한 IPSET 만들기 (존재하지 않는 경우) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # IP 영역 파일을 다운로드하십시오 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 기존 국가 규칙을 삭제합니다 + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # IPSET에 IP를 추가하십시오 + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 지정된 국가의 IP 만 허용됩니다 + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "성공적으로 만 허용됩니다$country_codeIP 주소" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 국가의 iptables 규칙을 삭제하십시오 + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # ipset을 파괴하십시오 + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "성공적으로 해제했습니다$country_codeIP 주소 제한" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1115,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "고급 방화벽 관리" - send_stats "고급 방화벽 관리" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "방화벽 관리" + echo "防火墙管理" echo "------------------------" - echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." - echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 지우십시오" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. 핑 허용 12. 핑을 비활성화하십시오" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15. 지정된 국가 IP 16. 지정된 국가 IP 만 허용됩니다." - echo "17. 지정된 국가에서 IP 제한을 해제합니다" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "열린 포트 번호를 입력하십시오 :" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "지정된 포트를 엽니 다" + send_stats "开放指定端口" ;; 2) - read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "지정된 포트를 닫습니다" + send_stats "关闭指定端口" ;; 3) - # 모든 포트를 엽니 다 + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1163,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 엽니 다" + send_stats "开放所有端口" ;; 4) - # 모든 포트를 닫습니다 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,40 +1179,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 닫습니다" + send_stats "关闭所有端口" ;; 5) - # IP 화이트리스트 - read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IP 블랙리스트 - read -e -p "차단 된 IP 또는 IP 세그먼트를 입력하십시오." c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 지정된 IP를 지우십시오 - read -e -p "청산 된 IP를 입력하십시오 :" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "지정된 IP를 지우십시오" + send_stats "清除指定IP" ;; 11) - # 핑을 허용하십시오 + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 허용하십시오" + send_stats "允许PING" ;; 12) - # 핑을 비활성화합니다 + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 비활성화합니다" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1223,20 +1222,20 @@ iptables_panel() { ;; 15) - read -e -p "차단 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "허용 국가$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "허용 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "나라를 차단하십시오$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "나라를 정리하십시오$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1256,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 모든 스왑 파티션을 반복하고 삭제하십시오 + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfile이 더 이상 사용되지 않도록하십시오 + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 이전 /스왑 파일을 삭제하십시오 + # 删除旧的 /swapfile rm -f /swapfile - # 새 스왑 파티션을 만듭니다 + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1287,7 @@ add_swap() { rc-update add local fi - echo -e "가상 메모리 크기가 크기가 커졌습니다${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1297,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야하는지 확인하십시오 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1313,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginx 버전을 얻으십시오 + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQL 버전을 얻으십시오 + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHP 버전을 얻으십시오 + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전을 얻으십시오 + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1340,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 필요한 디렉토리 및 파일을 만듭니다 + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1349,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.yml 파일을 다운로드하여 교체하십시오 + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일로 교체하십시오 + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1398,7 @@ install_ldnmp() { clear - echo "LDNMP 환경이 설치되었습니다" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1415,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "갱신 작업이 업데이트되었습니다" + echo "续签任务已更新" } @@ -1453,15 +1452,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming공개 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}인증서 저장 경로${gl_bai}" - echo "공개 키 :/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1469,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL 인증서를 신속하게 신청하고 만료 전에 서명을 자동으로 갱신하십시오.${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1485,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}응용 인증서 만료${gl_bai}" - echo "사이트 정보 인증서 만료 시간" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1525,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" + send_stats "域名证书申请成功" else - send_stats "도메인 이름 인증서 신청에 실패했습니다" - echo -e "${gl_hong}알아채다:${gl_bai}인증서 응용 프로그램이 실패했습니다. 가능한 이유를 확인하고 다시 시도하십시오." - echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." - echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." - echo -e "3. 네트워크 구성 문제 ➠ CloudFlare Warp 및 기타 가상 네트워크를 사용하는 경우 임시로 종료하십시오." - echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" - echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." - echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "다시 배포를 시도하십시오$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1548,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "도메인 이름 재사용" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1557,8 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1623,8 +1622,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1643,11 +1642,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "로그인 정보 :" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "시작$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1656,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 구성 파일이 있는지 확인하십시오 + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # Zone_ids를 배열로 변환합니다 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트합니다 - read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" - read -e -p "API_Token을 입력하십시오 :" API_TOKEN - read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL - read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 각 Zone_ID를 루프하고 CLEAR CACHE 명령을 실행하십시오. + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "Zone_ID의 캐시 지우기 :$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1686,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "캐시 클리어 요청이 전송되었습니다." + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "사이트 캐시를 정리하십시오" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1702,28 @@ web_cache() { web_del() { - send_stats "사이트 데이터 삭제" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하십시오 (여러 도메인 이름이 공간별로 분리됩니다)." yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "도메인 이름 삭제 :$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 도메인 이름을 데이터베이스 이름으로 변환합니다 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. - echo "데이터베이스 삭제 :$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1739,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 모드 매개 변수에 따라 WAF를 켜거나 끄기로 결정 + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAF 켜기 : 주석을 제거하십시오 + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # waf 닫기 : 댓글을 추가하십시오 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1802,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1829,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1857,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotli를 켜십시오 : 주석을 제거하십시오 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1871,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotli를 닫습니다 : 주석을 추가하십시오 + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1887,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1913,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTD를 켜십시오 : 주석을 제거하십시오 + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1928,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Zstd를 닫습니다 : 주석을 추가하십시오 + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1944,11 @@ nginx_zstd() { else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1975,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1989,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP 환경 방어" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2003,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "서버 웹 사이트 방어 프로그램${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 安装防御程序" echo "------------------------" - echo "5. SSH 차단 레코드보기 6. 웹 사이트 차단 레코드보기" - echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11. 인터셉트 매개 변수 구성 12. 차단 된 모든 IP를 지우십시오" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31. WAF 32를 켜십시오. WAF를 끄십시오" - echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2081,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2097,11 +2096,11 @@ web_security() { ;; 21) - send_stats "CloudFlare 모드" - echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2115,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CF 매개 변수 가져 오기 :" - echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" - echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken - read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2146,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "고 부하 자동 방패 오프닝 스크립트가 추가되었습니다" + echo "高负载自动开盾脚本已添加" else - echo "자동 방패 스크립트가 이미 존재합니다. 추가 할 필요가 없습니다." + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "사이트 waf가 활성화되어 있습니다" - send_stats "사이트 waf가 활성화되어 있습니다" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "사이트 waf가 닫혔습니다" - send_stats "사이트 waf가 닫혔습니다" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2188,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 현재 Worker_Processes 설정 값을 얻으십시오 +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 값에 따라 모드 정보를 설정합니다 +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2207,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTD가 활성화되어 있고 주석이 없는지 확인하십시오 (전체 라인은 ZSTD 켜기로 시작합니다.) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotli가 활성화되어 있고 댓글이 없는지 확인하십시오 + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2237,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP 환경을 최적화하십시오" - echo -e "LDNMP 환경을 최적화하십시오${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" - echo "5. BR 압축 켜기 6. BR 압축 끄기" - echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "사이트 표준 모드" + send_stats "站点标准模式" - # nginx 튜닝 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2275,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2287,23 @@ web_optimization() { optimize_balanced - echo "LDNMP 환경은 표준 모드로 설정되었습니다" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "사이트 고성능 모드" + send_stats "站点高性能模式" - # nginx 튜닝 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2315,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2325,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP 환경은 고성능 모드로 설정되었습니다" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2385,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker = "$ {gl_lv} $ {gl_bai} 설치" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2395,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "액세스 주소 :" +echo "访问地址:" ip_address @@ -2434,31 +2433,31 @@ check_docker_image_update() { return fi - # 컨테이너 생성 시간과 이미지 이름을 얻으십시오 + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 거울 창고 및 태그 추출 + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 기본 레이블이 최신입니다 + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 공식 이미지에 대한 지원을 추가하십시오 + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub API에서 이미지 게시 시간을 얻으십시오 + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득 시간을 확인하십시오 + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 타임 스탬프를 비교하십시오 + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2476,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2486,34 @@ block_container_port() { install iptables - # 다른 모든 IP를 점검하고 차단하십시오 + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 다른 모든 IP를 점검하고 차단하십시오 + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2523,7 @@ block_container_port() { fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2534,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2544,17 @@ clear_container_rules() { install iptables - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2563,17 @@ clear_container_rules() { - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2584,7 @@ clear_container_rules() { fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2598,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." - echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP 액세스를 거부했습니다 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2625,27 @@ block_host_port() { - # 다른 모든 IP 액세스를 거부했습니다 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 확립 및 관련 연결을 위해 트래픽을 허용합니다 + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2657,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." - echo "사용법 : CLEAR_HOST_PORT_RULES <포트 번호> <승인 IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2727,7 +2726,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}관리하다" +send_stats "${docker_name}管理" while true; do clear @@ -2747,18 +2746,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2770,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name설치" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "설치하다$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,12 +2785,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name설치" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "고쳐 쓰다$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,30 +2799,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" - send_stats "제거하십시오$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}도메인 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2859,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2894,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}도메인 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2994,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 세션이 존재하는지 확인하는 기능 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 존재하지 않는 세션 이름이 발견 될 때까지 루프 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 새로운 TMUX 세션을 만듭니다 +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,11 +3079,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "다시 시작" + echo "已重启" reboot ;; *) - echo "취소" + echo "已取消" ;; esac @@ -3127,8 +3126,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP 환경을 다시 설치할 수 없습니다" - echo -e "${gl_huang}힌트:${gl_bai}웹 사이트 구성 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3137,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP 환경을 설치하십시오" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3154,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx 환경을 설치하십시오" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3168,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginx가 설치되었습니다" -echo -e "현재 버전 :${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3180,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "먼저 LDNMP 환경을 설치하십시오" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3190,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "Nginx 환경을 먼저 설치하십시오" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3201,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신 것$webname세워짐!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "당신 것$webname세워짐!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3222,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3263,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "반세대 IP를 입력하십시오 :" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "반세대 포트를 입력하십시오 :" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3296,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3356,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP 사이트 관리" - echo "LDNMP 환경" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "대지:${output}인증서 만료 시간" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3374,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "데이터 베이스:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "사이트 디렉토리" + echo "站点目录" echo "------------------------" - echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" - echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" - echo "5. 액세스 로그보기 6. 오류 로그보기" - echo "7. 글로벌 구성 편집 8. 사이트 구성 편집" - echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서보기" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20. 지정된 사이트 데이터를 삭제합니다" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "도메인 이름 인증서를 신청하십시오" - read -e -p "도메인 이름을 입력하십시오 :" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3411,15 @@ ldnmp_web_status() { ;; 2) - send_stats "사이트 도메인 이름을 변경하십시오" - echo -e "${gl_hong}적극 권장 :${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" - read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # MySQL 교체 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3437,7 @@ ldnmp_web_status() { done done - # 웹 사이트 디렉토리 교체 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3458,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "관련 사이트를 만듭니다" - echo -e "액세스 용 기존 사이트의 새 도메인 이름을 연결하십시오." - read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3475,25 @@ ldnmp_web_status() { ;; 5) - send_stats "액세스 로그를 봅니다" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "오류 로그를 봅니다" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "글로벌 구성 편집" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "사이트 구성 편집" - read -e -p "사이트 구성을 편집하려면 편집 할 도메인 이름을 입력하십시오." yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3503,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "사이트 데이터를 봅니다" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3535,21 +3534,21 @@ fi install_panel() { -send_stats "${panelname}관리하다" +send_stats "${panelname}管理" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}요즘 인기 있고 강력한 운영 및 유지 관리 패널입니다." - echo "공식 웹 사이트 소개 :$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. 설치 2. 관리 3. 제거" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,20 +3557,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}설치하다" + send_stats "${panelname}安装" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}제어" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}제거하십시오" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3614,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRP 서버를 설치하십시오" - # 임의의 포트 및 자격 증명을 생성합니다 + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3636,17 @@ EOF donlond_frp frps - # 출력 생성 정보 + # 输出生成的信息 ip_address echo "------------------------" - echo "클라이언트 배포에 필요한 매개 변수" - echo "서비스 IP :$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRP 패널 정보" - echo "FRP 패널 주소 : http : //$ipv4_address:$dashboard_port" - echo "FRP 패널 사용자 이름 :$dashboard_user" - echo "FRP 패널 비밀번호 :$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3656,9 @@ EOF configure_frpc() { - send_stats "FRP 클라이언트를 설치하십시오" - read -e -p "외부 네트워크 도킹 IP를 입력하십시오." server_addr - read -e -p "외부 네트워크 도킹 토큰을 입력하십시오." token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3678,17 @@ EOF } add_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 추가하십시오" - # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 - read -e -p "서비스 이름을 입력하십시오 :" service_name - read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "인트라넷 포트를 입력하십시오 :" local_port - read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # 구성 파일에 사용자 입력을 쓰십시오 + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3698,8 @@ remote_port = ${remote_port} EOF - # 출력 생성 정보 - echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3710,12 @@ EOF delete_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 삭제하십시오" - # 삭제 해야하는 서비스 이름을 입력하라는 메시지 - read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name - # SED를 사용하여 서비스 및 관련 구성을 삭제하십시오. + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3725,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 헤더를 인쇄하십시오 + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3746,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 서비스 정보가있는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,11 +3755,11 @@ list_forwarding_services() { type } - # 현재 서비스 이름을 업데이트하십시오 + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 이전 값을 지우십시오 + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -3789,7 +3788,7 @@ list_forwarding_services() { } END { - # 마지막 서비스에 대한 정보를 인쇄하십시오 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3801,17 @@ list_forwarding_services() { -# FRP 서버 포트를 가져옵니다 +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 액세스 주소를 생성합니다 +# 生成访问地址 generate_access_urls() { - # 모든 포트를 먼저 얻으십시오 + # 首先获取所有端口 get_frp_ports - # 8055/8056 이외의 포트가 있는지 확인하십시오 + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3820,18 @@ generate_access_urls() { fi done - # 유효한 포트가있을 때만 제목과 콘텐츠 표시 + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRP 서비스 외부 액세스 주소 :" + echo "FRP服务对外访问地址:" - # 프로세스 IPv4 주소 + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # Process IPv6 주소 (현재 경우) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3840,7 @@ generate_access_urls() { done fi - # HTTPS 구성 처리 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3867,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP 서버" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3875,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 서버$check_frp $update_status" - echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 인트라넷 서비스에 대한 도메인 이름 액세스 6. 도메인 이름 액세스 삭제" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00. 서비스 상태 새로 고침 0. 이전 메뉴로 돌아갑니다." + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3901,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 서버가 설치되었습니다" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3911,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 서버가 업데이트되었습니다" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3922,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; 5) - echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" - send_stats "외부 도메인 이름에 대한 FRP 액세스" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용" - read -e -p "해제 할 포트를 입력하십시오." frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." - read -e -p "차단 해야하는 포트를 입력하십시오." frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRP 서비스 상태를 새로 고치십시오" - echo "FRP 서비스 상태가 새로 고쳐졌습니다" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3965,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP 클라이언트" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3973,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버로 도킹, 도킹 후 인터넷 액세스에 인트라넷 침투 서비스를 만들 수 있습니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3984,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 구성 수동으로 서비스 구성" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3998,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 클라이언트가 설치되었습니다" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4008,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP 클라이언트가 업데이트되었습니다" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4019,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; 4) @@ -4066,68 +4065,68 @@ yt_menu_pro() { fi clear - send_stats "YT-DLP 다운로드 도구" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLP는 YouTube, Bilibili, Twitter 등을 포함한 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." - echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "다운로드 된 비디오 목록 :" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. 단일 비디오 다운로드 6. 배치 비디오 다운로드 7. 사용자 정의 매개 변수 다운로드" - echo "8. MP3 오디오 9. 비디오 디렉토리 삭제 10. 쿠키 관리 (개발 중)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "옵션 번호를 입력하십시오 :" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "yt-dlp 설치 ..." - echo "yt-dlp 설치 ..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlp 업데이트 ..." - echo "yt-dlp 업데이트 ..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlp 제거 ..." - echo "yt-dlp 제거 ..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "단일 비디오 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "다운로드가 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "배치 비디오 다운로드" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "이제 배치 다운로드를 시작하십시오 ..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4134,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "배치 다운로드가 완료되었습니다. 키를 눌러 계속하십시오 ..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "맞춤형 비디오 다운로드" - read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "오디오 다운로드가 완료되었습니다. 키를 누르면 계속하십시오 ..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "비디오 삭제" - read -e -p "삭제 비디오의 이름을 입력하십시오." rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4194,7 @@ set_timedate() { -# DPKG 인터럽트 문제를 수정하십시오 +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4203,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4223,7 +4222,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi } @@ -4231,7 +4230,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}시스템 정리 ...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4259,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "패키지 관리자 캐시 청소 ..." + echo "清理包管理器缓存..." apk cache clean - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APK 캐시 삭제 ..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,23 +4283,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "사용하지 않는 의존성 정리 ..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "패키지 관리자 캐시 청소 ..." + echo "清理包管理器缓存..." pkg clean -y - echo "시스템 로그 삭제 ..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi return @@ -4340,26 +4339,26 @@ fi set_dns_ui() { root_use -send_stats "DNS 최적화" +send_stats "优化DNS" while true; do clear - echo "DNS 주소를 최적화합니다" + echo "优化DNS地址" echo "------------------------" - echo "현재 DNS 주소" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 외국 DNS 최적화 :" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 국내 DNS 최적화 :" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 구성을 수동으로 편집합니다" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4366,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "외국 DNS 최적화" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4374,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "국내 DNS 최적화" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "DNS 구성을 수동으로 편집합니다" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4402,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthentication이 발견되면 예로 설정하십시오 + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 발견 된 경우 PubKeyAuthentication이 예로 설정됩니다 + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4416,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthentication 또는 PubKeyAuthentication이 일치하지 않는 경우 기본값을 설정하십시오. + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4427,7 @@ correct_ssh_config() { new_ssh_port() { - # 백업 SSH 구성 파일 + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4440,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 포트는 다음으로 수정되었습니다.$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4458,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "개인 키 정보가 생성되었습니다. 복사하고 저장하십시오.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인 파일" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4470,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}루트 프라이빗 키 로그인이 활성화되고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "SSH 공개 키 내용을 입력하십시오 (일반적으로 'SSH-RSA'또는 'SSH-ED25519'로 시작) :" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}오류 : 공개 키 컨텐츠가 입력되지 않았습니다.${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4498,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}공개 키가 성공적으로 가져 왔고 루트 개인 키 로그인이 활성화되었고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4507,26 @@ import_sshkey() { add_sshpasswd() { -echo "루트 비밀번호를 설정하십시오" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능은 루트 사용자가 실행해야합니다!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "시스템을 다시 설치하십시오" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4537,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}Teddysun.com${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "시스템을 다시 설치하십시오" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4587,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "데비안 13을 다시 설치하십시오" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4609,49 @@ dd_xitong() { ;; 2) - send_stats "데비안 12를 다시 설치하십시오" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "데비안 11을 다시 설치하십시오" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "데비안 10을 다시 설치하십시오" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "우분투 24.04를 다시 설치하십시오" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "우분투 22.04를 다시 설치하십시오" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04를 다시 설치하십시오" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "우분투 18.04를 다시 설치하십시오" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4660,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10을 다시 설치하십시오" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4668,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9를 다시 설치하십시오" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4676,7 @@ dd_xitong() { ;; 23) - send_stats "Alma10을 다시 설치하십시오" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4684,7 @@ dd_xitong() { ;; 24) - send_stats "Alma9를 다시 설치하십시오" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4692,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10을 다시 설치하십시오" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4700,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9를 다시 설치하십시오" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4708,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42를 다시 설치하십시오" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4716,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41을 다시 설치하십시오" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4724,7 @@ dd_xitong() { ;; 29) - send_stats "CentOS10을 다시 설치하십시오" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4732,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9를 다시 설치하십시오" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4740,7 @@ dd_xitong() { ;; 31) - send_stats "알파인을 다시 설치하십시오" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4748,7 @@ dd_xitong() { ;; 32) - send_stats "아치를 다시 설치하십시오" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4756,7 @@ dd_xitong() { ;; 33) - send_stats "칼리를 다시 설치하십시오" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4764,7 @@ dd_xitong() { ;; 34) - send_stats "Openeuler를 다시 설치하십시오" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4772,7 @@ dd_xitong() { ;; 35) - send_stats "재설치 OpenSuse" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4780,7 @@ dd_xitong() { ;; 36) - send_stats "비행 소부소" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4789,7 @@ dd_xitong() { 41) - send_stats "Windows 11을 다시 설치하십시오" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4797,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "Windows 10을 다시 설치하십시오" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7을 다시 설치하십시오" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4811,21 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22를 다시 설치하십시오" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "Windows Server 19를 다시 설치하십시오" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "Windows Server 16을 다시 설치하십시오" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4833,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11 Arm을 다시 설치하십시오" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4851,7 +4850,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3 관리" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,17 +4863,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "Xanmod의 BBRV3 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. BBRV3 커널 업데이트 2. BBRV3 커널 제거" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4883,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4892,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmod 커널이 업데이트되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4902,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmod 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4915,13 @@ bbrv3() { else clear - echo "BBR3 가속도를 설정하십시오" - echo "비디오 소개 : https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "데비안/우분투 만 지원합니다" - echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4929,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경은이를 지원하지 않으며 데비안 및 우분투 시스템 만 지원합니다." + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "운영 체제 유형을 결정할 수 없습니다" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4945,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,17 +4956,17 @@ bbrv3() { bbr_on - echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4975,40 @@ bbrv3() { elrepo_install() { - # Elrepo GPG 공개 키를 가져 오십시오 - echo "Elrepo GPG 공개 키를 가져 오십시오 ..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 시스템 버전을 감지하십시오 + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 지원되는 운영 체제에서 실행하십시오 + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "지원되지 않는 운영 체제 :$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 감지 된 운영 체제 정보를 인쇄합니다 - echo "운영 체제 감지 :$os_name $os_version" - # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepo 저장소 구성 (버전 9)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "지원되지 않는 시스템 버전 :$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오. - echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepo 저장소 구성이 설치되어 최신 메인 라인 커널로 업데이트됩니다." + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5016,37 @@ elrepo_install() { elrepo() { root_use - send_stats "레드 모자 커널 관리" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hat 커널을 업데이트하십시오" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepo 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" - send_stats "빨간 모자 커널을 제거하십시오" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5059,26 @@ elrepo() { else clear - echo "데이터를 백업하고 Linux 커널을 업그레이드합니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" - echo "Linux 커널을 업그레이드하면 시스템 성능 및 보안이 향상 될 수 있습니다. 조건이 허용되고 생산 환경을 조심스럽게 업그레이드하는 경우 시도하는 것이 좋습니다!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hat 커널을 업그레이드하십시오" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5089,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}바이러스 데이터베이스 업데이트 ...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5099,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔 할 디렉토리를 지정하십시오." + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}스캔 디렉토리 $@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # 마운트 매개 변수를 빌드하십시오 + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # Clamscan 명령 매개 변수를 작성하십시오 + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5120,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Docker 명령을 실행하십시오 + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5129,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ scan이 완료되고 바이러스 보고서가 저장됩니다${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}바이러스가 있다면 제발${gl_huang}scan.log${gl_lv}파일에서 찾은 키워드를 검색하여 바이러스의 위치를 ​​확인하십시오.${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5142,23 @@ clamav_scan() { clamav() { root_use - send_stats "바이러스 스캔 관리" + send_stats "病毒扫描管理" while true; do clear - echo "Clamav 바이러스 스캐닝 도구" - echo "비디오 소개 : https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "오픈 소스 바이러스 백신 소프트웨어 도구로 주로 다양한 유형의 맬웨어를 감지하고 제거하는 데 사용됩니다." - echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리를 스캔하십시오${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "전체 디스크 스캔" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5167,7 @@ clamav() { ;; 2) - send_stats "중요한 디렉토리 스캔" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5175,8 @@ clamav() { break_end ;; 3) - send_stats "사용자 정의 디렉토리 스캔" - read -e -p "스캔 할 디렉토리를 입력하십시오." directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5193,21 @@ clamav() { -# 고성능 모드 최적화 기능 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}전환하십시오${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,36 +5219,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 이퀄라이제이션 모드 최적화 기능 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5260,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 기본 설정 기능을 복원하십시오 +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}기본 설정으로 복원하십시오 ...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}파일 디스크립터 복원 ...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}네트워크 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5301,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}캐시 관리 복원 ...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}다른 최적화를 복원 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 웹 사이트 구축 최적화 기능 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,16 +5343,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5363,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux 커널 튜닝 관리" - echo "Linux 시스템에서 커널 매개 변수의 최적화" - echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." - echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." - echo "2. 균형 최적화 모드 : 매일 사용하기에 적합한 성능과 자원 소비 사이의 균형." - echo "3. 웹 사이트 최적화 모드 : 웹 사이트 서버에 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." - echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." - echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." - echo "6. 기본 설정을 복원하십시오. 시스템 설정을 기본 구성으로 복원하십시오." + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "고성능 모드 최적화" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "균형 모드 최적화" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "웹 사이트 최적화 모델" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "라이브 스트리밍 최적화" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "게임 서버 최적화" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "기본 설정을 복원하십시오" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5445,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5454,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "지원되지 않는 시스템 :$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "지원되지 않는 시스템, 시스템 유형을 인식 할 수 없습니다." + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5474,29 @@ update_locale() { linux_language() { root_use -send_stats "스위치 시스템 언어" +send_stats "切换系统语言" while true; do clear - echo "현재 시스템 언어 :$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1. 영어 2. 중국어 3. 전통 중국어" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "영어로 전환하십시오" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "단순화 된 중국어로 전환하십시오" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "전통적인 중국어로 전환하십시오" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5518,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 볼 수 있도록 SSH를 다시 ​​연결하십시오!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5530,10 +5529,10 @@ break_end shell_bianse() { root_use - send_stats "명령 라인 미화 도구" + send_stats "命令行美化工具" while true; do clear - echo "명령 라인 미화 도구" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5543,9 +5542,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5589,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "시스템 재활용 스테이션" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5604,17 @@ linux_trash() { fi clear - echo -e "현재 재활용 쓰레기통${trash_status}" - echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "재활용 쓰레기통은 비어 있습니다" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1. 재활용 빈을 활성화합니다. 2. 재활용 쓰레기통을 닫습니다." - echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5622,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "Recycle Bin이 활성화되고 삭제 된 파일이 Recycle Bin으로 이동됩니다." + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,23 +5630,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "재활용 빈이 닫히고 파일이 직접 삭제됩니다." + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "복원 할 파일 이름을 입력하십시오." file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore홈 디렉토리로 복원되었습니다." + echo "$file_to_restore 已还原到主目录。" else - echo "파일이 존재하지 않습니다." + echo "文件不存在。" fi ;; 4) - read -e -p "재활용 쓰레기통을 지우셨습니까? [Y/N] :" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "재활용 쓰레기통이 지워졌습니다." + echo "回收站已清空。" fi ;; *) @@ -5658,23 +5657,23 @@ linux_trash() { } linux_fav() { -send_stats "명령 즐겨 찾기" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 백업을 만듭니다 +# 创建备份 create_backup() { - send_stats "백업을 만듭니다" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 - echo "백업 예제 :" - echo "- 단일 디렉토리를 백업 : /var /www" - echo "- 여러 디렉토리 백업 : /etc /home /var /log" - echo "- Direct Enter는 기본 디렉토리 ( /etc /usr /home)를 사용합니다." - read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # 사용자가 디렉토리를 입력하지 않으면 기본 디렉토리를 사용하십시오. + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5681,119 @@ create_backup() { "/home" # 用户数据 ) else - # 사용자가 입력 한 디렉토리를 공백 별 배열로 분리합니다. + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 백업 파일 접두사를 생성합니다 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 디렉토리 이름을 추출하고 슬래시를 제거하십시오 + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 마지막 밑줄을 제거하십시오 + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # 백업 파일 이름을 생성합니다 + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 사용자가 선택한 디렉토리를 인쇄하십시오 - echo "선택한 백업 디렉토리는 다음과 같습니다." + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 백업을 만듭니다 - echo "백업 생성$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 명령이 성공했는지 확인하십시오 + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "백업은 성공적으로 생성되었습니다.$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "백업 생성이 실패했습니다!" + echo "备份创建失败!" exit 1 fi } -# 백업을 복원하십시오 +# 恢复备份 restore_backup() { - send_stats "백업을 복원하십시오" - # 복원하려는 백업을 선택하십시오 - read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - echo "백업 복구$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "백업 및 복원을 성공적으로 복원하십시오!" + echo "备份恢复成功!" else - echo "백업 복구 실패!" + echo "备份恢复失败!" exit 1 fi } -# 백업을 나열합니다 +# 列出备份 list_backups() { - echo "사용 가능한 백업 :" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# 백업을 삭제하십시오 +# 删除备份 delete_backup() { - send_stats "백업을 삭제하십시오" + send_stats "删除备份" - read -e -p "삭제하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - # 백업을 삭제하십시오 + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "백업이 성공적으로 삭제되었습니다!" + echo "备份删除成功!" else - echo "백업 삭제가 실패했습니다!" + echo "备份删除失败!" exit 1 fi } -# 백업 메인 메뉴 +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "시스템 백업 기능" - echo "시스템 백업 기능" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. 백업 만들기 2. 백업 복원 3. 백업 삭제" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5805,56 @@ linux_backup() { -# 연결 목록 표시 +# 显示连接列表 list_connections() { - echo "저장된 연결 :" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 새 연결을 추가하십시오 +# 添加新连接 add_connection() { - send_stats "새 연결을 추가하십시오" - echo "새 연결을 만드는 예 :" - echo "- 연결 이름 : my_server" - echo "-IP 주소 : 192.168.1.100" - echo "- 사용자 이름 : 루트" - echo "- 포트 : 22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "연결 이름을 입력하십시오 :" name - read -e -p "IP 주소를 입력하십시오 :" ip - read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "인증 방법을 선택하십시오 :" - echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택 (1/2)을 입력하십시오 :" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5863,89 @@ add_connection() { fi ;; *) - echo "잘못된 선택!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "연결이 저장됩니다!" + echo "连接已保存!" } -# 연결을 삭제하십시오 +# 删除连接 delete_connection() { - send_stats "연결을 삭제하십시오" - read -e -p "삭제하려면 연결 번호를 입력하십시오." num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "연결이 삭제되었습니다!" + echo "连接已删除!" } -# 연결을 사용하십시오 +# 使用连接 use_connection() { - send_stats "연결을 사용하십시오" - read -e -p "사용할 연결 번호를 입력하십시오." num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "연결$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 키와 연결하십시오 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 키 파일 경로가 정확합니까?$password_or_key" - echo "2. 키 파일 권한이 올바른지 여부 (600이어야 함)." - echo "3. 대상 서버가 키를 사용하여 로그인 할 수 있는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # 비밀번호로 연결하십시오 + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." - echo "설치 방법 :" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 사용자 이름과 비밀번호가 올바른지 여부." - echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." - echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSH 원격 연결 도구" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 구성 파일과 키 디렉토리가 존재하는지 확인하고 존재하지 않으면 작성하십시오. + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5957,21 @@ ssh_manager() { while true; do clear - echo "SSH 원격 연결 도구" - echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1. 새 연결 만들기 2. 연결 사용 3. 연결 삭제" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5987,156 @@ ssh_manager() { -# 사용 가능한 하드 디스크 파티션을 나열하십시오 +# 列出可用的硬盘分区 list_partitions() { - echo "사용 가능한 하드 디스크 파티션 :" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 파티션을 장착하십시오 +# 挂载分区 mount_partition() { - send_stats "파티션을 장착하십시오" - read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션은 이미 장착되어 있습니다!" + echo "分区已经挂载!" return fi - # 마운트 포인트를 만듭니다 + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 파티션을 장착하십시오 + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "파티션 마운트 성공적으로 :$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "파티션 마운트 실패!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# 파티션을 제거하십시오 +# 卸载分区 unmount_partition() { - send_stats "파티션을 제거하십시오" - read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "파티션이 장착되지 않았습니다!" + echo "分区未挂载!" return fi - # 파티션을 제거하십시오 + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 분할 해제 성공 :$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "파티션 제거 실패!" + echo "分区卸载失败!" fi } -# 목록 장착 파티션 +# 列出已挂载的分区 list_mounted_partitions() { - echo "마운트 파티션 :" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 형식 파티션 +# 格式化分区 format_partition() { - send_stats "형식 파티션" - read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 장착되었습니다. 먼저 제거하십시오!" + echo "分区已经挂载,请先卸载!" return fi - # 파일 시스템 유형을 선택하십시오 - echo "파일 시스템 유형을 선택하십시오 :" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "선택을 입력하십시오 :" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "잘못된 선택!"; return ;; + *) echo "无效的选择!"; return ;; esac - # 형식을 확인하십시오 - read -e -p "파티션 형식 확인 /dev /$PARTITION~을 위한$FS_TYPE그게? (Y/N) :" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "작업이 취소되었습니다." + echo "操作已取消。" return fi - # 형식 파티션 - echo "파티션 서식 /dev /$PARTITION~을 위한$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 형식이 성공적이었습니다!" + echo "分区格式化成功!" else - echo "파티션 형식이 실패했습니다!" + echo "分区格式化失败!" fi } -# 파티션 상태를 확인하십시오 +# 检查分区状态 check_partition() { - send_stats "파티션 상태를 확인하십시오" - read -e -p "파티션 이름을 입력하여 확인하십시오 (예 : SDA1) :" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # 파티션이 있는지 확인하십시오 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션 상태를 확인하십시오 - echo "파티션 /개발자 /$PARTITION상태:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# 메인 메뉴 +# 主菜单 disk_manager() { - send_stats "하드 디스크 관리 기능" + send_stats "硬盘管理功能" while true; do clear - echo "하드 디스크 파티션 관리" - echo -e "${gl_huang}이 기능은 테스트 기간 동안 내부적으로 테스트되므로 생산 환경에서 사용하지 마십시오.${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" - echo "4. 파티션 형식 5. 파티션 상태를 확인하십시오" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6145,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } -# 작업 목록 표시 +# 显示任务列表 list_tasks() { - echo "저장된 동기화 작업 :" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 새로운 작업을 추가하십시오 +# 添加新任务 add_task() { - send_stats "새 동기화 작업을 추가하십시오" - echo "새 동기화 작업 작성 예 :" - echo "- 작업 이름 : Backup_www" - echo "- 로컬 디렉토리 : /var /www" - echo "- 원격 주소 : user@192.168.1.100" - echo "- 원격 디렉토리 : /백업 /www" - echo "- 포트 번호 (기본 22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "작업 이름을 입력하십시오 :" name - read -e -p "로컬 디렉토리를 입력하십시오 :" local_path - read -e -p "원격 디렉토리를 입력하십시오 :" remote_path - read -e -p "원격 사용자 @IP를 입력하십시오 :" remote - read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "인증 방법을 선택하십시오 :" - echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택하십시오 (1/2) :" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6210,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "잘못된 키 컨텐츠!" + echo "无效的密钥内容!" return fi ;; *) - echo "잘못된 선택!" + echo "无效的选择!" return ;; esac - echo "동기화 모드를 선택하십시오 :" - echo "1. 표준 모드 (-avz)" - echo "2. 대상 파일 삭제 (-avz-delete)" - read -e -p "선택하십시오 (1/2) :" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "유효하지 않은 선택, 기본값 -AVZ를 사용하십시오"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "작업을 저장했습니다!" + echo "任务已保存!" } -# 작업을 삭제하십시오 +# 删除任务 delete_task() { - send_stats "동기화 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 해당 작업을 찾을 수 없었습니다." + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "작업이 삭제되었습니다!" + echo "任务已删除!" } run_task() { - send_stats "동기화 작업을 수행하십시오" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 매개 변수를 분석하십시오 + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6277,51 @@ run_task() { num="$1" fi - # 들어오는 작업 번호가없는 경우 사용자에게 입력하라는 메시지를 표시하십시오. + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "실행할 작업 번호를 입력하십시오." num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 작업이 찾을 수 없었습니다!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 동기화 방향에 따라 소스 및 대상 경로를 조정하십시오 + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "동기화를 원격 끝으로 푸시합니다.$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH 연결 공통 매개 변수를 추가하십시오 + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." - echo "설치 방법 :" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 키 파일이 존재하는지 여부와 권한이 올바른지 확인 + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "오류 : 키 파일이 존재하지 않습니다.$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "경고 : 키 파일 권한이 잘못되었고 수리 중입니다 ..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6330,32 +6329,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "동기화가 완료되었습니다!" + echo "同步完成!" else - echo "동기화 실패! 다음을 확인하십시오." - echo "1. 네트워크 연결이 정상입니까?" - echo "2. 원격 호스트가 액세스 할 수 있습니까?" - echo "3. 인증 정보가 정확합니까?" - echo "4. 로컬 및 원격 디렉토리에 올바른 액세스 권한이 있습니까?" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 시간이 정한 작업을 만듭니다 +# 创建定时任务 schedule_task() { - send_stats "동기화 타이밍 작업을 추가하십시오" + send_stats "添加同步定时任务" - read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi - echo "시간이 정한 실행 간격을 선택하십시오." - echo "1) 한 시간에 한 번 실행하십시오" - echo "2) 하루에 한 번 수행하십시오" - echo "3) 일주일에 한 번 실행하십시오" - read -e -p "옵션을 입력하십시오 (1/2/3) :" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6362,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "오류 : 유효한 옵션을 입력하십시오!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 동일한 작업이 이미 존재하는지 확인하십시오 + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "오류 :이 작업의 타이밍 동기화가 이미 존재합니다!" + echo "错误: 该任务的定时同步已存在!" return fi - # 사용자에게 크론AB를 만듭니다 + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "타이밍 작업이 만들어졌습니다.$cron_job" + echo "定时任务已创建: $cron_job" } -# 예정된 작업을 봅니다 +# 查看定时任务 view_tasks() { - echo "현재 타이밍 작업 :" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 타이밍 작업을 삭제하십시오 +# 删除定时任务 delete_task_schedule() { - send_stats "동기화 타이밍 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "삭제 된 작업 번호$num타이밍 작업" + echo "已删除任务编号 $num 的定时任务" } -# 작업 관리 메인 메뉴 +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "RSYNC 원격 동기화 도구" - echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 새 작업 생성 2. 작업을 삭제하십시오" - echo "3. 원격 끝에 로컬 동기화 수행 4. 로컬 엔드에 대한 원격 동기화 수행" - echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6430,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6447,7 @@ rsync_manager() { linux_ps() { clear - send_stats "시스템 정보 쿼리" + send_stats "系统信息查询" ip_address @@ -6498,41 +6497,41 @@ linux_ps() { echo "" - echo -e "시스템 정보 쿼리" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}호스트 이름 :${gl_bai}$hostname" - echo -e "${gl_kjlan}시스템 버전 :${gl_bai}$os_info" - echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU 모델 :${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU 코어 수 :${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" - echo -e "${gl_kjlan}물리적 기억 :${gl_bai}$mem_info" - echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" - echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}네트워크 알고리즘 :${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 주소 :${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6 주소 :${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS 주소 :${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}지리적 위치 :${gl_bai}$country $city" - echo -e "${gl_kjlan}시스템 시간 :${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6544,111 @@ linux_tools() { while true; do clear - # send_stats "기본 도구" - echo -e "기본 도구" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" - echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" - echo -e "${gl_kjlan}9. ${gl_bai}Tmux 다중 채널 배경 달리기 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" - echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" - echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" curl --help - send_stats "컬을 설치하십시오" + send_stats "安装curl" ;; 2) clear install wget clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" wget --help - send_stats "wget을 설치하십시오" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" sudo --help - send_stats "Sudo를 설치하십시오" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" socat -h - send_stats "Socat을 설치하십시오" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "HTOP를 설치하십시오" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "iftop을 설치하십시오" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" unzip - send_stats "압축을 설치하십시오" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" tar --help - send_stats "타르를 설치하십시오" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmux를 설치하십시오" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "FFMPEG를 설치하십시오" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6656,7 @@ linux_tools() { install btop clear btop - send_stats "Btop을 설치하십시오" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6665,7 @@ linux_tools() { clear ranger cd ~ - send_stats "레인저를 설치하십시오" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6674,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDU를 설치하십시오" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6683,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZF를 설치하십시오" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6692,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIM을 설치하십시오" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6701,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "나노를 설치하십시오" + send_stats "安装nano" ;; @@ -6713,7 +6712,7 @@ linux_tools() { clear git --help cd ~ - send_stats "git을 설치하십시오" + send_stats "安装git" ;; 21) @@ -6721,67 +6720,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix를 설치하십시오" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "SL을 설치하십시오" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "Bastet을 설치하십시오" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "NSNAKE를 설치하십시오" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "Ninvaders를 설치하십시오" + send_stats "安装ninvaders" ;; 31) clear - send_stats "모두 설치하십시오" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "모든 설치 (게임 및 화면 보호기 제외)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "모든 것을 제거하십시오" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "설치된 도구 이름 (WGET CURL SUDO HTOP)을 입력하십시오." installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "지정된 소프트웨어를 설치하십시오" + send_stats "安装指定软件" ;; 42) clear - read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "지정된 소프트웨어를 제거하십시오" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6788,7 @@ linux_tools() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -6803,27 +6802,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR 관리" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "현재 TCP 차단 알고리즘 :$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" - echo "BBR 관리" + echo "BBR管理" echo "------------------------" - echo "1. BBRV3 켜기 2. BBRV3 끄기 (재시작)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "알파인 활성화 BBR3" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6868,18 +6867,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}현재 백업 목록 :${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" + echo -e "${BLUE}当前备份列表:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } # ---------------------------- - # 지원 + # 备份 # ---------------------------- backup_docker() { - echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" - read -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers + send_stats "Docker备份" + + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6890,7 +6892,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너가 없습니다${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6898,28 +6900,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 자동으로 생성 된 복원 스크립트" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # 중복 포장을 피하기 위해 패키지 작곡 프로젝트의 경로를 기록하십시오. + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}백업 컨테이너 :$c${NC}" + echo -e "${GREEN}备份容器: $c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}감지$c예, Docker-compose 컨테이너${NC}" + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir + read -p "未检测到 compose 目录,请手动输入路径: " project_dir fi - # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 + # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}작곡 프로젝트 [$project_name] 백업, 중복 포장을 건너 뛰십시오 ...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" continue fi @@ -6927,136 +6929,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# Docker-Compose Recovery :$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}작곡 프로젝트 [$project_name] 포장 :${project_dir}${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" else - echo -e "${RED}docker-compose.yml을 찾을 수 없고이 컨테이너를 건너 뛰십시오 ...${NC}" + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" fi else - # 일반 컨테이너 백업 볼륨 + # 普通容器备份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "포장 롤 :$path" + echo "打包卷: $path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 포트 + # 端口 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 환경 변수 + # 环境变量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 볼륨 매핑 + # 卷映射 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 거울 + # 镜像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\ n# 복원 컨테이너 :$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # /home /docker 아래의 모든 파일을 백업 (하위 디렉터 제외) + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home /docker 아래 파일을 백업 ...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - - echo -e "${GREEN}/home /docker의 파일은 다음과 같이 포장되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}백업이 완료되었습니다.${BACKUP_DIR}${NC}" - echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 절감 + # 还原 # ---------------------------- restore_docker() { - list_backups - read -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } - echo -e "${BLUE}복원 작업 시작 ...${NC}" + send_stats "Docker还原" + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" install tar jq gzip install_docker - # ----------------------------- + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path - # Compose 프로젝트 용 컨테이너가 이미 실행 중인지 확인하십시오. + # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" continue fi - read -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "새로운 복원 경로를 입력하십시오 :" original_path + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}작곡 프로젝트 [$project_name] 압축 압축 : :$original_path${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원이 완료되었습니다!${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" fi done - # ----------------------------- - echo -e "${BLUE}일반적인 도커 컨테이너를 확인하고 복원하십시오 ...${NC}" + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 컨테이너 :$container${NC}" + echo -e "${GREEN}处理容器: $container${NC}" - # 컨테이너가 이미 존재하고 실행 중인지 확인하십시오 + # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container]는 실행 중입니다. 회복을 건너 뛰십시오 ...${NC}" + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}거울 정보는 찾을 수 없었습니다.$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } - # 포트 매핑 + # 端口映射 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 환경 변수 + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 볼륨 매핑 + 볼륨 데이터 복구 + # 卷映射 + 卷数据恢复 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7067,32 +7070,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "볼륨 데이터 복구 :$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 기존이지만 실행되지 않은 컨테이너를 삭제하십시오 + # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container] 존재하지만 실행되지 않고 오래된 컨테이너를 삭제합니다 ...${NC}" + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" docker rm -f "$container" fi - # 컨테이너를 시작하십시오 - echo "복원 명령 실행 : docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" - # /home /docker에서 파일을 복원하십시오 + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home /docker에서 파일을 복원 ...${NC}" + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home /docker의 파일이 복원되었습니다${NC}" + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else - echo -e "${YELLOW}/home /docker 아래 파일의 백업이 발견되지 않았습니다.${NC}" + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" fi @@ -7100,66 +7103,68 @@ docker_ssh_migration() { # ---------------------------- - # 마이그레이션 + # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups - read -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + send_stats "Docker迁移" + install jq + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "대상 서버 IP :" TARGET_IP - read -p "대상 서버 SSH 사용자 이름 :" TARGET_USER + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}백업 전송 ...${NC}" + echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인하십시오 + # 使用密钥登录 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 백업을 삭제하십시오 + # 删除备份 # ---------------------------- delete_backup() { - list_backups - read -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + send_stats "Docker备份文件删除" + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" } # ---------------------------- - # 메인 메뉴 + # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" - echo -e "도커 백업/마이그레이션/복원 도구" + echo -e "Docker备份/迁移/还原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. Docker 프로젝트를 백업하십시오" - echo -e "2. Docker 프로젝트를 마이그레이션합니다" - echo -e "3. Docker 프로젝트를 복원하십시오" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" + echo -e "1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. 이전 메뉴로 돌아갑니다" + echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "선택하십시오 :" choice + read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}잘못된 옵션${NC}" ;; + *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } @@ -7174,38 +7179,38 @@ linux_docker() { while true; do clear - # Send_stats "Docker Management" - echo -e "도커 관리" + # send_stats "docker管理" + echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경을 설치하고 업데이트하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Docker Global Status를 봅니다${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" - echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" - echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너 및 미러 네트워크 데이터 볼륨을 청소하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" - echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}백업/마이그레이션/복원 Docker 환경" - echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "Docker 환경을 설치하십시오" + send_stats "安装docker环境" install_add_docker ;; @@ -7216,22 +7221,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "도커 글로벌 상태" - echo "도커 버전" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "도커 이미지 :${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7246,8 +7251,8 @@ linux_docker() { 5) while true; do clear - send_stats "도커 네트워크 관리" - echo "도커 네트워크 목록" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -7271,36 +7276,36 @@ linux_docker() { done echo "" - echo "네트워크 작동" + echo "网络操作" echo "------------------------" - echo "1. 네트워크를 만듭니다" - echo "2. 인터넷에 가입하십시오" - echo "3. 네트워크를 종료하십시오" - echo "4. 네트워크를 삭제합니다" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "네트워크를 만듭니다" - read -e -p "새 네트워크 이름 설정 :" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "인터넷에 가입하십시오" - read -e -p "네트워크 이름에 가입 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "인터넷에 가입하십시오" - read -e -p "종료 네트워크 이름 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다 (여러 컨테이너 이름은 공간별로 분리됩니다)." dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7309,8 +7314,8 @@ linux_docker() { ;; 4) - send_stats "네트워크를 삭제하십시오" - read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7324,29 +7329,29 @@ linux_docker() { 6) while true; do clear - send_stats "도커 볼륨 관리" - echo "도커 볼륨 목록" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "볼륨 작동" + echo "卷操作" echo "------------------------" - echo "1. 새 볼륨을 만듭니다" - echo "2. 지정된 볼륨을 삭제합니다" - echo "3. 모든 볼륨을 삭제하십시오" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "새 볼륨을 만듭니다" - read -e -p "새 볼륨 이름 설정 :" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "볼륨 삭제 이름을 입력하십시오 (공백으로 여러 볼륨 이름을 분리하십시오)." dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7355,7 +7360,7 @@ linux_docker() { ;; 3) - send_stats "모든 볼륨을 삭제하십시오" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7364,7 +7369,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7377,7 +7382,7 @@ linux_docker() { ;; 7) clear - send_stats "도커 청소" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7386,13 +7391,13 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "도커 소스" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7408,13 +7413,13 @@ linux_docker() { 11) clear - send_stats "Docker V6 열기" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker V6 레벨" + send_stats "Docker v6 关" docker_ipv6_off ;; @@ -7425,7 +7430,7 @@ linux_docker() { 20) clear - send_stats "Docker는 제거합니다" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7437,7 +7442,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7446,7 +7451,7 @@ linux_docker() { kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7463,151 +7468,151 @@ linux_test() { while true; do clear - # Send_stats "테스트 스크립트 컬렉션" - echo -e "스크립트 수집 테스트" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGpt는 상태 감지를 잠금 해제합니다" - echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" - echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}네트워크 속도 측정" - echo -e "${gl_kjlan}11. ${gl_bai}Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC 다기능 속도 테스트 스크립트" - echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}하드웨어 성능 테스트" - echo -e "${gl_kjlan}21. ${gl_bai}YABS 성능 테스트" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}포괄적 인 테스트" - echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "ChatGpt는 상태 감지를 잠금 해제합니다" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "지역 스트리밍 미디어 잠금 해제 테스트" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "YEAHWU 스트리밍 미디어 잠금 해제 탐지" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_ip 품질 신체 검사 스크립트" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "MTR_TRACE 3 개의 네트워크 리턴 라인 테스트" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed 3 Net 속도 측정" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace 빠른 백홀 테스트 스크립트" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo "참조 할 수있는 IP 목록" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "베이징 통신 : 219.141.136.12" - echo "베이징 유니폼 : 202.106.50.1" - echo "베이징 모바일 : 221.179.155.161" - echo "상하이 통신 : 202.96.209.133" - echo "상하이 유니폼 : 210.22.97.1" - echo "상하이 모바일 : 211.136.112.200" - echo "광저우 통신 : 58.60.188.222" - echo "광저우 유니폼 : 210.21.196.6" - echo "광저우 모바일 : 120.196.165.24" - echo "청두 통신 : 61.139.2.69" - echo "청두 유니폼 : 119.6.6.6" - echo "청두 모바일 : 211.137.96.205" - echo "Hunan Telecom : 36.111.200.100" - echo "후난 유니폼 : 42.48.16.100" - echo "후난 모바일 : 39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "지정된 IP를 입력하십시오." testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3 네트워크 라인 테스트" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC 다기능 속도 테스트 스크립트" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "네트워크 품질 테스트 스크립트" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABS 성능 테스트" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPU 성능 테스트 스크립트" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "벤치 성능 테스트" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX 퓨전 몬스터 검토" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7617,7 +7622,7 @@ linux_test() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7633,51 +7638,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud 스크립트 컬렉션" - echo -e "Oracle Cloud 스크립트 컬렉션" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}유휴 기계 활성 스크립트를 설치하십시오" - echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" - echo -e "${gl_kjlan}4. ${gl_bai}형사 R 스크립트 시작" - echo -e "${gl_kjlan}5. ${gl_bai}루트 비밀번호 로그인 모드를 켭니다" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6 복구 도구" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "활성 스크립트 : CPU는 10-20% 메모리를 점유합니다." - read -e -p "설치 하시겠습니까? (Y/N) :" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # 기본값을 설정합니다 + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율 백분율을 입력하라는 메시지를 표시하고 입력 한 경우 기본값을 사용하십시오. - read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용 백분율 범위 (예 : 10-20) [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "스피드 테스트 간격 시간 (초)을 입력하십시오 [기본값 :$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 도커 컨테이너를 실행하십시오 + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7685,14 +7690,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloud 설치 활성 스크립트" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7700,20 +7705,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "시스템을 다시 설치하십시오" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - read -e -p "계속할거야? (Y/N) :" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "다시 설치할 시스템을 선택하십시오 : 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7725,28 +7730,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "다시 설치 한 비밀번호를 입력하십시오." vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud 회복 시스템 스크립트" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "이 기능은 개발 단계에 있으므로 계속 지켜봐 주시기 바랍니다!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7756,15 +7761,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -7785,7 +7790,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7806,7 +7811,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7834,31 +7839,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp 웹 사이트 빌딩" - echo -e "${gl_huang}LDNMP 웹 사이트 구축" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPress를 설치하십시오${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" - echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginx 만 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" - echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" - echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" - echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" - echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7872,10 +7877,10 @@ linux_ldnmp() { 3) clear - # Discuz 포럼 + # Discuz论坛 webname="Discuz论坛" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,21 +7903,21 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao 클라우드 데스크탑 + # 可道云桌面 webname="可道云桌面" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7934,20 +7939,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" - echo "Redis 호스트 : Redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # Apple CMS + # 苹果CMS webname="苹果CMS" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,24 +7978,24 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사 : MAC_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "설치가 성공한 후 배경 주소에 로그인하십시오." + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 한 다리 카운팅 카드 + # 独脚数卡 webname="独脚数卡" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,34 +8016,34 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "Redis 주소 : Redis" - echo "Redis Password : 기본적으로 채워지지 않습니다" - echo "Redis Port : 6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "웹 사이트 URL : https : //$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "사용자 이름 : 관리자" - echo "비밀번호 : 관리자" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "로그인 할 때 오른쪽 상단에 빨간색 Error0이 나타나면 다음 명령을 사용하십시오." - echo "나는 또한 유니콘 번호 카드가 너무 귀찮다는 것에 대해 매우 화가 났으며 그러한 문제가있을 것입니다!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # Flarum 포럼 + # flarum论坛 webname="flarum论坛" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8075,12 +8080,12 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : flarum_" - echo "관리자 정보는 직접 설정됩니다" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -8088,8 +8093,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8113,11 +8118,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 접두사 : typecho_" - echo "데이터베이스 주소 : MySQL" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -8126,8 +8131,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8152,18 +8157,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8180,10 +8185,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8193,20 +8198,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php가있는 경로" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 Index.php의 경로를 입력하십시오.$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택하십시오" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1. PHP의 최신 버전 | 2. PHP7.4 :" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8217,15 +8222,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장자를 설치하십시오" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "설치된 확장" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8235,25 +8240,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "계속하려면 모든 키를 누르면 의사 정적 내용 등과 같은 사이트 구성을 자세히 설정할 수 있습니다." + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 작성하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8263,10 +8268,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "데이터베이스 가져 오기 테이블 데이터" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "데이터베이스 가져 오기가 완료되었습니다" + echo "数据库导入完成" ;; *) echo @@ -8278,12 +8283,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 :$prefix" - echo "관리자 로그인 정보는 직접 설정됩니다" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -8296,10 +8301,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -8321,7 +8326,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8332,11 +8337,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "도메인 이름 형식 :${gl_huang}google.com${gl_bai}" - read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8356,8 +8361,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8379,8 +8384,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8397,8 +8402,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8431,8 +8436,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8449,10 +8454,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,12 +8467,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 index.html로가는 경로를 입력하십시오.$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8492,21 +8497,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP 환경 백업" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "백업 파일이 작성되었습니다 : /home /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8514,9 +8519,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." + echo "文件已传送至远程服务器home目录。" else - echo "전송할 파일은 찾을 수 없었습니다." + echo "未找到要传送的文件。" fi break ;; @@ -8524,7 +8529,7 @@ linux_ldnmp() { break ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8532,9 +8537,9 @@ linux_ldnmp() { 33) clear - send_stats "시간이 지정된 원격 백업" - read -e -p "원격 서버 IP를 입력하십시오." useip - read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8544,18 +8549,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 주간 백업 2. 매일 백업" - read -e -p "선택을 입력하십시오 :" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "주간 백업의 요일을 선택하십시오 (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "매일 백업 시간을 선택하십시오 (시간, 0-23) :" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8569,19 +8574,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP 환경 복원" - echo "사용 가능한 사이트 백업" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8591,7 +8596,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8600,7 +8605,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "압축 패키지가 발견되지 않았습니다." + echo "没有找到压缩包。" fi ;; @@ -8618,11 +8623,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP 환경을 업데이트하십시오" - echo "LDNMP 환경을 업데이트하십시오" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "구성 요소의 새 버전을 발견하십시오" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8642,13 +8647,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. 전체 환경을 업데이트하십시오" + echo "5. 更新完整环境" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8657,7 +8662,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 8.0 8.3 8.4 9.0) (최신 버전을 얻으려면 입력) :" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8668,13 +8673,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 7.4 8.0 8.1 8.2 8.3) (최신 버전을 얻으려면 입력) :" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8707,8 +8712,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -8719,15 +8724,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP 환경을 완전히 업데이트하십시오" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8753,7 +8758,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP 환경을 제거하십시오" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8767,7 +8772,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8777,7 +8782,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 입력!" + echo "无效的输入!" esac break_end @@ -8797,12 +8802,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "응용 프로그램 시장" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 루프로 색상을 설정하십시오 + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8811,67 +8816,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" - echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" - echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" - echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" - echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" - echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" - echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" - echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" - echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" - echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" - echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" - echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" - echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" - echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" - echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" - echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" - echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" - echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" - echo -e "${gl_kjlan}89. ${color89}filecodebox 파일 Express${gl_kjlan}90. ${color90}매트릭스 분산 채팅 프로토콜" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8990,6 +8998,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -9021,8 +9032,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9055,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "Nezha를 구축하십시오" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -9064,20 +9075,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha 모니터링$check_docker $update_status" - echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" - echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 사용" + echo "1. 使用" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9134,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "우체국을 건설하십시오" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -9144,43 +9155,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우체국 서비스$check_docker $update_status" - echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "포트 감지" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "액세스 주소 :" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "이 DNS 레코드를 먼저 구문 분석하십시오" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9190,7 +9201,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "계속하려면 키를 누르십시오 ..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -9209,9 +9220,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -9234,9 +9245,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -9247,7 +9258,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "应用已卸载" ;; *) @@ -9281,7 +9292,7 @@ while true; do clear ip_address - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -9291,7 +9302,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chat이 설치되었습니다" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -9301,7 +9312,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -9385,7 +9396,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -9399,7 +9410,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -9544,7 +9555,7 @@ while true; do ;; 19|safeline) - send_stats "천둥 수영장을 건설하십시오" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -9552,20 +9563,20 @@ while true; do while true; do check_docker_app clear - echo -e "썬더 풀 서비스$check_docker" - echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9575,7 +9586,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Thunder Pool WAF 패널이 설치되었습니다" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9588,7 +9599,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "Thunder Pool WAF 패널이 업데이트되었습니다" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9599,7 +9610,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9718,8 +9729,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10007,7 +10018,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10060,7 +10071,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya 가족 버킷" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -10264,9 +10275,9 @@ while true; do prometheus_install clear ip_address - echo "설치" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -10284,7 +10295,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10371,7 +10382,7 @@ while true; do 51|pve) clear - send_stats "PVE 치킨" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10491,7 +10502,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10506,7 +10517,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10534,7 +10545,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10549,7 +10560,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10557,7 +10568,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10578,17 +10589,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "설치" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름 : 관리자" - echo "초기 비밀번호 : changeme" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "앱이 업데이트되었습니다" + echo "应用已更新" } @@ -10598,7 +10609,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10645,7 +10656,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10661,7 +10672,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -10923,7 +10934,7 @@ while true; do docker_rum() { - read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10957,9 +10968,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password - read -e -p "인증 코드를 입력하십시오." shouquanma + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma mkdir -p /home/docker/moontv @@ -10969,13 +10980,13 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -10989,7 +11000,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11062,8 +11073,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" app_use - read -e -p "로그인 비밀번호 설정 :" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -11160,11 +11171,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 암호를 생성합니다 + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11173,17 +11184,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 관리자 계정 정보를 추가하십시오 + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 컨테이너를 시작하십시오 + # 启动容器 docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -11193,7 +11204,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 원래 변수를 유지하십시오 + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11210,7 +11221,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11260,7 +11271,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11278,7 +11289,7 @@ while true; do docker_rum() { - read -e -p "설정${docker_name}SK-159KEJILIONYYDS163 :와 같은 로그인 키 (SK 별 문자 및 숫자 조합) :" app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11382,7 +11393,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -11395,7 +11406,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11556,7 +11567,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11608,7 +11619,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "설치" + echo "已经安装完成" check_docker_app_ip } @@ -11622,7 +11633,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "앱이 제거되었습니다" + echo "应用已卸载" } docker_app_plus @@ -11661,24 +11672,282 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + stop_containers_or_kill_process 51820 &>/dev/null + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=51820 \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 2 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 2 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear - send_stats "모든 응용 프로그램 백업" + send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "백업 파일이 작성되었습니다 : /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11686,14 +11955,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." + echo "文件已传送至远程服务器/根目录。" else - echo "전송할 파일은 찾을 수 없었습니다." + echo "未找到要传送的文件。" fi break ;; *) - echo "참고 : 현재 백업에는 Docker 프로젝트 만 포함되어 있으며 Pagoda 및 1Panel과 같은 웹 사이트 구축 패널의 데이터 백업은 포함되지 않습니다." + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" break ;; esac @@ -11703,29 +11972,29 @@ while true; do r) root_use - send_stats "모든 응용 프로그램이 복원됩니다" - echo "사용 가능한 앱 백업" + send_stats "全部应用还原" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else - echo "압축 패키지가 발견되지 않았습니다." + echo "没有找到压缩包。" fi ;; @@ -11748,35 +12017,35 @@ linux_work() { while true; do clear - send_stats "백엔드 작업 공간" - echo -e "백엔드 작업 공간" - echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." - echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." - echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "현재 기존 작업 공간 목록" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" - echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" - echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" - echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" - echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" - echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" - echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11784,7 +12053,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11792,63 +12061,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11860,21 +12129,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH 거주 모드" - echo -e "SSH 거주 모드${tmux_sshd_status}" - echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. 2를 켜십시오. 2를 끕니다" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11890,29 +12159,29 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "사용자 정의 작업 공간" + send_stats "自定义工作区" ;; 23) - read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "배경 작업 공간에 명령을 주입합니다" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "작업 공간을 삭제합니다" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -11937,54 +12206,54 @@ linux_Settings() { while true; do clear - # Send_stats "시스템 도구" - echo -e "시스템 도구" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" - echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" - echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" - echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" - echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" - echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" - echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" - echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" - send_stats "스크립트 바로 가기 키가 설정되었습니다" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11992,34 +12261,34 @@ linux_Settings() { 2) clear - send_stats "로그인 비밀번호를 설정하십시오" - echo "로그인 비밀번호를 설정하십시오" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "루트 비밀번호 모드" + send_stats "root密码模式" add_sshpasswd ;; 4) root_use - send_stats "PY 버전 관리" - echo "파이썬 버전 관리" - echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" - echo "더 많은 버전 : https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "스크립트 PY 관리" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -12052,7 +12321,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "알 수없는 패키지 관리자!" + echo "未知的包管理器!" return fi @@ -12081,55 +12350,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 Py 버전을 스위치하십시오" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "포트 열기" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "모든 포트가 열려 있습니다" + echo "端口已全部开放" ;; 6) root_use - send_stats "SSH 포트를 수정하십시오" + send_stats "修改SSH端口" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 현재 SSH 포트 번호를 읽으십시오 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 현재 SSH 포트 번호를 인쇄하십시오 - echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 - read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # 포트 번호가 유효한 범위 내에 있는지 확인 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH 포트가 수정되었습니다" + send_stats "SSH端口已修改" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH 포트 수정을 종료하십시오" + send_stats "退出SSH端口修改" break else - echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "입력이 유효하지 않으므로 번호를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -12148,8 +12417,8 @@ EOF ;; 9) root_use - send_stats "신규 사용자는 루트를 비활성화합니다" - read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12164,49 +12433,49 @@ EOF passwd -l root - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 10) root_use - send_stats "V4/V6 우선 순위를 설정하십시오" + send_stats "设置v4/v6优先级" while true; do clear - echo "V4/V6 우선 순위를 설정하십시오" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선호하는 네트워크를 선택하십시오." choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "IPv4 우선 순위로 전환되었습니다" - send_stats "IPv4 우선 순위로 전환되었습니다" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "IPv6 우선 순위로 전환되었습니다" - send_stats "IPv6 우선 순위로 전환되었습니다" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -12224,43 +12493,43 @@ EOF 12) root_use - send_stats "가상 메모리를 설정합니다" + send_stats "设置虚拟内存" while true; do clear - echo "가상 메모리를 설정합니다" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G 가상 메모리가 설정되었습니다" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G 가상 메모리가 설정되었습니다" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "사용자 정의 가상 메모리가 설정되었습니다" + send_stats "已设置自定义虚拟内存" ;; *) @@ -12273,8 +12542,8 @@ EOF 13) while true; do root_use - send_stats "사용자 관리" - echo "사용자 목록" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12285,62 +12554,62 @@ EOF echo "" - echo "계정 운영" + echo "账户操作" echo "------------------------" - echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. 계정을 삭제하십시오" + echo "5. 删除账号" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 2) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 새로운 사용자에게 허가를 부여하십시오 + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "작업이 완료되었습니다." + echo "操作已完成。" ;; 3) - read -e -p "사용자 이름을 입력하십시오 :" username - # 새로운 사용자에게 허가를 부여하십시오 + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "사용자 이름을 입력하십시오 :" username - # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자와 홈 디렉토리를 삭제하십시오 + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -12353,50 +12622,50 @@ EOF 14) clear - send_stats "사용자 정보 생성기" - echo "임의의 사용자 이름" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "임의의 사용자 이름$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "임의 이름" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5 개의 임의의 사용자 이름을 생성합니다 + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "임의의 사용자 이름$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "무작위 uuid" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "무작위 uuid$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16 비트 랜덤 비밀번호" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32 비트 랜덤 비밀번호" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "랜덤 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -12404,46 +12673,46 @@ EOF 15) root_use - send_stats "시간대를 변경하십시오" + send_stats "换时区" while true; do clear - echo "시스템 시간 정보" + echo "系统时间信息" - # 현재 시스템 시간대를 얻으십시오 + # 获取当前系统时区 local timezone=$(current_timezone) - # 현재 시스템 시간을 얻으십시오 + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 시간대와 시간을 보여줍니다 - echo "현재 시스템 시간대 :$timezone" - echo "현재 시스템 시간 :$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "시간대 스위칭" + echo "时区切换" echo "------------------------" - echo "아시아" - echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" - echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" - echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" - echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" - echo "9. 태국 방콕에서의 시간" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "유럽" - echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" - echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" - echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "미국" - echo "21. 서양 시간 22. 동부 시간" - echo "23. 캐나다 시간 24. 멕시코 시간" - echo "25. 브라질 시간 26. 아르헨티나 시간" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC 글로벌 표준 시간" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -12486,21 +12755,21 @@ EOF 18) root_use - send_stats "호스트 이름을 수정하십시오" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, Centos 등과 같은 다른 시스템 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12518,11 +12787,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" - send_stats "호스트 이름이 변경되었습니다" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "종료, 호스트 이름이 변경되지 않았습니다." + echo "已退出,未更改主机名。" break fi done @@ -12530,32 +12799,32 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스를 변경하십시오" + send_stats "换系统更新源" clear - echo "업데이트 소스 영역을 선택하십시오" - echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "중국 본토의 기본 소스" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "중국 본토의 교육 원" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "해외 출신" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "취소" + echo "已取消" ;; esac @@ -12563,62 +12832,62 @@ EOF ;; 20) - send_stats "타이밍 작업 관리" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "시간이 정한 작업 목록" + echo "定时任务列表" crontab -l echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. 월간 작업 2. 주간 작업" - echo "3. 일일 작업 4. 시간당 작업" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "선택을 입력하십시오 :" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "시간이 정한 작업을 추가하십시오" + send_stats "添加定时任务" ;; 2) - read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "타이밍 작업을 삭제하십시오" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "타이밍 작업 편집" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12630,32 +12899,32 @@ EOF 21) root_use - send_stats "지역 호스트 구문 분석" + send_stats "本地host解析" while true; do clear - echo "기본 호스트 구문 분석 목록" - echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "로컬 호스트 구문 분석이 추가되었습니다" + send_stats "本地host解析新增" ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "로컬 호스트 구문 분석 및 삭제" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12666,7 +12935,7 @@ EOF 22) root_use - send_stats "SSH 방어" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12678,20 +12947,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH 방어 프로그램$check_docker" - echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" - echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 安装防御程序" echo "------------------------" - echo "2. SSH 차단 레코드보기" - echo "3. 실시간 로그 모니터링" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12714,7 +12983,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12727,47 +12996,47 @@ EOF 23) root_use - send_stats "현재 제한 종료 기능" + send_stats "限流关机功能" while true; do clear - echo "현재 제한 종료 기능" - echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # limiting_shut_down.sh 파일이 있는지 확인하십시오 + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gb의 값을 얻으십시오 + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 새 가상 메모리 크기를 입력하십시오 - echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." - read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12780,15 +13049,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "전류 제한 종료가 설정되었습니다" - send_stats "전류 제한 종료가 설정되었습니다" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 종료 기능이 꺼졌습니다" + echo "已关闭限流关机功能" ;; *) break @@ -12801,40 +13070,40 @@ EOF 24) root_use - send_stats "개인 키 로그인" + send_stats "私钥登录" while true; do clear - echo "루트 비공개 키 로그인 모드" - echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "새로운 키를 생성하십시오" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "기존 공개 키를 가져옵니다" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "로컬 비밀 키를보십시오" + send_stats "查看本机密钥" echo "------------------------" - echo "공개 키 정보" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "개인 키 정보" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12850,18 +13119,18 @@ EOF 25) root_use - send_stats "전보 경고" - echo "TG-BOT 모니터링 및 조기 경고 기능" - echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." - echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." - echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속할거야? (Y/N) :" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "전보 경고가 활성화되었습니다" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12883,7 +13152,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # ~/.profile 파일에 추가하십시오 + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -12894,21 +13163,21 @@ EOF source ~/.profile clear - echo "TG-BOT 조기 경고 시스템이 시작되었습니다" - echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "SSH에서 고위험 취약점을 수정하십시오" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12952,7 +13221,7 @@ EOF ;; 37) clear - send_stats "명령 줄 기록" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12975,61 +13244,61 @@ EOF 41) clear - send_stats "게시판" - echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" + send_stats "留言板" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "원 스톱 튜닝" - echo "원 스톱 시스템 최적화" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "다음은 작동하고 최적화됩니다" - echo "1. 시스템을 최신으로 업데이트하십시오" - echo "2. 시스템 정크 파일 정리" - echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" - echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니 다" - echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" - echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" - echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" - echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "원 스톱 튜닝 시작" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13046,25 +13315,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" - echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -13072,7 +13341,7 @@ EOF 99) clear - send_stats "시스템을 다시 시작하십시오" + send_stats "重启系统" server_reboot ;; 100) @@ -13088,32 +13357,32 @@ EOF local status_message="无法确定的状态" fi - echo "개인 정보 및 보안" - echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." - echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "현재 상태 :$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. 수집을 켭니다" - echo "2. 컬렉션을 닫습니다" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 활성화되었습니다" - send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "컬렉션이 닫혔습니다" - send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -13129,11 +13398,11 @@ EOF 102) clear - send_stats "기술 라이온 스크립트를 제거하십시오" - echo "기술 라이온 스크립트를 제거하십시오" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." - read -e -p "계속할거야? (Y/N) :" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -13141,16 +13410,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "대본은 제거되었습니다." + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -13160,7 +13429,7 @@ EOF ;; *) - echo "잘못된 입력!" + echo "无效的输入!" ;; esac break_end @@ -13178,187 +13447,187 @@ EOF linux_file() { root_use - send_stats "파일 관리자" + send_stats "文件管理器" while true; do clear - echo "파일 관리자" + echo "文件管理器" echo "------------------------" - echo "현재 경로" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" - echo "15. 파일을 삭제하십시오" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" - echo "25. 파일을 다른 서버로 전달합니다" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" - send_stats "디렉토리로 이동하십시오" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname - mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" - send_stats "디렉토리를 만듭니다" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "디렉토리 권한을 수정하십시오" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name - read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "디렉토리의 이름을 바꿉니다" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname - rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "디렉토리 삭제" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "이전 메뉴 디렉토리로 돌아갑니다" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "작성하려면 파일 이름을 입력하십시오." filename - touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" - send_stats "파일을 만듭니다" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "편집 할 파일 이름을 입력하십시오." filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "파일 편집" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "파일 이름을 입력하십시오 :" filename - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" - send_stats "파일 권한을 수정하십시오" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "현재 파일 이름을 입력하십시오 :" current_name - read -e -p "새 파일 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" - send_stats "파일의 이름을 바꿉니다" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" - send_stats "파일 삭제" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" - send_stats "압축 파일/디렉토리" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" - send_stats "압축 파일/디렉토리 해제" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" - send_stats "파일 또는 디렉토리를 이동하십시오" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 - cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사합니다" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "오류 : 파일이 존재하지 않습니다." - send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "오류 : 원격 서버 비밀번호를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 알려진 호스트를위한 오래된 항목을 명확하게합니다 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCP를 사용하여 파일을 전송합니다 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트는 최신입니다$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13656,15 +13925,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" - send_stats "자동 스크립트 업데이트를 켜십시오" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" - send_stats "스크립트 자동 업데이트를 닫습니다" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13686,41 +13955,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" -echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" -echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" -echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" -echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" -echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" -echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" -echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" -echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" -echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" -echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" -echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" -echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" -echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" -echo -e "${gl_kjlan}15. ${gl_bai}광고 열" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" +echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "선택을 입력하십시오 :" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; - 3) clear ; send_stats "시스템 정리" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "워프 관리" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -13731,13 +14000,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "잘못된 입력!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13745,68 +14014,68 @@ done k_info() { -send_stats "K 명령 참조 사용 사례" +send_stats "k命令参考用例" echo "-------------------" -echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "다음은 K 명령 참조 유스 케이스입니다." -echo "스크립트 시작 k" -echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" -echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" -echo "업데이트 시스템 K 업데이트 | K 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | K 청소" -echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" -echo "BBR3 제어판 K BBR3 | K bbrv3" -echo "커널 튜닝 패널 K nhyh | K 커널 최적화" -echo "가상 메모리 K 스왑 2048을 설정하십시오" -echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" -echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" -echo "시스템 백업 기능 K 백업 | K bf | K 백업" -echo "SSH 원격 연결 도구 K SSH | K 원격 연결" -echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" -echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" -echo "인트라넷 침투 (서버 측) K frps" -echo "인트라넷 침투 (클라이언트) K frpc" -echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" -echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" -echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" -echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" -echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" -echo "도메인 이름 인증서 응용 프로그램 K SSL" -echo "도메인 이름 인증서 만료 쿼리 K SSL PS" -echo "도커 환경 설치 K 도커 설치 | K 도커 설치" -echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" -echo "Docker Image Management K Docker img | K Docker Image" -echo "LDNMP 사이트 관리 K 웹" -echo "LDNMP 캐시 정리 K 웹 캐시" -echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" -echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." -echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" -echo "방화벽 패널 K FHQ | K 방화벽" -echo "포트 k dkdk 8080 | k 오픈 포트 8080" -echo "포트 K GBDK 7800 | K 닫기 포트 7800" -echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" -echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" -echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" -echo "앱 시장 관리 K 앱" -echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # 매개 변수가없는 경우 대화식 로직을 실행하십시오 + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # 매개 변수가있는 경우 해당 함수를 실행하십시오 + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "소프트웨어를 설치하십시오" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "소프트웨어를 제거하십시오" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13840,7 +14109,7 @@ else rsync_run) shift - send_stats "시간이 정한 RSYNC 동기화" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13859,7 +14128,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13872,13 +14141,13 @@ else swap) shift - send_stats "가상 메모리를 신속하게 설정했습니다" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "시간대를 빠르게 설정하십시오" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13926,42 +14195,42 @@ else status|状态) shift - send_stats "소프트웨어 상태보기" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "소프트웨어 시작" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "소프트웨어 일시 정지" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 재시작" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "소프트웨어 부츠" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "인증서 상태를 확인하십시오" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "인증서를 신속하게 신청하십시오" + send_stats "快速申请证书" else k_info fi @@ -13971,15 +14240,15 @@ else shift case $1 in install|安装) - send_stats "Docker를 신속하게 설치하십시오" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "빠른 컨테이너 관리" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "빠른 미러 관리" + send_stats "快捷镜像管理" docker_image ;; *) @@ -14006,7 +14275,7 @@ else app) shift - send_stats "$@ 적용" + send_stats "应用$@" linux_panel "$@" ;; @@ -14016,4 +14285,3 @@ else ;; esac fi - diff --git a/tw/kejilion.sh b/tw/kejilion.sh index ece6e3e4e..cab3eb64a 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.0" +sh_v="4.1.2" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# 定義一個函數來執行命令 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋點信息的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! -# 為什麼要設計這個功能,目的更好的了解用戶喜歡使用的功能,進一步優化功能推出更多符合用戶需求的功能。 -# 全文可搜搜 send_stats 函數調用位置,透明開源,如有顧慮可拒絕使用。 +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用戶同意條款 +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" - echo "首次使用腳本,請先閱讀並同意用戶許可協議。" - echo "用戶許可協議: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上條款? (y/n):" user_input + read -r -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "許可同意" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "許可拒絕" + send_stats "许可拒绝" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供軟件包參數!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安裝$package...${gl_bai}" + echo -e "${gl_huang}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示:${gl_bai}磁盤空間不足!" - echo "當前可用空間: $((available_space_mb/1024))G" - echo "最小需求空間:${required_gb}G" - echo "無法繼續安裝,請清理磁盤空間後重試。" - send_stats "磁盤空間不足" + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供軟件包參數!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸載$package...${gl_bai}" + echo -e "${gl_huang}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -266,7 +266,7 @@ remove() { } -# 通用 systemctl 函數,適用於各種發行版 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重啟服務 +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1服務已重啟。" + echo "$1 服务已重启。" else - echo "錯誤:重啟$1服務失敗。" + echo "错误:重启 $1 服务失败。" fi } -# 啟動服務 +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1服務已啟動。" + echo "$1 服务已启动。" else - echo "錯誤:啟動$1服務失敗。" + echo "错误:启动 $1 服务失败。" fi } -# 停止服務 +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1服務已停止。" + echo "$1 服务已停止。" else - echo "錯誤:停止$1服務失敗。" + echo "错误:停止 $1 服务失败。" fi } -# 查看服務狀態 +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1服務狀態已顯示。" + echo "$1 服务状态已显示。" else - echo "錯誤:無法顯示$1服務狀態。" + echo "错误:无法显示 $1 服务状态。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME已設置為開機自啟。" + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意鍵繼續..." + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -349,22 +349,21 @@ kejilion() { -check_port() { +stop_containers_or_kill_process() { + local port=$1 + local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) install lsof + if [ -n "$containers" ]; then + docker stop $containers + else + for pid in $(lsof -t -i:$port); do + kill -9 $pid + done + fi +} - stop_containers_or_kill_process() { - local port=$1 - local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - - if [ -n "$containers" ]; then - docker stop $containers - else - for pid in $(lsof -t -i:$port); do - kill -9 $pid - done - fi - } +check_port() { stop_containers_or_kill_process 80 stop_containers_or_kill_process 443 } @@ -425,7 +424,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安裝docker環境...${gl_bai}" + echo -e "${gl_huang}正在安装docker环境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -506,49 +505,49 @@ while true; do echo "" echo "容器操作" echo "------------------------" - echo "1. 創建新的容器" + echo "1. 创建新的容器" echo "------------------------" - echo "2. 啟動指定容器 6. 啟動所有容器" + echo "2. 启动指定容器 6. 启动所有容器" echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 刪除指定容器 8. 刪除所有容器" - echo "5. 重啟指定容器 9. 重啟所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11. 進入指定容器 12. 查看容器日誌" - echo "13. 查看容器網絡 14. 查看容器佔用" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15. 開啟容器端口訪問 16. 關閉容器端口訪問" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "新建容器" - read -e -p "請輸入創建命令:" dockername + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "啟動指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) send_stats "停止指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "刪除指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "重啟指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "啟動所有容器" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) @@ -556,7 +555,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "刪除所有容器" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -565,28 +564,28 @@ while true; do [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "重啟所有容器" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "進入容器" - read -e -p "請輸入容器名:" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日誌" - read -e -p "請輸入容器名:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器網絡" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -604,14 +603,14 @@ while true; do break_end ;; 14) - send_stats "查看容器佔用" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "允許容器端口訪問" - read -e -p "請輸入容器名:" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -620,8 +619,8 @@ while true; do ;; 16) - send_stats "阻止容器端口訪問" - read -e -p "請輸入容器名:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -640,44 +639,44 @@ done docker_image() { while true; do clear - send_stats "Docker鏡像管理" - echo "Docker鏡像列表" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "鏡像操作" + echo "镜像操作" echo "------------------------" - echo "1. 獲取指定鏡像 3. 刪除指定鏡像" - echo "2. 更新指定鏡像 4. 刪除所有鏡像" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "拉取鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在獲取鏡像:$name${gl_bai}" + echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新鏡像:$name${gl_bai}" + echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "刪除鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "刪除所有鏡像" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -686,7 +685,7 @@ while true; do [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -754,16 +753,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的發行版:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "無法確定操作系統。" + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}crontab 已安裝且 cron 服務正在運行。${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -775,27 +774,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 檢查配置文件是否存在,如果不存在則創建文件並寫入默認設置 + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq處理配置文件的更新 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 檢查當前配置是否已經有 ipv6 設置 + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,開啟 IPv6 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 對比原始配置與新配置 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}當前已開啟ipv6訪問${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -810,28 +809,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 檢查配置文件是否存在 + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 讀取當前配置 + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq處理配置文件的更新 + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 檢查當前的 ipv6 狀態 + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 對比原始配置與新配置 + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}當前已關閉ipv6訪問${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功關閉ipv6訪問${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -870,88 +869,88 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "請提供至少一個端口號" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 刪除已存在的關閉規則 + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打開規則 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打開端口$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "已打開端口" + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "請提供至少一個端口號" + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 刪除已存在的打開規則 + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加關閉規則 + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已關閉端口$port" + echo "已关闭端口 $port" fi done - # 刪除已存在的規則(如果有) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新規則到第一條 + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已關閉端口" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "請提供至少一個IP地址或IP段" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 刪除已存在的阻止規則 + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允許規則 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP$ip" + echo "已放行IP $ip" fi done @@ -962,20 +961,20 @@ allow_ip() { block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "請提供至少一個IP地址或IP段" + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 刪除已存在的允許規則 + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止規則 + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP$ip" + echo "已阻止IP $ip" fi done @@ -990,7 +989,7 @@ block_ip() { enable_ddos_defense() { - # 開啟防禦 DDoS + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1000,12 +999,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "開啟DDoS防禦" + send_stats "开启DDoS防御" } -# 關閉DDoS防禦 +# 关闭DDoS防御 disable_ddos_defense() { - # 關閉防禦 DDoS + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1015,14 +1014,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "關閉DDoS防禦" + send_stats "关闭DDoS防御" } -# 管理國家IP規則的函數 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" local country_code="$2" @@ -1033,18 +1032,18 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在則創建 + # 如果 ipset 不存在则创建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下載 IP 區域文件 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 將 IP 添加到 ipset + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" @@ -1053,53 +1052,53 @@ manage_country_rules() { iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止$country_code的 IP 地址" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 為允許的國家創建 ipset(如果不存在) + # 为允许的国家创建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下載 IP 區域文件 + # 下载 IP 区域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" + echo "错误:下载 $country_code 的 IP 区域文件失败" exit 1 fi - # 刪除現有的國家規則 + # 删除现有的国家规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 將 IP 添加到 ipset + # 将 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 僅允許指定國家的 IP + # 仅允许指定国家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功僅允許$country_code的 IP 地址" + echo "已成功仅允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 刪除國家的 iptables 規則 + # 删除国家的 iptables 规则 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 銷毀 ipset + # 销毁 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除$country_code的 IP 地址限制" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) @@ -1116,42 +1115,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高級防火牆管理" - send_stats "高級防火牆管理" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火牆管理" + echo "防火墙管理" echo "------------------------" - echo "1. 開放指定端口 2. 關閉指定端口" - echo "3. 開放所有端口 4. 關閉所有端口" + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5. IP白名單 6. IP黑名單" + echo "5. IP白名单 6. IP黑名单" echo "7. 清除指定IP" echo "------------------------" - echo "11. 允許PING 12. 禁止PING" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" - echo "17. 解除指定國家IP限制" + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "請輸入開放的端口號:" o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "開放指定端口" + send_stats "开放指定端口" ;; 2) - read -e -p "請輸入關閉的端口號:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "關閉指定端口" + send_stats "关闭指定端口" ;; 3) - # 開放所有端口 + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1164,10 +1163,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "開放所有端口" + send_stats "开放所有端口" ;; 4) - # 關閉所有端口 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,33 +1179,33 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "關閉所有端口" + send_stats "关闭所有端口" ;; 5) - # IP 白名單 - read -e -p "請輸入放行的IP或IP段:" o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IP 黑名單 - read -e -p "請輸入封鎖的IP或IP段:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) # 清除指定 IP - read -e -p "請輸入清除的IP:" d_ip + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 send_stats "清除指定IP" ;; 11) - # 允許 PING + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允許PING" + send_stats "允许PING" ;; 12) # 禁用 PING @@ -1223,20 +1222,20 @@ iptables_panel() { ;; 15) - read -e -p "請輸入阻止的國家代碼(如 CN, US, JP):" country_code + read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code manage_country_rules block $country_code - send_stats "允許國家$country_code的IP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "請輸入允許的國家代碼(如 CN, US, JP):" country_code + read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code manage_country_rules allow $country_code - send_stats "阻止國家$country_code的IP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "請輸入清除的國家代碼(如 CN, US, JP):" country_code + read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code manage_country_rules unblock $country_code - send_stats "清除國家$country_code的IP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1257,23 +1256,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 獲取當前系統中所有的 swap 分區 + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍歷並刪除所有的 swap 分區 + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 確保 /swapfile 不再被使用 + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 刪除舊的 /swapfile + # 删除旧的 /swapfile rm -f /swapfile - # 創建新的 swap 分區 + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1288,7 +1287,7 @@ add_swap() { rc-update add local fi - echo -e "虛擬內存大小已調整為${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1298,7 +1297,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判斷是否需要創建虛擬內存 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1314,21 +1313,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 獲取nginx版本 + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 獲取mysql版本 + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 獲取php版本 + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 獲取redis版本 + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1341,7 +1340,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 創建必要的目錄和文件 + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1350,11 +1349,11 @@ install_ldnmp_conf() { default_server_ssl - # 下載 docker-compose.yml 文件並進行替換 + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中進行替換 + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1399,7 +1398,7 @@ install_ldnmp() { clear - echo "LDNMP環境安裝完畢" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1416,7 +1415,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "續簽任務已更新" + echo "续签任务已更新" } @@ -1453,15 +1452,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公鑰信息${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming私鑰信息${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}證書存放路徑${gl_bai}" - echo "公鑰: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私鑰: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1470,7 +1469,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1486,8 +1485,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點信息 證書到期時間" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1526,19 +1525,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名證書申請成功" + send_stats "域名证书申请成功" else - send_stats "域名證書申請失敗" - echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" - echo -e "1. 域名拼寫錯誤 ➠ 請檢查域名輸入是否正確" - echo -e "2. DNS解析問題 ➠ 確認域名已正確解析到本服務器IP" - echo -e "3. 網絡配置問題 ➠ 如使用Cloudflare Warp等虛擬網絡請暫時關閉" - echo -e "4. 防火牆限制 ➠ 檢查80/443端口是否開放,確保驗證可訪問" - echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" - echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" break_end clear - echo "請再次嘗試部署$webname" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status @@ -1549,7 +1548,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重複使用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1558,8 +1557,8 @@ fi add_yuming() { ip_address - echo -e "先將域名解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "請輸入你的IP或者解析過的域名:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1643,11 +1642,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登錄信息:" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "啟動$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1657,29 +1656,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 檢查配置文件是否存在 + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 從配置文件讀取 API_TOKEN 和 zone_id + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 將 ZONE_IDS 轉換為數組 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # 提示用戶是否清理緩存 - read -e -p "需要清理 Cloudflare 的緩存嗎? (y/n):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以後期修改CF信息" - read -e -p "請輸入你的 API_TOKEN:" API_TOKEN - read -e -p "請輸入你的CF用戶名:" EMAIL - read -e -p "請輸入 zone_id(多個用空格分隔):" -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循環遍歷每個 zone_id 並執行清除緩存命令 + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除緩存 for zone_id:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1687,13 +1686,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "緩存清除請求已發送完畢。" + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "清理站點緩存" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1703,28 +1702,28 @@ web_cache() { web_del() { - send_stats "刪除站點數據" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "刪除站點數據,請輸入你的域名(多個域名用空格隔開):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在刪除域名:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 將域名轉換為數據庫名 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 刪除數據庫前檢查是否存在,避免報錯 - echo "正在刪除數據庫:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1740,23 +1739,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根據 mode 參數來決定開啟或關閉 WAF + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # 開啟 WAF:去掉註釋 + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 關閉 WAF:加上註釋 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無效的參數:使用 'on' 或 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # 檢查 nginx 鏡像並根據情況處理 + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1803,11 +1802,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 刪除舊定義 + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定義,放在含 "Happy publishing" 的行前 + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1830,12 +1829,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 刪除舊定義 + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定義,放在含 "Happy publishing" 的行前 + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1858,7 +1857,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 開啟 Brotli:去掉註釋 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1872,7 +1871,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 關閉 Brotli:加上註釋 + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1888,11 +1887,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "無效的參數:使用 'on' 或 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # 檢查 nginx 鏡像並根據情況處理 + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1914,7 +1913,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 開啟 Zstd:去掉註釋 + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1929,7 +1928,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 關閉 Zstd:加上註釋 + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1945,11 +1944,11 @@ nginx_zstd() { else - echo "無效的參數:使用 'on' 或 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # 檢查 nginx 鏡像並根據情況處理 + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1976,7 +1975,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無效的參數:使用 'on' 或 'off'" + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -1990,7 +1989,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP環境防禦" + send_stats "LDNMP环境防御" while true; do check_waf_status check_cf_mode @@ -2004,25 +2003,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服務器網站防禦程序${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安裝防禦程序" + echo "1. 安装防御程序" echo "------------------------" - echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" - echo "7. 查看防禦規則列表 8. 查看日誌實時監控" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11. 配置攔截參數 12. 清除所有拉黑的IP" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. cloudflare模式 22. 高負載開啟5秒盾" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31. 開啟WAF 32. 關閉WAF" - echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9. 卸載防禦程序" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2082,7 +2081,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防禦程序已卸載" + echo "Fail2Ban防御程序已卸载" ;; 11) @@ -2098,10 +2097,10 @@ web_security() { 21) send_stats "cloudflare模式" - echo "到cf後台右上角我的個人資料,選擇左側API令牌,獲取Global API Key" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "輸入CF的賬號:" cfuser - read -e -p "輸入CF的Global API Key:" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,21 +2115,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "高負載開啟5秒盾" - echo -e "${gl_huang}網站每5分鐘自動檢測,當達檢測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "獲取CF參數:" - echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,獲取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "輸入CF的賬號:" cfuser - read -e -p "輸入CF的Global API Key:" cftoken - read -e -p "輸入CF中域名的區域ID:" cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2147,23 +2146,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負載自動開盾腳本已添加" + echo "高负载自动开盾脚本已添加" else - echo "自動開盾腳本已存在,無需添加" + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "站點WAF已開啟" - send_stats "站點WAF已開啟" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "站點WAF已關閉" - send_stats "站點WAF已關閉" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2189,10 +2188,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 獲取當前的 worker_processes 設置值 +# 获取当前的 worker_processes 设置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根據值設置模式信息 +# 根据值设置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2208,21 +2207,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 檢查 zstd 是否開啟且未被註釋(整行以 zstd on; 開頭) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 檢查 brotli 是否開啟且未被註釋 + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 檢查 gzip 是否開啟且未被註釋 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2238,33 +2237,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "優化LDNMP環境" - echo -e "優化LDNMP環境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 標準模式 2. 高性能模式 (推薦2H4G以上)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" - echo "5. 開啟br壓縮 6. 關閉br壓縮" - echo "7. 開啟zstd壓縮 8. 關閉zstd壓縮" + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "站點標準模式" + send_stats "站点标准模式" - # nginx調優 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php調優 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php調優 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2276,7 +2275,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql調優 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2288,23 +2287,23 @@ web_optimization() { optimize_balanced - echo "LDNMP環境已設置成 標準模式" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "站點高性能模式" + send_stats "站点高性能模式" - # nginx調優 + # nginx调优 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php調優 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php調優 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2315,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql調優 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2326,7 +2325,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP環境已設置成 高性能模式" + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2386,9 +2385,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安裝${gl_bai}" +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker="${gl_hui}未安裝${gl_bai}" +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2396,7 +2395,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "訪問地址:" +echo "访问地址:" ip_address @@ -2434,31 +2433,31 @@ check_docker_image_update() { return fi - # 獲取容器的創建時間和鏡像名稱 + # 获取容器的创建时间和镜像名称 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取鏡像倉庫和標籤 + # 提取镜像仓库和标签 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默認標籤為 latest + # 默认标签为 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加對官方鏡像的支持 + # 添加对官方镜像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 從 Docker Hub API 獲取鏡像發佈時間 + # 从 Docker Hub API 获取镜像发布时间 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 驗證獲取的時間 + # 验证获取的时间 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比較時間戳 + # 比较时间戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2476,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 獲取容器的 IP 地址 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2487,34 +2486,34 @@ block_container_port() { install iptables - # 檢查並封禁其他所有 IP + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 檢查並放行指定 IP + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 檢查並放行本地網絡 127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 檢查並封禁其他所有 IP + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 檢查並放行指定 IP + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 檢查並放行本地網絡 127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2524,7 +2523,7 @@ block_container_port() { fi - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2535,7 +2534,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 獲取容器的 IP 地址 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2545,17 +2544,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的規則 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的規則 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地網絡 127.0.0.0/8 的規則 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2564,17 +2563,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的規則 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的規則 + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地網絡 127.0.0.0/8 的規則 + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2585,7 +2584,7 @@ clear_container_rules() { fi - echo "已允許IP+端口訪問該服務" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2599,25 +2598,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供端口號和允許訪問的 IP。" - echo "用法: block_host_port <端口號> <允許的IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 拒絕其他所有 IP 訪問 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允許指定 IP 訪問 + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允許本機訪問 + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2626,27 +2625,27 @@ block_host_port() { - # 拒絕其他所有 IP 訪問 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允許指定 IP 訪問 + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允許本機訪問 + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允許已建立和相關連接的流量 + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2658,47 +2657,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供端口號和允許訪問的 IP。" - echo "用法: clear_host_port_rules <端口號> <允許的IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 訪問的規則 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允許本機訪問的規則 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允許指定 IP 訪問的規則 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 訪問的規則 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允許本機訪問的規則 + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允許指定 IP 訪問的規則 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允許IP+端口訪問該服務" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2747,18 +2746,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 添加域名訪問 6. 刪除域名訪問" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,12 +2770,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name已經安裝完成" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安裝$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2786,7 +2785,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name已經安裝完成" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use @@ -2800,30 +2799,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" - send_stats "解除安裝$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}域名訪問設置" - send_stats "${docker_name}域名訪問設置" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "允許IP訪問${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP訪問${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2860,18 +2859,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 添加域名訪問 6. 刪除域名訪問" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space $app_size - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,22 +2894,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名訪問設置" - send_stats "${docker_name}域名訪問設置" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "允許IP訪問${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP訪問${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,17 +2994,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 檢查會話是否存在的函數 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循環直到找到一個不存在的會話名稱 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 創建新的 tmux 會話 +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3080,7 +3079,7 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重啟" + echo "已重启" reboot ;; *) @@ -3127,8 +3126,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "無法再次安裝LDNMP環境" - echo -e "${gl_huang}提示:${gl_bai}建站環境已安裝。無需再次安裝!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3138,10 +3137,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安裝LDNMP環境" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3155,10 +3154,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安裝nginx環境" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3169,8 +3168,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安裝完成" -echo -e "當前版本:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3181,7 +3180,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "請先安裝LDNMP環境" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3191,7 +3190,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "請先安裝nginx環境" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3202,16 +3201,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的$webname搭建好了!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname安裝信息如下:" + echo "$webname 安装信息如下: " } nginx_web_on() { clear - echo "您的$webname搭建好了!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" } @@ -3223,8 +3222,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3264,17 +3263,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "請輸入你的反代IP:" reverseproxy + read -e -p "请输入你的反代IP: " reverseproxy fi if [ -z "$port" ]; then - read -e -p "請輸入你的反代端口:" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status install_ssltls @@ -3297,14 +3296,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "請輸入你的多個反代IP+端口用空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3357,12 +3356,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站點管理" - echo "LDNMP環境" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "站點:${output}證書到期時間" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3375,35 +3374,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "資料庫:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站點目錄" + echo "站点目录" echo "------------------------" - echo -e "數據${gl_hui}/home/web/html${gl_bai}證書${gl_hui}/home/web/certs${gl_bai}配置${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "操作" echo "------------------------" - echo "1. 申請/更新域名證書 2. 更換站點域名" - echo "3. 清理站點緩存 4. 創建關聯站點" - echo "5. 查看訪問日誌 6. 查看錯誤日誌" - echo "7. 編輯全局配置 8. 編輯站點配置" - echo "9. 管理站點數據庫 10. 查看站點分析報告" + echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20. 刪除指定站點數據" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "申請域名證書" - read -e -p "請輸入你的域名:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3412,15 +3411,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更換站點域名" - echo -e "${gl_hong}強烈建議:${gl_bai}先備份好全站數據再更換站點域名!" - read -e -p "請輸入舊域名:" oddyuming - read -e -p "請輸入新域名:" yuming + send_stats "更换站点域名" + echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status - # mysql替換 + # mysql替换 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3438,7 +3437,7 @@ ldnmp_web_status() { done done - # 網站目錄替換 + # 网站目录替换 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3459,10 +3458,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "創建關聯站點" - echo -e "為現有的站點再關聯一個新域名用於訪問" - read -e -p "請輸入現有的域名:" oddyuming - read -e -p "請輸入新域名:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3476,25 +3475,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看訪問日誌" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看錯誤日誌" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "編輯全局配置" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "編輯站點配置" - read -e -p "編輯站點配置,請輸入你要編輯的域名:" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3504,7 +3503,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站點數據" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3540,16 +3539,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款時下流行且強大的運維管理面板。" - echo "官網介紹:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. 安裝 2. 管理 3. 卸載" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -3558,7 +3557,7 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安裝" + send_stats "${panelname}安装" ;; 2) panel_app_manage @@ -3571,7 +3570,7 @@ while true; do panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}解除安裝" + send_stats "${panelname}卸载" ;; *) break @@ -3615,8 +3614,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安裝frp服務端" - # 生成隨機端口和憑證 + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3637,17 +3636,17 @@ EOF donlond_frp frps - # 輸出生成的信息 + # 输出生成的信息 ip_address echo "------------------------" - echo "客戶端部署時需要用的參數" - echo "服務IP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo echo "FRP面板信息" echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用戶名:$dashboard_user" - echo "FRP面板密碼:$dashboard_pwd" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -3657,9 +3656,9 @@ EOF configure_frpc() { - send_stats "安裝frp客戶端" - read -e -p "請輸入外網對接IP:" server_addr - read -e -p "請輸入外網對接token:" token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -3679,17 +3678,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp內網服務" - # 提示用戶輸入服務名稱和轉發信息 - read -e -p "請輸入服務名稱:" service_name - read -e -p "請輸入轉發類型 (tcp/udp) [回​​車默認tcp]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "請輸入內網IP [回車默認127.0.0.1]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "請輸入內網端口:" local_port - read -e -p "請輸入外網端口:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # 將用戶輸入寫入配置文件 + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3699,8 +3698,8 @@ remote_port = ${remote_port} EOF - # 輸出生成的信息 - echo "服務$service_name已成功添加到 frpc.toml" + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -3711,12 +3710,12 @@ EOF delete_forwarding_service() { - send_stats "刪除frp內網服務" - # 提示用戶輸入需要刪除的服務名稱 - read -e -p "請輸入需要刪除的服務名稱:" service_name - # 使用 sed 刪除該服務及其相關配置 + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服務$service_name已成功從 frpc.toml 刪除" + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -3726,7 +3725,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表頭 + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3747,7 +3746,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服務信息,在處理新服務之前打印當前服務 + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3756,7 +3755,7 @@ list_forwarding_services() { type } - # 更新當前服務名稱 + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -3789,7 +3788,7 @@ list_forwarding_services() { } END { - # 打印最後一個服務的信息 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3802,17 +3801,17 @@ list_forwarding_services() { -# 獲取 FRP 服務端端口 +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成訪問地址 +# 生成访问地址 generate_access_urls() { - # 首先獲取所有端口 + # 首先获取所有端口 get_frp_ports - # 檢查是否有非 8055/8056 的端口 + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3821,18 +3820,18 @@ generate_access_urls() { fi done - # 只在有有效端口時顯示標題和內容 + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRP服務對外訪問地址:" + echo "FRP服务对外访问地址:" - # 處理 IPv4 地址 + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 處理 IPv6 地址(如果存在) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3841,7 +3840,7 @@ generate_access_urls() { done fi - # 處理 HTTPS 配置 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3868,7 +3867,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服務端" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3876,25 +3875,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服務端$check_frp $update_status" - echo "構建FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" - echo "官網介紹: https://github.com/fatedier/frp/" - echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 內網服務域名訪問 6. 刪除域名訪問" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00. 刷新服務狀態 0. 返回上一級選單" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3902,7 +3901,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服務端已經安裝完成" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3912,7 +3911,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服務端已經更新完成" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3923,37 +3922,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "应用已卸载" ;; 5) - echo "將內網穿透服務反代成域名訪問" - send_stats "FRP對外域名訪問" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "請輸入你的內網穿透服務端口:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "允許IP訪問" - read -e -p "請輸入需要放行的端口:" frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP訪問" - echo "如果你已經反代域名訪問了,可用此功能阻止IP+端口訪問,這樣更安全。" - read -e -p "請輸入需要阻止的端口:" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服務狀態" - echo "已經刷新FRP服務狀態" + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -3966,7 +3965,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客戶端" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3974,10 +3973,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客戶端$check_frp $update_status" - echo "與服務端對接,對接後可創建內網穿透服務到互聯網訪問" - echo "官網介紹: https://github.com/fatedier/frp/" - echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: https://github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3985,13 +3984,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. 添加對外服務 5. 刪除對外服務 6. 手動配置服務" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -3999,7 +3998,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客戶端已經安裝完成" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4009,7 +4008,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客戶端已經更新完成" + echo "FRP客户端已经更新完成" ;; 3) @@ -4020,7 +4019,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "应用已卸载" ;; 4) @@ -4066,33 +4065,33 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下載工具" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一個功能強大的視頻下載工具,支持 YouTube、Bilibili、Twitter 等數千站點。" - echo -e "官網地址:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下載視頻列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. 單個視頻下載 6. 批量視頻下載 7. 自定義參數下載" - echo "8. 下載為MP3音頻 9. 刪除視頻目錄 10. Cookie管理(開發中)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "請輸入選項編號:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "正在安裝 yt-dlp..." - echo "正在安裝 yt-dlp..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安裝完成。按任意鍵繼續..." + echo "安装完成。按任意键继续..." read ;; 2) send_stats "正在更新 yt-dlp..." @@ -4100,34 +4099,34 @@ yt_menu_pro() { yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意鍵繼續..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "正在卸載 yt-dlp..." - echo "正在卸載 yt-dlp..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸載完成。按任意鍵繼續..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "單個視頻下載" - read -e -p "請輸入視頻鏈接:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下載完成,按任意鍵繼續..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "批量視頻下載" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 輸入多個視頻鏈接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "現在開始批量下載..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4135,31 +4134,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下載完成,按任意鍵繼續..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "自定義視頻下載" - read -e -p "請輸入完整 yt-dlp 參數(不含 yt-dlp):" custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "執行完成,按任意鍵繼續..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3下載" - read -e -p "請輸入視頻鏈接:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音頻下載完成,按任意鍵繼續..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "刪除視頻" - read -e -p "請輸入刪除視頻名稱:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4195,7 +4194,7 @@ set_timedate() { -# 修復dpkg中斷問題 +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4204,7 +4203,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系統更新...${gl_bai}" + echo -e "${gl_huang}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4231,7 +4230,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系統清理...${gl_bai}" + echo -e "${gl_huang}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4260,13 +4259,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器緩存..." + echo "清理包管理器缓存..." apk cache clean - echo "刪除系統日誌..." + echo "删除系统日志..." rm -rf /var/log/* - echo "刪除APK緩存..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "刪除臨時文件..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4284,19 +4283,19 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "刪除系統日誌..." + echo "删除系统日志..." rm -rf /var/log/* - echo "刪除臨時文件..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依賴..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "清理包管理器緩存..." + echo "清理包管理器缓存..." pkg clean -y - echo "刪除系統日誌..." + echo "删除系统日志..." rm -rf /var/log/* - echo "刪除臨時文件..." + echo "删除临时文件..." rm -rf /tmp/* else @@ -4340,26 +4339,26 @@ fi set_dns_ui() { root_use -send_stats "優化DNS" +send_stats "优化DNS" while true; do clear - echo "優化DNS地址" + echo "优化DNS地址" echo "------------------------" - echo "當前DNS地址" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 國外DNS優化:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 國內DNS優化:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手動編輯DNS配置" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4367,7 +4366,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "國外DNS優化" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4375,12 +4374,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "國內DNS優化" + send_stats "国内DNS优化" ;; 3) install nano nano /etc/resolv.conf - send_stats "手動編輯DNS配置" + send_stats "手动编辑DNS配置" ;; *) break @@ -4403,13 +4402,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 設置為 yes + # 如果找到 PasswordAuthentication 设置为 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 設置為 yes + # 如果找到 PubkeyAuthentication 设置为 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4417,7 +4416,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都沒有匹配,則設置默認值 + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4428,7 +4427,7 @@ correct_ssh_config() { new_ssh_port() { - # 備份 SSH 配置文件 + # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4441,7 +4440,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改為:$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4459,7 +4458,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私鑰信息已生成,務必復制保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4471,17 +4470,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" + echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } import_sshkey() { - read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}錯誤:未輸入公鑰內容。${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4499,7 +4498,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公鑰已成功導入,ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" + echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" } @@ -4508,26 +4507,26 @@ import_sshkey() { add_sshpasswd() { -echo "設置你的ROOT密碼" +echo "设置你的ROOT密码" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登錄設置完畢!${gl_bai}" +echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示:${gl_bai}該功能需要root用戶才能運行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } dd_xitong() { - send_stats "重裝系統" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4538,41 +4537,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始端口:${gl_huang}22${gl_bai}" - echo -e "按任意鍵繼續..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai}初始端口:${gl_huang}3389${gl_bai}" - echo -e "按任意鍵繼續..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}22${gl_bai}" - echo -e "按任意鍵繼續..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}3389${gl_bai}" - echo -e "按任意鍵繼續..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重裝系統" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" - echo -e "${gl_hui}感謝leitbogioro大佬和bin456789大佬的腳本支持!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4588,21 +4587,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請選擇要重裝的系統:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "重裝debian 13" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4610,49 +4609,49 @@ dd_xitong() { ;; 2) - send_stats "重裝debian 12" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重裝debian 11" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重裝debian 10" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重裝ubuntu 24.04" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重裝ubuntu 22.04" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重裝ubuntu 20.04" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重裝ubuntu 18.04" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4661,7 +4660,7 @@ dd_xitong() { 21) - send_stats "重裝rockylinux10" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4669,7 +4668,7 @@ dd_xitong() { ;; 22) - send_stats "重裝rockylinux9" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4677,7 +4676,7 @@ dd_xitong() { ;; 23) - send_stats "重裝alma10" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4685,7 +4684,7 @@ dd_xitong() { ;; 24) - send_stats "重裝alma9" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4693,7 +4692,7 @@ dd_xitong() { ;; 25) - send_stats "重裝oracle10" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4701,7 +4700,7 @@ dd_xitong() { ;; 26) - send_stats "重裝oracle9" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4709,7 +4708,7 @@ dd_xitong() { ;; 27) - send_stats "重裝fedora42" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4717,7 +4716,7 @@ dd_xitong() { ;; 28) - send_stats "重裝fedora41" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4725,7 +4724,7 @@ dd_xitong() { ;; 29) - send_stats "重裝centos10" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4733,7 +4732,7 @@ dd_xitong() { ;; 30) - send_stats "重裝centos9" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4741,7 +4740,7 @@ dd_xitong() { ;; 31) - send_stats "重裝alpine" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4749,7 +4748,7 @@ dd_xitong() { ;; 32) - send_stats "重裝arch" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4757,7 +4756,7 @@ dd_xitong() { ;; 33) - send_stats "重裝kali" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4765,7 +4764,7 @@ dd_xitong() { ;; 34) - send_stats "重裝openeuler" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4773,7 +4772,7 @@ dd_xitong() { ;; 35) - send_stats "重裝opensuse" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4781,7 +4780,7 @@ dd_xitong() { ;; 36) - send_stats "重裝飛牛" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4790,7 +4789,7 @@ dd_xitong() { 41) - send_stats "重裝windows11" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4798,13 +4797,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重裝windows10" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重裝windows7" + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4812,21 +4811,21 @@ dd_xitong() { ;; 44) - send_stats "重裝windows server 22" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重裝windows server 19" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重裝windows server 16" + send_stats "重装windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4834,7 +4833,7 @@ dd_xitong() { ;; 47) - send_stats "重裝windows11 ARM" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4864,17 +4863,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安裝xanmod的BBRv3內核" - echo "當前內核版本:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "內核管理" + echo "内核管理" echo "------------------------" - echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -4884,7 +4883,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步驟3:添加存儲庫 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4893,7 +4892,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod內核已更新。重啟後生效" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4903,7 +4902,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod內核已卸載。重啟後生效" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -4916,13 +4915,13 @@ bbrv3() { else clear - echo "設置BBR3加速" - echo "視頻介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "僅支持Debian/Ubuntu" - echo "請備份數據,將為你升級Linux內核開啟BBR3" + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "確定繼續嗎? (Y/N):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -4930,12 +4929,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "當前環境不支持,僅支持Debian和Ubuntu系統" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "無法確定操作系統類型" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -4946,7 +4945,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步驟3:添加存儲庫 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4957,7 +4956,7 @@ bbrv3() { bbr_on - echo "XanMod內核安裝並BBR3啟用成功。重啟後生效" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4967,7 +4966,7 @@ bbrv3() { echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -4976,40 +4975,40 @@ bbrv3() { elrepo_install() { - # 導入 ELRepo GPG 公鑰 - echo "導入 ELRepo GPG 公鑰..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 檢測系統版本 + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 確保我們在一個支持的操作系統上運行 + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系統:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 打印檢測到的操作系統信息 - echo "檢測到的操作系統:$os_name $os_version" - # 根據系統版本安裝對應的 ELRepo 倉庫配置 + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 8)..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 9)..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 10)..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系統版本:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # 啟用 ELRepo 內核倉庫並安裝最新的主線內核 - echo "啟用 ELRepo 內核倉庫並安裝最新的主線內核..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安裝 ELRepo 倉庫配置並更新到最新主線內核。" + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5017,37 +5016,37 @@ elrepo_install() { elrepo() { root_use - send_stats "紅帽內核管理" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安裝elrepo內核" - echo "當前內核版本:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "內核管理" + echo "内核管理" echo "------------------------" - echo "1. 更新elrepo內核 2. 卸載elrepo內核" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新紅帽內核" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo內核已卸載。重啟後生效" - send_stats "卸載紅帽內核" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5060,26 +5059,26 @@ elrepo() { else clear - echo "請備份數據,將為你升級Linux內核" - echo "視頻介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "僅支持紅帽系列發行版 CentOS/RedHat/Alma/Rocky/oracle" - echo "升級Linux內核可提升系統性能和安全,建議有條件的嘗試,生產環境謹慎升級!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "確定繼續嗎? (Y/N):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升級紅帽內核" + send_stats "升级红帽内核" server_reboot ;; [Nn]) echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5090,7 +5089,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒庫...${gl_bai}" + echo -e "${gl_huang}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5100,19 +5099,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "請指定要掃描的目錄。" + echo "请指定要扫描的目录。" return fi - echo -e "${gl_huang}正在掃描目錄$@...${gl_bai}" + echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" - # 構建 mount 參數 + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 構建 clamscan 命令參數 + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5121,7 +5120,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 執行 Docker 命令 + # 执行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5130,8 +5129,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 掃描完成,病毒報告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜索FOUND關鍵字確認病毒位置${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5143,23 +5142,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒掃描管理" + send_stats "病毒扫描管理" while true; do clear - echo "clamav病毒掃描工具" - echo "視頻介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "是一個開源的防病毒軟件工具,主要用於檢測和刪除各種類型的惡意軟件。" - echo "包括病毒、特洛伊木馬、間諜軟件、惡意腳本和其他有害軟件。" + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自定義目錄掃描${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "全盤掃描" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,7 +5167,7 @@ clamav() { ;; 2) - send_stats "重要目錄掃描" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5176,8 +5175,8 @@ clamav() { break_end ;; 3) - send_stats "自定義目錄掃描" - read -e -p "請輸入要掃描的目錄,用空格分隔(例如:/etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5194,21 +5193,21 @@ clamav() { -# 高性能模式優化函數 +# 高性能模式优化函数 optimize_high_performance() { - echo -e "${gl_lv}切換到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5220,14 +5219,14 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他優化...${gl_bai}" - # 禁用透明大頁面,減少延遲 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5235,21 +5234,21 @@ optimize_high_performance() { } -# 均衡模式優化函數 +# 均衡模式优化函数 optimize_balanced() { - echo -e "${gl_lv}切換到均衡模式...${gl_bai}" + echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5261,36 +5260,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他優化...${gl_bai}" - # 還原透明大頁面 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 還原 NUMA balancing + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 還原默認設置函數 +# 还原默认设置函数 restore_defaults() { - echo -e "${gl_lv}還原到默認設置...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}還原文件描述符...${gl_bai}" + echo -e "${gl_lv}还原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}還原虛擬內存...${gl_bai}" + echo -e "${gl_lv}还原虚拟内存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}還原網絡設置...${gl_bai}" + echo -e "${gl_lv}还原网络设置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5302,37 +5301,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}還原緩存管理...${gl_bai}" + echo -e "${gl_lv}还原缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}還原CPU設置...${gl_bai}" + echo -e "${gl_lv}还原CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}還原其他優化...${gl_bai}" - # 還原透明大頁面 + echo -e "${gl_lv}还原其他优化...${gl_bai}" + # 还原透明大页面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 還原 NUMA balancing + # 还原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 網站搭建優化函數 +# 网站搭建优化函数 optimize_web_server() { - echo -e "${gl_lv}切換到網站搭建優化模式...${gl_bai}" + echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}优化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}优化虚拟内存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}优化网络设置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5344,14 +5343,14 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}优化缓存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}优化CPU设置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他優化...${gl_bai}" - # 禁用透明大頁面,減少延遲 + echo -e "${gl_lv}其他优化...${gl_bai}" + # 禁用透明大页面,减少延迟 echo never > /sys/kernel/mm/transparent_hugepage/enabled # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5364,62 +5363,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux內核調優管理" - echo "Linux系統內核參數優化" - echo "視頻介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux内核调优管理" + echo "Linux系统内核参数优化" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多種系統參數調優模式,用戶可以根據自身使用場景進行選擇切換。" - echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo "--------------------" - echo "1. 高性能優化模式: 最大化系統性能,優化文件描述符、虛擬內存、網絡設置、緩存管理和CPU設置。" - echo "2. 均衡優化模式: 在性能與資源消耗之間取得平衡,適合日常使用。" - echo "3. 網站優化模式: 針對網站服務器進行優化,提高並發連接處理能力、響應速度和整體性能。" - echo "4. 直播優化模式: 針對直播推流的特殊需求進行優化,減少延遲,提高傳輸性能。" - echo "5. 遊戲服優化模式: 針對遊戲服務器進行優化,提高並發處理能力和響應速度。" - echo "6. 還原默認設置: 將系統設置還原為默認配置。" + echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo "6. 还原默认设置: 将系统设置还原为默认配置。" echo "--------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式優化" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式優化" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "網站優化模式" + send_stats "网站优化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流優化" + send_stats "直播推流优化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "遊戲服優化" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults - send_stats "還原默認設置" + send_stats "还原默认设置" ;; *) break @@ -5446,7 +5445,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -5455,17 +5454,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系統:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "不支持的系統,無法識別系統類型。" + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -5475,29 +5474,29 @@ update_locale() { linux_language() { root_use -send_stats "切換系統語言" +send_stats "切换系统语言" while true; do clear - echo "當前系統語言:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1. 英文 2. 簡體中文 3. 繁體中文" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切換到英文" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切換到簡體中文" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切換到繁體中文" + send_stats "切换到繁体中文" ;; *) break @@ -5519,7 +5518,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -5543,9 +5542,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5590,7 +5589,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系統回收站" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5605,17 +5604,17 @@ linux_trash() { fi clear - echo -e "當前回收站${trash_status}" - echo -e "啟用後rm刪除的文件先進入回收站,防止誤刪重要文件!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站為空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1. 啟用回收站 2. 關閉回收站" - echo "3. 還原內容 4. 清空回收站" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -5623,7 +5622,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已啟用,刪除的文件將移至回收站。" + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -5631,20 +5630,20 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已關閉,文件將直接刪除。" + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "輸入要還原的文件名:" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore已還原到主目錄。" + echo "$file_to_restore 已还原到主目录。" else echo "文件不存在。" fi ;; 4) - read -e -p "確認清空回收站? [y/n]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty echo "回收站已清空。" @@ -5658,23 +5657,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夾" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 創建備份 +# 创建备份 create_backup() { - send_stats "創建備份" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用戶輸入備份目錄 - echo "創建備份示例:" - echo "- 備份單個目錄: /var/www" - echo "- 備份多個目錄: /etc /home /var/log" - echo "- 直接回車將使用默認目錄 (/etc /usr /home)" - read -r -p "請輸入要備份的目錄(多個目錄用空格分隔,直接回車則使用默認目錄):" input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # 如果用戶沒有輸入目錄,則使用默認目錄 + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5682,119 +5681,119 @@ create_backup() { "/home" # 用户数据 ) else - # 將用戶輸入的目錄按空格分隔成數組 + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成備份文件前綴 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目錄名稱並去除斜杠 + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最後一個下劃線 + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # 生成備份文件名 + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用戶選擇的目錄 - echo "您選擇的備份目錄為:" + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 創建備份 - echo "正在創建備份$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 檢查命令是否成功 + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "備份創建成功:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "備份創建失敗!" + echo "备份创建失败!" exit 1 fi } -# 恢復備份 +# 恢复备份 restore_backup() { - send_stats "恢復備份" - # 選擇要恢復的備份 - read -e -p "請輸入要恢復的備份文件名:" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # 檢查備份文件是否存在 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "備份文件不存在!" + echo "备份文件不存在!" exit 1 fi - echo "正在恢復備份$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "備份恢復成功!" + echo "备份恢复成功!" else - echo "備份恢復失敗!" + echo "备份恢复失败!" exit 1 fi } -# 列出備份 +# 列出备份 list_backups() { - echo "可用的備份:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# 刪除備份 +# 删除备份 delete_backup() { - send_stats "刪除備份" + send_stats "删除备份" - read -e -p "請輸入要刪除的備份文件名:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # 檢查備份文件是否存在 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "備份文件不存在!" + echo "备份文件不存在!" exit 1 fi - # 刪除備份 + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "備份刪除成功!" + echo "备份删除成功!" else - echo "備份刪除失敗!" + echo "备份删除失败!" exit 1 fi } -# 備份主菜單 +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系統備份功能" - echo "系統備份功能" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. 創建備份 2. 恢復備份 3. 刪除備份" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按回车键继续..." done } @@ -5806,56 +5805,56 @@ linux_backup() { -# 顯示連接列表 +# 显示连接列表 list_connections() { - echo "已保存的連接:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新連接 +# 添加新连接 add_connection() { - send_stats "添加新連接" - echo "創建新連接示例:" - echo "- 連接名稱: my_server" - echo "- IP地址: 192.168.1.100" - echo "- 用戶名: root" - echo "- 端口: 22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "請輸入連接名稱:" name - read -e -p "請輸入IP地址:" ip - read -e -p "請輸入用戶名 (默認: root):" user + read -e -p "请输入连接名称: " name + read -e -p "请输入IP地址: " ip + read -e -p "请输入用户名 (默认: root): " user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "請輸入端口號 (默認: 22):" port + read -e -p "请输入端口号 (默认: 22): " port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "請選擇身份驗證方式:" - echo "1. 密碼" - echo "2. 密鑰" - read -e -p "請輸入選擇 (1/2):" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "請輸入密碼:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 ;; 2) - echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 檢查是否是密鑰內容 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5864,89 +5863,89 @@ add_connection() { fi ;; *) - echo "無效的選擇!" + echo "无效的选择!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "連接已保存!" + echo "连接已保存!" } -# 刪除連接 +# 删除连接 delete_connection() { - send_stats "刪除連接" - read -e -p "請輸入要刪除的連接編號:" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "錯誤:未找到對應的連接。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果連接使用的是密鑰文件,則刪除該密鑰文件 + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "連接已刪除!" + echo "连接已删除!" } -# 使用連接 +# 使用连接 use_connection() { - send_stats "使用連接" - read -e -p "請輸入要使用的連接編號:" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "錯誤:未找到對應的連接。" + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在連接到$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密鑰連接 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "連接失敗!請檢查以下內容:" - echo "1. 密鑰文件路徑是否正確:$password_or_key" - echo "2. 密鑰文件權限是否正確(應為 600)。" - echo "3. 目標服務器是否允許使用密鑰登錄。" + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # 使用密碼連接 + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" - echo "安裝方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "連接失敗!請檢查以下內容:" - echo "1. 用戶名和密碼是否正確。" - echo "2. 目標服務器是否允許密碼登錄。" - echo "3. 目標服務器的 SSH 服務是否正常運行。" + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "ssh遠程連接工具" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 檢查配置文件和密鑰目錄是否存在,如果不存在則創建 + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,21 +5957,21 @@ ssh_manager() { while true; do clear - echo "SSH 遠程連接工具" - echo "可以通過SSH連接到其他Linux系統上" + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1. 創建新連接 2. 使用連接 3. 刪除連接" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "無效的選擇,請重試。" ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -5988,156 +5987,156 @@ ssh_manager() { -# 列出可用的硬盤分區 +# 列出可用的硬盘分区 list_partitions() { - echo "可用的硬盤分區:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 掛載分區 +# 挂载分区 mount_partition() { - send_stats "掛載分區" - read -e -p "請輸入要掛載的分區名稱(例如 sda1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION - # 檢查分區是否存在 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分區不存在!" + echo "分区不存在!" return fi - # 檢查分區是否已經掛載 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分區已經掛載!" + echo "分区已经挂载!" return fi - # 創建掛載點 + # 创建挂载点 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 掛載分區 + # 挂载分区 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分區掛載成功:$MOUNT_POINT" + echo "分区挂载成功: $MOUNT_POINT" else - echo "分區掛載失敗!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" fi } -# 卸載分區 +# 卸载分区 unmount_partition() { - send_stats "卸載分區" - read -e -p "請輸入要卸載的分區名稱(例如 sda1):" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # 檢查分區是否已經掛載 + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分區未掛載!" + echo "分区未挂载!" return fi - # 卸載分區 + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分區卸載成功:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分區卸載失敗!" + echo "分区卸载失败!" fi } -# 列出已掛載的分區 +# 列出已挂载的分区 list_mounted_partitions() { - echo "已掛載的分區:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分區 +# 格式化分区 format_partition() { - send_stats "格式化分區" - read -e -p "請輸入要格式化的分區名稱(例如 sda1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # 檢查分區是否存在 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分區不存在!" + echo "分区不存在!" return fi - # 檢查分區是否已經掛載 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分區已經掛載,請先卸載!" + echo "分区已经挂载,请先卸载!" return fi - # 選擇文件系統類型 - echo "請選擇文件系統類型:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "請輸入你的選擇:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "無效的選擇!"; return ;; + *) echo "无效的选择!"; return ;; esac - # 確認格式化 - read -e -p "確認格式化分區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return fi - # 格式化分區 - echo "正在格式化分區 /dev/$PARTITION為$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分區格式化成功!" + echo "分区格式化成功!" else - echo "分區格式化失敗!" + echo "分区格式化失败!" fi } -# 檢查分區狀態 +# 检查分区状态 check_partition() { - send_stats "檢查分區狀態" - read -e -p "請輸入要檢查的分區名稱(例如 sda1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # 檢查分區是否存在 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分區不存在!" + echo "分区不存在!" return fi - # 檢查分區狀態 - echo "檢查分區 /dev/$PARTITION的狀態:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# 主菜單 +# 主菜单 disk_manager() { - send_stats "硬盤管理功能" + send_stats "硬盘管理功能" while true; do clear - echo "硬盤分區管理" - echo -e "${gl_huang}該功能內部測試階段,請勿在生產環境使用。${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 掛載分區 2. 卸載分區 3. 查看已掛載分區" - echo "4. 格式化分區 5. 檢查分區狀態" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6146,64 +6145,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按回车键继续..." done } -# 顯示任務列表 +# 显示任务列表 list_tasks() { - echo "已保存的同步任務:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任務 +# 添加新任务 add_task() { - send_stats "添加新同步任務" - echo "創建新同步任務示例:" - echo "- 任務名稱: backup_www" - echo "- 本地目錄: /var/www" - echo "- 遠程地址: user@192.168.1.100" - echo "- 遠程目錄: /backup/www" - echo "- 端口號 (默認 22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "請輸入任務名稱:" name - read -e -p "請輸入本地目錄:" local_path - read -e -p "請輸入遠程目錄:" remote_path - read -e -p "請輸入遠程用戶@IP:" remote - read -e -p "請輸入 SSH 端口 (默認 22):" port + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path + read -e -p "请输入远程用户@IP: " remote + read -e -p "请输入 SSH 端口 (默认 22): " port port=${port:-22} - echo "請選擇身份驗證方式:" - echo "1. 密碼" - echo "2. 密鑰" - read -e -p "請選擇 (1/2):" auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "請輸入密碼:" password_or_key + read -s -p "请输入密码: " password_or_key echo # 换行 auth_method="password" ;; 2) - echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" local password_or_key="" while IFS= read -r line; do - # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 + # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 + # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 檢查是否是密鑰內容 + # 检查是否是密钥内容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6211,63 +6210,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "無效的密鑰內容!" + echo "无效的密钥内容!" return fi ;; *) - echo "無效的選擇!" + echo "无效的选择!" return ;; esac - echo "請選擇同步模式:" - echo "1. 標準模式 (-avz)" - echo "2. 刪除目標文件 (-avz --delete)" - read -e -p "請選擇 (1/2):" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無效選擇,使用默認 -avz"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任務已保存!" + echo "任务已保存!" } -# 刪除任務 +# 删除任务 delete_task() { - send_stats "刪除同步任務" - read -e -p "請輸入要刪除的任務編號:" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "錯誤:未找到對應的任務。" + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任務使用的是密鑰文件,則刪除該密鑰文件 + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任務已刪除!" + echo "任务已删除!" } run_task() { - send_stats "執行同步任務" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析參數 + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -6278,51 +6277,51 @@ run_task() { num="$1" fi - # 如果沒有傳入任務編號,提示用戶輸入 + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "請輸入要執行的任務編號:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "錯誤: 未找到該任務!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根據同步方向調整源和目標路徑 + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到遠端:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 連接通用參數 + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" - echo "安裝方法:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 檢查密鑰文件是否存在和權限是否正確 + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "錯誤:密鑰文件不存在:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密鑰文件權限不正確,正在修復..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -6332,30 +6331,30 @@ run_task() { if [[ $? -eq 0 ]]; then echo "同步完成!" else - echo "同步失敗! 請檢查以下內容:" - echo "1. 網絡連接是否正常" - echo "2. 遠程主機是否可訪問" - echo "3. 認證信息是否正確" - echo "4. 本地和遠程目錄是否有正確的訪問權限" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 創建定時任務 +# 创建定时任务 schedule_task() { - send_stats "添加同步定時任務" + send_stats "添加同步定时任务" - read -e -p "請輸入要定時同步的任務編號:" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "錯誤: 請輸入有效的任務編號!" + echo "错误: 请输入有效的任务编号!" return fi - echo "請選擇定時執行間隔:" - echo "1) 每小時執行一次" - echo "2) 每天執行一次" - echo "3) 每週執行一次" - read -e -p "請輸入選項 (1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6363,66 +6362,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "錯誤: 請輸入有效的選項!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 檢查是否已存在相同任務 + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "錯誤: 該任務的定時同步已存在!" + echo "错误: 该任务的定时同步已存在!" return fi - # 創建到用戶的 crontab + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定時任務已創建:$cron_job" + echo "定时任务已创建: $cron_job" } -# 查看定時任務 +# 查看定时任务 view_tasks() { - echo "當前的定時任務:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 刪除定時任務 +# 删除定时任务 delete_task_schedule() { - send_stats "刪除同步定時任務" - read -e -p "請輸入要刪除的任務編號:" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "錯誤: 請輸入有效的任務編號!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已刪除任務編號$num的定時任務" + echo "已删除任务编号 $num 的定时任务" } -# 任務管理主菜單 +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 遠程同步工具" - echo "遠程目錄之間同步,支持增量同步,高效穩定。" + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 創建新任務 2. 刪除任務" - echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" - echo "5. 創建定時任務 6. 刪除定時任務" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6431,9 +6430,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "無效的選擇,請重試。" ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按回车键继续..." done } @@ -6448,7 +6447,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系統信息查詢" + send_stats "系统信息查询" ip_address @@ -6498,41 +6497,41 @@ linux_ps() { echo "" - echo -e "系統信息查詢" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主機名:${gl_bai}$hostname" - echo -e "${gl_kjlan}系統版本:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系統負載:${gl_bai}$load" - echo -e "${gl_kjlan}物理內存:${gl_bai}$mem_info" - echo -e "${gl_kjlan}虛擬內存:${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盤佔用:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}總接收:${gl_bai}$rx" - echo -e "${gl_kjlan}總發送:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}網絡算法:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}運營商:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" - echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -6545,111 +6544,111 @@ linux_tools() { while true; do clear - # send_stats "基礎工具" - echo -e "基礎工具" + # send_stats "基础工具" + echo -e "基础工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通信連接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網絡流量監控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視頻編碼直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盤佔用查看工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本編輯器${gl_kjlan}16. ${gl_bai}nano 文本編輯器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝國屏保${gl_kjlan}22. ${gl_bai}跑火車屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄羅斯方塊小遊戲${gl_kjlan}27. ${gl_bai}貪吃蛇小遊戲" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小遊戲" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安裝${gl_kjlan}32. ${gl_bai}全部安裝(不含屏保和遊戲)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸載" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安裝指定工具${gl_kjlan}42. ${gl_bai}卸載指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" curl --help - send_stats "安裝curl" + send_stats "安装curl" ;; 2) clear install wget clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" wget --help - send_stats "安裝wget" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" sudo --help - send_stats "安裝sudo" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" socat -h - send_stats "安裝socat" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "安裝htop" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "安裝iftop" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" unzip - send_stats "安裝unzip" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" tar --help - send_stats "安裝tar" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" tmux --help - send_stats "安裝tmux" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "安裝ffmpeg" + send_stats "安装ffmpeg" ;; 11) @@ -6657,7 +6656,7 @@ linux_tools() { install btop clear btop - send_stats "安裝btop" + send_stats "安装btop" ;; 12) clear @@ -6666,7 +6665,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安裝ranger" + send_stats "安装ranger" ;; 13) clear @@ -6675,7 +6674,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安裝ncdu" + send_stats "安装ncdu" ;; 14) clear @@ -6684,7 +6683,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安裝fzf" + send_stats "安装fzf" ;; 15) clear @@ -6693,7 +6692,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安裝vim" + send_stats "安装vim" ;; 16) clear @@ -6702,7 +6701,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安裝nano" + send_stats "安装nano" ;; @@ -6713,7 +6712,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安裝git" + send_stats "安装git" ;; 21) @@ -6721,67 +6720,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安裝cmatrix" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "安裝sl" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "安裝bastet" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "安裝nsnake" + send_stats "安装nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "安裝ninvaders" + send_stats "安装ninvaders" ;; 31) clear - send_stats "全部安裝" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安裝(不含遊戲和屏保)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸載" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "請輸入安裝的工具名(wget curl sudo htop):" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "安裝指定軟件" + send_stats "安装指定软件" ;; 42) clear - read -e -p "請輸入卸載的工具名(htop ufw tmux cmatrix):" removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "卸載指定軟件" + send_stats "卸载指定软件" ;; 0) @@ -6789,7 +6788,7 @@ linux_tools() { ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -6809,21 +6808,21 @@ linux_bbr() { clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "當前TCP阻塞算法:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 開啟BBRv3 2. 關閉BBRv3(會重啟)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine開啟bbr3" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6868,18 +6867,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}當前備份列表:${NC}" - ls -dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" + echo -e "${BLUE}当前备份列表:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } # ---------------------------- - # 備份 + # 备份 # ---------------------------- backup_docker() { - echo -e "${YELLOW}正在備份 Docker 容器...${NC}" - read -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers + send_stats "Docker备份" + + echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + docker ps --format '{{.Names}}' + read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6890,7 +6892,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}沒有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6898,28 +6900,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自動生成的還原腳本" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # 記錄已打包過的 Compose 項目路徑,避免重複打包 + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}備份容器:$c${NC}" + echo -e "${GREEN}备份容器: $c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}檢測到$c是 docker-compose 容器${NC}" + echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir + read -p "未检测到 compose 目录,请手动输入路径: " project_dir fi - # 如果該 Compose 項目已經打包過,跳過 + # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 項目 [$project_name] 已備份過,跳過重複打包...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" continue fi @@ -6927,19 +6929,19 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 項目 [$project_name] 已打包:${project_dir}${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" else - echo -e "${RED}未找到 docker-compose.yml,跳過此容器...${NC}" + echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" fi else - # 普通容器備份卷 + # 普通容器备份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷:$path" + echo "打包卷: $path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6948,7 +6950,7 @@ docker_ssh_migration() { mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 環境變量 + # 环境变量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done @@ -6957,90 +6959,91 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 鏡像 + # 镜像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 還原容器:$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 備份 /home/docker 下的所有文件(不含子目錄) + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}備份 /home/docker 下的文件...${NC}" - find /home/docker -maxdepth 1 -type f -print0 | tar --null -czf "${BACKUP_DIR}/home_docker_files.tar.gz" --files-from - - echo -e "${GREEN}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - + echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}備份完成:${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用還原腳本:${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 還原 + # 还原 # ---------------------------- restore_docker() { - list_backups - read -p "請輸入要還原的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } - echo -e "${BLUE}開始執行還原操作...${NC}" + send_stats "Docker还原" + read -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + + echo -e "${BLUE}开始执行还原操作...${NC}" install tar jq gzip install_docker - # --------- 優先還原 Compose 項目 --------- + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路徑,請輸入還原目錄路徑:" original_path + [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path - # 檢查該 compose 項目的容器是否已經在運行 + # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${NC}" + echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" continue fi - read -p "確認還原 Compose 項目 [$project_name] 到路徑 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "請輸入新的還原路徑:" original_path + read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 項目 [$project_name] 已解壓到:$original_path${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 項目 [$project_name] 還原完成!${NC}" + echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" fi done - # --------- 繼續還原普通容器 --------- - echo -e "${BLUE}檢查並還原普通 Docker 容器...${NC}" + # --------- 继续还原普通容器 --------- + echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}處理容器:$container${NC}" + echo -e "${GREEN}处理容器: $container${NC}" - # 檢查容器是否已經存在且正在運行 + # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在運行,跳過還原...${NC}" + echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到鏡像信息,跳過:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } # 端口映射 PORT_ARGS="" @@ -7049,14 +7052,14 @@ docker_ssh_migration() { [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 環境變量 + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷數據恢復 + # 卷映射 + 卷数据恢复 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7067,32 +7070,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢復卷數據:$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 刪除已存在但未運行的容器 + # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未運行,刪除舊容器...${NC}" + echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" docker rm -f "$container" fi - # 啟動容器 - echo "執行還原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的備份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" - # 還原 /home/docker 下的文件 + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在還原 /home/docker 下的文件...${NC}" + echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已還原完成${NC}" + echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的備份,跳過...${NC}" + echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" fi @@ -7100,66 +7103,68 @@ docker_ssh_migration() { # ---------------------------- - # 遷移 + # 迁移 # ---------------------------- migrate_docker() { - ensure_jq - list_backups - read -p "請輸入要遷移的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + send_stats "Docker迁移" + install jq + read -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "目標服務器IP:" TARGET_IP - read -p "目標服務器SSH用戶名:" TARGET_USER + read -p "目标服务器IP: " TARGET_IP + read -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}傳輸備份中...${NC}" + echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密鑰登錄 + # 使用密钥登录 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 刪除備份 + # 删除备份 # ---------------------------- delete_backup() { - list_backups - read -p "請輸入要刪除的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + send_stats "Docker备份文件删除" + read -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已刪除備份:${BACKUP_DIR}${NC}" + echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" } # ---------------------------- - # 主菜單 + # 主菜单 # ---------------------------- main_menu() { + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" - echo -e "Docker備份/遷移/還原工具" + echo -e "Docker备份/迁移/还原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 備份docker項目" - echo -e "2. 遷移docker項目" - echo -e "3. 還原docker項目" - echo -e "4. 刪除docker項目的備份文件" + echo -e "1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. 返回上一級菜單" + echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "請選擇:" choice + read -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}無效選項${NC}" ;; + *) echo -e "${RED}无效选项${NC}" ;; esac + break_end done } @@ -7178,34 +7183,34 @@ linux_docker() { echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安裝更新Docker環境${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局狀態${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker鏡像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker網絡管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker捲管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和鏡像網絡數據卷" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更換Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}編輯daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" - echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" - echo -e "${gl_kjlan}20. ${gl_bai}卸載Docker環境" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "安裝docker環境" + send_stats "安装docker环境" install_add_docker ;; @@ -7216,22 +7221,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局狀態" + send_stats "docker全局状态" echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker鏡像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker網絡:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7246,8 +7251,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker網絡管理" - echo "Docker網絡列表" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -7271,36 +7276,36 @@ linux_docker() { done echo "" - echo "網絡操作" + echo "网络操作" echo "------------------------" - echo "1. 創建網絡" - echo "2. 加入網絡" - echo "3. 退出網絡" - echo "4. 刪除網絡" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "創建網絡" - read -e -p "設置新網絡名:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入網絡" - read -e -p "加入網絡名:" dockernetwork - read -e -p "那些容器加入該網絡(多個容器名請用空格分隔):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入網絡" - read -e -p "退出網絡名:" dockernetwork - read -e -p "那些容器退出該網絡(多個容器名請用空格分隔):" dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7309,8 +7314,8 @@ linux_docker() { ;; 4) - send_stats "刪除網絡" - read -e -p "請輸入要刪除的網絡名:" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -7324,29 +7329,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker捲管理" + send_stats "Docker卷管理" echo "Docker卷列表" docker volume ls echo "" echo "卷操作" echo "------------------------" - echo "1. 創建新卷" - echo "2. 刪除指定卷" - echo "3. 刪除所有捲" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "新建卷" - read -e -p "設置新卷名:" dockerjuan + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "輸入刪除卷名(多個卷名請用空格分隔):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7355,7 +7360,7 @@ linux_docker() { ;; 3) - send_stats "刪除所有捲" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7364,7 +7369,7 @@ linux_docker() { [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7386,7 +7391,7 @@ linux_docker() { [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7408,13 +7413,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 開" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 關" + send_stats "Docker v6 关" docker_ipv6_off ;; @@ -7425,7 +7430,7 @@ linux_docker() { 20) clear - send_stats "Docker卸載" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7437,7 +7442,7 @@ linux_docker() { [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7446,7 +7451,7 @@ linux_docker() { kejilion ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -7463,151 +7468,151 @@ linux_test() { while true; do clear - # send_stats "測試腳本合集" - echo -e "測試腳本合集" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解鎖狀態檢測" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態檢測" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒體解鎖測試" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒體解鎖檢測" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP質量體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}網絡線路測速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三網線路測試" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網絡質量體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能測試" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能測試" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能測試腳本" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}綜合性測試" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能測試" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪測評${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解鎖狀態檢測" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒體解鎖測試" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒體解鎖檢測" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP質量體檢腳本" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三網回程延遲路由測試" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三網回程線路測試" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三網測速" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程測試腳本" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程測試腳本" - echo "可參考的IP列表" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "北京電信: 219.141.136.12" - echo "北京聯通: 202.106.50.1" - echo "北京移動: 221.179.155.161" - echo "上海電信: 202.96.209.133" - echo "上海聯通: 210.22.97.1" - echo "上海移動: 211.136.112.200" - echo "廣州電信: 58.60.188.222" - echo "廣州聯通: 210.21.196.6" - echo "廣州移動: 120.196.165.24" - echo "成都電信: 61.139.2.69" - echo "成都聯通: 119.6.6.6" - echo "成都移動: 211.137.96.205" - echo "湖南電信: 36.111.200.100" - echo "湖南聯通: 42.48.16.100" - echo "湖南移動: 39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "輸入一個指定IP:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三網線路測試" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能測速腳本" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "網絡質量測試腳本" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能測試" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能測試腳本" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能測試" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪測評" + send_stats "spiritysdx融合怪测评" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7617,7 +7622,7 @@ linux_test() { ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -7633,51 +7638,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云腳本合集" - echo -e "甲骨文云腳本合集" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安裝閒置機器活躍腳本" - echo -e "${gl_kjlan}2. ${gl_bai}卸載閒置機器活躍腳本" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重裝系統腳本" - echo -e "${gl_kjlan}4. ${gl_bai}R探長開機腳本" - echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登錄模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢復工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "活躍腳本: CPU佔用10-20% 內存佔用20%" - read -e -p "確定安裝嗎? (Y/N):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # 設置默認值 + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用戶輸入CPU核心數和占用百分比,如果回車則使用默認值 - read -e -p "請輸入CPU核心數 [默認:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [默認:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "請輸入內存佔用百分比 [默認:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "請輸入Speedtest間隔時間(秒) [默認:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 運行Docker容器 + # 运行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7685,14 +7690,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安裝活躍腳本" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -7700,20 +7705,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸載活躍腳本" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "重裝系統" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" - read -e -p "確定繼續嗎? (Y/N):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -7725,28 +7730,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "無效的選擇,請重新輸入。" + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "請輸入你重裝後的密碼:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重裝系統腳本" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - echo "該功能處於開發階段,敬請期待!" + echo "该功能处于开发阶段,敬请期待!" ;; 5) clear @@ -7756,15 +7761,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "該功能由jhb大神提供,感謝他!" - send_stats "ipv6修復" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -7785,7 +7790,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境已經安裝${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡像:${gl_lv}$image_count${gl_bai}網絡:${gl_lv}$network_count${gl_bai}卷:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -7806,7 +7811,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境已安裝${gl_bai}站點:$output資料庫:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -7838,27 +7843,27 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" - echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量博客網站" - echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack共享鏈接平台${gl_huang}20. ${gl_bai}自定義動態站點" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站點重定向" - echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo博客網站" - echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞生成器${gl_huang}28. ${gl_bai}站點反向代理-負載均衡" - echo -e "${gl_huang}30. ${gl_bai}自定義靜態站點" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站點數據管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" - echo -e "${gl_huang}33. ${gl_bai}定時遠程備份${gl_huang}34. ${gl_bai}還原全站數據" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸載LDNMP環境" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜單" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -7872,10 +7877,10 @@ linux_ldnmp() { 3) clear - # Discuz論壇 + # Discuz论坛 webname="Discuz论坛" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,11 +7903,11 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "表前綴: discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; @@ -7911,8 +7916,8 @@ linux_ldnmp() { clear # 可道云桌面 webname="可道云桌面" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7934,20 +7939,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "數據庫地址: mysql" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "數據庫名:$dbname" - echo "redis主機: redis" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # 蘋果CMS + # 苹果CMS webname="苹果CMS" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,24 +7978,24 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "數據庫前綴: mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "安裝成功後登錄後台地址" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 獨腳數卡 + # 独脚数卡 webname="独脚数卡" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,34 +8016,34 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" echo "redis地址: redis" - echo "redis密碼: 默認不填寫" + echo "redis密码: 默认不填写" echo "redis端口: 6379" echo "" - echo "網站url: https://$yuming" - echo "後台登錄路徑: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "用戶名: admin" - echo "密碼: admin" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "登錄時右上角如果出現紅色error0請使用如下命令:" - echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum論壇 + # flarum论坛 webname="flarum论坛" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8075,12 +8080,12 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "表前綴: flarum_" - echo "管理員信息自行設置" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -8088,8 +8093,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8113,11 +8118,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "數據庫前綴: typecho_" - echo "數據庫地址: mysql" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "數據庫名:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -8126,8 +8131,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8152,18 +8157,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8180,10 +8185,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP源碼" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8193,20 +8198,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路徑" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "請輸入index.php的路徑,類似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 請選擇PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 :" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8217,15 +8222,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "無效的選擇,請重新輸入。" + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安裝指定擴展" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "已經安裝的擴展" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8235,25 +8240,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 編輯站點配置" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "按任意鍵繼續,可以詳細設置站點配置,如偽靜態等內容" + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 數據庫管理" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有數據庫備份:" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "數據庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支持寶塔/1panel備份數據導入。" - read -e -p "也可以輸入下載鏈接,遠程下載備份數據,直接回車將跳過遠程下載:" url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8263,10 +8268,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "數據庫導入的表數據" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "數據庫導入完成" + echo "数据库导入完成" ;; *) echo @@ -8278,12 +8283,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" - echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" - echo "表前綴:$prefix" - echo "管理員登錄信息自行設置" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -8296,10 +8301,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "請輸入跳轉域名:" reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status install_ssltls certs_status @@ -8321,7 +8326,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8332,11 +8337,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "域名格式:${gl_huang}google.com${gl_bai}" - read -e -p "請輸入你的反代域名:" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls certs_status @@ -8356,8 +8361,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8379,8 +8384,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8397,8 +8402,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status install_ssltls @@ -8431,8 +8436,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安裝$webname" - echo "開始部署$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -8449,10 +8454,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態源碼" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,12 +8467,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路徑" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "請輸入index.html的路徑,類似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8492,21 +8497,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境備份" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "備份文件已創建: /home/$backup_filename" - read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8514,9 +8519,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已傳送至遠程服務器home目錄。" + echo "文件已传送至远程服务器home目录。" else - echo "未找到要傳送的文件。" + echo "未找到要传送的文件。" fi break ;; @@ -8524,7 +8529,7 @@ linux_ldnmp() { break ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -8532,9 +8537,9 @@ linux_ldnmp() { 33) clear - send_stats "定時遠程備份" - read -e -p "輸入遠程服務器IP:" useip - read -e -p "輸入遠程服務器密碼:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8544,18 +8549,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周備份 2. 每天備份" - read -e -p "請輸入你的選擇:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "選擇每周備份的星期幾 (0-6,0代表星期日):" weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "選擇每天備份的時間(小時,0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8569,19 +8574,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP環境還原" - echo "可用的站點備份" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用戶沒有輸入文件名,使用最新的壓縮包 + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8591,7 +8596,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8600,7 +8605,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "沒有找到壓縮包。" + echo "没有找到压缩包。" fi ;; @@ -8618,11 +8623,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP環境" - echo "更新LDNMP環境" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "發現新版本的組件" + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8644,11 +8649,11 @@ linux_ldnmp() { echo echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. 更新完整環境" + echo "5. 更新完整环境" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -8657,7 +8662,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "請輸入${ldnmp_pods}版本號 (如: 8.0 8.3 8.4 9.0)(回車獲取最新版):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -8674,7 +8679,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車獲取最新版):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8727,7 +8732,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP環境" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -8753,7 +8758,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸載LDNMP環境" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8767,7 +8772,7 @@ linux_ldnmp() { ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8777,7 +8782,7 @@ linux_ldnmp() { ;; *) - echo "無效的輸入!" + echo "无效的输入!" esac break_end @@ -8797,12 +8802,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "應用市場" + echo -e "应用市场" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循環設置顏色 + # 用循环设置颜色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8811,67 +8816,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}寶塔面板官方版${gl_kjlan}2. ${color2}aaPanel寶塔國際版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager可視化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存儲文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠程桌面網頁版" - echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io郵件服務器程序${gl_kjlan}10. ${color10}RocketChat多人在線聊天系統" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禪道項目管理軟件${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟件${gl_kjlan}18. ${color18}onlyoffice在線辦公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" - echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud網盤${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆棧管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相冊系統" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播錄製工具${gl_kjlan}40. ${color40}webssh網頁版SSH連接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠程連接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" - echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在線翻譯服務器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp視頻下載工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL證書管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂服務器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" - echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}在線DOS老遊戲" - echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" - echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" - echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in @@ -8990,6 +8998,9 @@ while true; do docker_rum() { + mkdir -p /home/docker/openlist + chmod -R 777 /home/docker/openlist + docker run -d \ --restart=always \ -v /home/docker/openlist:/opt/openlist/data \ @@ -9021,8 +9032,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9064,9 +9075,9 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒監控$check_docker $update_status" - echo "開源、輕量、易用的服務器監控與運維工具" - echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip @@ -9075,9 +9086,9 @@ while true; do echo "------------------------" echo "1. 使用" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9134,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "搭建郵局" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -9144,43 +9155,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "郵局服務$check_docker $update_status" - echo "poste.io 是一個開源的郵件服務器解決方案," - echo "視頻介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "端口檢測" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口$port當前可用${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}端口$port當前不可用${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "訪問地址:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) check_disk_space 2 - read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析這些DNS記錄" + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9190,7 +9201,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意鍵繼續..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -9209,9 +9220,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已經安裝完成" + echo "poste.io已经安装完成" echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -9234,9 +9245,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已經安裝完成" + echo "poste.io已经安装完成" echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -9247,7 +9258,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "应用已卸载" ;; *) @@ -9281,7 +9292,7 @@ while true; do clear ip_address - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -9291,7 +9302,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已經安裝完成" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -9301,7 +9312,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -9385,7 +9396,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -9399,7 +9410,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -9552,20 +9563,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" - echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 重置密碼 4. 卸載" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -9575,7 +9586,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已經安裝完成" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9588,7 +9599,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已經更新完成" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -9599,7 +9610,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9718,8 +9729,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10007,7 +10018,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10264,9 +10275,9 @@ while true; do prometheus_install clear ip_address - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip - echo "初始用戶名密碼均為: admin" + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -10284,7 +10295,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -10371,7 +10382,7 @@ while true; do 51|pve) clear - send_stats "PVE開小雞" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10491,7 +10502,7 @@ while true; do docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -10506,7 +10517,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -10534,7 +10545,7 @@ while true; do docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -10549,7 +10560,7 @@ while true; do docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -10557,7 +10568,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -10578,17 +10589,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip - echo "初始用戶名: admin" - echo "初始密碼: ChangeMe" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "應用已更新" + echo "应用已更新" } @@ -10598,7 +10609,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -10645,7 +10656,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -10661,7 +10672,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -10923,7 +10934,7 @@ while true; do docker_rum() { - read -e -p "設置LibreTV的登錄密碼:" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -10957,9 +10968,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password - read -e -p "輸入授權碼:" shouquanma + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma mkdir -p /home/docker/moontv @@ -10969,13 +10980,13 @@ while true; do curl -o /home/docker/moontv/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/moontv-docker-compose.yml sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin/${admin}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/admin_password/${admin_password}/g" /home/docker/moontv/docker-compose.yml - sed -i "s/shouquanma/${shouquanma}/g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin_password|${admin_password}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|admin|${admin}|g" /home/docker/moontv/docker-compose.yml + sed -i "s|shouquanma|${shouquanma}|g" /home/docker/moontv/docker-compose.yml cd /home/docker/moontv/ docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -10989,7 +11000,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -11062,8 +11073,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" app_use - read -e -p "設置登錄密碼:" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -11160,11 +11171,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下載官方 docker-compose 和 env 文件 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成隨機密鑰與密碼 + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11173,17 +11184,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理員賬號信息 + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 啟動容器 + # 启动容器 docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -11193,7 +11204,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的變量 + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11210,7 +11221,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -11260,7 +11271,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -11278,7 +11289,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登錄密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11382,7 +11393,7 @@ while true; do docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -11395,7 +11406,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -11556,7 +11567,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "創建初始用戶或管理員。請設置以下內容用戶名和密碼以及是否為管理員。" + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11608,7 +11619,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -11622,7 +11633,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "應用已卸載" + echo "应用已卸载" } docker_app_plus @@ -11661,24 +11672,282 @@ while true; do ;; + 93|dufs) + + local app_id="93" + local docker_name="dufs" + local docker_img="sigoden/dufs" + local docker_port=8093 + + docker_rum() { + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}:/data \ + -p ${docker_port}:5000 \ + ${docker_img} /data -A + + } + + local docker_describe="极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + 94|gopeed) + + local app_id="94" + local docker_name="gopeed" + local docker_img="liwei2633/gopeed" + local docker_port=8094 + + docker_rum() { + + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name ${docker_name} \ + --restart unless-stopped \ + -v /home/docker/${docker_name}/downloads:/app/Downloads \ + -v /home/docker/${docker_name}/storage:/app/storage \ + -p ${docker_port}:9999 \ + ${docker_img} -u ${app_use} -p ${app_passwd} + + } + + local docker_describe="分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + + 95|paperless) + + local app_id="95" + + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" + local docker_name="paperless-webserver-1" + local docker_port="8095" + local app_size="2" + + docker_app_install() { + + mkdir -p /home/docker/paperless + mkdir -p /home/docker/paperless/export + mkdir -p /home/docker/paperless/consume + cd /home/docker/paperless + + curl -o /home/docker/paperless/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/docker-compose.postgres-tika.yml + curl -o /home/docker/paperless/docker-compose.env ${gh_proxy}raw.githubusercontent.com/paperless-ngx/paperless-ngx/refs/heads/main/docker/compose/.env + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/paperless/docker-compose.yml + cd /home/docker/paperless + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/paperless/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/paperless/ && docker compose down --rmi all + rm -rf /home/docker/paperless + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) + + local app_id="97" + local docker_name="wireguard" + local docker_img="lscr.io/linuxserver/wireguard:latest" + local docker_port=51820 + + docker_rum() { + + read -p "请输入组网的客户端数量 (默认 5): " COUNT + COUNT=${COUNT:-5} + + PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) + + stop_containers_or_kill_process 51820 &>/dev/null + + ip_address + docker run -d \ + --name=wireguard \ + --network host \ + --cap-add=NET_ADMIN \ + --cap-add=SYS_MODULE \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e SERVERURL=${ipv4_address} \ + -e SERVERPORT=51820 \ + -e PEERS=${PEERS} \ + -e INTERNAL_SUBNET=10.13.13.0 \ + -e ALLOWEDIPS=10.13.13.0/24 \ + -e PERSISTENTKEEPALIVE_PEERS=all \ + -e LOG_CONFS=true \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules \ + --restart unless-stopped \ + lscr.io/linuxserver/wireguard:latest + + + sleep 3 + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + for f in "$d"/*.conf; do + grep -q "^PersistentKeepalive *= *25$" "$f" || \ + sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + done + done + ' + + docker exec -it wireguard bash -c ' + for d in /config/peer_*; do + cd "$d" || continue + conf_file=$(ls *.conf) + base_name="${conf_file%.conf}" + echo "生成二维码: $base_name.png" + qrencode -o "$base_name.png" < "$conf_file" + done + ' + + sleep 2 + docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + sleep 2 + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + sleep 2 + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 98|wgc) + + local app_id="98" + local docker_name="wireguardc" + local docker_img="kjlion/wireguard:alpine" + local docker_port=51820 + + docker_rum() { + + mkdir -p /home/docker/wireguard/config/ + + local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" + + # 创建目录(如果不存在) + mkdir -p "$(dirname "$CONFIG_FILE")" + + echo "请粘贴你的客户端配置,连续按两次回车保存:" + + # 初始化变量 + input="" + empty_line_count=0 + + # 逐行读取用户输入 + while IFS= read -r line; do + if [[ -z "$line" ]]; then + ((empty_line_count++)) + if [[ $empty_line_count -ge 2 ]]; then + break + fi + else + empty_line_count=0 + input+="$line"$'\n' + fi + done + + # 写入配置文件 + echo "$input" > "$CONFIG_FILE" + + echo "客户端配置已保存到 $CONFIG_FILE" + + docker run -d \ + --name wireguardc \ + --network host \ + --cap-add NET_ADMIN \ + --cap-add SYS_MODULE \ + -v /home/docker/wireguard/config:/config \ + -v /lib/modules:/lib/modules:ro \ + --restart always \ + kjlion/wireguard:alpine + + sleep 3 + + docker logs wireguardc + + break_end + + } + + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear - send_stats "全部應用備份" + send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "備份文件已創建: /$backup_filename" - read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" + echo "错误: 请输入远端服务器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11686,14 +11955,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已傳送至遠程服務器/根目錄。" + echo "文件已传送至远程服务器/根目录。" else - echo "未找到要傳送的文件。" + echo "未找到要传送的文件。" fi break ;; *) - echo "注意: 目前備份僅包含docker項目,不包含寶塔,1panel等建站面板的數據備份。" + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" break ;; esac @@ -11703,29 +11972,29 @@ while true; do r) root_use - send_stats "全部應用還原" - echo "可用的應用備份" + send_stats "全部应用还原" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用戶沒有輸入文件名,使用最新的壓縮包 + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "應用數據已還原,目前請手動進入指定應用菜單,更新應用,即可還原應用。" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else - echo "沒有找到壓縮包。" + echo "没有找到压缩包。" fi ;; @@ -11748,35 +12017,35 @@ linux_work() { while true; do clear - send_stats "後台工作區" - echo -e "後台工作區" - echo -e "系統將為你提供可以後台常駐運行的工作區,你可以用來執行長時間的任務" - echo -e "即使你斷開SSH,工作區中的任務也不會中斷,後台常駐任務。" - echo -e "${gl_huang}提示:${gl_bai}進入工作區後使用Ctrl+b再單獨按d,退出工作區!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "當前已存在的工作區列表" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1號工作區" - echo -e "${gl_kjlan}2. ${gl_bai}2號工作區" - echo -e "${gl_kjlan}3. ${gl_bai}3號工作區" - echo -e "${gl_kjlan}4. ${gl_bai}4號工作區" - echo -e "${gl_kjlan}5. ${gl_bai}5號工作區" - echo -e "${gl_kjlan}6. ${gl_bai}6號工作區" - echo -e "${gl_kjlan}7. ${gl_bai}7號工作區" - echo -e "${gl_kjlan}8. ${gl_bai}8號工作區" - echo -e "${gl_kjlan}9. ${gl_bai}9號工作區" - echo -e "${gl_kjlan}10. ${gl_bai}10號工作區" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐模式${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}創建/進入工作區" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到後台工作區" - echo -e "${gl_kjlan}24. ${gl_bai}刪除指定工作區" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -11784,7 +12053,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11792,63 +12061,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "啟動工作區$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -11860,21 +12129,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常駐模式" - echo -e "SSH常駐模式${tmux_sshd_status}" - echo "開啟後SSH連接後會直接進入常駐模式,直接回到之前的工作狀態。" + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. 開啟 2. 關閉" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "啟動工作區$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自動進入 tmux 會話\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -11890,29 +12159,29 @@ linux_work() { ;; 22) - read -e -p "請輸入你創建或進入的工作區名稱,如1​​001 kj001 work1:" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "自定義工作區" + send_stats "自定义工作区" ;; 23) - read -e -p "請輸入你要後台執行的命令,如:curl -fsSL https://get.docker.com | sh:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "注入命令到後台工作區" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "請輸入要刪除的工作區名稱:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "刪除工作區" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -11937,54 +12206,54 @@ linux_Settings() { while true; do clear - # send_stats "系統工具" - echo -e "系統工具" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}設置腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登錄密碼" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密碼登錄模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}開放所有端口${gl_kjlan}6. ${gl_bai}修改SSH連接端口" - echo -e "${gl_kjlan}7. ${gl_bai}優化DNS地址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT賬戶創建新賬戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用狀態${gl_kjlan}12. ${gl_bai}修改虛擬內存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用戶管理${gl_kjlan}14. ${gl_bai}用戶/密碼生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火牆高級管理器${gl_kjlan}18. ${gl_bai}修改主機名" - echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新源${gl_kjlan}20. ${gl_bai}定時任務管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}ROOT私鑰登錄模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux內核升級${gl_kjlan}28. ${gl_bai}Linux系統內核參數優化${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令行美化工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}設置系統回收站${gl_kjlan}34. ${gl_bai}系統備份與恢復" - echo -e "${gl_kjlan}35. ${gl_bai}ssh遠程連接工具${gl_kjlan}36. ${gl_bai}硬盤分區管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重啟服務器${gl_kjlan}100. ${gl_bai}隱私與安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高級用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸載科技lion腳本" + echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "請輸入你的快捷按鍵(輸入0退出):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷鍵已設置" - send_stats "腳本快捷鍵已設置" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -11992,13 +12261,13 @@ linux_Settings() { 2) clear - send_stats "設置你的登錄密碼" - echo "設置你的登錄密碼" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) root_use - send_stats "root密碼模式" + send_stats "root密码模式" add_sshpasswd ;; @@ -12006,20 +12275,20 @@ linux_Settings() { root_use send_stats "py版本管理" echo "python版本管理" - echo "視頻介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "該功能可無縫安裝python官方支持的任何版本!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查詢更多版本: https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "輸入你要安裝的python版本號(輸入0退出):" py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "腳本PY管理" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -12081,17 +12350,17 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" - send_stats "腳本PY版本切換" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "開放端口" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部開放" + echo "端口已全部开放" ;; 6) @@ -12102,19 +12371,19 @@ EOF clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 讀取當前的 SSH 端口號 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印當前的 SSH 端口號 - echo -e "當前的 SSH 端口號是:${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口號範圍1到65535之間的數字。 (輸入0退出)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # 提示用戶輸入新的 SSH 端口號 - read -e -p "請輸入新的 SSH 端口號:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # 判斷端口號是否在有效範圍內 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH端口已修改" @@ -12123,13 +12392,13 @@ EOF send_stats "退出SSH端口修改" break else - echo "端口號無效,請輸入1到65535之間的數字。" - send_stats "輸入無效SSH端口" + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "輸入無效,請輸入數字。" - send_stats "輸入無效SSH端口" + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -12148,8 +12417,8 @@ EOF ;; 9) root_use - send_stats "新用戶禁用root" - read -e -p "請輸入新用戶名(輸入0退出):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12170,43 +12439,43 @@ EOF 10) root_use - send_stats "設置v4/v6優先級" + send_stats "设置v4/v6优先级" while true; do clear - echo "設置v4/v6優先級" + echo "设置v4/v6优先级" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "當前網絡優先級設置:${gl_huang}IPv4${gl_bai}優先" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "當前網絡優先級設置:${gl_huang}IPv6${gl_bai}優先" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 優先 2. IPv6 優先 3. IPv6 修復工具" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "選擇優先的網絡:" choice + read -e -p "选择优先的网络: " choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切換為 IPv4 優先" - send_stats "已切換為 IPv4 優先" + echo "已切换为 IPv4 优先" + send_stats "已切换为 IPv4 优先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切換為 IPv6 優先" - send_stats "已切換為 IPv6 優先" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "該功能由jhb大神提供,感謝他!" - send_stats "ipv6修復" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -12224,43 +12493,43 @@ EOF 12) root_use - send_stats "設置虛擬內存" + send_stats "设置虚拟内存" while true; do clear - echo "設置虛擬內存" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "當前虛擬內存:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定義大小" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "已設置1G虛擬內存" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "已設置2G虛擬內存" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "已設置4G虛擬內存" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "請輸入虛擬內存大小(單位M):" new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "已設置自定義虛擬內存" + send_stats "已设置自定义虚拟内存" ;; *) @@ -12273,8 +12542,8 @@ EOF 13) while true; do root_use - send_stats "用戶管理" - echo "用戶列表" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12285,24 +12554,24 @@ EOF echo "" - echo "賬戶操作" + echo "账户操作" echo "------------------------" - echo "1. 創建普通賬戶 2. 創建高級賬戶" + echo "1. 创建普通账户 2. 创建高级账户" echo "------------------------" - echo "3. 賦予最高權限 4. 取消最高權限" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. 刪除賬號" + echo "5. 删除账号" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # 提示用戶輸入新用戶名 - read -e -p "請輸入新用戶名:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 創建新用戶並設置密碼 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" @@ -12310,14 +12579,14 @@ EOF ;; 2) - # 提示用戶輸入新用戶名 - read -e -p "請輸入新用戶名:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username - # 創建新用戶並設置密碼 + # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 賦予新用戶sudo權限 + # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12326,21 +12595,21 @@ EOF ;; 3) - read -e -p "請輸入用戶名:" username - # 賦予新用戶sudo權限 + read -e -p "请输入用户名: " username + # 赋予新用户sudo权限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "請輸入用戶名:" username - # 從sudoers文件中移除用戶的sudo權限 + read -e -p "请输入用户名: " username + # 从sudoers文件中移除用户的sudo权限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "請輸入要刪除的用戶名:" username - # 刪除用戶及其主目錄 + read -e -p "请输入要删除的用户名: " username + # 删除用户及其主目录 userdel -r "$username" ;; @@ -12353,50 +12622,50 @@ EOF 14) clear - send_stats "用戶信息生成器" - echo "隨機用戶名" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "隨機用戶名$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "隨機姓名" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5個隨機用戶姓名 + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "隨機用戶姓名$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "隨機UUID" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "隨機UUID$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16位隨機密碼" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "隨機密碼$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32位隨機密碼" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "隨機密碼$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -12404,46 +12673,46 @@ EOF 15) root_use - send_stats "換時區" + send_stats "换时区" while true; do clear - echo "系統時間信息" + echo "系统时间信息" - # 獲取當前系統時區 + # 获取当前系统时区 local timezone=$(current_timezone) - # 獲取當前系統時間 + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 顯示時區和時間 - echo "當前系統時區:$timezone" - echo "當前系統時間:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "時區切換" + echo "时区切换" echo "------------------------" - echo "亞洲" - echo "1. 中國上海時間 2. 中國香港時間" - echo "3. 日本東京時間 4. 韓國首爾時間" - echo "5. 新加坡時間 6. 印度加爾各答時間" - echo "7. 阿聯酋迪拜時間 8. 澳大利亞悉尼時間" - echo "9. 泰國曼谷時間" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "歐洲" - echo "11. 英國倫敦時間 12. 法國巴黎時間" - echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" - echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" echo "美洲" - echo "21. 美國西部時間 22. 美國東部時間" - echo "23. 加拿大時間 24. 墨西哥時間" - echo "25. 巴西時間 26. 阿根廷時間" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC全球標準時間" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -12486,21 +12755,21 @@ EOF 18) root_use - send_stats "修改主機名" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "當前主機名:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "請輸入新的主機名(輸入0退出):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系統,如 Debian, Ubuntu, CentOS 等 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12518,11 +12787,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主機名已更改為:$new_hostname" - send_stats "主機名已更改" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "已退出,未更改主機名。" + echo "已退出,未更改主机名。" break fi done @@ -12530,24 +12799,24 @@ EOF 19) root_use - send_stats "換系統更新源" + send_stats "换系统更新源" clear - echo "選擇更新源區域" - echo "接入LinuxMirrors切換系統更新源" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "中國大陸默認源" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中國大陸教育源" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) @@ -12563,62 +12832,62 @@ EOF ;; 20) - send_stats "定時任務管理" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "定時任務列表" + echo "定时任务列表" crontab -l echo "" echo "操作" echo "------------------------" - echo "1. 添加定時任務 2. 刪除定時任務 3. 編輯定時任務" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "請輸入新任務的執行命令:" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. 每月任務 2. 每週任務" - echo "3. 每天任務 4. 每小時任務" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "請輸入你的選擇:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "選擇每月的幾號執行任務? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "選擇週幾執行任務? (0-6,0代表星期日):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "選擇每天幾點執行任務? (小時,0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "輸入每小時的第幾分鐘執行任務? (分鐘,0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定時任務" + send_stats "添加定时任务" ;; 2) - read -e -p "請輸入需要刪除任務的關鍵字:" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "刪除定時任務" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "編輯定時任務" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -12633,29 +12902,29 @@ EOF send_stats "本地host解析" while true; do clear - echo "本機host解析列表" - echo "如果你在這裡添加解析匹配,將不再使用動態解析了" + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" echo "操作" echo "------------------------" - echo "1. 添加新的解析 2. 刪除解析地址" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "請輸入新的解析記錄 格式: 110.25.5.33 kejilion.pro :" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts send_stats "本地host解析新增" ;; 2) - read -e -p "請輸入需要刪除的解析內容關鍵字:" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析刪除" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -12666,7 +12935,7 @@ EOF 22) root_use - send_stats "ssh防禦" + send_stats "ssh防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12678,20 +12947,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防禦程序$check_docker" - echo "fail2ban是一個SSH防止暴力破解工具" - echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_docker" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安裝防禦程序" + echo "1. 安装防御程序" echo "------------------------" - echo "2. 查看SSH攔截記錄" - echo "3. 日誌實時監控" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "9. 卸載防禦程序" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) install_docker @@ -12714,7 +12983,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防禦程序已卸載" + echo "Fail2Ban防御程序已卸载" ;; *) break @@ -12727,47 +12996,47 @@ EOF 23) root_use - send_stats "限流關機功能" + send_stats "限流关机功能" while true; do clear - echo "限流關機功能" - echo "視頻介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "當前流量使用情況,重啟服務器流量計算會清零!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}總接收:${gl_bai}$rx" - echo -e "${gl_kjlan}總發送:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # 檢查是否存在 Limiting_Shut_down.sh 文件 + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # 獲取 threshold_gb 的值 + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}當前設置的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}當前設置的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}當前未啟用限流關機功能${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "系統每分鐘會檢測實際流量是否到達閾值,到達後會自動關閉服務器!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. 開啟限流關機功能 2. 停用限流關機功能" + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 輸入新的虛擬內存大小 - echo "如果實際服務器就100G流量,可設置閾值為95G,提前關機,以免出現流量誤差或溢出。" - read -e -p "請輸入進站流量閾值(單位為G,默認100G):" rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "請輸入出站流量閾值(單位為G,默認100G):" tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "請輸入流量重置日期(默認每月1日重置):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -12780,15 +13049,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流關機已設置" - send_stats "限流關機已設置" + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已關閉限流關機功能" + echo "已关闭限流关机功能" ;; *) break @@ -12801,40 +13070,40 @@ EOF 24) root_use - send_stats "私鑰登錄" + send_stats "私钥登录" while true; do clear - echo "ROOT私鑰登錄模式" - echo "視頻介紹: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "將會生成密鑰對,更安全的方式SSH登錄" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密鑰 2. 導入已有密鑰 3. 查看本機密鑰" + echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "生成新密鑰" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "導入已有公鑰" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "查看本機密鑰" + send_stats "查看本机密钥" echo "------------------------" - echo "公鑰信息" + echo "公钥信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私鑰信息" + echo "私钥信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -12850,18 +13119,18 @@ EOF 25) root_use - send_stats "電報預警" - echo "TG-bot監控預警功能" - echo "視頻介紹: https://youtu.be/vLL-eb3Z_TY" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要配置tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬盤,流量,SSH登錄的實時監控預警" - echo "到達閾值後會向用戶發預警消息" - echo -e "${gl_hui}-關於流量,重啟服務器將重新計算-${gl_bai}" - read -e -p "確定繼續嗎? (Y/N):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "電報預警啟用" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -12894,21 +13163,21 @@ EOF source ~/.profile clear - echo "TG-bot預警系統已啟動" - echo -e "${gl_hui}你還可以將root目錄中的TG-check-notify.sh預警文件放到其他機器上直接使用!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "修復SSH高危漏洞" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -12952,7 +13221,7 @@ EOF ;; 37) clear - send_stats "命令行歷史記錄" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -12976,60 +13245,60 @@ EOF 41) clear send_stats "留言板" - echo "科技lion留言板已遷移至官方社區!請在官方社區進行留言噢!" + echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一條龍調優" - echo "一條龍系統調優" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "將對以下內容進行操作與優化" - echo "1. 更新系統到最新" - echo "2. 清理系統垃圾文件" - echo -e "3. 設置虛擬內存${gl_huang}1G${gl_bai}" - echo -e "4. 設置SSH端口號為${gl_huang}5522${gl_bai}" - echo -e "5. 開放所有端口" - echo -e "6. 開啟${gl_huang}BBR${gl_bai}加速" - echo -e "7. 設置時區到${gl_huang}上海${gl_bai}" - echo -e "8. 自動優化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "9. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系統內核參數優化切換到${gl_huang}均衡優化模式${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 开放所有端口" + echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "確定一鍵保養嗎? (Y/N):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "一條龍調優啟動" + send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系統到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系統垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 設置虛擬內存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 開放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 設置時區到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13046,25 +13315,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自動優化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系統內核參數優化" - echo -e "${gl_lv}一條龍系統調優已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -13072,7 +13341,7 @@ EOF 99) clear - send_stats "重啟系統" + send_stats "重启系统" server_reboot ;; 100) @@ -13088,32 +13357,32 @@ EOF local status_message="无法确定的状态" fi - echo "隱私與安全" - echo "腳本將收集用戶使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" - echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "當前狀態:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. 開啟採集" - echo "2. 關閉採集" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "請輸入你的選擇:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已開啟採集" - send_stats "隱私與安全已開啟採集" + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已關閉採集" - send_stats "隱私與安全已關閉採集" + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -13129,11 +13398,11 @@ EOF 102) clear - send_stats "卸載科技lion腳本" - echo "卸載科技lion腳本" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "將徹底卸載kejilion腳本,不影響你其他功能" - read -e -p "確定繼續嗎? (Y/N):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -13141,7 +13410,7 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "腳本已卸載,再見!" + echo "脚本已卸载,再见!" break_end clear exit @@ -13150,7 +13419,7 @@ EOF echo "已取消" ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -13160,7 +13429,7 @@ EOF ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -13183,182 +13452,182 @@ linux_file() { clear echo "文件管理器" echo "------------------------" - echo "當前路徑" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 進入目錄 2. 創建目錄 3. 修改目錄權限 4. 重命名目錄" - echo "5. 刪除目錄 6. 返回上一級選單目錄" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. 創建文件 12. 編輯文件 13. 修改文件權限 14. 重命名文件" - echo "15. 刪除文件" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. 壓縮文件目錄 22. 解壓文件目錄 23. 移動文件目錄 24. 複製文件目錄" - echo "25. 傳文件至其他服務器" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "請輸入你的選擇:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "請輸入目錄名:" dirname - cd "$dirname" 2>/dev/null || echo "無法進入目錄" - send_stats "進入目錄" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "請輸入要創建的目錄名:" dirname - mkdir -p "$dirname" && echo "目錄已創建" || echo "創建失敗" - send_stats "創建目錄" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "請輸入目錄名:" dirname - read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" - send_stats "修改目錄權限" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "請輸入當前目錄名:" current_name - read -e -p "請輸入新目錄名:" new_name - mv "$current_name" "$new_name" && echo "目錄已重命名" || echo "重命名失敗" - send_stats "重命名目錄" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "請輸入要刪除的目錄名:" dirname - rm -rf "$dirname" && echo "目錄已刪除" || echo "刪除失敗" - send_stats "刪除目錄" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一級選單目錄" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "請輸入要創建的文件名:" filename - touch "$filename" && echo "文件已創建" || echo "創建失敗" - send_stats "創建文件" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "請輸入要編輯的文件名:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "編輯文件" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "請輸入文件名:" filename - read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$filename" && echo "權限已修改" || echo "修改失敗" - send_stats "修改文件權限" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "請輸入當前文件名:" current_name - read -e -p "請輸入新文件名:" new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失敗" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "請輸入要刪除的文件名:" filename - rm -f "$filename" && echo "文件已刪除" || echo "刪除失敗" - send_stats "刪除文件" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "請輸入要壓縮的文件/目錄名:" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "壓縮失敗" - send_stats "壓縮文件/目錄" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓的文件名 (.tar.gz):" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "已解壓$filename" || echo "解壓失敗" - send_stats "解壓文件/目錄" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "請輸入要移動的文件或目錄路徑:" src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "錯誤: 文件或目錄不存在。" - send_stats "移動文件或目錄失敗: 文件或目錄不存在" + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "錯誤: 請輸入目標路徑。" - send_stats "移動文件或目錄失敗: 目標路徑未指定" + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "文件或目錄已移動到$dest_path" || echo "移動文件或目錄失敗" - send_stats "移動文件或目錄" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "請輸入要復制的文件或目錄路徑:" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "錯誤: 文件或目錄不存在。" - send_stats "複製文件或目錄失敗: 文件或目錄不存在" + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "錯誤: 請輸入目標路徑。" - send_stats "複製文件或目錄失敗: 目標路徑未指定" + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # 使用 -r 選項以遞歸方式複制目錄 - cp -r "$src_path" "$dest_path" && echo "文件或目錄已復製到$dest_path" || echo "複製文件或目錄失敗" - send_stats "複製文件或目錄" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "請輸入要傳送的文件路徑:" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "錯誤: 文件不存在。" - send_stats "傳送文件失敗: 文件不存在" + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "请输入远端服务器IP: " remote_ip if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" - send_stats "傳送文件失敗: 未輸入遠端服務器IP" + echo "错误: 请输入远端服务器IP。" + send_stats "传送文件失败: 未输入远端服务器IP" continue fi - read -e -p "請輸入遠端服務器用戶名 (默認root):" remote_user + read -e -p "请输入远端服务器用户名 (默认root): " remote_user remote_user=${remote_user:-root} - read -e -p "請輸入遠端服務器密碼:" -s remote_password + read -e -p "请输入远端服务器密码: " -s remote_password echo if [ -z "$remote_password" ]; then - echo "錯誤: 請輸入遠端服務器密碼。" - send_stats "傳送文件失敗: 未輸入遠端服務器密碼" + echo "错误: 请输入远端服务器密码。" + send_stats "传送文件失败: 未输入远端服务器密码" continue fi - read -e -p "請輸入登錄端口 (默認22):" remote_port + read -e -p "请输入登录端口 (默认22): " remote_port remote_port=${remote_port:-22} - # 清除已知主機的舊條目 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp傳輸文件 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "腳本已經最新$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13656,15 +13925,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自動更新已開啟,每天凌晨2點腳本會自動更新!${gl_bai}" - send_stats "開啟腳本自動更新" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自動更新已關閉${gl_bai}" - send_stats "關閉腳本自動更新" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -13686,37 +13955,37 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion腳本工具箱 v$sh_v" -echo -e "命令行輸入${gl_huang}k${gl_kjlan}可快速啟動腳本${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系統信息查詢" -echo -e "${gl_kjlan}2. ${gl_bai}系統更新" -echo -e "${gl_kjlan}3. ${gl_bai}系統清理" -echo -e "${gl_kjlan}4. ${gl_bai}基礎工具" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}測試腳本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云腳本合集" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}應用市場" -echo -e "${gl_kjlan}12. ${gl_bai}後台工作區" -echo -e "${gl_kjlan}13. ${gl_bai}系統工具" -echo -e "${gl_kjlan}14. ${gl_bai}服務器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}廣告專欄" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻獸帕魯開服腳本" +echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}腳本更新" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出腳本" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "請輸入你的選擇:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系統更新" ; linux_update ;; - 3) clear ; send_stats "系統清理" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; @@ -13731,13 +14000,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻獸帕魯開服腳本" ; cd ~ + p) send_stats "幻兽帕鲁开服脚本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "無效的輸入!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -13745,68 +14014,68 @@ done k_info() { -send_stats "k命令參考用例" +send_stats "k命令参考用例" echo "-------------------" -echo "視頻介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令參考用例:" -echo "啟動腳本 k" -echo "安裝軟件包 k install nano wget | k add nano wget | k 安裝 nano wget" -echo "卸載軟件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" -echo "更新系統 k update | k 更新" -echo "清理系統垃圾 k clean | k 清理" -echo "重裝系統面板 k dd | k 重裝" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "內核調優面板 k nhyh | k 內核優化" -echo "設置虛擬內存 k swap 2048" -echo "設置虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" -echo "系統回收站 k trash | k hsz | k 回收站" -echo "系統備份功能 k backup | k bf | k 備份" -echo "ssh遠程連接工具 k ssh | k 遠程連接" -echo "rsync遠程同步工具 k rsync | k 遠程同步" -echo "硬盤管理工具 k disk | k 硬盤管理" -echo "內網穿透(服務端) k frps" -echo "內網穿透(客戶端) k frpc" -echo "軟件啟動 k start sshd | k 啟動 sshd" -echo "軟件停止 k stop sshd | k 停止 sshd" -echo "軟件重啟 k restart sshd | k 重啟 sshd" -echo "軟件狀態查看 k status sshd | k 狀態 sshd" -echo "軟件開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" -echo "域名證書申請 k ssl" -echo "域名證書到期查詢 k ssl ps" -echo "docker環境安裝 k docker install |k docker 安裝" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker环境安装 k docker install |k docker 安装" echo "docker容器管理 k docker ps |k docker 容器" -echo "docker鏡像管理 k docker img |k docker 鏡像" -echo "LDNMP站點管理 k web" -echo "LDNMP緩存清理 k web cache" -echo "安裝WordPress k wp |k wordpress |k wp xxx.com" -echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安裝負載均衡 k loadbalance |k 負載均衡" -echo "防火牆面板 k fhq |k 防火牆" -echo "開放端口 k dkdk 8080 |k 打開端口 8080" -echo "關閉端口 k gbdk 7800 |k 關閉端口 7800" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夾 k fav | k 命令收藏夾" -echo "應用市場管理 k app" -echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # 如果沒有參數,運行交互式邏輯 + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # 如果有參數,執行相應函數 + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "安裝軟件" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸載軟件" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -13840,7 +14109,7 @@ else rsync_run) shift - send_stats "定時rsync同步" + send_stats "定时rsync同步" run_task "$@" ;; @@ -13859,7 +14128,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+端口访问该服务" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -13872,13 +14141,13 @@ else swap) shift - send_stats "快速設置虛擬內存" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "快速設置時區" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -13926,42 +14195,42 @@ else status|状态) shift - send_stats "軟件狀態查看" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "軟件啟動" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "軟件暫停" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "軟件重啟" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "軟件開機自啟" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看證書狀態" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申請證書" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申請證書" + send_stats "快速申请证书" else k_info fi @@ -13971,7 +14240,7 @@ else shift case $1 in install|安装) - send_stats "快捷安裝docker" + send_stats "快捷安装docker" install_docker ;; ps|容器) @@ -13979,7 +14248,7 @@ else docker_ps ;; img|镜像) - send_stats "快捷鏡像管理" + send_stats "快捷镜像管理" docker_image ;; *) @@ -14006,7 +14275,7 @@ else app) shift - send_stats "應用$@" + send_stats "应用$@" linux_panel "$@" ;; @@ -14016,4 +14285,3 @@ else ;; esac fi - From c8de270df5fd1544325962f48c5da510819e25d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 07:29:49 +0800 Subject: [PATCH 0133/1285] Update kejilion.sh --- cn/kejilion.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bf1361ecf..dc0846216 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -11792,8 +11793,8 @@ while true; do COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ From 0dd466a8dd4f159cf7f433d89edae12ced10e0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 07:30:22 +0800 Subject: [PATCH 0134/1285] Refactor process termination in kejilion.sh --- kejilion.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f70cab559..e8af4649c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -11792,8 +11793,8 @@ while true; do COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ From d357622eeb82b10cfe185e94dbbd304dd71cc665 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 28 Aug 2025 01:50:11 +0000 Subject: [PATCH 0135/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-28=2001:50:11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 4729 ++++++++++++++++++++++++------------------------ jp/kejilion.sh | 4717 +++++++++++++++++++++++------------------------ kr/kejilion.sh | 4729 ++++++++++++++++++++++++------------------------ tw/kejilion.sh | 4505 ++++++++++++++++++++++----------------------- 4 files changed, 9342 insertions(+), 9338 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index cab3eb64a..1b54f388d 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# Define a function to execute commands run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# Functions that collect function buried point information, record the current script version number, usage time, system version, CPU architecture, the country of the machine and the function name used by the user. They absolutely do not involve any sensitive information, please rest assured! Please believe me! +# Why do we need to design this function? The purpose is to better understand the functions that users like to use, and further optimize the functions to launch more functions that meet user needs. +# For the full text, you can search for the send_stats function call location, transparent and open source, and you can refuse to use it if you have any concerns. @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# Prompt the user to agree to the terms UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}Welcome to the Tech lion script toolbox${gl_bai}" + echo "For the first time using the script, please read and agree to the user license agreement." + echo "User License Agreement: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "Do you agree to the above terms? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "License consent" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "Rejection of permission" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "Package parameters are not provided!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}Installing$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "Unknown package manager!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}hint:${gl_bai}Insufficient disk space!" + echo "Current available space: $((available_space_mb/1024))G" + echo "Minimum demand space:${required_gb}G" + echo "The installation cannot be continued. Please clean the disk space and try again." + send_stats "Insufficient disk space" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "Package parameters are not provided!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}Uninstalling$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "Unknown package manager!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# Universal systemctl function, suitable for various distributions systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# Restart the service restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1The service has been restarted." else - echo "错误:重启 $1 服务失败。" + echo "Error: Restart$1Service failed." fi } -# 启动服务 +# Start the service start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1The service has been started." else - echo "错误:启动 $1 服务失败。" + echo "Error: Start$1Service failed." fi } -# 停止服务 +# Stop service stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1Service has been stopped." else - echo "错误:停止 $1 服务失败。" + echo "Error: Stop$1Service failed." fi } -# 查看服务状态 +# Check service status status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1The service status is displayed." else - echo "错误:无法显示 $1 服务状态。" + echo "Error: Unable to display$1Service status." fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAMESet to power on." } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}Operation completed${gl_bai}" + echo "Press any key to continue..." read -n 1 -s -r -p "" echo "" clear @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -424,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Installing docker environment...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -499,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "Docker container management" + echo "Docker container list" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "Container operation" echo "------------------------" - echo "1. 创建新的容器" + echo "1. Create a new container" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2. Start the specified container 6. Start all containers" + echo "3. Stop the specified container 7. Stop all containers" + echo "4. Delete the specified container 8. Delete all containers" + echo "5. Restart the specified container 9. Restart all containers" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11. Enter the specified container 12. View the container log" + echo "13. View container network 14. View container occupancy" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15. Turn on container port access 16. Turn off container port access" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "Create a new container" + read -e -p "Please enter the creation command:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "Start the specified container" + read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "Stop the specified container" + read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "Delete the specified container" + read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "Restart the specified container" + read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "Start all containers" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "Stop all containers" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "Delete all containers" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -564,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "Restart all containers" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "Enter the container" + read -e -p "Please enter the container name:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "View container log" + read -e -p "Please enter the container name:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "View container network" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -603,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "View container occupancy" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "Allow container port access" + read -e -p "Please enter the container name:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -619,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "Block container port access" + read -e -p "Please enter the container name:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -639,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "Docker image management" + echo "Docker image list" docker image ls echo "" - echo "镜像操作" + echo "Mirror operation" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1. Get the specified image 3. Delete the specified image" + echo "2. Update the specified image 4. Delete all images" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "Pull the mirror" + read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}Getting the image:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "Update the image" + read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}Updated image:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "Delete the mirror" + read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "Delete all images" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -685,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -753,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "Unsupported distributions:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "The operating system cannot be determined." return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}crontab is installed and the cron service is running.${gl_bai}" } @@ -774,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # Check if the configuration file exists, create the file and write the default settings if it does not exist if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # Use jq to handle updates of configuration files local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # Check whether the current configuration already has ipv6 settings local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # Update configuration and enable IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # Comparing original configuration with new configuration if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 access is currently enabled${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -809,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # Check if the configuration file exists if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}The configuration file does not exist${gl_bai}" return fi - # 读取当前配置 + # Read the current configuration local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # Use jq to handle updates of configuration files local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # Check the current ipv6 status local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # Comparing original configuration with new configuration if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 access is currently closed${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 access has been successfully closed${gl_bai}" fi } @@ -869,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "Please provide at least one port number" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # Delete existing closing rules iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # Add Open Rules if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "The port has been opened$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "The port has been opened" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "Please provide at least one port number" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # Delete existing open rules iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # Add a close rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "Port closed$port" fi done - # 删除已存在的规则(如果有) + # Delete existing rules (if any) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # Insert new rules to first iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "Port closed" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "Please provide at least one IP address or IP segment" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # Delete existing blocking rules iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # Add allow rules if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "Released IP$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "Released IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "Please provide at least one IP address or IP segment" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # Delete existing allow rules iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # Add blocking rules if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IP blocked$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IP blocked" } @@ -989,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # Turn on defense DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -999,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "Turn on DDoS defense" } -# 关闭DDoS防御 +# Turn off DDoS Defense disable_ddos_defense() { - # 关闭防御 DDoS + # Turn off defense DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1014,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "Turn off DDoS Defense" } -# 管理国家IP规则的函数 +# Functions that manage national IP rules manage_country_rules() { local action="$1" local country_code="$2" @@ -1032,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # Create if ipset does not exist if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # Download IP area file if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "Error: Download$country_codeIP zone file failed" exit 1 fi - # 将 IP 添加到 ipset + # Add IP to ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # Block IP with iptables iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "Blocked successfully$country_codeIP address" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # Create an ipset for allowed countries (if not exist) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # Download IP area file if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "Error: Download$country_codeIP zone file failed" exit 1 fi - # 删除现有的国家规则 + # Delete existing national rules iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # Add IP to ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # Only IPs in designated countries are allowed iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "Successfully only allowed$country_codeIP address" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # Delete the iptables rules for the country iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # Destroy ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "Successfully lifted$country_codeIP address restrictions" ;; *) @@ -1115,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "Advanced Firewall Management" + send_stats "Advanced Firewall Management" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "Firewall Management" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1. Open the specified port 2. Close the specified port" + echo "3. Open all ports 4. Close all ports" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5. IP whitelist 6. IP blacklist" + echo "7. Clear the specified IP" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. Allow PING 12. Disable PING" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. Start DDOS Defense 14. Turn off DDOS Defense" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15. Block specified country IP 16. Only specified country IPs are allowed" + echo "17. Release IP restrictions in designated countries" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "Please enter the open port number:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "Open a specified port" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "Please enter the closed port number:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "Close the specified port" ;; 3) - # 开放所有端口 + # Open all ports current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1163,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "Open all ports" ;; 4) - # 关闭所有端口 + # Close all ports current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1179,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "Close all ports" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IP whitelist + read -e -p "Please enter the IP or IP segment to release:" o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IP blacklist + read -e -p "Please enter the blocked IP or IP segment:" c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # Clear the specified IP + read -e -p "Please enter the cleared IP:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "Clear the specified IP" ;; 11) - # 允许 PING + # Allow PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "Allow PING" ;; 12) - # 禁用 PING + # Disable PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "Disable PING" ;; 13) enable_ddos_defense @@ -1222,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "Please enter the blocked country code (such as CN, US, JP):" country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "Allowed countries$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "Please enter the allowed country code (such as CN, US, JP):" country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "Block the country$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "Please enter the cleared country code (such as CN, US, JP):" country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "Clear the country$country_codeIP" ;; *) @@ -1256,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # Get all swap partitions in the current system local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # Iterate over and delete all swap partitions for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # Make sure /swapfile is no longer used swapoff /swapfile - # 删除旧的 /swapfile + # Delete the old /swapfile rm -f /swapfile - # 创建新的 swap 分区 + # Create a new swap partition fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1287,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "The virtual memory size has been resized to${gl_huang}${new_swap}${gl_bai}M" } @@ -1297,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# Determine whether virtual memory needs to be created [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1313,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # Get nginx version local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # Get the mysql version local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # Get the php version local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Get the redis version local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1340,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # Create necessary directories and files cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1349,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # Download the docker-compose.yml file and replace it wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # Replace in docker-compose.yml file sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1398,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP environment has been installed" echo "------------------------" ldnmp_v @@ -1415,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "Renewal task has been updated" } @@ -1452,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yumingPublic key information${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yumingPrivate key information${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}Certificate storage path${gl_bai}" + echo "Public key: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "Private key: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1469,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}Quickly apply for an SSL certificate, automatically renew your signature before expiration${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1485,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}The expiration of the applied certificate${gl_bai}" + echo "Site information Certificate expiration time" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1525,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "Successful application for domain name certificate" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "Application for domain name certificate failed" + echo -e "${gl_hong}Notice:${gl_bai}The certificate application failed. Please check the following possible reasons and try again:" + echo -e "1. Domain name spelling error ➠ Please check whether the domain name is entered correctly" + echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to this server IP" + echo -e "3. Network configuration issues ➠ If you use Cloudflare Warp and other virtual networks, please temporarily shut down" + echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open to ensure verification is accessible" + echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" + echo -e "6. Domestic registration restrictions ➠ Please confirm whether the domain name is registered in mainland China" break_end clear - echo "请再次尝试部署 $webname" + echo "Please try deploying again$webname" add_yuming install_ssltls certs_status @@ -1548,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "Domain name reuse" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1557,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -1622,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "renew$ldnmp_pods" + echo "renew${ldnmp_pods}Finish" } @@ -1642,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "Login information:" + echo "username:$dbuse" + echo "password:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "start up$ldnmp_pods" } @@ -1656,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # Check if the configuration file exists if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # Read API_TOKEN and zone_id from configuration files read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # Convert ZONE_IDS to an array ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # Prompt the user whether to clean the cache + read -e -p "Need to clean Cloudflare's cache? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF information is saved in$CONFIG_FILE, you can modify CF information later" + read -e -p "Please enter your API_TOKEN:" API_TOKEN + read -e -p "Please enter your CF username:" EMAIL + read -e -p "Please enter zone_id (multiple separated by spaces):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # Loop through each zone_id and execute the clear cache command for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "Clearing cache for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1686,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "The cache clear request has been sent." } web_cache() { - send_stats "清理站点缓存" + send_stats "Clean up site cache" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1702,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "Delete site data" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "To delete site data, please enter your domain name (multiple domain names are separated by spaces):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "Deleting the domain name:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # Convert domain name to database name dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # Check whether the database exists before deleting it to avoid errors + echo "Deleting the database:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1739,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # Decide to turn on or off WAF according to mode parameters if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # Close WAF: Add Comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "Invalid parameter: Use 'on' or 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Check nginx images and handle them according to the situation if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1802,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # Delete old definition sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # Insert a new definition before the line with "Happy publishing" awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1829,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # Delete old definition sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # Insert a new definition before the line with "Happy publishing" awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1857,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Turn on Brotli: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1871,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Close Brotli: Add comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1887,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "Invalid parameter: Use 'on' or 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Check nginx images and handle them according to the situation if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1913,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # Turn on Zstd: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1928,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # Close Zstd: Add comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1944,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "Invalid parameter: Use 'on' or 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Check nginx images and handle them according to the situation if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1975,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "Invalid parameter: Use 'on' or 'off'" return 1 fi @@ -1989,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP environment defense" while true; do check_waf_status check_cf_mode @@ -2003,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "Server website defense program${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1. Install the defense program" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5. View SSH interception record 6. View website interception record" + echo "7. View the list of defense rules 8. View real-time monitoring of logs" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11. Configure intercept parameters 12. Clear all blocked IPs" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21. cloudflare mode 22. High load on 5 seconds shield" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31. Turn on WAF 32. Turn off WAF" + echo "33. Turn on DDOS Defense 34. Turn off DDOS Defense" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. Uninstall the defense program" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2081,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban defense program has been uninstalled" ;; 11) @@ -2096,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "cloudflare mode" + echo "Go to the upper right corner of the cf background, select the API token on the left, and obtain the Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "Enter CF account number:" cfuser + read -e -p "Enter the Global API Key for CF:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2115,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "Cloudflare mode is configured to view intercept records in the cf background, site-security-events" ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "High load on 5 seconds shield" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "Get CF parameters:" + echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" + echo -e "Go to the bottom right of the cf background domain name summary page to get${gl_huang}Region ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "Enter CF account number:" cfuser + read -e -p "Enter the Global API Key for CF:" cftoken + read -e -p "Enter the region ID of the domain name in CF:" cfzonID cd ~ install jq bc @@ -2146,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "High load automatic shield opening script has been added" else - echo "自动开盾脚本已存在,无需添加" + echo "Automatic shield script already exists, no need to add it" fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "Site WAF is enabled" + send_stats "Site WAF is enabled" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "Site WAF has been closed" + send_stats "Site WAF has been closed" ;; 33) @@ -2188,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# Get the current worker_processes setting value current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# Set mode information according to value if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2207,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # Check whether zstd is enabled and not commented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Check if brotli is enabled and not commented if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # Check if gzip is enabled and not commented if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2237,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "Optimize LDNMP environment" + echo -e "Optimize LDNMP environment${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. Standard mode 2. High performance mode (recommended 2H4G or above)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3. Turn on gzip compression 4. Turn off gzip compression" + echo "5. Turn on br compression 6. Turn off br compression" + echo "7. Turn on zstd compression 8. Turn off zstd compression" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "Site standard mode" - # nginx调优 + # nginx tuning sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # php tuning wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # php tuning wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2275,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysql tuning wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2287,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP environment has been set to standard mode" ;; 2) - send_stats "站点高性能模式" + send_stats "Site high performance mode" - # nginx调优 + # nginx tuning sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # php tuning wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # php tuning wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2315,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysql tuning wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2325,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP environment has been set to high performance mode" ;; 3) @@ -2385,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker="${gl_lv}${gl_bai} installed" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker="${gl_hui}${gl_bai} is not installed" # fi # } @@ -2395,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "Access address:" ip_address @@ -2433,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # Get the container creation time and image name local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # Extract mirror warehouses and tags local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # The default label is latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # Add support for official images [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Get image publishing time from Docker Hub API local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # Verify the time of acquisition if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # Compare timestamps if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2476,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # Get the IP address of the container local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2486,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # Check and block all other IPs if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # Check and release the specified IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # Check and release the local network 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # Check and block all other IPs if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # Check and release the specified IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # Check and release the local network 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2523,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ ports have been blocked from accessing the service" save_iptables_rules } @@ -2534,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # Get the IP address of the container local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2544,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # Clear rules that block all other IPs if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # Clear the rules for releasing the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # Clear the rules for release local network 127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2563,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # Clear rules that block all other IPs if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # Clear the rules for releasing the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # Clear the rules for release local network 127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2584,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+ports have been allowed to access the service" save_iptables_rules } @@ -2598,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "Error: Please provide the port number and the IP that is allowed to access." + echo "Usage: block_host_port " return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # Denied all other IP access if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # Allow specified IP access if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # Allow local access if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2625,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # Denied all other IP access if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # Allow specified IP access if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # Allow local access if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # Allow traffic for established and related connections if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ ports have been blocked from accessing the service" save_iptables_rules } @@ -2657,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "Error: Please provide the port number and the IP that is allowed to access." + echo "Usage: clear_host_port_rules " return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # Clear rules that block all other IP access if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # Clear rules that allow native access if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # Clear rules that allow specified IP access if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # Clear rules that block all other IP access if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # Clear rules that allow native access if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # Clear rules that allow specified IP access if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+ports have been allowed to access the service" save_iptables_rules } @@ -2726,7 +2727,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}管理" +send_stats "${docker_name}manage" while true; do clear @@ -2746,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. Add domain name access 6. Delete domain name access" + echo "7. Allow IP+ port access 8. Block IP+ port access" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2770,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameInstalled" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "Install$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2785,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameInstalled" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "renew$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2799,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "The app has been uninstalled" + send_stats "uninstall$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}Domain access settings" + send_stats "${docker_name}Domain access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "Domain name format example.com does not come with https://" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "Allow IP access${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "Block IP access${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2859,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. Add domain name access 6. Delete domain name access" + echo "7. Allow IP+ port access 8. Block IP+ port access" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2894,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}Domain access settings" + send_stats "${docker_name}Domain access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "Domain name format example.com does not come with https://" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "Allow IP access${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "Block IP access${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2994,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# Functions that check whether the session exists session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# Loop until a non-existent session name is found while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# Create a new tmux session tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3079,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "Restarted" reboot ;; *) - echo "已取消" + echo "Canceled" ;; esac @@ -3126,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "Unable to install LDNMP environment again" + echo -e "${gl_huang}hint:${gl_bai}The website construction environment is installed. No need to install again!" break_end linux_ldnmp fi @@ -3137,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "Install LDNMP environment" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}The LDNMP environment is not installed, start installing the LDNMP environment...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3154,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Install nginx environment" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginx is not installed, start installing nginx environment...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3168,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "nginx has been installed" +echo -e "Current version:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3180,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "Please install the LDNMP environment first" ldnmp_install_all fi @@ -3190,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "Please install nginx environment first" nginx_install_all fi @@ -3201,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "Yours$webnameBuilt!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webnameThe installation information is as follows:" } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "Yours$webnameBuilt!" echo "https://$yuming" } @@ -3222,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3263,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "Please enter your anti-generation IP:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "Please enter your anti-generation port:" port fi nginx_install_status install_ssltls @@ -3296,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3356,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMP site management" + echo "LDNMP environment" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "Site:${output}Certificate expiration time" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3374,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "database:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "Site Directory" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "operate" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1. Apply for/update the domain name certificate 2. Change the site domain name" + echo "3. Clean up the site cache 4. Create an associated site" + echo "5. View access log 6. View error log" + echo "7. Edit global configuration 8. Edit site configuration" + echo "9. Manage site database 10. View site analysis report" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. Delete the specified site data" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "Apply for a domain name certificate" + read -e -p "Please enter your domain name:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3411,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "Change the site domain name" + echo -e "${gl_hong}Highly recommended:${gl_bai}First back up the entire site data and then change the site domain name!" + read -e -p "Please enter the old domain name:" oddyuming + read -e -p "Please enter the new domain name:" yuming install_certbot install_ssltls certs_status - # mysql替换 + # mysql replacement add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3437,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # Website directory replacement mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3458,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "Create an associated site" + echo -e "Associate a new domain name for the existing site for access" + read -e -p "Please enter the existing domain name:" oddyuming + read -e -p "Please enter the new domain name:" yuming install_certbot install_ssltls certs_status @@ -3475,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "View access log" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "View error log" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "Edit global configuration" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "Edit site configuration" + read -e -p "To edit the site configuration, please enter the domain name you want to edit:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3503,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "View site data" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3534,21 +3535,21 @@ fi install_panel() { -send_stats "${panelname}管理" +send_stats "${panelname}manage" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}It is a popular and powerful operation and maintenance management panel nowadays." + echo "Official website introduction:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. Install 2. Management 3. Uninstall" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) check_disk_space 1 @@ -3557,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}Install" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}控制" + send_stats "${panelname}control" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}uninstall" ;; *) break @@ -3614,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "Install the frp server" + # Generate random ports and credentials local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3636,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # Output generated information ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "Parameters required for client deployment" + echo "Service IP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRP panel information" + echo "FRP panel address: http://$ipv4_address:$dashboard_port" + echo "FRP panel username:$dashboard_user" + echo "FRP panel password:$dashboard_pwd" echo open_port 8055 8056 @@ -3656,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "Install the frp client" + read -e -p "Please enter the external network docking IP:" server_addr + read -e -p "Please enter the external network docking token:" token echo mkdir -p /home/frp @@ -3678,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "Add FRP intranet service" + # Prompt the user to enter the service name and forwarding information + read -e -p "Please enter the service name:" service_name + read -e -p "Please enter the forwarding type (tcp/udp) [Enter default tcp]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "Please enter the intranet IP [Enter default 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "Please enter the intranet port:" local_port + read -e -p "Please enter the external network port:" remote_port - # 将用户输入写入配置文件 + # Write user input to configuration file cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3698,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # Output generated information + echo "Serve$service_nameAdded successfully to frpc.toml" docker restart frpc @@ -3710,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "Delete the frp intranet service" + # Prompt the user to enter the service name that needs to be deleted + read -e -p "Please enter the service name that needs to be deleted:" service_name + # Use sed to delete the service and its related configurations sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "Serve$service_nameDeleted successfully from frpc.toml" docker restart frpc @@ -3725,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # Print the header printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3746,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # If there is service information, print the current service before processing the new service if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3755,11 +3756,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # Update the current service name if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # Clear the previous value local_ip="" local_port="" remote_port="" @@ -3788,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # Print the information for the last service if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3801,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# Get the FRP server port get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# Generate access address generate_access_urls() { - # 首先获取所有端口 + # Get all ports first get_frp_ports - # 检查是否有非 8055/8056 的端口 + # Check if there are ports other than 8055/8056 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3820,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # Show title and content only when there is a valid port if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP service external access address:" - # 处理 IPv4 地址 + # Process IPv4 address for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # Process IPv6 addresses (if present) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3840,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # Handling HTTPS configuration for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3867,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRP server" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3875,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP server$check_frp $update_status" + echo "Build an FRP intranet penetration service environment to expose devices without public IP to the Internet" + echo "Official website introduction: https://github.com/fatedier/frp/" + echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5. Domain name access for intranet service 6. Delete domain name access" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. Allow IP+ port access 8. Block IP+ port access" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. Refresh service status 0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) install jq grep ss @@ -3901,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "The FRP server has been installed" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3911,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "The FRP server has been updated" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3922,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "The app has been uninstalled" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "Reverse intranet penetration service into domain name access" + send_stats "FRP access to external domain names" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "Please enter your intranet penetration service port:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "Domain name format example.com does not come with https://" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "Allow IP access" + read -e -p "Please enter the port to be released:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "Block IP access" + echo "If you have accessed the anti-generation domain name, you can use this function to block IP+ port access, which is more secure." + read -e -p "Please enter the port you need to block:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "Refresh the FRP service status" + echo "FRP service status has been refreshed" ;; *) @@ -3965,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRP Client" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3973,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP Client$check_frp $update_status" + echo "Docking with the server, after docking, you can create intranet penetration service to the Internet access" + echo "Official website introduction: https://github.com/fatedier/frp/" + echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3984,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. Add external services 5. Delete external services 6. Configure services manually" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) install jq grep ss @@ -3998,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "The FRP client has been installed" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4008,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "The FRP client has been updated" ;; 3) @@ -4019,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "The app has been uninstalled" ;; 4) @@ -4065,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "yt-dlp download tool" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp is a powerful video download tool that supports thousands of sites including YouTube, Bilibili, Twitter, etc." + echo -e "Official website address: https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "Downloaded video list:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(None yet)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. Single video download 6. Batch video download 7. Custom parameter download" + echo "8. Download as MP3 audio 9. Delete the video directory 10. Cookie management (under development)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "Please enter the option number:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "Installing yt-dlp..." + echo "Installing yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "The installation is complete. Press any key to continue..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "Update yt-dlp..." + echo "Update yt-dlp..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "Update completed. Press any key to continue..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "Uninstalling yt-dlp..." + echo "Uninstalling yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "Uninstall is complete. Press any key to continue..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "Single video download" + read -e -p "Please enter the video link:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "After the download is complete, press any key to continue..." ;; 6) - send_stats "批量视频下载" + send_stats "Batch video download" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# Enter multiple video link addresses\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "Now start batch download..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4134,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "The batch download is completed, press any key to continue..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "Custom video download" + read -e -p "Please enter the full yt-dlp parameter (excluding yt-dlp):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "After the execution is completed, press any key to continue..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3 download" + read -e -p "Please enter the video link:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "The audio download is completed, press any key to continue..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "Delete video" + read -e -p "Please enter the name of the delete video:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4194,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# Fix dpkg interrupt problem fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4203,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}System update...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4222,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "Unknown package manager!" return fi } @@ -4230,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}Cleaning up the system...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4259,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "Clean the package manager cache..." apk cache clean - echo "删除系统日志..." + echo "Delete the system log..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "Delete APK cache..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "Delete temporary files..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4283,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "Delete the system log..." rm -rf /var/log/* - echo "删除临时文件..." + echo "Delete temporary files..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "Clean up unused dependencies..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "Clean the package manager cache..." pkg clean -y - echo "删除系统日志..." + echo "Delete the system log..." rm -rf /var/log/* - echo "删除临时文件..." + echo "Delete temporary files..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "Unknown package manager!" return fi return @@ -4339,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "Optimize DNS" while true; do clear - echo "优化DNS地址" + echo "Optimize DNS address" echo "------------------------" - echo "当前DNS地址" + echo "Current DNS address" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1. Foreign DNS optimization:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2. Domestic DNS optimization:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3. Manually edit DNS configuration" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "Please enter your selection:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4366,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "Foreign DNS optimization" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4374,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "Domestic DNS optimization" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "Manually edit DNS configuration" ;; *) break @@ -4402,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # If PasswordAuthentication is found, set to yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # If found PubkeyAuthentication is set to yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4416,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # If neither PasswordAuthentication nor PubkeyAuthentication matches, set the default value if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4427,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # Backup SSH configuration files cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4440,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "The SSH port has been modified to:$new_port" sleep 1 @@ -4458,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "The private key information has been generated. Be sure to copy and save it.${gl_huang}${ipv4_address}_ssh.key${gl_bai}File for future SSH login" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4470,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}ROOT private key login is enabled, ROOT password login has been closed, reconnection will take effect${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "Please enter your SSH public key contents (usually starting with 'ssh-rsa' or 'ssh-ed25519'):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}Error: The public key content was not entered.${gl_bai}" return 1 fi @@ -4498,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}The public key has been successfully imported, the ROOT private key login has been enabled, the ROOT password login has been closed, and the reconnection will take effect${gl_bai}" } @@ -4507,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "Set your ROOT password" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}ROOT login is set up!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "Reinstall the system" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4537,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "Initial username after reinstallation:${gl_huang}root${gl_bai}Initial password:${gl_huang}LeitboGi0ro${gl_bai}Initial port:${gl_huang}22${gl_bai}" + echo -e "Press any key to continue..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "Initial username after reinstallation:${gl_huang}Administrator${gl_bai}Initial password:${gl_huang}Teddysun.com${gl_bai}Initial port:${gl_huang}3389${gl_bai}" + echo -e "Press any key to continue..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "Initial username after reinstallation:${gl_huang}root${gl_bai}Initial password:${gl_huang}123@@@${gl_bai}Initial port:${gl_huang}22${gl_bai}" + echo -e "Press any key to continue..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "Initial username after reinstallation:${gl_huang}Administrator${gl_bai}Initial password:${gl_huang}123@@@${gl_bai}Initial port:${gl_huang}3389${gl_bai}" + echo -e "Press any key to continue..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." + echo -e "${gl_hui}Thanks to the script support of leitbogioro and bin456789!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4587,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. openSUSE Tumbleweed 36. fnos Feiniu public beta version" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "Please select the system to reinstall:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "Reinstall debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4609,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "Reinstall debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "Reinstall debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "Reinstall debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "Reinstall ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "Reinstall ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Reinstall ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "Reinstall ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4660,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Reinstall rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4668,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Reinstall rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4676,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "Reinstall alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4684,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "Reinstall alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4692,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Reinstall oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4700,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Reinstall oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4708,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Reinstall fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4716,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Reinstall fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4724,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "Reinstall centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4732,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "Reinstall centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4740,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "Reinstall alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4748,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "Reinstall arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4756,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "Reinstall kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4764,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Reinstall openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4772,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "Reinstall opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4780,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "Reload flying cow" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4789,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Reinstall windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4797,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Reinstall Windows 10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Reinstall Windows 7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4811,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Reinstall windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Reinstall windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Reinstall windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4833,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Reinstall windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4850,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "bbrv3 management" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4863,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "You have installed xanmod's BBRv3 kernel" + echo "Current kernel version:$kernel_version" echo "" - echo "内核管理" + echo "Kernel Management" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. Update the BBRv3 kernel 2. Uninstall the BBRv3 kernel" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) @@ -4883,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # Step 3: Add a repository echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4892,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "The XanMod kernel has been updated. Take effect after restart" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4902,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "The XanMod kernel is uninstalled. Take effect after restart" server_reboot ;; @@ -4915,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "Set up BBR3 acceleration" + echo "Video introduction: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "Only support Debian/Ubuntu" + echo "Please back up the data and will enable BBR3 for you to upgrade the Linux kernel." echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in [Yy]) @@ -4929,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "The current environment does not support it, only supports Debian and Ubuntu systems" break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "Unable to determine the operating system type" break_end linux_Settings fi @@ -4945,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # Step 3: Add a repository echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4956,17 +4957,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "XanMod kernel is installed and BBR3 is enabled successfully. Take effect after restart" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac fi @@ -4975,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Import ELRepo GPG public key + echo "Import the ELRepo GPG public key..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # Detect system version local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # Make sure we run on a supported operating system if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "Unsupported operating systems:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # Print detected operating system information + echo "Operating system detected:$os_name $os_version" + # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Install ELRepo repository configuration (version 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Install ELRepo repository configuration (version 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Install ELRepo repository configuration (version 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "Unsupported system versions:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Enable the ELRepo kernel repository and install the latest mainline kernel + echo "Enable the ELRepo kernel repository and install the latest mainline kernel..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "The ELRepo repository configuration is installed and updated to the latest mainline kernel." server_reboot } @@ -5016,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "Red Hat Kernel Management" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "You have installed the elrepo kernel" + echo "Current kernel version:$kernel_version" echo "" - echo "内核管理" + echo "Kernel Management" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Update the elrepo kernel 2. Uninstall the elrepo kernel" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Update the Red Hat kernel" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "The elrepo kernel is uninstalled. Take effect after restart" + send_stats "Uninstall the Red Hat kernel" server_reboot ;; @@ -5059,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "Please back up the data and will upgrade the Linux kernel for you" + echo "Video introduction: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "Only support Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" + echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if conditions permit and upgrade the production environment with caution!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Upgrade the Red Hat kernel" server_reboot ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac fi @@ -5089,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}Update the virus database...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5099,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "Please specify the directory to scan." return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}Scanning directory $@...${gl_bai}" - # 构建 mount 参数 + # Build mount parameters local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # Build clamscan command parameters local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5120,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Execute Docker commands docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5129,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@ Scan is completed, virus report is stored${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}If there is a virus, please${gl_huang}scan.log${gl_lv}Search for FOUND keyword in the file to confirm the location of the virus${gl_bai}" } @@ -5142,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "Virus Scan Management" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav virus scanning tool" + echo "Video introduction: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "It is an open source antivirus software tool, mainly used to detect and remove various types of malware." + echo "Including viruses, Trojan horses, spyware, malicious scripts and other harmful software." echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. Full disk scan${gl_bai} ${gl_huang}2. Scan the important directory${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "Full disk scan" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5167,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "Important directory scan" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5175,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "Custom directory scanning" + read -e -p "Please enter the directory to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5193,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# High-performance mode optimization function optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}Switch to${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}Optimize network settings...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5219,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}Optimize cache management...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}Other optimizations...${gl_bai}" + # Disable large transparent pages to reduce latency echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # Disable NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# Equalization mode optimization function optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}Switch to equalization mode...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}Optimize network settings...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5260,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}Optimize cache management...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}Other optimizations...${gl_bai}" + # Restore transparent page echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# Restore the default settings function restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}Restore to default settings...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}Restore file descriptor...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}Restore virtual memory...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}Restore network settings...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}Restore cache management...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}Restore CPU settings...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}Restore other optimizations...${gl_bai}" + # Restore transparent page echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# Website building optimization function optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}Switch to the website building optimization mode...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}Optimize network settings...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5343,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}Optimize cache management...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}Other optimizations...${gl_bai}" + # Disable large transparent pages to reduce latency echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # Disable NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5363,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux kernel tuning management" + echo "Optimization of kernel parameters in Linux system" + echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "A variety of system parameter tuning modes are provided, and users can choose and switch according to their own usage scenarios." + echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." + echo "2. Balanced optimization mode: Balance between performance and resource consumption, suitable for daily use." + echo "3. Website optimization mode: Optimize for the website server to improve concurrent connection processing capabilities, response speed and overall performance." + echo "4. Live broadcast optimization mode: Optimize the special needs of live broadcast streaming to reduce latency and improve transmission performance." + echo "5. Game server optimization mode: Optimize for game servers to improve concurrent processing capabilities and response speed." + echo "6. Restore the default settings: Restore the system settings to the default configuration." echo "--------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "High performance mode optimization" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "Balanced mode optimization" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "Website optimization model" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "Live streaming optimization" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "Game server optimization" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "Restore default settings" ;; *) break @@ -5445,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" hash -r break_end @@ -5454,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "Unsupported systems:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "Unsupported systems, system type cannot be recognized." break_end fi } @@ -5474,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "Switch system language" while true; do clear - echo "当前系统语言: $LANG" + echo "Current system language:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. English 2. Simplified Chinese 3. Traditional Chinese" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "Switch to English" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "Switch to Simplified Chinese" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "Switch to Traditional Chinese" ;; *) break @@ -5518,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}Change is completed. Reconnect SSH to view changes!${gl_bai}" hash -r break_end @@ -5529,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "Command line beautification tool" while true; do clear - echo "命令行美化工具" + echo "Command line beautification tool" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5542,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) @@ -5589,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "System Recycling Station" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5604,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "Current recycling bin${trash_status}" + echo -e "After enabling, the files deleted by rm will first enter the recycling bin to prevent the mistaken deletion of important files!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "The recycling bin is empty" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1. Enable the Recycle Bin 2. Close the Recycle Bin" + echo "3. Restore content 4. Clear the recycling bin" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) @@ -5622,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "The Recycle Bin is enabled and deleted files will be moved to the Recycle Bin." sleep 2 ;; 2) @@ -5630,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "The recycling bin is closed and the file will be deleted directly." sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "Enter the file name to restore:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restoreRestored to the home directory." else - echo "文件不存在。" + echo "The file does not exist." fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "Confirm to clear the recycling bin? [y/n]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "The recycling bin has been cleared." fi ;; *) @@ -5657,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# Create a backup create_backup() { - send_stats "创建备份" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # Prompt the user to enter the backup directory + echo "Create a backup example:" + echo "- Backup a single directory: /var/www" + echo "- Backup multiple directories: /etc /home /var/log" + echo "- Direct Enter will use the default directory (/etc /usr /home)" + read -r -p "Please enter the directory to back up (multiple directories are separated by spaces, and if you enter directly, use the default directory):" input - # 如果用户没有输入目录,则使用默认目录 + # If the user does not enter a directory, use the default directory if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5681,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # Separate the directory entered by the user into an array by spaces IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # Generate backup file prefix local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # Extract directory name and remove slashes dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # Remove the last underscore local PREFIX=${PREFIX%_} - # 生成备份文件名 + # Generate backup file name local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # Print the directory selected by the user + echo "The backup directory you selected is:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # Create a backup + echo "Creating a backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # Check if the command is successful if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "The backup was created successfully:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "Backup creation failed!" exit 1 fi } -# 恢复备份 +# Restore backup restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "Restore backup" + # Select the backup you want to restore + read -e -p "Please enter the backup file name to restore:" BACKUP_NAME - # 检查备份文件是否存在 + # Check if the backup file exists if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "The backup file does not exist!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "Recovering backup$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "Backup and restore successfully!" else - echo "备份恢复失败!" + echo "Backup recovery failed!" exit 1 fi } -# 列出备份 +# List backups list_backups() { - echo "可用的备份:" + echo "Available backups:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# Delete backup delete_backup() { - send_stats "删除备份" + send_stats "Delete backup" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "Please enter the backup file name to delete:" BACKUP_NAME - # 检查备份文件是否存在 + # Check if the backup file exists if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "The backup file does not exist!" exit 1 fi - # 删除备份 + # Delete backup rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "The backup was deleted successfully!" else - echo "备份删除失败!" + echo "Backup deletion failed!" exit 1 fi } -# 备份主菜单 +# Backup main menu linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "System backup function" + echo "System backup function" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1. Create a backup 2. Restore a backup 3. Delete the backup" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Press Enter to continue..." done } @@ -5805,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# Show connection list list_connections() { - echo "已保存的连接:" + echo "Saved connection:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# Add a new connection add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "Add a new connection" + echo "Example to create a new connection:" + echo "- Connection name: my_server" + echo "- IP address: 192.168.1.100" + echo "- Username: root" + echo "- Port: 22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "Please enter the connection name:" name + read -e -p "Please enter your IP address:" ip + read -e -p "Please enter the username (default: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "Please enter the port number (default: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "Please select the authentication method:" + echo "1. Password" + echo "2. Key" + read -e -p "Please enter the selection (1/2):" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "Please enter your password:" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "Please paste the key content (press press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # If the input is empty and the key content already contains the beginning, the input ends if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # If it is the first line or the key content has been entered, continue to add if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # Check if it is the key content if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5863,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "Invalid choice!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "The connection is saved!" } -# 删除连接 +# Delete a connection delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "Delete a connection" + read -e -p "Please enter the connection number to delete:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "Error: The corresponding connection was not found." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # If the connection is using a key file, delete the key file if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "The connection has been deleted!" } -# 使用连接 +# Use connection use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "Use connection" + read -e -p "Please enter the connection number to use:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "Error: The corresponding connection was not found." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "Connecting to$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # Connect with a key ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "Connection failed! Please check the following:" + echo "1. Is the key file path correct?$password_or_key" + echo "2. Whether the key file permissions are correct (should be 600)." + echo "3. Whether the target server allows login using the key." fi else - # 使用密码连接 + # Connect with a password if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "Error: sshpass is not installed, please install sshpass first." + echo "Installation method:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "Connection failed! Please check the following:" + echo "1. Whether the username and password are correct." + echo "2. Whether the target server allows password login." + echo "3. Whether the SSH service of the target server is running normally." fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "ssh remote connection tool" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # Check if the configuration file and key directory exist, and if it does not exist, create it if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5957,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSH Remote Connection Tool" + echo "Can be connected to other Linux systems via SSH" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. Create a new connection 2. Use a connection 3. Delete a connection" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "Invalid selection, please try again." ;; esac done } @@ -5987,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# List available hard disk partitions list_partitions() { - echo "可用的硬盘分区:" + echo "Available hard disk partitions:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# Mount the partition mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "Mount the partition" + read -e -p "Please enter the partition name to be mounted (for example, sda1):" PARTITION - # 检查分区是否存在 + # Check if the partition exists if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "The partition does not exist!" return fi - # 检查分区是否已经挂载 + # Check if the partition is already mounted if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "The partition is already mounted!" return fi - # 创建挂载点 + # Create a mount point MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # Mount the partition mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "Partition mount successfully:$MOUNT_POINT" else - echo "分区挂载失败!" + echo "Partition mount failed!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# Uninstall the partition unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "Uninstall the partition" + read -e -p "Please enter the partition name (for example, sda1):" PARTITION - # 检查分区是否已经挂载 + # Check if the partition is already mounted MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "The partition is not mounted!" return fi - # 卸载分区 + # Uninstall the partition umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "Partition uninstallation successfully:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "Partition uninstallation failed!" fi } -# 列出已挂载的分区 +# List mounted partitions list_mounted_partitions() { - echo "已挂载的分区:" + echo "Mounted partition:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# Format partition format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "Format partition" + read -e -p "Please enter the partition name to format (for example, sda1):" PARTITION - # 检查分区是否存在 + # Check if the partition exists if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "The partition does not exist!" return fi - # 检查分区是否已经挂载 + # Check if the partition is already mounted if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "The partition has been mounted, please uninstall it first!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # Select a file system type + echo "Please select the file system type:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "Please enter your selection:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "Invalid choice!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # Confirm formatting + read -e -p "Confirm formatting partition /dev/$PARTITIONfor$FS_TYPEIs it? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "The operation has been cancelled." return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # Format partition + echo "Formatting partition /dev/$PARTITIONfor$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "The partition format was successful!" else - echo "分区格式化失败!" + echo "Partition formatting failed!" fi } -# 检查分区状态 +# Check partition status check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "Check partition status" + read -e -p "Please enter the partition name to check (for example sda1):" PARTITION - # 检查分区是否存在 + # Check if the partition exists if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "The partition does not exist!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # Check partition status + echo "Check partition /dev/$PARTITIONStatus:" fsck "/dev/$PARTITION" } -# 主菜单 +# Main Menu disk_manager() { - send_stats "硬盘管理功能" + send_stats "Hard disk management function" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "Hard disk partition management" + echo -e "${gl_huang}This function is internally tested during the test period, please do not use it in the production environment.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1. Mount the partition 2. Uninstall the partition 3. View mounted partition" + echo "4. Format the partition 5. Check the partition status" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6145,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Press Enter to continue..." done } -# 显示任务列表 +# Show task list list_tasks() { - echo "已保存的同步任务:" + echo "Saved synchronization tasks:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# Add a new task add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "Add a new synchronization task" + echo "Create a new synchronization task example:" + echo "- Task name: backup_www" + echo "- Local Directory: /var/www" + echo "- Remote address: user@192.168.1.100" + echo "- Remote Directory: /backup/www" + echo "- Port number (default 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "Please enter the task name:" name + read -e -p "Please enter the local directory:" local_path + read -e -p "Please enter the remote directory:" remote_path + read -e -p "Please enter the remote user @IP:" remote + read -e -p "Please enter the SSH port (default 22):" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "Please select the authentication method:" + echo "1. Password" + echo "2. Key" + read -e -p "Please select (1/2):" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "Please enter your password:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "Please paste the key content (press press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # If the input is empty and the key content already contains the beginning, the input ends if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # If it is the first line or the key content has been entered, continue to add if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # Check if it is the key content if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6210,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "Invalid key content!" return fi ;; *) - echo "无效的选择!" + echo "Invalid choice!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "Please select the synchronization mode:" + echo "1. Standard mode (-avz)" + echo "2. Delete the target file (-avz --delete)" + read -e -p "Please select (1/2):" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "Invalid selection, use default -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "Task saved!" } -# 删除任务 +# Delete a task delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "Delete synchronization tasks" + read -e -p "Please enter the task number to delete:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "Error: The corresponding task was not found." return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # If the task is using a key file, delete the key file if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "Task deleted!" } run_task() { - send_stats "执行同步任务" + send_stats "Perform synchronization tasks" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # Analyze parameters local direction="push" # 默认是推送到远端 local num @@ -6277,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # If there is no incoming task number, prompt the user to enter if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "Please enter the task number to be executed:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "Error: The task was not found!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # Adjust source and target path according to synchronization direction if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "Pulling synchronization to local:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "Push synchronization to the remote end:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # Add SSH connection common parameters local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "Error: sshpass is not installed, please install sshpass first." + echo "Installation method:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # Check whether the key file exists and whether the permissions are correct if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "Error: The key file does not exist:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "Warning: The key file permissions are incorrect, and are being repaired..." chmod 600 "$password_or_key" fi @@ -6329,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "Synchronization is complete!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "Synchronization failed! Please check the following:" + echo "1. Is the network connection normal?" + echo "2. Is the remote host accessible?" + echo "3. Is the authentication information correct?" + echo "4. Do local and remote directories have correct access permissions" fi } -# 创建定时任务 +# Create a timed task schedule_task() { - send_stats "添加同步定时任务" + send_stats "Add synchronization timing tasks" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "Please enter the task number to be synchronized regularly:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "Error: Please enter a valid task number!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "Please select the timed execution interval:" + echo "1) Execute once an hour" + echo "2) Perform once a day" + echo "3) Execute once a week" + read -e -p "Please enter options (1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6362,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "Error: Please enter a valid option!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # Check if the same task already exists if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "Error: The timing synchronization of this task already exists!" return fi - # 创建到用户的 crontab + # Create a crontab to the user (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "The timing task has been created:$cron_job" } -# 查看定时任务 +# View scheduled tasks view_tasks() { - echo "当前的定时任务:" + echo "Current timing tasks:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# Delete timing tasks delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "Delete synchronization timing tasks" + read -e -p "Please enter the task number to delete:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "Error: Please enter a valid task number!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "Deleted task number$numTiming tasks" } -# 任务管理主菜单 +# Task Management Main Menu rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "Rsync remote synchronization tool" + echo "Synchronization between remote directories supports incremental synchronization, efficient and stable." echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1. Create a new task 2. Delete a task" + echo "3. Perform local synchronization to the remote end 4. Perform remote synchronization to the local end" + echo "5. Create a timing task 6. Delete a timing task" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6430,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "Invalid selection, please try again." ;; esac - read -e -p "按回车键继续..." + read -e -p "Press Enter to continue..." done } @@ -6447,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "System information query" ip_address @@ -6497,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "System information query" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}Host Name:${gl_bai}$hostname" + echo -e "${gl_kjlan}System version:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux version:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU architecture:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU model:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}Number of CPU cores:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU frequency:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU occupancy:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}System load:${gl_bai}$load" + echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" + echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" + echo -e "${gl_kjlan}Hard disk occupation:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" + echo -e "${gl_kjlan}Total send:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}Operator:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4 address:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6 address:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS address:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}Geographical location:${gl_bai}$country $city" + echo -e "${gl_kjlan}System time:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}Runtime:${gl_bai}$runtime" echo @@ -6544,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats "Basic Tools" + echo -e "Basic tools" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo super management permission tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" + echo -e "${gl_kjlan}5. ${gl_bai}htop system monitoring tool${gl_kjlan}6. ${gl_bai}iftop network traffic monitoring tool" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP compression decompression tool${gl_kjlan}8. ${gl_bai}tar GZ compression decompression tool" + echo -e "${gl_kjlan}9. ${gl_bai}tmux multi-channel background running tool${gl_kjlan}10. ${gl_bai}ffmpeg video encoding live streaming tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tools${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}range file management tool" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk occupation viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" + echo -e "${gl_kjlan}15. ${gl_bai}vim text editor${gl_kjlan}16. ${gl_bai}nano text editor${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git version control system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screen Guarantee${gl_kjlan}22. ${gl_bai}Train screen security" + echo -e "${gl_kjlan}26. ${gl_bai}Tetris game${gl_kjlan}27. ${gl_bai}Snake-eating game" + echo -e "${gl_kjlan}28. ${gl_bai}Space Invader Game" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}All installations (excluding screen savers and games)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}Uninstall all" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}Install the specified tool${gl_kjlan}42. ${gl_bai}Uninstall the specified tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" curl --help - send_stats "安装curl" + send_stats "Install curl" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" wget --help - send_stats "安装wget" + send_stats "Install wget" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" sudo --help - send_stats "安装sudo" + send_stats "Install sudo" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" socat -h - send_stats "安装socat" + send_stats "Install socat" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "Install htop" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "Install iftop" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" unzip - send_stats "安装unzip" + send_stats "Install unzip" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" tar --help - send_stats "安装tar" + send_stats "Install tar" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" tmux --help - send_stats "安装tmux" + send_stats "Install tmux" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "The tool has been installed and the usage method is as follows:" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "Install ffmpeg" ;; 11) @@ -6656,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "Install btop" ;; 12) clear @@ -6665,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "Install ranger" ;; 13) clear @@ -6674,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "Install ncdu" ;; 14) clear @@ -6683,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "Install fzf" ;; 15) clear @@ -6692,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "Install vim" ;; 16) clear @@ -6701,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "Install nano" ;; @@ -6712,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "Install git" ;; 21) @@ -6720,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "Install cmatrix" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "Install sl" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "Install bastet" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "Install nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Install ninvaders" ;; 31) clear - send_stats "全部安装" + send_stats "Install all" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "Install all (excluding games and screen savers)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "Uninstall all" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "Please enter the installed tool name (wget curl sudo htop):" installname install $installname - send_stats "安装指定软件" + send_stats "Install the specified software" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "Please enter the uninstalled tool name (htop ufw tmux cmatrix):" removename remove $removename - send_stats "卸载指定软件" + send_stats "Uninstall the specified software" ;; 0) @@ -6788,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -6802,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "bbr management" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "Current TCP blocking algorithm:$congestion_algorithm $queue_algorithm" echo "" - echo "BBR管理" + echo "BBR Management" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. Turn on BBRv3 2. Turn off BBRv3 (restarts)" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "Alpine enable bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6867,21 +6868,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}当前备份列表:${NC}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + echo -e "${BLUE}Current backup list:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "No backup" } # ---------------------------- - # 备份 + # Backup # ---------------------------- backup_docker() { - send_stats "Docker备份" + send_stats "Docker backup" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${YELLOW}Backing up Docker container...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers install tar jq gzip install_docker @@ -6892,7 +6893,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}No container found${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6900,28 +6901,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "# Automatically generated restore script" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # Record the path of the packaged Compose project to avoid duplicate packaging declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${GREEN}Backup container:$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${BLUE}Detected$cYes docker-compose container${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -p "The compose directory is not detected, please enter the path manually:" project_dir fi - # 如果该 Compose 项目已经打包过,跳过 + # If the Compose project has been packaged, skip it if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" continue fi @@ -6929,137 +6930,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose recovery:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${GREEN}Compose project [$project_name] Packed:${project_dir}${NC}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${RED}docker-compose.yml not found, skip this container...${NC}" fi else - # 普通容器备份卷 + # Normal container backup volume local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷: $path" + echo "Packing rolls:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 端口 + # port local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 环境变量 + # Environment variables local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 卷映射 + # Volume Mapping local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 镜像 + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo -e "\n# Restore container:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 备份 /home/docker 下的所有文件(不含子目录) + # Backup all files under /home/docker (excluding subdirectories) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${BLUE}Backup the files under /home/docker...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}The file under /home/docker has been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}Backup is complete:${BACKUP_DIR}${NC}" + echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 还原 + # reduction # ---------------------------- restore_docker() { - send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Docker restore" + read -p "Please enter the backup directory to restore:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${BLUE}Start the restore operation...${NC}" install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # ------------------------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -p "The original path was not found, please enter the restore directory path:" original_path - # 检查该 compose 项目的容器是否已经在运行 + # Check if the container for the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "Please enter a new restore path:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${GREEN}Compose project [$project_name] Decompressed to:$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${GREEN}Compose project [$project_name] Restore is complete!${NC}" fi done - # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + # ------------------------- + echo -e "${BLUE}Check and restore a normal Docker container...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${GREEN}Processing container:$container${NC}" - # 检查容器是否已经存在且正在运行 + # Check if the container already exists and is running if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${YELLOW}Container [$container] is running, skip restore...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information was not found, skip:$container${NC}"; continue; } - # 端口映射 + # Port Mapping PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 环境变量 + # Environment variables ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷数据恢复 + # Volume Mapping + Volume Data Recovery VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7070,32 +7071,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢复卷数据: $VOL_SRC" + echo "Recover volume data:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 删除已存在但未运行的容器 + # Delete existing but not running containers if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${YELLOW}Container [$container] Exist but not running, delete the old container...${NC}" docker rm -f "$container" fi - # 启动容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # Start the container + echo "Execute the restore command: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for normal containers was found${NC}" - # 还原 /home/docker 下的文件 + # Restore the file under /home/docker if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${BLUE}Restore the file under /home/docker...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${GREEN}The file under /home/docker has been restored${NC}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${YELLOW}No backup of the file under /home/docker was found, skip...${NC}" fi @@ -7103,66 +7104,66 @@ docker_ssh_migration() { # ---------------------------- - # 迁移 + # migrate # ---------------------------- migrate_docker() { - send_stats "Docker迁移" + send_stats "Docker migration" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + read -p "Please enter the backup directory to migrate:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -p "Target server IP:" TARGET_IP + read -p "Target server SSH username:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${YELLOW}Transfer backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密钥登录 + # Log in with a key scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 删除备份 + # Delete backup # ---------------------------- delete_backup() { - send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Docker backup file deletion" + read -p "Please enter the backup directory to delete:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" } # ---------------------------- - # 主菜单 + # Main Menu # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "Docker backup migration and restore" while true; do clear echo "------------------------" - echo -e "Docker备份/迁移/还原工具" + echo -e "Docker backup/migration/restore tool" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" - echo -e "2. 迁移docker项目" - echo -e "3. 还原docker项目" - echo -e "4. 删除docker项目的备份文件" + echo -e "1. Backup the docker project" + echo -e "2. Migrate docker projects" + echo -e "3. Restore the docker project" + echo -e "4. Delete the backup file of the docker project" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0. Return to the previous menu" echo "------------------------" - read -p "请选择: " choice + read -p "Please select:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${RED}Invalid option${NC}" ;; esac break_end done @@ -7179,38 +7180,38 @@ linux_docker() { while true; do clear - # send_stats "docker管理" - echo -e "Docker管理" + # send_stats "docker management" + echo -e "Docker Management" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Install and update Docker environment${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}View Docker global status${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker container management${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker image management" + echo -e "${gl_kjlan}5. ${gl_bai}Docker Network Management" + echo -e "${gl_kjlan}6. ${gl_bai}Docker volume management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}Clean useless docker containers and mirror network data volumes" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Replace Docker source" + echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" + echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}Backup/Migration/Restore Docker Environment" + echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Install docker environment" install_add_docker ;; @@ -7221,22 +7222,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "Docker global status" + echo "Docker version" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "Docker image:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "Docker container:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Docker volume:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Docker Network:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7251,8 +7252,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "Docker Network Management" + echo "Docker network list" echo "------------------------------------------------------------" docker network ls echo "" @@ -7276,36 +7277,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "Network operation" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1. Create a network" + echo "2. Join the Internet" + echo "3. Exit the network" + echo "4. Delete the network" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "Create a network" + read -e -p "Set a new network name:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "Join the Internet" + read -e -p "Join the network name:" dockernetwork + read -e -p "Those containers are added to the network (multiple container names are separated by spaces):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "Join the Internet" + read -e -p "Exit network name:" dockernetwork + read -e -p "Those containers exit the network (multiple container names are separated by spaces):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7314,8 +7315,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "Delete the network" + read -e -p "Please enter the network name to delete:" dockernetwork docker network rm $dockernetwork ;; @@ -7329,29 +7330,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "Docker volume management" + echo "Docker volume list" docker volume ls echo "" - echo "卷操作" + echo "Volume operation" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1. Create a new volume" + echo "2. Delete the specified volume" + echo "3. Delete all volumes" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "Create a new volume" + read -e -p "Set the new volume name:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "Enter the delete volume name (please separate multiple volume names with spaces):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7360,7 +7361,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "Delete all volumes" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7369,7 +7370,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -7382,7 +7383,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "Docker cleaning" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7391,13 +7392,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "Docker source" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7413,13 +7414,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker v6 open" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker v6 level" docker_ipv6_off ;; @@ -7430,7 +7431,7 @@ linux_docker() { 20) clear - send_stats "Docker卸载" + send_stats "Docker uninstall" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7442,7 +7443,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -7451,7 +7452,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -7468,151 +7469,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats "Test script collection" + echo -e "Test script collection" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP and unlock status detection" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT Unlock Status Detection" + echo -e "${gl_kjlan}2. ${gl_bai}Region streaming media unlock test" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu streaming media unlock detection" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality physical examination script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}Network speed measurement" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace three network backhaul delay routing test" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace Three-network backhaul line test" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed three-net speed measurement" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace Specifies IP backhaul test script" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three-network line test" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunction speed test script" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality Network Quality Physical Examination Script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}Hardware performance testing" + echo -e "${gl_kjlan}21. ${gl_bai}yabs performance testing" + echo -e "${gl_kjlan}22. ${gl_bai}iicu/gb5 CPU performance test script" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}Comprehensive test" + echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" + echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx Fusion Monster Review${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "ChatGPT unlock status detection" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "Region streaming media unlock test" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "yeahwu streaming media unlock detection" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "xykt_IP quality physical examination script" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "Besttrace three network backhaul delay routing test" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "mtr_trace three network return line test" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "Superspeed three-net speed measurement" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace fast backhaul test script" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "nxtrace specifies IP backhaul test script" + echo "List of IPs that can be referenced" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "Beijing Telecom: 219.141.136.12" + echo "Beijing Unicom: 202.106.50.1" + echo "Beijing Mobile: 221.179.155.161" + echo "Shanghai Telecom: 202.96.209.133" + echo "Shanghai Unicom: 210.22.97.1" + echo "Shanghai Mobile: 211.136.112.200" + echo "Guangzhou Telecom: 58.60.188.222" + echo "Guangzhou Unicom: 210.21.196.6" + echo "Guangzhou Mobile: 120.196.165.24" + echo "Chengdu Telecom: 61.139.2.69" + echo "Chengdu Unicom: 119.6.6.6" + echo "Chengdu Mobile: 211.137.96.205" + echo "Hunan Telecom: 36.111.200.100" + echo "Hunan Unicom: 42.48.16.100" + echo "Hunan Mobile: 39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "Enter a specified IP:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "ludashi2020 three-network line test" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "i-abc multifunction speed test script" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "Network quality test script" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "yabs performance testing" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "iicu/gb5 CPU performance test script" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "bench performance test" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "Spiritysdx Fusion Monster Review" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7622,7 +7623,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -7638,51 +7639,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud Script Collection" + echo -e "Oracle Cloud Script Collection" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}Install idle machine active script" + echo -e "${gl_kjlan}2. ${gl_bai}Uninstall idle machine active script" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD reinstall system script" + echo -e "${gl_kjlan}4. ${gl_bai}Detective R start script" + echo -e "${gl_kjlan}5. ${gl_bai}Turn on ROOT password login mode" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6 recovery tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "Active script: CPU occupies 10-20% memory occupies 20%" + read -e -p "Are you sure to install it? (Y/N):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # Set default values local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # Prompt the user to enter the number of CPU cores and occupancy percentage, and if entered, use the default value. + read -e -p "Please enter the number of CPU cores [default:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "Please enter the CPU usage percentage range (for example, 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "Please enter the memory usage percentage [default:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "Please enter the Speedtest interval time (seconds) [default:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # Run Docker container docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7690,14 +7691,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloud Installation Active Script" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -7705,20 +7706,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloud Uninstall Active Script" ;; 3) clear - echo "重装系统" + echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." + read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "Please select the system to reinstall: 1. Debian12 | 2. Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7730,28 +7731,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "Invalid selection, please re-enter." ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "Please enter your reinstalled password:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud Reinstall System Script" ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "This feature is in the development stage, so stay tuned!" ;; 5) clear @@ -7761,15 +7762,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "This function is provided by the master jhb, thanks to him!" + send_stats "ipv6 fix" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -7790,7 +7791,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}The environment has been installed${gl_bai}container:${gl_lv}$container_count${gl_bai}Mirror:${gl_lv}$image_count${gl_bai}network:${gl_lv}$network_count${gl_bai}roll:${gl_lv}$volume_count${gl_bai}" fi } @@ -7811,7 +7812,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}The environment is installed${gl_bai}Site:$outputdatabase:$db_output" fi fi @@ -7839,31 +7840,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "LDNMP website building" + echo -e "${gl_huang}LDNMP website building" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}Install LDNMP environment${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install the Kadao Cloud Desktop" + echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Film and Television Station${gl_huang}6. ${gl_bai}Install a Unicorn Digital Card Network" + echo -e "${gl_huang}7. ${gl_bai}Install the flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" + echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Customize dynamic site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" + echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" + echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" + echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" + echo -e "${gl_huang}30. ${gl_bai}Customize static site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up the entire site data" + echo -e "${gl_huang}33. ${gl_bai}Timed remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environment${gl_huang}36. ${gl_bai}Optimize LDNMP environment" + echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall LDNMP environment" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}Return to main menu" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in @@ -7877,10 +7878,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # Discuz Forum webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7903,21 +7904,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "Database address: mysql" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Table prefix: discuz_" ;; 4) clear - # 可道云桌面 + # Kedao Cloud Desktop webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7939,20 +7940,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "Database address: mysql" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Database name:$dbname" + echo "redis host: redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7978,24 +7979,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "Database address: mysql" + echo "Database port: 3306" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Database prefix: mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "Log in to the background address after installation is successful" echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # One-legged counting card webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8016,34 +8017,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "Database address: mysql" + echo "Database port: 3306" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "redis address: redis" + echo "Redis password: Not filled in by default" + echo "Redis port: 6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "Website url: https://$yuming" + echo "Background login path: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "Username: admin" + echo "Password: admin" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "If red error0 appears in the upper right corner when logging in, please use the following command:" + echo "I am also very angry that the unicorn number card is so troublesome, and there will be such problems!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # Flarum Forum webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8080,12 +8081,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "Database address: mysql" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Table prefix: flarum_" + echo "Administrator information is set by yourself" ;; @@ -8093,8 +8094,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8118,11 +8119,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "Database prefix: typecho_" + echo "Database address: mysql" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Database name:$dbname" ;; @@ -8131,8 +8132,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8157,18 +8158,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "Database address: mysql" + echo "Database port: 3306" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8185,10 +8186,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] Upload PHP source code" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" + read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8198,20 +8199,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] The path where index.php is located" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "Please enter the path of index.php, similar to (/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] Please select the PHP version" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. The latest version of php | 2. php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8222,15 +8223,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "Invalid selection, please re-enter." ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}] Install the specified extension" echo "-------------" - echo "已经安装的扩展" + echo "Installed extensions" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8240,25 +8241,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}] Edit site configuration" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "Press any key to continue, and you can set the site configuration in detail, such as pseudo-static contents, etc." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}] Database Management" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. I build a new site 2. I build an old site and have a database backup:" use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." + read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8268,10 +8269,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "Database import table data" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "Database import completed" ;; *) echo @@ -8283,12 +8284,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "Database address: mysql" + echo "Database name:$dbname" + echo "username:$dbuse" + echo "password:$dbusepasswd" + echo "Table prefix:$prefix" + echo "Administrator login information is set by yourself" ;; @@ -8301,10 +8302,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "Please enter the jump domain name:" reverseproxy nginx_install_status install_ssltls certs_status @@ -8326,7 +8327,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ ports have been blocked from accessing the service" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8337,11 +8338,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "Domain name format:${gl_huang}google.com${gl_bai}" + read -e -p "Please enter your anti-generation domain name:" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8361,8 +8362,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming nginx_install_status install_ssltls @@ -8384,8 +8385,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming nginx_install_status install_ssltls @@ -8402,8 +8403,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming nginx_install_status install_ssltls @@ -8436,8 +8437,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "Install$webname" + echo "Start deployment$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8454,10 +8455,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}] Upload static source code" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" + read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8467,12 +8468,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] The path where index.html is located" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "Please enter the path to index.html, similar to (/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8497,21 +8498,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP environment backup" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "The backup file has been created: /home/$backup_filename" + read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "Please enter the remote server IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "Error: Please enter the remote server IP." continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8519,9 +8520,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "The file has been transferred to the remote server home directory." else - echo "未找到要传送的文件。" + echo "The file to be transferred was not found." fi break ;; @@ -8529,7 +8530,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac done @@ -8537,9 +8538,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "Timed remote backup" + read -e -p "Enter the remote server IP:" useip + read -e -p "Enter the remote server password:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8549,18 +8550,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1. Weekly backup 2. Daily backup" + read -e -p "Please enter your selection:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "Select the day of the week for your weekly backup (0-6, 0 represents Sunday):" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "Select the time for daily backup (hours, 0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8574,19 +8575,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP environment restoration" + echo "Available site backups" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # If the user does not enter the file name, use the latest compressed package if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8596,7 +8597,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8605,7 +8606,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "No compression package was found." fi ;; @@ -8623,11 +8624,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "Update LDNMP environment" + echo "Update LDNMP environment" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "Discover new version of components" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8647,13 +8648,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. Update nginx 2. Update mysql 3. Update php 4. Update redis" echo "------------------------" - echo "5. 更新完整环境" + echo "5. Update the complete environment" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8662,7 +8663,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "Please enter${ldnmp_pods}Version number (such as: 8.0 8.3 8.4 9.0) (Enter to get the latest version):" version local version=${version:-latest} cd /home/web/ @@ -8673,13 +8674,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "renew$ldnmp_pods" + echo "renew${ldnmp_pods}Finish" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "Please enter${ldnmp_pods}Version number (such as: 7.4 8.0 8.1 8.2 8.3) (Enter to get the latest version):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8712,8 +8713,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "renew$ldnmp_pods" + echo "renew${ldnmp_pods}Finish" ;; 4) @@ -8724,15 +8725,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "renew$ldnmp_pods" + echo "renew${ldnmp_pods}Finish" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "Completely update the LDNMP environment" cd /home/web/ docker compose down --rmi all @@ -8758,7 +8759,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "Uninstall LDNMP environment" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8772,7 +8773,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -8782,7 +8783,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "Invalid input!" esac break_end @@ -8802,12 +8803,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "Application Market" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # Set the color with loop for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8816,70 +8817,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager Visual Panel" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" + echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" + echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" + echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome Adware${gl_kjlan}18. ${color18}onlyoffice online office OFFICE" + echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" + echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" + echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" + echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI Chat Aggregation Website" + echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" + echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}Mouse Management Panel${gl_kjlan}42. ${color42}Nexte remote connection tool" + echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub Acceleration Station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}Prometheus Monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVE Chicken Panel${gl_kjlan}52. ${color52}DPanel Container Management Panel" + echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" + echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" + echo -e "${gl_kjlan}65. ${color65}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" + echo -e "${gl_kjlan}67. ${color67}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL Certificate Management Platform" + echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot Chat Robot Framework" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden Password Manager${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV Private Movie" + echo -e "${gl_kjlan}75. ${color75}Melody Music Elf${gl_kjlan}76. ${color76}Online DOS old games" + echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki Intelligent Document Management System" + echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" + echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tools" + echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" + echo -e "${gl_kjlan}87. ${color87}SyncTV movie watching artifact${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser File Manager" + echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" + echo -e "${gl_kjlan}95. ${color95}paperless document management platform" + echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice fi case $sub_choice in @@ -9032,8 +9033,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9066,7 +9067,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "Build Nezha" local app_id="7" local docker_name="nezha-dashboard" @@ -9075,20 +9076,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezha Monitoring$check_docker $update_status" + echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" + echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1. Use" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) @@ -9145,7 +9146,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "Build a post office" clear install telnet local app_id="9" @@ -9155,43 +9156,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "Post Office Services$check_docker $update_status" + echo "poste.io is an open source mail server solution." + echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "端口检测" + echo "Port detection" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}port$portCurrently available${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}port$portNot currently available${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "Access address:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "Parse these DNS records first" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9201,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "Press any key to continue..." read -n 1 -s -r -p "" install jq @@ -9220,9 +9221,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "poste.io has been installed" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "You can access poste.io using the following address:" echo "https://$yuming" echo "" @@ -9245,9 +9246,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "poste.io has been installed" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "You can access poste.io using the following address:" echo "https://$yuming" echo "" ;; @@ -9258,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "The app has been uninstalled" ;; *) @@ -9292,7 +9293,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -9302,7 +9303,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "rocket.chat has been installed" check_docker_app_ip } @@ -9312,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -9396,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -9410,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -9555,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "Build a Thunder Pool" local app_id="19" local docker_name=safeline-mgt @@ -9563,20 +9564,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "Thunder Pool Service$check_docker" + echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." + echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1. Install 2. Update 3. Reset Password 4. Uninstall" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) @@ -9586,7 +9587,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "The Thunder Pool WAF panel has been installed" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9599,7 +9600,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "Thunder Pool WAF panel has been updated" check_docker_app_ip ;; 3) @@ -9610,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9729,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10018,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10071,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoya Family Bucket" clear install_docker check_disk_space 1 @@ -10275,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "Installed" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "The initial username and password are: admin" } docker_app_update() { @@ -10295,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -10382,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVE Chicken" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10502,7 +10503,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -10517,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -10545,7 +10546,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -10560,7 +10561,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -10568,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -10589,17 +10590,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "Initial username: admin" + echo "Initial password: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "The app has been updated" } @@ -10609,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -10656,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -10672,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -10934,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "Set the LibreTV login password:" app_passwd docker run -d \ --name libretv \ @@ -10968,9 +10969,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password - read -e -p "输入授权码: " shouquanma + read -e -p "Set login username:" admin + read -e -p "Set the login user password:" admin_password + read -e -p "Enter the authorization code:" shouquanma mkdir -p /home/docker/moontv @@ -10986,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -11000,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11073,8 +11074,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "Set login username:" app_use + read -e -p "Set login password:" app_passwd docker run -d \ --name xunlei \ @@ -11171,11 +11172,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # Download the official docker-compose and env files curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # Generate random keys and passwords local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11184,17 +11185,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # Add administrator account information echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # Start the container docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -11204,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # Keep the original variable source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11221,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11271,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11289,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "set up${docker_name}The login key (sk-staring letters and numbers combinations) such as: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11393,7 +11394,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -11406,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11567,7 +11568,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + echo "Create an initial user or administrator. Please set the following username and password and whether you are an administrator." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11619,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -11633,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11708,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "Set login username:" app_use + read -e -p "Set login password:" app_passwd docker run -d \ --name ${docker_name} \ @@ -11757,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "已经安装完成" + echo "Installed" check_docker_app_ip } @@ -11771,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "应用已卸载" + echo "The app has been uninstalled" } docker_app_plus @@ -11788,12 +11789,12 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -p "Please enter the number of clients to form the network (default 5):" COUNT COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ @@ -11833,7 +11834,7 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" + echo "Generate QR code:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' @@ -11843,11 +11844,11 @@ while true; do sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" - echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}All outputs are provided by each client. The usage method is as follows:${gl_bai}" + echo -e "${gl_lv}1. Download wg's APP on your mobile phone, scan the QR code above to quickly connect to the network${gl_bai}" + echo -e "${gl_lv}2. Download the Windows client and copy the configuration code to connect to the network.${gl_bai}" + echo -e "${gl_lv}3. Linux uses scripts to deploy WG clients and copy configuration code to connect to the network.${gl_bai}" + echo -e "${gl_lv}Official client download method: https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11875,16 +11876,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # Create a directory (if it does not exist) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "请粘贴你的客户端配置,连续按两次回车保存:" + echo "Please paste your client configuration and press Enter twice in a row to save:" - # 初始化变量 + # Initialize variables input="" empty_line_count=0 - # 逐行读取用户输入 + # Read user input line by line while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -11897,10 +11898,10 @@ while true; do fi done - # 写入配置文件 + # Write to the configuration file echo "$input" > "$CONFIG_FILE" - echo "客户端配置已保存到 $CONFIG_FILE" + echo "Client configuration has been saved to$CONFIG_FILE" docker run -d \ --name wireguardc \ @@ -11933,21 +11934,21 @@ while true; do b) clear - send_stats "全部应用备份" + send_stats "All applications backup" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "The backup file has been created: /$backup_filename" + read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "Please enter the remote server IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "Error: Please enter the remote server IP." continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11955,14 +11956,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "The file has been transferred to the remote server/root directory." else - echo "未找到要传送的文件。" + echo "The file to be transferred was not found." fi break ;; *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + echo "Note: Currently, the backup only includes docker projects, and does not include data backup of website building panels such as Pagoda and 1panel." break ;; esac @@ -11972,29 +11973,29 @@ while true; do r) root_use - send_stats "全部应用还原" - echo "可用的应用备份" + send_stats "All applications restore" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用户没有输入文件名,使用最新的压缩包 + # If the user does not enter the file name, use the latest compressed package if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." else - echo "没有找到压缩包。" + echo "No compression package was found." fi ;; @@ -12017,35 +12018,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "Backend workspace" + echo -e "Backend workspace" + echo -e "The system will provide you with a workspace that can be run on the backend, which you can use to perform long-term tasks." + echo -e "Even if you disconnect SSH, tasks in the workspace will not be interrupted, and tasks in the background will be resident." + echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "List of currently existing workspaces" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}Workspace No. 1" + echo -e "${gl_kjlan}2. ${gl_bai}Workspace No. 2" + echo -e "${gl_kjlan}3. ${gl_bai}Workspace No. 3" + echo -e "${gl_kjlan}4. ${gl_bai}Workspace No. 4" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}6. ${gl_bai}Workspace No. 6" + echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" + echo -e "${gl_kjlan}8. ${gl_bai}Workspace No. 8" + echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}Create/enter the workspace" + echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" + echo -e "${gl_kjlan}24. ${gl_bai}Delete the specified workspace" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in @@ -12053,7 +12054,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; @@ -12061,63 +12062,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "Start the workspace$SESSION_NAME" tmux_run ;; @@ -12129,21 +12130,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH resident mode" + echo -e "SSH resident mode${tmux_sshd_status}" + echo "After SSH connection is enabled, it will directly enter the resident mode and return to the previous working state." echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. Turn on 2. Turn off" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "Please enter your selection:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "Start the workspace$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# Automatically enter the tmux session\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12159,29 +12160,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "Please enter the name of the workspace you created or entered, such as 1001 kj001 work1:" SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "Custom workspace" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "Please enter the command you want to execute in the background, such as: curl -fsSL https://get.docker.com | sh:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "Inject commands into the background workspace" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "Please enter the name of the workspace you want to delete:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "Delete the workspace" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -12206,54 +12207,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats "System Tools" + echo -e "System Tools" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Modify the login password" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" + echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify the SSH connection port" + echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}One-click reinstallation system${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account to create a new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" + echo -e "${gl_kjlan}13. ${gl_bai}User Management${gl_kjlan}14. ${gl_bai}User/Password Generator" + echo -e "${gl_kjlan}15. ${gl_bai}System time zone adjustment${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" + echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" + echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tool${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}File Manager" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}Switch system language${gl_kjlan}32. ${gl_bai}Command line beautification tool${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}Set up a system recycling bin${gl_kjlan}34. ${gl_bai}System backup and recovery" + echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" + echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" + echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and Security" + echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "Please enter your shortcut key (enter 0 to exit):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "Shortcut keys are set" + send_stats "Script shortcut keys have been set" break_end linux_Settings done @@ -12261,34 +12262,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "Set your login password" + echo "Set your login password" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "root password mode" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "py version management" + echo "Python version management" + echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "This feature seamlessly installs any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "Recommended version: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "Query more versions: https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "Enter the python version number you want to install (enter 0 to exit):" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "Script PY Management" break_end linux_Settings fi @@ -12321,7 +12322,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "Unknown package manager!" return fi @@ -12350,55 +12351,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" + send_stats "Switch script PY version" ;; 5) root_use - send_stats "开放端口" + send_stats "Open port" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "All ports are open" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "Modify SSH port" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # Read the current SSH port number local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # Print the current SSH port number + echo -e "The current SSH port number is:${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "Numbers with port numbers ranging from 1 to 65535. (Enter 0 to exit)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # Prompt the user to enter a new SSH port number + read -e -p "Please enter the new SSH port number:" new_port - # 判断端口号是否在有效范围内 + # Determine whether the port number is within the valid range if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH port has been modified" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "Exit SSH port modification" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "The port number is invalid, please enter a number between 1 and 65535." + send_stats "Invalid SSH port input" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "The input is invalid, please enter the number." + send_stats "Invalid SSH port input" break_end fi done @@ -12417,8 +12418,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "New users disable root" + read -e -p "Please enter the new username (enter 0 to exit):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12433,49 +12434,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "The operation has been completed." ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "Set v4/v6 priority" while true; do clear - echo "设置v4/v6优先级" + echo "Set v4/v6 priority" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "Current network priority settings:${gl_huang}IPv4${gl_bai}priority" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "Current network priority settings:${gl_huang}IPv6${gl_bai}priority" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 priority 2. IPv6 priority 3. IPv6 repair tool" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "Choose a preferred network:" choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "Switched to IPv4 priority" + send_stats "Switched to IPv4 priority" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "This function is provided by the master jhb, thanks to him!" + send_stats "ipv6 fix" ;; *) @@ -12493,43 +12494,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "Set up virtual memory" while true; do clear - echo "设置虚拟内存" + echo "Set up virtual memory" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "Current virtual memory:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. Assign 1024M 2. Assign 2048M 3. Assign 4096M 4. Custom size" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "Please enter your selection:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G virtual memory has been set" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G virtual memory has been set" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G virtual memory has been set" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "Please enter the virtual memory size (unit M):" new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "Custom virtual memory has been set" ;; *) @@ -12542,8 +12543,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "User Management" + echo "User List" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12554,62 +12555,62 @@ EOF echo "" - echo "账户操作" + echo "Account operation" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. Create a normal account 2. Create a premium account" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. Give the highest permissions 4. Cancel the highest permissions" echo "------------------------" - echo "5. 删除账号" + echo "5. Delete the account" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # Prompt the user to enter a new username + read -e -p "Please enter a new username:" new_username - # 创建新用户并设置密码 + # Create a new user and set a password useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "The operation has been completed." ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # Prompt the user to enter a new username + read -e -p "Please enter a new username:" new_username - # 创建新用户并设置密码 + # Create a new user and set a password useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # Grant new users sudo permissions echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作已完成。" + echo "The operation has been completed." ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "Please enter your username:" username + # Grant new users sudo permissions echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "Please enter your username:" username + # Remove user's sudo permissions from sudoers file sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "Please enter the username to delete:" username + # Delete the user and its home directory userdel -r "$username" ;; @@ -12622,50 +12623,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "User Information Generator" + echo "Random username" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "Random username$i: $username" done echo "" - echo "随机姓名" + echo "Random name" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # Generate 5 random user names for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "Random user name$i: $user_name" done echo "" - echo "随机UUID" + echo "Random UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "Random UUID$i: $uuid" done echo "" - echo "16位随机密码" + echo "16-bit random password" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "Random password$i: $password" done echo "" - echo "32位随机密码" + echo "32-bit random password" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "Random password$i: $password" done echo "" @@ -12673,46 +12674,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "Change time zone" while true; do clear - echo "系统时间信息" + echo "System time information" - # 获取当前系统时区 + # Get the current system time zone local timezone=$(current_timezone) - # 获取当前系统时间 + # Get the current system time local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # Show time zone and time + echo "Current system time zone:$timezone" + echo "Current system time:$current_time" echo "" - echo "时区切换" + echo "Time zone switching" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "Asia" + echo "1. Shanghai time in China 2. Hong Kong time in China" + echo "3. Tokyo time in Japan 4. Seoul time in South Korea" + echo "5. Singapore time 6. Kolkata time in India" + echo "7. Dubai time in the UAE 8. Sydney time in Australia" + echo "9. Time in Bangkok, Thailand" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "Europe" + echo "11. London time in the UK 12. Paris time in France" + echo "13. Berlin time, Germany 14. Moscow time, Russia" + echo "15. Utrecht time in the Netherlands 16. Madrid time in Spain" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "America" + echo "21. Western Time 22. Eastern Time" + echo "23. Canadian time 24. Mexican time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC Global Standard Time" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in @@ -12755,21 +12756,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "Modify the host name" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "Current host name:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "Please enter the new host name (enter 0 to exit):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Other systems, such as Debian, Ubuntu, CentOS, etc. hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12787,11 +12788,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "The host name has been changed to:$new_hostname" + send_stats "Host name has been changed" sleep 1 else - echo "已退出,未更改主机名。" + echo "Exited, hostname not changed." break fi done @@ -12799,32 +12800,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "Change the system update source" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "Select the update source area" + echo "Connect to LinuxMirrors to switch system update source" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas Regions" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "Enter your choice:" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "Default source in mainland China" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "Source of education in mainland China" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "Overseas origin" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "Canceled" ;; esac @@ -12832,62 +12833,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "Timing task management" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "Timed task list" crontab -l echo "" - echo "操作" + echo "operate" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. Add timing tasks 2. Delete timing tasks 3. Edit timing tasks" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "Please enter the execution command for the new task:" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. Monthly Tasks 2. Weekly Tasks" + echo "3. Daily tasks 4. Hourly tasks" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "Please enter your selection:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "Choose what day of each month to perform tasks? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "Choose what week to perform the task? (0-6, 0 represents Sunday):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "Choose what time to perform tasks every day? (Hours, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "Enter what minute of the hour to perform the task? (mins, 0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "Add timed tasks" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "Please enter the keywords that need to be deleted:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "Delete timing tasks" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "Edit timing tasks" ;; *) break # 跳出循环,退出菜单 @@ -12899,32 +12900,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "Local host parsing" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "Native host parsing list" + echo "If you add parse matches here, dynamic parsing will no longer be used" cat /etc/hosts echo "" - echo "操作" + echo "operate" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. Add a new parsing 2. Delete the parsing address" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "Please enter your selection:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "Please enter a new parsing record Format: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "Local host parsing has been added" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "Local host parsing and deletion" ;; *) break # 跳出循环,退出菜单 @@ -12935,7 +12936,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "ssh defense" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12947,20 +12948,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH Defense Program$check_docker" + echo "fail2ban is an SSH tool to prevent brute force" + echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. Install the defense program" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. View SSH interception records" + echo "3. Real-time log monitoring" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. Uninstall the defense program" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) install_docker @@ -12983,7 +12984,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban defense program has been uninstalled" ;; *) break @@ -12996,47 +12997,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "Current limit shutdown function" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "Current limit shutdown function" + echo "Video introduction: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "Current traffic usage, restarting the server traffic calculation will be cleared!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" + echo -e "${gl_kjlan}Total send:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # Check if the Limiting_Shut_down.sh file exists if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # Get the value of threshold_gb local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}The current set entry-station current limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}The current outbound current limit threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}Current limit shutdown function is not enabled${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "The system will detect whether the actual traffic reaches the threshold every minute, and the server will be automatically shut down after it arrives!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. Turn on the current limit shutdown function 2. Deactivate the current limit shutdown function" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "Please enter your selection:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # Enter the new virtual memory size + echo "If the actual server has 100G traffic, the threshold can be set to 95G and shut down the power in advance to avoid traffic errors or overflows." + read -e -p "Please enter the incoming traffic threshold (unit is G, default is 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "Please enter the traffic reset date (default reset on the 1st of each month):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13049,15 +13050,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "Current limit shutdown has been set" + send_stats "Current limit shutdown has been set" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "Current limit shutdown function has been turned off" ;; *) break @@ -13070,40 +13071,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "Private key login" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ROOT private key login mode" + echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "A key pair will be generated, a more secure way to SSH login" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. Generate a new key 2. Import an existing key 3. View the native key" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "Please enter your selection:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "Generate a new key" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "Import an existing public key" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "View the local secret key" echo "------------------------" - echo "公钥信息" + echo "Public key information" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "Private key information" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -13119,18 +13120,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "Telegram warning" + echo "TG-bot monitoring and early warning function" + echo "Video introduction: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "You need to configure the tg robot API and the user ID to receive early warnings to realize real-time monitoring and early warning of native CPU, memory, hard disk, traffic, and SSH login" + echo "After reaching the threshold, the user will be sent to the user" + echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate-${gl_bai}" + read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "Telegram warning is enabled" cd ~ install nano tmux bc jq check_crontab_installed @@ -13152,7 +13153,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # Add to ~/.profile file if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -13163,21 +13164,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-bot early warning system has been started" + echo -e "${gl_hui}You can also place the TG-check-notify.sh warning file in the root directory on other machines and use it directly!${gl_bai}" ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "Fix high-risk vulnerabilities in SSH" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13221,7 +13222,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "Command line history" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -13244,61 +13245,61 @@ EOF 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "Message board" + echo "The technology lion message board has been moved to the official community! Please leave a message in the official community!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "One-stop tuning" + echo "One-stop system optimization" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "The following will be operated and optimized" + echo "1. Update the system to the latest" + echo "2. Clean up system junk files" + echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" + echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" + echo -e "5. Open all ports" + echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" + echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "8. Automatically optimize DNS address${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" + echo -e "9. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "One-stop tuning start" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. Update the system to the latest" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. Clean up system junk files" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. Set up virtual memory${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. Set the SSH port number to${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. Open all ports" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. Open${gl_huang}BBR${gl_bai}accelerate" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set the time zone to${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13315,25 +13316,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Optimization of kernel parameters for Linux system" + echo -e "${gl_lv}One-stop system tuning has been completed${gl_bai}" ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac @@ -13341,7 +13342,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "Restart the system" server_reboot ;; 100) @@ -13357,32 +13358,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "Privacy and Security" + echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "Current status:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. Turn on collection" + echo "2. Close the collection" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "Collection has been enabled" + send_stats "Privacy and security collection has been enabled" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "Collection closed" + send_stats "Privacy and Security have been closed for collection" ;; *) break @@ -13398,11 +13399,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "Uninstall tech lion script" + echo "Uninstall tech lion script" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Will completely uninstall the kejilion script and will not affect your other functions" + read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in [Yy]) @@ -13410,16 +13411,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "The script has been uninstalled, goodbye!" break_end clear exit ;; [Nn]) - echo "已取消" + echo "Canceled" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "Invalid selection, please enter Y or N." ;; esac ;; @@ -13429,7 +13430,7 @@ EOF ;; *) - echo "无效的输入!" + echo "Invalid input!" ;; esac break_end @@ -13447,187 +13448,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "File Manager" while true; do clear - echo "文件管理器" + echo "File Manager" echo "------------------------" - echo "当前路径" + echo "Current path" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. Enter the directory 2. Create the directory 3. Modify the directory permissions 4. Rename the directory" + echo "5. Delete the directory 6. Return to the previous menu directory" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. Create a file 12. Edit a file 13. Modify file permissions 14. Rename a file" + echo "15. Delete the file" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. Compress file directory 22. Unzip file directory 23. Move file directory 24. Copy file directory" + echo "25. Pass the file to another server" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. Return to the previous menu" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "Please enter your selection:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "Please enter the directory name:" dirname + cd "$dirname" 2>/dev/null || echo "Unable to enter the directory" + send_stats "Go to the directory" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "Please enter the directory name to create:" dirname + mkdir -p "$dirname" && echo "Directory created" || echo "Creation failed" + send_stats "Create a directory" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "Please enter the directory name:" dirname + read -e -p "Please enter permissions (such as 755):" perm + chmod "$perm" "$dirname" && echo "Permissions have been modified" || echo "Modification failed" + send_stats "Modify directory permissions" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "Please enter the current directory name:" current_name + read -e -p "Please enter the new directory name:" new_name + mv "$current_name" "$new_name" && echo "Directory has been renamed" || echo "Rename failed" + send_stats "Rename the directory" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "Please enter the directory name to delete:" dirname + rm -rf "$dirname" && echo "Directory has been deleted" || echo "Deletion failed" + send_stats "Delete Directory" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "Return to the previous menu directory" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "Please enter the file name to create:" filename + touch "$filename" && echo "File created" || echo "Creation failed" + send_stats "Create a file" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "Please enter the file name to edit:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "Edit files" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "Please enter the file name:" filename + read -e -p "Please enter permissions (such as 755):" perm + chmod "$perm" "$filename" && echo "Permissions have been modified" || echo "Modification failed" + send_stats "Modify file permissions" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "Please enter the current file name:" current_name + read -e -p "Please enter a new file name:" new_name + mv "$current_name" "$new_name" && echo "File renamed" || echo "Rename failed" + send_stats "Rename the file" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "Please enter the file name to delete:" filename + rm -f "$filename" && echo "File deleted" || echo "Deletion failed" + send_stats "Delete files" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "Please enter the file/directory name to be compressed:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "Compressed to$name.tar.gz" || echo "Compression failed" + send_stats "Compressed files/directories" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "Please enter the file name (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "Decompressed$filename" || echo "Decompression failed" + send_stats "Unzip files/directories" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "Please enter the file or directory path to move:" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "Error: The file or directory does not exist." + send_stats "Failed to move a file or directory: The file or directory does not exist" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "Please enter the target path (including the new file name or directory name):" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "Error: Please enter the target path." + send_stats "Moving file or directory failed: The destination path is not specified" continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "The file or directory has been moved to$dest_path" || echo "Failed to move files or directories" + send_stats "Move files or directories" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "Error: The file or directory does not exist." + send_stats "Failed to copy a file or directory: The file or directory does not exist" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "Please enter the target path (including the new file name or directory name):" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "Error: Please enter the target path." + send_stats "Failed to copy file or directory: Destination path not specified" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # Use the -r option to copy the directory recursively + cp -r "$src_path" "$dest_path" && echo "The file or directory has been copied to$dest_path" || echo "Failed to copy a file or directory" + send_stats "Copy files or directories" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "Please enter the file path to be transferred:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "Error: The file does not exist." + send_stats "Failed to transfer the file: The file does not exist" continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "Please enter the remote server IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "Error: Please enter the remote server IP." + send_stats "File transfer failed: Remote server IP was not entered" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "Please enter the remote server username (default root):" remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "Please enter the remote server password:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "Error: Please enter the remote server password." + send_stats "File transfer failed: Remote server password not entered" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "Please enter the login port (default 22):" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # Clear old entries for known hosts ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # Transfer files using scp scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "The script is up to date$sh_v_new" break_end ~/kejilion.sh exit @@ -13925,15 +13926,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + send_stats "Turn on automatic script update" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}Automatic update is closed${gl_bai}" + send_stats "Close script automatic update" break_end ;; *) @@ -13955,41 +13956,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "Technology lion script toolbox v$sh_v" +echo -e "Command line input${gl_huang}k${gl_kjlan}Quickly start scripts${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" -echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" -echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}1. ${gl_bai}System information query" +echo -e "${gl_kjlan}2. ${gl_bai}System update" +echo -e "${gl_kjlan}3. ${gl_bai}System Cleanup" +echo -e "${gl_kjlan}4. ${gl_bai}Basic tools" +echo -e "${gl_kjlan}5. ${gl_bai}BBR Management" +echo -e "${gl_kjlan}6. ${gl_bai}Docker Management" +echo -e "${gl_kjlan}7. ${gl_bai}WARP Management" +echo -e "${gl_kjlan}8. ${gl_bai}Test script collection" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Script Collection" +echo -e "${gl_huang}10. ${gl_bai}LDNMP website building" +echo -e "${gl_kjlan}11. ${gl_bai}Application Market" +echo -e "${gl_kjlan}12. ${gl_bai}Backend workspace" +echo -e "${gl_kjlan}13. ${gl_bai}System Tools" +echo -e "${gl_kjlan}14. ${gl_bai}Server cluster control" +echo -e "${gl_kjlan}15. ${gl_bai}Advertising column" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu server opening script" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}Exit script" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "Please enter your selection:" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "System update" ; linux_update ;; + 3) clear ; send_stats "System Cleanup" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "warp management" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -14000,13 +14001,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu server opening script" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "Invalid input!" ;; esac break_end done @@ -14014,68 +14015,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "k command reference use case" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "The following is the k command reference use case:" +echo "Start script k" +echo "Install software package k install nano wget | k add nano wget | k Install nano wget" +echo "Uninstall the package k remove nano wget | k del nano wget | k uninstall nano wget | k Uninstall nano wget" +echo "Update system k update | k update" +echo "Clean system garbage k clean | k clean" +echo "Reinstall the system panel k dd | k Reinstall" +echo "bbr3 control panel k bbr3 | k bbrv3" +echo "Kernel Tuning Panel k nhyh | k kernel optimization" +echo "Set virtual memory k swap 2048" +echo "Set virtual time zone k time Asia/Shanghai | k time zone Asia/Shanghai" +echo "System Recycling Bin k trash | k hsz | k Recycling Bin" +echo "System backup function k backup | k bf | k backup" +echo "ssh remote connection tool k ssh | k remote connection" +echo "rsync remote synchronization tool k rsync | k remote synchronization" +echo "Hard disk management tool k disk | k hard disk management" +echo "Intranet penetration (server side) k frps" +echo "Intranet penetration (client) k frpc" +echo "Software start k start sshd | k start sshd" +echo "Software stop k stop sshd | k stop sshd" +echo "Software restart k restart sshd | k restart sshd" +echo "Software status view k status sshd | k status sshd" +echo "Software boot k enable docker | k autostart docke | k startup docker" +echo "Domain name certificate application k ssl" +echo "Domain name certificate expiration query k ssl ps" +echo "docker environment installation k docker install |k docker installation" +echo "docker container management k docker ps |k docker container" +echo "docker image management k docker img |k docker image" +echo "LDNMP site management k web" +echo "LDNMP cache cleanup k web cache" +echo "Install WordPress k wp |k wordpress |k wp xxx.com" +echo "Install the reverse proxy k fd |k rp |k anti-generation |k fd xxx.com" +echo "Install load balancing k loadbalance |k load balancing" +echo "Firewall panel k fhq |k firewall" +echo "Open port k dkdk 8080 |k Open port 8080" +echo "Close port k gbdk 7800 |k Close port 7800" +echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" +echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" +echo "Command favorites k fav | k command favorites" +echo "App Market Management k app" +echo "Application number quick management k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # If there are no parameters, run interactive logic kejilion_sh else - # 如果有参数,执行相应函数 + # If there are parameters, execute the corresponding function case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "Install software" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "Uninstall the software" remove "$@" ;; update|更新) @@ -14109,7 +14110,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "Timed rsync synchronization" run_task "$@" ;; @@ -14128,7 +14129,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ ports have been blocked from accessing the service" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14141,13 +14142,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "Quickly set up virtual memory" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "Quickly set time zone" set_timedate "$@" ;; @@ -14195,42 +14196,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "Software status view" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "Software startup" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "Software pause" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "Software restart" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "Software boots up" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "Check the certificate status" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "Quickly apply for a certificate" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "Quickly apply for a certificate" else k_info fi @@ -14240,15 +14241,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Quickly install docker" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "Quick container management" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "Quick mirror management" docker_image ;; *) @@ -14275,7 +14276,7 @@ else app) shift - send_stats "应用$@" + send_stats "Apply $@" linux_panel "$@" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index cab3eb64a..4f60c7f2e 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# コマンドを実行する関数を定義します run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! +# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 +# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# ユーザーに条件に同意するように促します UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" + echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" + echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "上記の条件に同意しますか? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "ライセンスの同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "許可の拒否" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}インストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" + echo "現在利用可能なスペース:$((available_space_mb/1024))g" + echo "最小需要スペース:${required_gb}G" + echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" + send_stats "ディスクスペースが不十分です" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}アンインストール$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# さまざまな分布に適したUniversal SystemCTL関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# サービスを再起動します restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1サービスは再開されました。" else - echo "错误:重启 $1 服务失败。" + echo "エラー:再起動$1サービスは失敗しました。" fi } -# 启动服务 +# サービスを開始します start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1サービスが開始されました。" else - echo "错误:启动 $1 服务失败。" + echo "エラー:開始$1サービスは失敗しました。" fi } -# 停止服务 +# サービスを停止します stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1サービスは停止しました。" else - echo "错误:停止 $1 服务失败。" + echo "エラー:停止します$1サービスは失敗しました。" fi } -# 查看服务状态 +# サービスのステータスを確認します status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1サービスステータスが表示されます。" else - echo "错误:无法显示 $1 服务状态。" + echo "エラー:表示できません$1サービスステータス。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME電源を入れるように設定します。" } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}操作が完了しました${gl_bai}" + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" echo "" clear @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -424,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -499,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "Dockerコンテナ管理" + echo "Dockerコンテナリスト" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "コンテナ操作" echo "------------------------" - echo "1. 创建新的容器" + echo "1.新しいコンテナを作成します" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" + echo "3.指定された容器を停止します7。すべての容器を停止します" + echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" + echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11。指定されたコンテナを入力します12。コンテナログを表示します" + echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "新しいコンテナを作成します" + read -e -p "作成コマンドを入力してください:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を停止します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定されたコンテナを削除します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "指定された容器を再起動します" + read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "すべてのコンテナを起動します" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "すべてのコンテナを停止します" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "すべてのコンテナを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -564,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "すべてのコンテナを再起動します" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "コンテナを入力します" + read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "コンテナログを表示します" + read -e -p "コンテナ名を入力してください:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "コンテナネットワークを表示します" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -603,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "コンテナの占有を表示します" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスを許可します" + read -e -p "コンテナ名を入力してください:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -619,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "コンテナポートアクセスをブロックします" + read -e -p "コンテナ名を入力してください:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -639,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "Docker画像管理" + echo "Docker画像リスト" docker image ls echo "" - echo "镜像操作" + echo "ミラー操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1.指定された画像を取得する3。指定された画像を削除します" + echo "2。指定された画像4を更新します。すべての画像を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "鏡を引っ張ります" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}画像を取得する:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "画像を更新します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}更新された画像:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "ミラーを削除します" + read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "すべての画像を削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -685,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -753,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "サポートされていない分布:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "オペレーティングシステムを決定することはできません。" return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" } @@ -774,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 現在の構成には既にIPv6設定があるかどうかを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 構成を更新し、IPv6を有効にします if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 元の構成と新しい構成を比較します if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -809,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" return fi - # 读取当前配置 + # 現在の構成をお読みください local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # JQを使用して、構成ファイルの更新を処理します local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 現在のIPv6ステータスを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 元の構成を新しい構成と比較します if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" fi } @@ -869,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 既存のクロージングルールを削除します iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # オープンルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "ポートが開かれました$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "ポートが開かれました" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "少なくとも1つのポート番号を提供してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 既存のオープンルールを削除します iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 緊密なルールを追加します if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "ポートは閉じた$port" fi done - # 删除已存在的规则(如果有) + # 既存のルールを削除する(ある場合) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 最初に新しいルールを挿入します iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "ポートは閉じた" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 既存のブロッキングルールを削除します iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 許可ルールを追加します if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "IPをリリースしました$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "IPをリリースしました" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 既存の許可ルールを削除します iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # ブロッキングルールを追加します if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IPブロック$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IPブロック" } @@ -989,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 防御DDOをオンにします iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -999,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDOS防御をオンにします" } -# 关闭DDoS防御 +# DDOS防御をオフにします disable_ddos_defense() { - # 关闭防御 DDoS + # 防御DDOをオフにします iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1014,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDOS防御をオフにします" } -# 管理国家IP规则的函数 +# 国家IPルールを管理する機能 manage_country_rules() { local action="$1" local country_code="$2" @@ -1032,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # IPSETが存在しない場合は作成します if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # iptablesでIPをブロックします iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "正常にブロックされました$country_codeIPアドレス" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 許可された国のIPSETを作成する(存在しない場合) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IPエリアファイルをダウンロードします if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" exit 1 fi - # 删除现有的国家规则 + # 既存の国家ルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # IPSETにIPを追加します while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 指定された国のIPのみが許可されています iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "正常に許可されています$country_codeIPアドレス" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 国のiptablesルールを削除します iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # Ipsetを破壊します if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "正常に持ち上げられました$country_codeIPアドレスの制限" ;; *) @@ -1115,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "高度なファイアウォール管理" + send_stats "高度なファイアウォール管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "ファイアウォール管理" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1.指定されたポート2を開きます。指定されたポートを閉じます" + echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5。IPホワイトリスト6。IPブラックリスト" + echo "7.指定されたIPをクリアします" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. ping 12を許可します。Pingを無効にします" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" + echo "17.指定国でのIP制限をリリースします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "オープンポート番号を入力してください:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "指定されたポートを開きます" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "閉じたポート番号を入力してください:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "指定されたポートを閉じます" ;; 3) - # 开放所有端口 + # すべてのポートを開きます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1163,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "すべてのポートを開きます" ;; 4) - # 关闭所有端口 + # すべてのポートを閉じます current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1179,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "すべてのポートを閉じます" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IPホワイトリスト + read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IPブラックリスト + read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 指定されたIPをクリアします + read -e -p "クリアされたIPを入力してください:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "指定されたIPをクリアします" ;; 11) - # 允许 PING + # pingを許可します iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "pingを許可します" ;; 12) - # 禁用 PING + # pingを無効にします iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "pingを無効にします" ;; 13) enable_ddos_defense @@ -1222,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "許可された国$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "国をブロックします$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "国をきれいにします$country_codeIP" ;; *) @@ -1256,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 現在のシステムですべてのスワップパーティションを取得します local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 反復して、すべてのスワップパーティションを削除します for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfileが使用されなくなったことを確認してください swapoff /swapfile - # 删除旧的 /swapfile + # 古い /swapfileを削除します rm -f /swapfile - # 创建新的 swap 分区 + # 新しいスワップパーティションを作成します fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1287,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" } @@ -1297,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 仮想メモリを作成する必要があるかどうかを判断します [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1313,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginxバージョンを取得します local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # MySQLバージョンを取得します local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHPバージョンを取得します local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redisバージョンを取得します local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1340,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 必要なディレクトリとファイルを作成します cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1349,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.ymlファイルをダウンロードして置き換えます wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.ymlファイルに置き換えます sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1398,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP環境がインストールされています" echo "------------------------" ldnmp_v @@ -1415,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "更新タスクが更新されました" } @@ -1452,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}証明書ストレージパス${gl_bai}" + echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1469,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1485,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" + echo "サイト情報証明書の有効期限" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1525,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "ドメイン名証明書の成功したアプリケーション" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "ドメイン名証明書のアプリケーションは失敗しました" + echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" + echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" + echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" + echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" + echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" + echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" + echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" break_end clear - echo "请再次尝试部署 $webname" + echo "もう一度展開してみてください$webname" add_yuming install_ssltls certs_status @@ -1548,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "ドメイン名の再利用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1557,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1622,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" } @@ -1642,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "ログイン情報:" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "起動する$ldnmp_pods" } @@ -1656,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 構成ファイルが存在するかどうかを確認します if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # ゾーン_idsを配列に変換します ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # キャッシュをクリーニングするかどうかをユーザーに促します + read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" + read -e -p "API_TOKENを入力してください:" API_TOKEN + read -e -p "CFユーザ​​ー名を入力してください:" EMAIL + read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1686,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "キャッシュクリアリクエストが送信されました。" } web_cache() { - send_stats "清理站点缓存" + send_stats "サイトキャッシュをクリーンアップします" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1702,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "サイトデータを削除します" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "ドメイン名の削除:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # ドメイン名をデータベース名に変換します dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します + echo "データベースの削除:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1739,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # WAFを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1802,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1829,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 古い定義を削除します sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 「Happy Publishing」で行の前に新しい定義を挿入する awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1857,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotliをオンにする:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1871,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotliを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1887,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1913,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # ZSTDをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1928,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # ZSTDを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1944,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1975,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無効なパラメーター:「オン」または「オフ」を使用します" return 1 fi @@ -1989,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP環境防御" while true; do check_waf_status check_cf_mode @@ -2003,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" + echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21。CloudFlareモード22。5秒シールドの高負荷" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31。WAF32をオンにしてください。WAFをオフにします" + echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2081,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; 11) @@ -2096,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "CloudFlareモード" + echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2115,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "5秒シールドでの高負荷" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CFパラメーターを取得します:" + echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" + echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID cd ~ install jq bc @@ -2146,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "高負荷自動シールドオープニングスクリプトが追加されました" else - echo "自动开盾脚本已存在,无需添加" + echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "サイトWAFが有効になっています" + send_stats "サイトWAFが有効になっています" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "サイトWAFは閉鎖されています" + send_stats "サイトWAFは閉鎖されています" ;; 33) @@ -2188,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 現在のworker_processesの設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 値に応じてモード情報を設定します if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2207,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Brotliが有効であり、コメントされていないかどうかを確認してください if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # GZIPが有効になっており、コメントされていないかどうかを確認してください if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2237,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP環境を最適化します" + echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1。標準モード2。高性能モード(推奨2H4g以上)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" + echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" + echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "サイト標準モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2275,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2287,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境は標準モードに設定されています" ;; 2) - send_stats "站点高性能模式" + send_stats "サイトの高性能モード" - # nginx调优 + # nginxチューニング sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # PHPチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHPチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2315,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysqlチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2325,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP環境は、高性能モードに設定されています" ;; 3) @@ -2385,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker = "$ {gl_lv} $ {gl_bai}インストール" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" # fi # } @@ -2395,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "アクセスアドレス:" ip_address @@ -2433,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # コンテナの作成時間と画像名を取得します local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # ミラーウェアハウスとタグを抽出します local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # デフォルトのラベルは最新です [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 公式画像のサポートを追加します [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Docker Hub APIから画像公開時間を取得します local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 買収の時間を確認します if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # タイムスタンプを比較します if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2476,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2486,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 他のすべてのIPSを確認してブロックします if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 指定されたIPを確認してリリースします if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワークを確認してリリースします127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2523,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2534,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # コンテナのIPアドレスを取得します local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2544,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2563,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 他のすべてのIPをブロックするルールを明確にします if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2584,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2598,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:block_host_port <ポート番号> <承認IP>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2625,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 他のすべてのIPアクセスを拒否しました if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 指定されたIPアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # ローカルアクセスを許可します if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 確立された関連接続および関連する接続のトラフィックを許可します if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" save_iptables_rules } @@ -2657,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 他のすべてのIPアクセスをブロックするルールをクリアします if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 指定されたIPアクセスを許可するルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+ポートはサービスにアクセスすることが許可されています" save_iptables_rules } @@ -2746,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2770,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "インストール$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2785,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_nameインストール" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "更新します$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2799,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "アプリはアンインストールされています" + send_stats "アンインストール$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2859,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2894,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}ドメインアクセス設定" + send_stats "${docker_name}ドメインアクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IPアクセスを許可します${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2994,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# セッションが存在するかどうかを確認する関数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 存在しないセッション名が見つかるまでループします while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 新しいTMUXセッションを作成します tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3079,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "再起動" reboot ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -3126,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP環境を再度インストールできません" + echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" break_end linux_ldnmp fi @@ -3137,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP環境をインストールします" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3154,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Nginx環境をインストールします" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3168,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "Nginxがインストールされています" +echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3180,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "LDNMP環境を最初にインストールしてください" ldnmp_install_all fi @@ -3190,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "最初にNGINX環境をインストールしてください" nginx_install_all fi @@ -3201,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webnameインストール情報は次のとおりです。" } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "あなたの$webname建てられた!" echo "https://$yuming" } @@ -3222,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3263,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "発生防止ポートを入力してください。" port fi nginx_install_status install_ssltls @@ -3296,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3356,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMPサイト管理" + echo "LDNMP環境" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "サイト:${output}証明書の有効期限" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3374,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "データベース:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "サイトディレクトリ" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" + echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" + echo "5.アクセスログを表示6。エラーログを表示します" + echo "7.グローバル構成の編集8。サイト構成の編集" + echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20.指定されたサイトデータを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "ドメイン名証明書を申請します" + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3411,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "サイトドメイン名を変更します" + echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" + read -e -p "古いドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status - # mysql替换 + # MySQLの交換 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3437,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # ウェブサイトディレクトリの交換 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3458,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "関連するサイトを作成します" + echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" + read -e -p "既存のドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status @@ -3475,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "アクセスログを表示します" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "エラーログを表示します" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "グローバル構成を編集します" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "サイト構成を編集します" + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3503,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "サイトデータを表示します" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3539,16 +3540,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" + echo "公式ウェブサイトの紹介:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1。インストール2。管理3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) check_disk_space 1 @@ -3557,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}インストール" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}控制" + send_stats "${panelname}コントロール" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}アンインストール" ;; *) break @@ -3614,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRPサーバーをインストールします" + # ランダムポートと資格情報を生成します local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3636,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 出力生成情報 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "クライアントの展開に必要なパラメーター" + echo "サービスIP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRPパネル情報" + echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" + echo "FRPパネルのユーザー名:$dashboard_user" + echo "FRPパネルパスワード:$dashboard_pwd" echo open_port 8055 8056 @@ -3656,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRPクライアントをインストールします" + read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr + read -e -p "外部ネットワークドッキングトークンを入力してください:" token echo mkdir -p /home/frp @@ -3678,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRPイントラネットサービスを追加します" + # ユーザーにサービス名と転送情報を入力するように促します + read -e -p "サービス名を入力してください:" service_name + read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "イントラネットポートを入力してください:" local_port + read -e -p "外部ネットワークポートを入力してください:" remote_port - # 将用户输入写入配置文件 + # ユーザー入力を構成ファイルに書き込みます cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3698,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 出力生成情報 + echo "仕える$service_nameFRPC.TOMLに正常に追加されました" docker restart frpc @@ -3710,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRPイントラネットサービスを削除します" + # ユーザーに削除する必要があるサービス名を入力するように促します + read -e -p "削除する必要があるサービス名を入力してください:" service_name + # SEDを使用して、サービスとその関連構成を削除します sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "仕える$service_nameFRPC.TOMLから削除されました" docker restart frpc @@ -3725,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # ヘッダーを印刷します printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3746,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3755,11 +3756,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 現在のサービス名を更新します if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 前の値をクリアします local_ip="" local_port="" remote_port="" @@ -3788,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 最後のサービスの情報を印刷します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3801,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRPサーバーポートを取得します get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# アクセスアドレスを生成します generate_access_urls() { - # 首先获取所有端口 + # 最初にすべてのポートを取得します get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056以外のポートがあるかどうかを確認してください local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3820,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 有効なポートがある場合にのみタイトルとコンテンツを表示します if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRPサービス外部アクセスアドレス:" - # 处理 IPv4 地址 + # IPv4アドレスを処理します for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # IPv6アドレスを処理する(存在する場合) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3840,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3867,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRPサーバー" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3875,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRPサーバー$check_frp $update_status" + echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00。サービスのステータスを更新します。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3901,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "FRPサーバーがインストールされています" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3911,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "FRPサーバーが更新されました" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3922,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "ドメイン名アクセスへの逆イントラネット侵入サービス" + send_stats "FRP外部ドメイン名へのアクセス" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IPアクセスを許可します" + read -e -p "リリースするポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IPアクセスをブロックします" + echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" + read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRPサービスステータスを更新します" + echo "FRPサービスステータスは更新されました" ;; *) @@ -3965,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRPクライアント" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3973,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRPクライアント$check_frp $update_status" + echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" + echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3984,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) install jq grep ss @@ -3998,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "FRPクライアントがインストールされています" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4008,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "FRPクライアントが更新されました" ;; 3) @@ -4019,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; 4) @@ -4065,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "YT-DLPダウンロードツール" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" + echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "ダウンロードされたビデオリスト:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" + echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "オプション番号を入力してください:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "YT-DLPのインストール..." + echo "YT-DLPのインストール..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlpを更新..." + echo "yt-dlpを更新..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlpのアンインストール..." + echo "yt-dlpのアンインストール..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "単一のビデオダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; 6) - send_stats "批量视频下载" + send_stats "バッチビデオのダウンロード" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "バッチダウンロードを開始します..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4134,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "カスタムビデオのダウンロード" + read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "実行が完了したら、キーを押して続行します..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "mp3ダウンロード" + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "ビデオを削除します" + read -e -p "削除ビデオの名前を入力してください:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4194,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# DPKG割り込みの問題を修正します fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4203,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}システムの更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4222,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi } @@ -4230,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4259,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." apk cache clean - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APKキャッシュを削除してください..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4283,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "未使用の依存関係をクリーンアップ..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "パッケージマネージャーのキャッシュを掃除します..." pkg clean -y - echo "删除系统日志..." + echo "システムログを削除してください..." rm -rf /var/log/* - echo "删除临时文件..." + echo "一時ファイルを削除します..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi return @@ -4339,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNSを最適化します" while true; do clear - echo "优化DNS地址" + echo "DNSアドレスを最適化します" echo "------------------------" - echo "当前DNS地址" + echo "現在のDNSアドレス" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1。外国DNS最適化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2。国内のDNS最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3。DNS構成を手動で編集します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4366,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "外国のDNS最適化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4374,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "国内のDNS最適化" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS構成を手動で編集します" ;; *) break @@ -4402,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # PasswordAuthenticationが見つかった場合は、はいに設定します if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 発見された場合、pubkeyauthenticationはyesに設定されています if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4416,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4427,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # バックアップSSH構成ファイル cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4440,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSHポートは次のように変更されています。$new_port" sleep 1 @@ -4458,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4470,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" return 1 fi @@ -4498,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" } @@ -4507,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "ルートパスワードを設定します" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能では、ルートユーザーを実行する必要があります!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "システムを再インストールします" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4537,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4587,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "Debian 13を再インストールします" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4609,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "Debian 12を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "Debian 11を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "Debian 10を再インストールします" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "Ubuntu 24.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "Ubuntu 22.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Ubuntu 20.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "Ubuntu 18.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4660,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Rockylinux10を再インストールします" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4668,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Rockylinux9を再インストールします" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4676,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "alma10を再インストールします" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4684,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "alma9を再インストールします" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4692,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Oracle10を再インストールします" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4700,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Oracle9を再インストールします" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4708,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Fedora42を再インストールします" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4716,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Fedora41を再インストールします" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4724,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "CENTOS10を再インストールします" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4732,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "CENTOS9を再インストールします" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4740,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "アルパインを再インストールします" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4748,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "アーチを再インストールします" dd_xitong_3 bash reinstall.sh arch reboot @@ -4756,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "Kaliを再インストールします" dd_xitong_3 bash reinstall.sh kali reboot @@ -4764,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Openeulerを再インストールします" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4772,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "OpenSuseを再インストールします" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4780,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "飛ぶ牛をリロードします" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4789,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Windows11を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4797,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Windows 10を再インストールします" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows 7を再インストールします" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4811,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Windows Server 22を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Windows Server 19を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Windows Server 16を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4833,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Windows11アームを再インストールします" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4850,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "BBRV3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4863,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "XanmodのBBRV3カーネルをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) @@ -4883,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4892,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "Xanmodカーネルが更新されました。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4902,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" server_reboot ;; @@ -4915,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3加速度をセットアップします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "Debian/Ubuntuのみをサポートします" + echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -4929,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "オペレーティングシステムの種類を決定できません" break_end linux_Settings fi @@ -4945,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # ステップ3:リポジトリを追加します echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4956,17 +4957,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -4975,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Elrepo GPG公開キーをインポートします + echo "Elrepo GPG公開キーをインポートしてください..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # システムバージョンを検出します local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # サポートされているオペレーティングシステムで実行されていることを確認してください if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "サポートされていないオペレーティングシステム:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 検出されたオペレーティングシステム情報を印刷します + echo "検出されたオペレーティングシステム:$os_name $os_version" + # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "サポートされていないシステムバージョン:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします + echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" server_reboot } @@ -5016,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "レッドハットカーネル管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "Elrepo Kernelをインストールしました" + echo "現在のカーネルバージョン:$kernel_version" echo "" - echo "内核管理" + echo "カーネル管理" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hatカーネルを更新します" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" + send_stats "レッドハットカーネルをアンインストールします" server_reboot ;; @@ -5059,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" + echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hatカーネルをアップグレードします" server_reboot ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac fi @@ -5089,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5099,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "スキャンするディレクトリを指定してください。" return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" - # 构建 mount 参数 + # マウントパラメーターを構築します local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # CLAMSCANコマンドパラメーターを作成します local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5120,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Dockerコマンドを実行します docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5129,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" } @@ -5142,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "ウイルススキャン管理" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "クラマブウイルススキャンツール" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" + echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "フルディスクスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5167,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "重要なディレクトリスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5175,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "カスタムディレクトリスキャン" + read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5193,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# 高性能モード最適化関数 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5219,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# イコライゼーションモード最適化関数 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5260,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# デフォルト設定関数を復元します restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}デフォルト設定に復元...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" + # 透明なページを復元します echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# ウェブサイトの構築最適化機能 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5343,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}その他の最適化...${gl_bai}" + # レイテンシを減らすために、大きな透明なページを無効にします echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5363,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linuxカーネルチューニング管理" + echo "Linuxシステムにおけるカーネルパラメーターの最適化" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" + echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" + echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" + echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" + echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" + echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" + echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "高性能モードの最適化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "バランスモードの最適化" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "ウェブサイトの最適化モデル" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "ライブストリーミング最適化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "ゲームサーバーの最適化" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "デフォルト設定を復元します" ;; *) break @@ -5445,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end @@ -5454,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "サポートされていないシステム:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "サポートされていないシステム、システムタイプは認識できません。" break_end fi } @@ -5474,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "システム言語を切り替えます" while true; do clear - echo "当前系统语言: $LANG" + echo "現在のシステム言語:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1。英語2。簡素化された中国語3。伝統的な中国語" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "英語に切り替えます" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "簡素化された中国人に切り替えます" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "伝統的な中国人に切り替えます" ;; *) break @@ -5518,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" hash -r break_end @@ -5529,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "コマンドラインの美化ツール" while true; do clear - echo "命令行美化工具" + echo "コマンドラインの美化ツール" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5542,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5589,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "システムリサイクルステーション" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5604,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "現在のリサイクルビン${trash_status}" + echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" + echo "3。コンテンツを復元4。リサイクルビンをクリアします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -5622,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" sleep 2 ;; 2) @@ -5630,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "復元するにはファイル名を入力してください。" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restoreホームディレクトリに復元されました。" else - echo "文件不存在。" + echo "ファイルは存在しません。" fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "リサイクルビンがクリアされました。" fi ;; *) @@ -5657,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# バックアップを作成します create_backup() { - send_stats "创建备份" + send_stats "バックアップを作成します" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # ユーザーにバックアップディレクトリを入力するように求めます + echo "バックアップ例を作成します:" + echo "- 単一のディレクトリをバックアップします: /var /www" + echo "- バックアップ複数のディレクトリ: /etc /home /var /log" + echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" + read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input - # 如果用户没有输入目录,则使用默认目录 + # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5681,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # ユーザーが入力したディレクトリをスペースごとに配列に分離します IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # バックアップファイルプレフィックスを生成します local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # ディレクトリ名を抽出し、スラッシュを削除します dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 最後のアンダースコアを削除します local PREFIX=${PREFIX%_} - # 生成备份文件名 + # バックアップファイル名を生成します local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # ユーザーが選択したディレクトリを印刷します + echo "選択したバックアップディレクトリは次のとおりです。" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # バックアップを作成します + echo "バックアップを作成します$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # コマンドが成功しているかどうかを確認してください if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "バックアップの作成に失敗しました!" exit 1 fi } -# 恢复备份 +# バックアップを復元します restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "バックアップを復元します" + # 復元するバックアップを選択します + read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "バックアップの回復$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "バックアップと復元を正常に!" else - echo "备份恢复失败!" + echo "バックアップリカバリに失敗しました!" exit 1 fi } -# 列出备份 +# バックアップをリストします list_backups() { - echo "可用的备份:" + echo "利用可能なバックアップ:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# バックアップを削除します delete_backup() { - send_stats "删除备份" + send_stats "バックアップを削除します" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME - # 检查备份文件是否存在 + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "バックアップファイルは存在しません!" exit 1 fi - # 删除备份 + # バックアップを削除します rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "バックアップは正常に削除されました!" else - echo "备份删除失败!" + echo "バックアップの削除が失敗しました!" exit 1 fi } -# 备份主菜单 +# バックアップメインメニュー linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "システムバックアップ機能" + echo "システムバックアップ機能" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -5805,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# 接続リストを表示します list_connections() { - echo "已保存的连接:" + echo "接続の保存:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 新しい接続を追加します add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "新しい接続を追加します" + echo "新しい接続を作成する例:" + echo "- 接続名:my_server" + echo "- IPアドレス:192.168.1.100" + echo "- ユーザー名:root" + echo "- ポート:22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "接続名を入力してください:" name + read -e -p "IPアドレスを入力してください:" ip + read -e -p "ユーザー名(デフォルト:root)を入力してください:" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "ポート番号を入力してください(デフォルト:22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "選択(1/2)を入力してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5863,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "接続が保存されます!" } -# 删除连接 +# 接続を削除します delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "接続を削除します" + read -e -p "削除するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続​​は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 接続がキーファイルを使用している場合、キーファイルを削除します if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "接続が削除されました!" } -# 使用连接 +# 接続を使用します use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "接続を使用します" + read -e -p "使用するには、接続番号を入力してください。" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "エラー:対応する接続​​は見つかりませんでした。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "接続$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "接続に失敗しました!以下を確認してください。" + echo "1。キーファイルパスは正しいですか?$password_or_key" + echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" + echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" fi else - # 使用密码连接 + # パスワードで接続します if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "接続に失敗しました!以下を確認してください。" + echo "1.ユーザー名とパスワードが正しいかどうか。" + echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" + echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSHリモート接続ツール" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5957,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSHリモート接続ツール" + echo "SSHを介して他のLinuxシステムに接続できます" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac done } @@ -5987,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 利用可能なハードディスクパーティションをリストします list_partitions() { - echo "可用的硬盘分区:" + echo "利用可能なハードディスクパーティション:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# パーティションをマウントします mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをマウントします" + read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "パーティションはすでに取り付けられています!" return fi - # 创建挂载点 + # マウントポイントを作成します MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # パーティションをマウントします mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "パーティションマウントに正常に:$MOUNT_POINT" else - echo "分区挂载失败!" + echo "パーティションマウントは失敗しました!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# パーティションをアンインストールします unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "パーティションをアンインストールします" + read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "パーティションはマウントされていません!" return fi - # 卸载分区 + # パーティションをアンインストールします umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "パーティションのアンインストールに正常に:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "パーティションのアンインストールに失敗しました!" fi } -# 列出已挂载的分区 +# マウントされたパーティションをリストします list_mounted_partitions() { - echo "已挂载的分区:" + echo "マウントされたパーティション:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# フォーマットパーティション format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "フォーマットパーティション" + read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区是否已经挂载 + # パーティションが既にマウントされているかどうかを確認してください if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "パーティションがマウントされました。最初にアンインストールしてください!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # ファイルシステムタイプを選択します + echo "ファイルシステムタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "選択を入力してください:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "無効な選択!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # フォーマットを確認します + read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "操作はキャンセルされました。" return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # フォーマットパーティション + echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "パーティション形式は成功しました!" else - echo "分区格式化失败!" + echo "パーティションのフォーマットが失敗しました!" fi } -# 检查分区状态 +# パーティションステータスを確認します check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "パーティションステータスを確認します" + read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION - # 检查分区是否存在 + # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "パーティションは存在しません!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # パーティションステータスを確認します + echo "パーティション /dev /$PARTITION状態:" fsck "/dev/$PARTITION" } -# 主菜单 +# メインメニュー disk_manager() { - send_stats "硬盘管理功能" + send_stats "ハードディスク管理機能" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "ハードディスクパーティション管理" + echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" + echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6145,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } -# 显示任务列表 +# タスクリストを表示します list_tasks() { - echo "已保存的同步任务:" + echo "保存された同期タスク:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 新しいタスクを追加します add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "新しい同期タスクを追加します" + echo "新しい同期タスクを作成する例:" + echo "- タスク名:backup_www" + echo "- ローカルディレクトリ: /var /www" + echo "- リモートアドレス:user@192.168.1.100" + echo "- リモートディレクトリ: /バックアップ /www" + echo "- ポート番号(デフォルト22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "タスク名を入力してください:" name + read -e -p "ローカルディレクトリを入力してください:" local_path + read -e -p "リモートディレクトリを入力してください:" remote_path + read -e -p "リモートユーザー@IPを入力してください:" remote + read -e -p "SSHポートを入力してください(デフォルト22):" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "認証方法を選択してください:" + echo "1。パスワード" + echo "2。キー" + read -e -p "(1/2)を選択してください:" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # キーコンテンツのかどうかを確認してください if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6210,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "無効なキーコンテンツ!" return fi ;; *) - echo "无效的选择!" + echo "無効な選択!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "同期モードを選択してください:" + echo "1。標準モード(-AVZ)" + echo "2。ターゲットファイル(-avz - delete)を削除します" + read -e -p "(1/2)を選択してください:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "タスクが節約されました!" } -# 删除任务 +# タスクを削除します delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "エラー:対応するタスクは見つかりませんでした。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # タスクがキーファイルを使用している場合、キーファイルを削除します if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "削除されたタスク!" } run_task() { - send_stats "执行同步任务" + send_stats "同期タスクを実行します" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # パラメーターを分析します local direction="push" # 默认是推送到远端 local num @@ -6277,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 着信タスク番号がない場合は、ユーザーに入力するように促します if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "実行するタスク番号を入力してください:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "エラー:タスクは見つかりませんでした!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH接続の共通パラメーターを追加します local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "エラー:キーファイルが存在しません:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." chmod 600 "$password_or_key" fi @@ -6329,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "同期は完了です!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "同期は失敗しました!以下を確認してください。" + echo "1。ネットワーク接続は正常ですか?" + echo "2。リモートホストにアクセスできますか?" + echo "3。認証情報は正しいですか?" + echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" fi } -# 创建定时任务 +# 時限タスクを作成します schedule_task() { - send_stats "添加同步定时任务" + send_stats "同期タイミングタスクを追加します" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "定期的に同期するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "時限実行間隔を選択してください:" + echo "1)1時間に1回実行します" + echo "2)1日1回実行します" + echo "3)週に1回実行します" + read -e -p "オプションを入力してください(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6362,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "エラー:有効なオプションを入力してください!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 同じタスクが既に存在するかどうかを確認してください if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "エラー:このタスクのタイミング同期はすでに存在しています!" return fi - # 创建到用户的 crontab + # ユーザーにクロンタブを作成します (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "タイミングタスクが作成されました。$cron_job" } -# 查看定时任务 +# スケジュールされたタスクを表示します view_tasks() { - echo "当前的定时任务:" + echo "現在のタイミングタスク:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# タイミングタスクを削除します delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "同期タイミングタスクを削除します" + read -e -p "削除するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "エラー:有効なタスク番号を入力してください!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "削除されたタスク番号$numタイミングタスク" } -# 任务管理主菜单 +# タスク管理メインメニュー rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "RSYNCリモート同期ツール" + echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1.新しいタスクを作成します2。タスクを削除します" + echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" + echo "5.タイミングタスクを作成6.タイミングタスクを削除します" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6430,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無効な選択、もう一度やり直してください。" ;; esac - read -e -p "按回车键继续..." + read -e -p "Enterを押して続行します..." done } @@ -6447,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "システム情報クエリ" ip_address @@ -6497,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "システム情報クエリ" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" + echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" + echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" + echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" + echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" + echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" echo @@ -6544,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats「基本ツール」 + echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" + echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" + echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" + echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" + echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" + echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}Gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" + echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" + echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" curl --help - send_stats "安装curl" + send_stats "カールをインストールします" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" wget --help - send_stats "安装wget" + send_stats "WGETをインストールします" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" sudo --help - send_stats "安装sudo" + send_stats "sudoをインストールします" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" socat -h - send_stats "安装socat" + send_stats "SOCATをインストールします" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "HTOPをインストールします" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "IFTOPをインストールします" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" unzip - send_stats "安装unzip" + send_stats "unzipをインストールします" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tar --help - send_stats "安装tar" + send_stats "タールをインストールします" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" tmux --help - send_stats "安装tmux" + send_stats "tmuxをインストールします" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "ツールがインストールされており、使用方法は次のとおりです。" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "ffmpegをインストールします" ;; 11) @@ -6656,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "BTOPをインストールします" ;; 12) clear @@ -6665,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "レンジャーをインストールします" ;; 13) clear @@ -6674,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "NCDUをインストールします" ;; 14) clear @@ -6683,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "FZFをインストールします" ;; 15) clear @@ -6692,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "VIMをインストールします" ;; 16) clear @@ -6701,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "ナノをインストールします" ;; @@ -6712,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "gitをインストールします" ;; 21) @@ -6720,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrixをインストールします" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "SLをインストールします" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "バステットをインストールします" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "nsnakeをインストールします" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Ninvadersをインストールします" ;; 31) clear - send_stats "全部安装" + send_stats "すべてをインストールします" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "すべてをアンインストールします" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname install $installname - send_stats "安装指定软件" + send_stats "指定されたソフトウェアをインストールします" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename remove $removename - send_stats "卸载指定软件" + send_stats "指定されたソフトウェアをアンインストールします" ;; 0) @@ -6788,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -6802,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "AlpineはBBR3を有効にします" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6867,21 +6868,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}当前备份列表:${NC}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + echo -e "${BLUE}現在のバックアップリスト:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" } # ---------------------------- - # 备份 + # バックアップ # ---------------------------- backup_docker() { - send_stats "Docker备份" + send_stats "Dockerバックアップ" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers install tar jq gzip install_docker @@ -6892,7 +6893,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナは見つかりません${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6900,28 +6901,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "#自動的に生成された復元スクリプト" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # パッケージ化されたプロジェクトのパスを記録して、パッケージの重複を避ける declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${GREEN}バックアップコンテナ:$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${BLUE}検出されました$cはい、Docker-Composeコンテナ${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir fi - # 如果该 Compose 项目已经打包过,跳过 + # Composeプロジェクトがパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${YELLOW}プロジェクトを作成する[$project_name]バックアップ、複製パッケージをスキップ...${NC}" continue fi @@ -6929,137 +6930,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "#docker-compose Recovery:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${GREEN}プロジェクトを作成する[$project_name]パック:${project_dir}${NC}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${RED}docker-compose.ymlが見つかりません、このコンテナをスキップしてください...${NC}" fi else - # 普通容器备份卷 + # 通常のコンテナバックアップボリューム local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷: $path" + echo "梱包ロール:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 端口 + # ポート local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 环境变量 + # 環境変数 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 卷映射 + # ボリュームマッピング local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 镜像 + # 鏡 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo -e "\ n#復元コンテナ:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 备份 /home/docker 下的所有文件(不含子目录) + # /home /dockerのすべてのファイルをバックアップします(サブディレクトリを除く) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${BLUE}/home /dockerの下のファイルをバックアップ...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}/home /dockerの下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" + echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 还原 + # 削減 # ---------------------------- restore_docker() { - send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Dockerの復元" + read -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${BLUE}復元操作を開始します...${NC}" install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # ------------------------------ for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path - # 检查该 compose 项目的容器是否已经在运行 + # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${YELLOW}プロジェクトを作成する[$project_name]すでにコンテナが走っています、復元をスキップします...${NC}" continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "新しい復元パスを入力してください:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${GREEN}プロジェクトを作成する[$project_name]減圧:$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${GREEN}プロジェクトを作成する[$project_name]復元が完了しました!${NC}" fi done - # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + # ------------------------------ + echo -e "${BLUE}通常のDockerコンテナを確認して復元します...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${GREEN}コンテナの処理:$container${NC}" - # 检查容器是否已经存在且正在运行 + # 容器が既に存在し、実行中かどうかを確認してください if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${YELLOW}容器 [$container]走っています、復元をスキップします...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報は見つかりませんでした、スキップ:$container${NC}"; continue; } - # 端口映射 + # ポートマッピング PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 环境变量 + # 環境変数 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷数据恢复 + # ボリュームマッピング +ボリュームデータリカバリ VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7070,32 +7071,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢复卷数据: $VOL_SRC" + echo "ボリュームデータの回復:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 删除已存在但未运行的容器 + # 既存のが実行されていないコンテナを削除します if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${YELLOW}容器 [$container]存在しますが、実行していません。古いコンテナを削除してください...${NC}" docker rm -f "$container" fi - # 启动容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # コンテナを起動します + echo "restoreコマンドを実行します:docker run -d - name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}通常のコンテナのバックアップ情報は見つかりませんでした${NC}" - # 还原 /home/docker 下的文件 + # /home /dockerの下でファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${BLUE}/home /dockerの下でファイルを復元します...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${GREEN}/home /dockerの下のファイルが復元されました${NC}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${YELLOW}/home /dockerの下のファイルのバックアップは見つかりませんでした、スキップ...${NC}" fi @@ -7103,66 +7104,66 @@ docker_ssh_migration() { # ---------------------------- - # 迁移 + # 移動します # ---------------------------- migrate_docker() { - send_stats "Docker迁移" + send_stats "Dockerの移行" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + read -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -p "ターゲットサーバーIP:" TARGET_IP + read -p "ターゲットサーバーSSHユーザー名:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${YELLOW}バックアップを転送...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密钥登录 + # キーでログインします scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 删除备份 + # バックアップを削除します # ---------------------------- delete_backup() { - send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Dockerバックアップファイルの削除" + read -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" } # ---------------------------- - # 主菜单 + # メインメニュー # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "Dockerバックアップの移行と復元" while true; do clear echo "------------------------" - echo -e "Docker备份/迁移/还原工具" + echo -e "Dockerバックアップ/移行/復元ツール" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" - echo -e "2. 迁移docker项目" - echo -e "3. 还原docker项目" - echo -e "4. 删除docker项目的备份文件" + echo -e "1。Dockerプロジェクトをバックアップします" + echo -e "2。Dockerプロジェクトを移行します" + echo -e "3. Dockerプロジェクトを復元します" + echo -e "4. Dockerプロジェクトのバックアップファイルを削除します" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0。前のメニューに戻ります" echo "------------------------" - read -p "请选择: " choice + read -p "選択してください:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${RED}無効なオプション${NC}" ;; esac break_end done @@ -7179,38 +7180,38 @@ linux_docker() { while true; do clear - # send_stats "docker管理" + # send_stats「Docker Management」 echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" + echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" + echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" + echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Docker環境をインストールします" install_add_docker ;; @@ -7221,22 +7222,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "Dockerグローバルステータス" + echo "Dockerバージョン" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7251,8 +7252,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "Dockerネットワーク管理" + echo "Dockerネットワークリスト" echo "------------------------------------------------------------" docker network ls echo "" @@ -7276,36 +7277,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "ネットワーク操作" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1.ネットワークを作成します" + echo "2。インターネットに参加してください" + echo "3。ネットワークを終了します" + echo "4.ネットワークを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "ネットワークを作成します" + read -e -p "新しいネットワーク名を設定します:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "ネットワーク名に参加してください:" dockernetwork + read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "インターネットに参加してください" + read -e -p "出口ネットワーク名:" dockernetwork + read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7314,8 +7315,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "ネットワークを削除します" + read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork docker network rm $dockernetwork ;; @@ -7329,29 +7330,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "Dockerボリューム管理" + echo "Dockerボリュームリスト" docker volume ls echo "" - echo "卷操作" + echo "ボリューム操作" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1.新しいボリュームを作成します" + echo "2。指定されたボリュームを削除します" + echo "3.すべてのボリュームを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "新しいボリュームを作成します" + read -e -p "新しいボリューム名を設定します:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7360,7 +7361,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "すべてのボリュームを削除します" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7369,7 +7370,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7382,7 +7383,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "Dockerクリーニング" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7391,13 +7392,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "Dockerソース" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7413,13 +7414,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker V6が開いています" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker V6レベル" docker_ipv6_off ;; @@ -7430,7 +7431,7 @@ linux_docker() { 20) clear - send_stats "Docker卸载" + send_stats "Dockerアンインストール" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7442,7 +7443,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7451,7 +7452,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7468,151 +7469,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats「テストスクリプトコレクション」 + echo -e "テストスクリプトコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" + echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" + echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" + echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}ネットワーク速度測定" + echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" + echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" + echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" + echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" + echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" + echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" + echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" + echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}包括的なテスト" + echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "CHATGPTはステータス検出のロックを解除します" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "リージョンストリーミングメディアのロック解除テスト" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "YeahWUストリーミングメディアのロック解除検出" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "XYKT_IP品質の身体検査スクリプト" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "MTR_TRACE 3ネットワークリターンラインテスト" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "SuperSpeed Three-Net速度測定" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace高速バックホールテストスクリプト" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" + echo "参照できるIPのリスト" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "北京テレコム:219.141.136.12" + echo "北京ユニコム:202.106.50.1" + echo "北京モバイル:221.179.155.161" + echo "上海通信:202.96.209.133" + echo "上海ユニコム:210.22.97.1" + echo "上海モバイル:211.136.112.200" + echo "広州通信:58.60.188.222" + echo "広州ユニコム:210.21.196.6" + echo "広州モバイル:120.196.165.24" + echo "成都通信:61.139.2.69" + echo "成都ユニコム:119.6.6.6" + echo "成都モバイル:211.137.96.205" + echo "Hunan Telecom:36.111.200.100" + echo "Hunan Unicom:42.48.16.100" + echo "Hunan Mobile:39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "指定されたIPを入力してください:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "Ludashi2020 3ネットワークラインテスト" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "I-ABC多機能速度テストスクリプト" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "ネットワーク品質のテストスクリプト" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "YABSパフォーマンステスト" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "ベンチパフォーマンステスト" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "SpiritySDX Fusion Monster Review" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7622,7 +7623,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7638,51 +7639,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud Scriptコレクション" + echo -e "Oracle Cloud Scriptコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" + echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" + echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" + echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" + echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" + read -e -p "必ずインストールしますか? (y/n):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # デフォルト値を設定します local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 + read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # Dockerコンテナを実行します docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7690,14 +7691,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloudインストールアクティブスクリプト" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -7705,20 +7706,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" ;; 3) clear - echo "重装系统" + echo "システムを再インストールします" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7730,28 +7731,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "再インストールされたパスワードを入力してください:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud再インストールシステムスクリプト" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "この機能は開発段階にあるので、お楽しみに!" ;; 5) clear @@ -7761,15 +7762,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -7790,7 +7791,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" fi } @@ -7811,7 +7812,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" fi fi @@ -7839,31 +7840,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "ldnmp webサイトビルディング" + echo -e "${gl_huang}LDNMP Webサイトビルディング" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" + echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" + echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" + echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" + echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" + echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" + echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -7877,10 +7878,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # ディスクフォーラム webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7903,21 +7904,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "データベースアドレス:MySQL" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:discuz_" ;; 4) clear - # 可道云桌面 + # Kedao Cloudデスクトップ webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7939,20 +7940,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "データベースアドレス:MySQL" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" + echo "Redisホスト:Redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7978,24 +7979,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "データベースアドレス:MySQL" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベースプレフィックス:mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "インストールが成功した後、バックグラウンドアドレスにログインします" echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 一本足のカウントカード webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8016,34 +8017,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:MySQL" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "Redisアドレス:Redis" + echo "Redisパスワード:デフォルトで記入されていません" + echo "Redisポート:6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "ウェブサイトURL:https://$yuming" + echo "バックグラウンドログインパス: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "ユーザー名:admin" + echo "パスワード:管理者" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" + echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # フララムフォーラム webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8080,12 +8081,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "データベースアドレス:MySQL" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:flarum_" + echo "管理者情報は自分で設定されます" ;; @@ -8093,8 +8094,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8118,11 +8119,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "データベースプレフィックス:typecho_" + echo "データベースアドレス:MySQL" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "データベース名:$dbname" ;; @@ -8131,8 +8132,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8157,18 +8158,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "データベースアドレス:MySQL" + echo "データベースポート:3306" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8185,10 +8186,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8198,20 +8199,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8222,15 +8223,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "選択の無効な、再入力してください。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" echo "-------------" - echo "已经安装的扩展" + echo "インストールされた拡張機能" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8240,25 +8241,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8268,10 +8269,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "データベースインポートテーブルデータ" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "データベースのインポートが完了しました" ;; *) echo @@ -8283,12 +8284,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "データベースアドレス:MySQL" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" + echo "パスワード:$dbusepasswd" + echo "テーブルプレフィックス:$prefix" + echo "管理者ログイン情報は自分で設定されます" ;; @@ -8301,10 +8302,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "ジャンプドメイン名を入力してください:" reverseproxy nginx_install_status install_ssltls certs_status @@ -8326,7 +8327,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8337,11 +8338,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" + read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8361,8 +8362,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8384,8 +8385,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8402,8 +8403,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming nginx_install_status install_ssltls @@ -8436,8 +8437,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "インストール$webname" + echo "展開を開始します$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8454,10 +8455,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8467,12 +8468,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8497,21 +8498,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境バックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "バックアップファイルが作成されました: /home /$backup_filename" + read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "エラー:リモートサーバーIPを入力してください。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8519,9 +8520,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" else - echo "未找到要传送的文件。" + echo "転送されるファイルは見つかりませんでした。" fi break ;; @@ -8529,7 +8530,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac done @@ -8537,9 +8538,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "タイミングのリモートバックアップ" + read -e -p "リモートサーバーIPを入力してください:" useip + read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8549,18 +8550,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1。毎週のバックアップ2。毎日のバックアップ" + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8574,19 +8575,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP環境修復" + echo "利用可能なサイトバックアップ" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8596,7 +8597,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8605,7 +8606,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "圧縮パッケージは見つかりませんでした。" fi ;; @@ -8623,11 +8624,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP環境を更新します" + echo "LDNMP環境を更新します" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "コンポーネントの新しいバージョンを発見します" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8647,13 +8648,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" echo "------------------------" - echo "5. 更新完整环境" + echo "5。完全な環境を更新します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8662,7 +8663,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version local version=${version:-latest} cd /home/web/ @@ -8673,13 +8674,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8712,8 +8713,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 4) @@ -8724,15 +8725,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "更新します$ldnmp_pods" + echo "更新します${ldnmp_pods}仕上げる" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP環境を完全に更新します" cd /home/web/ docker compose down --rmi all @@ -8758,7 +8759,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP環境をアンインストールします" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8772,7 +8773,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -8782,7 +8783,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "無効な入力!" esac break_end @@ -8802,12 +8803,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "アプリケーション市場" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # ループで色を設定します for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8816,70 +8817,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" + echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" + echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" + echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" + echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" + echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" + echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" + echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" + echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" + echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" + echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" + echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" + echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" + echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" + echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" + echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" + echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" + echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" + echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" + echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" + echo -e "${gl_kjlan}93. ${color93}DUFS Minimalist Static File Server${gl_kjlan}94. ${color94}ゴープ高速ダウンロードツール" + echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム" + echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice fi case $sub_choice in @@ -9032,8 +9033,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9066,7 +9067,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "ネザを作る" local app_id="7" local docker_name="nezha-dashboard" @@ -9075,20 +9076,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezhaの監視$check_docker $update_status" + echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" + echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1。使用します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -9145,7 +9146,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "郵便局を建設します" clear install telnet local app_id="9" @@ -9155,43 +9156,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "郵便局サービス$check_docker $update_status" + echo "Poste.ioはオープンソースメールサーバーソリューションです。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" - echo "端口检测" + echo "ポート検出" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "アクセスアドレス:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "これらのDNSレコードを最初に解析します" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9201,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "任意のキーを押して続行します..." read -n 1 -s -r -p "" install jq @@ -9220,9 +9221,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" @@ -9245,9 +9246,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.ioがインストールされています" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" echo "" ;; @@ -9258,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "アプリはアンインストールされています" ;; *) @@ -9292,7 +9293,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -9302,7 +9303,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chatがインストールされています" check_docker_app_ip } @@ -9312,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9396,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -9410,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -9555,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "サンダープールを構築します" local app_id="19" local docker_name=safeline-mgt @@ -9563,20 +9564,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "サンダープールサービス$check_docker" + echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) @@ -9586,7 +9587,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9599,7 +9600,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "サンダープールWAFパネルが更新されました" check_docker_app_ip ;; 3) @@ -9610,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9729,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10018,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10071,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoyaファミリーバケット" clear install_docker check_disk_space 1 @@ -10275,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "最初のユーザー名とパスワードは次のとおりです" } docker_app_update() { @@ -10295,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10382,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVEチキン" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10502,7 +10503,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10517,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10545,7 +10546,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10560,7 +10561,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10568,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10589,17 +10590,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "初期ユーザー名:admin" + echo "最初のパスワード:changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "アプリが更新されました" } @@ -10609,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10656,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -10672,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10934,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretvログインパスワードを設定します。" app_passwd docker run -d \ --name libretv \ @@ -10968,9 +10969,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password - read -e -p "输入授权码: " shouquanma + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "承認コードを入力してください:" shouquanma mkdir -p /home/docker/moontv @@ -10986,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11000,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11073,8 +11074,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "ログインユーザー名を設定します:" app_use + read -e -p "ログインパスワードの設定:" app_passwd docker run -d \ --name xunlei \ @@ -11171,11 +11172,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 公式のDocker-ComposeおよびEnvファイルをダウンロードします curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # ランダムキーとパスワードを生成します local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11184,17 +11185,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 管理者アカウント情報を追加します echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # コンテナを起動します docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11204,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 元の変数を保持します source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11221,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11271,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11289,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "設定${docker_name}SK-159KEJILIONYYDS163などのログインキー(SKターニング文字と数字の組み合わせ):" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11393,7 +11394,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11406,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11567,7 +11568,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + echo "初期ユーザーまたは管理者を作成します。次のユーザー名とパスワード、およびあなたが管理者であるかどうかを設定してください。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11619,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11633,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11708,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "ログインユーザー名を設定します:" app_use + read -e -p "ログインパスワードの設定:" app_passwd docker run -d \ --name ${docker_name} \ @@ -11757,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "已经安装完成" + echo "インストール" check_docker_app_ip } @@ -11771,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "应用已卸载" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11788,12 +11789,12 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -p "ネットワークを形成するためにクライアントの数を入力してください(デフォルト5):" COUNT COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ @@ -11833,7 +11834,7 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" + echo "QRコードを生成します:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' @@ -11843,11 +11844,11 @@ while true; do sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" - echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}すべての出力は各クライアントによって提供されます。使用方法は次のとおりです。${gl_bai}" + echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" + echo -e "${gl_lv}2。Windowsクライアントをダウンロードし、構成コードをコピーしてネットワークに接続します。${gl_bai}" + echo -e "${gl_lv}3。Linuxはスクリプトを使用してWGクライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" + echo -e "${gl_lv}公式クライアントのダウンロード方法:https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11875,16 +11876,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # ディレクトリを作成する(存在しない場合) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "请粘贴你的客户端配置,连续按两次回车保存:" + echo "クライアントの構成を貼り付け、Enterを2回連続で押して保存してください。" - # 初始化变量 + # 変数を初期化します input="" empty_line_count=0 - # 逐行读取用户输入 + # ユーザーの入力を行ごとに読み取ります while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -11897,10 +11898,10 @@ while true; do fi done - # 写入配置文件 + # 構成ファイルに書き込みます echo "$input" > "$CONFIG_FILE" - echo "客户端配置已保存到 $CONFIG_FILE" + echo "クライアントの構成が保存されています$CONFIG_FILE" docker run -d \ --name wireguardc \ @@ -11933,21 +11934,21 @@ while true; do b) clear - send_stats "全部应用备份" + send_stats "すべてのアプリケーションバックアップ" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "バックアップファイルが作成されました: /$backup_filename" + read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "エラー:リモートサーバーIPを入力してください。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11955,14 +11956,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "ファイルは、リモートサーバー/ルートディレクトリに転送されました。" else - echo "未找到要传送的文件。" + echo "転送されるファイルは見つかりませんでした。" fi break ;; *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + echo "注:現在、バックアップにはDockerプロジェクトのみが含まれており、Pagodaや1PanelなどのWebサイトビルディングパネルのデータバックアップは含まれていません。" break ;; esac @@ -11972,29 +11973,29 @@ while true; do r) root_use - send_stats "全部应用还原" - echo "可用的应用备份" + send_stats "すべてのアプリケーションが復元されます" + echo "利用可能なアプリバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用户没有输入文件名,使用最新的压缩包 + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "アプリケーションデータが復元されました。指定されたアプリケーションメニューを手動で入力し、アプリケーションを更新してアプリケーションを復元してください。" else - echo "没有找到压缩包。" + echo "圧縮パッケージは見つかりませんでした。" fi ;; @@ -12017,35 +12018,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "バックエンドワークスペース" + echo -e "バックエンドワークスペース" + echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "現在既存のワークスペースのリスト" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" + echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" + echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" + echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" + echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" + echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" + echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" + echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" + echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" + echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -12053,7 +12054,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -12061,63 +12062,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "ワークスペースを開始します$SESSION_NAME" tmux_run ;; @@ -12129,21 +12130,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH常駐モード" + echo -e "SSH常駐モード${tmux_sshd_status}" + echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1。2をオンにします。オフにします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "選択を入力してください:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "ワークスペースを開始します$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12159,29 +12160,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "カスタムワークスペース" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "バックグラウンドワークスペースにコマンドを注入します" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "ワークスペースを削除します" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -12206,54 +12207,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats「システムツール」 + echo -e "システムツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" + echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" + echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" + echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" + echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" + echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" + echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" + echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" + echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" + echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" + echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "ショートカットキーが設定されています" + send_stats "スクリプトのショートカットキーが設定されています" break_end linux_Settings done @@ -12261,34 +12262,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "ログインパスワードを設定します" + echo "ログインパスワードを設定します" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "ルートパスワードモード" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "Pyバージョン管理" + echo "Pythonバージョン管理" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" + echo "クエリの詳細:https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "スクリプトPy管理" break_end linux_Settings fi @@ -12321,7 +12322,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "不明なパッケージマネージャー!" return fi @@ -12350,55 +12351,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + send_stats "スイッチスクリプトPyバージョン" ;; 5) root_use - send_stats "开放端口" + send_stats "オープンポート" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "すべてのポートが開いています" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSHポートを変更します" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 現在のSSHポート番号をお読みください local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 現在のSSHポート番号を印刷します + echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # ユーザーに新しいSSHポート番号を入力するように促します + read -e -p "新しいSSHポート番号を入力してください:" new_port - # 判断端口号是否在有效范围内 + # ポート番号が有効な範囲内にあるかどうかを判断します if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSHポート変更を終了します" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "ポート番号が無効です。1〜65535の数字を入力してください。" + send_stats "無効なSSHポート入力" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "入力が無効です。番号を入力してください。" + send_stats "無効なSSHポート入力" break_end fi done @@ -12417,8 +12418,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "新しいユーザーはルートを無効にします" + read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12433,49 +12434,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "操作が完了しました。" ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6の優先度を設定します" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6の優先度を設定します" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "優先ネットワークを選択します。" choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4の優先度に切り替えました" + send_stats "IPv4の優先度に切り替えました" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6の優先度に切り替えました" + send_stats "IPv6の優先度に切り替えました" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + send_stats "IPv6修正" ;; *) @@ -12493,43 +12494,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "仮想メモリを設定します" while true; do clear - echo "设置虚拟内存" + echo "仮想メモリを設定します" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "選択を入力してください:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G仮想メモリが設定されています" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G仮想メモリが設定されています" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G仮想メモリが設定されています" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "カスタム仮想メモリが設定されています" ;; *) @@ -12542,8 +12543,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "ユーザー管理" + echo "ユーザーリスト" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12554,62 +12555,62 @@ EOF echo "" - echo "账户操作" + echo "アカウント操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3.最高の権限を与える4。最高の権限をキャンセルします" echo "------------------------" - echo "5. 删除账号" + echo "5.アカウントを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "操作が完了しました。" ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # ユーザーに新しいユーザー名を入力するように求めます + read -e -p "新しいユーザー名を入力してください:" new_username - # 创建新用户并设置密码 + # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 新規ユーザーのsudo許可を付与します echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作已完成。" + echo "操作が完了しました。" ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "ユーザー名を入力してください:" username + # 新規ユーザーのsudo許可を付与します echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "ユーザー名を入力してください:" username + # sudoersファイルからユーザーのsudo許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "削除するにはユーザー名を入力してください:" username + # ユーザーとそのホームディレクトリを削除します userdel -r "$username" ;; @@ -12622,50 +12623,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "ユーザー情報ジェネレーター" + echo "ランダムユーザー名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "ランダムユーザー名$i: $username" done echo "" - echo "随机姓名" + echo "ランダム名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5つのランダムユーザー名を生成します for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "ランダムなユーザー名$i: $user_name" done echo "" - echo "随机UUID" + echo "ランダムuuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "ランダムuuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" - echo "32位随机密码" + echo "32ビットランダムパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "ランダムなパスワード$i: $password" done echo "" @@ -12673,46 +12674,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "タイムゾーンを変更します" while true; do clear - echo "系统时间信息" + echo "システム時間情報" - # 获取当前系统时区 + # 現在のシステムタイムゾーンを取得します local timezone=$(current_timezone) - # 获取当前系统时间 + # 現在のシステム時間を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # タイムゾーンと時間を表示します + echo "現在のシステムタイムゾーン:$timezone" + echo "現在のシステム時間:$current_time" echo "" - echo "时区切换" + echo "タイムゾーンの切り替え" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "アジア" + echo "1。中国の上海時間2。中国の香港時間" + echo "3。日本の東京時間4。韓国のソウル時間" + echo "5。シンガポール時間6。インドのコルカタ時間" + echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" + echo "9。タイのバンコクでの時間" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "ヨーロッパ" + echo "11。英国のロンドン時間12。パリの時間フランスの時間" + echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" + echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "アメリカ" + echo "21。WesternTime22。東部時間" + echo "23。カナダ時間24。メキシコの時間" + echo "25。ブラジル時間26。アルゼンチン時間" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31。UTCグローバル標準時間" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -12755,21 +12756,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "ホスト名を変更します" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian、Ubuntu、Centosなどの他のシステム。 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12787,11 +12788,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "ホスト名は次のように変更されています。$new_hostname" + send_stats "ホスト名が変更されました" sleep 1 else - echo "已退出,未更改主机名。" + echo "終了すると、ホスト名は変更されていません。" break fi done @@ -12799,32 +12800,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "システムの更新ソースを変更します" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "更新ソース領域を選択します" + echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "あなたの選択を入力してください:" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "中国本土のデフォルトソース" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "中国本土の教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "海外起源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "キャンセル" ;; esac @@ -12832,62 +12833,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "タイミングタスク管理" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "タイミングされたタスクリスト" crontab -l echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1。毎月のタスク2。毎週のタスク" + echo "3。毎日のタスク4。時間ごとのタスク" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "タイムされたタスクを追加します" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "削除する必要があるキーワードを入力してください。" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "タイミングタスクを削除します" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "タイミングタスクを編集します" ;; *) break # 跳出循环,退出菜单 @@ -12899,32 +12900,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "ローカルホストの解析" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "ネイティブホストのペルシングリスト" + echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" cat /etc/hosts echo "" - echo "操作" + echo "動作します" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1.新しい解析2を追加します。解析アドレスを削除します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "ローカルホストの解析が追加されました" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "ローカルホストの解析と削除" ;; *) break # 跳出循环,退出菜单 @@ -12935,7 +12936,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH防御" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12947,20 +12948,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防衛プログラム$check_docker" + echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" + echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2。SSH傍受記録を表示します" + echo "3。リアルタイムログ監視" echo "------------------------" - echo "9. 卸载防御程序" + echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) install_docker @@ -12983,7 +12984,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防衛プログラムがアンインストールされています" ;; *) break @@ -12996,47 +12997,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "電流制限シャットダウン機能" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "電流制限シャットダウン機能" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.shファイルが存在するかどうかを確認してください if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gbの値を取得します local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 新しい仮想メモリサイズを入力します + echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" + read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13049,15 +13050,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "現在の制限シャットダウンが設定されています" + send_stats "現在の制限シャットダウンが設定されています" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "現在の制限シャットダウン関数はオフになっています" ;; *) break @@ -13070,40 +13071,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "秘密キーログイン" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ルート秘密キーログインモード" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "キーペアが生成され、SSHログインのより安全な方法" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "選択を入力してください:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "新しいキーを生成します" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "既存の公開キーをインポートします" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "地元の秘密の鍵を表示します" echo "------------------------" - echo "公钥信息" + echo "公開鍵情報" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "秘密のキー情報" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -13119,18 +13120,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "電報警告" + echo "TG-BOTモニタリングと早期警告機能" + echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "しきい値に達した後、ユーザーはユーザーに送信されます" + echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "電報警告が有効になっています" cd ~ install nano tmux bc jq check_crontab_installed @@ -13152,7 +13153,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # 〜/.Profileファイルに追加します if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -13163,21 +13164,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT早期警告システムが開始されました" + echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSHの高リスクの脆弱性を修正します" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13221,7 +13222,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "コマンドラインの履歴" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -13244,61 +13245,61 @@ EOF 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "メッセージボード" + echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "ワンストップチューニング" + echo "ワンストップシステムの最適化" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "以下が操作され、最適化されます" + echo "1.システムを最新の状態に更新します" + echo "2。システムジャンクファイルをクリーンアップします" + echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "5.すべてのポートを開きます" + echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" + echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "ワンストップチューニングスタート" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13315,25 +13316,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" + echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac @@ -13341,7 +13342,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "システムを再起動します" server_reboot ;; 100) @@ -13357,32 +13358,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "プライバシーとセキュリティ" + echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" + echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "現在のステータス:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1。コレクションをオンにします" + echo "2。コレクションを閉じます" echo "--------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "コレクションが有効になっています" + send_stats "プライバシーとセキュリティコレクションが有効になっています" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "コレクションは閉じた" + send_stats "プライバシーとセキュリティは収集のために閉鎖されています" ;; *) break @@ -13398,11 +13399,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "テックライオンスクリプトをアンインストールします" + echo "テックライオンスクリプトをアンインストールします" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in [Yy]) @@ -13410,16 +13411,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "スクリプトはアンインストールされています、さようなら!" break_end clear exit ;; [Nn]) - echo "已取消" + echo "キャンセル" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無効な選択、yまたはnを入力してください。" ;; esac ;; @@ -13429,7 +13430,7 @@ EOF ;; *) - echo "无效的输入!" + echo "無効な入力!" ;; esac break_end @@ -13447,187 +13448,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "ファイルマネージャー" while true; do clear - echo "文件管理器" + echo "ファイルマネージャー" echo "------------------------" - echo "当前路径" + echo "現在のパス" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" + echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" + echo "15.ファイルを削除します" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" + echo "25。ファイルを別のサーバーに渡します" echo "------------------------" - echo "0. 返回上一级选单" + echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "選択を入力してください:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "ディレクトリ名を入力してください:" dirname + cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" + send_stats "ディレクトリに移動します" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "作成するにはディレクトリ名を入力してください。" dirname + mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" + send_stats "ディレクトリを作成します" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "ディレクトリ名を入力してください:" dirname + read -e -p "許可(755など)を入力してください。" perm + chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ディレクトリ権限を変更します" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "現在のディレクトリ名を入力してください:" current_name + read -e -p "新しいディレクトリ名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" + send_stats "ディレクトリの名前を変更します" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "削除するには、ディレクトリ名を入力してください。" dirname + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" + send_stats "ディレクトリを削除します" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "前のメニューディレクトリに戻ります" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "作成するにはファイル名を入力してください。" filename + touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" + send_stats "ファイルを作成します" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "編集するにはファイル名を入力してください:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "ファイルを編集します" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "ファイル名を入力してください:" filename + read -e -p "許可(755など)を入力してください。" perm + chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" + send_stats "ファイル権限を変更します" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "現在のファイル名を入力してください:" current_name + read -e -p "新しいファイル名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" + send_stats "ファイルの名前を変更します" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "削除するには、ファイル名を入力してください。" filename + rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" + send_stats "ファイルを削除します" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" + send_stats "圧縮ファイル/ディレクトリ" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "ファイル名(.tar.gz)を入力してください:" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" + send_stats "ファイル/ディレクトリを解凍します" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + send_stats "ファイルまたはディレクトリを移動します" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "エラー:ファイルまたはディレクトリは存在しません。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "エラー:ターゲットパスを入力してください。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -Rオプションを使用して、ディレクトリを再帰的にコピーします + cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" + send_stats "ファイルまたはディレクトリをコピーします" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "転送されるファイルパスを入力してください。" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "エラー:ファイルは存在しません。" + send_stats "ファイルの転送に失敗しました:ファイルは存在しません" continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "エラー:リモートサーバーIPを入力してください。" + send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "エラー:リモートサーバーのパスワードを入力してください。" + send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "ログインポートを入力してください(デフォルト22):" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 既知のホストの古いエントリをクリアします ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCPを使用してファイルを転送します scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "スクリプトは最新です$sh_v_new" break_end ~/kejilion.sh exit @@ -13925,15 +13926,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" + send_stats "自動スクリプトの更新をオンにします" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" + send_stats "スクリプト自動更新を閉じます" break_end ;; *) @@ -13955,41 +13956,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" +echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" +echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" +echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" +echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" +echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" +echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" +echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" +echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" +echo -e "${gl_kjlan}13. ${gl_bai}システムツール" +echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" +echo -e "${gl_kjlan}15. ${gl_bai}広告列" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "選択を入力してください:" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "システムの更新" ; linux_update ;; + 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "ワープ管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -14000,13 +14001,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "無効な入力!" ;; esac break_end done @@ -14014,68 +14015,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "Kコマンド参照ユースケース" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "以下は、Kコマンドリファレンスユースケースです。" +echo "スクリプトkを開始します" +echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" +echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" +echo "システムKアップデートを更新| Kアップデート" +echo "クリーンシステムガベージkクリーン| kきれい" +echo "システムパネルk dd |を再インストールしますk再インストール" +echo "BBR3コントロールパネルK BBR3 | K BBRV3" +echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" +echo "仮想メモリkスワップ2048を設定します" +echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" +echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" +echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" +echo "SSHリモート接続ツールK SSH | Kリモート接続" +echo "rsyncリモート同期ツールk rsync | Kリモート同期" +echo "ハードディスク管理ツールKディスク| Kハードディスク管理" +echo "イントラネット浸透(サーバー側)K FRP" +echo "イントラネット浸透(クライアント)K FRPC" +echo "ソフトウェアStart K Start SSHD | k sshdを開始します" +echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" +echo "ソフトウェア再起動k再起動sshd | k再起動sshd" +echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" +echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" +echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書の有効期限クエリK SSL PS" +echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" +echo "Docker Container Management K Docker PS | K Dockerコンテナ" +echo "Docker Image Management K Docker IMG | K Docker画像" +echo "LDNMPサイト管理k Web" +echo "LDNMPキャッシュクリーンアップK Webキャッシュ" +echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" +echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" +echo "ロードバランスkロードバランス| kロードバランシングをインストールします" +echo "ファイアウォールパネルk fhq | kファイアウォール" +echo "オープンポートK DKDK 8080 | Kオープンポート8080" +echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" +echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" +echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" +echo "コマンドお気に入りk fav | Kコマンドのお気に入り" +echo "アプリ市場管理Kアプリ" +echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # パラメーターがない場合は、インタラクティブロジックを実行します kejilion_sh else - # 如果有参数,执行相应函数 + # パラメーターがある場合は、対応する関数を実行します case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "ソフトウェアをインストールします" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "ソフトウェアをアンインストールします" remove "$@" ;; update|更新) @@ -14109,7 +14110,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "タイム付きRSYNC同期" run_task "$@" ;; @@ -14128,7 +14129,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ポートは、サービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14141,13 +14142,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "仮想メモリをすばやく設定します" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "タイムゾーンをすばやく設定します" set_timedate "$@" ;; @@ -14195,42 +14196,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "ソフトウェアステータスビュー" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "ソフトウェアスタートアップ" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "ソフトウェアの一時停止" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "ソフトウェアの再起動" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "ソフトウェアが起動します" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "証明書のステータスを確認してください" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "すぐに証明書を申請してください" else k_info fi @@ -14240,15 +14241,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Dockerをすばやくインストールします" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "クイックコンテナ管理" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "クイックミラー管理" docker_image ;; *) @@ -14275,7 +14276,7 @@ else app) shift - send_stats "应用$@" + send_stats "$@を適用します" linux_panel "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index cab3eb64a..7aed0d70d 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# 명령을 실행할 함수를 정의합니다 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. +# 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# 사용자에게 이용 약관에 동의하라는 메시지 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}Tech Lion Script Toolbox에 오신 것을 환영합니다${gl_bai}" + echo "스크립트를 처음 사용하면 사용자 라이센스 계약을 읽고 동의하십시오." + echo "사용자 라이센스 계약 : https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "위의 용어에 동의하십니까? (Y/N) :" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "라이센스 동의" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "허가 거부" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "패키지 매개 변수는 제공되지 않습니다!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}설치$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return 1 fi fi @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}힌트:${gl_bai}불충분 한 디스크 공간!" + echo "현재 사용 가능한 공간 : $ ((uvery_space_mb/1024)) g" + echo "최소 수요 공간 :${required_gb}G" + echo "설치를 계속할 수 없습니다. 디스크 공간을 청소하고 다시 시도하십시오." + send_stats "불충분 한 디스크 공간" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "패키지 매개 변수는 제공되지 않습니다!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}제거$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -259,14 +259,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# 다양한 분포에 적합한 범용 SystemCTL 기능 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# 서비스를 다시 시작하십시오 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1서비스가 다시 시작되었습니다." else - echo "错误:重启 $1 服务失败。" + echo "오류 : 다시 시작합니다$1서비스가 실패했습니다." fi } -# 启动服务 +# 서비스를 시작하십시오 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1서비스가 시작되었습니다." else - echo "错误:启动 $1 服务失败。" + echo "오류 : 시작$1서비스가 실패했습니다." fi } -# 停止服务 +# 서비스 중지 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1서비스가 중단되었습니다." else - echo "错误:停止 $1 服务失败。" + echo "오류 : 중지$1서비스가 실패했습니다." fi } -# 查看服务状态 +# 서비스 상태를 확인하십시오 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1서비스 상태가 표시됩니다." else - echo "错误:无法显示 $1 服务状态。" + echo "오류 : 표시 할 수 없습니다$1서비스 상태." fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME전원 켜기로 설정합니다." } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" + echo "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" echo "" clear @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -424,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -499,63 +500,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "도커 컨테이너 관리" + echo "도커 컨테이너 목록" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "컨테이너 작동" echo "------------------------" - echo "1. 创建新的容器" + echo "1. 새 컨테이너를 만듭니다" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" + echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" + echo "4. 지정된 컨테이너를 삭제합니다. 8. 모든 컨테이너를 삭제하십시오" + echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" + echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "새 컨테이너를 만듭니다" + read -e -p "창조 명령을 입력하십시오 :" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 시작하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 중지하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 삭제하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 다시 시작하십시오" + read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "모든 컨테이너를 시작하십시오" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "모든 컨테이너를 중지하십시오" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "모든 컨테이너를 삭제하십시오" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -564,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "모든 컨테이너를 다시 시작하십시오" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너를 입력하십시오" + read -e -p "컨테이너 이름을 입력하십시오 :" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너 로그를 봅니다" + read -e -p "컨테이너 이름을 입력하십시오 :" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "컨테이너 네트워크를 봅니다" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -603,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "컨테이너 점유를 봅니다" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 액세스를 허용합니다" + read -e -p "컨테이너 이름을 입력하십시오 :" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -619,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 액세스 차단" + read -e -p "컨테이너 이름을 입력하십시오 :" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -639,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "도커 이미지 관리" + echo "도커 이미지 목록" docker image ls echo "" - echo "镜像操作" + echo "미러 작동" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" + echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "거울을 당기십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "이미지를 업데이트하십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "거울을 삭제하십시오" + read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "모든 이미지를 삭제합니다" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -685,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -753,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "지원되지 않는 분포 :$ID" return ;; esac else - echo "无法确定操作系统。" + echo "운영 체제를 결정할 수 없습니다." return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}Crontab이 설치되고 Cron 서비스가 실행 중입니다.${gl_bai}" } @@ -774,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 구성 파일이 존재하는지 확인하고 파일을 작성하고 기본 설정이 존재하지 않는 경우 작성하십시오. if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 구성 업데이트 및 IPv6을 활성화하십시오 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 원래 구성과 새로운 구성을 비교합니다 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 현재 활성화되어 있습니다${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -809,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}구성 파일이 존재하지 않습니다${gl_bai}" return fi - # 读取当前配置 + # 현재 구성을 읽으십시오 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 현재 IPv6 상태를 확인하십시오 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 원래 구성과 새로운 구성을 비교합니다 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스는 현재 닫힙니다${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 성공적으로 닫혔습니다${gl_bai}" fi } @@ -869,117 +870,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "하나 이상의 포트 번호를 제공하십시오" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 기존 마감 규칙을 삭제하십시오 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # 열린 규칙을 추가하십시오 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "포트가 열렸습니다$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "포트가 열렸습니다" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "하나 이상의 포트 번호를 제공하십시오" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 기존 열린 규칙을 삭제합니다 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 가까운 규칙을 추가하십시오 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "포트 폐쇄$port" fi done - # 删除已存在的规则(如果有) + # 기존 규칙 삭제 (있는 경우) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 새로운 규칙을 먼저 삽입하십시오 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "포트 폐쇄" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 기존 차단 규칙을 삭제하십시오 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 허용 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "IP 출시$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "IP 출시" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 기존 허용 규칙을 삭제합니다 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # 차단 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IP 차단$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IP 차단" } @@ -989,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 방어 DDO를 켜십시오 iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -999,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDOS 방어를 켜십시오" } -# 关闭DDoS防御 +# DDOS 방어를 끕니다 disable_ddos_defense() { - # 关闭防御 DDoS + # 방어 DDO를 끄십시오 iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1014,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDOS 방어를 끕니다" } -# 管理国家IP规则的函数 +# 국가 IP 규칙을 관리하는 기능 manage_country_rules() { local action="$1" local country_code="$2" @@ -1032,73 +1033,73 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # IPSET가 존재하지 않는 경우 작성하십시오 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IP 영역 파일을 다운로드하십시오 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" exit 1 fi - # 将 IP 添加到 ipset + # IPSET에 IP를 추가하십시오 while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 使用 iptables 阻止 IP + # iptables와 함께 IP를 차단하십시오 iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "성공적으로 차단되었습니다$country_codeIP 주소" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 허용 국가에 대한 IPSET 만들기 (존재하지 않는 경우) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # IP 영역 파일을 다운로드하십시오 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" exit 1 fi - # 删除现有的国家规则 + # 기존 국가 규칙을 삭제합니다 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # IPSET에 IP를 추가하십시오 while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 지정된 국가의 IP 만 허용됩니다 iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "성공적으로 만 허용됩니다$country_codeIP 주소" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 국가의 iptables 규칙을 삭제하십시오 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # ipset을 파괴하십시오 if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "성공적으로 해제했습니다$country_codeIP 주소 제한" ;; *) @@ -1115,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "고급 방화벽 관리" + send_stats "고급 방화벽 관리" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "방화벽 관리" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." + echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5. IP 화이트리스트 6. IP 블랙리스트" + echo "7. 지정된 IP를 지우십시오" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. 핑 허용 12. 핑을 비활성화하십시오" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15. 지정된 국가 IP 16. 지정된 국가 IP 만 허용됩니다." + echo "17. 지정된 국가에서 IP 제한을 해제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "열린 포트 번호를 입력하십시오 :" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "지정된 포트를 엽니 다" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "지정된 포트를 닫습니다" ;; 3) - # 开放所有端口 + # 모든 포트를 엽니 다 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1163,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "모든 포트를 엽니 다" ;; 4) - # 关闭所有端口 + # 모든 포트를 닫습니다 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1179,40 +1180,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "모든 포트를 닫습니다" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IP 화이트리스트 + read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IP 블랙리스트 + read -e -p "차단 된 IP 또는 IP 세그먼트를 입력하십시오." c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 지정된 IP를 지우십시오 + read -e -p "청산 된 IP를 입력하십시오 :" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "지정된 IP를 지우십시오" ;; 11) - # 允许 PING + # 핑을 허용하십시오 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "핑을 허용하십시오" ;; 12) - # 禁用 PING + # 핑을 비활성화합니다 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "핑을 비활성화합니다" ;; 13) enable_ddos_defense @@ -1222,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "차단 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "허용 국가$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "허용 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "나라를 차단하십시오$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "나라를 정리하십시오$country_codeIP" ;; *) @@ -1256,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 모든 스왑 파티션을 반복하고 삭제하십시오 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfile이 더 이상 사용되지 않도록하십시오 swapoff /swapfile - # 删除旧的 /swapfile + # 이전 /스왑 파일을 삭제하십시오 rm -f /swapfile - # 创建新的 swap 分区 + # 새 스왑 파티션을 만듭니다 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1287,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "가상 메모리 크기가 크기가 커졌습니다${gl_huang}${new_swap}${gl_bai}M" } @@ -1297,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 가상 메모리를 만들어야하는지 확인하십시오 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1313,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginx 버전을 얻으십시오 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # MySQL 버전을 얻으십시오 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHP 버전을 얻으십시오 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redis 버전을 얻으십시오 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1340,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 필요한 디렉토리 및 파일을 만듭니다 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1349,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.yml 파일을 다운로드하여 교체하십시오 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.yml 파일로 교체하십시오 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1398,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP 환경이 설치되었습니다" echo "------------------------" ldnmp_v @@ -1415,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "갱신 작업이 업데이트되었습니다" } @@ -1452,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming공개 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}인증서 저장 경로${gl_bai}" + echo "공개 키 :/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1469,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL 인증서를 신속하게 신청하고 만료 전에 서명을 자동으로 갱신하십시오.${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1485,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}응용 인증서 만료${gl_bai}" + echo "사이트 정보 인증서 만료 시간" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1525,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "도메인 이름 인증서 신청에 실패했습니다" + echo -e "${gl_hong}알아채다:${gl_bai}인증서 응용 프로그램이 실패했습니다. 가능한 이유를 확인하고 다시 시도하십시오." + echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." + echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." + echo -e "3. 네트워크 구성 문제 ➠ CloudFlare Warp 및 기타 가상 네트워크를 사용하는 경우 임시로 종료하십시오." + echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" + echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." + echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." break_end clear - echo "请再次尝试部署 $webname" + echo "다시 배포를 시도하십시오$webname" add_yuming install_ssltls certs_status @@ -1548,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "도메인 이름 재사용" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1557,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -1622,8 +1623,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" } @@ -1642,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "로그인 정보 :" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "시작$ldnmp_pods" } @@ -1656,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오 if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # 캐시 청소 여부를 사용자에게 프롬프트하십시오 + read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" + read -e -p "API_Token을 입력하십시오 :" API_TOKEN + read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL + read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 각 Zone_ID를 루프하고 CLEAR CACHE 명령을 실행하십시오. for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "Zone_ID의 캐시 지우기 :$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1686,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "캐시 클리어 요청이 전송되었습니다." } web_cache() { - send_stats "清理站点缓存" + send_stats "사이트 캐시를 정리하십시오" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1702,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "사이트 데이터 삭제" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하십시오 (여러 도메인 이름이 공간별로 분리됩니다)." yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "도메인 이름 삭제 :$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # 도메인 이름을 데이터베이스 이름으로 변환합니다 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. + echo "데이터베이스 삭제 :$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1739,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # 모드 매개 변수에 따라 WAF를 켜거나 끄기로 결정 if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAF 켜기 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # waf 닫기 : 댓글을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1802,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 오래된 정의를 삭제하십시오 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1829,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 오래된 정의를 삭제하십시오 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1857,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotli를 켜십시오 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1871,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotli를 닫습니다 : 주석을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1887,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1913,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # ZSTD를 켜십시오 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1928,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # Zstd를 닫습니다 : 주석을 추가하십시오 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1944,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1975,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" return 1 fi @@ -1989,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP 환경 방어" while true; do check_waf_status check_cf_mode @@ -2003,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "서버 웹 사이트 방어 프로그램${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5. SSH 차단 레코드보기 6. 웹 사이트 차단 레코드보기" + echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11. 인터셉트 매개 변수 구성 12. 차단 된 모든 IP를 지우십시오" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31. WAF 32를 켜십시오. WAF를 끄십시오" + echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램을 제거하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2081,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2ban 방어 프로그램은 제거되었습니다" ;; 11) @@ -2096,11 +2097,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "CloudFlare 모드" + echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CF 계정 번호를 입력하십시오." cfuser + read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2115,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "5 초 방패의 높은 하중" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CF 매개 변수 가져 오기 :" + echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" + echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CF 계정 번호를 입력하십시오." cfuser + read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID cd ~ install jq bc @@ -2146,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "고 부하 자동 방패 오프닝 스크립트가 추가되었습니다" else - echo "自动开盾脚本已存在,无需添加" + echo "자동 방패 스크립트가 이미 존재합니다. 추가 할 필요가 없습니다." fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "사이트 waf가 활성화되어 있습니다" + send_stats "사이트 waf가 활성화되어 있습니다" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "사이트 waf가 닫혔습니다" + send_stats "사이트 waf가 닫혔습니다" ;; 33) @@ -2188,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 현재 Worker_Processes 설정 값을 얻으십시오 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 값에 따라 모드 정보를 설정합니다 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2207,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # ZSTD가 활성화되어 있고 주석이 없는지 확인하십시오 (전체 라인은 ZSTD 켜기로 시작합니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # Brotli가 활성화되어 있고 댓글이 없는지 확인하십시오 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2237,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP 환경을 최적화하십시오" + echo -e "LDNMP 환경을 최적화하십시오${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" + echo "5. BR 압축 켜기 6. BR 압축 끄기" + echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "사이트 표준 모드" - # nginx调优 + # nginx 튜닝 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2275,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2287,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP 환경은 표준 모드로 설정되었습니다" ;; 2) - send_stats "站点高性能模式" + send_stats "사이트 고성능 모드" - # nginx调优 + # nginx 튜닝 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2315,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2325,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP 환경은 고성능 모드로 설정되었습니다" ;; 3) @@ -2385,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker = "$ {gl_lv} $ {gl_bai} 설치" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" # fi # } @@ -2395,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "액세스 주소 :" ip_address @@ -2433,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # 컨테이너 생성 시간과 이미지 이름을 얻으십시오 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # 거울 창고 및 태그 추출 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # 기본 레이블이 최신입니다 [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 공식 이미지에 대한 지원을 추가하십시오 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # Docker Hub API에서 이미지 게시 시간을 얻으십시오 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 획득 시간을 확인하십시오 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # 타임 스탬프를 비교하십시오 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2476,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소를 가져옵니다 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2486,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 다른 모든 IP를 점검하고 차단하십시오 if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP를 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 다른 모든 IP를 점검하고 차단하십시오 if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP를 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2523,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" save_iptables_rules } @@ -2534,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소를 가져옵니다 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2544,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 지정된 IP를 공개하기위한 규칙을 지우십시오 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2563,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 지정된 IP를 공개하기위한 규칙을 지우십시오 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2584,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+포트는 서비스에 액세스 할 수있었습니다" save_iptables_rules } @@ -2598,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 다른 모든 IP 액세스를 거부했습니다 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP 액세스를 허용합니다 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스를 허용합니다 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2625,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 다른 모든 IP 액세스를 거부했습니다 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP 액세스를 허용합니다 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스를 허용합니다 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 확립 및 관련 연결을 위해 트래픽을 허용합니다 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" save_iptables_rules } @@ -2657,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "사용법 : CLEAR_HOST_PORT_RULES <포트 번호> <승인 IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP 액세스를 차단하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 기본 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP 액세스를 차단하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 기본 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+포트는 서비스에 액세스 할 수있었습니다" save_iptables_rules } @@ -2726,7 +2727,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}管理" +send_stats "${docker_name}관리하다" while true; do clear @@ -2746,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2770,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "설치하다$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2785,12 +2786,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "고쳐 쓰다$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2799,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "앱이 제거되었습니다" + send_stats "제거하십시오$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 액세스 설정" + send_stats "${docker_name}도메인 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 액세스를 차단하십시오${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2859,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2894,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 액세스 설정" + send_stats "${docker_name}도메인 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 액세스를 차단하십시오${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2994,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# 세션이 존재하는지 확인하는 기능 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 존재하지 않는 세션 이름이 발견 될 때까지 루프 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 새로운 TMUX 세션을 만듭니다 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3079,11 +3080,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "다시 시작" reboot ;; *) - echo "已取消" + echo "취소" ;; esac @@ -3126,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP 환경을 다시 설치할 수 없습니다" + echo -e "${gl_huang}힌트:${gl_bai}웹 사이트 구성 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" break_end linux_ldnmp fi @@ -3137,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP 환경을 설치하십시오" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3154,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "Nginx 환경을 설치하십시오" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3168,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "Nginx가 설치되었습니다" +echo -e "현재 버전 :${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3180,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "먼저 LDNMP 환경을 설치하십시오" ldnmp_install_all fi @@ -3190,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "Nginx 환경을 먼저 설치하십시오" nginx_install_all fi @@ -3201,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "당신 것$webname세워짐!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webname설치 정보는 다음과 같습니다." } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "당신 것$webname세워짐!" echo "https://$yuming" } @@ -3222,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3263,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "반세대 IP를 입력하십시오 :" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "반세대 포트를 입력하십시오 :" port fi nginx_install_status install_ssltls @@ -3296,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port fi nginx_install_status @@ -3356,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMP 사이트 관리" + echo "LDNMP 환경" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "대지:${output}인증서 만료 시간" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3374,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "데이터 베이스:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "사이트 디렉토리" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" + echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" + echo "5. 액세스 로그보기 6. 오류 로그보기" + echo "7. 글로벌 구성 편집 8. 사이트 구성 편집" + echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서보기" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. 지정된 사이트 데이터를 삭제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "도메인 이름 인증서를 신청하십시오" + read -e -p "도메인 이름을 입력하십시오 :" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3411,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "사이트 도메인 이름을 변경하십시오" + echo -e "${gl_hong}적극 권장 :${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" + read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming + read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot install_ssltls certs_status - # mysql替换 + # MySQL 교체 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3437,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # 웹 사이트 디렉토리 교체 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3458,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "관련 사이트를 만듭니다" + echo -e "액세스 용 기존 사이트의 새 도메인 이름을 연결하십시오." + read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming + read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot install_ssltls certs_status @@ -3475,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "액세스 로그를 봅니다" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "오류 로그를 봅니다" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "글로벌 구성 편집" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "사이트 구성 편집" + read -e -p "사이트 구성을 편집하려면 편집 할 도메인 이름을 입력하십시오." yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3503,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "사이트 데이터를 봅니다" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3534,21 +3535,21 @@ fi install_panel() { -send_stats "${panelname}管理" +send_stats "${panelname}관리하다" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}요즘 인기 있고 강력한 운영 및 유지 관리 패널입니다." + echo "공식 웹 사이트 소개 :$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 설치 2. 관리 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space 1 @@ -3557,20 +3558,20 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}설치하다" ;; 2) panel_app_manage mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}控制" + send_stats "${panelname}제어" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}제거하십시오" ;; *) break @@ -3614,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRP 서버를 설치하십시오" + # 임의의 포트 및 자격 증명을 생성합니다 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3636,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 출력 생성 정보 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "클라이언트 배포에 필요한 매개 변수" + echo "서비스 IP :$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRP 패널 정보" + echo "FRP 패널 주소 : http : //$ipv4_address:$dashboard_port" + echo "FRP 패널 사용자 이름 :$dashboard_user" + echo "FRP 패널 비밀번호 :$dashboard_pwd" echo open_port 8055 8056 @@ -3656,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRP 클라이언트를 설치하십시오" + read -e -p "외부 네트워크 도킹 IP를 입력하십시오." server_addr + read -e -p "외부 네트워크 도킹 토큰을 입력하십시오." token echo mkdir -p /home/frp @@ -3678,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRP 인트라넷 서비스를 추가하십시오" + # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 + read -e -p "서비스 이름을 입력하십시오 :" service_name + read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "인트라넷 포트를 입력하십시오 :" local_port + read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port - # 将用户输入写入配置文件 + # 구성 파일에 사용자 입력을 쓰십시오 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3698,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 출력 생성 정보 + echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다" docker restart frpc @@ -3710,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRP 인트라넷 서비스를 삭제하십시오" + # 삭제 해야하는 서비스 이름을 입력하라는 메시지 + read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name + # SED를 사용하여 서비스 및 관련 구성을 삭제하십시오. sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" docker restart frpc @@ -3725,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # 헤더를 인쇄하십시오 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3746,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 서비스 정보가있는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3755,11 +3756,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 현재 서비스 이름을 업데이트하십시오 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 이전 값을 지우십시오 local_ip="" local_port="" remote_port="" @@ -3788,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 마지막 서비스에 대한 정보를 인쇄하십시오 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3801,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRP 서버 포트를 가져옵니다 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# 액세스 주소를 생성합니다 generate_access_urls() { - # 首先获取所有端口 + # 모든 포트를 먼저 얻으십시오 get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056 이외의 포트가 있는지 확인하십시오 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3820,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 유효한 포트가있을 때만 제목과 콘텐츠 표시 if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP 서비스 외부 액세스 주소 :" - # 处理 IPv4 地址 + # 프로세스 IPv4 주소 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # Process IPv6 주소 (현재 경우) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3840,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS 구성 처리 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3867,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRP 서버" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3875,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP 서버$check_frp $update_status" + echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." + echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5. 인트라넷 서비스에 대한 도메인 이름 액세스 6. 도메인 이름 액세스 삭제" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. 서비스 상태 새로 고침 0. 이전 메뉴로 돌아갑니다." echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) install jq grep ss @@ -3901,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "FRP 서버가 설치되었습니다" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3911,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "FRP 서버가 업데이트되었습니다" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3922,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" + send_stats "외부 도메인 이름에 대한 FRP 액세스" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IP 액세스 허용" + read -e -p "해제 할 포트를 입력하십시오." frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IP 액세스를 차단하십시오" + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." + read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRP 서비스 상태를 새로 고치십시오" + echo "FRP 서비스 상태가 새로 고쳐졌습니다" ;; *) @@ -3965,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRP 클라이언트" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3973,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP 클라이언트$check_frp $update_status" + echo "서버로 도킹, 도킹 후 인터넷 액세스에 인트라넷 침투 서비스를 만들 수 있습니다." + echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3984,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 구성 수동으로 서비스 구성" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) install jq grep ss @@ -3998,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "FRP 클라이언트가 설치되었습니다" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4008,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "FRP 클라이언트가 업데이트되었습니다" ;; 3) @@ -4019,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; 4) @@ -4065,68 +4066,68 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "YT-DLP 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "YT-DLP는 YouTube, Bilibili, Twitter 등을 포함한 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." + echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "다운로드 된 비디오 목록 :" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. 단일 비디오 다운로드 6. 배치 비디오 다운로드 7. 사용자 정의 매개 변수 다운로드" + echo "8. MP3 오디오 9. 비디오 디렉토리 삭제 10. 쿠키 관리 (개발 중)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "옵션 번호를 입력하십시오 :" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "yt-dlp 설치 ..." + echo "yt-dlp 설치 ..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlp 업데이트 ..." + echo "yt-dlp 업데이트 ..." yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlp 제거 ..." + echo "yt-dlp 제거 ..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "단일 비디오 다운로드" + read -e -p "비디오 링크를 입력하십시오 :" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "다운로드가 완료되면 키를 눌러 계속하십시오 ..." ;; 6) - send_stats "批量视频下载" + send_stats "배치 비디오 다운로드" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "이제 배치 다운로드를 시작하십시오 ..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4134,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "배치 다운로드가 완료되었습니다. 키를 눌러 계속하십시오 ..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "맞춤형 비디오 다운로드" + read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3 다운로드" + read -e -p "비디오 링크를 입력하십시오 :" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "오디오 다운로드가 완료되었습니다. 키를 누르면 계속하십시오 ..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "비디오 삭제" + read -e -p "삭제 비디오의 이름을 입력하십시오." rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4194,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# DPKG 인터럽트 문제를 수정하십시오 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4203,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4222,7 +4223,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi } @@ -4230,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}시스템 정리 ...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4259,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 청소 ..." apk cache clean - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APK 캐시 삭제 ..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4283,23 +4284,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "사용하지 않는 의존성 정리 ..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 청소 ..." pkg clean -y - echo "删除系统日志..." + echo "시스템 로그 삭제 ..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제 ..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi return @@ -4339,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNS 최적화" while true; do clear - echo "优化DNS地址" + echo "DNS 주소를 최적화합니다" echo "------------------------" - echo "当前DNS地址" + echo "현재 DNS 주소" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1. 외국 DNS 최적화 :" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2. 국내 DNS 최적화 :" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3. DNS 구성을 수동으로 편집합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4366,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "외국 DNS 최적화" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4374,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "국내 DNS 최적화" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS 구성을 수동으로 편집합니다" ;; *) break @@ -4402,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # PasswordAuthentication이 발견되면 예로 설정하십시오 if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 발견 된 경우 PubKeyAuthentication이 예로 설정됩니다 if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4416,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # PasswordAuthentication 또는 PubKeyAuthentication이 일치하지 않는 경우 기본값을 설정하십시오. if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4427,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # 백업 SSH 구성 파일 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4440,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSH 포트는 다음으로 수정되었습니다.$new_port" sleep 1 @@ -4458,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "개인 키 정보가 생성되었습니다. 복사하고 저장하십시오.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인 파일" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4470,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}루트 프라이빗 키 로그인이 활성화되고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH 공개 키 내용을 입력하십시오 (일반적으로 'SSH-RSA'또는 'SSH-ED25519'로 시작) :" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}오류 : 공개 키 컨텐츠가 입력되지 않았습니다.${gl_bai}" return 1 fi @@ -4498,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}공개 키가 성공적으로 가져 왔고 루트 개인 키 로그인이 활성화되었고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" } @@ -4507,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "루트 비밀번호를 설정하십시오" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능은 루트 사용자가 실행해야합니다!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "시스템을 다시 설치하십시오" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4537,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}Teddysun.com${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "시스템을 다시 설치하십시오" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." + echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4587,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "데비안 13을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4609,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "데비안 12를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "데비안 11을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "데비안 10을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "우분투 24.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "우분투 22.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "Ubuntu 20.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "우분투 18.04를 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4660,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "Rockylinux10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4668,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "Rockylinux9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4676,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "Alma10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4684,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "Alma9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4692,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "Oracle10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4700,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "Oracle9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4708,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "Fedora42를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4716,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "Fedora41을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4724,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "CentOS10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4732,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "CentOS9를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4740,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "알파인을 다시 설치하십시오" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4748,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "아치를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh arch reboot @@ -4756,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "칼리를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh kali reboot @@ -4764,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "Openeuler를 다시 설치하십시오" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4772,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "재설치 OpenSuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4780,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "비행 소부소" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4789,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "Windows 11을 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4797,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "Windows 10을 다시 설치하십시오" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows 7을 다시 설치하십시오" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4811,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "Windows Server 22를 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "Windows Server 19를 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "Windows Server 16을 다시 설치하십시오" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4833,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "Windows11 Arm을 다시 설치하십시오" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4850,7 +4851,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "BBRV3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4863,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "Xanmod의 BBRV3 커널을 설치했습니다" + echo "현재 커널 버전 :$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. BBRV3 커널 업데이트 2. BBRV3 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) @@ -4883,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3 단계 : 저장소를 추가합니다 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4892,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "Xanmod 커널이 업데이트되었습니다. 다시 시작한 후에도 적용됩니다" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4902,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "Xanmod 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" server_reboot ;; @@ -4915,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3 가속도를 설정하십시오" + echo "비디오 소개 : https://www.bilibili.com/video/bv14k421x7bs?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "데비안/우분투 만 지원합니다" + echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -4929,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "현재 환경은이를 지원하지 않으며 데비안 및 우분투 시스템 만 지원합니다." break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "운영 체제 유형을 결정할 수 없습니다" break_end linux_Settings fi @@ -4945,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3 단계 : 저장소를 추가합니다 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4956,17 +4957,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac fi @@ -4975,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # Elrepo GPG 공개 키를 가져 오십시오 + echo "Elrepo GPG 공개 키를 가져 오십시오 ..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # 시스템 버전을 감지하십시오 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 지원되는 운영 체제에서 실행하십시오 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "지원되지 않는 운영 체제 :$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 감지 된 운영 체제 정보를 인쇄합니다 + echo "운영 체제 감지 :$os_name $os_version" + # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "Elrepo 저장소 구성 (버전 9)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "지원되지 않는 시스템 버전 :$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오. + echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "Elrepo 저장소 구성이 설치되어 최신 메인 라인 커널로 업데이트됩니다." server_reboot } @@ -5016,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "레드 모자 커널 관리" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "Elrepo 커널을 설치했습니다" + echo "현재 커널 버전 :$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hat 커널을 업데이트하십시오" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "Elrepo 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" + send_stats "빨간 모자 커널을 제거하십시오" server_reboot ;; @@ -5059,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "데이터를 백업하고 Linux 커널을 업그레이드합니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" + echo "Linux 커널을 업그레이드하면 시스템 성능 및 보안이 향상 될 수 있습니다. 조건이 허용되고 생산 환경을 조심스럽게 업그레이드하는 경우 시도하는 것이 좋습니다!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hat 커널을 업그레이드하십시오" server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac fi @@ -5089,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}바이러스 데이터베이스 업데이트 ...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5099,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "스캔 할 디렉토리를 지정하십시오." return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}스캔 디렉토리 $@...${gl_bai}" - # 构建 mount 参数 + # 마운트 매개 변수를 빌드하십시오 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # Clamscan 명령 매개 변수를 작성하십시오 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5120,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # Docker 명령을 실행하십시오 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5129,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@ scan이 완료되고 바이러스 보고서가 저장됩니다${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}바이러스가 있다면 제발${gl_huang}scan.log${gl_lv}파일에서 찾은 키워드를 검색하여 바이러스의 위치를 ​​확인하십시오.${gl_bai}" } @@ -5142,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "바이러스 스캔 관리" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "Clamav 바이러스 스캐닝 도구" + echo "비디오 소개 : https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "오픈 소스 바이러스 백신 소프트웨어 도구로 주로 다양한 유형의 맬웨어를 감지하고 제거하는 데 사용됩니다." + echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리를 스캔하십시오${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "전체 디스크 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5167,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "중요한 디렉토리 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5175,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "사용자 정의 디렉토리 스캔" + read -e -p "스캔 할 디렉토리를 입력하십시오." directories install_docker clamav_freshclam clamav_scan $directories @@ -5193,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# 고성능 모드 최적화 기능 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}전환하십시오${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5219,36 +5220,36 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # NUMA 밸런싱을 비활성화합니다 sysctl -w kernel.numa_balancing=0 2>/dev/null } -# 均衡模式优化函数 +# 이퀄라이제이션 모드 최적화 기능 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5260,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 투명 페이지를 복원하십시오 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # NUMA 밸런싱을 복원하십시오 sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# 기본 설정 기능을 복원하십시오 restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}기본 설정으로 복원하십시오 ...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 디스크립터 복원 ...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 복원 ...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 복원 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 복원 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}다른 최적화를 복원 ...${gl_bai}" + # 투명 페이지를 복원하십시오 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # NUMA 밸런싱을 복원하십시오 sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# 웹 사이트 구축 최적화 기능 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5343,16 +5344,16 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing + # NUMA 밸런싱을 비활성화합니다 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5363,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux 커널 튜닝 관리" + echo "Linux 시스템에서 커널 매개 변수의 최적화" + echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." + echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." + echo "2. 균형 최적화 모드 : 매일 사용하기에 적합한 성능과 자원 소비 사이의 균형." + echo "3. 웹 사이트 최적화 모드 : 웹 사이트 서버에 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." + echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." + echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." + echo "6. 기본 설정을 복원하십시오. 시스템 설정을 기본 구성으로 복원하십시오." echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "고성능 모드 최적화" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "균형 모드 최적화" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "웹 사이트 최적화 모델" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "라이브 스트리밍 최적화" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "게임 서버 최적화" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "기본 설정을 복원하십시오" ;; *) break @@ -5445,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end @@ -5454,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "지원되지 않는 시스템 :$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "지원되지 않는 시스템, 시스템 유형을 인식 할 수 없습니다." break_end fi } @@ -5474,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "스위치 시스템 언어" while true; do clear - echo "当前系统语言: $LANG" + echo "현재 시스템 언어 :$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. 영어 2. 중국어 3. 전통 중국어" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "영어로 전환하십시오" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "단순화 된 중국어로 전환하십시오" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "전통적인 중국어로 전환하십시오" ;; *) break @@ -5518,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 볼 수 있도록 SSH를 다시 ​​연결하십시오!${gl_bai}" hash -r break_end @@ -5529,10 +5530,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "명령 라인 미화 도구" while true; do clear - echo "命令行美化工具" + echo "명령 라인 미화 도구" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5542,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -5589,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "시스템 재활용 스테이션" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5604,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "현재 재활용 쓰레기통${trash_status}" + echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "재활용 쓰레기통은 비어 있습니다" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1. 재활용 빈을 활성화합니다. 2. 재활용 쓰레기통을 닫습니다." + echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -5622,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "Recycle Bin이 활성화되고 삭제 된 파일이 Recycle Bin으로 이동됩니다." sleep 2 ;; 2) @@ -5630,23 +5631,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "재활용 빈이 닫히고 파일이 직접 삭제됩니다." sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "복원 할 파일 이름을 입력하십시오." file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restore홈 디렉토리로 복원되었습니다." else - echo "文件不存在。" + echo "파일이 존재하지 않습니다." fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "재활용 쓰레기통을 지우셨습니까? [Y/N] :" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "재활용 쓰레기통이 지워졌습니다." fi ;; *) @@ -5657,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "명령 즐겨 찾기" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# 백업을 만듭니다 create_backup() { - send_stats "创建备份" + send_stats "백업을 만듭니다" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 + echo "백업 예제 :" + echo "- 단일 디렉토리를 백업 : /var /www" + echo "- 여러 디렉토리 백업 : /etc /home /var /log" + echo "- Direct Enter는 기본 디렉토리 ( /etc /usr /home)를 사용합니다." + read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input - # 如果用户没有输入目录,则使用默认目录 + # 사용자가 디렉토리를 입력하지 않으면 기본 디렉토리를 사용하십시오. if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5681,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 사용자가 입력 한 디렉토리를 공백 별 배열로 분리합니다. IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 백업 파일 접두사를 생성합니다 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # 디렉토리 이름을 추출하고 슬래시를 제거하십시오 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 마지막 밑줄을 제거하십시오 local PREFIX=${PREFIX%_} - # 生成备份文件名 + # 백업 파일 이름을 생성합니다 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # 사용자가 선택한 디렉토리를 인쇄하십시오 + echo "선택한 백업 디렉토리는 다음과 같습니다." for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # 백업을 만듭니다 + echo "백업 생성$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # 명령이 성공했는지 확인하십시오 if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "백업은 성공적으로 생성되었습니다.$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "백업 생성이 실패했습니다!" exit 1 fi } -# 恢复备份 +# 백업을 복원하십시오 restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "백업을 복원하십시오" + # 복원하려는 백업을 선택하십시오 + read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "백업 복구$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "백업 및 복원을 성공적으로 복원하십시오!" else - echo "备份恢复失败!" + echo "백업 복구 실패!" exit 1 fi } -# 列出备份 +# 백업을 나열합니다 list_backups() { - echo "可用的备份:" + echo "사용 가능한 백업 :" ls -1 "$BACKUP_DIR" } -# 删除备份 +# 백업을 삭제하십시오 delete_backup() { - send_stats "删除备份" + send_stats "백업을 삭제하십시오" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "삭제하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - # 删除备份 + # 백업을 삭제하십시오 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "백업이 성공적으로 삭제되었습니다!" else - echo "备份删除失败!" + echo "백업 삭제가 실패했습니다!" exit 1 fi } -# 备份主菜单 +# 백업 메인 메뉴 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "시스템 백업 기능" + echo "시스템 백업 기능" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1. 백업 만들기 2. 백업 복원 3. 백업 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } @@ -5805,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# 연결 목록 표시 list_connections() { - echo "已保存的连接:" + echo "저장된 연결 :" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 새 연결을 추가하십시오 add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "새 연결을 추가하십시오" + echo "새 연결을 만드는 예 :" + echo "- 연결 이름 : my_server" + echo "-IP 주소 : 192.168.1.100" + echo "- 사용자 이름 : 루트" + echo "- 포트 : 22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "연결 이름을 입력하십시오 :" name + read -e -p "IP 주소를 입력하십시오 :" ip + read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "인증 방법을 선택하십시오 :" + echo "1. 비밀번호" + echo "2. 키" + read -e -p "선택 (1/2)을 입력하십시오 :" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "비밀번호를 입력하십시오 :" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 주요 내용인지 확인하십시오 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5863,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "잘못된 선택!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "연결이 저장됩니다!" } -# 删除连接 +# 연결을 삭제하십시오 delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "연결을 삭제하십시오" + read -e -p "삭제하려면 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류 : 해당 연결을 찾을 수 없었습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "연결이 삭제되었습니다!" } -# 使用连接 +# 연결을 사용하십시오 use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "연결을 사용하십시오" + read -e -p "사용할 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류 : 해당 연결을 찾을 수 없었습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "연결$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 키와 연결하십시오 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "연결 실패! 다음을 확인하십시오." + echo "1. 키 파일 경로가 정확합니까?$password_or_key" + echo "2. 키 파일 권한이 올바른지 여부 (600이어야 함)." + echo "3. 대상 서버가 키를 사용하여 로그인 할 수 있는지 여부." fi else - # 使用密码连接 + # 비밀번호로 연결하십시오 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "설치 방법 :" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "연결 실패! 다음을 확인하십시오." + echo "1. 사용자 이름과 비밀번호가 올바른지 여부." + echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." + echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSH 원격 연결 도구" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 구성 파일과 키 디렉토리가 존재하는지 확인하고 존재하지 않으면 작성하십시오. if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5957,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSH 원격 연결 도구" + echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. 새 연결 만들기 2. 연결 사용 3. 연결 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "잘못된 선택, 다시 시도하십시오." ;; esac done } @@ -5987,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 사용 가능한 하드 디스크 파티션을 나열하십시오 list_partitions() { - echo "可用的硬盘分区:" + echo "사용 가능한 하드 디스크 파티션 :" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# 파티션을 장착하십시오 mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "파티션을 장착하십시오" + read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "파티션은 이미 장착되어 있습니다!" return fi - # 创建挂载点 + # 마운트 포인트를 만듭니다 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # 파티션을 장착하십시오 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "파티션 마운트 성공적으로 :$MOUNT_POINT" else - echo "分区挂载失败!" + echo "파티션 마운트 실패!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# 파티션을 제거하십시오 unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "파티션을 제거하십시오" + read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "파티션이 장착되지 않았습니다!" return fi - # 卸载分区 + # 파티션을 제거하십시오 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "파티션 분할 해제 성공 :$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "파티션 제거 실패!" fi } -# 列出已挂载的分区 +# 목록 장착 파티션 list_mounted_partitions() { - echo "已挂载的分区:" + echo "마운트 파티션 :" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# 형식 파티션 format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "형식 파티션" + read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区是否已经挂载 + # 파티션이 이미 장착되어 있는지 확인하십시오 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "파티션이 장착되었습니다. 먼저 제거하십시오!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # 파일 시스템 유형을 선택하십시오 + echo "파일 시스템 유형을 선택하십시오 :" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "선택을 입력하십시오 :" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "잘못된 선택!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # 형식을 확인하십시오 + read -e -p "파티션 형식 확인 /dev /$PARTITION~을 위한$FS_TYPE그게? (Y/N) :" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "작업이 취소되었습니다." return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # 형식 파티션 + echo "파티션 서식 /dev /$PARTITION~을 위한$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "파티션 형식이 성공적이었습니다!" else - echo "分区格式化失败!" + echo "파티션 형식이 실패했습니다!" fi } -# 检查分区状态 +# 파티션 상태를 확인하십시오 check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "파티션 상태를 확인하십시오" + read -e -p "파티션 이름을 입력하여 확인하십시오 (예 : SDA1) :" PARTITION - # 检查分区是否存在 + # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # 파티션 상태를 확인하십시오 + echo "파티션 /개발자 /$PARTITION상태:" fsck "/dev/$PARTITION" } -# 主菜单 +# 메인 메뉴 disk_manager() { - send_stats "硬盘管理功能" + send_stats "하드 디스크 관리 기능" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "하드 디스크 파티션 관리" + echo -e "${gl_huang}이 기능은 테스트 기간 동안 내부적으로 테스트되므로 생산 환경에서 사용하지 마십시오.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" + echo "4. 파티션 형식 5. 파티션 상태를 확인하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6145,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } -# 显示任务列表 +# 작업 목록 표시 list_tasks() { - echo "已保存的同步任务:" + echo "저장된 동기화 작업 :" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 새로운 작업을 추가하십시오 add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "새 동기화 작업을 추가하십시오" + echo "새 동기화 작업 작성 예 :" + echo "- 작업 이름 : Backup_www" + echo "- 로컬 디렉토리 : /var /www" + echo "- 원격 주소 : user@192.168.1.100" + echo "- 원격 디렉토리 : /백업 /www" + echo "- 포트 번호 (기본 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "작업 이름을 입력하십시오 :" name + read -e -p "로컬 디렉토리를 입력하십시오 :" local_path + read -e -p "원격 디렉토리를 입력하십시오 :" remote_path + read -e -p "원격 사용자 @IP를 입력하십시오 :" remote + read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "인증 방법을 선택하십시오 :" + echo "1. 비밀번호" + echo "2. 키" + read -e -p "선택하십시오 (1/2) :" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "비밀번호를 입력하십시오 :" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 주요 내용인지 확인하십시오 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6210,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "잘못된 키 컨텐츠!" return fi ;; *) - echo "无效的选择!" + echo "잘못된 선택!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "동기화 모드를 선택하십시오 :" + echo "1. 표준 모드 (-avz)" + echo "2. 대상 파일 삭제 (-avz-delete)" + read -e -p "선택하십시오 (1/2) :" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "유효하지 않은 선택, 기본값 -AVZ를 사용하십시오"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "작업을 저장했습니다!" } -# 删除任务 +# 작업을 삭제하십시오 delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 작업을 삭제합니다" + read -e -p "삭제하려면 작업 번호를 입력하십시오." num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "오류 : 해당 작업을 찾을 수 없었습니다." return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "작업이 삭제되었습니다!" } run_task() { - send_stats "执行同步任务" + send_stats "동기화 작업을 수행하십시오" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # 매개 변수를 분석하십시오 local direction="push" # 默认是推送到远端 local num @@ -6277,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 들어오는 작업 번호가없는 경우 사용자에게 입력하라는 메시지를 표시하십시오. if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "실행할 작업 번호를 입력하십시오." num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "오류 : 작업이 찾을 수 없었습니다!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 동기화 방향에 따라 소스 및 대상 경로를 조정하십시오 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "동기화를 원격 끝으로 푸시합니다.$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH 연결 공통 매개 변수를 추가하십시오 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "설치 방법 :" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # 키 파일이 존재하는지 여부와 권한이 올바른지 확인 if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "오류 : 키 파일이 존재하지 않습니다.$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "경고 : 키 파일 권한이 잘못되었고 수리 중입니다 ..." chmod 600 "$password_or_key" fi @@ -6329,32 +6330,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "동기화가 완료되었습니다!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "동기화 실패! 다음을 확인하십시오." + echo "1. 네트워크 연결이 정상입니까?" + echo "2. 원격 호스트가 액세스 할 수 있습니까?" + echo "3. 인증 정보가 정확합니까?" + echo "4. 로컬 및 원격 디렉토리에 올바른 액세스 권한이 있습니까?" fi } -# 创建定时任务 +# 시간이 정한 작업을 만듭니다 schedule_task() { - send_stats "添加同步定时任务" + send_stats "동기화 타이밍 작업을 추가하십시오" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류 : 유효한 작업 번호를 입력하십시오!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "시간이 정한 실행 간격을 선택하십시오." + echo "1) 한 시간에 한 번 실행하십시오" + echo "2) 하루에 한 번 수행하십시오" + echo "3) 일주일에 한 번 실행하십시오" + read -e -p "옵션을 입력하십시오 (1/2/3) :" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6362,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "오류 : 유효한 옵션을 입력하십시오!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 동일한 작업이 이미 존재하는지 확인하십시오 if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "오류 :이 작업의 타이밍 동기화가 이미 존재합니다!" return fi - # 创建到用户的 crontab + # 사용자에게 크론AB를 만듭니다 (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "타이밍 작업이 만들어졌습니다.$cron_job" } -# 查看定时任务 +# 예정된 작업을 봅니다 view_tasks() { - echo "当前的定时任务:" + echo "현재 타이밍 작업 :" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# 타이밍 작업을 삭제하십시오 delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 타이밍 작업을 삭제합니다" + read -e -p "삭제하려면 작업 번호를 입력하십시오." num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류 : 유효한 작업 번호를 입력하십시오!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "삭제 된 작업 번호$num타이밍 작업" } -# 任务管理主菜单 +# 작업 관리 메인 메뉴 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "RSYNC 원격 동기화 도구" + echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1. 새 작업 생성 2. 작업을 삭제하십시오" + echo "3. 원격 끝에 로컬 동기화 수행 4. 로컬 엔드에 대한 원격 동기화 수행" + echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6430,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "잘못된 선택, 다시 시도하십시오." ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르십시오 ..." done } @@ -6447,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "시스템 정보 쿼리" ip_address @@ -6497,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "시스템 정보 쿼리" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}호스트 이름 :${gl_bai}$hostname" + echo -e "${gl_kjlan}시스템 버전 :${gl_bai}$os_info" + echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU 모델 :${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU 코어 수 :${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" + echo -e "${gl_kjlan}물리적 기억 :${gl_bai}$mem_info" + echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" + echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}네트워크 알고리즘 :${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4 주소 :${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6 주소 :${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS 주소 :${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}지리적 위치 :${gl_bai}$country $city" + echo -e "${gl_kjlan}시스템 시간 :${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" echo @@ -6544,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats "기본 도구" + echo -e "기본 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" + echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" + echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" + echo -e "${gl_kjlan}9. ${gl_bai}Tmux 다중 채널 배경 달리기 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" + echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" + echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." curl --help - send_stats "安装curl" + send_stats "컬을 설치하십시오" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." wget --help - send_stats "安装wget" + send_stats "wget을 설치하십시오" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." sudo --help - send_stats "安装sudo" + send_stats "Sudo를 설치하십시오" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." socat -h - send_stats "安装socat" + send_stats "Socat을 설치하십시오" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "HTOP를 설치하십시오" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "iftop을 설치하십시오" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." unzip - send_stats "安装unzip" + send_stats "압축을 설치하십시오" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." tar --help - send_stats "安装tar" + send_stats "타르를 설치하십시오" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." tmux --help - send_stats "安装tmux" + send_stats "tmux를 설치하십시오" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 사용법은 다음과 같습니다." ffmpeg --help - send_stats "安装ffmpeg" + send_stats "FFMPEG를 설치하십시오" ;; 11) @@ -6656,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "Btop을 설치하십시오" ;; 12) clear @@ -6665,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "레인저를 설치하십시오" ;; 13) clear @@ -6674,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "NCDU를 설치하십시오" ;; 14) clear @@ -6683,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "FZF를 설치하십시오" ;; 15) clear @@ -6692,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "VIM을 설치하십시오" ;; 16) clear @@ -6701,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "나노를 설치하십시오" ;; @@ -6712,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "git을 설치하십시오" ;; 21) @@ -6720,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrix를 설치하십시오" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "SL을 설치하십시오" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "Bastet을 설치하십시오" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "NSNAKE를 설치하십시오" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "Ninvaders를 설치하십시오" ;; 31) clear - send_stats "全部安装" + send_stats "모두 설치하십시오" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "모든 설치 (게임 및 화면 보호기 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "모든 것을 제거하십시오" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "설치된 도구 이름 (WGET CURL SUDO HTOP)을 입력하십시오." installname install $installname - send_stats "安装指定软件" + send_stats "지정된 소프트웨어를 설치하십시오" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename remove $removename - send_stats "卸载指定软件" + send_stats "지정된 소프트웨어를 제거하십시오" ;; 0) @@ -6788,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -6802,27 +6803,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR 관리" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "현재 TCP 차단 알고리즘 :$congestion_algorithm $queue_algorithm" echo "" - echo "BBR管理" + echo "BBR 관리" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. BBRV3 켜기 2. BBRV3 끄기 (재시작)" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "알파인 활성화 BBR3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6867,21 +6868,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}当前备份列表:${NC}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + echo -e "${BLUE}현재 백업 목록 :${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" } # ---------------------------- - # 备份 + # 지원 # ---------------------------- backup_docker() { - send_stats "Docker备份" + send_stats "도커 백업" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers install tar jq gzip install_docker @@ -6892,7 +6893,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너가 없습니다${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6900,28 +6901,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "# 자동으로 생성 된 복원 스크립트" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # 중복 포장을 피하기 위해 패키지 작곡 프로젝트의 경로를 기록하십시오. declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${GREEN}백업 컨테이너 :$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${BLUE}감지$c예, Docker-compose 컨테이너${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir fi - # 如果该 Compose 项目已经打包过,跳过 + # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${YELLOW}작곡 프로젝트 [$project_name] 백업, 중복 포장을 건너 뛰십시오 ...${NC}" continue fi @@ -6929,137 +6930,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "# Docker-Compose Recovery :$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${GREEN}작곡 프로젝트 [$project_name] 포장 :${project_dir}${NC}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${RED}docker-compose.yml을 찾을 수 없고이 컨테이너를 건너 뛰십시오 ...${NC}" fi else - # 普通容器备份卷 + # 일반 컨테이너 백업 볼륨 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷: $path" + echo "포장 롤 :$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 端口 + # 포트 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 环境变量 + # 환경 변수 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 卷映射 + # 볼륨 매핑 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 镜像 + # 거울 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo -e "\ n# 복원 컨테이너 :$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 备份 /home/docker 下的所有文件(不含子目录) + # /home /docker 아래의 모든 파일을 백업 (하위 디렉터 제외) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${BLUE}/home /docker 아래 파일을 백업 ...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}/home /docker의 파일은 다음과 같이 포장되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}백업이 완료되었습니다.${BACKUP_DIR}${NC}" + echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 还原 + # 절감 # ---------------------------- restore_docker() { - send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "도커 복원" + read -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${BLUE}복원 작업 시작 ...${NC}" install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # ----------------------------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path - # 检查该 compose 项目的容器是否已经在运行 + # Compose 프로젝트 용 컨테이너가 이미 실행 중인지 확인하십시오. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "새로운 복원 경로를 입력하십시오 :" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${GREEN}작곡 프로젝트 [$project_name] 압축 압축 : :$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원이 완료되었습니다!${NC}" fi done - # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + # ----------------------------- + echo -e "${BLUE}일반적인 도커 컨테이너를 확인하고 복원하십시오 ...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${GREEN}처리 컨테이너 :$container${NC}" - # 检查容器是否已经存在且正在运行 + # 컨테이너가 이미 존재하고 실행 중인지 확인하십시오 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${YELLOW}컨테이너 [$container]는 실행 중입니다. 회복을 건너 뛰십시오 ...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}거울 정보는 찾을 수 없었습니다.$container${NC}"; continue; } - # 端口映射 + # 포트 매핑 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 环境变量 + # 환경 변수 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷数据恢复 + # 볼륨 매핑 + 볼륨 데이터 복구 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7070,32 +7071,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢复卷数据: $VOL_SRC" + echo "볼륨 데이터 복구 :$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 删除已存在但未运行的容器 + # 기존이지만 실행되지 않은 컨테이너를 삭제하십시오 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${YELLOW}컨테이너 [$container] 존재하지만 실행되지 않고 오래된 컨테이너를 삭제합니다 ...${NC}" docker rm -f "$container" fi - # 启动容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 컨테이너를 시작하십시오 + echo "복원 명령 실행 : docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" - # 还原 /home/docker 下的文件 + # /home /docker에서 파일을 복원하십시오 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${BLUE}/home /docker에서 파일을 복원 ...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${GREEN}/home /docker의 파일이 복원되었습니다${NC}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${YELLOW}/home /docker 아래 파일의 백업이 발견되지 않았습니다.${NC}" fi @@ -7103,66 +7104,66 @@ docker_ssh_migration() { # ---------------------------- - # 迁移 + # 마이그레이션 # ---------------------------- migrate_docker() { - send_stats "Docker迁移" + send_stats "도커 마이그레이션" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + read -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -p "대상 서버 IP :" TARGET_IP + read -p "대상 서버 SSH 사용자 이름 :" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${YELLOW}백업 전송 ...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密钥登录 + # 키로 로그인하십시오 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 删除备份 + # 백업을 삭제하십시오 # ---------------------------- delete_backup() { - send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Docker 백업 파일 삭제" + read -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" } # ---------------------------- - # 主菜单 + # 메인 메뉴 # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "도커 백업 마이그레이션 및 복원" while true; do clear echo "------------------------" - echo -e "Docker备份/迁移/还原工具" + echo -e "도커 백업/마이그레이션/복원 도구" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" - echo -e "2. 迁移docker项目" - echo -e "3. 还原docker项目" - echo -e "4. 删除docker项目的备份文件" + echo -e "1. Docker 프로젝트를 백업하십시오" + echo -e "2. Docker 프로젝트를 마이그레이션합니다" + echo -e "3. Docker 프로젝트를 복원하십시오" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -p "请选择: " choice + read -p "선택하십시오 :" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${RED}잘못된 옵션${NC}" ;; esac break_end done @@ -7179,38 +7180,38 @@ linux_docker() { while true; do clear - # send_stats "docker管理" - echo -e "Docker管理" + # Send_stats "Docker Management" + echo -e "도커 관리" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경을 설치하고 업데이트하십시오${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Docker Global Status를 봅니다${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" + echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" + echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너 및 미러 네트워크 데이터 볼륨을 청소하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" + echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}백업/마이그레이션/복원 Docker 환경" + echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "Docker 환경을 설치하십시오" install_add_docker ;; @@ -7221,22 +7222,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "도커 글로벌 상태" + echo "도커 버전" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "도커 이미지 :${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7251,8 +7252,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "도커 네트워크 관리" + echo "도커 네트워크 목록" echo "------------------------------------------------------------" docker network ls echo "" @@ -7276,36 +7277,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "네트워크 작동" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1. 네트워크를 만듭니다" + echo "2. 인터넷에 가입하십시오" + echo "3. 네트워크를 종료하십시오" + echo "4. 네트워크를 삭제합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "네트워크를 만듭니다" + read -e -p "새 네트워크 이름 설정 :" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "인터넷에 가입하십시오" + read -e -p "네트워크 이름에 가입 :" dockernetwork + read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "인터넷에 가입하십시오" + read -e -p "종료 네트워크 이름 :" dockernetwork + read -e -p "해당 컨테이너는 네트워크를 종료합니다 (여러 컨테이너 이름은 공간별로 분리됩니다)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7314,8 +7315,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "네트워크를 삭제하십시오" + read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork docker network rm $dockernetwork ;; @@ -7329,29 +7330,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "도커 볼륨 관리" + echo "도커 볼륨 목록" docker volume ls echo "" - echo "卷操作" + echo "볼륨 작동" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1. 새 볼륨을 만듭니다" + echo "2. 지정된 볼륨을 삭제합니다" + echo "3. 모든 볼륨을 삭제하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "새 볼륨을 만듭니다" + read -e -p "새 볼륨 이름 설정 :" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "볼륨 삭제 이름을 입력하십시오 (공백으로 여러 볼륨 이름을 분리하십시오)." dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7360,7 +7361,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "모든 볼륨을 삭제하십시오" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7369,7 +7370,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7382,7 +7383,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "도커 청소" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7391,13 +7392,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "도커 소스" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7413,13 +7414,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker V6 열기" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker V6 레벨" docker_ipv6_off ;; @@ -7430,7 +7431,7 @@ linux_docker() { 20) clear - send_stats "Docker卸载" + send_stats "Docker는 제거합니다" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7442,7 +7443,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7451,7 +7452,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7468,151 +7469,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # Send_stats "테스트 스크립트 컬렉션" + echo -e "스크립트 수집 테스트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGpt는 상태 감지를 잠금 해제합니다" + echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" + echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}네트워크 속도 측정" + echo -e "${gl_kjlan}11. ${gl_bai}Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" + echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" + echo -e "${gl_kjlan}17. ${gl_bai}I-ABC 다기능 속도 테스트 스크립트" + echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}하드웨어 성능 테스트" + echo -e "${gl_kjlan}21. ${gl_bai}YABS 성능 테스트" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}포괄적 인 테스트" + echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "ChatGpt는 상태 감지를 잠금 해제합니다" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "지역 스트리밍 미디어 잠금 해제 테스트" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "YEAHWU 스트리밍 미디어 잠금 해제 탐지" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "xykt_ip 품질 신체 검사 스크립트" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "MTR_TRACE 3 개의 네트워크 리턴 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "Superspeed 3 Net 속도 측정" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace 빠른 백홀 테스트 스크립트" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" + echo "참조 할 수있는 IP 목록" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "베이징 통신 : 219.141.136.12" + echo "베이징 유니폼 : 202.106.50.1" + echo "베이징 모바일 : 221.179.155.161" + echo "상하이 통신 : 202.96.209.133" + echo "상하이 유니폼 : 210.22.97.1" + echo "상하이 모바일 : 211.136.112.200" + echo "광저우 통신 : 58.60.188.222" + echo "광저우 유니폼 : 210.21.196.6" + echo "광저우 모바일 : 120.196.165.24" + echo "청두 통신 : 61.139.2.69" + echo "청두 유니폼 : 119.6.6.6" + echo "청두 모바일 : 211.137.96.205" + echo "Hunan Telecom : 36.111.200.100" + echo "후난 유니폼 : 42.48.16.100" + echo "후난 모바일 : 39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "지정된 IP를 입력하십시오." testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "Ludashi2020 3 네트워크 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "I-ABC 다기능 속도 테스트 스크립트" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "네트워크 품질 테스트 스크립트" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "YABS 성능 테스트" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "IICU/GB5 CPU 성능 테스트 스크립트" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "벤치 성능 테스트" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "SpiritySDX 퓨전 몬스터 검토" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7622,7 +7623,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7638,51 +7639,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud 스크립트 컬렉션" + echo -e "Oracle Cloud 스크립트 컬렉션" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}유휴 기계 활성 스크립트를 설치하십시오" + echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" + echo -e "${gl_kjlan}4. ${gl_bai}형사 R 스크립트 시작" + echo -e "${gl_kjlan}5. ${gl_bai}루트 비밀번호 로그인 모드를 켭니다" + echo -e "${gl_kjlan}6. ${gl_bai}IPv6 복구 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "활성 스크립트 : CPU는 10-20% 메모리를 점유합니다." + read -e -p "설치 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # 기본값을 설정합니다 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # 사용자에게 CPU 코어 수와 점유율 백분율을 입력하라는 메시지를 표시하고 입력 한 경우 기본값을 사용하십시오. + read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 사용 백분율 범위 (예 : 10-20) [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "스피드 테스트 간격 시간 (초)을 입력하십시오 [기본값 :$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # 도커 컨테이너를 실행하십시오 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7690,14 +7691,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloud 설치 활성 스크립트" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -7705,20 +7706,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" ;; 3) clear - echo "重装系统" + echo "시스템을 다시 설치하십시오" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "다시 설치할 시스템을 선택하십시오 : 1. Debian12 | 2. Ubuntu20.04 :" sys_choice case "$sys_choice" in 1) @@ -7730,28 +7731,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "유효하지 않은 선택, 다시 입력하십시오." ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "다시 설치 한 비밀번호를 입력하십시오." vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud 회복 시스템 스크립트" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "이 기능은 개발 단계에 있으므로 계속 지켜봐 주시기 바랍니다!" ;; 5) clear @@ -7761,15 +7762,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 마스터 JHB가 제공합니다." + send_stats "IPv6 수정" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -7790,7 +7791,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" fi } @@ -7811,7 +7812,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" fi fi @@ -7839,31 +7840,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "ldnmp 웹 사이트 빌딩" + echo -e "${gl_huang}LDNMP 웹 사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPress를 설치하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginx 만 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" + echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" + echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" + echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" + echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" + echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -7877,10 +7878,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # Discuz 포럼 webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7903,21 +7904,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 : discuz_" ;; 4) clear - # 可道云桌面 + # Kedao 클라우드 데스크탑 webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7939,20 +7940,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "데이터베이스 주소 : MySQL" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름 :$dbname" + echo "Redis 호스트 : Redis" ;; 5) clear - # 苹果CMS + # Apple CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7978,24 +7979,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 접두사 : MAC_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "설치가 성공한 후 배경 주소에 로그인하십시오." echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 한 다리 카운팅 카드 webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8016,34 +8017,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "Redis 주소 : Redis" + echo "Redis Password : 기본적으로 채워지지 않습니다" + echo "Redis Port : 6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "웹 사이트 URL : https : //$yuming" + echo "백그라운드 로그인 경로 : /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "사용자 이름 : 관리자" + echo "비밀번호 : 관리자" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "로그인 할 때 오른쪽 상단에 빨간색 Error0이 나타나면 다음 명령을 사용하십시오." + echo "나는 또한 유니콘 번호 카드가 너무 귀찮다는 것에 대해 매우 화가 났으며 그러한 문제가있을 것입니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # Flarum 포럼 webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8080,12 +8081,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 : flarum_" + echo "관리자 정보는 직접 설정됩니다" ;; @@ -8093,8 +8094,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8118,11 +8119,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "데이터베이스 접두사 : typecho_" + echo "데이터베이스 주소 : MySQL" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름 :$dbname" ;; @@ -8131,8 +8132,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8157,18 +8158,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 포트 : 3306" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8185,10 +8186,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8198,20 +8199,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.php가있는 경로" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/와 유사한 Index.php의 경로를 입력하십시오.$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택하십시오" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. PHP의 최신 버전 | 2. PHP7.4 :" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8222,15 +8223,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "유효하지 않은 선택, 다시 입력하십시오." ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장자를 설치하십시오" echo "-------------" - echo "已经安装的扩展" + echo "설치된 확장" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8240,25 +8241,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "계속하려면 모든 키를 누르면 의사 정적 내용 등과 같은 사이트 구성을 자세히 설정할 수 있습니다." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 작성하고 데이터베이스 백업이 있습니다." use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." + read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8268,10 +8269,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "데이터베이스 가져 오기 테이블 데이터" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "데이터베이스 가져 오기가 완료되었습니다" ;; *) echo @@ -8283,12 +8284,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 이름 :$dbname" + echo "사용자 이름 :$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사 :$prefix" + echo "관리자 로그인 정보는 직접 설정됩니다" ;; @@ -8301,10 +8302,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy nginx_install_status install_ssltls certs_status @@ -8326,7 +8327,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8337,11 +8338,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "도메인 이름 형식 :${gl_huang}google.com${gl_bai}" + read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8361,8 +8362,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8384,8 +8385,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8402,8 +8403,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming nginx_install_status install_ssltls @@ -8436,8 +8437,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포를 시작하십시오$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8454,10 +8455,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8467,12 +8468,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/와 유사한 index.html로가는 경로를 입력하십시오.$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8497,21 +8498,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP 환경 백업" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "백업 파일이 작성되었습니다 : /home /$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "오류 : 원격 서버 IP를 입력하십시오." continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8519,9 +8520,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." else - echo "未找到要传送的文件。" + echo "전송할 파일은 찾을 수 없었습니다." fi break ;; @@ -8529,7 +8530,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac done @@ -8537,9 +8538,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "시간이 지정된 원격 백업" + read -e -p "원격 서버 IP를 입력하십시오." useip + read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8549,18 +8550,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1. 주간 백업 2. 매일 백업" + read -e -p "선택을 입력하십시오 :" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "주간 백업의 요일을 선택하십시오 (0-6, 0은 일요일을 나타냅니다) :" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "매일 백업 시간을 선택하십시오 (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8574,19 +8575,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP 환경 복원" + echo "사용 가능한 사이트 백업" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8596,7 +8597,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8605,7 +8606,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "압축 패키지가 발견되지 않았습니다." fi ;; @@ -8623,11 +8624,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP 환경을 업데이트하십시오" + echo "LDNMP 환경을 업데이트하십시오" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "구성 요소의 새 버전을 발견하십시오" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8647,13 +8648,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" echo "------------------------" - echo "5. 更新完整环境" + echo "5. 전체 환경을 업데이트하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8662,7 +8663,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 8.0 8.3 8.4 9.0) (최신 버전을 얻으려면 입력) :" version local version=${version:-latest} cd /home/web/ @@ -8673,13 +8674,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 7.4 8.0 8.1 8.2 8.3) (최신 버전을 얻으려면 입력) :" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8712,8 +8713,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 4) @@ -8724,15 +8725,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP 환경을 완전히 업데이트하십시오" cd /home/web/ docker compose down --rmi all @@ -8758,7 +8759,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP 환경을 제거하십시오" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8772,7 +8773,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -8782,7 +8783,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "잘못된 입력!" esac break_end @@ -8802,12 +8803,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "응용 프로그램 시장" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # 루프로 색상을 설정하십시오 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8816,70 +8817,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" + echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" + echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" + echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" + echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" + echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" + echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" + echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" + echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" + echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" + echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" + echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" + echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" + echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" + echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" + echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" + echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" + echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" + echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" + echo -e "${gl_kjlan}89. ${color89}filecodebox 파일 Express${gl_kjlan}90. ${color90}매트릭스 분산 채팅 프로토콜" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" + echo -e "${gl_kjlan}93. ${color93}DUFS 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" + echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼" + echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice fi case $sub_choice in @@ -9032,8 +9033,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9066,7 +9067,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "Nezha를 구축하십시오" local app_id="7" local docker_name="nezha-dashboard" @@ -9075,20 +9076,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "Nezha 모니터링$check_docker $update_status" + echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" + echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1. 사용" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -9145,7 +9146,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "우체국을 건설하십시오" clear install telnet local app_id="9" @@ -9155,43 +9156,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "우체국 서비스$check_docker $update_status" + echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" - echo "端口检测" + echo "포트 감지" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "액세스 주소 :" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "이 DNS 레코드를 먼저 구문 분석하십시오" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9201,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install jq @@ -9220,9 +9221,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" echo "" @@ -9245,9 +9246,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "Poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" echo "" ;; @@ -9258,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다" ;; *) @@ -9292,7 +9293,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -9302,7 +9303,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chat이 설치되었습니다" check_docker_app_ip } @@ -9312,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -9396,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -9410,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -9555,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "천둥 수영장을 건설하십시오" local app_id="19" local docker_name=safeline-mgt @@ -9563,20 +9564,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "썬더 풀 서비스$check_docker" + echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) @@ -9586,7 +9587,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "Thunder Pool WAF 패널이 설치되었습니다" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9599,7 +9600,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip ;; 3) @@ -9610,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9729,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10018,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10071,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoya 가족 버킷" clear install_docker check_disk_space 1 @@ -10275,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "설치" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" } docker_app_update() { @@ -10295,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10382,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVE 치킨" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10502,7 +10503,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10517,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10545,7 +10546,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10560,7 +10561,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10568,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10589,17 +10590,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "설치" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "초기 사용자 이름 : 관리자" + echo "초기 비밀번호 : changeme" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "앱이 업데이트되었습니다" } @@ -10609,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10656,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -10672,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -10934,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd docker run -d \ --name libretv \ @@ -10968,9 +10969,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password - read -e -p "输入授权码: " shouquanma + read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "인증 코드를 입력하십시오." shouquanma mkdir -p /home/docker/moontv @@ -10986,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11000,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11073,8 +11074,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "로그인 사용자 이름 설정 :" app_use + read -e -p "로그인 비밀번호 설정 :" app_passwd docker run -d \ --name xunlei \ @@ -11171,11 +11172,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # 임의의 키와 암호를 생성합니다 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11184,17 +11185,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 관리자 계정 정보를 추가하십시오 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # 컨테이너를 시작하십시오 docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11204,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 원래 변수를 유지하십시오 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11221,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11271,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11289,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "설정${docker_name}SK-159KEJILIONYYDS163 :와 같은 로그인 키 (SK 별 문자 및 숫자 조합) :" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11393,7 +11394,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11406,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11567,7 +11568,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11619,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11633,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11708,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "로그인 사용자 이름 설정 :" app_use + read -e -p "로그인 비밀번호 설정 :" app_passwd docker run -d \ --name ${docker_name} \ @@ -11757,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "已经安装完成" + echo "설치" check_docker_app_ip } @@ -11771,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "应用已卸载" + echo "앱이 제거되었습니다" } docker_app_plus @@ -11788,12 +11789,12 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ @@ -11833,7 +11834,7 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" + echo "QR 코드 생성 :$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' @@ -11843,11 +11844,11 @@ while true; do sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" - echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}모든 출력은 각 클라이언트가 제공합니다. 사용법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}1. 휴대 전화에서 WG의 앱을 다운로드하고 위의 QR 코드를 스캔하여 네트워크에 빠르게 연결하십시오.${gl_bai}" + echo -e "${gl_lv}2. Windows 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결하십시오.${gl_bai}" + echo -e "${gl_lv}3. Linux는 스크립트를 사용하여 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" + echo -e "${gl_lv}공식 클라이언트 다운로드 방법 : https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11875,16 +11876,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # 디렉토리 생성 (존재하지 않는 경우) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "请粘贴你的客户端配置,连续按两次回车保存:" + echo "클라이언트 구성을 붙여 넣고 다음을 저장하려면 Enter Enter를 두 번 누릅니다." - # 初始化变量 + # 변수 초기화 input="" empty_line_count=0 - # 逐行读取用户输入 + # 사용자 입력 라인별로 읽으십시오 while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -11897,10 +11898,10 @@ while true; do fi done - # 写入配置文件 + # 구성 파일에 쓰십시오 echo "$input" > "$CONFIG_FILE" - echo "客户端配置已保存到 $CONFIG_FILE" + echo "클라이언트 구성이 저장되었습니다$CONFIG_FILE" docker run -d \ --name wireguardc \ @@ -11933,21 +11934,21 @@ while true; do b) clear - send_stats "全部应用备份" + send_stats "모든 응용 프로그램 백업" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "백업 파일이 작성되었습니다 : /$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "오류 : 원격 서버 IP를 입력하십시오." continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11955,14 +11956,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." else - echo "未找到要传送的文件。" + echo "전송할 파일은 찾을 수 없었습니다." fi break ;; *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + echo "참고 : 현재 백업에는 Docker 프로젝트 만 포함되어 있으며 Pagoda 및 1Panel과 같은 웹 사이트 구축 패널의 데이터 백업은 포함되지 않습니다." break ;; esac @@ -11972,29 +11973,29 @@ while true; do r) root_use - send_stats "全部应用还原" - echo "可用的应用备份" + send_stats "모든 응용 프로그램이 복원됩니다" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." else - echo "没有找到压缩包。" + echo "압축 패키지가 발견되지 않았습니다." fi ;; @@ -12017,35 +12018,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "백엔드 작업 공간" + echo -e "백엔드 작업 공간" + echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." + echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." + echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "현재 기존 작업 공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" + echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" + echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" + echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" + echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" + echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" + echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" + echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" + echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" + echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -12053,7 +12054,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -12061,63 +12062,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -12129,21 +12130,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH 거주 모드" + echo -e "SSH 거주 모드${tmux_sshd_status}" + echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 2를 켜십시오. 2를 끕니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "선택을 입력하십시오 :" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "작업 공간을 시작하십시오$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12159,29 +12160,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "사용자 정의 작업 공간" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "배경 작업 공간에 명령을 주입합니다" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "작업 공간을 삭제합니다" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -12206,54 +12207,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # Send_stats "시스템 도구" + echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" + echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" + echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" + echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" + echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" + echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" + echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "바로 가기 키가 설정되어 있습니다" + send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings done @@ -12261,34 +12262,34 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "로그인 비밀번호를 설정하십시오" + echo "로그인 비밀번호를 설정하십시오" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "루트 비밀번호 모드" add_sshpasswd ;; 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "PY 버전 관리" + echo "파이썬 버전 관리" + echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" + echo "더 많은 버전 : https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "스크립트 PY 관리" break_end linux_Settings fi @@ -12321,7 +12322,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "알 수없는 패키지 관리자!" return fi @@ -12350,55 +12351,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + send_stats "스크립트 Py 버전을 스위치하십시오" ;; 5) root_use - send_stats "开放端口" + send_stats "포트 열기" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "모든 포트가 열려 있습니다" ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSH 포트를 수정하십시오" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 현재 SSH 포트 번호를 읽으십시오 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 현재 SSH 포트 번호를 인쇄하십시오 + echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 + read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port - # 判断端口号是否在有效范围内 + # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH 포트가 수정되었습니다" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSH 포트 수정을 종료하십시오" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "입력이 유효하지 않으므로 번호를 입력하십시오." + send_stats "잘못된 SSH 포트 입력" break_end fi done @@ -12417,8 +12418,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "신규 사용자는 루트를 비활성화합니다" + read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12433,49 +12434,49 @@ EOF passwd -l root - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 10) root_use - send_stats "设置v4/v6优先级" + send_stats "V4/V6 우선 순위를 설정하십시오" while true; do clear - echo "设置v4/v6优先级" + echo "V4/V6 우선 순위를 설정하십시오" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "선호하는 네트워크를 선택하십시오." choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "IPv4 우선 순위로 전환되었습니다" + send_stats "IPv4 우선 순위로 전환되었습니다" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "IPv6 우선 순위로 전환되었습니다" + send_stats "IPv6 우선 순위로 전환되었습니다" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 마스터 JHB가 제공합니다." + send_stats "IPv6 수정" ;; *) @@ -12493,43 +12494,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "가상 메모리를 설정합니다" while true; do clear - echo "设置虚拟内存" + echo "가상 메모리를 설정합니다" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G 가상 메모리가 설정되었습니다" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G 가상 메모리가 설정되었습니다" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "사용자 정의 가상 메모리가 설정되었습니다" ;; *) @@ -12542,8 +12543,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "사용자 관리" + echo "사용자 목록" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12554,62 +12555,62 @@ EOF echo "" - echo "账户操作" + echo "계정 운영" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." echo "------------------------" - echo "5. 删除账号" + echo "5. 계정을 삭제하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + read -e -p "새 사용자 이름을 입력하십시오 :" new_username - # 创建新用户并设置密码 + # 새 사용자를 생성하고 비밀번호를 설정하십시오 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 새로운 사용자에게 허가를 부여하십시오 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作已完成。" + echo "작업이 완료되었습니다." ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # 새로운 사용자에게 허가를 부여하십시오 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "사용자 이름을 입력하십시오 :" username + # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "삭제하려면 사용자 이름을 입력하십시오." username + # 사용자와 홈 디렉토리를 삭제하십시오 userdel -r "$username" ;; @@ -12622,50 +12623,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "사용자 정보 생성기" + echo "임의의 사용자 이름" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "임의의 사용자 이름$i: $username" done echo "" - echo "随机姓名" + echo "임의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5 개의 임의의 사용자 이름을 생성합니다 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "임의의 사용자 이름$i: $user_name" done echo "" - echo "随机UUID" + echo "무작위 uuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "무작위 uuid$i: $uuid" done echo "" - echo "16位随机密码" + echo "16 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" - echo "32位随机密码" + echo "32 비트 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "랜덤 비밀번호$i: $password" done echo "" @@ -12673,46 +12674,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "시간대를 변경하십시오" while true; do clear - echo "系统时间信息" + echo "시스템 시간 정보" - # 获取当前系统时区 + # 현재 시스템 시간대를 얻으십시오 local timezone=$(current_timezone) - # 获取当前系统时间 + # 현재 시스템 시간을 얻으십시오 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # 시간대와 시간을 보여줍니다 + echo "현재 시스템 시간대 :$timezone" + echo "현재 시스템 시간 :$current_time" echo "" - echo "时区切换" + echo "시간대 스위칭" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "아시아" + echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" + echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" + echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" + echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" + echo "9. 태국 방콕에서의 시간" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "유럽" + echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" + echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" + echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "미국" + echo "21. 서양 시간 22. 동부 시간" + echo "23. 캐나다 시간 24. 멕시코 시간" + echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC 글로벌 표준 시간" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -12755,21 +12756,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "호스트 이름을 수정하십시오" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian, Ubuntu, Centos 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12787,11 +12788,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" + send_stats "호스트 이름이 변경되었습니다" sleep 1 else - echo "已退出,未更改主机名。" + echo "종료, 호스트 이름이 변경되지 않았습니다." break fi done @@ -12799,32 +12800,32 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "시스템 업데이트 소스를 변경하십시오" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "업데이트 소스 영역을 선택하십시오" + echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택을 입력하십시오 :" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "중국 본토의 기본 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "중국 본토의 교육 원" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "해외 출신" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) - echo "已取消" + echo "취소" ;; esac @@ -12832,62 +12833,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "타이밍 작업 관리" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "시간이 정한 작업 목록" crontab -l echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. 월간 작업 2. 주간 작업" + echo "3. 일일 작업 4. 시간당 작업" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "선택을 입력하십시오 :" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "시간이 정한 작업을 추가하십시오" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "타이밍 작업을 삭제하십시오" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "타이밍 작업 편집" ;; *) break # 跳出循环,退出菜单 @@ -12899,32 +12900,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "지역 호스트 구문 분석" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "기본 호스트 구문 분석 목록" + echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." cat /etc/hosts echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "로컬 호스트 구문 분석이 추가되었습니다" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "로컬 호스트 구문 분석 및 삭제" ;; *) break # 跳出循环,退出菜单 @@ -12935,7 +12936,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "SSH 방어" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12947,20 +12948,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH 방어 프로그램$check_docker" + echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" + echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. SSH 차단 레코드보기" + echo "3. 실시간 로그 모니터링" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램을 제거하십시오" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) install_docker @@ -12983,7 +12984,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2ban 방어 프로그램은 제거되었습니다" ;; *) break @@ -12996,47 +12997,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "현재 제한 종료 기능" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "현재 제한 종료 기능" + echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # limiting_shut_down.sh 파일이 있는지 확인하십시오 if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # threshold_gb의 값을 얻으십시오 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 새 가상 메모리 크기를 입력하십시오 + echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." + read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day cz_day=${cz_day:-1} cd ~ @@ -13049,15 +13050,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "전류 제한 종료가 설정되었습니다" + send_stats "전류 제한 종료가 설정되었습니다" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "전류 제한 종료 기능이 꺼졌습니다" ;; *) break @@ -13070,40 +13071,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "개인 키 로그인" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "루트 비공개 키 로그인 모드" + echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택을 입력하십시오 :" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "새로운 키를 생성하십시오" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "기존 공개 키를 가져옵니다" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "로컬 비밀 키를보십시오" echo "------------------------" - echo "公钥信息" + echo "공개 키 정보" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "개인 키 정보" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -13119,18 +13120,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "전보 경고" + echo "TG-BOT 모니터링 및 조기 경고 기능" + echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." + echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." + echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "전보 경고가 활성화되었습니다" cd ~ install nano tmux bc jq check_crontab_installed @@ -13152,7 +13153,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # ~/.profile 파일에 추가하십시오 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -13163,21 +13164,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-BOT 조기 경고 시스템이 시작되었습니다" + echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "SSH에서 고위험 취약점을 수정하십시오" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13221,7 +13222,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "명령 줄 기록" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -13244,61 +13245,61 @@ EOF 41) clear - send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + send_stats "게시판" + echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "원 스톱 튜닝" + echo "원 스톱 시스템 최적화" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "다음은 작동하고 최적화됩니다" + echo "1. 시스템을 최신으로 업데이트하십시오" + echo "2. 시스템 정크 파일 정리" + echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" + echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "5. 모든 포트를 엽니 다" + echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" + echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" + echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "원 스톱 튜닝 시작" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13315,25 +13316,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" + echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac @@ -13341,7 +13342,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "시스템을 다시 시작하십시오" server_reboot ;; 100) @@ -13357,32 +13358,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "개인 정보 및 보안" + echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." + echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "현재 상태 :$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. 수집을 켭니다" + echo "2. 컬렉션을 닫습니다" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "수집이 활성화되었습니다" + send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "컬렉션이 닫혔습니다" + send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" ;; *) break @@ -13398,11 +13399,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "기술 라이온 스크립트를 제거하십시오" + echo "기술 라이온 스크립트를 제거하십시오" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -13410,16 +13411,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "대본은 제거되었습니다." break_end clear exit ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac ;; @@ -13429,7 +13430,7 @@ EOF ;; *) - echo "无效的输入!" + echo "잘못된 입력!" ;; esac break_end @@ -13447,187 +13448,187 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "파일 관리자" while true; do clear - echo "文件管理器" + echo "파일 관리자" echo "------------------------" - echo "当前路径" + echo "현재 경로" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" + echo "15. 파일을 삭제하십시오" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" + echo "25. 파일을 다른 서버로 전달합니다" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" + send_stats "디렉토리로 이동하십시오" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname + mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" + send_stats "디렉토리를 만듭니다" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "디렉토리 이름을 입력하십시오 :" dirname + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "디렉토리 권한을 수정하십시오" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name + read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "디렉토리의 이름을 바꿉니다" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname + rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "디렉토리 삭제" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "이전 메뉴 디렉토리로 돌아갑니다" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "작성하려면 파일 이름을 입력하십시오." filename + touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" + send_stats "파일을 만듭니다" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "편집 할 파일 이름을 입력하십시오." filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "파일 편집" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "파일 이름을 입력하십시오 :" filename + read -e -p "권한을 입력하십시오 (예 : 755) :" perm + chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + send_stats "파일 권한을 수정하십시오" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "현재 파일 이름을 입력하십시오 :" current_name + read -e -p "새 파일 이름을 입력하십시오 :" new_name + mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + send_stats "파일의 이름을 바꿉니다" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "삭제하려면 파일 이름을 입력하십시오." filename + rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" + send_stats "파일 삭제" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" + send_stats "압축 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" + send_stats "압축 파일/디렉토리 해제" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" + send_stats "파일 또는 디렉토리를 이동하십시오" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "오류 : 대상 경로를 입력하십시오." + send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 + cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" + send_stats "파일 또는 디렉토리를 복사합니다" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "오류 : 파일이 존재하지 않습니다." + send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "오류 : 원격 서버 IP를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "오류 : 원격 서버 비밀번호를 입력하십시오." + send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 알려진 호스트를위한 오래된 항목을 명확하게합니다 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # SCP를 사용하여 파일을 전송합니다 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "스크립트는 최신입니다$sh_v_new" break_end ~/kejilion.sh exit @@ -13925,15 +13926,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" + send_stats "자동 스크립트 업데이트를 켜십시오" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" + send_stats "스크립트 자동 업데이트를 닫습니다" break_end ;; *) @@ -13955,41 +13956,41 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" +echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" -echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" -echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" +echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" +echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" +echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" +echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" +echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" +echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" +echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" +echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" +echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" +echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" +echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" +echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" +echo -e "${gl_kjlan}15. ${gl_bai}광고 열" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "선택을 입력하십시오 :" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; + 3) clear ; send_stats "시스템 정리" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "워프 관리" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -14000,13 +14001,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "잘못된 입력!" ;; esac break_end done @@ -14014,68 +14015,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "K 명령 참조 사용 사례" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "다음은 K 명령 참조 유스 케이스입니다." +echo "스크립트 시작 k" +echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" +echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" +echo "업데이트 시스템 K 업데이트 | K 업데이트" +echo "깨끗한 시스템 쓰레기 K Clean | K 청소" +echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" +echo "BBR3 제어판 K BBR3 | K bbrv3" +echo "커널 튜닝 패널 K nhyh | K 커널 최적화" +echo "가상 메모리 K 스왑 2048을 설정하십시오" +echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" +echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" +echo "시스템 백업 기능 K 백업 | K bf | K 백업" +echo "SSH 원격 연결 도구 K SSH | K 원격 연결" +echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" +echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" +echo "인트라넷 침투 (서버 측) K frps" +echo "인트라넷 침투 (클라이언트) K frpc" +echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" +echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" +echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" +echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" +echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" +echo "도메인 이름 인증서 응용 프로그램 K SSL" +echo "도메인 이름 인증서 만료 쿼리 K SSL PS" +echo "도커 환경 설치 K 도커 설치 | K 도커 설치" +echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" +echo "Docker Image Management K Docker img | K Docker Image" +echo "LDNMP 사이트 관리 K 웹" +echo "LDNMP 캐시 정리 K 웹 캐시" +echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" +echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." +echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" +echo "방화벽 패널 K FHQ | K 방화벽" +echo "포트 k dkdk 8080 | k 오픈 포트 8080" +echo "포트 K GBDK 7800 | K 닫기 포트 7800" +echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" +echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" +echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" +echo "앱 시장 관리 K 앱" +echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 매개 변수가없는 경우 대화식 로직을 실행하십시오 kejilion_sh else - # 如果有参数,执行相应函数 + # 매개 변수가있는 경우 해당 함수를 실행하십시오 case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "소프트웨어를 설치하십시오" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "소프트웨어를 제거하십시오" remove "$@" ;; update|更新) @@ -14109,7 +14110,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "시간이 정한 RSYNC 동기화" run_task "$@" ;; @@ -14128,7 +14129,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14141,13 +14142,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "가상 메모리를 신속하게 설정했습니다" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "시간대를 빠르게 설정하십시오" set_timedate "$@" ;; @@ -14195,42 +14196,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "소프트웨어 상태보기" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "소프트웨어 시작" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "소프트웨어 일시 정지" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "소프트웨어 재시작" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "소프트웨어 부츠" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "인증서 상태를 확인하십시오" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "인증서를 신속하게 신청하십시오" else k_info fi @@ -14240,15 +14241,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "Docker를 신속하게 설치하십시오" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "빠른 컨테이너 관리" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "빠른 미러 관리" docker_image ;; *) @@ -14275,7 +14276,7 @@ else app) shift - send_stats "应用$@" + send_stats "$@ 적용" linux_panel "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index cab3eb64a..960b74c13 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# 定義一個函數來執行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 收集功能埋點信息的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! +# 為什麼要設計這個功能,目的更好的了解用戶喜歡使用的功能,進一步優化功能推出更多符合用戶需求的功能。 +# 全文可搜搜 send_stats 函數調用位置,透明開源,如有顧慮可拒絕使用。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# 提示用戶同意條款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" + echo "首次使用腳本,請先閱讀並同意用戶許可協議。" + echo "用戶許可協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -r -p "是否同意以上條款? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "許可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "許可拒絕" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "未提供軟件包參數!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_huang}正在安裝$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -219,11 +219,11 @@ check_disk_space() { available_space_mb=$(df -m / | awk 'NR==2 {print $4}') if [ $available_space_mb -lt $required_space_mb ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}提示:${gl_bai}磁盤空間不足!" + echo "當前可用空間: $((available_space_mb/1024))G" + echo "最小需求空間:${required_gb}G" + echo "無法繼續安裝,請清理磁盤空間後重試。" + send_stats "磁盤空間不足" break_end kejilion fi @@ -236,12 +236,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "未提供軟件包參數!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_huang}正在卸載$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -266,7 +266,7 @@ remove() { } -# 通用 systemctl 函数,适用于各种发行版 +# 通用 systemctl 函數,適用於各種發行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -279,43 +279,43 @@ systemctl() { } -# 重启服务 +# 重啟服務 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1服務已重啟。" else - echo "错误:重启 $1 服务失败。" + echo "錯誤:重啟$1服務失敗。" fi } -# 启动服务 +# 啟動服務 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1服務已啟動。" else - echo "错误:启动 $1 服务失败。" + echo "錯誤:啟動$1服務失敗。" fi } -# 停止服务 +# 停止服務 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1服務已停止。" else - echo "错误:停止 $1 服务失败。" + echo "錯誤:停止$1服務失敗。" fi } -# 查看服务状态 +# 查看服務狀態 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1服務狀態已顯示。" else - echo "错误:无法显示 $1 服务状态。" + echo "錯誤:無法顯示$1服務狀態。" fi } @@ -328,14 +328,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME已設置為開機自啟。" } break_end() { echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo "按任意鍵繼續..." read -n 1 -s -r -p "" echo "" clear @@ -352,10 +352,11 @@ kejilion() { stop_containers_or_kill_process() { local port=$1 local containers=$(docker ps --filter "publish=$port" --format "{{.ID}}" 2>/dev/null) - install lsof + if [ -n "$containers" ]; then docker stop $containers else + install lsof for pid in $(lsof -t -i:$port); do kill -9 $pid done @@ -424,7 +425,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_huang}正在安裝docker環境...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -505,49 +506,49 @@ while true; do echo "" echo "容器操作" echo "------------------------" - echo "1. 创建新的容器" + echo "1. 創建新的容器" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" + echo "2. 啟動指定容器 6. 啟動所有容器" echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "4. 刪除指定容器 8. 刪除所有容器" + echo "5. 重啟指定容器 9. 重啟所有容器" echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11. 進入指定容器 12. 查看容器日誌" + echo "13. 查看容器網絡 14. 查看容器佔用" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15. 開啟容器端口訪問 16. 關閉容器端口訪問" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + read -e -p "請輸入創建命令:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "啟動指定容器" + read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername docker start $dockername ;; 3) send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "刪除指定容器" + read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "重啟指定容器" + read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "啟動所有容器" docker start $(docker ps -a -q) ;; 7) @@ -555,7 +556,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "刪除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -564,28 +565,28 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "重啟所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "進入容器" + read -e -p "請輸入容器名:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "查看容器日誌" + read -e -p "請輸入容器名:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "查看容器網絡" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -603,14 +604,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "查看容器佔用" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "允許容器端口訪問" + read -e -p "請輸入容器名:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -619,8 +620,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "阻止容器端口訪問" + read -e -p "請輸入容器名:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -639,44 +640,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "Docker鏡像管理" + echo "Docker鏡像列表" docker image ls echo "" - echo "镜像操作" + echo "鏡像操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1. 獲取指定鏡像 3. 刪除指定鏡像" + echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "拉取鏡像" + read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_huang}正在獲取鏡像:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "更新鏡像" + read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_huang}正在更新鏡像:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "刪除鏡像" + read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "刪除所有鏡像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -685,7 +686,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -753,16 +754,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "不支持的發行版:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "無法確定操作系統。" return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}crontab 已安裝且 cron 服務正在運行。${gl_bai}" } @@ -774,27 +775,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 檢查配置文件是否存在,如果不存在則創建文件並寫入默認設置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # 使用jq處理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 檢查當前配置是否已經有 ipv6 設置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 更新配置,開啟 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 對比原始配置與新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}當前已開啟ipv6訪問${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -809,28 +810,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 檢查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 读取当前配置 + # 讀取當前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # 使用jq處理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 檢查當前的 ipv6 狀態 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 對比原始配置與新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}當前已關閉ipv6訪問${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}已成功關閉ipv6訪問${gl_bai}" fi } @@ -869,88 +870,88 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "請提供至少一個端口號" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 刪除已存在的關閉規則 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # 添加打開規則 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "已打開端口$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "已打開端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "請提供至少一個端口號" return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 刪除已存在的打開規則 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 添加關閉規則 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "已關閉端口$port" fi done - # 删除已存在的规则(如果有) + # 刪除已存在的規則(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 插入新規則到第一條 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "已關閉端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "請提供至少一個IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 刪除已存在的阻止規則 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 添加允許規則 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "已放行IP$ip" fi done @@ -961,20 +962,20 @@ allow_ip() { block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "請提供至少一個IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 刪除已存在的允許規則 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # 添加阻止規則 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "已阻止IP$ip" fi done @@ -989,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # 開啟防禦 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -999,12 +1000,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "開啟DDoS防禦" } -# 关闭DDoS防御 +# 關閉DDoS防禦 disable_ddos_defense() { - # 关闭防御 DDoS + # 關閉防禦 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1014,14 +1015,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "關閉DDoS防禦" } -# 管理国家IP规则的函数 +# 管理國家IP規則的函數 manage_country_rules() { local action="$1" local country_code="$2" @@ -1032,18 +1033,18 @@ manage_country_rules() { case "$action" in block) - # 如果 ipset 不存在则创建 + # 如果 ipset 不存在則創建 if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # 下載 IP 區域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "錯誤:下載$country_code的 IP 區域文件失敗" exit 1 fi - # 将 IP 添加到 ipset + # 將 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" @@ -1052,53 +1053,53 @@ manage_country_rules() { iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "已成功阻止$country_code的 IP 地址" rm "${country_code,,}.zone" ;; allow) - # 为允许的国家创建 ipset(如果不存在) + # 為允許的國家創建 ipset(如果不存在) if ! ipset list "$ipset_name" &> /dev/null; then ipset create "$ipset_name" hash:net fi - # 下载 IP 区域文件 + # 下載 IP 區域文件 if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "錯誤:下載$country_code的 IP 區域文件失敗" exit 1 fi - # 删除现有的国家规则 + # 刪除現有的國家規則 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null ipset flush "$ipset_name" - # 将 IP 添加到 ipset + # 將 IP 添加到 ipset while IFS= read -r ip; do ipset add "$ipset_name" "$ip" done < "${country_code,,}.zone" - # 仅允许指定国家的 IP + # 僅允許指定國家的 IP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" + echo "已成功僅允許$country_code的 IP 地址" rm "${country_code,,}.zone" ;; unblock) - # 删除国家的 iptables 规则 + # 刪除國家的 iptables 規則 iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset + # 銷毀 ipset if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "已成功解除$country_code的 IP 地址限制" ;; *) @@ -1115,42 +1116,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "高級防火牆管理" + send_stats "高級防火牆管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "防火牆管理" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1. 開放指定端口 2. 關閉指定端口" + echo "3. 開放所有端口 4. 關閉所有端口" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" + echo "5. IP白名單 6. IP黑名單" echo "7. 清除指定IP" echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. 允許PING 12. 禁止PING" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" + echo "17. 解除指定國家IP限制" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "請輸入開放的端口號:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "開放指定端口" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "請輸入關閉的端口號:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "關閉指定端口" ;; 3) - # 开放所有端口 + # 開放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1163,10 +1164,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "開放所有端口" ;; 4) - # 关闭所有端口 + # 關閉所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1179,33 +1180,33 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "關閉所有端口" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IP 白名單 + read -e -p "請輸入放行的IP或IP段:" o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IP 黑名單 + read -e -p "請輸入封鎖的IP或IP段:" c_ip block_ip $c_ip ;; 7) # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + read -e -p "請輸入清除的IP:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 send_stats "清除指定IP" ;; 11) - # 允许 PING + # 允許 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "允許PING" ;; 12) # 禁用 PING @@ -1222,20 +1223,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "請輸入阻止的國家代碼(如 CN, US, JP):" country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "請輸入允許的國家代碼(如 CN, US, JP):" country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "阻止國家$country_code的IP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "請輸入清除的國家代碼(如 CN, US, JP):" country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "清除國家$country_code的IP" ;; *) @@ -1256,23 +1257,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 獲取當前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 遍歷並刪除所有的 swap 分區 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # 確保 /swapfile 不再被使用 swapoff /swapfile - # 删除旧的 /swapfile + # 刪除舊的 /swapfile rm -f /swapfile - # 创建新的 swap 分区 + # 創建新的 swap 分區 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1287,7 +1288,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "虛擬內存大小已調整為${gl_huang}${new_swap}${gl_bai}M" } @@ -1297,7 +1298,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 判斷是否需要創建虛擬內存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1313,21 +1314,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # 獲取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # 獲取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # 獲取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # 獲取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1340,7 +1341,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 創建必要的目錄和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1349,11 +1350,11 @@ install_ldnmp_conf() { default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # 下載 docker-compose.yml 文件並進行替換 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # 在 docker-compose.yml 文件中進行替換 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1398,7 +1399,7 @@ install_ldnmp() { clear - echo "LDNMP环境安装完毕" + echo "LDNMP環境安裝完畢" echo "------------------------" ldnmp_v @@ -1415,7 +1416,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "續簽任務已更新" } @@ -1452,15 +1453,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming公鑰信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming私鑰信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}證書存放路徑${gl_bai}" + echo "公鑰: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私鑰: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1469,7 +1470,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1485,8 +1486,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" + echo "站點信息 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1525,19 +1526,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "域名證書申請成功" else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "域名證書申請失敗" + echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + echo -e "1. 域名拼寫錯誤 ➠ 請檢查域名輸入是否正確" + echo -e "2. DNS解析問題 ➠ 確認域名已正確解析到本服務器IP" + echo -e "3. 網絡配置問題 ➠ 如使用Cloudflare Warp等虛擬網絡請暫時關閉" + echo -e "4. 防火牆限制 ➠ 檢查80/443端口是否開放,確保驗證可訪問" + echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" + echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" break_end clear - echo "请再次尝试部署 $webname" + echo "請再次嘗試部署$webname" add_yuming install_ssltls certs_status @@ -1548,7 +1549,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "域名重複使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1557,8 +1558,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "先將域名解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "請輸入你的IP或者解析過的域名:" yuming } @@ -1642,11 +1643,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "登錄信息:" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "啟動$ldnmp_pods" } @@ -1656,29 +1657,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 檢查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 從配置文件讀取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # 將 ZONE_IDS 轉換為數組 ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # 提示用戶是否清理緩存 + read -e -p "需要清理 Cloudflare 的緩存嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以後期修改CF信息" + read -e -p "請輸入你的 API_TOKEN:" API_TOKEN + read -e -p "請輸入你的CF用戶名:" EMAIL + read -e -p "請輸入 zone_id(多個用空格分隔):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 循環遍歷每個 zone_id 並執行清除緩存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "正在清除緩存 for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1686,13 +1687,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "緩存清除請求已發送完畢。" } web_cache() { - send_stats "清理站点缓存" + send_stats "清理站點緩存" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1702,28 +1703,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "刪除站點數據,請輸入你的域名(多個域名用空格隔開):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "正在刪除域名:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # 將域名轉換為數據庫名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # 刪除數據庫前檢查是否存在,避免報錯 + echo "正在刪除數據庫:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1739,23 +1740,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # 根據 mode 參數來決定開啟或關閉 WAF if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # 開啟 WAF:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # 關閉 WAF:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無效的參數:使用 'on' 或 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # 檢查 nginx 鏡像並根據情況處理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1802,11 +1803,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 刪除舊定義 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 插入新定義,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1829,12 +1830,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 刪除舊定義 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 插入新定義,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1857,7 +1858,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # 開啟 Brotli:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1871,7 +1872,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # 關閉 Brotli:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1887,11 +1888,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "無效的參數:使用 'on' 或 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # 檢查 nginx 鏡像並根據情況處理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1913,7 +1914,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # 開啟 Zstd:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1928,7 +1929,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # 關閉 Zstd:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1944,11 +1945,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "無效的參數:使用 'on' 或 'off'" return 1 fi - # 检查 nginx 镜像并根据情况处理 + # 檢查 nginx 鏡像並根據情況處理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1975,7 +1976,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "無效的參數:使用 'on' 或 'off'" return 1 fi @@ -1989,7 +1990,7 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP環境防禦" while true; do check_waf_status check_cf_mode @@ -2003,25 +2004,25 @@ web_security() { docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服務器網站防禦程序${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 安裝防禦程序" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" + echo "7. 查看防禦規則列表 8. 查看日誌實時監控" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11. 配置攔截參數 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21. cloudflare模式 22. 高負載開啟5秒盾" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31. 開啟WAF 32. 關閉WAF" + echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 卸載防禦程序" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2081,7 +2082,7 @@ web_security() { docker rm -f fail2ban rm -rf /path/to/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防禦程序已卸載" ;; 11) @@ -2097,10 +2098,10 @@ web_security() { 21) send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + echo "到cf後台右上角我的個人資料,選擇左側API令牌,獲取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "輸入CF的賬號:" cfuser + read -e -p "輸入CF的Global API Key:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2115,21 +2116,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "高負載開啟5秒盾" + echo -e "${gl_huang}網站每5分鐘自動檢測,當達檢測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "獲取CF參數:" + echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,獲取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "輸入CF的賬號:" cfuser + read -e -p "輸入CF的Global API Key:" cftoken + read -e -p "輸入CF中域名的區域ID:" cfzonID cd ~ install jq bc @@ -2146,23 +2147,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "高負載自動開盾腳本已添加" else - echo "自动开盾脚本已存在,无需添加" + echo "自動開盾腳本已存在,無需添加" fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "站點WAF已開啟" + send_stats "站點WAF已開啟" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "站點WAF已關閉" + send_stats "站點WAF已關閉" ;; 33) @@ -2188,10 +2189,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 获取当前的 worker_processes 设置值 +# 獲取當前的 worker_processes 設置值 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 根据值设置模式信息 +# 根據值設置模式信息 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2207,21 +2208,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # 檢查 zstd 是否開啟且未被註釋(整行以 zstd on; 開頭) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # 檢查 brotli 是否開啟且未被註釋 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # 檢查 gzip 是否開啟且未被註釋 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2237,33 +2238,33 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "優化LDNMP環境" + echo -e "優化LDNMP環境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. 標準模式 2. 高性能模式 (推薦2H4G以上)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" + echo "5. 開啟br壓縮 6. 關閉br壓縮" + echo "7. 開啟zstd壓縮 8. 關閉zstd壓縮" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "站點標準模式" - # nginx调优 + # nginx調優 sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # php调优 + # php調優 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # php調優 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2275,7 +2276,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysql調優 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2287,23 +2288,23 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境已設置成 標準模式" ;; 2) - send_stats "站点高性能模式" + send_stats "站點高性能模式" - # nginx调优 + # nginx調優 sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # php调优 + # php調優 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # php調優 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2315,7 +2316,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # mysql調優 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2325,7 +2326,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP環境已設置成 高性能模式" ;; 3) @@ -2385,9 +2386,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker="${gl_lv}已安裝${gl_bai}" # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker="${gl_hui}未安裝${gl_bai}" # fi # } @@ -2395,7 +2396,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "訪問地址:" ip_address @@ -2433,31 +2434,31 @@ check_docker_image_update() { return fi - # 获取容器的创建时间和镜像名称 + # 獲取容器的創建時間和鏡像名稱 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 提取镜像仓库和标签 + # 提取鏡像倉庫和標籤 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 默认标签为 latest + # 默認標籤為 latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 添加对官方镜像的支持 + # 添加對官方鏡像的支持 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 从 Docker Hub API 获取镜像发布时间 + # 從 Docker Hub API 獲取鏡像發佈時間 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 验证获取的时间 + # 驗證獲取的時間 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 比较时间戳 + # 比較時間戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2476,7 +2477,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 獲取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2486,34 +2487,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 檢查並封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 檢查並放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 檢查並放行本地網絡 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 檢查並封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 檢查並放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 檢查並放行本地網絡 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2523,7 +2524,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "已阻止IP+端口訪問該服務" save_iptables_rules } @@ -2534,7 +2535,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 獲取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2544,17 +2545,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 清除封禁其他所有 IP 的規則 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 清除放行指定 IP 的規則 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 清除放行本地網絡 127.0.0.0/8 的規則 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2563,17 +2564,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 清除封禁其他所有 IP 的規則 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 清除放行指定 IP 的規則 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 清除放行本地網絡 127.0.0.0/8 的規則 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2584,7 +2585,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "已允許IP+端口訪問該服務" save_iptables_rules } @@ -2598,25 +2599,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "錯誤:請提供端口號和允許訪問的 IP。" + echo "用法: block_host_port <端口號> <允許的IP>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 拒絕其他所有 IP 訪問 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 允許指定 IP 訪問 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 允許本機訪問 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2625,27 +2626,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 拒絕其他所有 IP 訪問 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 允許指定 IP 訪問 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 允許本機訪問 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 允許已建立和相關連接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "已阻止IP+端口訪問該服務" save_iptables_rules } @@ -2657,47 +2658,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "錯誤:請提供端口號和允許訪問的 IP。" + echo "用法: clear_host_port_rules <端口號> <允許的IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 清除封禁所有其他 IP 訪問的規則 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 清除允許本機訪問的規則 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 清除允許指定 IP 訪問的規則 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 清除封禁所有其他 IP 訪問的規則 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 清除允許本機訪問的規則 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 清除允許指定 IP 訪問的規則 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "已允許IP+端口訪問該服務" save_iptables_rules } @@ -2746,18 +2747,18 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 添加域名訪問 6. 刪除域名訪問" + echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2770,12 +2771,12 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name已經安裝完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "安裝$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2785,7 +2786,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "$docker_name 已经安装完成" + echo "$docker_name已經安裝完成" check_docker_app_ip echo "" $docker_use @@ -2799,30 +2800,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "應用已卸載" + send_stats "解除安裝$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}域名訪問設置" + send_stats "${docker_name}域名訪問設置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "域名格式 example.com 不帶https://" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "允許IP訪問${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "阻止IP訪問${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2859,18 +2860,18 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 添加域名訪問 6. 刪除域名訪問" + echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) check_disk_space $app_size - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2894,22 +2895,22 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}域名訪問設置" + send_stats "${docker_name}域名訪問設置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "域名格式 example.com 不帶https://" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "允許IP訪問${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "阻止IP訪問${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2994,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# 檢查會話是否存在的函數 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 循環直到找到一個不存在的會話名稱 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 創建新的 tmux 會話 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3079,7 +3080,7 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "已重啟" reboot ;; *) @@ -3126,8 +3127,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "無法再次安裝LDNMP環境" + echo -e "${gl_huang}提示:${gl_bai}建站環境已安裝。無需再次安裝!" break_end linux_ldnmp fi @@ -3137,10 +3138,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "安裝LDNMP環境" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" check_disk_space 3 check_port install_dependency @@ -3154,10 +3155,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "安裝nginx環境" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" check_disk_space 1 check_port install_dependency @@ -3168,8 +3169,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安裝完成" +echo -e "當前版本:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3180,7 +3181,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "請先安裝LDNMP環境" ldnmp_install_all fi @@ -3190,7 +3191,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "請先安裝nginx環境" nginx_install_all fi @@ -3201,16 +3202,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "您的$webname搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webname安裝信息如下:" } nginx_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "您的$webname搭建好了!" echo "https://$yuming" } @@ -3222,8 +3223,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3263,17 +3264,17 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "請輸入你的反代IP:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "請輸入你的反代端口:" port fi nginx_install_status install_ssltls @@ -3296,14 +3297,14 @@ ldnmp_Proxy_backend() { yuming="${1:-}" reverseproxy_port="${2:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "請輸入你的多個反代IP+端口用空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3356,12 +3357,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMP站點管理" + echo "LDNMP環境" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "站點:${output}證書到期時間" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3374,35 +3375,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "資料庫:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "站點目錄" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "數據${gl_hui}/home/web/html${gl_bai}證書${gl_hui}/home/web/certs${gl_bai}配置${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "操作" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1. 申請/更新域名證書 2. 更換站點域名" + echo "3. 清理站點緩存 4. 創建關聯站點" + echo "5. 查看訪問日誌 6. 查看錯誤日誌" + echo "7. 編輯全局配置 8. 編輯站點配置" + echo "9. 管理站點數據庫 10. 查看站點分析報告" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. 刪除指定站點數據" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "申請域名證書" + read -e -p "請輸入你的域名:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3411,15 +3412,15 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "更換站點域名" + echo -e "${gl_hong}強烈建議:${gl_bai}先備份好全站數據再更換站點域名!" + read -e -p "請輸入舊域名:" oddyuming + read -e -p "請輸入新域名:" yuming install_certbot install_ssltls certs_status - # mysql替换 + # mysql替換 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3437,7 +3438,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # 網站目錄替換 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3458,10 +3459,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "創建關聯站點" + echo -e "為現有的站點再關聯一個新域名用於訪問" + read -e -p "請輸入現有的域名:" oddyuming + read -e -p "請輸入新域名:" yuming install_certbot install_ssltls certs_status @@ -3475,25 +3476,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "查看訪問日誌" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "查看錯誤日誌" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "編輯全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "編輯站點配置" + read -e -p "編輯站點配置,請輸入你要編輯的域名:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3503,7 +3504,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "查看站點數據" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3539,16 +3540,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}是一款時下流行且強大的運維管理面板。" + echo "官網介紹:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 安裝 2. 管理 3. 卸載" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) check_disk_space 1 @@ -3557,7 +3558,7 @@ while true; do panel_app_install mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - send_stats "${panelname}安装" + send_stats "${panelname}安裝" ;; 2) panel_app_manage @@ -3570,7 +3571,7 @@ while true; do panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}解除安裝" ;; *) break @@ -3614,8 +3615,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "安裝frp服務端" + # 生成隨機端口和憑證 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3636,17 +3637,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 輸出生成的信息 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "客戶端部署時需要用的參數" + echo "服務IP:$ipv4_address" echo "token: $token" echo echo "FRP面板信息" echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRP面板用戶名:$dashboard_user" + echo "FRP面板密碼:$dashboard_pwd" echo open_port 8055 8056 @@ -3656,9 +3657,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "安裝frp客戶端" + read -e -p "請輸入外網對接IP:" server_addr + read -e -p "請輸入外網對接token:" token echo mkdir -p /home/frp @@ -3678,17 +3679,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "添加frp內網服務" + # 提示用戶輸入服務名稱和轉發信息 + read -e -p "請輸入服務名稱:" service_name + read -e -p "請輸入轉發類型 (tcp/udp) [回​​車默認tcp]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "請輸入內網IP [回車默認127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "請輸入內網端口:" local_port + read -e -p "請輸入外網端口:" remote_port - # 将用户输入写入配置文件 + # 將用戶輸入寫入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3698,8 +3699,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 輸出生成的信息 + echo "服務$service_name已成功添加到 frpc.toml" docker restart frpc @@ -3710,12 +3711,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "刪除frp內網服務" + # 提示用戶輸入需要刪除的服務名稱 + read -e -p "請輸入需要刪除的服務名稱:" service_name + # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "服務$service_name已成功從 frpc.toml 刪除" docker restart frpc @@ -3725,7 +3726,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # 打印表頭 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3746,7 +3747,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 如果已有服務信息,在處理新服務之前打印當前服務 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3755,7 +3756,7 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 更新當前服務名稱 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -3788,7 +3789,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 打印最後一個服務的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3801,17 +3802,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# 獲取 FRP 服務端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# 生成訪問地址 generate_access_urls() { - # 首先获取所有端口 + # 首先獲取所有端口 get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 檢查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3820,18 +3821,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 只在有有效端口時顯示標題和內容 if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP服務對外訪問地址:" - # 处理 IPv4 地址 + # 處理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # 處理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3840,7 +3841,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # 處理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3867,7 +3868,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRP服務端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -3875,25 +3876,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP服務端$check_frp $update_status" + echo "構建FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" + echo "官網介紹: https://github.com/fatedier/frp/" + echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5. 內網服務域名訪問 6. 刪除域名訪問" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. 刷新服務狀態 0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) install jq grep ss @@ -3901,7 +3902,7 @@ frps_panel() { generate_frps_config mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经安装完成" + echo "FRP服務端已經安裝完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3911,7 +3912,7 @@ frps_panel() { donlond_frp frps mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP服务端已经更新完成" + echo "FRP服務端已經更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3922,37 +3923,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "應用已卸載" ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "將內網穿透服務反代成域名訪問" + send_stats "FRP對外域名訪問" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "請輸入你的內網穿透服務端口:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "域名格式 example.com 不帶https://" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "允許IP訪問" + read -e -p "請輸入需要放行的端口:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "阻止IP訪問" + echo "如果你已經反代域名訪問了,可用此功能阻止IP+端口訪問,這樣更安全。" + read -e -p "請輸入需要阻止的端口:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "刷新FRP服務狀態" + echo "已經刷新FRP服務狀態" ;; *) @@ -3965,7 +3966,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRP客戶端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3973,10 +3974,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP客戶端$check_frp $update_status" + echo "與服務端對接,對接後可創建內網穿透服務到互聯網訪問" + echo "官網介紹: https://github.com/fatedier/frp/" + echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3984,13 +3985,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. 添加對外服務 5. 刪除對外服務 6. 手動配置服務" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) install jq grep ss @@ -3998,7 +3999,7 @@ frpc_panel() { configure_frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经安装完成" + echo "FRP客戶端已經安裝完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4008,7 +4009,7 @@ frpc_panel() { donlond_frp frpc mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "FRP客户端已经更新完成" + echo "FRP客戶端已經更新完成" ;; 3) @@ -4019,7 +4020,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "應用已卸載" ;; 4) @@ -4065,33 +4066,33 @@ yt_menu_pro() { fi clear - send_stats "yt-dlp 下载工具" + send_stats "yt-dlp 下載工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一個功能強大的視頻下載工具,支持 YouTube、Bilibili、Twitter 等數千站點。" + echo -e "官網地址:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "已下載視頻列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. 單個視頻下載 6. 批量視頻下載 7. 自定義參數下載" + echo "8. 下載為MP3音頻 9. 刪除視頻目錄 10. Cookie管理(開發中)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "請輸入選項編號:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "正在安裝 yt-dlp..." + echo "正在安裝 yt-dlp..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "安装完成。按任意键继续..." + echo "安裝完成。按任意鍵繼續..." read ;; 2) send_stats "正在更新 yt-dlp..." @@ -4099,34 +4100,34 @@ yt_menu_pro() { yt-dlp -U mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) - echo "更新完成。按任意键继续..." + echo "更新完成。按任意鍵繼續..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "正在卸載 yt-dlp..." + echo "正在卸載 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "卸載完成。按任意鍵繼續..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "單個視頻下載" + read -e -p "請輸入視頻鏈接:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "下載完成,按任意鍵繼續..." ;; 6) - send_stats "批量视频下载" + send_stats "批量視頻下載" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 輸入多個視頻鏈接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "現在開始批量下載..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4134,31 +4135,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "批量下載完成,按任意鍵繼續..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "自定義視頻下載" + read -e -p "請輸入完整 yt-dlp 參數(不含 yt-dlp):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "執行完成,按任意鍵繼續..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3下載" + read -e -p "請輸入視頻鏈接:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "音頻下載完成,按任意鍵繼續..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "刪除視頻" + read -e -p "請輸入刪除視頻名稱:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4194,7 +4195,7 @@ set_timedate() { -# 修复dpkg中断问题 +# 修復dpkg中斷問題 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4203,7 +4204,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_huang}正在系統更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4230,7 +4231,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_huang}正在系統清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4259,13 +4260,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "清理包管理器緩存..." apk cache clean - echo "删除系统日志..." + echo "刪除系統日誌..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "刪除APK緩存..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "刪除臨時文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4283,19 +4284,19 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "刪除系統日誌..." rm -rf /var/log/* - echo "删除临时文件..." + echo "刪除臨時文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "清理未使用的依賴..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "清理包管理器緩存..." pkg clean -y - echo "删除系统日志..." + echo "刪除系統日誌..." rm -rf /var/log/* - echo "删除临时文件..." + echo "刪除臨時文件..." rm -rf /tmp/* else @@ -4339,26 +4340,26 @@ fi set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "優化DNS" while true; do clear - echo "优化DNS地址" + echo "優化DNS地址" echo "------------------------" - echo "当前DNS地址" + echo "當前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1. 國外DNS優化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2. 國內DNS優化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3. 手動編輯DNS配置" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "請輸入你的選擇:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4366,7 +4367,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "國外DNS優化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4374,12 +4375,12 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "國內DNS優化" ;; 3) install nano nano /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "手動編輯DNS配置" ;; *) break @@ -4402,13 +4403,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes + # 如果找到 PasswordAuthentication 設置為 yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 如果找到 PubkeyAuthentication 设置为 yes + # 如果找到 PubkeyAuthentication 設置為 yes if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4416,7 +4417,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 + # 如果 PasswordAuthentication 和 PubkeyAuthentication 都沒有匹配,則設置默認值 if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4427,7 +4428,7 @@ correct_ssh_config() { new_ssh_port() { - # 备份 SSH 配置文件 + # 備份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4440,7 +4441,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSH 端口已修改為:$new_port" sleep 1 @@ -4458,7 +4459,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "私鑰信息已生成,務必復制保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4470,17 +4471,17 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" } import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}錯誤:未輸入公鑰內容。${gl_bai}" return 1 fi @@ -4498,7 +4499,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}公鑰已成功導入,ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" } @@ -4507,26 +4508,26 @@ import_sshkey() { add_sshpasswd() { -echo "设置你的ROOT密码" +echo "設置你的ROOT密碼" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" +echo -e "${gl_lv}ROOT登錄設置完畢!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示:${gl_bai}該功能需要root用戶才能運行!" && break_end && kejilion } dd_xitong() { - send_stats "重装系统" + send_stats "重裝系統" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4537,41 +4538,41 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始端口:${gl_huang}22${gl_bai}" + echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai}初始端口:${gl_huang}3389${gl_bai}" + echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}22${gl_bai}" + echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}3389${gl_bai}" + echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" + echo -e "${gl_hui}感謝leitbogioro大佬和bin456789大佬的腳本支持!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4587,21 +4588,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2022" echo "45. Windows Server 2019 46. Windows Server 2016" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "請選擇要重裝的系統:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "重裝debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4609,49 +4610,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "重裝debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "重裝debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "重裝debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "重裝ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "重裝ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "重裝ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "重裝ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4660,7 +4661,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "重裝rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4668,7 +4669,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "重裝rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4676,7 +4677,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "重裝alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4684,7 +4685,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "重裝alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4692,7 +4693,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "重裝oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4700,7 +4701,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "重裝oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4708,7 +4709,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "重裝fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4716,7 +4717,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "重裝fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4724,7 +4725,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "重裝centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4732,7 +4733,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "重裝centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4740,7 +4741,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "重裝alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4748,7 +4749,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "重裝arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -4756,7 +4757,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "重裝kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -4764,7 +4765,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "重裝openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4772,7 +4773,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "重裝opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4780,7 +4781,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "重裝飛牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4789,7 +4790,7 @@ dd_xitong() { 41) - send_stats "重装windows11" + send_stats "重裝windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4797,13 +4798,13 @@ dd_xitong() { ;; 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "重裝windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "重裝windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4811,21 +4812,21 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "重裝windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; 45) - send_stats "重装windows server 19" + send_stats "重裝windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; 46) - send_stats "重装windows server 16" + send_stats "重裝windows server 16" dd_xitong_2 bash InstallNET.sh -windows 2016 -lang "cn" reboot @@ -4833,7 +4834,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "重裝windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4863,17 +4864,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "您已安裝xanmod的BBRv3內核" + echo "當前內核版本:$kernel_version" echo "" - echo "内核管理" + echo "內核管理" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) @@ -4883,7 +4884,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 步驟3:添加存儲庫 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4892,7 +4893,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "XanMod內核已更新。重啟後生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4902,7 +4903,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "XanMod內核已卸載。重啟後生效" server_reboot ;; @@ -4915,13 +4916,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "設置BBR3加速" + echo "視頻介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "僅支持Debian/Ubuntu" + echo "請備份數據,將為你升級Linux內核開啟BBR3" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) @@ -4929,12 +4930,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "當前環境不支持,僅支持Debian和Ubuntu系統" break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "無法確定操作系統類型" break_end linux_Settings fi @@ -4945,7 +4946,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 步驟3:添加存儲庫 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4956,7 +4957,7 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "XanMod內核安裝並BBR3啟用成功。重啟後生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4966,7 +4967,7 @@ bbrv3() { echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac fi @@ -4975,40 +4976,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # 導入 ELRepo GPG 公鑰 + echo "導入 ELRepo GPG 公鑰..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 確保我們在一個支持的操作系統上運行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "不支持的操作系統:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 打印檢測到的操作系統信息 + echo "檢測到的操作系統:$os_name $os_version" + # 根據系統版本安裝對應的 ELRepo 倉庫配置 if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "安裝 ELRepo 倉庫配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "安裝 ELRepo 倉庫配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "安裝 ELRepo 倉庫配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "不支持的系統版本:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # 啟用 ELRepo 內核倉庫並安裝最新的主線內核 + echo "啟用 ELRepo 內核倉庫並安裝最新的主線內核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "已安裝 ELRepo 倉庫配置並更新到最新主線內核。" server_reboot } @@ -5016,37 +5017,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "紅帽內核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "您已安裝elrepo內核" + echo "當前內核版本:$kernel_version" echo "" - echo "内核管理" + echo "內核管理" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. 更新elrepo內核 2. 卸載elrepo內核" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "更新紅帽內核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "elrepo內核已卸載。重啟後生效" + send_stats "卸載紅帽內核" server_reboot ;; @@ -5059,26 +5060,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "請備份數據,將為你升級Linux內核" + echo "視頻介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "僅支持紅帽系列發行版 CentOS/RedHat/Alma/Rocky/oracle" + echo "升級Linux內核可提升系統性能和安全,建議有條件的嘗試,生產環境謹慎升級!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "升級紅帽內核" server_reboot ;; [Nn]) echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac fi @@ -5089,7 +5090,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_huang}正在更新病毒庫...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5099,19 +5100,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "請指定要掃描的目錄。" return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_huang}正在掃描目錄$@...${gl_bai}" - # 构建 mount 参数 + # 構建 mount 參數 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # 構建 clamscan 命令參數 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5120,7 +5121,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # 執行 Docker 命令 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5129,8 +5130,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}$@ 掃描完成,病毒報告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜索FOUND關鍵字確認病毒位置${gl_bai}" } @@ -5142,23 +5143,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "病毒掃描管理" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒掃描工具" + echo "視頻介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "是一個開源的防病毒軟件工具,主要用於檢測和刪除各種類型的惡意軟件。" + echo "包括病毒、特洛伊木馬、間諜軟件、惡意腳本和其他有害軟件。" echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自定義目錄掃描${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "全盤掃描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5167,7 +5168,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "重要目錄掃描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5175,8 +5176,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "自定義目錄掃描" + read -e -p "請輸入要掃描的目錄,用空格分隔(例如:/etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5193,21 +5194,21 @@ clamav() { -# 高性能模式优化函数 +# 高性能模式優化函數 optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}切換到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}優化虛擬內存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}優化網絡設置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5219,14 +5220,14 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}優化緩存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}優化CPU設置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}其他優化...${gl_bai}" + # 禁用透明大頁面,減少延遲 echo never > /sys/kernel/mm/transparent_hugepage/enabled # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5234,21 +5235,21 @@ optimize_high_performance() { } -# 均衡模式优化函数 +# 均衡模式優化函數 optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" + echo -e "${gl_lv}切換到均衡模式...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化文件描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}優化虛擬內存...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}優化網絡設置...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5260,36 +5261,36 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}優化緩存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}優化CPU設置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}其他優化...${gl_bai}" + # 還原透明大頁面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # 還原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 还原默认设置函数 +# 還原默認設置函數 restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}還原到默認設置...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" + echo -e "${gl_lv}還原文件描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" + echo -e "${gl_lv}還原虛擬內存...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}还原网络设置...${gl_bai}" + echo -e "${gl_lv}還原網絡設置...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,37 +5302,37 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}还原缓存管理...${gl_bai}" + echo -e "${gl_lv}還原緩存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}还原CPU设置...${gl_bai}" + echo -e "${gl_lv}還原CPU設置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 + echo -e "${gl_lv}還原其他優化...${gl_bai}" + # 還原透明大頁面 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing + # 還原 NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null } -# 网站搭建优化函数 +# 網站搭建優化函數 optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" + echo -e "${gl_lv}切換到網站搭建優化模式...${gl_bai}" - echo -e "${gl_lv}优化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化文件描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" + echo -e "${gl_lv}優化虛擬內存...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}优化网络设置...${gl_bai}" + echo -e "${gl_lv}優化網絡設置...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5343,14 +5344,14 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}优化缓存管理...${gl_bai}" + echo -e "${gl_lv}優化緩存管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}优化CPU设置...${gl_bai}" + echo -e "${gl_lv}優化CPU設置...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 + echo -e "${gl_lv}其他優化...${gl_bai}" + # 禁用透明大頁面,減少延遲 echo never > /sys/kernel/mm/transparent_hugepage/enabled # 禁用 NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5363,62 +5364,62 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - echo "Linux系统内核参数优化" - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux內核調優管理" + echo "Linux系統內核參數優化" + echo "視頻介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "提供多種系統參數調優模式,用戶可以根據自身使用場景進行選擇切換。" + echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo "1. 高性能優化模式: 最大化系統性能,優化文件描述符、虛擬內存、網絡設置、緩存管理和CPU設置。" + echo "2. 均衡優化模式: 在性能與資源消耗之間取得平衡,適合日常使用。" + echo "3. 網站優化模式: 針對網站服務器進行優化,提高並發連接處理能力、響應速度和整體性能。" + echo "4. 直播優化模式: 針對直播推流的特殊需求進行優化,減少延遲,提高傳輸性能。" + echo "5. 遊戲服優化模式: 針對遊戲服務器進行優化,提高並發處理能力和響應速度。" + echo "6. 還原默認設置: 將系統設置還原為默認配置。" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能模式优化" + send_stats "高性能模式優化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "均衡模式優化" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "網站優化模式" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "直播推流优化" + send_stats "直播推流優化" ;; 5) cd ~ clear local tiaoyou_moshi="游戏服优化模式" optimize_high_performance - send_stats "游戏服优化" + send_stats "遊戲服優化" ;; 6) cd ~ clear restore_defaults - send_stats "还原默认设置" + send_stats "還原默認設置" ;; *) break @@ -5445,7 +5446,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" hash -r break_end @@ -5454,17 +5455,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "不支持的系統:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "不支持的系統,無法識別系統類型。" break_end fi } @@ -5474,29 +5475,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "切換系統語言" while true; do clear - echo "当前系统语言: $LANG" + echo "當前系統語言:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. 英文 2. 簡體中文 3. 繁體中文" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "切換到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "切換到簡體中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "切換到繁體中文" ;; *) break @@ -5518,7 +5519,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" hash -r break_end @@ -5542,9 +5543,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) @@ -5589,7 +5590,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "系統回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5604,17 +5605,17 @@ linux_trash() { fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "當前回收站${trash_status}" + echo -e "啟用後rm刪除的文件先進入回收站,防止誤刪重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站為空" echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1. 啟用回收站 2. 關閉回收站" + echo "3. 還原內容 4. 清空回收站" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) @@ -5622,7 +5623,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "回收站已啟用,刪除的文件將移至回收站。" sleep 2 ;; 2) @@ -5630,20 +5631,20 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "回收站已關閉,文件將直接刪除。" sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "輸入要還原的文件名:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restore已還原到主目錄。" else echo "文件不存在。" fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "確認清空回收站? [y/n]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty echo "回收站已清空。" @@ -5657,23 +5658,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "命令收藏夾" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# 創建備份 create_backup() { - send_stats "创建备份" + send_stats "創建備份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # 提示用戶輸入備份目錄 + echo "創建備份示例:" + echo "- 備份單個目錄: /var/www" + echo "- 備份多個目錄: /etc /home /var/log" + echo "- 直接回車將使用默認目錄 (/etc /usr /home)" + read -r -p "請輸入要備份的目錄(多個目錄用空格分隔,直接回車則使用默認目錄):" input - # 如果用户没有输入目录,则使用默认目录 + # 如果用戶沒有輸入目錄,則使用默認目錄 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5681,119 +5682,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 將用戶輸入的目錄按空格分隔成數組 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 生成備份文件前綴 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # 提取目錄名稱並去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 去除最後一個下劃線 local PREFIX=${PREFIX%_} - # 生成备份文件名 + # 生成備份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # 打印用戶選擇的目錄 + echo "您選擇的備份目錄為:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # 創建備份 + echo "正在創建備份$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # 檢查命令是否成功 if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "備份創建成功:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "備份創建失敗!" exit 1 fi } -# 恢复备份 +# 恢復備份 restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "恢復備份" + # 選擇要恢復的備份 + read -e -p "請輸入要恢復的備份文件名:" BACKUP_NAME - # 检查备份文件是否存在 + # 檢查備份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "備份文件不存在!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "正在恢復備份$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "備份恢復成功!" else - echo "备份恢复失败!" + echo "備份恢復失敗!" exit 1 fi } -# 列出备份 +# 列出備份 list_backups() { - echo "可用的备份:" + echo "可用的備份:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# 刪除備份 delete_backup() { - send_stats "删除备份" + send_stats "刪除備份" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "請輸入要刪除的備份文件名:" BACKUP_NAME - # 检查备份文件是否存在 + # 檢查備份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "備份文件不存在!" exit 1 fi - # 删除备份 + # 刪除備份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "備份刪除成功!" else - echo "备份删除失败!" + echo "備份刪除失敗!" exit 1 fi } -# 备份主菜单 +# 備份主菜單 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "系統備份功能" + echo "系統備份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1. 創建備份 2. 恢復備份 3. 刪除備份" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "按回車鍵繼續..." done } @@ -5805,56 +5806,56 @@ linux_backup() { -# 显示连接列表 +# 顯示連接列表 list_connections() { - echo "已保存的连接:" + echo "已保存的連接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 添加新連接 add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "添加新連接" + echo "創建新連接示例:" + echo "- 連接名稱: my_server" + echo "- IP地址: 192.168.1.100" + echo "- 用戶名: root" + echo "- 端口: 22" echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user + read -e -p "請輸入連接名稱:" name + read -e -p "請輸入IP地址:" ip + read -e -p "請輸入用戶名 (默認: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port + read -e -p "請輸入端口號 (默認: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "請選擇身份驗證方式:" + echo "1. 密碼" + echo "2. 密鑰" + read -e -p "請輸入選擇 (1/2):" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "請輸入密碼:" password_or_key echo # 换行 ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 檢查是否是密鑰內容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5863,89 +5864,89 @@ add_connection() { fi ;; *) - echo "无效的选择!" + echo "無效的選擇!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "連接已保存!" } -# 删除连接 +# 刪除連接 delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "刪除連接" + read -e -p "請輸入要刪除的連接編號:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "錯誤:未找到對應的連接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 如果連接使用的是密鑰文件,則刪除該密鑰文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "連接已刪除!" } -# 使用连接 +# 使用連接 use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "使用連接" + read -e -p "請輸入要使用的連接編號:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "錯誤:未找到對應的連接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "正在連接到$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 使用密鑰連接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "連接失敗!請檢查以下內容:" + echo "1. 密鑰文件路徑是否正確:$password_or_key" + echo "2. 密鑰文件權限是否正確(應為 600)。" + echo "3. 目標服務器是否允許使用密鑰登錄。" fi else - # 使用密码连接 + # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "連接失敗!請檢查以下內容:" + echo "1. 用戶名和密碼是否正確。" + echo "2. 目標服務器是否允許密碼登錄。" + echo "3. 目標服務器的 SSH 服務是否正常運行。" fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "ssh遠程連接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 檢查配置文件和密鑰目錄是否存在,如果不存在則創建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5957,21 +5958,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSH 遠程連接工具" + echo "可以通過SSH連接到其他Linux系統上" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. 創建新連接 2. 使用連接 3. 刪除連接" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無效的選擇,請重試。" ;; esac done } @@ -5987,156 +5988,156 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 列出可用的硬盤分區 list_partitions() { - echo "可用的硬盘分区:" + echo "可用的硬盤分區:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 +# 掛載分區 mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "掛載分區" + read -e -p "請輸入要掛載的分區名稱(例如 sda1):" PARTITION - # 检查分区是否存在 + # 檢查分區是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "分區不存在!" return fi - # 检查分区是否已经挂载 + # 檢查分區是否已經掛載 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载!" + echo "分區已經掛載!" return fi - # 创建挂载点 + # 創建掛載點 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 + # 掛載分區 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" + echo "分區掛載成功:$MOUNT_POINT" else - echo "分区挂载失败!" + echo "分區掛載失敗!" rmdir "$MOUNT_POINT" fi } -# 卸载分区 +# 卸載分區 unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "卸載分區" + read -e -p "請輸入要卸載的分區名稱(例如 sda1):" PARTITION - # 检查分区是否已经挂载 + # 檢查分區是否已經掛載 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "分區未掛載!" return fi - # 卸载分区 + # 卸載分區 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "分區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "分區卸載失敗!" fi } -# 列出已挂载的分区 +# 列出已掛載的分區 list_mounted_partitions() { - echo "已挂载的分区:" + echo "已掛載的分區:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# 格式化分區 format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "格式化分區" + read -e -p "請輸入要格式化的分區名稱(例如 sda1):" PARTITION - # 检查分区是否存在 + # 檢查分區是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "分區不存在!" return fi - # 检查分区是否已经挂载 + # 檢查分區是否已經掛載 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "分區已經掛載,請先卸載!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # 選擇文件系統類型 + echo "請選擇文件系統類型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "請輸入你的選擇:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "無效的選擇!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # 確認格式化 + read -e -p "確認格式化分區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # 格式化分區 + echo "正在格式化分區 /dev/$PARTITION為$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "分區格式化成功!" else - echo "分区格式化失败!" + echo "分區格式化失敗!" fi } -# 检查分区状态 +# 檢查分區狀態 check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "檢查分區狀態" + read -e -p "請輸入要檢查的分區名稱(例如 sda1):" PARTITION - # 检查分区是否存在 + # 檢查分區是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "分區不存在!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # 檢查分區狀態 + echo "檢查分區 /dev/$PARTITION的狀態:" fsck "/dev/$PARTITION" } -# 主菜单 +# 主菜單 disk_manager() { - send_stats "硬盘管理功能" + send_stats "硬盤管理功能" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "硬盤分區管理" + echo -e "${gl_huang}該功能內部測試階段,請勿在生產環境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1. 掛載分區 2. 卸載分區 3. 查看已掛載分區" + echo "4. 格式化分區 5. 檢查分區狀態" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6145,64 +6146,64 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "按回車鍵繼續..." done } -# 显示任务列表 +# 顯示任務列表 list_tasks() { - echo "已保存的同步任务:" + echo "已保存的同步任務:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 添加新任務 add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "添加新同步任務" + echo "創建新同步任務示例:" + echo "- 任務名稱: backup_www" + echo "- 本地目錄: /var/www" + echo "- 遠程地址: user@192.168.1.100" + echo "- 遠程目錄: /backup/www" + echo "- 端口號 (默認 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port + read -e -p "請輸入任務名稱:" name + read -e -p "請輸入本地目錄:" local_path + read -e -p "請輸入遠程目錄:" remote_path + read -e -p "請輸入遠程用戶@IP:" remote + read -e -p "請輸入 SSH 端口 (默認 22):" port port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + echo "請選擇身份驗證方式:" + echo "1. 密碼" + echo "2. 密鑰" + read -e -p "請選擇 (1/2):" auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "請輸入密碼:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 + # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 + # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 + # 檢查是否是密鑰內容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6210,63 +6211,63 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "无效的密钥内容!" + echo "無效的密鑰內容!" return fi ;; *) - echo "无效的选择!" + echo "無效的選擇!" return ;; esac - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "請選擇同步模式:" + echo "1. 標準模式 (-avz)" + echo "2. 刪除目標文件 (-avz --delete)" + read -e -p "請選擇 (1/2):" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "無效選擇,使用默認 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "任務已保存!" } -# 删除任务 +# 刪除任務 delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "刪除同步任務" + read -e -p "請輸入要刪除的任務編號:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "錯誤:未找到對應的任務。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # 如果任務使用的是密鑰文件,則刪除該密鑰文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "任務已刪除!" } run_task() { - send_stats "执行同步任务" + send_stats "執行同步任務" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # 解析參數 local direction="push" # 默认是推送到远端 local num @@ -6277,51 +6278,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 如果沒有傳入任務編號,提示用戶輸入 if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "請輸入要執行的任務編號:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "錯誤: 未找到該任務!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 根據同步方向調整源和目標路徑 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "正在推送同步到遠端:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # 添加 SSH 連接通用參數 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # 檢查密鑰文件是否存在和權限是否正確 if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "錯誤:密鑰文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "警告:密鑰文件權限不正確,正在修復..." chmod 600 "$password_or_key" fi @@ -6331,30 +6332,30 @@ run_task() { if [[ $? -eq 0 ]]; then echo "同步完成!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "同步失敗! 請檢查以下內容:" + echo "1. 網絡連接是否正常" + echo "2. 遠程主機是否可訪問" + echo "3. 認證信息是否正確" + echo "4. 本地和遠程目錄是否有正確的訪問權限" fi } -# 创建定时任务 +# 創建定時任務 schedule_task() { - send_stats "添加同步定时任务" + send_stats "添加同步定時任務" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "請輸入要定時同步的任務編號:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "錯誤: 請輸入有效的任務編號!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "請選擇定時執行間隔:" + echo "1) 每小時執行一次" + echo "2) 每天執行一次" + echo "3) 每週執行一次" + read -e -p "請輸入選項 (1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6362,66 +6363,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "錯誤: 請輸入有效的選項!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 檢查是否已存在相同任務 if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "錯誤: 該任務的定時同步已存在!" return fi - # 创建到用户的 crontab + # 創建到用戶的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "定時任務已創建:$cron_job" } -# 查看定时任务 +# 查看定時任務 view_tasks() { - echo "当前的定时任务:" + echo "當前的定時任務:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# 刪除定時任務 delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "刪除同步定時任務" + read -e -p "請輸入要刪除的任務編號:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "錯誤: 請輸入有效的任務編號!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "已刪除任務編號$num的定時任務" } -# 任务管理主菜单 +# 任務管理主菜單 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "Rsync 遠程同步工具" + echo "遠程目錄之間同步,支持增量同步,高效穩定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1. 創建新任務 2. 刪除任務" + echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" + echo "5. 創建定時任務 6. 刪除定時任務" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6430,9 +6431,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "無效的選擇,請重試。" ;; esac - read -e -p "按回车键继续..." + read -e -p "按回車鍵繼續..." done } @@ -6447,7 +6448,7 @@ rsync_manager() { linux_ps() { clear - send_stats "系统信息查询" + send_stats "系統信息查詢" ip_address @@ -6497,41 +6498,41 @@ linux_ps() { echo "" - echo -e "系统信息查询" + echo -e "系統信息查詢" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主機名:${gl_bai}$hostname" + echo -e "${gl_kjlan}系統版本:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系統負載:${gl_bai}$load" + echo -e "${gl_kjlan}物理內存:${gl_bai}$mem_info" + echo -e "${gl_kjlan}虛擬內存:${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盤佔用:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}總接收:${gl_bai}$rx" + echo -e "${gl_kjlan}總發送:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}網絡算法:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}運營商:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" + echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" echo @@ -6544,111 +6545,111 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats "基礎工具" + echo -e "基礎工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通信連接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網絡流量監控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視頻編碼直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盤佔用查看工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本編輯器${gl_kjlan}16. ${gl_bai}nano 文本編輯器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝國屏保${gl_kjlan}22. ${gl_bai}跑火車屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄羅斯方塊小遊戲${gl_kjlan}27. ${gl_bai}貪吃蛇小遊戲" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小遊戲" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}全部安裝${gl_kjlan}32. ${gl_bai}全部安裝(不含屏保和遊戲)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸載" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}安裝指定工具${gl_kjlan}42. ${gl_bai}卸載指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" curl --help - send_stats "安装curl" + send_stats "安裝curl" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" wget --help - send_stats "安装wget" + send_stats "安裝wget" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" sudo --help - send_stats "安装sudo" + send_stats "安裝sudo" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" socat -h - send_stats "安装socat" + send_stats "安裝socat" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "安裝htop" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "安裝iftop" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" unzip - send_stats "安装unzip" + send_stats "安裝unzip" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" tar --help - send_stats "安装tar" + send_stats "安裝tar" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" tmux --help - send_stats "安装tmux" + send_stats "安裝tmux" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "工具已安裝,使用方法如下:" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "安裝ffmpeg" ;; 11) @@ -6656,7 +6657,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "安裝btop" ;; 12) clear @@ -6665,7 +6666,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "安裝ranger" ;; 13) clear @@ -6674,7 +6675,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "安裝ncdu" ;; 14) clear @@ -6683,7 +6684,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "安裝fzf" ;; 15) clear @@ -6692,7 +6693,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "安裝vim" ;; 16) clear @@ -6701,7 +6702,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "安裝nano" ;; @@ -6712,7 +6713,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "安裝git" ;; 21) @@ -6720,67 +6721,67 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "安裝cmatrix" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "安裝sl" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "安裝bastet" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "安裝nsnake" ;; 28) clear install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "安裝ninvaders" ;; 31) clear - send_stats "全部安装" + send_stats "全部安裝" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "全部安裝(不含遊戲和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "全部卸載" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "請輸入安裝的工具名(wget curl sudo htop):" installname install $installname - send_stats "安装指定软件" + send_stats "安裝指定軟件" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "請輸入卸載的工具名(htop ufw tmux cmatrix):" removename remove $removename - send_stats "卸载指定软件" + send_stats "卸載指定軟件" ;; 0) @@ -6788,7 +6789,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -6808,21 +6809,21 @@ linux_bbr() { clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "當前TCP阻塞算法:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. 開啟BBRv3 2. 關閉BBRv3(會重啟)" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "alpine開啟bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6867,21 +6868,21 @@ docker_ssh_migration() { } list_backups() { - echo -e "${BLUE}当前备份列表:${NC}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + echo -e "${BLUE}當前備份列表:${NC}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" } # ---------------------------- - # 备份 + # 備份 # ---------------------------- backup_docker() { - send_stats "Docker备份" + send_stats "Docker備份" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${YELLOW}正在備份 Docker 容器...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers install tar jq gzip install_docker @@ -6892,7 +6893,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}沒有找到容器${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6900,28 +6901,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "# 自動生成的還原腳本" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # 記錄已打包過的 Compose 項目路徑,避免重複打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${GREEN}備份容器:$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${BLUE}檢測到$c是 docker-compose 容器${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir fi - # 如果该 Compose 项目已经打包过,跳过 + # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${YELLOW}Compose 項目 [$project_name] 已備份過,跳過重複打包...${NC}" continue fi @@ -6929,19 +6930,19 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${GREEN}Compose 項目 [$project_name] 已打包:${project_dir}${NC}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${RED}未找到 docker-compose.yml,跳過此容器...${NC}" fi else - # 普通容器备份卷 + # 普通容器備份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷: $path" + echo "打包卷:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6950,7 +6951,7 @@ docker_ssh_migration() { mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 环境变量 + # 環境變量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done @@ -6959,91 +6960,91 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 镜像 + # 鏡像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo -e "\n# 還原容器:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 备份 /home/docker 下的所有文件(不含子目录) + # 備份 /home/docker 下的所有文件(不含子目錄) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${BLUE}備份 /home/docker 下的文件...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}備份完成:${BACKUP_DIR}${NC}" + echo -e "${GREEN}可用還原腳本:${RESTORE_SCRIPT}${NC}" } # ---------------------------- - # 还原 + # 還原 # ---------------------------- restore_docker() { - send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Docker還原" + read -p "請輸入要還原的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${BLUE}開始執行還原操作...${NC}" install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # --------- 優先還原 Compose 項目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -p "未找到原始路徑,請輸入還原目錄路徑:" original_path - # 检查该 compose 项目的容器是否已经在运行 + # 檢查該 compose 項目的容器是否已經在運行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${YELLOW}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${NC}" continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -p "確認還原 Compose 項目 [$project_name] 到路徑 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -p "請輸入新的還原路徑:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${GREEN}Compose 項目 [$project_name] 已解壓到:$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${GREEN}Compose 項目 [$project_name] 還原完成!${NC}" fi done - # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + # --------- 繼續還原普通容器 --------- + echo -e "${BLUE}檢查並還原普通 Docker 容器...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${GREEN}處理容器:$container${NC}" - # 检查容器是否已经存在且正在运行 + # 檢查容器是否已經存在且正在運行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${YELLOW}容器 [$container] 已在運行,跳過還原...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到鏡像信息,跳過:$container${NC}"; continue; } # 端口映射 PORT_ARGS="" @@ -7052,14 +7053,14 @@ docker_ssh_migration() { [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 环境变量 + # 環境變量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷数据恢复 + # 卷映射 + 卷數據恢復 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7070,32 +7071,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢复卷数据: $VOL_SRC" + echo "恢復卷數據:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 删除已存在但未运行的容器 + # 刪除已存在但未運行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${YELLOW}容器 [$container] 存在但未運行,刪除舊容器...${NC}" docker rm -f "$container" fi - # 启动容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 啟動容器 + echo "執行還原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的備份信息${NC}" - # 还原 /home/docker 下的文件 + # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${BLUE}正在還原 /home/docker 下的文件...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${GREEN}/home/docker 下的文件已還原完成${NC}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${YELLOW}未找到 /home/docker 下文件的備份,跳過...${NC}" fi @@ -7103,66 +7104,66 @@ docker_ssh_migration() { # ---------------------------- - # 迁移 + # 遷移 # ---------------------------- migrate_docker() { - send_stats "Docker迁移" + send_stats "Docker遷移" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + read -p "請輸入要遷移的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -p "目標服務器IP:" TARGET_IP + read -p "目標服務器SSH用戶名:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${YELLOW}傳輸備份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密钥登录 + # 使用密鑰登錄 scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 删除备份 + # 刪除備份 # ---------------------------- delete_backup() { - send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + send_stats "Docker備份文件刪除" + read -p "請輸入要刪除的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${GREEN}已刪除備份:${BACKUP_DIR}${NC}" } # ---------------------------- - # 主菜单 + # 主菜單 # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "Docker備份遷移還原" while true; do clear echo "------------------------" - echo -e "Docker备份/迁移/还原工具" + echo -e "Docker備份/遷移/還原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" - echo -e "2. 迁移docker项目" - echo -e "3. 还原docker项目" - echo -e "4. 删除docker项目的备份文件" + echo -e "1. 備份docker項目" + echo -e "2. 遷移docker項目" + echo -e "3. 還原docker項目" + echo -e "4. 刪除docker項目的備份文件" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0. 返回上一級菜單" echo "------------------------" - read -p "请选择: " choice + read -p "請選擇:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${RED}無效選項${NC}" ;; esac break_end done @@ -7183,34 +7184,34 @@ linux_docker() { echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安裝更新Docker環境${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局狀態${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker鏡像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker網絡管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker捲管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和鏡像網絡數據卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}更換Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}編輯daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" + echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" + echo -e "${gl_kjlan}20. ${gl_bai}卸載Docker環境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "安裝docker環境" install_add_docker ;; @@ -7221,22 +7222,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" + send_stats "docker全局狀態" echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "Docker鏡像:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Docker網絡:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7251,8 +7252,8 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "Docker網絡管理" + echo "Docker網絡列表" echo "------------------------------------------------------------" docker network ls echo "" @@ -7276,36 +7277,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "網絡操作" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1. 創建網絡" + echo "2. 加入網絡" + echo "3. 退出網絡" + echo "4. 刪除網絡" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "創建網絡" + read -e -p "設置新網絡名:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "加入網絡" + read -e -p "加入網絡名:" dockernetwork + read -e -p "那些容器加入該網絡(多個容器名請用空格分隔):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "加入網絡" + read -e -p "退出網絡名:" dockernetwork + read -e -p "那些容器退出該網絡(多個容器名請用空格分隔):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7314,8 +7315,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "刪除網絡" + read -e -p "請輸入要刪除的網絡名:" dockernetwork docker network rm $dockernetwork ;; @@ -7329,29 +7330,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" + send_stats "Docker捲管理" echo "Docker卷列表" docker volume ls echo "" echo "卷操作" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1. 創建新卷" + echo "2. 刪除指定卷" + echo "3. 刪除所有捲" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + read -e -p "設置新卷名:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "輸入刪除卷名(多個卷名請用空格分隔):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7360,7 +7361,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "刪除所有捲" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7369,7 +7370,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -7391,7 +7392,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -7413,13 +7414,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "Docker v6 開" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "Docker v6 關" docker_ipv6_off ;; @@ -7430,7 +7431,7 @@ linux_docker() { 20) clear - send_stats "Docker卸载" + send_stats "Docker卸載" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7442,7 +7443,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -7451,7 +7452,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -7468,151 +7469,151 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats "測試腳本合集" + echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解鎖狀態檢測" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態檢測" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒體解鎖測試" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒體解鎖檢測" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP質量體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}網絡線路測速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三網線路測試" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網絡質量體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}硬件性能測試" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能測試" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能測試腳本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}綜合性測試" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能測試" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪測評${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "ChatGPT解鎖狀態檢測" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "Region流媒體解鎖測試" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "yeahwu流媒體解鎖檢測" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "xykt_IP質量體檢腳本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "besttrace三網回程延遲路由測試" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "mtr_trace三網回程線路測試" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "Superspeed三網測速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace快速回程測試腳本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "nxtrace指定IP回程測試腳本" + echo "可參考的IP列表" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "北京電信: 219.141.136.12" + echo "北京聯通: 202.106.50.1" + echo "北京移動: 221.179.155.161" + echo "上海電信: 202.96.209.133" + echo "上海聯通: 210.22.97.1" + echo "上海移動: 211.136.112.200" + echo "廣州電信: 58.60.188.222" + echo "廣州聯通: 210.21.196.6" + echo "廣州移動: 120.196.165.24" + echo "成都電信: 61.139.2.69" + echo "成都聯通: 119.6.6.6" + echo "成都移動: 211.137.96.205" + echo "湖南電信: 36.111.200.100" + echo "湖南聯通: 42.48.16.100" + echo "湖南移動: 39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "輸入一個指定IP:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "ludashi2020三網線路測試" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "i-abc多功能測速腳本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "網絡質量測試腳本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "yabs性能測試" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "icu/gb5 CPU性能測試腳本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "bench性能測試" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "spiritysdx融合怪測評" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7622,7 +7623,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -7638,51 +7639,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "甲骨文云腳本合集" + echo -e "甲骨文云腳本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}安裝閒置機器活躍腳本" + echo -e "${gl_kjlan}2. ${gl_bai}卸載閒置機器活躍腳本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD重裝系統腳本" + echo -e "${gl_kjlan}4. ${gl_bai}R探長開機腳本" + echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登錄模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢復工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "活躍腳本: CPU佔用10-20% 內存佔用20%" + read -e -p "確定安裝嗎? (Y/N):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # 設置默認值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # 提示用戶輸入CPU核心數和占用百分比,如果回車則使用默認值 + read -e -p "請輸入CPU核心數 [默認:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [默認:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "請輸入內存佔用百分比 [默認:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "請輸入Speedtest間隔時間(秒) [默認:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # 運行Docker容器 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7690,14 +7691,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "甲骨文云安裝活躍腳本" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -7705,20 +7706,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "甲骨文云卸載活躍腳本" ;; 3) clear - echo "重装系统" + echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" + read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice case "$sys_choice" in 1) @@ -7730,28 +7731,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "無效的選擇,請重新輸入。" ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "請輸入你重裝後的密碼:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "甲骨文云重裝系統腳本" ;; [Nn]) echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; 4) clear - echo "该功能处于开发阶段,敬请期待!" + echo "該功能處於開發階段,敬請期待!" ;; 5) clear @@ -7761,15 +7762,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "該功能由jhb大神提供,感謝他!" + send_stats "ipv6修復" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -7790,7 +7791,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境已經安裝${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡像:${gl_lv}$image_count${gl_bai}網絡:${gl_lv}$network_count${gl_bai}卷:${gl_lv}$volume_count${gl_bai}" fi } @@ -7811,7 +7812,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}環境已安裝${gl_bai}站點:$output資料庫:$db_output" fi fi @@ -7843,27 +7844,27 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" + echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量博客網站" + echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack共享鏈接平台${gl_huang}20. ${gl_bai}自定義動態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站點重定向" + echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo博客網站" + echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞生成器${gl_huang}28. ${gl_bai}站點反向代理-負載均衡" + echo -e "${gl_huang}30. ${gl_bai}自定義靜態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}站點數據管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" + echo -e "${gl_huang}33. ${gl_bai}定時遠程備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸載LDNMP環境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}返回主菜單" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -7877,10 +7878,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # Discuz論壇 webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7903,11 +7904,11 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "數據庫地址: mysql" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "表前綴: discuz_" ;; @@ -7916,8 +7917,8 @@ linux_ldnmp() { clear # 可道云桌面 webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7939,20 +7940,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "數據庫地址: mysql" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "數據庫名:$dbname" + echo "redis主機: redis" ;; 5) clear - # 苹果CMS + # 蘋果CMS webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7978,24 +7979,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "數據庫地址: mysql" + echo "數據庫端口: 3306" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "數據庫前綴: mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "安裝成功後登錄後台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 + # 獨腳數卡 webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8016,34 +8017,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "數據庫地址: mysql" + echo "數據庫端口: 3306" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" echo "" echo "redis地址: redis" - echo "redis密码: 默认不填写" + echo "redis密碼: 默認不填寫" echo "redis端口: 6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "網站url: https://$yuming" + echo "後台登錄路徑: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "用戶名: admin" + echo "密碼: admin" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "登錄時右上角如果出現紅色error0請使用如下命令:" + echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 + # flarum論壇 webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8080,12 +8081,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "數據庫地址: mysql" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "表前綴: flarum_" + echo "管理員信息自行設置" ;; @@ -8093,8 +8094,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8118,11 +8119,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "數據庫前綴: typecho_" + echo "數據庫地址: mysql" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "數據庫名:$dbname" ;; @@ -8131,8 +8132,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8157,18 +8158,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "數據庫地址: mysql" + echo "數據庫端口: 3306" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" ;; 20) clear webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8185,10 +8186,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP源碼" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" + read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8198,20 +8199,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路徑" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "請輸入index.php的路徑,類似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] 請選擇PHP版本" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. php最新版 | 2. php7.4 :" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8222,15 +8223,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "無效的選擇,請重新輸入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}] 安裝指定擴展" echo "-------------" - echo "已经安装的扩展" + echo "已經安裝的擴展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8240,25 +8241,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}] 編輯站點配置" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "按任意鍵繼續,可以詳細設置站點配置,如偽靜態等內容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}] 數據庫管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有數據庫備份:" use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "數據庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支持寶塔/1panel備份數據導入。" + read -e -p "也可以輸入下載鏈接,遠程下載備份數據,直接回車將跳過遠程下載:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8268,10 +8269,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "數據庫導入的表數據" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "數據庫導入完成" ;; *) echo @@ -8283,12 +8284,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "數據庫地址: mysql" + echo "數據庫名:$dbname" + echo "使用者名稱:$dbuse" + echo "密碼:$dbusepasswd" + echo "表前綴:$prefix" + echo "管理員登錄信息自行設置" ;; @@ -8301,10 +8302,10 @@ linux_ldnmp() { 22) clear webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "請輸入跳轉域名:" reverseproxy nginx_install_status install_ssltls certs_status @@ -8326,7 +8327,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "已阻止IP+端口訪問該服務" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8337,11 +8338,11 @@ linux_ldnmp() { 24) clear webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "域名格式:${gl_huang}google.com${gl_bai}" + read -e -p "請輸入你的反代域名:" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8361,8 +8362,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming nginx_install_status install_ssltls @@ -8384,8 +8385,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming nginx_install_status install_ssltls @@ -8402,8 +8403,8 @@ linux_ldnmp() { 27) clear webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming nginx_install_status install_ssltls @@ -8436,8 +8437,8 @@ linux_ldnmp() { 30) clear webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "安裝$webname" + echo "開始部署$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8454,10 +8455,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態源碼" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" + read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8467,12 +8468,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路徑" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "請輸入index.html的路徑,類似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8497,21 +8498,21 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境備份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "備份文件已創建: /home/$backup_filename" + read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "請輸入遠端服務器IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "錯誤: 請輸入遠端服務器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8519,9 +8520,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "文件已傳送至遠程服務器home目錄。" else - echo "未找到要传送的文件。" + echo "未找到要傳送的文件。" fi break ;; @@ -8529,7 +8530,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac done @@ -8537,9 +8538,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "定時遠程備份" + read -e -p "輸入遠程服務器IP:" useip + read -e -p "輸入遠程服務器密碼:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8549,18 +8550,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1. 每周備份 2. 每天備份" + read -e -p "請輸入你的選擇:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "選擇每周備份的星期幾 (0-6,0代表星期日):" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "選擇每天備份的時間(小時,0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8574,19 +8575,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP環境還原" + echo "可用的站點備份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 如果用戶沒有輸入文件名,使用最新的壓縮包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8596,7 +8597,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8605,7 +8606,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "沒有找到壓縮包。" fi ;; @@ -8623,11 +8624,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "更新LDNMP環境" + echo "更新LDNMP環境" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "發現新版本的組件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8649,11 +8650,11 @@ linux_ldnmp() { echo echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. 更新完整环境" + echo "5. 更新完整環境" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8662,7 +8663,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "請輸入${ldnmp_pods}版本號 (如: 8.0 8.3 8.4 9.0)(回車獲取最新版):" version local version=${version:-latest} cd /home/web/ @@ -8679,7 +8680,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車獲取最新版):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8732,7 +8733,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "完整更新LDNMP環境" cd /home/web/ docker compose down --rmi all @@ -8758,7 +8759,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "卸載LDNMP環境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8772,7 +8773,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -8782,7 +8783,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "無效的輸入!" esac break_end @@ -8802,12 +8803,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "應用市場" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # 用循環設置顏色 for i in {1..100}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8816,70 +8817,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}寶塔面板官方版${gl_kjlan}2. ${color2}aaPanel寶塔國際版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager可視化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存儲文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠程桌面網頁版" + echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件服務器程序${gl_kjlan}10. ${color10}RocketChat多人在線聊天系統" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}禪道項目管理軟件${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟件${gl_kjlan}18. ${color18}onlyoffice在線辦公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" + echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud網盤${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆棧管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相冊系統" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播錄製工具${gl_kjlan}40. ${color40}webssh網頁版SSH連接工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠程連接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" + echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}在線翻譯服務器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp視頻下載工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL證書管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂服務器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" + echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}在線DOS老遊戲" + echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" + echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" + echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" + echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台" + echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice fi case $sub_choice in @@ -9032,8 +9033,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9075,9 +9076,9 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒監控$check_docker $update_status" + echo "開源、輕量、易用的服務器監控與運維工具" + echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip @@ -9086,9 +9087,9 @@ while true; do echo "------------------------" echo "1. 使用" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) @@ -9145,7 +9146,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "搭建郵局" clear install telnet local app_id="9" @@ -9155,43 +9156,43 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "郵局服務$check_docker $update_status" + echo "poste.io 是一個開源的郵件服務器解決方案," + echo "視頻介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "端口检测" + echo "端口檢測" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}端口$port當前可用${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}端口$port當前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "訪問地址:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) check_disk_space 2 - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "先解析這些DNS記錄" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9201,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "按任意鍵繼續..." read -n 1 -s -r -p "" install jq @@ -9220,9 +9221,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "poste.io已經安裝完成" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "您可以使用以下地址訪問poste.io:" echo "https://$yuming" echo "" @@ -9245,9 +9246,9 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "poste.io已经安装完成" + echo "poste.io已經安裝完成" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "您可以使用以下地址訪問poste.io:" echo "https://$yuming" echo "" ;; @@ -9258,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "應用已卸載" ;; *) @@ -9292,7 +9293,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -9302,7 +9303,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "rocket.chat已經安裝完成" check_docker_app_ip } @@ -9312,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -9396,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -9410,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -9563,20 +9564,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服務$check_docker" + echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" + echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1. 安裝 2. 更新 3. 重置密碼 4. 卸載" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) @@ -9586,7 +9587,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经安装完成" + echo "雷池WAF面板已經安裝完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9599,7 +9600,7 @@ while true; do mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) clear - echo "雷池WAF面板已经更新完成" + echo "雷池WAF面板已經更新完成" check_docker_app_ip ;; 3) @@ -9610,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9729,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10018,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10275,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "初始用戶名密碼均為: admin" } docker_app_update() { @@ -10295,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -10382,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVE開小雞" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10502,7 +10503,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -10517,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -10545,7 +10546,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -10560,7 +10561,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -10568,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -10589,17 +10590,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "初始用戶名: admin" + echo "初始密碼: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "應用已更新" } @@ -10609,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -10656,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -10672,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -10934,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "設置LibreTV的登錄密碼:" app_passwd docker run -d \ --name libretv \ @@ -10968,9 +10969,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password - read -e -p "输入授权码: " shouquanma + read -e -p "設置登錄用戶名:" admin + read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "輸入授權碼:" shouquanma mkdir -p /home/docker/moontv @@ -10986,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -11000,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11073,8 +11074,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "設置登錄用戶名:" app_use + read -e -p "設置登錄密碼:" app_passwd docker run -d \ --name xunlei \ @@ -11171,11 +11172,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 下載官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # 生成隨機密鑰與密碼 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11184,17 +11185,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 追加管理員賬號信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # 啟動容器 docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -11204,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 保留原本的變量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11221,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11271,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11289,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "設定${docker_name}的登錄密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11393,7 +11394,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -11406,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11567,7 +11568,7 @@ while true; do --restart unless-stopped \ matrixdotorg/synapse:latest - echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + echo "創建初始用戶或管理員。請設置以下內容用戶名和密碼以及是否為管理員。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11619,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -11633,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11708,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "設置登錄用戶名:" app_use + read -e -p "設置登錄密碼:" app_passwd docker run -d \ --name ${docker_name} \ @@ -11757,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "已经安装完成" + echo "已經安裝完成" check_docker_app_ip } @@ -11771,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "应用已卸载" + echo "應用已卸載" } docker_app_plus @@ -11788,12 +11789,12 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -p "請輸入組網的客戶端數量 (默認 5):" COUNT COUNT=${COUNT:-5} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - - stop_containers_or_kill_process 51820 &>/dev/null + + ip link delete wg0 &>/dev/null ip_address docker run -d \ @@ -11833,7 +11834,7 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" + echo "生成二維碼:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' @@ -11843,11 +11844,11 @@ while true; do sleep 2 docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" - echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可以快速連接網絡${gl_bai}" + echo -e "${gl_lv}2. Windows下載客戶端,複製配置代碼連接網絡。${gl_bai}" + echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製配置代碼連接網絡。${gl_bai}" + echo -e "${gl_lv}官方客戶端下載方式: https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11875,16 +11876,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # 創建目錄(如果不存在) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "请粘贴你的客户端配置,连续按两次回车保存:" + echo "請粘貼你的客戶端配置,連續按兩次回車保存:" - # 初始化变量 + # 初始化變量 input="" empty_line_count=0 - # 逐行读取用户输入 + # 逐行讀取用戶輸入 while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -11897,10 +11898,10 @@ while true; do fi done - # 写入配置文件 + # 寫入配置文件 echo "$input" > "$CONFIG_FILE" - echo "客户端配置已保存到 $CONFIG_FILE" + echo "客戶端配置已保存到$CONFIG_FILE" docker run -d \ --name wireguardc \ @@ -11933,21 +11934,21 @@ while true; do b) clear - send_stats "全部应用备份" + send_stats "全部應用備份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "備份文件已創建: /$backup_filename" + read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "請輸入遠端服務器IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" + echo "錯誤: 請輸入遠端服務器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -11955,14 +11956,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "文件已傳送至遠程服務器/根目錄。" else - echo "未找到要传送的文件。" + echo "未找到要傳送的文件。" fi break ;; *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + echo "注意: 目前備份僅包含docker項目,不包含寶塔,1panel等建站面板的數據備份。" break ;; esac @@ -11972,29 +11973,29 @@ while true; do r) root_use - send_stats "全部应用还原" - echo "可用的应用备份" + send_stats "全部應用還原" + echo "可用的應用備份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 如果用戶沒有輸入文件名,使用最新的壓縮包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "應用數據已還原,目前請手動進入指定應用菜單,更新應用,即可還原應用。" else - echo "没有找到压缩包。" + echo "沒有找到壓縮包。" fi ;; @@ -12017,35 +12018,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "後台工作區" + echo -e "後台工作區" + echo -e "系統將為你提供可以後台常駐運行的工作區,你可以用來執行長時間的任務" + echo -e "即使你斷開SSH,工作區中的任務也不會中斷,後台常駐任務。" + echo -e "${gl_huang}提示:${gl_bai}進入工作區後使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "當前已存在的工作區列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}1號工作區" + echo -e "${gl_kjlan}2. ${gl_bai}2號工作區" + echo -e "${gl_kjlan}3. ${gl_bai}3號工作區" + echo -e "${gl_kjlan}4. ${gl_bai}4號工作區" + echo -e "${gl_kjlan}5. ${gl_bai}5號工作區" + echo -e "${gl_kjlan}6. ${gl_bai}6號工作區" + echo -e "${gl_kjlan}7. ${gl_bai}7號工作區" + echo -e "${gl_kjlan}8. ${gl_bai}8號工作區" + echo -e "${gl_kjlan}9. ${gl_bai}9號工作區" + echo -e "${gl_kjlan}10. ${gl_bai}10號工作區" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐模式${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}創建/進入工作區" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到後台工作區" + echo -e "${gl_kjlan}24. ${gl_bai}刪除指定工作區" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -12053,7 +12054,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; @@ -12061,63 +12062,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "啟動工作區$SESSION_NAME" tmux_run ;; @@ -12129,21 +12130,21 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH常駐模式" + echo -e "SSH常駐模式${tmux_sshd_status}" + echo "開啟後SSH連接後會直接進入常駐模式,直接回到之前的工作狀態。" echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 開啟 2. 關閉" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "請輸入你的選擇:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "啟動工作區$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自動進入 tmux 會話\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12159,29 +12160,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "請輸入你創建或進入的工作區名稱,如1​​001 kj001 work1:" SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "自定義工作區" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "請輸入你要後台執行的命令,如:curl -fsSL https://get.docker.com | sh:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "注入命令到後台工作區" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "請輸入要刪除的工作區名稱:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "刪除工作區" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -12206,54 +12207,54 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats "系統工具" + echo -e "系統工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}設置腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登錄密碼" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT密碼登錄模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}開放所有端口${gl_kjlan}6. ${gl_bai}修改SSH連接端口" + echo -e "${gl_kjlan}7. ${gl_bai}優化DNS地址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT賬戶創建新賬戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用狀態${gl_kjlan}12. ${gl_bai}修改虛擬內存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用戶管理${gl_kjlan}14. ${gl_bai}用戶/密碼生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火牆高級管理器${gl_kjlan}18. ${gl_bai}修改主機名" + echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}ROOT私鑰登錄模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux內核升級${gl_kjlan}28. ${gl_bai}Linux系統內核參數優化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令行美化工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}設置系統回收站${gl_kjlan}34. ${gl_bai}系統備份與恢復" + echo -e "${gl_kjlan}35. ${gl_bai}ssh遠程連接工具${gl_kjlan}36. ${gl_bai}硬盤分區管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}41. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重啟服務器${gl_kjlan}100. ${gl_bai}隱私與安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高級用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸載科技lion腳本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "請輸入你的快捷按鍵(輸入0退出):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "快捷鍵已設置" + send_stats "腳本快捷鍵已設置" break_end linux_Settings done @@ -12261,13 +12262,13 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "設置你的登錄密碼" + echo "設置你的登錄密碼" passwd ;; 3) root_use - send_stats "root密码模式" + send_stats "root密碼模式" add_sshpasswd ;; @@ -12275,20 +12276,20 @@ linux_Settings() { root_use send_stats "py版本管理" echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + echo "視頻介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "該功能可無縫安裝python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查詢更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "輸入你要安裝的python版本號(輸入0退出):" py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "腳本PY管理" break_end linux_Settings fi @@ -12350,17 +12351,17 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" + send_stats "腳本PY版本切換" ;; 5) root_use - send_stats "开放端口" + send_stats "開放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "端口已全部開放" ;; 6) @@ -12371,19 +12372,19 @@ EOF clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 讀取當前的 SSH 端口號 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 打印當前的 SSH 端口號 + echo -e "當前的 SSH 端口號是:${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "端口號範圍1到65535之間的數字。 (輸入0退出)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 提示用戶輸入新的 SSH 端口號 + read -e -p "請輸入新的 SSH 端口號:" new_port - # 判断端口号是否在有效范围内 + # 判斷端口號是否在有效範圍內 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH端口已修改" @@ -12392,13 +12393,13 @@ EOF send_stats "退出SSH端口修改" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "端口號無效,請輸入1到65535之間的數字。" + send_stats "輸入無效SSH端口" break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "輸入無效,請輸入數字。" + send_stats "輸入無效SSH端口" break_end fi done @@ -12417,8 +12418,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "新用戶禁用root" + read -e -p "請輸入新用戶名(輸入0退出):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12439,43 +12440,43 @@ EOF 10) root_use - send_stats "设置v4/v6优先级" + send_stats "設置v4/v6優先級" while true; do clear - echo "设置v4/v6优先级" + echo "設置v4/v6優先級" echo "------------------------" local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) if [ "$ipv6_disabled" -eq 1 ]; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "當前網絡優先級設置:${gl_huang}IPv4${gl_bai}優先" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "當前網絡優先級設置:${gl_huang}IPv6${gl_bai}優先" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 優先 2. IPv6 優先 3. IPv6 修復工具" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "選擇優先的網絡:" choice case $choice in 1) sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + echo "已切換為 IPv4 優先" + send_stats "已切換為 IPv4 優先" ;; 2) sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "已切換為 IPv6 優先" + send_stats "已切換為 IPv6 優先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "該功能由jhb大神提供,感謝他!" + send_stats "ipv6修復" ;; *) @@ -12493,43 +12494,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "設置虛擬內存" while true; do clear - echo "设置虚拟内存" + echo "設置虛擬內存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "當前虛擬內存:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定義大小" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "請輸入你的選擇:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "已設置1G虛擬內存" add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "已設置2G虛擬內存" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "已設置4G虛擬內存" add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "請輸入虛擬內存大小(單位M):" new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "已設置自定義虛擬內存" ;; *) @@ -12542,8 +12543,8 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "用戶管理" + echo "用戶列表" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12554,24 +12555,24 @@ EOF echo "" - echo "账户操作" + echo "賬戶操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 創建普通賬戶 2. 創建高級賬戶" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" - echo "5. 删除账号" + echo "5. 刪除賬號" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 提示用戶輸入新用戶名 + read -e -p "請輸入新用戶名:" new_username - # 创建新用户并设置密码 + # 創建新用戶並設置密碼 useradd -m -s /bin/bash "$new_username" passwd "$new_username" @@ -12579,14 +12580,14 @@ EOF ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 提示用戶輸入新用戶名 + read -e -p "請輸入新用戶名:" new_username - # 创建新用户并设置密码 + # 創建新用戶並設置密碼 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 赋予新用户sudo权限 + # 賦予新用戶sudo權限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12595,21 +12596,21 @@ EOF ;; 3) - read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 + read -e -p "請輸入用戶名:" username + # 賦予新用戶sudo權限 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "请输入用户名: " username - # 从sudoers文件中移除用户的sudo权限 + read -e -p "請輸入用戶名:" username + # 從sudoers文件中移除用戶的sudo權限 sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 + read -e -p "請輸入要刪除的用戶名:" username + # 刪除用戶及其主目錄 userdel -r "$username" ;; @@ -12622,50 +12623,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "用戶信息生成器" + echo "隨機用戶名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "隨機用戶名$i: $username" done echo "" - echo "随机姓名" + echo "隨機姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 生成5個隨機用戶姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "隨機用戶姓名$i: $user_name" done echo "" - echo "随机UUID" + echo "隨機UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "隨機UUID$i: $uuid" done echo "" - echo "16位随机密码" + echo "16位隨機密碼" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "隨機密碼$i: $password" done echo "" - echo "32位随机密码" + echo "32位隨機密碼" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "隨機密碼$i: $password" done echo "" @@ -12673,46 +12674,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "換時區" while true; do clear - echo "系统时间信息" + echo "系統時間信息" - # 获取当前系统时区 + # 獲取當前系統時區 local timezone=$(current_timezone) - # 获取当前系统时间 + # 獲取當前系統時間 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # 顯示時區和時間 + echo "當前系統時區:$timezone" + echo "當前系統時間:$current_time" echo "" - echo "时区切换" + echo "時區切換" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "亞洲" + echo "1. 中國上海時間 2. 中國香港時間" + echo "3. 日本東京時間 4. 韓國首爾時間" + echo "5. 新加坡時間 6. 印度加爾各答時間" + echo "7. 阿聯酋迪拜時間 8. 澳大利亞悉尼時間" + echo "9. 泰國曼谷時間" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "歐洲" + echo "11. 英國倫敦時間 12. 法國巴黎時間" + echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" + echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" echo "------------------------" echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "21. 美國西部時間 22. 美國東部時間" + echo "23. 加拿大時間 24. 墨西哥時間" + echo "25. 巴西時間 26. 阿根廷時間" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC全球標準時間" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -12755,21 +12756,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "修改主機名" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "當前主機名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "請輸入新的主機名(輸入0退出):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # 其他系統,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -12787,11 +12788,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "主機名已更改為:$new_hostname" + send_stats "主機名已更改" sleep 1 else - echo "已退出,未更改主机名。" + echo "已退出,未更改主機名。" break fi done @@ -12799,24 +12800,24 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "換系統更新源" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "選擇更新源區域" + echo "接入LinuxMirrors切換系統更新源" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "輸入你的選擇:" choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "中國大陸默認源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "中國大陸教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) @@ -12832,62 +12833,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "定時任務管理" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "定時任務列表" crontab -l echo "" echo "操作" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 添加定時任務 2. 刪除定時任務 3. 編輯定時任務" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "請輸入新任務的執行命令:" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. 每月任務 2. 每週任務" + echo "3. 每天任務 4. 每小時任務" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "請輸入你的選擇:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "選擇每月的幾號執行任務? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "選擇週幾執行任務? (0-6,0代表星期日):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "選擇每天幾點執行任務? (小時,0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "輸入每小時的第幾分鐘執行任務? (分鐘,0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "添加定時任務" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "請輸入需要刪除任務的關鍵字:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "刪除定時任務" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "編輯定時任務" ;; *) break # 跳出循环,退出菜单 @@ -12902,29 +12903,29 @@ EOF send_stats "本地host解析" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "本機host解析列表" + echo "如果你在這裡添加解析匹配,將不再使用動態解析了" cat /etc/hosts echo "" echo "操作" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 添加新的解析 2. 刪除解析地址" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "請輸入你的選擇:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "請輸入新的解析記錄 格式: 110.25.5.33 kejilion.pro :" addhost echo "$addhost" >> /etc/hosts send_stats "本地host解析新增" ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "請輸入需要刪除的解析內容關鍵字:" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "本地host解析刪除" ;; *) break # 跳出循环,退出菜单 @@ -12935,7 +12936,7 @@ EOF 22) root_use - send_stats "ssh防御" + send_stats "ssh防禦" while true; do if [ -x "$(command -v fail2ban-client)" ] ; then clear @@ -12947,20 +12948,20 @@ EOF docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 docker_name="fail2ban" check_docker_app - echo -e "SSH防御程序 $check_docker" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防禦程序$check_docker" + echo "fail2ban是一個SSH防止暴力破解工具" + echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 安裝防禦程序" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. 查看SSH攔截記錄" + echo "3. 日誌實時監控" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 卸載防禦程序" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) install_docker @@ -12983,7 +12984,7 @@ EOF 9) docker rm -f fail2ban rm -rf /path/to/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防禦程序已卸載" ;; *) break @@ -12996,47 +12997,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "限流關機功能" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "限流關機功能" + echo "視頻介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "當前流量使用情況,重啟服務器流量計算會清零!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}總接收:${gl_bai}$rx" + echo -e "${gl_kjlan}總發送:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # 檢查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # 獲取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}當前設置的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}當前設置的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}當前未啟用限流關機功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "系統每分鐘會檢測實際流量是否到達閾值,到達後會自動關閉服務器!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. 開啟限流關機功能 2. 停用限流關機功能" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "請輸入你的選擇:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 輸入新的虛擬內存大小 + echo "如果實際服務器就100G流量,可設置閾值為95G,提前關機,以免出現流量誤差或溢出。" + read -e -p "請輸入進站流量閾值(單位為G,默認100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "請輸入出站流量閾值(單位為G,默認100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "請輸入流量重置日期(默認每月1日重置):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13049,15 +13050,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "限流關機已設置" + send_stats "限流關機已設置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "已關閉限流關機功能" ;; *) break @@ -13070,40 +13071,40 @@ EOF 24) root_use - send_stats "私钥登录" + send_stats "私鑰登錄" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "ROOT私鑰登錄模式" + echo "視頻介紹: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "將會生成密鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 生成新密鑰 2. 導入已有密鑰 3. 查看本機密鑰" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "請輸入你的選擇:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "生成新密鑰" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "導入已有公鑰" import_sshkey break_end ;; 3) - send_stats "查看本机密钥" + send_stats "查看本機密鑰" echo "------------------------" - echo "公钥信息" + echo "公鑰信息" cat ~/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "私鑰信息" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -13119,18 +13120,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "電報預警" + echo "TG-bot監控預警功能" + echo "視頻介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "您需要配置tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬盤,流量,SSH登錄的實時監控預警" + echo "到達閾值後會向用戶發預警消息" + echo -e "${gl_hui}-關於流量,重啟服務器將重新計算-${gl_bai}" + read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "電報預警啟用" cd ~ install nano tmux bc jq check_crontab_installed @@ -13163,21 +13164,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-bot預警系統已啟動" + echo -e "${gl_hui}你還可以將root目錄中的TG-check-notify.sh預警文件放到其他機器上直接使用!${gl_bai}" ;; [Nn]) echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "修復SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13221,7 +13222,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "命令行歷史記錄" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -13245,60 +13246,60 @@ EOF 41) clear send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" + echo "科技lion留言板已遷移至官方社區!請在官方社區進行留言噢!" echo "https://bbs.kejilion.pro/" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "一條龍調優" + echo "一條龍系統調優" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo "將對以下內容進行操作與優化" + echo "1. 更新系統到最新" + echo "2. 清理系統垃圾文件" + echo -e "3. 設置虛擬內存${gl_huang}1G${gl_bai}" + echo -e "4. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo -e "5. 開放所有端口" + echo -e "6. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "7. 設置時區到${gl_huang}上海${gl_bai}" + echo -e "8. 自動優化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" + echo -e "9. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "10. Linux系統內核參數優化切換到${gl_huang}均衡優化模式${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "確定一鍵保養嗎? (Y/N):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "一條龍調優啟動" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系統到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系統垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 設置虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. 設置SSH端口號為${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 開放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 開啟${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 設置時區到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13315,25 +13316,25 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自動優化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系統內核參數優化" + echo -e "${gl_lv}一條龍系統調優已完成${gl_bai}" ;; [Nn]) echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac @@ -13341,7 +13342,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "重啟系統" server_reboot ;; 100) @@ -13357,32 +13358,32 @@ EOF local status_message="无法确定的状态" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "隱私與安全" + echo "腳本將收集用戶使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" + echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "當前狀態:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. 開啟採集" + echo "2. 關閉採集" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "已開啟採集" + send_stats "隱私與安全已開啟採集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "已關閉採集" + send_stats "隱私與安全已關閉採集" ;; *) break @@ -13398,11 +13399,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "卸載科技lion腳本" + echo "卸載科技lion腳本" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "將徹底卸載kejilion腳本,不影響你其他功能" + read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) @@ -13410,7 +13411,7 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "腳本已卸載,再見!" break_end clear exit @@ -13419,7 +13420,7 @@ EOF echo "已取消" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -13429,7 +13430,7 @@ EOF ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -13452,182 +13453,182 @@ linux_file() { clear echo "文件管理器" echo "------------------------" - echo "当前路径" + echo "當前路徑" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. 進入目錄 2. 創建目錄 3. 修改目錄權限 4. 重命名目錄" + echo "5. 刪除目錄 6. 返回上一級選單目錄" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. 創建文件 12. 編輯文件 13. 修改文件權限 14. 重命名文件" + echo "15. 刪除文件" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. 壓縮文件目錄 22. 解壓文件目錄 23. 移動文件目錄 24. 複製文件目錄" + echo "25. 傳文件至其他服務器" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "請輸入你的選擇:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "請輸入目錄名:" dirname + cd "$dirname" 2>/dev/null || echo "無法進入目錄" + send_stats "進入目錄" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "請輸入要創建的目錄名:" dirname + mkdir -p "$dirname" && echo "目錄已創建" || echo "創建失敗" + send_stats "創建目錄" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "請輸入目錄名:" dirname + read -e -p "請輸入權限 (如 755):" perm + chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" + send_stats "修改目錄權限" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "請輸入當前目錄名:" current_name + read -e -p "請輸入新目錄名:" new_name + mv "$current_name" "$new_name" && echo "目錄已重命名" || echo "重命名失敗" + send_stats "重命名目錄" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "請輸入要刪除的目錄名:" dirname + rm -rf "$dirname" && echo "目錄已刪除" || echo "刪除失敗" + send_stats "刪除目錄" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "返回上一級選單目錄" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "請輸入要創建的文件名:" filename + touch "$filename" && echo "文件已創建" || echo "創建失敗" + send_stats "創建文件" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "請輸入要編輯的文件名:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "編輯文件" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "請輸入文件名:" filename + read -e -p "請輸入權限 (如 755):" perm + chmod "$perm" "$filename" && echo "權限已修改" || echo "修改失敗" + send_stats "修改文件權限" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + read -e -p "請輸入當前文件名:" current_name + read -e -p "請輸入新文件名:" new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失敗" send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "請輸入要刪除的文件名:" filename + rm -f "$filename" && echo "文件已刪除" || echo "刪除失敗" + send_stats "刪除文件" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "請輸入要壓縮的文件/目錄名:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "壓縮失敗" + send_stats "壓縮文件/目錄" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "請輸入要解壓的文件名 (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "已解壓$filename" || echo "解壓失敗" + send_stats "解壓文件/目錄" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "請輸入要移動的文件或目錄路徑:" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "錯誤: 文件或目錄不存在。" + send_stats "移動文件或目錄失敗: 文件或目錄不存在" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "錯誤: 請輸入目標路徑。" + send_stats "移動文件或目錄失敗: 目標路徑未指定" continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "文件或目錄已移動到$dest_path" || echo "移動文件或目錄失敗" + send_stats "移動文件或目錄" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "請輸入要復制的文件或目錄路徑:" src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "錯誤: 文件或目錄不存在。" + send_stats "複製文件或目錄失敗: 文件或目錄不存在" continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "錯誤: 請輸入目標路徑。" + send_stats "複製文件或目錄失敗: 目標路徑未指定" continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # 使用 -r 選項以遞歸方式複制目錄 + cp -r "$src_path" "$dest_path" && echo "文件或目錄已復製到$dest_path" || echo "複製文件或目錄失敗" + send_stats "複製文件或目錄" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "請輸入要傳送的文件路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "錯誤: 文件不存在。" + send_stats "傳送文件失敗: 文件不存在" continue fi - read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "請輸入遠端服務器IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" + echo "錯誤: 請輸入遠端服務器IP。" + send_stats "傳送文件失敗: 未輸入遠端服務器IP" continue fi - read -e -p "请输入远端服务器用户名 (默认root): " remote_user + read -e -p "請輸入遠端服務器用戶名 (默認root):" remote_user remote_user=${remote_user:-root} - read -e -p "请输入远端服务器密码: " -s remote_password + read -e -p "請輸入遠端服務器密碼:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" + echo "錯誤: 請輸入遠端服務器密碼。" + send_stats "傳送文件失敗: 未輸入遠端服務器密碼" continue fi - read -e -p "请输入登录端口 (默认22): " remote_port + read -e -p "請輸入登錄端口 (默認22):" remote_port remote_port=${remote_port:-22} - # 清除已知主机的旧条目 + # 清除已知主機的舊條目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # 使用scp傳輸文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "腳本已經最新$sh_v_new" break_end ~/kejilion.sh exit @@ -13925,15 +13926,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}自動更新已開啟,每天凌晨2點腳本會自動更新!${gl_bai}" + send_stats "開啟腳本自動更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}自動更新已關閉${gl_bai}" + send_stats "關閉腳本自動更新" break_end ;; *) @@ -13955,37 +13956,37 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "科技lion腳本工具箱 v$sh_v" +echo -e "命令行輸入${gl_huang}k${gl_kjlan}可快速啟動腳本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}1. ${gl_bai}系統信息查詢" +echo -e "${gl_kjlan}2. ${gl_bai}系統更新" +echo -e "${gl_kjlan}3. ${gl_bai}系統清理" +echo -e "${gl_kjlan}4. ${gl_bai}基礎工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_kjlan}8. ${gl_bai}測試腳本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云腳本合集" echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}11. ${gl_bai}應用市場" +echo -e "${gl_kjlan}12. ${gl_bai}後台工作區" +echo -e "${gl_kjlan}13. ${gl_bai}系統工具" +echo -e "${gl_kjlan}14. ${gl_bai}服務器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}廣告專欄" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}p. ${gl_bai}幻獸帕魯開服腳本" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}腳本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}退出腳本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "請輸入你的選擇:" choice case $choice in 1) linux_ps ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "系統更新" ; linux_update ;; + 3) clear ; send_stats "系統清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; @@ -14000,13 +14001,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ + p) send_stats "幻獸帕魯開服腳本" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "無效的輸入!" ;; esac break_end done @@ -14014,68 +14015,68 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "k命令參考用例" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" +echo "視頻介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令參考用例:" +echo "啟動腳本 k" +echo "安裝軟件包 k install nano wget | k add nano wget | k 安裝 nano wget" +echo "卸載軟件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" +echo "更新系統 k update | k 更新" +echo "清理系統垃圾 k clean | k 清理" +echo "重裝系統面板 k dd | k 重裝" echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker环境安装 k docker install |k docker 安装" +echo "內核調優面板 k nhyh | k 內核優化" +echo "設置虛擬內存 k swap 2048" +echo "設置虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" +echo "系統回收站 k trash | k hsz | k 回收站" +echo "系統備份功能 k backup | k bf | k 備份" +echo "ssh遠程連接工具 k ssh | k 遠程連接" +echo "rsync遠程同步工具 k rsync | k 遠程同步" +echo "硬盤管理工具 k disk | k 硬盤管理" +echo "內網穿透(服務端) k frps" +echo "內網穿透(客戶端) k frpc" +echo "軟件啟動 k start sshd | k 啟動 sshd" +echo "軟件停止 k stop sshd | k 停止 sshd" +echo "軟件重啟 k restart sshd | k 重啟 sshd" +echo "軟件狀態查看 k status sshd | k 狀態 sshd" +echo "軟件開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" +echo "域名證書申請 k ssl" +echo "域名證書到期查詢 k ssl ps" +echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "docker鏡像管理 k docker img |k docker 鏡像" +echo "LDNMP站點管理 k web" +echo "LDNMP緩存清理 k web cache" +echo "安裝WordPress k wp |k wordpress |k wp xxx.com" +echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安裝負載均衡 k loadbalance |k 負載均衡" +echo "防火牆面板 k fhq |k 防火牆" +echo "開放端口 k dkdk 8080 |k 打開端口 8080" +echo "關閉端口 k gbdk 7800 |k 關閉端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "命令收藏夾 k fav | k 命令收藏夾" +echo "應用市場管理 k app" +echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 如果沒有參數,運行交互式邏輯 kejilion_sh else - # 如果有参数,执行相应函数 + # 如果有參數,執行相應函數 case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "安裝軟件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "卸載軟件" remove "$@" ;; update|更新) @@ -14109,7 +14110,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "定時rsync同步" run_task "$@" ;; @@ -14128,7 +14129,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "已阻止IP+端口訪問該服務" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14141,13 +14142,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "快速設置虛擬內存" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "快速設置時區" set_timedate "$@" ;; @@ -14195,42 +14196,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "軟件狀態查看" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "軟件啟動" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "軟件暫停" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "軟件重啟" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "軟件開機自啟" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "查看證書狀態" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "快速申請證書" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "快速申請證書" else k_info fi @@ -14240,7 +14241,7 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "快捷安裝docker" install_docker ;; ps|容器) @@ -14248,7 +14249,7 @@ else docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "快捷鏡像管理" docker_image ;; *) @@ -14275,7 +14276,7 @@ else app) shift - send_stats "应用$@" + send_stats "應用$@" linux_panel "$@" ;; From c8425328c32b07dca958a6301654caba1fa2b6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 10:03:15 +0800 Subject: [PATCH 0136/1285] Update kejilion.sh --- cn/kejilion.sh | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dc0846216..dca97b01a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "请输入组网的客户端数量 (默认 5): " COUNT COUNT=${COUNT:-5} + read -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,8 +11810,8 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ @@ -11819,6 +11821,19 @@ while true; do sleep 3 + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + # 全局替换所有 51820 为新端口 + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' docker exec wireguard sh -c ' for d in /config/peer_*; do @@ -11839,10 +11854,12 @@ while true; do done ' + docker restart wireguard + sleep 2 docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" From f93a8864256b72f640f67bd935d3d4a1caa75baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 10:03:50 +0800 Subject: [PATCH 0137/1285] Change WireGuard port and update configuration scripts --- kejilion.sh | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e8af4649c..6e3cd5745 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "请输入组网的客户端数量 (默认 5): " COUNT COUNT=${COUNT:-5} + read -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,8 +11810,8 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ @@ -11819,6 +11821,19 @@ while true; do sleep 3 + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + # 全局替换所有 51820 为新端口 + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' docker exec wireguard sh -c ' for d in /config/peer_*; do @@ -11839,10 +11854,12 @@ while true; do done ' + docker restart wireguard + sleep 2 docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" From 58801f6400ca43bbfbf594d3cac7fd380fea7517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 12:20:35 +0800 Subject: [PATCH 0138/1285] Update kejilion.sh --- cn/kejilion.sh | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dca97b01a..8fb605605 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11816,7 +11816,7 @@ while true; do -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest From a4751d4ec424c8a33ec2e4eedc700c9dc19f71f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 28 Aug 2025 12:22:04 +0800 Subject: [PATCH 0139/1285] Change Docker restart policy to always --- kejilion.sh | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6e3cd5745..216548b03 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11816,7 +11816,7 @@ while true; do -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest From accc7e95ca90fbaf886b10cdc9e57e6a1a75a966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 07:48:59 +0800 Subject: [PATCH 0140/1285] Update kejilion.sh --- cn/kejilion.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8fb605605..ffbd27911 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11824,7 +11824,6 @@ while true; do docker exec wireguard sh -c " f='/config/wg_confs/wg0.conf' - # 全局替换所有 51820 为新端口 sed -i 's/51820/${docker_port}/g' \$f " @@ -11834,12 +11833,18 @@ while true; do done " - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/i MTU = 1420" "$d"/*.conf + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11849,7 +11854,6 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' From 41e3f9bd7e4ba81e65c04d2f2c9c22c308b8e806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 07:49:36 +0800 Subject: [PATCH 0141/1285] Modify WireGuard config handling in kejilion.sh Replace DNS entries and update PersistentKeepalive settings in WireGuard configuration files. --- kejilion.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 216548b03..7c5ceba3b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11824,7 +11824,6 @@ while true; do docker exec wireguard sh -c " f='/config/wg_confs/wg0.conf' - # 全局替换所有 51820 为新端口 sed -i 's/51820/${docker_port}/g' \$f " @@ -11834,12 +11833,18 @@ while true; do done " - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/i MTU = 1420" "$d"/*.conf + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11849,7 +11854,6 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二维码: $base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' From 010337cb936814e0d42bbc3355aa8a5ca45a2caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 09:41:51 +0800 Subject: [PATCH 0142/1285] Update kejilion.sh --- cn/kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ffbd27911..7d6b52605 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11835,7 +11835,6 @@ while true; do docker exec wireguard sh -c ' for d in /config/peer_*; do - sed -i "/^DNS/i MTU = 1420" "$d"/*.conf sed -i "/^DNS/d" "$d"/*.conf done ' From 4cf9c4e4c1fdd61a5abedf0eb990a027fdae0cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 09:42:23 +0800 Subject: [PATCH 0143/1285] Modify peer configuration in kejilion.sh --- kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7c5ceba3b..d2293f10c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11835,7 +11835,6 @@ while true; do docker exec wireguard sh -c ' for d in /config/peer_*; do - sed -i "/^DNS/i MTU = 1420" "$d"/*.conf sed -i "/^DNS/d" "$d"/*.conf done ' From fbdd845fc884cc45fc7af18302e2024b53ae09b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 09:51:03 +0800 Subject: [PATCH 0144/1285] Enhance output for client configurations in kejilion.sh --- cn/kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7d6b52605..b40319141 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11860,8 +11860,12 @@ while true; do docker restart wireguard sleep 2 + echo + echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 + echo + echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" From 3841a90467a6f070ae6d6ea8ce4e4cae0785690f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 09:52:06 +0800 Subject: [PATCH 0145/1285] Enhance kejilion.sh with client config outputs --- kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index d2293f10c..263b9fe54 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11860,8 +11860,12 @@ while true; do docker restart wireguard sleep 2 + echo + echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 + echo + echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" From 12f74d47e9a1c68ee2eaf2db20ba427aec75756d Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 29 Aug 2025 03:21:28 +0000 Subject: [PATCH 0146/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-29=2003:21:28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 110 +++++++++++++++++++++++++++------------------ jp/kejilion.sh | 118 +++++++++++++++++++++++++++++-------------------- kr/kejilion.sh | 110 +++++++++++++++++++++++++++------------------ tw/kejilion.sh | 108 ++++++++++++++++++++++++++------------------ 4 files changed, 271 insertions(+), 175 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 1b54f388d..bbd681882 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "Create an initial user or administrator. Please set the following username and password and whether you are an administrator." @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "Please enter the number of clients to form the network (default 5):" COUNT COUNT=${COUNT:-5} + read -p "Please enter the WireGuard segment (default 10.13.13.0):" NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,23 +11810,40 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest sleep 3 - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11834,15 +11853,20 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "Generate QR code:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' + docker restart wireguard + sleep 2 + echo + echo -e "${gl_huang}All client QR code configuration:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + echo + echo -e "${gl_huang}All client configuration codes:${gl_bai}" + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}All outputs are provided by each client. The usage method is as follows:${gl_bai}" echo -e "${gl_lv}1. Download wg's APP on your mobile phone, scan the QR code above to quickly connect to the network${gl_bai}" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4f60c7f2e..49903c967 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -793,7 +793,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成と新しい構成を比較します + # 元の構成を新しい構成と比較します if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -6557,7 +6557,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}Gitバージョン制御システム" + echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "初期ユーザーまたは管理者を作成します。次のユーザー名とパスワード、およびあなたが管理者であるかどうかを設定してください。" @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "ネットワークを形成するためにクライアントの数を入力してください(デフォルト5):" COUNT COUNT=${COUNT:-5} + read -p "WireGuardセグメントを入力してください(デフォルト10.13.13.0):" NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,23 +11810,40 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest sleep 3 - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11834,15 +11853,20 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "QRコードを生成します:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' + docker restart wireguard + sleep 2 + echo + echo -e "${gl_huang}すべてのクライアントQRコード構成:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + echo + echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}すべての出力は各クライアントによって提供されます。使用方法は次のとおりです。${gl_bai}" echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" @@ -12229,7 +12253,7 @@ linux_Settings() { echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" @@ -12393,7 +12417,7 @@ EOF send_stats "SSHポート変更を終了します" break else - echo "ポート番号が無効です。1〜65535の数字を入力してください。" + echo "ポート番号は無効です。1〜65535の数字を入力してください。" send_stats "無効なSSHポート入力" break_end fi @@ -12604,7 +12628,7 @@ EOF ;; 4) read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudo許可を削除します + # sudoersファイルからユーザーのsudoアクセス許可を削除します sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 7aed0d70d..f5581ad44 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1664,7 +1664,7 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트하십시오 + # 캐시 청소 여부를 사용자에게 프롬프트합니다 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT COUNT=${COUNT:-5} + read -p "Wireguard 세그먼트를 입력하십시오 (기본값 10.13.13.0) :" NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,23 +11810,40 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest sleep 3 - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11834,15 +11853,20 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "QR 코드 생성 :$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' + docker restart wireguard + sleep 2 + echo + echo -e "${gl_huang}모든 클라이언트 QR 코드 구성 :${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + echo + echo -e "${gl_huang}모든 클라이언트 구성 코드 :${gl_bai}" + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}모든 출력은 각 클라이언트가 제공합니다. 사용법은 다음과 같습니다.${gl_bai}" echo -e "${gl_lv}1. 휴대 전화에서 WG의 앱을 다운로드하고 위의 QR 코드를 스캔하여 네트워크에 빠르게 연결하십시오.${gl_bai}" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 960b74c13..982ef2ad2 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -2949,7 +2949,7 @@ docker network create $NETWORK_NAME docker run -d \ --name=node-exporter \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter # Run Prometheus container @@ -2958,7 +2958,7 @@ docker run -d \ -v $PROMETHEUS_DIR/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $PROMETHEUS_DIR/data:/prometheus \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ --user 0:0 \ prom/prometheus:latest @@ -2968,7 +2968,7 @@ docker run -d \ -p ${docker_port}:3000 \ -v $GRAFANA_DIR:/var/lib/grafana \ --network $NETWORK_NAME \ - --restart unless-stopped \ + --restart=always \ grafana/grafana:latest } @@ -3037,7 +3037,7 @@ f2b_install_sshd() { -v /path/to/fail2ban/config:/config \ -v /var/log:/var/log:ro \ -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/fail2ban:latest sleep 3 @@ -9049,7 +9049,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:ubuntu-kde @@ -9131,7 +9131,7 @@ while true; do -p 56881:56881/udp \ -v /home/docker/qbittorrent/config:/config \ -v /home/docker/qbittorrent/downloads:/downloads \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/qbittorrent:latest } @@ -9366,7 +9366,7 @@ while true; do -p ${docker_port}:5700 \ --name qinglong \ --hostname qinglong \ - --restart unless-stopped \ + --restart=always \ whyour/qinglong:latest @@ -9432,7 +9432,7 @@ while true; do -e PGID=1000 \ -v /home/docker/easyimage/config:/app/web/config \ -v /home/docker/easyimage/i:/app/web/i \ - --restart unless-stopped \ + --restart=always \ ddsderek/easyimage:latest } @@ -9749,7 +9749,7 @@ while true; do -v /home/docker/webtop/data:/config \ -v /var/run/docker.sock:/var/run/docker.sock \ --shm-size="1gb" \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/webtop:latest } @@ -9812,7 +9812,7 @@ while true; do docker_rum() { - docker run -d --name dockge --restart unless-stopped -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge + docker run -d --name dockge --restart=always -p ${docker_port}:5001 -v /var/run/docker.sock:/var/run/docker.sock -v /home/docker/dockge/data:/app/data -v /home/docker/dockge/stacks:/home/docker/dockge/stacks -e DOCKGE_STACKS_DIR=/home/docker/dockge/stacks louislam/dockge } @@ -9854,7 +9854,7 @@ while true; do docker run -d \ --name searxng \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v "/home/docker/searxng:/etc/searxng" \ searxng/searxng @@ -10008,7 +10008,7 @@ while true; do docker_rum() { - docker run -d --restart unless-stopped \ + docker run -d --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/moments/data:/app/data \ -v /etc/localtime:/etc/localtime:ro \ @@ -10162,7 +10162,7 @@ while true; do -e ENCRYPTION_KEY=${ENCRYPTION_KEY} \ -p ${docker_port}:6989 \ -v /home/docker/nexterm:/app/data \ - --restart unless-stopped \ + --restart=always \ germannewsmaker/nexterm:latest } @@ -10183,7 +10183,7 @@ while true; do docker_rum() { - docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs + docker run --name hbbs -v /home/docker/hbbs/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbs } @@ -10204,7 +10204,7 @@ while true; do docker_rum() { - docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr + docker run --name hbbr -v /home/docker/hbbr/data:/root -td --net=host --restart=always rustdesk/rustdesk-server hbbr } @@ -10313,7 +10313,7 @@ while true; do docker run -d \ --name=node-exporter \ -p ${docker_port}:9100 \ - --restart unless-stopped \ + --restart=always \ prom/node-exporter @@ -10337,7 +10337,7 @@ while true; do docker run -d \ --name=cadvisor \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ @@ -10708,7 +10708,7 @@ while true; do local docker_port=8064 docker_rum() { - docker run -d --name it-tools --restart unless-stopped -p ${docker_port}:80 corentinth/it-tools:latest + docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" @@ -10852,7 +10852,7 @@ while true; do -p 6199:6199 \ -p 11451:11451 \ -v /home/docker/astrbot/data:/AstrBot/data \ - --restart unless-stopped \ + --restart=always \ --name astrbot \ soulter/astrbot:latest @@ -10877,7 +10877,7 @@ while true; do docker run -d \ --name navidrome \ - --restart=unless-stopped \ + --restart=always \ --user $(id -u):$(id -g) \ -v /home/docker/navidrome/music:/music \ -v /home/docker/navidrome/data:/data \ @@ -10939,7 +10939,7 @@ while true; do docker run -d \ --name libretv \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -e PASSWORD=${app_passwd} \ bestzwei/libretv:latest @@ -11020,7 +11020,7 @@ while true; do docker run -d \ --name melody \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:5566 \ -v /home/docker/melody/.profile:/app/backend/.profile \ foamzou/melody:latest @@ -11049,7 +11049,7 @@ while true; do docker_rum() { docker run -d \ --name dosgame \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:262 \ oldiy/dosgame-web-docker:latest @@ -11079,7 +11079,7 @@ while true; do docker run -d \ --name xunlei \ - --restart unless-stopped \ + --restart=always \ --privileged \ -e XL_DASHBOARD_USERNAME=${app_use} \ -e XL_DASHBOARD_PASSWORD=${app_passwd} \ @@ -11141,7 +11141,7 @@ while true; do mkdir -p /home/docker/beszel && \ docker run -d \ --name beszel \ - --restart=unless-stopped \ + --restart=always \ -v /home/docker/beszel:/beszel_data \ -p ${docker_port}:8090 \ henrygd/beszel @@ -11359,7 +11359,7 @@ while true; do -v /home/docker/wallos/logos:/var/www/html/images/uploads/logos \ -e TZ=UTC \ -p ${docker_port}:80 \ - --restart unless-stopped \ + --restart=always \ bellamy/wallos:latest } @@ -11436,7 +11436,7 @@ while true; do --mount type=bind,source=/home/docker/jellyfin/media,target=/media \ -p ${docker_port}:8096 \ -p 7359:7359/udp \ - --restart=unless-stopped \ + --restart=always \ jellyfin/jellyfin @@ -11524,7 +11524,7 @@ while true; do --name file-code-box \ -p ${docker_port}:12345 \ -v /home/docker/file-code-box/data:/app/data \ - --restart unless-stopped \ + --restart=always \ lanol/filecodebox:latest } @@ -11565,7 +11565,7 @@ while true; do --name matrix \ -v /home/docker/matrix/data:/data \ -p ${docker_port}:8008 \ - --restart unless-stopped \ + --restart=always \ matrixdotorg/synapse:latest echo "創建初始用戶或管理員。請設置以下內容用戶名和密碼以及是否為管理員。" @@ -11655,7 +11655,7 @@ while true; do docker run -d \ --name filebrowser \ - --restart unless-stopped \ + --restart=always \ -p ${docker_port}:8080 \ -v /home/docker/filebrowser/data:/data \ -v /home/docker/filebrowser/config:/config \ @@ -11684,7 +11684,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}:/data \ -p ${docker_port}:5000 \ ${docker_img} /data -A @@ -11714,7 +11714,7 @@ while true; do docker run -d \ --name ${docker_name} \ - --restart unless-stopped \ + --restart=always \ -v /home/docker/${docker_name}/downloads:/app/Downloads \ -v /home/docker/${docker_name}/storage:/app/storage \ -p ${docker_port}:9999 \ @@ -11785,15 +11785,17 @@ while true; do local app_id="97" local docker_name="wireguard" local docker_img="lscr.io/linuxserver/wireguard:latest" - local docker_port=51820 + local docker_port=8097 docker_rum() { read -p "請輸入組網的客戶端數量 (默認 5):" COUNT COUNT=${COUNT:-5} + read -p "請輸入 WireGuard 網段 (默認 10.13.13.0):" NETWORK + NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) - + ip link delete wg0 &>/dev/null ip_address @@ -11808,23 +11810,40 @@ while true; do -e SERVERURL=${ipv4_address} \ -e SERVERPORT=51820 \ -e PEERS=${PEERS} \ - -e INTERNAL_SUBNET=10.13.13.0 \ - -e ALLOWEDIPS=10.13.13.0/24 \ + -e INTERNAL_SUBNET=${NETWORK} \ + -e ALLOWEDIPS=${NETWORK}/24 \ -e PERSISTENTKEEPALIVE_PEERS=all \ -e LOG_CONFS=true \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules \ - --restart unless-stopped \ + --restart=always \ lscr.io/linuxserver/wireguard:latest sleep 3 - docker exec wireguard sh -c 'for d in /config/peer_*; do sed -i "/^DNS *= *10\.13\.13\.1$/d" "$d"/*.conf; done' + + docker exec wireguard sh -c " + f='/config/wg_confs/wg0.conf' + sed -i 's/51820/${docker_port}/g' \$f + " + + docker exec wireguard sh -c " + for d in /config/peer_*; do + sed -i 's/51820/${docker_port}/g' \$d/*.conf + done + " + + docker exec wireguard sh -c ' + for d in /config/peer_*; do + sed -i "/^DNS/d" "$d"/*.conf + done + ' + docker exec wireguard sh -c ' for d in /config/peer_*; do for f in "$d"/*.conf; do - grep -q "^PersistentKeepalive *= *25$" "$f" || \ - sed -i "/^AllowedIPs *= *10\.13\.13\.0\/24$/a PersistentKeepalive = 25" "$f" + grep -q "^PersistentKeepalive" "$f" || \ + sed -i "/^AllowedIPs/ a PersistentKeepalive = 25" "$f" done done ' @@ -11834,15 +11853,20 @@ while true; do cd "$d" || continue conf_file=$(ls *.conf) base_name="${conf_file%.conf}" - echo "生成二維碼:$base_name.png" qrencode -o "$base_name.png" < "$conf_file" done ' + docker restart wireguard + sleep 2 + echo + echo -e "${gl_huang}所有客戶端二維碼配置:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 - docker exec wireguard sh -c 'for d in /config/peer_*; do echo "===== $(basename $d) ====="; cat $d/*.conf; echo; done' + echo + echo -e "${gl_huang}所有客戶端配置代碼:${gl_bai}" + docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可以快速連接網絡${gl_bai}" From 506d02f4f005015b2dfe20c472587af6be81f88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 22:11:01 +0800 Subject: [PATCH 0147/1285] Update kejilion.sh --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b40319141..a07a34820 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11927,6 +11927,8 @@ while true; do echo "客户端配置已保存到 $CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ From 0572d013e6e6272374d9c532157e34344a6dd13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 29 Aug 2025 22:13:22 +0800 Subject: [PATCH 0148/1285] Update kejilion.sh --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 263b9fe54..c4b1c3b54 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11927,6 +11927,8 @@ while true; do echo "客户端配置已保存到 $CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ From e6234a21922c2567994951c8d4004754f64cba8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:48:11 +0800 Subject: [PATCH 0149/1285] Update kejilion.sh --- cn/kejilion.sh | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a07a34820..a654a167e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0. 返回上一级选单" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "重装windows11" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "重装windows10" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "重装windows7" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "重装windows server 25" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "重装windows server 19" + send_stats "重装windows server 22" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "重装windows server 16" + send_stats "重装windows server 19" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; From a0bcba71e67fb47fe942703eb0ab1ea00159cd42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:49:10 +0800 Subject: [PATCH 0150/1285] Update Windows versions in kejilion.sh --- kejilion.sh | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c4b1c3b54..0709e8047 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0. 返回上一级选单" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "重装windows11" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "重装windows10" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "重装windows7" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 22" + send_stats "重装windows server 25" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "重装windows server 19" + send_stats "重装windows server 22" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "重装windows server 16" + send_stats "重装windows server 19" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; From 7f53ab1f3cfce7dc61f775d36c0f5cee23524869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:50:46 +0800 Subject: [PATCH 0151/1285] Add installation instructions for Windows sreve 2025 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4b6de42ef..e94f0069e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1290,4 +1290,5 @@ docker管理增加全局备份还原迁移功能。 ------------------------ 2025-08-27 v4.1.2 应用市场新增WireGuard异地隧道组网工具的安装及使用。 +系统工具中一键重装系统新增Windows sreve 2025的安装。 ------------------------ From d65e24a05fd5f383b9acec72bedb880353089d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:53:56 +0800 Subject: [PATCH 0152/1285] Update kejilion.sh --- cn/kejilion.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a654a167e..1525f00e2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6885,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}正在备份 Docker 容器...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6920,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir fi # 如果该 Compose 项目已经打包过,跳过 @@ -6993,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR + read -e -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } echo -e "${BLUE}开始执行还原操作...${NC}" @@ -7008,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -e -p "未找到原始路径,请输入还原目录路径: " original_path # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7017,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -e -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7112,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker迁移" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR + read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -e -p "目标服务器IP: " TARGET_IP + read -e -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7133,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR + read -e -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" @@ -7159,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "请选择: " choice + read -e -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -11792,9 +11792,9 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -e -p "请输入组网的客户端数量 (默认 5): " COUNT COUNT=${COUNT:-5} - read -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) From 5d407d5ceecd531f4424539e09233927baa3a3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:54:23 +0800 Subject: [PATCH 0153/1285] Update read prompts to use -e option for editing --- kejilion.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0709e8047..febdadf4e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6885,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}正在备份 Docker 容器...${NC}" docker ps --format '{{.Names}}' - read -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -6920,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir fi # 如果该 Compose 项目已经打包过,跳过 @@ -6993,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker还原" - read -p "请输入要还原的备份目录: " BACKUP_DIR + read -e -p "请输入要还原的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } echo -e "${BLUE}开始执行还原操作...${NC}" @@ -7008,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -e -p "未找到原始路径,请输入还原目录路径: " original_path # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7017,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "请输入新的还原路径: " original_path + read -e -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7112,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker迁移" install jq - read -p "请输入要迁移的备份目录: " BACKUP_DIR + read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } - read -p "目标服务器IP: " TARGET_IP - read -p "目标服务器SSH用户名: " TARGET_USER + read -e -p "目标服务器IP: " TARGET_IP + read -e -p "目标服务器SSH用户名: " TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7133,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker备份文件删除" - read -p "请输入要删除的备份目录: " BACKUP_DIR + read -e -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" @@ -7159,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 返回上一级菜单" echo "------------------------" - read -p "请选择: " choice + read -e -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -11792,9 +11792,9 @@ while true; do docker_rum() { - read -p "请输入组网的客户端数量 (默认 5): " COUNT + read -e -p "请输入组网的客户端数量 (默认 5): " COUNT COUNT=${COUNT:-5} - read -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) From ecb6c8508380e906b48ec049d3b5375c3a235461 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 31 Aug 2025 08:48:20 +0000 Subject: [PATCH 0154/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-08-31=2008:48:20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 55 +++++++++++++++-------------- jp/kejilion.sh | 93 ++++++++++++++++++++++++++------------------------ kr/kejilion.sh | 55 +++++++++++++++-------------- tw/kejilion.sh | 49 ++++++++++++++------------ 4 files changed, 136 insertions(+), 116 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index bbd681882..d8334ddda 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35. openSUSE Tumbleweed 36. fnos Feiniu public beta version" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0. Return to the previous menu" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "Reinstall windows11" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "Reinstall Windows 10" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "Reinstall Windows 7" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "Reinstall windows server 22" + send_stats "Reinstall windows server 25" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "Reinstall windows server 19" + send_stats "Reinstall windows server 22" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "Reinstall windows server 16" + send_stats "Reinstall windows server 19" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; @@ -5818,7 +5821,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Example to create a new connection:" + echo "Create a new connection example:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -6882,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Backing up Docker container...${NC}" docker ps --format '{{.Names}}' - read -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers + read -e -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers install tar jq gzip install_docker @@ -6917,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "The compose directory is not detected, please enter the path manually:" project_dir + read -e -p "The compose directory is not detected, please enter the path manually:" project_dir fi # If the Compose project has been packaged, skip it @@ -6990,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker restore" - read -p "Please enter the backup directory to restore:" BACKUP_DIR + read -e -p "Please enter the backup directory to restore:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } echo -e "${BLUE}Start the restore operation...${NC}" @@ -7005,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "The original path was not found, please enter the restore directory path:" original_path + [[ -z "$original_path" ]] && read -e -p "The original path was not found, please enter the restore directory path:" original_path # Check if the container for the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7014,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "Please enter a new restore path:" original_path + read -e -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "Please enter a new restore path:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7109,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker migration" install jq - read -p "Please enter the backup directory to migrate:" BACKUP_DIR + read -e -p "Please enter the backup directory to migrate:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } - read -p "Target server IP:" TARGET_IP - read -p "Target server SSH username:" TARGET_USER + read -e -p "Target server IP:" TARGET_IP + read -e -p "Target server SSH username:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7130,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker backup file deletion" - read -p "Please enter the backup directory to delete:" BACKUP_DIR + read -e -p "Please enter the backup directory to delete:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" @@ -7156,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. Return to the previous menu" echo "------------------------" - read -p "Please select:" choice + read -e -p "Please select:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -11789,9 +11792,9 @@ while true; do docker_rum() { - read -p "Please enter the number of clients to form the network (default 5):" COUNT + read -e -p "Please enter the number of clients to form the network (default 5):" COUNT COUNT=${COUNT:-5} - read -p "Please enter the WireGuard segment (default 10.13.13.0):" NETWORK + read -e -p "Please enter the WireGuard segment (default 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11868,7 +11871,7 @@ while true; do echo -e "${gl_huang}All client configuration codes:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}All outputs are provided by each client. The usage method is as follows:${gl_bai}" + echo -e "${gl_lv}${COUNT}All outputs are all configured by each client, and the usage method is as follows:${gl_bai}" echo -e "${gl_lv}1. Download wg's APP on your mobile phone, scan the QR code above to quickly connect to the network${gl_bai}" echo -e "${gl_lv}2. Download the Windows client and copy the configuration code to connect to the network.${gl_bai}" echo -e "${gl_lv}3. Linux uses scripts to deploy WG clients and copy configuration code to connect to the network.${gl_bai}" @@ -11927,6 +11930,8 @@ while true; do echo "Client configuration has been saved to$CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 49903c967..98244489e 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -793,7 +793,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成を新しい構成と比較します + # 元の構成と新しい構成を比較します if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else @@ -825,7 +825,7 @@ docker_ipv6_off() { # 現在のIPv6ステータスを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成を新しい構成と比較します + # 元の構成と新しい構成を比較します if [[ "$CURRENT_IPV6" == "false" ]]; then echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -3892,7 +3892,7 @@ frps_panel() { echo "------------------------" echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "00。サービスのステータスを更新します。前のメニューに戻ります" + echo "00。サービスのステータスを更新します0。前のメニューに戻ります" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice case $choice in @@ -4147,7 +4147,7 @@ yt_menu_pro() { --no-overwrites --no-post-overwrites read -e -p "実行が完了したら、キーを押して続行します..." ;; 8) - send_stats "mp3ダウンロード" + send_stats "MP3ダウンロード" read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ @@ -4521,7 +4521,7 @@ echo -e "${gl_lv}ルートログインがセットアップされます!${gl_b root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能では、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion } @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0。前のメニューに戻ります" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "Windows11を再インストールします" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "Windows 10を再インストールします" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "Windows 7を再インストールします" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22を再インストールします" + send_stats "Windows Server 25を再インストールします" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "Windows Server 19を再インストールします" + send_stats "Windows Server 22を再インストールします" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "Windows Server 16を再インストールします" + send_stats "Windows Server 19を再インストールします" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; @@ -5278,7 +5281,7 @@ optimize_balanced() { # デフォルト設定関数を復元します restore_defaults() { - echo -e "${gl_lv}デフォルト設定に復元...${gl_bai}" + echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" ulimit -n 1024 @@ -5818,7 +5821,7 @@ list_connections() { # 新しい接続を追加します add_connection() { send_stats "新しい接続を追加します" - echo "新しい接続を作成する例:" + echo "新しい接続例を作成します:" echo "- 接続名:my_server" echo "- IPアドレス:192.168.1.100" echo "- ユーザー名:root" @@ -6418,7 +6421,7 @@ rsync_manager() { echo echo "1.新しいタスクを作成します2。タスクを削除します" echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6.タイミングタスクを削除します" + echo "5.タイミングタスクを作成6。タイミングタスクを削除します" echo "---------------------------------" echo "0。前のメニューに戻ります" echo "---------------------------------" @@ -6882,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" docker ps --format '{{.Names}}' - read -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers + read -e -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers install tar jq gzip install_docker @@ -6917,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir + read -e -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir fi # Composeプロジェクトがパッケージ化されている場合は、スキップしてください @@ -6990,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "Dockerの復元" - read -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR + read -e -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } echo -e "${BLUE}復元操作を開始します...${NC}" @@ -7005,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path + [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7014,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "新しい復元パスを入力してください:" original_path + read -e -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "新しい復元パスを入力してください:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7109,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "Dockerの移行" install jq - read -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR + read -e -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - read -p "ターゲットサーバーIP:" TARGET_IP - read -p "ターゲットサーバーSSHユーザー名:" TARGET_USER + read -e -p "ターゲットサーバーIP:" TARGET_IP + read -e -p "ターゲットサーバーSSHユーザー名:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7130,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Dockerバックアップファイルの削除" - read -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR + read -e -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" @@ -7156,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0。前のメニューに戻ります" echo "------------------------" - read -p "選択してください:" choice + read -e -p "選択してください:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -7904,7 +7907,7 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -7940,7 +7943,7 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "データベース名:$dbname" @@ -7979,7 +7982,7 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベースポート:3306" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" @@ -8017,7 +8020,7 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベースポート:3306" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" @@ -8081,7 +8084,7 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -8120,7 +8123,7 @@ linux_ldnmp() { clear ldnmp_web_on echo "データベースプレフィックス:typecho_" - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "データベース名:$dbname" @@ -8158,7 +8161,7 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベースポート:3306" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" @@ -8284,7 +8287,7 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "データベースアドレス:MySQL" + echo "データベースアドレス:mysql" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -11789,9 +11792,9 @@ while true; do docker_rum() { - read -p "ネットワークを形成するためにクライアントの数を入力してください(デフォルト5):" COUNT + read -e -p "ネットワークを形成するためにクライアントの数を入力してください(デフォルト5):" COUNT COUNT=${COUNT:-5} - read -p "WireGuardセグメントを入力してください(デフォルト10.13.13.0):" NETWORK + read -e -p "WireGuardセグメントを入力してください(デフォルト10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11868,7 +11871,7 @@ while true; do echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}すべての出力は各クライアントによって提供されます。使用方法は次のとおりです。${gl_bai}" + echo -e "${gl_lv}${COUNT}すべての出力はすべて各クライアントによって構成されており、使用方法は次のとおりです。${gl_bai}" echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" echo -e "${gl_lv}2。Windowsクライアントをダウンロードし、構成コードをコピーしてネットワークに接続します。${gl_bai}" echo -e "${gl_lv}3。Linuxはスクリプトを使用してWGクライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" @@ -11927,6 +11930,8 @@ while true; do echo "クライアントの構成が保存されています$CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ @@ -12903,7 +12908,7 @@ EOF break # 跳出 ;; esac - send_stats "タイムされたタスクを追加します" + send_stats "時限タスクを追加します" ;; 2) read -e -p "削除する必要があるキーワードを入力してください。" kquest @@ -13148,7 +13153,7 @@ EOF echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" read -e -p "必ず続行しますか? (y/n):" choice @@ -13508,7 +13513,7 @@ linux_file() { ;; 3) # 修改目录权限 read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可(755など)を入力してください。" perm + read -e -p "許可を入力してください(755など):" perm chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" send_stats "ディレクトリ権限を変更します" ;; @@ -13540,7 +13545,7 @@ linux_file() { ;; 13) # 修改文件权限 read -e -p "ファイル名を入力してください:" filename - read -e -p "許可(755など)を入力してください。" perm + read -e -p "許可を入力してください(755など):" perm chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" send_stats "ファイル権限を変更します" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index f5581ad44..ce2dac590 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1558,7 +1558,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "Windows 11을 다시 설치하십시오" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "Windows 10을 다시 설치하십시오" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "Windows 7을 다시 설치하십시오" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 22를 다시 설치하십시오" + send_stats "Windows Server 25를 다시 설치하십시오" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "Windows Server 19를 다시 설치하십시오" + send_stats "Windows Server 22를 다시 설치하십시오" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "Windows Server 16을 다시 설치하십시오" + send_stats "Windows Server 19를 다시 설치하십시오" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; @@ -5818,7 +5821,7 @@ list_connections() { # 새 연결을 추가하십시오 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결을 만드는 예 :" + echo "새 연결 예제 :" echo "- 연결 이름 : my_server" echo "-IP 주소 : 192.168.1.100" echo "- 사용자 이름 : 루트" @@ -6882,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" docker ps --format '{{.Names}}' - read -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers + read -e -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers install tar jq gzip install_docker @@ -6917,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir + read -e -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir fi # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 @@ -6990,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "도커 복원" - read -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + read -e -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } echo -e "${BLUE}복원 작업 시작 ...${NC}" @@ -7005,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path + [[ -z "$original_path" ]] && read -e -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path # Compose 프로젝트 용 컨테이너가 이미 실행 중인지 확인하십시오. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7014,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "새로운 복원 경로를 입력하십시오 :" original_path + read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "새로운 복원 경로를 입력하십시오 :" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7109,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + read -e -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } - read -p "대상 서버 IP :" TARGET_IP - read -p "대상 서버 SSH 사용자 이름 :" TARGET_USER + read -e -p "대상 서버 IP :" TARGET_IP + read -e -p "대상 서버 SSH 사용자 이름 :" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7130,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker 백업 파일 삭제" - read -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + read -e -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" @@ -7156,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -p "선택하십시오 :" choice + read -e -p "선택하십시오 :" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -11789,9 +11792,9 @@ while true; do docker_rum() { - read -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT + read -e -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT COUNT=${COUNT:-5} - read -p "Wireguard 세그먼트를 입력하십시오 (기본값 10.13.13.0) :" NETWORK + read -e -p "Wireguard 세그먼트를 입력하십시오 (기본값 10.13.13.0) :" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11868,7 +11871,7 @@ while true; do echo -e "${gl_huang}모든 클라이언트 구성 코드 :${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}모든 출력은 각 클라이언트가 제공합니다. 사용법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}${COUNT}모든 출력은 모두 각 클라이언트에 의해 구성되며 사용 방법은 다음과 같습니다.${gl_bai}" echo -e "${gl_lv}1. 휴대 전화에서 WG의 앱을 다운로드하고 위의 QR 코드를 스캔하여 네트워크에 빠르게 연결하십시오.${gl_bai}" echo -e "${gl_lv}2. Windows 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결하십시오.${gl_bai}" echo -e "${gl_lv}3. Linux는 스크립트를 사용하여 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" @@ -11927,6 +11930,8 @@ while true; do echo "클라이언트 구성이 저장되었습니다$CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 982ef2ad2..3856c7de1 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -4591,8 +4591,8 @@ dd_xitong() { echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" echo "------------------------" echo "41. Windows 11 42. Windows 10" - echo "43. Windows 7 44. Windows Server 2022" - echo "45. Windows Server 2019 46. Windows Server 2016" + echo "43. Windows 7 44. Windows Server 2025" + echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" echo "0. 返回上一級選單" @@ -4788,7 +4788,6 @@ dd_xitong() { exit ;; - 41) send_stats "重裝windows11" dd_xitong_2 @@ -4796,6 +4795,7 @@ dd_xitong() { reboot exit ;; + 42) dd_xitong_2 send_stats "重裝windows10" @@ -4803,6 +4803,7 @@ dd_xitong() { reboot exit ;; + 43) send_stats "重裝windows7" dd_xitong_4 @@ -4812,23 +4813,25 @@ dd_xitong() { ;; 44) - send_stats "重裝windows server 22" + send_stats "重裝windows server 25" dd_xitong_2 - bash InstallNET.sh -windows 2022 -lang "cn" + bash InstallNET.sh -windows 2025 -lang "cn" reboot exit ;; + 45) - send_stats "重裝windows server 19" + send_stats "重裝windows server 22" dd_xitong_2 - bash InstallNET.sh -windows 2019 -lang "cn" + bash InstallNET.sh -windows 2022 -lang "cn" reboot exit ;; + 46) - send_stats "重裝windows server 16" + send_stats "重裝windows server 19" dd_xitong_2 - bash InstallNET.sh -windows 2016 -lang "cn" + bash InstallNET.sh -windows 2019 -lang "cn" reboot exit ;; @@ -6882,7 +6885,7 @@ docker_ssh_migration() { echo -e "${YELLOW}正在備份 Docker 容器...${NC}" docker ps --format '{{.Names}}' - read -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers + read -e -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers install tar jq gzip install_docker @@ -6917,7 +6920,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir + read -e -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -6990,7 +6993,7 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker還原" - read -p "請輸入要還原的備份目錄:" BACKUP_DIR + read -e -p "請輸入要還原的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } echo -e "${BLUE}開始執行還原操作...${NC}" @@ -7005,7 +7008,7 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -p "未找到原始路徑,請輸入還原目錄路徑:" original_path + [[ -z "$original_path" ]] && read -e -p "未找到原始路徑,請輸入還原目錄路徑:" original_path # 檢查該 compose 項目的容器是否已經在運行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) @@ -7014,8 +7017,8 @@ docker_ssh_migration() { continue fi - read -p "確認還原 Compose 項目 [$project_name] 到路徑 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -p "請輸入新的還原路徑:" original_path + read -e -p "確認還原 Compose 項目 [$project_name] 到路徑 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "請輸入新的還原路徑:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7109,11 +7112,11 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker遷移" install jq - read -p "請輸入要遷移的備份目錄:" BACKUP_DIR + read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } - read -p "目標服務器IP:" TARGET_IP - read -p "目標服務器SSH用戶名:" TARGET_USER + read -e -p "目標服務器IP:" TARGET_IP + read -e -p "目標服務器SSH用戶名:" TARGET_USER LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 @@ -7130,7 +7133,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker備份文件刪除" - read -p "請輸入要刪除的備份目錄:" BACKUP_DIR + read -e -p "請輸入要刪除的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}已刪除備份:${BACKUP_DIR}${NC}" @@ -7156,7 +7159,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 返回上一級菜單" echo "------------------------" - read -p "請選擇:" choice + read -e -p "請選擇:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -11789,9 +11792,9 @@ while true; do docker_rum() { - read -p "請輸入組網的客戶端數量 (默認 5):" COUNT + read -e -p "請輸入組網的客戶端數量 (默認 5):" COUNT COUNT=${COUNT:-5} - read -p "請輸入 WireGuard 網段 (默認 10.13.13.0):" NETWORK + read -e -p "請輸入 WireGuard 網段 (默認 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11927,6 +11930,8 @@ while true; do echo "客戶端配置已保存到$CONFIG_FILE" + ip link delete wg0 &>/dev/null + docker run -d \ --name wireguardc \ --network host \ From 679fdeffbb1a63adfce93b748d4e782810059a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:07:57 +0800 Subject: [PATCH 0155/1285] Update kejilion.sh --- cn/kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1525f00e2..335539908 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -9082,7 +9082,7 @@ while true; do echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9570,7 +9570,7 @@ while true; do echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" From 2d91ee371b7a18f580934c57b6da86abff4bba1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:08:16 +0800 Subject: [PATCH 0156/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 335539908..0a7c0e94e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From aa833d1d7992e8ac6aaf096c935f00569d9a1572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:08:41 +0800 Subject: [PATCH 0157/1285] Update docker name check to suppress error output --- kejilion.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index febdadf4e..335539908 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安装${gl_bai}" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -9082,7 +9082,7 @@ while true; do echo -e "哪吒监控 $check_docker $update_status" echo "开源、轻量、易用的服务器监控与运维工具" echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "访问地址: " echo "https://$yuming" @@ -9570,7 +9570,7 @@ while true; do echo -e "雷池服务 $check_docker" echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" From cbbee9b68645cc52998f11fd6e3a5f9d98ce163d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:17:44 +0800 Subject: [PATCH 0158/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0a7c0e94e..16ceb9f60 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" From 622bcff1a34d1db044af6aa4435eb9b1ed21c336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:52:02 +0800 Subject: [PATCH 0159/1285] Update kejilion.sh --- cn/kejilion.sh | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 16ceb9f60..abba095b2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name 已经安装完成" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name 已经安装完成" @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}安装" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}控制" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服务端已经安装完成" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服务端已经更新完成" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客户端已经安装完成" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客户端已经更新完成" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "安装完成。按任意键继续..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "更新完成。按任意键继续..." read ;; 3) @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已经安装完成" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已经安装完成" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From 91aac6c22b92aa37c79b686bf928cccfdd2ec123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:52:51 +0800 Subject: [PATCH 0160/1285] Refactor app ID addition in kejilion.sh --- kejilion.sh | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 335539908..049bc80ae 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name 已经安装完成" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name 已经安装完成" @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}安装" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}控制" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服务端已经安装完成" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服务端已经更新完成" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客户端已经安装完成" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客户端已经更新完成" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "安装完成。按任意键继续..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "更新完成。按任意键继续..." read ;; 3) @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已经安装完成" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已经安装完成" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已经安装完成" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已经更新完成" check_docker_app_ip From 6ef2c8d48df9c473f71e4da3dd72f26dd16e97cc Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 1 Sep 2025 02:15:44 +0000 Subject: [PATCH 0161/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-01=2002:15:44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 48 ++++++++++++++++++++++++------------------------ jp/kejilion.sh | 48 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 48 ++++++++++++++++++++++++------------------------ tw/kejilion.sh | 48 ++++++++++++++++++++++++------------------------ 4 files changed, 96 insertions(+), 96 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d8334ddda..40fdcb29f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}${gl_bai} installed" # else # check_docker="${gl_hui}${gl_bai} is not installed" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_nameInstalled" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_nameInstalled" @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}Install" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}control" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "The FRP server has been installed" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "The FRP server has been updated" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "The FRP client has been installed" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "The FRP client has been updated" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "The installation is complete. Press any key to continue..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "Update yt-dlp..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "Update completed. Press any key to continue..." read ;; 3) @@ -9082,7 +9082,7 @@ while true; do echo -e "Nezha Monitoring$check_docker $update_status" echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "Access address:" echo "https://$yuming" @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io has been installed" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io has been installed" @@ -9570,7 +9570,7 @@ while true; do echo -e "Thunder Pool Service$check_docker" echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "The Thunder Pool WAF panel has been installed" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Thunder Pool WAF panel has been updated" check_docker_app_ip diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 98244489e..80e1e4a16 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker = "$ {gl_lv} $ {gl_bai}インストール" # else # check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_nameインストール" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_nameインストール" @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}インストール" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}コントロール" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRPサーバーがインストールされています" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRPサーバーが更新されました" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRPクライアントがインストールされています" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRPクライアントが更新されました" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "インストールが完了しました。任意のキーを押して続行します..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "yt-dlpを更新..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) @@ -9082,7 +9082,7 @@ while true; do echo -e "Nezhaの監視$check_docker $update_status" echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "アクセスアドレス:" echo "https://$yuming" @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Poste.ioがインストールされています" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Poste.ioがインストールされています" @@ -9570,7 +9570,7 @@ while true; do echo -e "サンダープールサービス$check_docker" echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "サンダープールWAFパネルがインストールされています" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "サンダープールWAFパネルが更新されました" check_docker_app_ip diff --git a/kr/kejilion.sh b/kr/kejilion.sh index ce2dac590..23df14ba3 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker = "$ {gl_lv} $ {gl_bai} 설치" # else # check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name설치" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name설치" @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}설치하다" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}제어" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP 서버가 설치되었습니다" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP 서버가 업데이트되었습니다" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP 클라이언트가 설치되었습니다" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP 클라이언트가 업데이트되었습니다" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "yt-dlp 업데이트 ..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." read ;; 3) @@ -9082,7 +9082,7 @@ while true; do echo -e "Nezha 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "액세스 주소 :" echo "https://$yuming" @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Poste.io가 설치되었습니다" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Poste.io가 설치되었습니다" @@ -9570,7 +9570,7 @@ while true; do echo -e "썬더 풀 서비스$check_docker" echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Thunder Pool WAF 패널이 설치되었습니다" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 3856c7de1..b772af125 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'china|mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2374,7 +2374,7 @@ web_optimization() { check_docker_app() { - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1 ; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then check_docker="${gl_lv}已安装${gl_bai}" else check_docker="${gl_hui}未安装${gl_bai}" @@ -2385,7 +2385,7 @@ check_docker_app() { # check_docker_app() { -# if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then +# if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}已安裝${gl_bai}" # else # check_docker="${gl_hui}未安裝${gl_bai}" @@ -2736,7 +2736,7 @@ while true; do echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2768,7 +2768,7 @@ while true; do setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name已經安裝完成" @@ -2783,7 +2783,7 @@ while true; do docker rmi -f "$docker_img" docker_rum - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "$docker_name已經安裝完成" @@ -2849,7 +2849,7 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} @@ -2880,12 +2880,12 @@ docker_app_plus() { setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 2) docker_app_update - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id ;; 3) docker_app_uninstall @@ -3557,13 +3557,13 @@ while true; do iptables_open panel_app_install - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}安裝" ;; 2) panel_app_manage - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id send_stats "${panelname}控制" ;; @@ -3901,7 +3901,7 @@ frps_panel() { install_docker generate_frps_config - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服務端已經安裝完成" ;; 2) @@ -3911,7 +3911,7 @@ frps_panel() { [ -f /home/frp/frps.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frps.toml /home/frp/frps.toml donlond_frp frps - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP服務端已經更新完成" ;; 3) @@ -3998,7 +3998,7 @@ frpc_panel() { install_docker configure_frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客戶端已經安裝完成" ;; 2) @@ -4008,7 +4008,7 @@ frpc_panel() { [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml donlond_frp frpc - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "FRP客戶端已經更新完成" ;; @@ -4091,7 +4091,7 @@ yt_menu_pro() { curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "安裝完成。按任意鍵繼續..." read ;; 2) @@ -4099,7 +4099,7 @@ yt_menu_pro() { echo "正在更新 yt-dlp..." yt-dlp -U - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id echo "更新完成。按任意鍵繼續..." read ;; 3) @@ -9082,7 +9082,7 @@ while true; do echo -e "哪吒監控$check_docker $update_status" echo "開源、輕量、易用的服務器監控與運維工具" echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi @@ -9174,7 +9174,7 @@ while true; do fi echo "" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) echo "訪問地址:" echo "https://$yuming" @@ -9221,7 +9221,7 @@ while true; do -d analogic/poste.io - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已經安裝完成" @@ -9246,7 +9246,7 @@ while true; do -d analogic/poste.i - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "poste.io已經安裝完成" @@ -9570,7 +9570,7 @@ while true; do echo -e "雷池服務$check_docker" echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" - if docker ps -a --format '{{.Names}}' | grep -q "$docker_name" >/dev/null 2>&1; then + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" @@ -9588,7 +9588,7 @@ while true; do check_disk_space 5 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已經安裝完成" check_docker_app_ip @@ -9601,7 +9601,7 @@ while true; do docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') echo "" - mkdir -p /home/docker && touch /home/docker/appno.txt && (add_app_id) + add_app_id clear echo "雷池WAF面板已經更新完成" check_docker_app_ip From c4b4f80234d3928f179c4fd9fd0f302a916b8b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:13:40 +0800 Subject: [PATCH 0162/1285] Update kejilion.sh --- cn/kejilion.sh | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index abba095b2..47765a4a9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" echo "当前可用空间: $((available_space_mb/1024))G" echo "最小需求空间: ${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "请输入你的选择: " choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "输入你的选择: " choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "安装LDNMP环境" root_use clear echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "安装nginx环境" root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt From c853578a918238b64c3f7b20838e924049274e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:14:14 +0800 Subject: [PATCH 0163/1285] Update version and improve disk space checks --- kejilion.sh | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 049bc80ae..b943713b8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" echo "当前可用空间: $((available_space_mb/1024))G" echo "最小需求空间: ${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "请输入你的选择: " choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "输入你的选择: " choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "安装LDNMP环境" root_use clear echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "安装nginx环境" root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt From 0eab38e1143ee57f4d30cedd5876197930b60f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:16:44 +0800 Subject: [PATCH 0164/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e94f0069e..ee90b209c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1292,3 +1292,8 @@ docker管理增加全局备份还原迁移功能。 应用市场新增WireGuard异地隧道组网工具的安装及使用。 系统工具中一键重装系统新增Windows sreve 2025的安装。 ------------------------ +2025-09-03 v4.1.3 +应用市场尝试适配群晖系统文件结构。 +应用安装时的存储空间检测进行优化,可以更精准检测应用目录大小。 +------------------------ + From f4d68cd10a30885b550bb8172a29e8335c2b3b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Sep 2025 22:43:35 +0800 Subject: [PATCH 0165/1285] Update kejilion.sh --- cn/kejilion.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 47765a4a9..498b73bee 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8888,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" @@ -11796,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" From 72c6324975b6621d06b005f11d5b5a5b390d7593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Sep 2025 22:44:02 +0800 Subject: [PATCH 0166/1285] Add 2FAuth application installation script --- kejilion.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index b943713b8..06f459a2b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8888,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" @@ -11796,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" From 74dd85b15f4bc3d6968e3ed2d9e8e165665948b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Sep 2025 22:45:10 +0800 Subject: [PATCH 0167/1285] Add 2FAuth installation and usage information --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ee90b209c..92d38ec91 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1295,5 +1295,6 @@ docker管理增加全局备份还原迁移功能。 2025-09-03 v4.1.3 应用市场尝试适配群晖系统文件结构。 应用安装时的存储空间检测进行优化,可以更精准检测应用目录大小。 +应用市场新增2FAuth自托管二步验证器的安装及使用。 ------------------------ From 49cb452ff3885de82c359db03c2c50a01dfaf3be Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 7 Sep 2025 04:42:46 +0000 Subject: [PATCH 0168/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-07=2004:42:46?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 118 ++++++++++++++++++++++++++++++++++++++----------- jp/kejilion.sh | 110 ++++++++++++++++++++++++++++++++++++--------- kr/kejilion.sh | 118 ++++++++++++++++++++++++++++++++++++++----------- tw/kejilion.sh | 96 ++++++++++++++++++++++++++++++++++------ 4 files changed, 357 insertions(+), 85 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 40fdcb29f..26434a352 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}hint:${gl_bai}Insufficient disk space!" echo "Current available space: $((available_space_mb/1024))G" echo "Minimum demand space:${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -1558,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -2121,7 +2123,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "Please enter your selection:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "Enter your choice:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "Install LDNMP environment" root_use clear echo -e "${gl_huang}The LDNMP environment is not installed, start installing the LDNMP environment...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "Install nginx environment" root_use clear echo -e "${gl_huang}nginx is not installed, start installing nginx environment...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -4514,7 +4526,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login is set up!${gl_bai}" +echo -e "${gl_lv}ROOT login settings are complete!${gl_bai}" } @@ -4992,7 +5004,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Operating system detected:$os_name $os_version" + echo "Detected operating systems:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -5821,7 +5833,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Create a new connection example:" + echo "Example to create a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -8031,7 +8043,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "Backend login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -8854,7 +8866,7 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" @@ -8876,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser File Manager" echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" - echo -e "${gl_kjlan}95. ${color95}paperless document management platform" + echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step validator" echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt @@ -11783,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "Installed" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" @@ -11925,7 +11993,7 @@ while true; do fi done - # Write to the configuration file + # Write to configuration file echo "$input" > "$CONFIG_FILE" echo "Client configuration has been saved to$CONFIG_FILE" @@ -12251,7 +12319,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" @@ -12282,7 +12350,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys are set" + echo "Shortcut keys have been set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -12952,7 +13020,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 80e1e4a16..ea8d514fc 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" echo "現在利用可能なスペース:$((available_space_mb/1024))g" echo "最小需要スペース:${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -1558,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -2121,7 +2123,7 @@ web_security() { 22) send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" echo "CFパラメーターを取得します:" echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "選択を入力してください:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "あなたの選択を入力してください:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "LDNMP環境をインストールします" root_use clear echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "Nginx環境をインストールします" root_use clear echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -4514,7 +4526,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" +echo -e "${gl_lv}ルートログイン設定が完了しました!${gl_bai}" } @@ -5821,7 +5833,7 @@ list_connections() { # 新しい接続を追加します add_connection() { send_stats "新しい接続を追加します" - echo "新しい接続例を作成します:" + echo "新しい接続を作成する例:" echo "- 接続名:my_server" echo "- IPアドレス:192.168.1.100" echo "- ユーザー名:root" @@ -8031,7 +8043,7 @@ linux_ldnmp() { echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "バックエンドログインパス: /admin" echo "------------------------" echo "ユーザー名:admin" echo "パスワード:管理者" @@ -8876,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" echo -e "${gl_kjlan}93. ${color93}DUFS Minimalist Static File Server${gl_kjlan}94. ${color94}ゴープ高速ダウンロードツール" - echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム" + echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2Fauth自己ホストの2段階検証装置" echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt @@ -11783,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "インストール" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" @@ -12251,7 +12319,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" @@ -12952,7 +13020,7 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts send_stats "ローカルホストの解析と削除" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 23df14ba3..035283b71 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}힌트:${gl_bai}불충분 한 디스크 공간!" echo "현재 사용 가능한 공간 : $ ((uvery_space_mb/1024)) g" echo "최소 수요 공간 :${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -1558,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -1664,7 +1666,7 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트합니다 + # 캐시 청소 여부를 사용자에게 프롬프트하십시오 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" @@ -2121,7 +2123,7 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "선택을 입력하십시오 :" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "선택을 입력하십시오 :" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "LDNMP 환경을 설치하십시오" root_use clear echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "Nginx 환경을 설치하십시오" root_use clear echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -4514,7 +4526,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" +echo -e "${gl_lv}루트 로그인 설정이 완료되었습니다!${gl_bai}" } @@ -4992,7 +5004,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "운영 체제 감지 :$os_name $os_version" + echo "감지 된 운영 체제 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -5821,7 +5833,7 @@ list_connections() { # 새 연결을 추가하십시오 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결 예제 :" + echo "새 연결을 만드는 예 :" echo "- 연결 이름 : my_server" echo "-IP 주소 : 192.168.1.100" echo "- 사용자 이름 : 루트" @@ -8031,7 +8043,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "백엔드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" @@ -8876,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" echo -e "${gl_kjlan}93. ${color93}DUFS 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" - echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼" + echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAUTH 자체 호스팅 2 단계 유효성 검사기" echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt @@ -11783,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "설치" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" @@ -11925,7 +11993,7 @@ while true; do fi done - # 구성 파일에 쓰십시오 + # 구성 파일에 씁니다 echo "$input" > "$CONFIG_FILE" echo "클라이언트 구성이 저장되었습니다$CONFIG_FILE" @@ -12251,7 +12319,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" @@ -12282,7 +12350,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" + echo "바로 가기 키가 설정되었습니다" send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings @@ -12952,7 +13020,7 @@ EOF ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index b772af125..c13db439e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.2" +sh_v="4.1.3" gl_hui='\e[37m' @@ -213,12 +213,13 @@ install() { check_disk_space() { + local required_gb=$1 + local path=${2:-/} - required_gb=$1 - required_space_mb=$((required_gb * 1024)) - available_space_mb=$(df -m / | awk 'NR==2 {print $4}') + local required_space_mb=$((required_gb * 1024)) + local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') - if [ $available_space_mb -lt $required_space_mb ]; then + if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}提示:${gl_bai}磁盤空間不足!" echo "當前可用空間: $((available_space_mb/1024))G" echo "最小需求空間:${required_gb}G" @@ -230,6 +231,7 @@ check_disk_space() { } + install_dependency() { install wget unzip tar jq grep } @@ -2707,13 +2709,23 @@ clear_host_port_rules() { setup_docker_dir() { - mkdir -p /home/docker/ 2>/dev/null + mkdir -p /home /home/docker 2>/dev/null + if [ -d "/vol1/1000/" ] && [ ! -d "/vol1/1000/docker" ]; then cp -f /home/docker /home/docker1 2>/dev/null rm -rf /home/docker 2>/dev/null mkdir -p /vol1/1000/docker 2>/dev/null ln -s /vol1/1000/docker /home/docker 2>/dev/null fi + + if [ -d "/volume1/" ] && [ ! -d "/volume1/docker" ]; then + cp -f /home/docker /home/docker1 2>/dev/null + rm -rf /home/docker 2>/dev/null + mkdir -p /volume1/docker 2>/dev/null + ln -s /volume1/docker /home/docker 2>/dev/null + fi + + } @@ -2757,7 +2769,8 @@ while true; do read -e -p "請輸入你的選擇:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2765,7 +2778,6 @@ while true; do install jq install_docker docker_rum - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -2870,14 +2882,14 @@ docker_app_plus() { read -e -p "輸入你的選擇:" choice case $choice in 1) - check_disk_space $app_size + setup_docker_dir + check_disk_space $app_size /home/docker read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq install_docker docker_app_install - setup_docker_dir echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3142,7 +3154,7 @@ send_stats "安裝LDNMP環境" root_use clear echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" -check_disk_space 3 +check_disk_space 3 /home check_port install_dependency install_docker @@ -3159,7 +3171,7 @@ send_stats "安裝nginx環境" root_use clear echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" -check_disk_space 1 +check_disk_space 1 /home check_port install_dependency install_docker @@ -8876,7 +8888,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" - echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台" + echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台${gl_kjlan}96. ${color96}2FAuth自託管二步驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" @@ -9189,7 +9201,8 @@ while true; do case $choice in 1) - check_disk_space 2 + setup_docker_dir + check_disk_space 2 /home/docker read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt @@ -11783,6 +11796,61 @@ while true; do ;; + + 96|2fauth) + + local app_id="96" + + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: https://github.com/Bubka/2FAuth" + local docker_name="2fauth" + local docker_port="8096" + local app_size="1" + + docker_app_install() { + + add_yuming + + mkdir -p /home/docker/2fauth + mkdir -p /home/docker/2fauth/data + chmod -R 777 /home/docker/2fauth/ + cd /home/docker/2fauth + + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml + + sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + cd /home/docker/2fauth + docker compose up -d + + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + block_container_port "$docker_name" "$ipv4_address" + + clear + echo "已經安裝完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/2fauth/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/2fauth/ && docker compose down --rmi all + rm -rf /home/docker/2fauth + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + 97|wgs) local app_id="97" From b2835c2f8ea52613fc3cb41fbfbe9c5d19774853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:44:39 +0800 Subject: [PATCH 0169/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 498b73bee..2e15d40d6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12559,12 +12559,12 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "已切换为 IPv4 优先" send_stats "已切换为 IPv4 优先" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "已切换为 IPv6 优先" send_stats "已切换为 IPv6 优先" ;; From bfc15210d34c4677fbac5c5e8a53b8de0f8b496f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:45:05 +0800 Subject: [PATCH 0170/1285] Modify network preference handling in kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 06f459a2b..66e7c510e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12559,12 +12559,12 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "已切换为 IPv4 优先" send_stats "已切换为 IPv4 优先" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "已切换为 IPv6 优先" send_stats "已切换为 IPv6 优先" ;; From 3701f6c5b5b31d9ecfca3d3acc37156ea7206d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:46:28 +0800 Subject: [PATCH 0171/1285] Enhance IPV4 and IPV6 prioritization in system tools Optimized system tools for IPV4 and IPV6 prioritization. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 92d38ec91..38a3b4899 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1296,5 +1296,6 @@ docker管理增加全局备份还原迁移功能。 应用市场尝试适配群晖系统文件结构。 应用安装时的存储空间检测进行优化,可以更精准检测应用目录大小。 应用市场新增2FAuth自托管二步验证器的安装及使用。 +系统工具IPV4和IPV6优先进行优化,不再粗暴关闭V6来实现V4优先了。 ------------------------ From a554731d102bf439997e9c07b74bc07a394a8191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:55:49 +0800 Subject: [PATCH 0172/1285] Update kejilion.sh --- cn/kejilion.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2e15d40d6..5aa950dc0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12542,13 +12542,14 @@ EOF clear echo "设置v4/v6优先级" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi + echo "" echo "------------------------" echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" @@ -12559,7 +12560,8 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "已切换为 IPv4 优先" send_stats "已切换为 IPv4 优先" ;; From 8994c7d211a8c4ba81324729f67b3e0d521afb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:56:17 +0800 Subject: [PATCH 0173/1285] Update kejilion.sh --- kejilion.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 66e7c510e..16c5b41c7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12542,13 +12542,14 @@ EOF clear echo "设置v4/v6优先级" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi + echo "" echo "------------------------" echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" @@ -12559,7 +12560,8 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "已切换为 IPv4 优先" send_stats "已切换为 IPv4 优先" ;; From e70f8fba38cbf2dc91aa4ef2c4be357028d70af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:05:43 +0800 Subject: [PATCH 0174/1285] Update custom_mysql_config.cnf --- custom_mysql_config.cnf | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_mysql_config.cnf b/custom_mysql_config.cnf index a4240a45c..00aedc27a 100644 --- a/custom_mysql_config.cnf +++ b/custom_mysql_config.cnf @@ -42,3 +42,4 @@ log_queries_not_using_indexes = 1 # ⭐记录无索引扫描 # 其他 sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION performance_schema=ON # ⭐生产环境推荐打开,监控分析好用 +disable-log-bin From 8f2fa2fb25dd334da09686d90c5bf710939a5187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:50:27 +0800 Subject: [PATCH 0175/1285] Update kejilion.sh --- cn/kejilion.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5aa950dc0..4f8285dbc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "手动编辑DNS配置" ;; *) @@ -11816,16 +11822,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "已经安装完成" From 00e65465bda30743f16118c71875290063d13755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:51:08 +0800 Subject: [PATCH 0176/1285] Update version and modify DNS handling in kejilion.sh --- kejilion.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 16c5b41c7..2a389435a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "手动编辑DNS配置" ;; *) @@ -11816,16 +11822,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "已经安装完成" From 2f42e8cc6590a8e4795eea88e8f95de1dbf308bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:52:43 +0800 Subject: [PATCH 0177/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 38a3b4899..31da133d4 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1298,4 +1298,7 @@ docker管理增加全局备份还原迁移功能。 应用市场新增2FAuth自托管二步验证器的安装及使用。 系统工具IPV4和IPV6优先进行优化,不再粗暴关闭V6来实现V4优先了。 ------------------------ +2025-09-10 v4.1.4 +系统工具中DNS优化支持文件锁定功能,解决重启后文件复原问题。 +------------------------ From 1bae6f9df9db406b7fddd8aaac8ebe4a33a48523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:26:55 +0800 Subject: [PATCH 0178/1285] Update kejilion.sh --- cn/kejilion.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4f8285dbc..b1c426bd9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8896,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12034,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "设置内存大小 (默认 4G): " RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + b) clear From 6b36e735b18efeeb5f5981b0f282bec85fed041d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:27:28 +0800 Subject: [PATCH 0179/1285] Update kejilion.sh --- kejilion.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 2a389435a..b7f3759b8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8896,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12034,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "设置内存大小 (默认 4G): " RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "已经安装完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + b) clear From 3cb7d1cf7d0e62cdaf8be4aebb7a01c07a88ffa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:29:11 +0800 Subject: [PATCH 0180/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 31da133d4..e734f8f46 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1300,5 +1300,6 @@ docker管理增加全局备份还原迁移功能。 ------------------------ 2025-09-10 v4.1.4 系统工具中DNS优化支持文件锁定功能,解决重启后文件复原问题。 +应用市场新增了DSM群晖虚拟机的安装及使用。 ------------------------ From ec5cc2f5e2a1ba2db63ec4f940ddc6324c3b9e65 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 11 Sep 2025 03:33:26 +0000 Subject: [PATCH 0181/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-11=2003:33:26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 107 ++++++++++++++++++++++++++++++++++++++++--------- jp/kejilion.sh | 103 ++++++++++++++++++++++++++++++++++++++--------- kr/kejilion.sh | 103 ++++++++++++++++++++++++++++++++++++++--------- tw/kejilion.sh | 83 ++++++++++++++++++++++++++++++++++---- 4 files changed, 332 insertions(+), 64 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 26434a352..c0b324593 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -1560,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or the resolved domain name:" yuming } @@ -1742,7 +1742,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to mode parameters + # Decide to turn on or off WAF according to the mode parameter if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2123,7 +2123,7 @@ web_security() { 22) send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it reaches the detection of a high load, the shield will be automatically turned on, and the low load will be automatically turned off for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "Manually edit DNS configuration" ;; *) @@ -4526,7 +4532,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login settings are complete!${gl_bai}" +echo -e "${gl_lv}ROOT login is set up!${gl_bai}" } @@ -5004,7 +5010,7 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Detected operating systems:$os_name $os_version" + echo "Operating system detected:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." @@ -8866,7 +8872,7 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" @@ -8890,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step validator" echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" @@ -11816,16 +11823,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "Installed" @@ -11939,7 +11946,7 @@ while true; do echo -e "${gl_huang}All client configuration codes:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}All outputs are all configured by each client, and the usage method is as follows:${gl_bai}" + echo -e "${gl_lv}${COUNT}All outputs are provided by each client. The usage method is as follows:${gl_bai}" echo -e "${gl_lv}1. Download wg's APP on your mobile phone, scan the QR code above to quickly connect to the network${gl_bai}" echo -e "${gl_lv}2. Download the Windows client and copy the configuration code to connect to the network.${gl_bai}" echo -e "${gl_lv}3. Linux uses scripts to deploy WG clients and copy configuration code to connect to the network.${gl_bai}" @@ -11993,7 +12000,7 @@ while true; do fi done - # Write to configuration file + # Write to the configuration file echo "$input" > "$CONFIG_FILE" echo "Client configuration has been saved to$CONFIG_FILE" @@ -12028,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "Set the number of CPU cores (default 2):" CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "Set the memory size (default 4G):" RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "Installed" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + + + b) clear @@ -12319,7 +12384,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host analysis${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" @@ -12350,7 +12415,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys have been set" + echo "Shortcut keys are set" send_stats "Script shortcut keys have been set" break_end linux_Settings @@ -12542,13 +12607,14 @@ EOF clear echo "Set v4/v6 priority" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "Current network priority settings:${gl_huang}IPv4${gl_bai}priority" else echo -e "Current network priority settings:${gl_huang}IPv6${gl_bai}priority" fi + echo "" echo "------------------------" echo "1. IPv4 priority 2. IPv6 priority 3. IPv6 repair tool" @@ -12559,12 +12625,13 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "Switched to IPv4 priority" send_stats "Switched to IPv4 priority" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "Switched to IPv6 priority" send_stats "Switched to IPv6 priority" ;; @@ -12794,7 +12861,7 @@ EOF echo "3. Tokyo time in Japan 4. Seoul time in South Korea" echo "5. Singapore time 6. Kolkata time in India" echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Time in Bangkok, Thailand" + echo "9. Bangkok Time, Thailand" echo "------------------------" echo "Europe" echo "11. London time in the UK 12. Paris time in France" @@ -13020,7 +13087,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index ea8d514fc..dc5359911 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -1560,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1742,7 +1742,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します + # モードパラメーターに従ってWAFをオンまたはオフにすることにしました if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2123,7 +2123,7 @@ web_security() { 22) send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷の検出に達すると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" echo "--------------" echo "CFパラメーターを取得します:" echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "DNS構成を手動で編集します" ;; *) @@ -4526,7 +4532,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログイン設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" } @@ -8227,7 +8233,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v + read -e -p "1. The latest version of php | 2。Php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8274,7 +8280,7 @@ linux_ldnmp() { ;; 2) echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8890,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}DUFS Minimalist Static File Server${gl_kjlan}94. ${color94}ゴープ高速ダウンロードツール" echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2Fauth自己ホストの2段階検証装置" echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" @@ -11816,16 +11823,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "インストール" @@ -11939,7 +11946,7 @@ while true; do echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}すべての出力はすべて各クライアントによって構成されており、使用方法は次のとおりです。${gl_bai}" + echo -e "${gl_lv}${COUNT}すべての出力は各クライアントによって提供されます。使用方法は次のとおりです。${gl_bai}" echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" echo -e "${gl_lv}2。Windowsクライアントをダウンロードし、構成コードをコピーしてネットワークに接続します。${gl_bai}" echo -e "${gl_lv}3。Linuxはスクリプトを使用してWGクライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" @@ -12028,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "CPUコアの数を設定します(デフォルト2):" CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "メモリサイズを設定します(デフォルト4G):" RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "インストール" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + + + b) clear @@ -12542,13 +12607,14 @@ EOF clear echo "V4/V6の優先度を設定します" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi + echo "" echo "------------------------" echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" @@ -12559,12 +12625,13 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "IPv4の優先度に切り替えました" send_stats "IPv4の優先度に切り替えました" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "IPv6の優先度に切り替えました" send_stats "IPv6の優先度に切り替えました" ;; @@ -12794,7 +12861,7 @@ EOF echo "3。日本の東京時間4。韓国のソウル時間" echo "5。シンガポール時間6。インドのコルカタ時間" echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。タイのバンコクでの時間" + echo "9。バンコク・タイム、タイ" echo "------------------------" echo "ヨーロッパ" echo "11。英国のロンドン時間12。パリの時間フランスの時間" @@ -13020,7 +13087,7 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost + read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts send_stats "ローカルホストの解析と削除" ;; @@ -13221,7 +13288,7 @@ EOF echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" read -e -p "必ず続行しますか? (y/n):" choice diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 035283b71..1bd683889 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -1560,7 +1560,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 기본 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming } @@ -2123,7 +2123,7 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "DNS 구성을 수동으로 편집합니다" ;; *) @@ -4526,7 +4532,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}루트 로그인 설정이 완료되었습니다!${gl_bai}" +echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" } @@ -5004,7 +5010,7 @@ elrepo_install() { linux_Settings fi # 감지 된 운영 체제 정보를 인쇄합니다 - echo "감지 된 운영 체제 :$os_name $os_version" + echo "운영 체제 감지 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." @@ -8890,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}DUFS 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAUTH 자체 호스팅 2 단계 유효성 검사기" echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" echo -e "${gl_kjlan}------------------------" @@ -11816,16 +11823,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "설치" @@ -11939,7 +11946,7 @@ while true; do echo -e "${gl_huang}모든 클라이언트 구성 코드 :${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}모든 출력은 모두 각 클라이언트에 의해 구성되며 사용 방법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}${COUNT}모든 출력은 각 클라이언트가 제공합니다. 사용법은 다음과 같습니다.${gl_bai}" echo -e "${gl_lv}1. 휴대 전화에서 WG의 앱을 다운로드하고 위의 QR 코드를 스캔하여 네트워크에 빠르게 연결하십시오.${gl_bai}" echo -e "${gl_lv}2. Windows 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결하십시오.${gl_bai}" echo -e "${gl_lv}3. Linux는 스크립트를 사용하여 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" @@ -11993,7 +12000,7 @@ while true; do fi done - # 구성 파일에 씁니다 + # 구성 파일에 쓰십시오 echo "$input" > "$CONFIG_FILE" echo "클라이언트 구성이 저장되었습니다$CONFIG_FILE" @@ -12028,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "CPU 코어 수를 설정 (기본값 2) :" CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "메모리 크기를 설정 (기본 4G) :" RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "설치" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + + + b) clear @@ -12319,7 +12384,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" @@ -12350,7 +12415,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되었습니다" + echo "바로 가기 키가 설정되어 있습니다" send_stats "스크립트 바로 가기 키가 설정되었습니다" break_end linux_Settings @@ -12542,13 +12607,14 @@ EOF clear echo "V4/V6 우선 순위를 설정하십시오" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" else echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" fi + echo "" echo "------------------------" echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" @@ -12559,12 +12625,13 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "IPv4 우선 순위로 전환되었습니다" send_stats "IPv4 우선 순위로 전환되었습니다" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "IPv6 우선 순위로 전환되었습니다" send_stats "IPv6 우선 순위로 전환되었습니다" ;; @@ -12794,7 +12861,7 @@ EOF echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" - echo "9. 태국 방콕에서의 시간" + echo "9. 방콕 시간, 태국" echo "------------------------" echo "유럽" echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" @@ -13020,7 +13087,7 @@ EOF ;; 2) - read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost + read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index c13db439e..27036859e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.3" +sh_v="4.1.4" gl_hui='\e[37m' @@ -4334,9 +4334,11 @@ set_dns() { ip_address +chattr -i /etc/resolv.conf rm /etc/resolv.conf touch /etc/resolv.conf + if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf echo "nameserver $dns2_ipv4" >> /etc/resolv.conf @@ -4347,6 +4349,8 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +chattr +i /etc/resolv.conf + } @@ -4391,7 +4395,9 @@ while true; do ;; 3) install nano + chattr -i /etc/resolv.conf nano /etc/resolv.conf + chattr +i /etc/resolv.conf send_stats "手動編輯DNS配置" ;; *) @@ -8890,6 +8896,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台${gl_kjlan}96. ${color96}2FAuth自託管二步驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" + echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -11816,16 +11823,16 @@ while true; do mkdir -p /home/docker/2fauth/data chmod -R 777 /home/docker/2fauth/ cd /home/docker/2fauth - + curl -o /home/docker/2fauth/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/2fauth-docker-compose.yml sed -i "s/8000:8000/${docker_port}:8000/g" /home/docker/2fauth/docker-compose.yml - sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml + sed -i "s/yuming.com/${yuming}/g" /home/docker/2fauth/docker-compose.yml cd /home/docker/2fauth docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + block_container_port "$docker_name" "$ipv4_address" clear echo "已經安裝完成" @@ -12028,6 +12035,64 @@ while true; do ;; + 99|dsm) + + local app_id="99" + + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: https://github.com/vdsm/virtual-dsm" + local docker_name="dsm" + local docker_port="8099" + local app_size="16" + + docker_app_install() { + + read -e -p "設置 CPU 核數 (默認 2):" CPU_CORES + local CPU_CORES=${CPU_CORES:-2} + + read -e -p "設置內存大小 (默認 4G):" RAM_SIZE + local RAM_SIZE=${RAM_SIZE:-4} + + mkdir -p /home/docker/dsm + mkdir -p /home/docker/dsm/dev + chmod -R 777 /home/docker/dsm/ + cd /home/docker/dsm + + curl -o /home/docker/dsm/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/dsm-docker-compose.yml + + sed -i "s/5000:5000/${docker_port}:5000/g" /home/docker/dsm/docker-compose.yml + sed -i "s|CPU_CORES: "2"|CPU_CORES: "${CPU_CORES}"|g" /home/docker/dsm/docker-compose.yml + sed -i "s|RAM_SIZE: "2G"|RAM_SIZE: "${RAM_SIZE}G"|g" /home/docker/dsm/docker-compose.yml + cd /home/docker/dsm + docker compose up -d + + clear + echo "已經安裝完成" + check_docker_app_ip + } + + + docker_app_update() { + cd /home/docker/dsm/ && docker compose down --rmi all + docker_app_install + } + + + docker_app_uninstall() { + cd /home/docker/dsm/ && docker compose down --rmi all + rm -rf /home/docker/dsm + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + + b) clear @@ -12542,13 +12607,14 @@ EOF clear echo "設置v4/v6優先級" echo "------------------------" - local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) - if [ "$ipv6_disabled" -eq 1 ]; then + + if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "當前網絡優先級設置:${gl_huang}IPv4${gl_bai}優先" else echo -e "當前網絡優先級設置:${gl_huang}IPv6${gl_bai}優先" fi + echo "" echo "------------------------" echo "1. IPv4 優先 2. IPv6 優先 3. IPv6 修復工具" @@ -12559,12 +12625,13 @@ EOF case $choice in 1) - sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 + grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "已切換為 IPv4 優先" send_stats "已切換為 IPv4 優先" ;; 2) - sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 + rm -f /etc/gai.conf echo "已切換為 IPv6 優先" send_stats "已切換為 IPv6 優先" ;; From e21dc962b3cc487ea87273e9b8ed602f0998bd59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 11 Sep 2025 20:48:56 +0800 Subject: [PATCH 0182/1285] Update kejilion.sh --- cn/kejilion.sh | 128 +++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b1c426bd9..e8072f393 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1027,91 +1027,85 @@ disable_ddos_defense() { # 管理国家IP规则的函数 manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # 如果 ipset 不存在则创建 - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # 下载 IP 区域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 将 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "错误:下载 $country_code 的 IP 区域文件失败" + continue + fi - # 使用 iptables 阻止 IP - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "已成功阻止 $country_code 的 IP 地址" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP + iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - allow) - # 为允许的国家创建 ipset(如果不存在) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "已成功阻止 $country_code 的 IP 地址" + rm "${country_code,,}.zone" + ;; - # 下载 IP 区域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 删除现有的国家规则 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "错误:下载 $country_code 的 IP 区域文件失败" + continue + fi - # 将 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # 仅允许指定国家的 IP - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT + iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" - rm "${country_code,,}.zone" - ;; + echo "已成功允许 $country_code 的 IP 地址" + rm "${country_code,,}.zone" + ;; - unblock) - # 删除国家的 iptables 规则 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null + iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - echo "已成功解除 $country_code 的 IP 地址限制" - ;; + echo "已成功解除 $country_code 的 IP 地址限制" + ;; - *) - ;; - esac + *) + echo "用法: manage_country_rules {block|allow|unblock} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1219,18 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入阻止的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules block $country_code send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules unblock $country_code send_stats "清除国家 $country_code 的IP" ;; @@ -1254,8 +1248,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 From ce4896e3c0cd04d9bef6ae721a41dd294fffaea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 11 Sep 2025 20:49:26 +0800 Subject: [PATCH 0183/1285] Update kejilion.sh --- kejilion.sh | 128 ++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index b7f3759b8..3c7f74956 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1027,91 +1027,85 @@ disable_ddos_defense() { # 管理国家IP规则的函数 manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # 如果 ipset 不存在则创建 - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # 下载 IP 区域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 将 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "错误:下载 $country_code 的 IP 区域文件失败" + continue + fi - # 使用 iptables 阻止 IP - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "已成功阻止 $country_code 的 IP 地址" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP + iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP - allow) - # 为允许的国家创建 ipset(如果不存在) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "已成功阻止 $country_code 的 IP 地址" + rm "${country_code,,}.zone" + ;; - # 下载 IP 区域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 删除现有的国家规则 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "错误:下载 $country_code 的 IP 区域文件失败" + continue + fi - # 将 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # 仅允许指定国家的 IP - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT + iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功仅允许 $country_code 的 IP 地址" - rm "${country_code,,}.zone" - ;; + echo "已成功允许 $country_code 的 IP 地址" + rm "${country_code,,}.zone" + ;; - unblock) - # 删除国家的 iptables 规则 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null + iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - # 销毁 ipset - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - echo "已成功解除 $country_code 的 IP 地址限制" - ;; + echo "已成功解除 $country_code 的 IP 地址限制" + ;; - *) - ;; - esac + *) + echo "用法: manage_country_rules {block|allow|unblock} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1219,18 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入阻止的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules block $country_code send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "请输入允许的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "请输入清除的国家代码(如 CN, US, JP): " country_code + read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules unblock $country_code send_stats "清除国家 $country_code 的IP" ;; @@ -1254,8 +1248,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 From a184e532f737acadf34cbf0bf82d3835f5124cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 11 Sep 2025 20:50:57 +0800 Subject: [PATCH 0184/1285] Add support for multiple country IP management in firewall --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e734f8f46..a6c2e3511 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1301,5 +1301,6 @@ docker管理增加全局备份还原迁移功能。 2025-09-10 v4.1.4 系统工具中DNS优化支持文件锁定功能,解决重启后文件复原问题。 应用市场新增了DSM群晖虚拟机的安装及使用。 +系统工具中高级防火墙支持同时对多个国家地区的IP进行放行或封禁。 ------------------------ From a43ae11e79988b815de168afc22dad80e143b67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:36:21 +0800 Subject: [PATCH 0185/1285] Update kejilion.sh --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e8072f393..07acc8e47 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1051,7 +1051,6 @@ manage_country_rules() { done < "${country_code,,}.zone" iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" @@ -1072,8 +1071,9 @@ manage_country_rules() { ipset add "$ipset_name" "$ip" 2>/dev/null done < "${country_code,,}.zone" + + iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT echo "已成功允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" @@ -1081,7 +1081,6 @@ manage_country_rules() { unblock) iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" From fd583f206500d6771549895293be355acec9bab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:36:57 +0800 Subject: [PATCH 0186/1285] Modify iptables rules for IP blocking and allowing --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3c7f74956..d61fc3ed3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1051,7 +1051,6 @@ manage_country_rules() { done < "${country_code,,}.zone" iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" @@ -1072,8 +1071,9 @@ manage_country_rules() { ipset add "$ipset_name" "$ip" 2>/dev/null done < "${country_code,,}.zone" + + iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT echo "已成功允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" @@ -1081,7 +1081,6 @@ manage_country_rules() { unblock) iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null if ipset list "$ipset_name" &> /dev/null; then ipset destroy "$ipset_name" From 3a17199da8bc4bccfdf29aaf61b23da0951dcb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:34:43 +0800 Subject: [PATCH 0187/1285] Update kejilion.sh --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 07acc8e47..4c4844db3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1072,7 +1072,7 @@ manage_country_rules() { done < "${country_code,,}.zone" - iptables -P INPUT DROP + iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT echo "已成功允许 $country_code 的 IP 地址" @@ -13401,8 +13401,8 @@ EOF 41) clear send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" - echo "https://bbs.kejilion.pro/" + echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" + echo "https://board.kejilion.pro" ;; 66) From c823c6f031c595b7880ff2b901c060e5247e95f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:35:32 +0800 Subject: [PATCH 0188/1285] Modify iptables policy and update echo messages Updated messages and adjusted iptables policy. --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d61fc3ed3..1246e4fdd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1072,7 +1072,7 @@ manage_country_rules() { done < "${country_code,,}.zone" - iptables -P INPUT DROP + iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT echo "已成功允许 $country_code 的 IP 地址" @@ -13401,8 +13401,8 @@ EOF 41) clear send_stats "留言板" - echo "科技lion留言板已迁移至官方社区!请在官方社区进行留言噢!" - echo "https://bbs.kejilion.pro/" + echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" + echo "https://board.kejilion.pro" ;; 66) From 358cb98e8653ad5c46d93c0c835aad28c35942ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:39:47 +0800 Subject: [PATCH 0189/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index a6c2e3511..151746895 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1302,5 +1302,6 @@ docker管理增加全局备份还原迁移功能。 系统工具中DNS优化支持文件锁定功能,解决重启后文件复原问题。 应用市场新增了DSM群晖虚拟机的安装及使用。 系统工具中高级防火墙支持同时对多个国家地区的IP进行放行或封禁。 +系统工具中留言板功能重新上线,您对脚本有任何想法欢迎留言交流! ------------------------ From 0e3a52071c65d8ba91788b54552ec04a900c5b45 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 14 Sep 2025 04:20:32 +0000 Subject: [PATCH 0190/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-14=2004:20:32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 137 ++++++++++++++++++++++------------------------ jp/kejilion.sh | 143 +++++++++++++++++++++++-------------------------- kr/kejilion.sh | 135 ++++++++++++++++++++++------------------------ tw/kejilion.sh | 131 +++++++++++++++++++++----------------------- 4 files changed, 255 insertions(+), 291 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index c0b324593..aca8b6c25 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1027,91 +1027,84 @@ disable_ddos_defense() { # Functions that manage national IP rules manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # Create if ipset does not exist - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # Download IP area file - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "Error: Download$country_codeIP zone file failed" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # Add IP to ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "Error: Download$country_codeIP zone file failed" + continue + fi - # Block IP with iptables - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "Blocked successfully$country_codeIP address" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - allow) - # Create an ipset for allowed countries (if not exist) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "Blocked successfully$country_codeIP address" + rm "${country_code,,}.zone" + ;; - # Download IP area file - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "Error: Download$country_codeIP zone file failed" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # Delete existing national rules - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "Error: Download$country_codeIP zone file failed" + continue + fi - # Add IP to ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # Only IPs in designated countries are allowed - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "Successfully only allowed$country_codeIP address" - rm "${country_code,,}.zone" - ;; + iptables -P INPUT DROP + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - unblock) - # Delete the iptables rules for the country - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + echo "Successfully allowed$country_codeIP address" + rm "${country_code,,}.zone" + ;; - # Destroy ipset - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - echo "Successfully lifted$country_codeIP address restrictions" - ;; + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - *) - ;; - esac + echo "Successfully lifted$country_codeIP address restrictions" + ;; + + *) + echo "Usage: manage_country_rules {block|allow|unblock} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1218,18 @@ iptables_panel() { ;; 15) - read -e -p "Please enter the blocked country code (such as CN, US, JP):" country_code + read -e -p "Please enter the blocked country code (multiple country codes can be separated by spaces such as CN US JP):" country_code manage_country_rules block $country_code send_stats "Allowed countries$country_codeIP" ;; 16) - read -e -p "Please enter the allowed country code (such as CN, US, JP):" country_code + read -e -p "Please enter the allowed country code (multiple country codes can be separated by spaces such as CN US JP):" country_code manage_country_rules allow $country_code send_stats "Block the country$country_codeIP" ;; 17) - read -e -p "Please enter the cleared country code (such as CN, US, JP):" country_code + read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces such as CN US JP):" country_code manage_country_rules unblock $country_code send_stats "Clear the country$country_codeIP" ;; @@ -1254,8 +1247,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 @@ -5839,7 +5830,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Example to create a new connection:" + echo "Create a new connection example:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -8049,7 +8040,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Backend login path: /admin" + echo "Background login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -12861,7 +12852,7 @@ EOF echo "3. Tokyo time in Japan 4. Seoul time in South Korea" echo "5. Singapore time 6. Kolkata time in India" echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Bangkok Time, Thailand" + echo "9. Time in Bangkok, Thailand" echo "------------------------" echo "Europe" echo "11. London time in the UK 12. Paris time in France" @@ -13410,8 +13401,8 @@ EOF 41) clear send_stats "Message board" - echo "The technology lion message board has been moved to the official community! Please leave a message in the official community!" - echo "https://bbs.kejilion.pro/" + echo "Visit the official message board of Technology lion. If you have any ideas about scripts, please leave a message and communicate!" + echo "https://board.kejilion.pro" ;; 66) diff --git a/jp/kejilion.sh b/jp/kejilion.sh index dc5359911..a193a670a 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1027,91 +1027,84 @@ disable_ddos_defense() { # 国家IPルールを管理する機能 manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # IPSETが存在しない場合は作成します - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # IPエリアファイルをダウンロードします - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # IPSETにIPを追加します - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + continue + fi - # iptablesでIPをブロックします - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "正常にブロックされました$country_codeIPアドレス" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - allow) - # 許可された国のIPSETを作成する(存在しない場合) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "正常にブロックされました$country_codeIPアドレス" + rm "${country_code,,}.zone" + ;; - # IPエリアファイルをダウンロードします - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 既存の国家ルールを削除します - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + continue + fi - # IPSETにIPを追加します - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # 指定された国のIPのみが許可されています - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "正常に許可されています$country_codeIPアドレス" - rm "${country_code,,}.zone" - ;; + iptables -P INPUT DROP + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - unblock) - # 国のiptablesルールを削除します - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + echo "正常に許可されています$country_codeIPアドレス" + rm "${country_code,,}.zone" + ;; - # Ipsetを破壊します - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - echo "正常に持ち上げられました$country_codeIPアドレスの制限" - ;; + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - *) - ;; - esac + echo "正常に持ち上げられました$country_codeIPアドレスの制限" + ;; + + *) + echo "使用法:manage_country_rules {block | lock | block} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1218,18 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "ブロックされた国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "許可された国$country_codeIP" ;; 16) - read -e -p "許可された国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "許可された国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code manage_country_rules allow $country_code send_stats "国をブロックします$country_codeIP" ;; 17) - read -e -p "クリアされた国コード(CN、米国、JPなど)を入力してください。" country_code + read -e -p "クリアされた国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code manage_country_rules unblock $country_code send_stats "国をきれいにします$country_codeIP" ;; @@ -1254,8 +1247,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 @@ -8049,7 +8040,7 @@ linux_ldnmp() { echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックエンドログインパス: /admin" + echo "バックグラウンドログインパス: /admin" echo "------------------------" echo "ユーザー名:admin" echo "パスワード:管理者" @@ -8233,7 +8224,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1. The latest version of php | 2。Php7.4:" pho_v + read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8280,7 +8271,7 @@ linux_ldnmp() { ;; 2) echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download_db + read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -12384,7 +12375,7 @@ linux_Settings() { echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト分析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" @@ -12861,7 +12852,7 @@ EOF echo "3。日本の東京時間4。韓国のソウル時間" echo "5。シンガポール時間6。インドのコルカタ時間" echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。バンコク・タイム、タイ" + echo "9。タイのバンコクでの時間" echo "------------------------" echo "ヨーロッパ" echo "11。英国のロンドン時間12。パリの時間フランスの時間" @@ -13288,7 +13279,7 @@ EOF echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、SSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" read -e -p "必ず続行しますか? (y/n):" choice @@ -13410,8 +13401,8 @@ EOF 41) clear send_stats "メッセージボード" - echo "テクノロジーライオンメッセージボードは公式コミュニティに移動されました!公式コミュニティにメッセージを残してください!" - echo "https://bbs.kejilion.pro/" + echo "公式のメッセージ技術委員会ライオンをご覧ください。スクリプトについて何かアイデアがある場合は、メッセージを残してコミュニケーションをとってください!" + echo "https://board.kejilion.pro" ;; 66) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 1bd683889..18dfbf7e6 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1027,91 +1027,84 @@ disable_ddos_defense() { # 국가 IP 규칙을 관리하는 기능 manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # IPSET가 존재하지 않는 경우 작성하십시오 - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # IP 영역 파일을 다운로드하십시오 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # IPSET에 IP를 추가하십시오 - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + continue + fi - # iptables와 함께 IP를 차단하십시오 - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "성공적으로 차단되었습니다$country_codeIP 주소" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - allow) - # 허용 국가에 대한 IPSET 만들기 (존재하지 않는 경우) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "성공적으로 차단되었습니다$country_codeIP 주소" + rm "${country_code,,}.zone" + ;; - # IP 영역 파일을 다운로드하십시오 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 기존 국가 규칙을 삭제합니다 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + continue + fi - # IPSET에 IP를 추가하십시오 - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # 지정된 국가의 IP 만 허용됩니다 - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "성공적으로 만 허용됩니다$country_codeIP 주소" - rm "${country_code,,}.zone" - ;; + iptables -P INPUT DROP + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - unblock) - # 국가의 iptables 규칙을 삭제하십시오 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + echo "성공적으로 허용됩니다$country_codeIP 주소" + rm "${country_code,,}.zone" + ;; - # ipset을 파괴하십시오 - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - echo "성공적으로 해제했습니다$country_codeIP 주소 제한" - ;; + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - *) - ;; - esac + echo "성공적으로 해제했습니다$country_codeIP 주소 제한" + ;; + + *) + echo "사용법 : manage_country_rules {블록 | 허용 | unblock} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1218,18 @@ iptables_panel() { ;; 15) - read -e -p "차단 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "차단 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code manage_country_rules block $country_code send_stats "허용 국가$country_codeIP" ;; 16) - read -e -p "허용 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "허용 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code manage_country_rules allow $country_code send_stats "나라를 차단하십시오$country_codeIP" ;; 17) - read -e -p "청산 된 국가 코드 (예 : CN, US, JP)를 입력하십시오." country_code + read -e -p "청산 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code manage_country_rules unblock $country_code send_stats "나라를 정리하십시오$country_codeIP" ;; @@ -1254,8 +1247,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 @@ -8049,7 +8040,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백엔드 로그인 경로 : /admin" + echo "백그라운드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" @@ -12861,7 +12852,7 @@ EOF echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" - echo "9. 방콕 시간, 태국" + echo "9. 태국 방콕에서의 시간" echo "------------------------" echo "유럽" echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" @@ -13410,8 +13401,8 @@ EOF 41) clear send_stats "게시판" - echo "Technology Lion 게시판은 공식 커뮤니티로 옮겨졌습니다! 공식 커뮤니티에 메시지를 남겨주세요!" - echo "https://bbs.kejilion.pro/" + echo "공식 게시위원회의 기술 사자를 방문하십시오. 스크립트에 대한 아이디어가 있으시면 메시지를 남겨두고 의사 소통하십시오!" + echo "https://board.kejilion.pro" ;; 66) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 27036859e..89fa24d13 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1027,91 +1027,84 @@ disable_ddos_defense() { # 管理國家IP規則的函數 manage_country_rules() { local action="$1" - local country_code="$2" - local ipset_name="${country_code,,}_block" - local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" + shift # 去掉第一个参数,剩下的全是国家代码 install ipset - case "$action" in - block) - # 如果 ipset 不存在則創建 - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + for country_code in "$@"; do + local ipset_name="${country_code,,}_block" + local download_url="http://www.ipdeny.com/ipblocks/data/countries/${country_code,,}.zone" - # 下載 IP 區域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" - exit 1 - fi + case "$action" in + block) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 將 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "錯誤:下載$country_code的 IP 區域文件失敗" + continue + fi - # 使用 iptables 阻止 IP - iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - iptables -I OUTPUT -m set --match-set "$ipset_name" dst -j DROP + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - echo "已成功阻止$country_code的 IP 地址" - rm "${country_code,,}.zone" - ;; + iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - allow) - # 為允許的國家創建 ipset(如果不存在) - if ! ipset list "$ipset_name" &> /dev/null; then - ipset create "$ipset_name" hash:net - fi + echo "已成功阻止$country_code的 IP 地址" + rm "${country_code,,}.zone" + ;; - # 下載 IP 區域文件 - if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" - exit 1 - fi + allow) + if ! ipset list "$ipset_name" &> /dev/null; then + ipset create "$ipset_name" hash:net + fi - # 刪除現有的國家規則 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null - ipset flush "$ipset_name" + if ! wget -q "$download_url" -O "${country_code,,}.zone"; then + echo "錯誤:下載$country_code的 IP 區域文件失敗" + continue + fi - # 將 IP 添加到 ipset - while IFS= read -r ip; do - ipset add "$ipset_name" "$ip" - done < "${country_code,,}.zone" + ipset flush "$ipset_name" + while IFS= read -r ip; do + ipset add "$ipset_name" "$ip" 2>/dev/null + done < "${country_code,,}.zone" - # 僅允許指定國家的 IP - iptables -P INPUT DROP - iptables -P OUTPUT DROP - iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - iptables -A OUTPUT -m set --match-set "$ipset_name" dst -j ACCEPT - echo "已成功僅允許$country_code的 IP 地址" - rm "${country_code,,}.zone" - ;; + iptables -P INPUT DROP + iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - unblock) - # 刪除國家的 iptables 規則 - iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - iptables -D OUTPUT -m set --match-set "$ipset_name" dst -j DROP 2>/dev/null + echo "已成功允許$country_code的 IP 地址" + rm "${country_code,,}.zone" + ;; - # 銷毀 ipset - if ipset list "$ipset_name" &> /dev/null; then - ipset destroy "$ipset_name" - fi + unblock) + iptables -D INPUT -m set --match-set "$ipset_name" src -j DROP 2>/dev/null - echo "已成功解除$country_code的 IP 地址限制" - ;; + if ipset list "$ipset_name" &> /dev/null; then + ipset destroy "$ipset_name" + fi - *) - ;; - esac + echo "已成功解除$country_code的 IP 地址限制" + ;; + + *) + echo "用法: manage_country_rules {block|allow|unblock} " + ;; + esac + done } + + + + + + iptables_panel() { root_use install iptables @@ -1225,18 +1218,18 @@ iptables_panel() { ;; 15) - read -e -p "請輸入阻止的國家代碼(如 CN, US, JP):" country_code + read -e -p "請輸入阻止的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules block $country_code send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "請輸入允許的國家代碼(如 CN, US, JP):" country_code + read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; 17) - read -e -p "請輸入清除的國家代碼(如 CN, US, JP):" country_code + read -e -p "請輸入清除的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules unblock $country_code send_stats "清除國家$country_code的IP" ;; @@ -1254,8 +1247,6 @@ iptables_panel() { - - add_swap() { local new_swap=$1 # 获取传入的参数 @@ -13410,8 +13401,8 @@ EOF 41) clear send_stats "留言板" - echo "科技lion留言板已遷移至官方社區!請在官方社區進行留言噢!" - echo "https://bbs.kejilion.pro/" + echo "訪問科技lion官方留言板,您對腳本有任何想法歡迎留言交流!" + echo "https://board.kejilion.pro" ;; 66) From 13f0a062dbcfa4eaaed29b650dba859b177e17fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:59:20 +0800 Subject: [PATCH 0191/1285] Update kejilion.sh --- cn/kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4c4844db3..7ad5b38c3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -14198,6 +14198,7 @@ echo "软件状态查看 k status sshd | k 状态 sshd " echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " echo "域名证书申请 k ssl" echo "域名证书到期查询 k ssl ps" +echo "docker管理平面 k docker" echo "docker环境安装 k docker install |k docker 安装" echo "docker容器管理 k docker ps |k docker 容器" echo "docker镜像管理 k docker img |k docker 镜像" @@ -14408,7 +14409,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; From a9b98940f4fa836d69bc8c8a49e57e2fb64f6f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:00:08 +0800 Subject: [PATCH 0192/1285] Update kejilion.sh --- kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1246e4fdd..886670107 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -14198,6 +14198,7 @@ echo "软件状态查看 k status sshd | k 状态 sshd " echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " echo "域名证书申请 k ssl" echo "域名证书到期查询 k ssl ps" +echo "docker管理平面 k docker" echo "docker环境安装 k docker install |k docker 安装" echo "docker容器管理 k docker ps |k docker 容器" echo "docker镜像管理 k docker img |k docker 镜像" @@ -14408,7 +14409,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; From b72c75a4953c8ff6ba926dba319fc05bdbeb3933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:02:33 +0800 Subject: [PATCH 0193/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 151746895..ced5e8b0d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1304,4 +1304,7 @@ docker管理增加全局备份还原迁移功能。 系统工具中高级防火墙支持同时对多个国家地区的IP进行放行或封禁。 系统工具中留言板功能重新上线,您对脚本有任何想法欢迎留言交流! ------------------------ +2025-09-15 v4.1.5 +k快捷键增加 k docker 命令行输入后能够快速到达docker管理平面。 +------------------------ From 87f9560da9af7fa4bf6553e3e5b3f1027a74841e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:44:11 +0800 Subject: [PATCH 0194/1285] Update kejilion.sh --- cn/kejilion.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7ad5b38c3..c92aaf35b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7126,13 +7126,15 @@ docker_ssh_migration() { read -e -p "目标服务器IP: " TARGET_IP read -e -p "目标服务器SSH用户名: " TARGET_USER + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then # 使用密钥登录 - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8525,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "错误: 请输入远端服务器IP。" continue @@ -8531,7 +8535,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "文件已传送至远程服务器home目录。" else echo "未找到要传送的文件。" @@ -12100,6 +12104,9 @@ while true; do case "$choice" in [Yy]) read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "错误: 请输入远端服务器IP。" continue @@ -12108,7 +12115,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "文件已传送至远程服务器/根目录。" else echo "未找到要传送的文件。" From b2ea52ad39224955522b2eadb74bfed81c37406a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:44:42 +0800 Subject: [PATCH 0195/1285] Add SSH port option for SCP commands --- kejilion.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 886670107..a5a4fa177 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7126,13 +7126,15 @@ docker_ssh_migration() { read -e -p "目标服务器IP: " TARGET_IP read -e -p "目标服务器SSH用户名: " TARGET_USER + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}传输备份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then # 使用密钥登录 - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8525,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "错误: 请输入远端服务器IP。" continue @@ -8531,7 +8535,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "文件已传送至远程服务器home目录。" else echo "未找到要传送的文件。" @@ -12100,6 +12104,9 @@ while true; do case "$choice" in [Yy]) read -e -p "请输入远端服务器IP: " remote_ip + read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "错误: 请输入远端服务器IP。" continue @@ -12108,7 +12115,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "文件已传送至远程服务器/根目录。" else echo "未找到要传送的文件。" From f680aba498a04b476cd958cee27d0f42321e3955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:46:43 +0800 Subject: [PATCH 0196/1285] Enhance docker command with custom SSH port support --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ced5e8b0d..f751167ba 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1306,5 +1306,6 @@ docker管理增加全局备份还原迁移功能。 ------------------------ 2025-09-15 v4.1.5 k快捷键增加 k docker 命令行输入后能够快速到达docker管理平面。 +docker,站点等数据迁移时支持用户自定义输入SSH端口号迁移数据。 ------------------------ From f117335e79eac7502eb7acb41ba8b508cb8b2fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:22:44 +0800 Subject: [PATCH 0197/1285] Update kejilion.sh --- cn/kejilion.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c92aaf35b..74f529ada 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}当前备份列表:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') From 6ac741ed00294054e99c97eab4434bf7dceea8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:23:39 +0800 Subject: [PATCH 0198/1285] Refactor backup variables in kejilion.sh --- kejilion.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a5a4fa177..45066ea79 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}当前备份列表:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') From 5cb3dc433cfa848c72cfa36ea69a42c0e4bc97dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:47:38 +0800 Subject: [PATCH 0199/1285] Update kejilion.sh --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 74f529ada..e2b1d872c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13409,6 +13409,7 @@ EOF send_stats "留言板" echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" echo "https://board.kejilion.pro" + echo "公共密码: kejilion.sh" ;; 66) From 31c1577c60719c7a5476d3721ec643ec7322df98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:48:44 +0800 Subject: [PATCH 0200/1285] Include public password in kejilion.sh --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 45066ea79..399c1409a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13409,6 +13409,7 @@ EOF send_stats "留言板" echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" echo "https://board.kejilion.pro" + echo "公共密码: kejilion.sh" ;; 66) From 22bafd569f989cf2d238508c18247066f7c0eefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Sep 2025 18:18:04 +0800 Subject: [PATCH 0201/1285] Update kejilion.sh --- cn/kejilion.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e2b1d872c..e5f6902f5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "系统信息查询" @@ -14146,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "系统更新" ; linux_update ;; 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; @@ -14222,6 +14222,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "显示系统信息 k info" } @@ -14444,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; From c1e11aecd550b13d21739fc8d208b083eb94a90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Sep 2025 18:18:40 +0800 Subject: [PATCH 0202/1285] Update kejilion.sh --- kejilion.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 399c1409a..3965f8432 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "系统信息查询" @@ -14146,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "请输入你的选择: " choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "系统更新" ; linux_update ;; 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; @@ -14222,6 +14222,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "显示系统信息 k info" } @@ -14444,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; From 50f4a8a82c4c7ff4010f0602e3ecd26dcaa7273e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Sep 2025 18:22:38 +0800 Subject: [PATCH 0203/1285] Update kejilion_sh_log.txt with version 4.1.5 changes --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f751167ba..18d77c7f2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1307,5 +1307,6 @@ docker管理增加全局备份还原迁移功能。 2025-09-15 v4.1.5 k快捷键增加 k docker 命令行输入后能够快速到达docker管理平面。 docker,站点等数据迁移时支持用户自定义输入SSH端口号迁移数据。 +k快捷命令增加了 k info 系统信息快速查询。 ------------------------ From 0b5e5c82a648fbcec45d3956f33b123d0a9a95e3 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 21 Sep 2025 04:23:28 +0000 Subject: [PATCH 0204/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-21=2004:23:28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 43 ++++++++++++++++++++++++++++--------------- jp/kejilion.sh | 41 +++++++++++++++++++++++++++-------------- kr/kejilion.sh | 43 ++++++++++++++++++++++++++++--------------- tw/kejilion.sh | 37 +++++++++++++++++++++++++------------ 4 files changed, 108 insertions(+), 56 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index aca8b6c25..aa17a3682 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -5830,7 +5830,7 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Create a new connection example:" + echo "Example to create a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "System information query" @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}Current backup list:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "No backup" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -7126,13 +7125,15 @@ docker_ssh_migration() { read -e -p "Target server IP:" TARGET_IP read -e -p "Target server SSH username:" TARGET_USER + read -e -p "Target server SSH port [default 22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}Transfer backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then # Log in with a key - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8524,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "Please enter the remote server IP:" remote_ip + read -e -p "Target server SSH port [default 22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "Error: Please enter the remote server IP." continue @@ -8531,7 +8534,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "The file has been transferred to the remote server home directory." else echo "The file to be transferred was not found." @@ -12100,6 +12103,9 @@ while true; do case "$choice" in [Yy]) read -e -p "Please enter the remote server IP:" remote_ip + read -e -p "Target server SSH port [default 22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "Error: Please enter the remote server IP." continue @@ -12108,7 +12114,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "The file has been transferred to the remote server/root directory." else echo "The file to be transferred was not found." @@ -13023,7 +13029,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "Choose what time to perform tasks every day? (Hours, 0-23):" hour + read -e -p "Choose when to perform tasks every day? (Hours, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13078,7 +13084,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -13403,6 +13409,7 @@ EOF send_stats "Message board" echo "Visit the official message board of Technology lion. If you have any ideas about scripts, please leave a message and communicate!" echo "https://board.kejilion.pro" + echo "Public password: kejilion.sh" ;; 66) @@ -14139,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "Please enter your selection:" choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "System update" ; linux_update ;; 3) clear ; send_stats "System Cleanup" ; linux_clean ;; 4) linux_tools ;; @@ -14198,6 +14205,7 @@ echo "Software status view k status sshd | k status sshd" echo "Software boot k enable docker | k autostart docke | k startup docker" echo "Domain name certificate application k ssl" echo "Domain name certificate expiration query k ssl ps" +echo "docker management plane k docker" echo "docker environment installation k docker install |k docker installation" echo "docker container management k docker ps |k docker container" echo "docker image management k docker img |k docker image" @@ -14214,6 +14222,7 @@ echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" echo "Command favorites k fav | k command favorites" echo "App Market Management k app" echo "Application number quick management k app 26 | k app 1panel | k app npm" +echo "Display system information k info" } @@ -14408,7 +14417,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; @@ -14436,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a193a670a..0a84f0c12 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "システム情報クエリ" @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}現在のバックアップリスト:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -7126,13 +7125,15 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーSSHユーザー名:" TARGET_USER + read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}バックアップを転送...${NC}" if [[ -z "$TARGET_PASS" ]]; then # キーでログインします - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8524,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "エラー:リモートサーバーIPを入力してください。" continue @@ -8531,7 +8534,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" else echo "転送されるファイルは見つかりませんでした。" @@ -12100,6 +12103,9 @@ while true; do case "$choice" in [Yy]) read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "エラー:リモートサーバーIPを入力してください。" continue @@ -12108,7 +12114,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "ファイルは、リモートサーバー/ルートディレクトリに転送されました。" else echo "転送されるファイルは見つかりませんでした。" @@ -13023,7 +13029,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour + read -e -p "毎日タスクを実行する時期を選択しますか? (時間、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13078,7 +13084,7 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts send_stats "ローカルホストの解析と削除" ;; @@ -13403,6 +13409,7 @@ EOF send_stats "メッセージボード" echo "公式のメッセージ技術委員会ライオンをご覧ください。スクリプトについて何かアイデアがある場合は、メッセージを残してコミュニケーションをとってください!" echo "https://board.kejilion.pro" + echo "パスワード:kejilion.sh" ;; 66) @@ -14139,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択を入力してください:" choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "システムの更新" ; linux_update ;; 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; @@ -14198,6 +14205,7 @@ echo "ソフトウェアステータスビューKステータスSSHD | Kステ echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" echo "ドメイン名証明書アプリケーションK SSL" echo "ドメイン名証明書の有効期限クエリK SSL PS" +echo "Docker Management Plane K Docker" echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" echo "Docker Container Management K Docker PS | K Dockerコンテナ" echo "Docker Image Management K Docker IMG | K Docker画像" @@ -14214,6 +14222,7 @@ echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" echo "コマンドお気に入りk fav | Kコマンドのお気に入り" echo "アプリ市場管理Kアプリ" echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" +echo "システム情報を表示k情報" } @@ -14408,7 +14417,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; @@ -14436,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 18dfbf7e6..7a7f37a8a 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "시스템 정보 쿼리" @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}현재 백업 목록 :${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -7126,13 +7125,15 @@ docker_ssh_migration() { read -e -p "대상 서버 IP :" TARGET_IP read -e -p "대상 서버 SSH 사용자 이름 :" TARGET_USER + read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}백업 전송 ...${NC}" if [[ -z "$TARGET_PASS" ]]; then # 키로 로그인하십시오 - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8524,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "오류 : 원격 서버 IP를 입력하십시오." continue @@ -8531,7 +8534,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." else echo "전송할 파일은 찾을 수 없었습니다." @@ -12100,6 +12103,9 @@ while true; do case "$choice" in [Yy]) read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "오류 : 원격 서버 IP를 입력하십시오." continue @@ -12108,7 +12114,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." else echo "전송할 파일은 찾을 수 없었습니다." @@ -13023,7 +13029,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour + read -e -p "매일 작업을 수행 할시기를 선택 하시겠습니까? (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13078,7 +13084,7 @@ EOF ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; @@ -13403,6 +13409,7 @@ EOF send_stats "게시판" echo "공식 게시위원회의 기술 사자를 방문하십시오. 스크립트에 대한 아이디어가 있으시면 메시지를 남겨두고 의사 소통하십시오!" echo "https://board.kejilion.pro" + echo "공개 비밀번호 : Kejilion.sh" ;; 66) @@ -13736,7 +13743,7 @@ linux_file() { # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사합니다" + send_stats "파일 또는 디렉토리를 복사하십시오" ;; @@ -14139,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택을 입력하십시오 :" choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; 3) clear ; send_stats "시스템 정리" ; linux_clean ;; 4) linux_tools ;; @@ -14198,6 +14205,7 @@ echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" echo "도메인 이름 인증서 응용 프로그램 K SSL" echo "도메인 이름 인증서 만료 쿼리 K SSL PS" +echo "Docker Management Plane K Docker" echo "도커 환경 설치 K 도커 설치 | K 도커 설치" echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" echo "Docker Image Management K Docker img | K Docker Image" @@ -14214,6 +14222,7 @@ echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" echo "앱 시장 관리 K 앱" echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" +echo "디스플레이 시스템 정보 K 정보" } @@ -14408,7 +14417,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; @@ -14436,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 89fa24d13..b64b35045 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.4" +sh_v="4.1.5" gl_hui='\e[37m' @@ -6457,7 +6457,7 @@ rsync_manager() { -linux_ps() { +linux_info() { clear send_stats "系統信息查詢" @@ -6870,16 +6870,13 @@ docker_ssh_migration() { BLUE='\033[0;36m' NC='\033[0m' - BACKUP_ROOT="/tmp" - DATE_STR=$(date +%Y%m%d_%H%M%S) - - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 } list_backups() { + local BACKUP_ROOT="/tmp" echo -e "${BLUE}當前備份列表:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" } @@ -6899,6 +6896,8 @@ docker_ssh_migration() { install tar jq gzip install_docker + local BACKUP_ROOT="/tmp" + local DATE_STR=$(date +%Y%m%d_%H%M%S) local TARGET_CONTAINERS=() if [ -z "$containers" ]; then mapfile -t TARGET_CONTAINERS < <(docker ps --format '{{.Names}}') @@ -7126,13 +7125,15 @@ docker_ssh_migration() { read -e -p "目標服務器IP:" TARGET_IP read -e -p "目標服務器SSH用戶名:" TARGET_USER + read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} - LATEST_TAR="$BACKUP_DIR" # 这里直接传整个目录 + local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}傳輸備份中...${NC}" if [[ -z "$TARGET_PASS" ]]; then # 使用密鑰登錄 - scp -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } @@ -8523,6 +8524,8 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "錯誤: 請輸入遠端服務器IP。" continue @@ -8531,7 +8534,7 @@ linux_ldnmp() { if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "文件已傳送至遠程服務器home目錄。" else echo "未找到要傳送的文件。" @@ -12100,6 +12103,9 @@ while true; do case "$choice" in [Yy]) read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + local TARGET_PORT=${TARGET_PORT:-22} + if [ -z "$remote_ip" ]; then echo "錯誤: 請輸入遠端服務器IP。" continue @@ -12108,7 +12114,7 @@ while true; do if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 - scp -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" + scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "文件已傳送至遠程服務器/根目錄。" else echo "未找到要傳送的文件。" @@ -13403,6 +13409,7 @@ EOF send_stats "留言板" echo "訪問科技lion官方留言板,您對腳本有任何想法歡迎留言交流!" echo "https://board.kejilion.pro" + echo "公共密碼: kejilion.sh" ;; 66) @@ -14139,7 +14146,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" choice case $choice in - 1) linux_ps ;; + 1) linux_info ;; 2) clear ; send_stats "系統更新" ; linux_update ;; 3) clear ; send_stats "系統清理" ; linux_clean ;; 4) linux_tools ;; @@ -14198,6 +14205,7 @@ echo "軟件狀態查看 k status sshd | k 狀態 sshd" echo "軟件開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "域名證書申請 k ssl" echo "域名證書到期查詢 k ssl ps" +echo "docker管理平面 k docker" echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" echo "docker鏡像管理 k docker img |k docker 鏡像" @@ -14214,6 +14222,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夾 k fav | k 命令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" +echo "顯示系統信息 k info" } @@ -14408,7 +14417,7 @@ else docker_image ;; *) - k_info + linux_docker ;; esac ;; @@ -14436,6 +14445,10 @@ else ;; + info) + linux_info + ;; + *) k_info ;; From 1d7771cbc83ced24b0591ced186ba3ca7da2cc66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:41:49 +0800 Subject: [PATCH 0205/1285] Update kejilion.sh --- cn/kejilion.sh | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e5f6902f5..f85164f4a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -8890,7 +8890,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" - echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12085,8 +12085,37 @@ while true; do + 100|syncthing) + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + docker_rum() { + + docker run -d \ + --name syncthing \ + -p ${docker_port}:8384 \ # Web UI + -p 22000:22000/tcp \ # TCP 文件传输 + -p 22000:22000/udp \ # QUIC 文件传输 + -p 21027:21027/udp \ # 局域网发现 + -v /home/docker/${docker_name}/st-sync:/var/syncthing \ + --hostname=my-syncthing \ + -e PUID=1000 \ + -e PGID=1000 \ + syncthing/syncthing:latest + + } + + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) clear @@ -14222,7 +14251,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" -echo "显示系统信息 k info" +echo "显示系统信息 k info" } From ec7947607b5b510202445efac8d4c6d4a3affb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:43:37 +0800 Subject: [PATCH 0206/1285] Update kejilion.sh --- kejilion.sh | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3965f8432..cb879bc96 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -8890,7 +8890,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" - echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12085,8 +12085,37 @@ while true; do + 100|syncthing) + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + docker_rum() { + + docker run -d \ + --name syncthing \ + -p ${docker_port}:8384 \ # Web UI + -p 22000:22000/tcp \ # TCP 文件传输 + -p 22000:22000/udp \ # QUIC 文件传输 + -p 21027:21027/udp \ # 局域网发现 + -v /home/docker/${docker_name}/st-sync:/var/syncthing \ + --hostname=my-syncthing \ + -e PUID=1000 \ + -e PGID=1000 \ + syncthing/syncthing:latest + + } + + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) clear @@ -14222,7 +14251,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" -echo "显示系统信息 k info" +echo "显示系统信息 k info" } From a983135f3dfd9b8a2562764161a3fa2b23a7406b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:45:18 +0800 Subject: [PATCH 0207/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 18d77c7f2..b4a198a0f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1309,4 +1309,7 @@ k快捷键增加 k docker 命令行输入后能够快速到达docker管理平面 docker,站点等数据迁移时支持用户自定义输入SSH端口号迁移数据。 k快捷命令增加了 k info 系统信息快速查询。 ------------------------ +2025-09-25 v4.1.6 +应用市场新增了Syncthing开源的点对点文件同步工具的安装及使用。 +------------------------ From 81c38801bdf1e454876f20e37adccde02c08e409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 17:01:43 +0800 Subject: [PATCH 0208/1285] Update kejilion.sh --- cn/kejilion.sh | 57 ++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f85164f4a..81578f659 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8384,7 +8384,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8405,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -9499,7 +9499,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9527,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9654,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9678,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9727,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9849,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9897,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +10002,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10128,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10246,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10267,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10383,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10438,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10490,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10706,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10750,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10924,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +12008,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12093,19 +12093,16 @@ while true; do local docker_port=8100 docker_rum() { - docker run -d \ - --name syncthing \ - -p ${docker_port}:8384 \ # Web UI - -p 22000:22000/tcp \ # TCP 文件传输 - -p 22000:22000/udp \ # QUIC 文件传输 - -p 21027:21027/udp \ # 局域网发现 - -v /home/docker/${docker_name}/st-sync:/var/syncthing \ + --name=syncthing \ --hostname=my-syncthing \ - -e PUID=1000 \ - -e PGID=1000 \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ syncthing/syncthing:latest - } local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" From 453e58ab196c6a0771093877903a6e56cf3cb18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 17:02:18 +0800 Subject: [PATCH 0209/1285] Standardize docker restart policy syntax --- kejilion.sh | 57 +++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index cb879bc96..b58640b6e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8384,7 +8384,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8405,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -9499,7 +9499,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9527,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9654,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9678,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9727,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9849,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9897,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +10002,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10128,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10246,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10267,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10383,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10438,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10490,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10706,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10750,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10924,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +12008,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12093,19 +12093,16 @@ while true; do local docker_port=8100 docker_rum() { - docker run -d \ - --name syncthing \ - -p ${docker_port}:8384 \ # Web UI - -p 22000:22000/tcp \ # TCP 文件传输 - -p 22000:22000/udp \ # QUIC 文件传输 - -p 21027:21027/udp \ # 局域网发现 - -v /home/docker/${docker_name}/st-sync:/var/syncthing \ + --name=syncthing \ --hostname=my-syncthing \ - -e PUID=1000 \ - -e PGID=1000 \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ syncthing/syncthing:latest - } local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" From 0c3d0dbf21d3187075d7ca5e04f965ef93110af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:26:50 +0800 Subject: [PATCH 0210/1285] Add stats sending and installation script execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Send statistics and execute installation script for R探长开机脚本. --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 81578f659..41739d2a4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7765,7 +7765,8 @@ linux_Oracle() { 4) clear - echo "该功能处于开发阶段,敬请期待!" + send_stats "R探长开机脚本" + bash <(wget -qO- https://github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear From 205bd0874bd89956b49515f75a860c95b63510d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:27:43 +0800 Subject: [PATCH 0211/1285] Update option 4 to send stats and execute script Replaced placeholder message with stats sending and script execution. --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index b58640b6e..64fb6ba02 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7765,7 +7765,8 @@ linux_Oracle() { 4) clear - echo "该功能处于开发阶段,敬请期待!" + send_stats "R探长开机脚本" + bash <(wget -qO- https://github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear From 94933ca0655758c3cf2cc1d4002022056df50f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:30:28 +0800 Subject: [PATCH 0212/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index b4a198a0f..e56245632 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1311,5 +1311,6 @@ k快捷命令增加了 k info 系统信息快速查询。 ------------------------ 2025-09-25 v4.1.6 应用市场新增了Syncthing开源的点对点文件同步工具的安装及使用。 +甲骨文云合集中增加大佬的R探长开机脚本,非常感谢大佬脚本。 ------------------------ From 1f1f51cb6e7842e222bbfc9e3b63e6a851045667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:07:08 +0800 Subject: [PATCH 0213/1285] Update kejilion.sh --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 41739d2a4..379764420 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3063,6 +3063,8 @@ f2b_install_sshd() { fi rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf + sed -i 's/action = %(action_)s/action = iptables-multiport/g' /etc/fail2ban/jail.conf + } f2b_sshd() { @@ -7766,7 +7768,7 @@ linux_Oracle() { 4) clear send_stats "R探长开机脚本" - bash <(wget -qO- https://github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear From 5f475e9fefa9dbf718d5e8824f72b61998545d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:07:52 +0800 Subject: [PATCH 0214/1285] Fix fail2ban action and update oci-helper install URL Updated fail2ban action configuration and modified installation script URL. --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 64fb6ba02..4146d6d7a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3063,6 +3063,8 @@ f2b_install_sshd() { fi rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf + sed -i 's/action = %(action_)s/action = iptables-multiport/g' /etc/fail2ban/jail.conf + } f2b_sshd() { @@ -7766,7 +7768,7 @@ linux_Oracle() { 4) clear send_stats "R探长开机脚本" - bash <(wget -qO- https://github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear From f49992dc329a997af5fc838b3fe2f325d66a0231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:09:38 +0800 Subject: [PATCH 0215/1285] Fix fail2ban SSH rule loading error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复SSH防御fail2ban加载ssh规则报错的问题。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e56245632..79b60d8d2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1312,5 +1312,6 @@ k快捷命令增加了 k info 系统信息快速查询。 2025-09-25 v4.1.6 应用市场新增了Syncthing开源的点对点文件同步工具的安装及使用。 甲骨文云合集中增加大佬的R探长开机脚本,非常感谢大佬脚本。 +又来修复SSH防御fail2ban加载ssh规则报错的问题。 ------------------------ From 5d8ab0d1c3fd891f5909b6fdd43b73e426047c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:16:22 +0800 Subject: [PATCH 0216/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 4146d6d7a..3bac38768 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3063,7 +3063,7 @@ f2b_install_sshd() { fi rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf - sed -i 's/action = %(action_)s/action = iptables-multiport/g' /etc/fail2ban/jail.conf + sed -i 's/action = %(action_)s/action = iptables-multiport/g' /path/to/fail2ban/config/fail2ban/jail.conf } From 377e3c090ede9ced9ed880f18e28f1da58facaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:17:03 +0800 Subject: [PATCH 0217/1285] Update fail2ban config file path in kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 379764420..2eb221caf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3063,7 +3063,7 @@ f2b_install_sshd() { fi rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf - sed -i 's/action = %(action_)s/action = iptables-multiport/g' /etc/fail2ban/jail.conf + sed -i 's/action = %(action_)s/action = iptables-multiport/g' /path/to/fail2ban/config/fail2ban/jail.conf } From 54e4a90d2bc3db4b9134601df8fbc3bd8899bef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:06:11 +0800 Subject: [PATCH 0218/1285] Update kejilion.sh --- cn/kejilion.sh | 114 +++++++++++++++---------------------------------- 1 file changed, 35 insertions(+), 79 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2eb221caf..9dbe8384f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP环境防御" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安装防御程序" echo "------------------------" @@ -2019,11 +2011,11 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2065,28 +2057,28 @@ web_security() { ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防御程序已卸载" ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2091,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" @@ -2171,7 +2163,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,53 +3008,28 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="已安装" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="未安装" fi +} + +f2b_install_sshd() { - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf - sed -i 's/action = %(action_)s/action = iptables-multiport/g' /path/to/fail2ban/config/fail2ban/jail.conf + install fail2ban + start fail2ban + enable fail2ban } @@ -13128,17 +13094,9 @@ EOF root_use send_stats "ssh防御" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH防御程序 $check_docker" + + check_f2b_status + echo -e "SSH防御程序 $check_f2b_status" echo "fail2ban是一个SSH防止暴力破解工具" echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13154,7 +13112,6 @@ EOF read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13168,19 +13125,18 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2Ban防御程序已卸载" ;; *) break ;; esac - fi done ;; From 2079722370e8be6e3c822dfaa4ea42becd91288c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:07:02 +0800 Subject: [PATCH 0219/1285] Update kejilion.sh --- kejilion.sh | 114 ++++++++++++++++------------------------------------ 1 file changed, 35 insertions(+), 79 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3bac38768..0052102f4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP环境防御" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "服务器网站防御程序 ${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安装防御程序" echo "------------------------" @@ -2019,11 +2011,11 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2065,28 +2057,28 @@ web_security() { ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防御程序已卸载" ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2091,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" @@ -2171,7 +2163,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,53 +3008,28 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="已安装" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="未安装" fi +} + +f2b_install_sshd() { - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf - sed -i 's/action = %(action_)s/action = iptables-multiport/g' /path/to/fail2ban/config/fail2ban/jail.conf + install fail2ban + start fail2ban + enable fail2ban } @@ -13128,17 +13094,9 @@ EOF root_use send_stats "ssh防御" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH防御程序 $check_docker" + + check_f2b_status + echo -e "SSH防御程序 $check_f2b_status" echo "fail2ban是一个SSH防止暴力破解工具" echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13154,7 +13112,6 @@ EOF read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13168,19 +13125,18 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2Ban防御程序已卸载" ;; *) break ;; esac - fi done ;; From c75027fafcd266063028681f7b9ab75f10e745d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:14:45 +0800 Subject: [PATCH 0220/1285] Update kejilion.sh --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 0052102f4..a53f913d3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2068,6 +2068,7 @@ web_security() { rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防御程序已卸载" + break ;; 11) @@ -3027,6 +3028,7 @@ check_f2b_status() { f2b_install_sshd() { + docker rm -f fail2ban >/dev/null 2>&1 install fail2ban start fail2ban enable fail2ban @@ -13132,6 +13134,7 @@ EOF remove fail2ban rm -rf /etc/fail2ban echo "Fail2Ban防御程序已卸载" + break ;; *) break From 0bef33d8b6a1d5b67a8d8a6f56b98defaab957fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:15:17 +0800 Subject: [PATCH 0221/1285] Update kejilion.sh --- cn/kejilion.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9dbe8384f..a53f913d3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -2068,6 +2068,7 @@ web_security() { rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防御程序已卸载" + break ;; 11) @@ -3027,6 +3028,7 @@ check_f2b_status() { f2b_install_sshd() { + docker rm -f fail2ban >/dev/null 2>&1 install fail2ban start fail2ban enable fail2ban @@ -13132,6 +13134,7 @@ EOF remove fail2ban rm -rf /etc/fail2ban echo "Fail2Ban防御程序已卸载" + break ;; *) break From 055e21981f3a2a54e7bbd015bf8dd86557f5fe24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:15:37 +0800 Subject: [PATCH 0222/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a53f913d3..d4060cfc3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From 286c1411eb3867e215675be86e02f22454c9e606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:17:59 +0800 Subject: [PATCH 0223/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d4060cfc3..b4061a2bf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3020,9 +3020,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="已安装" + check_f2b_status="${gl_lv}已安装${gl_bai}" else - check_f2b_status="未安装" + check_f2b_status="${gl_hui}未安装${gl_bai}" fi } From c7b465dd626c50723e488c9a9eb0f1a88663e3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:18:29 +0800 Subject: [PATCH 0224/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a53f913d3..8e49521a1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3020,9 +3020,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="已安装" + check_f2b_status="${gl_lv}已安装${gl_bai}" else - check_f2b_status="未安装" + check_f2b_status="${gl_hui}未安装${gl_bai}" fi } From 38014e60dc4f7fc96647794676ad6aff1ad1754a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:27:15 +0800 Subject: [PATCH 0225/1285] Update kejilion.sh --- cn/kejilion.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b4061a2bf..4e59e3fb6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2012,7 +2012,21 @@ web_security() { 1) f2b_install_sshd cd /etc/fail2ban/filter.d + + # 下载 fail2ban-nginx-cc.conf curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf + + # 下载 linuxserver 的 nginx 相关 filter + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf From 3baf0acec11b8e508468a34acf0776362c48cc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:27:56 +0800 Subject: [PATCH 0226/1285] Download fail2ban filter configurations Added commands to download various fail2ban filter configurations for nginx and apache. --- kejilion.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 8e49521a1..420d9ba4e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2012,7 +2012,21 @@ web_security() { 1) f2b_install_sshd cd /etc/fail2ban/filter.d + + # 下载 fail2ban-nginx-cc.conf curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf + + # 下载 linuxserver 的 nginx 相关 filter + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf From 325c6fe00d2b12c8c337a7cc559f91d72f99fa40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:41:46 +0800 Subject: [PATCH 0227/1285] Update kejilion.sh --- kejilion.sh | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 420d9ba4e..9ad6354bf 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2012,20 +2012,15 @@ web_security() { 1) f2b_install_sshd cd /etc/fail2ban/filter.d - - # 下载 fail2ban-nginx-cc.conf curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - - # 下载 linuxserver 的 nginx 相关 filter - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf - + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From 64df0f89a5fab5ce9af76bf80053e0075ba809a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:42:38 +0800 Subject: [PATCH 0228/1285] Switch from curl to wget for fail2ban config downloads Replaced curl commands with wget for downloading fail2ban filter configurations. --- cn/kejilion.sh | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4e59e3fb6..f3ad521f5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2012,20 +2012,15 @@ web_security() { 1) f2b_install_sshd cd /etc/fail2ban/filter.d - - # 下载 fail2ban-nginx-cc.conf curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - - # 下载 linuxserver 的 nginx 相关 filter - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf - + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From f1c1397823f6102e5e61fdfec975c7ef22aa0ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:48:15 +0800 Subject: [PATCH 0229/1285] Update kejilion.sh --- cn/kejilion.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3ad521f5..3cfa6eae4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2014,13 +2014,8 @@ web_security() { cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From 459392a382bc9b3fba88b3d0b6dfd7df3170a753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:48:57 +0800 Subject: [PATCH 0230/1285] Clean up wget commands in kejilion.sh Removed unnecessary wget commands for fail2ban configurations. --- kejilion.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9ad6354bf..5d218cba6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2014,13 +2014,8 @@ web_security() { cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/apache-badbots.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-botsearch.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-http-auth.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/php-url-fopen.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From 42bb99a3ae7a8f6be46876d00799bc5b461a485c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:54:32 +0800 Subject: [PATCH 0231/1285] Update kejilion.sh --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 5d218cba6..3af853806 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2016,6 +2016,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From f929319e9cbc9490db1907ae2b39ce859e005ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:55:14 +0800 Subject: [PATCH 0232/1285] Update kejilion.sh --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3cfa6eae4..0dedf1f18 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2016,6 +2016,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf From 3a7122f4f61a63c6ac8f328c348ea5ac37b05673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 15:04:48 +0800 Subject: [PATCH 0233/1285] Update kejilion.sh --- cn/kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0dedf1f18..18c85a20a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2034,28 +2034,28 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" From 0041d6d2f96e31c9ca02b9f862aff566fcda35a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 15:05:28 +0800 Subject: [PATCH 0234/1285] Update kejilion.sh --- kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3af853806..37b294ae3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2034,28 +2034,28 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" From ea18b87cfcfa950815df229e19270e3e9b05cbc2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 28 Sep 2025 08:35:44 +0000 Subject: [PATCH 0235/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-28=2008:35:44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 215 ++++++++++++++++++++++++------------------------ jp/kejilion.sh | 217 ++++++++++++++++++++++++------------------------- kr/kejilion.sh | 217 ++++++++++++++++++++++++------------------------- tw/kejilion.sh | 213 +++++++++++++++++++++++------------------------- 4 files changed, 417 insertions(+), 445 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index aa17a3682..e24ed301e 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP environment defense" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "Server website defense program${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "Server website defense program${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. Install the defense program" echo "------------------------" @@ -2019,11 +2011,16 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2037,56 +2034,57 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban defense program has been uninstalled" + break ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2097,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "Cloudflare mode is configured to view intercept records in the cf background, site-security-events" @@ -2171,7 +2169,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,52 +3014,30 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="${gl_lv}已安装${gl_bai}" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="${gl_hui}未安装${gl_bai}" fi +} + +f2b_install_sshd() { + + docker rm -f fail2ban >/dev/null 2>&1 + install fail2ban + start fail2ban + enable fail2ban - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf } f2b_sshd() { @@ -7765,7 +7740,8 @@ linux_Oracle() { 4) clear - echo "This feature is in the development stage, so stay tuned!" + send_stats "Detective R start script" + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear @@ -8384,7 +8360,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8381,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -8890,7 +8866,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step validator" echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine" + echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing point-to-point file synchronization tool" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" @@ -9499,7 +9475,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9503,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9630,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9654,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9703,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9825,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9873,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +9978,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10104,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10222,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10243,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10359,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10414,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10466,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10682,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10726,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10900,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +11984,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12085,8 +12061,34 @@ while true; do + 100|syncthing) + + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + + docker_rum() { + docker run -d \ + --name=syncthing \ + --hostname=my-syncthing \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ + syncthing/syncthing:latest + } + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; b) clear @@ -13029,7 +13031,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "Choose when to perform tasks every day? (Hours, 0-23):" hour + read -e -p "Choose what time to perform tasks every day? (Hours, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13084,7 +13086,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords for parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -13099,17 +13101,9 @@ EOF root_use send_stats "ssh defense" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH Defense Program$check_docker" + + check_f2b_status + echo -e "SSH Defense Program$check_f2b_status" echo "fail2ban is an SSH tool to prevent brute force" echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13125,7 +13119,6 @@ EOF read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13139,19 +13132,19 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2Ban defense program has been uninstalled" + break ;; *) break ;; esac - fi done ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 0a84f0c12..11e2710d0 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP環境防御" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "サーバーWebサイト防衛プログラム${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "サーバーWebサイト防衛プログラム${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1.防衛プログラムをインストールします" echo "------------------------" @@ -2019,11 +2011,16 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2037,56 +2034,57 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防衛プログラムがアンインストールされています" + break ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2097,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" @@ -2171,7 +2169,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,52 +3014,30 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="${gl_lv}已安装${gl_bai}" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="${gl_hui}未安装${gl_bai}" fi +} + +f2b_install_sshd() { + + docker rm -f fail2ban >/dev/null 2>&1 + install fail2ban + start fail2ban + enable fail2ban - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf } f2b_sshd() { @@ -7765,7 +7740,8 @@ linux_Oracle() { 4) clear - echo "この機能は開発段階にあるので、お楽しみに!" + send_stats "探偵r開始スクリプト" + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear @@ -8384,7 +8360,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8381,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -8890,7 +8866,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}DUFS Minimalist Static File Server${gl_kjlan}94. ${color94}ゴープ高速ダウンロードツール" echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2Fauth自己ホストの2段階検証装置" echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン" + echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}同期ポイントツーポイントファイル同期ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" @@ -9499,7 +9475,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9503,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9630,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9654,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9703,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9825,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9873,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +9978,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10104,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10222,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10243,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10359,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10414,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10466,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10682,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10726,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10900,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +11984,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12085,8 +12061,34 @@ while true; do + 100|syncthing) + + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + + docker_rum() { + docker run -d \ + --name=syncthing \ + --hostname=my-syncthing \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ + syncthing/syncthing:latest + } + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; b) clear @@ -12924,7 +12926,7 @@ EOF local current_hostname=$(uname -n) echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname + read -e -p "新しいホスト名を入力してください(0を入力して終了してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine @@ -13029,7 +13031,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時期を選択しますか? (時間、0-23):" hour + read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13084,7 +13086,7 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツを解析するために、キーワードを入力してください。" delhost + read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost sed -i "/$delhost/d" /etc/hosts send_stats "ローカルホストの解析と削除" ;; @@ -13099,17 +13101,9 @@ EOF root_use send_stats "SSH防御" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH防衛プログラム$check_docker" + + check_f2b_status + echo -e "SSH防衛プログラム$check_f2b_status" echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13125,7 +13119,6 @@ EOF read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13139,19 +13132,19 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2Ban防衛プログラムがアンインストールされています" + break ;; *) break ;; esac - fi done ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 7a7f37a8a..7aaf3e288 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP 환경 방어" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "서버 웹 사이트 방어 프로그램${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "서버 웹 사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" @@ -2019,11 +2011,16 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2037,56 +2034,57 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2ban 방어 프로그램은 제거되었습니다" + break ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2097,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." @@ -2171,7 +2169,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,52 +3014,30 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="${gl_lv}已安装${gl_bai}" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="${gl_hui}未安装${gl_bai}" fi +} + +f2b_install_sshd() { + + docker rm -f fail2ban >/dev/null 2>&1 + install fail2ban + start fail2ban + enable fail2ban - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf } f2b_sshd() { @@ -7765,7 +7740,8 @@ linux_Oracle() { 4) clear - echo "이 기능은 개발 단계에 있으므로 계속 지켜봐 주시기 바랍니다!" + send_stats "형사 R 스크립트 시작" + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear @@ -8384,7 +8360,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8381,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -8890,7 +8866,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}DUFS 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAUTH 자체 호스팅 2 단계 유효성 검사기" echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine" + echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" echo -e "${gl_kjlan}------------------------" @@ -9499,7 +9475,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9503,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9630,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9654,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9703,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9825,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9873,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +9978,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10104,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10222,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10243,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10359,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10414,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10466,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10682,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10726,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10900,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +11984,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12085,8 +12061,34 @@ while true; do + 100|syncthing) + + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + + docker_rum() { + docker run -d \ + --name=syncthing \ + --hostname=my-syncthing \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ + syncthing/syncthing:latest + } + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; b) clear @@ -13029,7 +13031,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할시기를 선택 하시겠습니까? (시간, 0-23) :" hour + read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13084,7 +13086,7 @@ EOF ;; 2) - read -e -p "삭제 해야하는 콘텐츠를 구문 분석하기위한 키워드를 입력하십시오." delhost + read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; @@ -13099,17 +13101,9 @@ EOF root_use send_stats "SSH 방어" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH 방어 프로그램$check_docker" + + check_f2b_status + echo -e "SSH 방어 프로그램$check_f2b_status" echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13125,7 +13119,6 @@ EOF read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13139,19 +13132,19 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2ban 방어 프로그램은 제거되었습니다" + break ;; *) break ;; esac - fi done ;; @@ -13743,7 +13736,7 @@ linux_file() { # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사하십시오" + send_stats "파일 또는 디렉토리를 복사합니다" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index b64b35045..0f24849db 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.5" +sh_v="4.1.6" gl_hui='\e[37m' @@ -1771,7 +1771,7 @@ check_waf_status() { check_cf_mode() { - if [ -f "/path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf" ]; then + if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then CFmessage=" cf模式已开启" else CFmessage="" @@ -1985,19 +1985,11 @@ nginx_gzip() { web_security() { send_stats "LDNMP環境防禦" while true; do + check_f2b_status check_waf_status check_cf_mode - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "服務器網站防禦程序${check_docker}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服務器網站防禦程序${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" @@ -2019,11 +2011,16 @@ web_security() { case $sub_choice in 1) f2b_install_sshd - cd /path/to/fail2ban/config/fail2ban/filter.d + cd /etc/fail2ban/filter.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf + wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - sed -i "/cloudflare/d" /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + sed -i "/cloudflare/d" /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status ;; 5) @@ -2037,56 +2034,57 @@ web_security() { local xxx="fail2ban-nginx-cc" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-418" + local xxx="nginx-418" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-bad-request" + local xxx="nginx-bad-request" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-badbots" + local xxx="nginx-badbots" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-botsearch" + local xxx="nginx-botsearch" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-deny" + local xxx="nginx-deny" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-http-auth" + local xxx="nginx-http-auth" f2b_status_xxx echo "------------------------" - local xxx="docker-nginx-unauthorized" + local xxx="nginx-unauthorized" f2b_status_xxx echo "------------------------" - local xxx="docker-php-url-fopen" + local xxx="php-url-fopen" f2b_status_xxx echo "------------------------" ;; 7) - docker exec -it fail2ban fail2ban-client status + fail2ban-client status ;; 8) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null echo "Fail2Ban防禦程序已卸載" + break ;; 11) install nano - nano /path/to/fail2ban/config/fail2ban/jail.d/nginx-docker-cc.conf + nano /etc/fail2ban/jail.d/nginx-docker-cc.conf f2b_status break ;; 12) - docker exec -it fail2ban fail2ban-client unban --all + fail2ban-client unban --all ;; 21) @@ -2099,14 +2097,14 @@ web_security() { wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload - cd /path/to/fail2ban/config/fail2ban/jail.d/ + cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf - cd /path/to/fail2ban/config/fail2ban/action.d + cd /etc/fail2ban/action.d curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf - sed -i "s/kejilion@outlook.com/$cfuser/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf - sed -i "s/APIKEY00000/$cftoken/g" /path/to/fail2ban/config/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/kejilion@outlook.com/$cfuser/g" /etc/fail2ban/action.d/cloudflare-docker.conf + sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" @@ -2171,7 +2169,6 @@ web_security() { break ;; esac - fi break_end done } @@ -3017,52 +3014,30 @@ tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" f2b_status() { - docker exec -it fail2ban fail2ban-client reload + fail2ban-client reload sleep 3 - docker exec -it fail2ban fail2ban-client status + fail2ban-client status } f2b_status_xxx() { - docker exec -it fail2ban fail2ban-client status $xxx + fail2ban-client status $xxx } -f2b_install_sshd() { - - docker run -d \ - --name=fail2ban \ - --net=host \ - --cap-add=NET_ADMIN \ - --cap-add=NET_RAW \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Etc/UTC \ - -e VERBOSITY=-vv \ - -v /path/to/fail2ban/config:/config \ - -v /var/log:/var/log:ro \ - -v /home/web/log/nginx/:/remotelogs/nginx:ro \ - --restart=always \ - lscr.io/linuxserver/fail2ban:latest - - sleep 3 - if grep -q 'Alpine' /etc/issue; then - cd /path/to/fail2ban/config/fail2ban/filter.d - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd.conf - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-sshd-ddos.conf - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/alpine-ssh.conf - elif command -v dnf &>/dev/null; then - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf +check_f2b_status() { + if command -v fail2ban-client >/dev/null 2>&1; then + check_f2b_status="${gl_lv}已安装${gl_bai}" else - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog - cd /path/to/fail2ban/config/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/linux-ssh.conf - systemctl restart rsyslog + check_f2b_status="${gl_hui}未安装${gl_bai}" fi +} + +f2b_install_sshd() { + + docker rm -f fail2ban >/dev/null 2>&1 + install fail2ban + start fail2ban + enable fail2ban - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf } f2b_sshd() { @@ -7765,7 +7740,8 @@ linux_Oracle() { 4) clear - echo "該功能處於開發階段,敬請期待!" + send_stats "R探長開機腳本" + bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) clear @@ -8384,7 +8360,7 @@ linux_ldnmp() { docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server @@ -8405,7 +8381,7 @@ linux_ldnmp() { install_ssltls certs_status - docker run -d --name halo --restart always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 + docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 reverse_proxy @@ -8890,7 +8866,7 @@ while true; do echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台${gl_kjlan}96. ${color96}2FAuth自託管二步驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" - echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機" + echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -9499,7 +9475,7 @@ while true; do docker_rum() { - docker run -d --name looking-glass --restart always -p ${docker_port}:80 wikihostinc/looking-glass-server + docker run -d --name looking-glass --restart=always -p ${docker_port}:80 wikihostinc/looking-glass-server } @@ -9527,7 +9503,7 @@ while true; do -p 53:53/tcp \ -p 53:53/udp \ -p ${docker_port}:3000/tcp \ - --restart always \ + --restart=always \ adguard/adguardhome @@ -9654,7 +9630,7 @@ while true; do -p ${docker_port}:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/portainer:/data \ - --restart always \ + --restart=always \ portainer/portainer } @@ -9678,7 +9654,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart always codercom/code-server + docker run -d -p ${docker_port}:8080 -v /home/docker/vscode-web:/home/coder/.local/share/code-server --name vscode-web --restart=always codercom/code-server } @@ -9727,7 +9703,7 @@ while true; do docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest } @@ -9849,7 +9825,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 --name speedtest --restart always ghcr.io/librespeed/speedtest + docker run -d -p ${docker_port}:8080 --name speedtest --restart=always ghcr.io/librespeed/speedtest } @@ -9897,7 +9873,7 @@ while true; do docker run -d \ --name photoprism \ - --restart always \ + --restart=always \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -p ${docker_port}:2342 \ @@ -10002,7 +9978,7 @@ while true; do docker run -d \ --name pingvin-share \ - --restart always \ + --restart=always \ -p ${docker_port}:3000 \ -v /home/docker/pingvin-share/data:/opt/app/backend/data \ stonith404/pingvin-share @@ -10128,7 +10104,7 @@ while true; do local docker_img="jrohy/webssh" local docker_port=8040 docker_rum() { - docker run -d -p ${docker_port}:5032 --restart always --name webssh -e TZ=Asia/Shanghai jrohy/webssh + docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } local docker_describe="简易在线ssh连接工具和sftp工具" @@ -10246,7 +10222,7 @@ while true; do --name registry \ -v /home/docker/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ - --restart always \ + --restart=always \ registry:2 } @@ -10267,7 +10243,7 @@ while true; do docker_rum() { - docker run -d --name ghproxy --restart always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest + docker run -d --name ghproxy --restart=always -p ${docker_port}:8080 -v /home/docker/ghproxy/config:/data/ghproxy/config wjqserver/ghproxy:latest } @@ -10383,7 +10359,7 @@ while true; do docker_rum() { - docker run -d --restart always -p ${docker_port}:5000 \ + docker run -d --restart=always -p ${docker_port}:5000 \ -v /home/docker/datastore:/datastore \ --name changedetection dgtlmoon/changedetection.io:latest @@ -10438,7 +10414,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10490,7 +10466,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p ${docker_port}:8080 -v /home/docker/ollama:/root/.ollama -v /home/docker/ollama/open-webui:/app/backend/data --name ollama --restart=always ghcr.io/open-webui/open-webui:ollama } @@ -10706,7 +10682,7 @@ while true; do docker_rum() { - docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p ${docker_port}:8080 -v /home/docker/open-webui:/app/backend/data --name open-webui --restart=always ghcr.io/open-webui/open-webui:main } @@ -10750,7 +10726,7 @@ while true; do chmod -R 777 /home/docker/n8n docker run -d --name n8n \ - --restart always \ + --restart=always \ -p ${docker_port}:5678 \ -v /home/docker/n8n:/home/node/.n8n \ -e N8N_HOST=${yuming} \ @@ -10924,7 +10900,7 @@ while true; do docker run -d \ --name bitwarden \ - --restart always \ + --restart=always \ -p ${docker_port}:80 \ -v /home/docker/bitwarden/data:/data \ vaultwarden/server @@ -12008,7 +11984,7 @@ while true; do --cap-add SYS_MODULE \ -v /home/docker/wireguard/config:/config \ -v /lib/modules:/lib/modules:ro \ - --restart always \ + --restart=always \ kjlion/wireguard:alpine sleep 3 @@ -12085,8 +12061,34 @@ while true; do + 100|syncthing) + + local app_id="100" + local docker_name="syncthing" + local docker_img="syncthing/syncthing:latest" + local docker_port=8100 + + docker_rum() { + docker run -d \ + --name=syncthing \ + --hostname=my-syncthing \ + --restart=always \ + -p ${docker_port}:8384 \ + -p 22000:22000/tcp \ + -p 22000:22000/udp \ + -p 21027:21027/udp \ + -v /home/docker/syncthing:/var/syncthing \ + syncthing/syncthing:latest + } + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; b) clear @@ -13099,17 +13101,9 @@ EOF root_use send_stats "ssh防禦" while true; do - if [ -x "$(command -v fail2ban-client)" ] ; then - clear - remove fail2ban - rm -rf /etc/fail2ban - else - clear - rm -f /path/to/fail2ban/config/fail2ban/jail.d/sshd.conf > /dev/null 2>&1 - docker exec -it fail2ban fail2ban-client reload > /dev/null 2>&1 - docker_name="fail2ban" - check_docker_app - echo -e "SSH防禦程序$check_docker" + + check_f2b_status + echo -e "SSH防禦程序$check_f2b_status" echo "fail2ban是一個SSH防止暴力破解工具" echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13125,7 +13119,6 @@ EOF read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - install_docker f2b_install_sshd cd ~ @@ -13139,19 +13132,19 @@ EOF break_end ;; 3) - tail -f /path/to/fail2ban/config/log/fail2ban/fail2ban.log + tail -f /var/log/fail2ban.log break ;; 9) - docker rm -f fail2ban - rm -rf /path/to/fail2ban + remove fail2ban + rm -rf /etc/fail2ban echo "Fail2Ban防禦程序已卸載" + break ;; *) break ;; esac - fi done ;; @@ -14222,7 +14215,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夾 k fav | k 命令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" -echo "顯示系統信息 k info" +echo "顯示系統信息 k info" } From dba36b8f1e7036c806e3d4ff2dda556faf9ebdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 17:50:03 +0800 Subject: [PATCH 0236/1285] Update kejilion.sh --- cn/kejilion.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 18c85a20a..79d57ea43 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if grep -q 'dnf' /etc/issue; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { From 5a189e54f2f948c93618644d414e1c810f67ff10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 17:50:33 +0800 Subject: [PATCH 0237/1285] Download fail2ban config for DNF systems Add support for downloading fail2ban config on DNF-based systems. --- kejilion.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 37b294ae3..896fa5c24 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if grep -q 'dnf' /etc/issue; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { From 5dc799c636608d04eacf4ea35109431c7977c160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:19:15 +0800 Subject: [PATCH 0238/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 79d57ea43..79a62619a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3038,7 +3038,7 @@ f2b_install_sshd() { start fail2ban enable fail2ban - if grep -q 'dnf' /etc/issue; then + if command -v dnf &>/dev/null; then cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi From f0e428842d0fed6b33996cd2806ce6e73d1f0611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:20:02 +0800 Subject: [PATCH 0239/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 896fa5c24..6701921b6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3038,7 +3038,7 @@ f2b_install_sshd() { start fail2ban enable fail2ban - if grep -q 'dnf' /etc/issue; then + if command -v dnf &>/dev/null; then cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi From d3e26cd1eb7e9665b268a42ae78d356dfaa42ca6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 28 Sep 2025 10:53:38 +0000 Subject: [PATCH 0240/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-09-28=2010:53:38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 11 ++++++++--- jp/kejilion.sh | 11 ++++++++--- kr/kejilion.sh | 9 +++++++-- tw/kejilion.sh | 5 +++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index e24ed301e..322c45f41 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1733,7 +1733,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to the mode parameter + # Decide to turn on or off WAF according to mode parameters if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if command -v dnf &>/dev/null; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { @@ -5946,7 +5951,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can be connected to other Linux systems via SSH" + echo "Can connect to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -8017,7 +8022,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "Backend login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 11e2710d0..c93e5aea8 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1733,7 +1733,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることにしました + # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if command -v dnf &>/dev/null; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { @@ -8017,7 +8022,7 @@ linux_ldnmp() { echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "バックエンドログインパス: /admin" echo "------------------------" echo "ユーザー名:admin" echo "パスワード:管理者" @@ -12926,7 +12931,7 @@ EOF local current_hostname=$(uname -n) echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(0を入力して終了してください):" new_hostname + read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 7aaf3e288..b7d69c906 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if command -v dnf &>/dev/null; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { @@ -8017,7 +8022,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "백엔드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 0f24849db..05b2db1f1 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -3038,6 +3038,11 @@ f2b_install_sshd() { start fail2ban enable fail2ban + if command -v dnf &>/dev/null; then + cd /etc/fail2ban/jail.d/ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + fi + } f2b_sshd() { From 7efb2cfe29b8cc7080326eca4bd2f44736d08900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:05:17 +0800 Subject: [PATCH 0241/1285] Update kejilion.sh --- cn/kejilion.sh | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 79a62619a..148e46055 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -12095,6 +12097,50 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/docker/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + + b) clear send_stats "全部应用备份" From f1e594cd504fe243a96dfb922ec39f22f6560308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:05:57 +0800 Subject: [PATCH 0242/1285] Add MoneyPrinterTurbo app management to kejilion.sh Added AI video generation tool 'MoneyPrinterTurbo' installation and management functions. --- kejilion.sh | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 6701921b6..3fa89fa06 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -12095,6 +12097,50 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/docker/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + + b) clear send_stats "全部应用备份" From d301b258a59d8d1f4463f87d8285c1ffc2dc1fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:08:29 +0800 Subject: [PATCH 0243/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 79b60d8d2..4d4cd9af9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1314,4 +1314,7 @@ k快捷命令增加了 k info 系统信息快速查询。 甲骨文云合集中增加大佬的R探长开机脚本,非常感谢大佬脚本。 又来修复SSH防御fail2ban加载ssh规则报错的问题。 ------------------------ +2025-09-30 v4.1.7 +应用市场新增了MoneyPrinterTurbo视频生成器的安装及使用。 +------------------------ From c85d75247fe079b9b761d2cd01cc17c3f918e96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:03:35 +0800 Subject: [PATCH 0244/1285] Update kejilion.sh --- cn/kejilion.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 148e46055..9716db4db 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}AZ/AWS/OCI管理面板" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12119,7 +12119,7 @@ while true; do } docker_app_update() { - cd /home/docker/MoneyPrinterTurbo/docker/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ git pull origin main sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml @@ -12138,6 +12138,59 @@ while true; do + 102|cloud-manager) + local app_id="102" + local app_name="AZ/AWS/OCI管理面板" + local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" + local app_url="官方网站: https://github.com/SIJULY/cloud_manager" + local docker_name="caddy" + local docker_port="8102" + local app_size="1" + + docker_app_install() { + + + read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} + + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/SIJULY/cloud_manager.git && cd cloud_manager/ + sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml + sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml + cp .env.example .env + sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/cloud_manager/ && docker compose down --rmi all + cd /home/docker/cloud_manager/ + git pull origin main + + read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} + + sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml + sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml + cp .env.example .env + sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + + cd /home/docker/cloud_manager/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/cloud_manager/ && docker compose down --rmi all + rm -rf /home/docker/cloud_manager + echo "应用已卸载" + } + + docker_app_plus + + ;; From fa213cc75a9c997bbcbb7515dbe67b214b400005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:04:08 +0800 Subject: [PATCH 0245/1285] Update kejilion.sh --- kejilion.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3fa89fa06..21067e8b8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}AZ/AWS/OCI管理面板" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12119,7 +12119,7 @@ while true; do } docker_app_update() { - cd /home/docker/MoneyPrinterTurbo/docker/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ git pull origin main sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml @@ -12138,6 +12138,59 @@ while true; do + 102|cloud-manager) + local app_id="102" + local app_name="AZ/AWS/OCI管理面板" + local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" + local app_url="官方网站: https://github.com/SIJULY/cloud_manager" + local docker_name="caddy" + local docker_port="8102" + local app_size="1" + + docker_app_install() { + + + read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} + + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/SIJULY/cloud_manager.git && cd cloud_manager/ + sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml + sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml + cp .env.example .env + sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/cloud_manager/ && docker compose down --rmi all + cd /home/docker/cloud_manager/ + git pull origin main + + read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} + + sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml + sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml + cp .env.example .env + sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + + cd /home/docker/cloud_manager/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/cloud_manager/ && docker compose down --rmi all + rm -rf /home/docker/cloud_manager + echo "应用已卸载" + } + + docker_app_plus + + ;; From 35faef138bc9186c749a1f06dfa244fd3437c795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:05:38 +0800 Subject: [PATCH 0246/1285] Add installation instructions for AZ/AWS/OCI panel --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4d4cd9af9..941d420d7 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1316,5 +1316,6 @@ k快捷命令增加了 k info 系统信息快速查询。 ------------------------ 2025-09-30 v4.1.7 应用市场新增了MoneyPrinterTurbo视频生成器的安装及使用。 +应用市场新增了AZ/AWS/OCI开机管理面板的安装及使用。 ------------------------ From 56a15891463d2e4479dd0681091c9ca76351bbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:09:14 +0800 Subject: [PATCH 0247/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 21067e8b8..d34b6cc95 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12143,7 +12143,7 @@ while true; do local app_name="AZ/AWS/OCI管理面板" local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" local app_url="官方网站: https://github.com/SIJULY/cloud_manager" - local docker_name="caddy" + local docker_name="cloud_manager-caddy-1" local docker_port="8102" local app_size="1" From 1fc84c37e18773b0a5ab5d2a9c727f00a15e1876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:09:49 +0800 Subject: [PATCH 0248/1285] Rename docker_name for cloud manager setup --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9716db4db..567786e8a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12143,7 +12143,7 @@ while true; do local app_name="AZ/AWS/OCI管理面板" local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" local app_url="官方网站: https://github.com/SIJULY/cloud_manager" - local docker_name="caddy" + local docker_name="cloud_manager-caddy-1" local docker_port="8102" local app_size="1" From 89c4745c587f1097b1b24e8d4433c724a0056895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:22:46 +0800 Subject: [PATCH 0249/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 567786e8a..981211dfd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # 用循环设置颜色 - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -12150,7 +12150,7 @@ while true; do docker_app_install() { - read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + read -e -p "设置面板登录密码 (默认 123ADMIN123): " LOGIN_PASSWD local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} install git From 8bbf807ab68d47904d1a6b2cbda15bb23f310a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:23:27 +0800 Subject: [PATCH 0250/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d34b6cc95..1ddb3d02b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # 用循环设置颜色 - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -12150,7 +12150,7 @@ while true; do docker_app_install() { - read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD + read -e -p "设置面板登录密码 (默认 123ADMIN123): " LOGIN_PASSWD local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} install git From 0b4047ca0e58dba6c573412ecf4d9fe8b285abc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:43:34 +0800 Subject: [PATCH 0251/1285] Update kejilion.sh --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 981211dfd..2c2de8207 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12159,6 +12159,7 @@ while true; do sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml cp .env.example .env sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + sed -i "s|your.domain.com|${ipv4_address}|" .env docker compose up -d clear From 991e40980a10015541a44ad8593f2a8d8a06350a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:44:06 +0800 Subject: [PATCH 0252/1285] Update .env with actual IPv4 address Replace placeholder domain with actual IPv4 address in .env file. --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 1ddb3d02b..5e35e70d9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12159,6 +12159,7 @@ while true; do sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml cp .env.example .env sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env + sed -i "s|your.domain.com|${ipv4_address}|" .env docker compose up -d clear From 241b5acc280f2d55d504427f995ee54e63f0db8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:02:20 +0800 Subject: [PATCH 0253/1285] Update kejilion.sh --- kejilion.sh | 55 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 5e35e70d9..18146005d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}AZ/AWS/OCI管理面板" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12138,58 +12138,7 @@ while true; do - 102|cloud-manager) - local app_id="102" - local app_name="AZ/AWS/OCI管理面板" - local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" - local app_url="官方网站: https://github.com/SIJULY/cloud_manager" - local docker_name="cloud_manager-caddy-1" - local docker_port="8102" - local app_size="1" - - docker_app_install() { - - - read -e -p "设置面板登录密码 (默认 123ADMIN123): " LOGIN_PASSWD - local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} - - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/SIJULY/cloud_manager.git && cd cloud_manager/ - sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml - sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml - cp .env.example .env - sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env - sed -i "s|your.domain.com|${ipv4_address}|" .env - - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/cloud_manager/ && docker compose down --rmi all - cd /home/docker/cloud_manager/ - git pull origin main - - read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD - local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} - - sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml - sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml - cp .env.example .env - sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env - - cd /home/docker/cloud_manager/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/cloud_manager/ && docker compose down --rmi all - rm -rf /home/docker/cloud_manager - echo "应用已卸载" - } - - docker_app_plus + 102) ;; From 5ca6f7508371c9e7c71ac76de0962efec3e7ca8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:04:01 +0800 Subject: [PATCH 0254/1285] Remove cloud manager app management functions Removed cloud manager application installation, update, and uninstall functions. --- cn/kejilion.sh | 55 ++------------------------------------------------ 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2c2de8207..62e36f213 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}AZ/AWS/OCI管理面板" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12138,58 +12138,7 @@ while true; do - 102|cloud-manager) - local app_id="102" - local app_name="AZ/AWS/OCI管理面板" - local app_text="整合AZ微软云,AWS亚马逊云,OCI甲骨文云一体化管理工具" - local app_url="官方网站: https://github.com/SIJULY/cloud_manager" - local docker_name="cloud_manager-caddy-1" - local docker_port="8102" - local app_size="1" - - docker_app_install() { - - - read -e -p "设置面板登录密码 (默认 123ADMIN123): " LOGIN_PASSWD - local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} - - install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/SIJULY/cloud_manager.git && cd cloud_manager/ - sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml - sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml - cp .env.example .env - sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env - sed -i "s|your.domain.com|${ipv4_address}|" .env - - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip - } - - docker_app_update() { - cd /home/docker/cloud_manager/ && docker compose down --rmi all - cd /home/docker/cloud_manager/ - git pull origin main - - read -e -p "设置面板登录密码 (默认 123ADMIN123)" LOGIN_PASSWD - local LOGIN_PASSWD=${LOGIN_PASSWD:-123ADMIN123} - - sed -i "s/80:80/${docker_port}:80/g" /home/docker/cloud_manager/docker-compose.yml - sed -i "/443:443/d" /home/docker/cloud_manager/docker-compose.yml - cp .env.example .env - sed -i "s|PANEL_PASSWORD=YourSecurePassword123|PANEL_PASSWORD=$LOGIN_PASSWD|" .env - - cd /home/docker/cloud_manager/ && docker compose up -d - } - - docker_app_uninstall() { - cd /home/docker/cloud_manager/ && docker compose down --rmi all - rm -rf /home/docker/cloud_manager - echo "应用已卸载" - } - - docker_app_plus + 102) ;; From 1ef08e61a50b05a0c30d9ef95bfd50d08dd40cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:05:09 +0800 Subject: [PATCH 0255/1285] Update kejilion_sh_log.txt by removing a line Removed mention of AZ/AWS/OCI management panel installation from the log. --- kejilion_sh_log.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 941d420d7..4d4cd9af9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1316,6 +1316,5 @@ k快捷命令增加了 k info 系统信息快速查询。 ------------------------ 2025-09-30 v4.1.7 应用市场新增了MoneyPrinterTurbo视频生成器的安装及使用。 -应用市场新增了AZ/AWS/OCI开机管理面板的安装及使用。 ------------------------ From 4bd93f5786ee1a81bcfd24e8a91335086285d2c0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 5 Oct 2025 04:27:02 +0000 Subject: [PATCH 0256/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-05=2004:27:02?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++----- jp/kejilion.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++---- kr/kejilion.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++----- tw/kejilion.sh | 53 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 212 insertions(+), 16 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 322c45f41..126e184bd 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -1733,7 +1733,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to mode parameters + # Decide to turn on or off WAF according to the mode parameter if [ "$mode" == "on" ]; then # Turn on WAF: Remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -5951,7 +5951,7 @@ ssh_manager() { while true; do clear echo "SSH Remote Connection Tool" - echo "Can connect to other Linux systems via SSH" + echo "Can be connected to other Linux systems via SSH" echo "------------------------" list_connections echo "1. Create a new connection 2. Use a connection 3. Delete a connection" @@ -8022,7 +8022,7 @@ linux_ldnmp() { echo "Redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Backend login path: /admin" + echo "Background login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # Set the color with loop - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing point-to-point file synchronization tool" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AI video generation tool" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -12095,6 +12097,53 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "Installed" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "The app has been uninstalled" + } + + docker_app_plus + + ;; + + + + 102) + + ;; + + + b) clear send_stats "All applications backup" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index c93e5aea8..f72c82993 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -1733,7 +1733,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることを決定します + # モードパラメーターに従ってWAFをオンまたはオフにすることにしました if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -8022,7 +8022,7 @@ linux_ldnmp() { echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックエンドログインパス: /admin" + echo "バックグラウンドログインパス: /admin" echo "------------------------" echo "ユーザー名:admin" echo "パスワード:管理者" @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # ループで色を設定します - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}同期ポイントツーポイントファイル同期ツール" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AIビデオ生成ツール" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" @@ -12095,6 +12097,53 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "インストール" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "アプリはアンインストールされています" + } + + docker_app_plus + + ;; + + + + 102) + + ;; + + + b) clear send_stats "すべてのアプリケーションバックアップ" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b7d69c906..a693df95d 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! # 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -1657,7 +1657,7 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트하십시오 + # 캐시 청소 여부를 사용자에게 프롬프트합니다 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" @@ -8022,7 +8022,7 @@ linux_ldnmp() { echo "Redis Port : 6379" echo "" echo "웹 사이트 URL : https : //$yuming" - echo "백엔드 로그인 경로 : /admin" + echo "백그라운드 로그인 경로 : /admin" echo "------------------------" echo "사용자 이름 : 관리자" echo "비밀번호 : 관리자" @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # 루프로 색상을 설정하십시오 - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AI 비디오 생성 도구" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" @@ -12095,6 +12097,53 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "설치" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "앱이 제거되었습니다" + } + + docker_app_plus + + ;; + + + + 102) + + ;; + + + b) clear send_stats "모든 응용 프로그램 백업" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 05b2db1f1..5ee2d1c24 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.6" +sh_v="4.1.7" gl_hui='\e[37m' @@ -8805,7 +8805,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") # 用循環設置顏色 - for i in {1..100}; do + for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" else @@ -8873,6 +8873,8 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" @@ -12095,6 +12097,53 @@ while true; do ;; + + 101|moneyprinterturbo) + local app_id="101" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local docker_name="moneyprinterturbo" + local docker_port="8101" + local app_size="3" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + cd /home/docker/MoneyPrinterTurbo/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml + cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all + rm -rf /home/docker/MoneyPrinterTurbo + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + 102) + + ;; + + + b) clear send_stats "全部應用備份" From ac7da25ef7012b7d8a5c2cfdcdabb0df68fdf994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:06:34 +0800 Subject: [PATCH 0257/1285] Update kejilion.sh --- cn/kejilion.sh | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 62e36f213..0fb6077be 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; From c65d48898199075486fa78bf4c28c8469c09c517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:06:59 +0800 Subject: [PATCH 0258/1285] Update version and add VoceChat server setup --- kejilion.sh | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 18146005d..e1b27b425 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; From 251be4795528ea92698fdb0703cbec3e9c545ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:33:38 +0800 Subject: [PATCH 0259/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4d4cd9af9..a1a777973 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1317,4 +1317,8 @@ k快捷命令增加了 k info 系统信息快速查询。 2025-09-30 v4.1.7 应用市场新增了MoneyPrinterTurbo视频生成器的安装及使用。 ------------------------ +2025-10-06 v4.1.8 +应用市场FileCodeBox文件快递增加管理员入口的提示路径与密码。 +应用市场新增了VoceChat多人聊天系统的安装及使用。 +------------------------ From 45f451190f3d5e68a68a30b4b8d3ae1ae24ca15f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 7 Oct 2025 00:00:43 +0000 Subject: [PATCH 0260/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-07=2000:00:43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 258 +++++++++++++----------- jp/kejilion.sh | 534 +++++++++++++++++++++++++------------------------ kr/kejilion.sh | 460 ++++++++++++++++++++++-------------------- tw/kejilion.sh | 32 ++- 4 files changed, 686 insertions(+), 598 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 126e184bd..d29734073 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -315,7 +315,7 @@ stop() { status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1The service status is displayed." + echo "$1Service status is shown." else echo "Error: Unable to display$1Service status." fi @@ -667,7 +667,7 @@ while true; do send_stats "Update the image" read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}Updated image:$name${gl_bai}" + echo -e "${gl_huang}Updating image:$name${gl_bai}" docker pull $name done ;; @@ -950,7 +950,7 @@ allow_ip() { # Delete existing blocking rules iptables -D INPUT -s $ip -j DROP 2>/dev/null - # Add allow rules + # Add allow rule if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "Released IP$ip" @@ -1017,14 +1017,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "Turn off DDoS Defense" + send_stats "Turn off DDoS defense" } -# Functions that manage national IP rules +# Functions to manage national IP rules manage_country_rules() { local action="$1" shift # 去掉第一个参数,剩下的全是国家代码 @@ -1112,7 +1112,7 @@ iptables_panel() { while true; do clear echo "Advanced Firewall Management" - send_stats "Advanced Firewall Management" + send_stats "Advanced firewall management" echo "------------------------" iptables -L INPUT echo "" @@ -1138,12 +1138,12 @@ iptables_panel() { 1) read -e -p "Please enter the open port number:" o_port open_port $o_port - send_stats "Open a specified port" + send_stats "Open specified port" ;; 2) read -e -p "Please enter the closed port number:" c_port close_port $c_port - send_stats "Close the specified port" + send_stats "Close specified port" ;; 3) # Open all ports @@ -1231,7 +1231,7 @@ iptables_panel() { 17) read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces such as CN US JP):" country_code manage_country_rules unblock $country_code - send_stats "Clear the country$country_codeIP" + send_stats "clear country$country_codeIP" ;; *) @@ -1312,7 +1312,7 @@ ldnmp_v() { local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # Get the mysql version + # Get mysql version local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" @@ -1699,7 +1699,7 @@ web_del() { send_stats "Delete site data" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "To delete site data, please enter your domain name (multiple domain names are separated by spaces):" yuming_list + read -e -p "To delete site data, please enter your domain name (separate multiple domain names with spaces):" yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1716,7 +1716,7 @@ web_del() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # Check whether the database exists before deleting it to avoid errors + # Check whether the database exists before deleting it to avoid errors. echo "Deleting the database:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1938,7 +1938,7 @@ nginx_zstd() { else - echo "Invalid parameter: Use 'on' or 'off'" + echo "Invalid argument: use 'on' or 'off'" return 1 fi @@ -2007,7 +2007,7 @@ web_security() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2092,7 +2092,7 @@ web_security() { echo "Go to the upper right corner of the cf background, select the API token on the left, and obtain the Global API Key" echo "https://dash.cloudflare.com/login" read -e -p "Enter CF account number:" cfuser - read -e -p "Enter the Global API Key for CF:" cftoken + read -e -p "Enter CF’s Global API Key:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2540,7 +2540,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules for releasing the specified IP + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2559,7 +2559,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules for releasing the specified IP + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2616,7 +2616,7 @@ block_host_port() { - # Denied all other IP access + # Deny access from all other IPs if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi @@ -2649,7 +2649,7 @@ clear_host_port_rules() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "Error: Please provide the port number and the IP that is allowed to access." - echo "Usage: clear_host_port_rules " + echo "Usage: clear_host_port_rules " return 1 fi @@ -2677,7 +2677,7 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # Clear rules that allow native access + # Clear rules that allow local access if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2895,7 +2895,7 @@ docker_app_plus() { ;; 5) - echo "${docker_name}Domain access settings" + echo "${docker_name}Domain name access settings" send_stats "${docker_name}Domain access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -3000,7 +3000,7 @@ session_exists() { tmux has-session -t $1 2>/dev/null } -# Loop until a non-existent session name is found +# Loop until a non-existing session name is found while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done @@ -3287,7 +3287,7 @@ ldnmp_Proxy_backend() { fi if [ -z "$reverseproxy_port" ]; then - read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "Please enter your multiple anti-generation IP+ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3795,7 +3795,7 @@ generate_access_urls() { # Get all ports first get_frp_ports - # Check if there are ports other than 8055/8056 + # Check if there is a port other than 8055/8056 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3824,7 +3824,7 @@ generate_access_urls() { done fi - # Handling HTTPS configuration + # Handle HTTPS configuration for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3929,8 +3929,8 @@ frps_panel() { 8) send_stats "Block IP access" - echo "If you have accessed the anti-generation domain name, you can use this function to block IP+ port access, which is more secure." - read -e -p "Please enter the port you need to block:" frps_port + echo "If you have reversed domain name access, you can use this function to block IP+port access, which is safer." + read -e -p "Please enter the port to be blocked:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3958,7 +3958,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP Client$check_frp $update_status" - echo "Docking with the server, after docking, you can create intranet penetration service to the Internet access" + echo "Connect with the server. After the connection, you can create an intranet penetration service to access the Internet." echo "Official website introduction: https://github.com/fatedier/frp/" echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4128,7 +4128,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "After the execution is completed, press any key to continue..." ;; + read -e -p "Execution completed, press any key to continue..." ;; 8) send_stats "MP3 download" read -e -p "Please enter the video link:" url @@ -4267,7 +4267,7 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "Delete the system log..." + echo "Delete system log..." rm -rf /var/log/* echo "Delete temporary files..." rm -rf /tmp/* @@ -4560,7 +4560,7 @@ dd_xitong() { root_use echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." + echo -e "${gl_hong}Notice:${gl_bai}Reinstallation may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." echo -e "${gl_hui}Thanks to the script support of leitbogioro and bin456789!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" @@ -4971,7 +4971,7 @@ elrepo_install() { # Import ELRepo GPG public key echo "Import the ELRepo GPG public key..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # Detect system version + # Check system version local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) # Make sure we run on a supported operating system @@ -5135,7 +5135,7 @@ clamav_scan() { clamav() { root_use - send_stats "Virus Scan Management" + send_stats "Virus scan management" while true; do clear echo "clamav virus scanning tool" @@ -5260,7 +5260,7 @@ optimize_balanced() { sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Restore transparent page + # Restore transparent huge pages echo always > /sys/kernel/mm/transparent_hugepage/enabled # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5268,7 +5268,7 @@ optimize_balanced() { } -# Restore the default settings function +# Restore default settings function restore_defaults() { echo -e "${gl_lv}Restore to default settings...${gl_bai}" @@ -5282,7 +5282,7 @@ restore_defaults() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}Restore network settings...${gl_bai}" + echo -e "${gl_lv}Reset network settings...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,7 +5301,7 @@ restore_defaults() { sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}Restore other optimizations...${gl_bai}" - # Restore transparent page + # Restore transparent huge pages echo always > /sys/kernel/mm/transparent_hugepage/enabled # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5630,7 +5630,7 @@ linux_trash() { read -e -p "Enter the file name to restore:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreRestored to the home directory." + echo "$file_to_restoreRestored to home directory." else echo "The file does not exist." fi @@ -5716,7 +5716,7 @@ create_backup() { restore_backup() { send_stats "Restore backup" # Select the backup you want to restore - read -e -p "Please enter the backup file name to restore:" BACKUP_NAME + read -e -p "Please enter the backup file name to be restored:" BACKUP_NAME # Check if the backup file exists if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -5837,7 +5837,7 @@ add_connection() { echo "Please paste the key content (press press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # If the input is empty and the key content already contains the beginning, the input ends + # If the input is a blank line and the key content already contains the beginning, end the input if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -5909,7 +5909,7 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "Connection failed! Please check the following:" echo "1. Is the key file path correct?$password_or_key" - echo "2. Whether the key file permissions are correct (should be 600)." + echo "2. Are the key file permissions correct (should be 600)." echo "3. Whether the target server allows login using the key." fi else @@ -6007,7 +6007,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # Mount the partition + # Mount partition mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6050,7 +6050,7 @@ list_mounted_partitions() { # Format partition format_partition() { send_stats "Format partition" - read -e -p "Please enter the partition name to format (for example, sda1):" PARTITION + read -e -p "Please enter the name of the partition to be formatted (e.g. sda1):" PARTITION # Check if the partition exists if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then @@ -6335,7 +6335,7 @@ run_task() { # Create a timed task schedule_task() { - send_stats "Add synchronization timing tasks" + send_stats "Add synchronization scheduled tasks" read -e -p "Please enter the task number to be synchronized regularly:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6367,7 +6367,7 @@ schedule_task() { return fi - # Create a crontab to the user + # Create to user's crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - echo "The timing task has been created:$cron_job" } @@ -6380,7 +6380,7 @@ view_tasks() { echo "---------------------------------" } -# Delete timing tasks +# Delete scheduled tasks delete_task_schedule() { send_stats "Delete synchronization timing tasks" read -e -p "Please enter the task number to delete:" num @@ -6492,7 +6492,7 @@ linux_info() { echo "" echo -e "System information query" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Host Name:${gl_bai}$hostname" + echo -e "${gl_kjlan}Hostname:${gl_bai}$hostname" echo -e "${gl_kjlan}System version:${gl_bai}$os_info" echo -e "${gl_kjlan}Linux version:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" @@ -6507,7 +6507,7 @@ linux_info() { echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" echo -e "${gl_kjlan}Hard disk occupation:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" + echo -e "${gl_kjlan}Total received:${gl_bai}$rx" echo -e "${gl_kjlan}Total send:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" @@ -6804,7 +6804,7 @@ linux_bbr() { echo "Current TCP blocking algorithm:$congestion_algorithm $queue_algorithm" echo "" - echo "BBR Management" + echo "BBR management" echo "------------------------" echo "1. Turn on BBRv3 2. Turn off BBRv3 (restarts)" echo "------------------------" @@ -6913,7 +6913,7 @@ docker_ssh_migration() { # If the Compose project has been packaged, skip it if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" + echo -e "${YELLOW}Compose project [$project_name] Already backed up, skip repeated packaging...${NC}" continue fi @@ -6998,7 +6998,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "The original path was not found, please enter the restore directory path:" original_path - # Check if the container for the compose project is already running + # Check whether the container of the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" @@ -7051,7 +7051,7 @@ docker_ssh_migration() { ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # Volume Mapping + Volume Data Recovery + # Volume mapping + volume data recovery VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7112,7 +7112,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transfer backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with a key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7664,7 +7664,7 @@ linux_Oracle() { local DEFAULT_SPEEDTEST_INTERVAL=120 # Prompt the user to enter the number of CPU cores and occupancy percentage, and if entered, use the default value. - read -e -p "Please enter the number of CPU cores [default:$DEFAULT_CPU_CORE]: " cpu_core + read -e -p "Please enter the number of CPU cores [Default:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "Please enter the CPU usage percentage range (for example, 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util @@ -7844,13 +7844,13 @@ linux_ldnmp() { echo -e "${gl_huang}7. ${gl_bai}Install the flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Customize dynamic site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" + echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}site redirect" echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" echo -e "${gl_huang}30. ${gl_bai}Customize static site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up the entire site data" + echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" echo -e "${gl_huang}33. ${gl_bai}Timed remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environment${gl_huang}36. ${gl_bai}Optimize LDNMP environment" @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -8027,7 +8027,7 @@ linux_ldnmp() { echo "Username: admin" echo "Password: admin" echo "------------------------" - echo "If red error0 appears in the upper right corner when logging in, please use the following command:" + echo "If a red error0 appears in the upper right corner when logging in, please use the following command:" echo "I am also very angry that the unicorn number card is so troublesome, and there will be such problems!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8237,7 +8237,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}5/6${gl_bai}] Edit site configuration" echo "-------------" - echo "Press any key to continue, and you can set the site configuration in detail, such as pseudo-static contents, etc." + echo "Press any key to continue. You can set the site configuration in detail, such as pseudo-static content." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf @@ -8500,7 +8500,7 @@ linux_ldnmp() { while true; do clear - echo "The backup file has been created: /home/$backup_filename" + echo "Backup file created: /home/$backup_filename" read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) @@ -8552,7 +8552,7 @@ linux_ldnmp() { case $dingshi in 1) check_crontab_installed - read -e -p "Select the day of the week for your weekly backup (0-6, 0 represents Sunday):" weekday + read -e -p "Select the day of the week for weekly backup (0-6, 0 represents Sunday):" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) @@ -8624,7 +8624,7 @@ linux_ldnmp() { echo "Update LDNMP environment" echo "------------------------" ldnmp_v - echo "Discover new version of components" + echo "New version of component found" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8813,9 +8813,9 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel International Edition" + echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel International Edition" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager Visual Panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" echo -e "${gl_kjlan}------------------------" @@ -8826,7 +8826,7 @@ while true; do echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" - echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop Remote Desktop Web Edition${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop remote desktop web version${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" @@ -8841,12 +8841,12 @@ while true; do echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub Acceleration Station${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}Prometheus Monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" + echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}51. ${color51}PVE Chicken Panel${gl_kjlan}52. ${color52}DPanel Container Management Panel" echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify large model knowledge base${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing point-to-point file synchronization tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI video generation tool" + echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" @@ -9187,7 +9187,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "Please set the email domain name, for example, mail.yuming.com:" yuming + read -e -p "Please set the email domain name, for example mail.yuming.com:" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -9577,7 +9577,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -10072,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya Family Bucket" + send_stats "Xiaoya family bucket" clear install_docker check_disk_space 1 @@ -11001,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11205,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # Keep the original variable + # Keep original variables source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11272,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -11634,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11955,7 +11955,7 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # Create a directory (if it does not exist) + # Create directory if it does not exist mkdir -p "$(dirname "$CONFIG_FILE")" echo "Please paste your client configuration and press Enter twice in a row to save:" @@ -12129,7 +12129,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; @@ -12210,7 +12232,7 @@ while true; do cd / && tar -xzf "$filename" echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." else - echo "No compression package was found." + echo "No compressed package found." fi ;; @@ -12248,7 +12270,7 @@ linux_work() { echo -e "${gl_kjlan}3. ${gl_bai}Workspace No. 3" echo -e "${gl_kjlan}4. ${gl_bai}Workspace No. 4" echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" - echo -e "${gl_kjlan}6. ${gl_bai}Workspace No. 6" + echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" echo -e "${gl_kjlan}8. ${gl_bai}Workspace No. 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" @@ -12291,7 +12313,7 @@ linux_work() { clear install tmux local SESSION_NAME="work4" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 5) @@ -12347,7 +12369,7 @@ linux_work() { fi send_stats "SSH resident mode" echo -e "SSH resident mode${tmux_sshd_status}" - echo "After SSH connection is enabled, it will directly enter the resident mode and return to the previous working state." + echo "After opening the SSH connection, it will directly enter the resident mode and return directly to the previous working state." echo "------------------------" echo "1. Turn on 2. Turn off" echo "------------------------" @@ -12425,9 +12447,9 @@ linux_Settings() { # send_stats "System Tools" echo -e "System Tools" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Modify the login password" + echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Change login password" echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" - echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify the SSH connection port" + echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}One-click reinstallation system${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account to create a new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -12444,12 +12466,12 @@ linux_Settings() { echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tool${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}File Manager" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Switch system language${gl_kjlan}32. ${gl_bai}Command line beautification tool${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Set up a system recycling bin${gl_kjlan}34. ${gl_bai}System backup and recovery" + echo -e "${gl_kjlan}33. ${gl_bai}Set up system recycle bin${gl_kjlan}34. ${gl_bai}System backup and recovery" echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system tuning${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and Security" echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" echo -e "${gl_kjlan}------------------------" @@ -12573,7 +12595,7 @@ EOF 5) root_use - send_stats "Open port" + send_stats "open port" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "All ports are open" @@ -12772,7 +12794,7 @@ EOF echo "" - echo "Account operation" + echo "Account operations" echo "------------------------" echo "1. Create a normal account 2. Create a premium account" echo "------------------------" @@ -12809,7 +12831,7 @@ EOF install sudo - echo "The operation has been completed." + echo "The operation is complete." ;; 3) @@ -12849,7 +12871,7 @@ EOF done echo "" - echo "Random name" + echo "random name" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") @@ -12924,7 +12946,7 @@ EOF echo "America" echo "21. Western Time 22. Eastern Time" echo "23. Canadian time 24. Mexican time" - echo "25. Brazil time 26. Argentina time" + echo "25. Brazil Time 26. Argentina Time" echo "------------------------" echo "31. UTC Global Standard Time" echo "------------------------" @@ -12973,7 +12995,7 @@ EOF 18) root_use - send_stats "Modify the host name" + send_stats "Modify hostname" while true; do clear @@ -13034,7 +13056,7 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "Source of education in mainland China" + send_stats "Mainland China Education Source" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) @@ -13140,7 +13162,7 @@ EOF ;; 2) - read -e -p "Please enter the keywords of parsing content that need to be deleted:" delhost + read -e -p "Please enter the keywords of the parsed content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "Local host parsing and deletion" ;; @@ -13221,7 +13243,7 @@ EOF # Get the value of threshold_gb local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}The current set entry-station current limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The current outbound current limit threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}Current limit shutdown function is not enabled${gl_bai}" @@ -13245,7 +13267,7 @@ EOF rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "Please enter the traffic reset date (default reset on the 1st of each month):" cz_day + read -e -p "Please enter the traffic reset date (default resets on the 1st of every month):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13285,7 +13307,7 @@ EOF echo "ROOT private key login mode" echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "A key pair will be generated, a more secure way to SSH login" + echo "A key pair will be generated, a more secure way to log in via SSH" echo "------------------------" echo "1. Generate a new key 2. Import an existing key 3. View the native key" echo "------------------------" @@ -13332,10 +13354,10 @@ EOF echo "TG-bot monitoring and early warning function" echo "Video introduction: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "You need to configure the tg robot API and the user ID to receive early warnings to realize real-time monitoring and early warning of native CPU, memory, hard disk, traffic, and SSH login" + echo "You need to configure the tg robot API and the user ID to receive alerts to achieve real-time monitoring and alerts of local CPU, memory, hard disk, traffic, and SSH login." echo "After reaching the threshold, the user will be sent to the user" echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate-${gl_bai}" - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) @@ -13386,7 +13408,7 @@ EOF 26) root_use - send_stats "Fix high-risk vulnerabilities in SSH" + send_stats "Fix high-risk SSH vulnerabilities" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13567,7 +13589,7 @@ EOF local status_message="无法确定的状态" fi - echo "Privacy and Security" + echo "Privacy and security" echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," echo "------------------------------------------------" @@ -13578,7 +13600,7 @@ EOF echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) cd ~ @@ -13683,7 +13705,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 read -e -p "Please enter the directory name:" dirname - cd "$dirname" 2>/dev/null || echo "Unable to enter the directory" + cd "$dirname" 2>/dev/null || echo "Unable to enter directory" send_stats "Go to the directory" ;; 2) # 创建目录 @@ -13705,7 +13727,7 @@ linux_file() { ;; 5) # 删除目录 read -e -p "Please enter the directory name to delete:" dirname - rm -rf "$dirname" && echo "Directory has been deleted" || echo "Deletion failed" + rm -rf "$dirname" && echo "Directory has been deleted" || echo "Delete failed" send_stats "Delete Directory" ;; 6) # 返回上一级选单目录 @@ -13732,7 +13754,7 @@ linux_file() { 14) # 重命名文件 read -e -p "Please enter the current file name:" current_name read -e -p "Please enter a new file name:" new_name - mv "$current_name" "$new_name" && echo "File renamed" || echo "Rename failed" + mv "$current_name" "$new_name" && echo "File has been renamed" || echo "Rename failed" send_stats "Rename the file" ;; 15) # 删除文件 @@ -13757,11 +13779,11 @@ linux_file() { read -e -p "Please enter the file or directory path to move:" src_path if [ ! -e "$src_path" ]; then echo "Error: The file or directory does not exist." - send_stats "Failed to move a file or directory: The file or directory does not exist" + send_stats "Failed to move file or directory: File or directory does not exist" continue fi - read -e -p "Please enter the target path (including the new file name or directory name):" dest_path + read -e -p "Please enter the destination path (including new file or directory name):" dest_path if [ -z "$dest_path" ]; then echo "Error: Please enter the target path." send_stats "Moving file or directory failed: The destination path is not specified" @@ -13846,7 +13868,7 @@ EOF 0) # 返回上一级选单 - send_stats "Return to the previous menu menu" + send_stats "Return to the previous menu" break ;; *) # 处理无效输入 @@ -13915,14 +13937,14 @@ while true; do cat ~/cluster/servers.py echo echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}Server List Management${gl_bai}" + echo -e "${gl_kjlan}Server list management${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}Add a server${gl_kjlan}2. ${gl_bai}Delete the server${gl_kjlan}3. ${gl_bai}Edit the server" echo -e "${gl_kjlan}4. ${gl_bai}Backup cluster${gl_kjlan}5. ${gl_bai}Restore the cluster" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install the tech lion script${gl_kjlan}12. ${gl_bai}Update the system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set up 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set the time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom commands" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom commands" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14024,13 +14046,13 @@ echo "------------------------" echo -e "${gl_lan}Leica Cloud Hong Kong CN2 GIA South Korea Dual ISP US CN2 GIA Discounts${gl_bai}" echo -e "${gl_bai}Website: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" -echo -e "${gl_lan}RackNerd $10.99 per year United States 1 core 1G memory 20G hard drive 1T traffic per month${gl_bai}" +echo -e "${gl_lan}RackNerd $10.99 per year, USA, 1 core, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 52.7 dollars per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" -echo -e "${gl_bai}Website: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" +echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Brickworker, $49 per quarter, US CN2GIA, Japan SoftBank, 2 cores, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" +echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan SoftBank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT $28 per quarter US CN2GIA 1 core 2G memory 20G hard drive 800G traffic per month${gl_bai}" @@ -14092,7 +14114,7 @@ while true; do if [ -n "$existing_cron" ]; then echo "------------------------" - echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" fi echo "------------------------" @@ -14248,7 +14270,7 @@ echo "Intranet penetration (client) k frpc" echo "Software start k start sshd | k start sshd" echo "Software stop k stop sshd | k stop sshd" echo "Software restart k restart sshd | k restart sshd" -echo "Software status view k status sshd | k status sshd" +echo "Check software status k status sshd | k status sshd" echo "Software boot k enable docker | k autostart docke | k startup docker" echo "Domain name certificate application k ssl" echo "Domain name certificate expiration query k ssl ps" @@ -14460,7 +14482,7 @@ else docker_ps ;; img|镜像) - send_stats "Quick mirror management" + send_stats "Quick image management" docker_image ;; *) diff --git a/jp/kejilion.sh b/jp/kejilion.sh index f72c82993..f3f6a02e1 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -116,7 +116,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" - echo "ユーザーライセンス契約:https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "上記の条件に同意しますか? (y/n):" user_input @@ -170,7 +170,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "パッケージパラメータが指定されていません!" return 1 fi @@ -268,7 +268,7 @@ remove() { } -# さまざまな分布に適したUniversal SystemCTL関数 +# さまざまなディストリビューションに適したユニバーサル systemctl 関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -287,7 +287,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1サービスは再開されました。" else - echo "エラー:再起動$1サービスは失敗しました。" + echo "エラー:再起動$1サービスが失敗しました。" fi } @@ -337,7 +337,7 @@ enable() { break_end() { echo -e "${gl_lv}操作が完了しました${gl_bai}" - echo "任意のキーを押して続行します..." + echo "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" echo "" clear @@ -508,7 +508,7 @@ while true; do echo "" echo "コンテナ操作" echo "------------------------" - echo "1.新しいコンテナを作成します" + echo "1. 新しいコンテナを作成する" echo "------------------------" echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" echo "3.指定された容器を停止します7。すべての容器を停止します" @@ -520,9 +520,9 @@ while true; do echo "------------------------" echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) send_stats "新しいコンテナを作成します" @@ -540,7 +540,7 @@ while true; do docker stop $dockername ;; 4) - send_stats "指定されたコンテナを削除します" + send_stats "指定したコンテナを削除します" read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker rm -f $dockername ;; @@ -576,7 +576,7 @@ while true; do docker restart $(docker ps -q) ;; 11) - send_stats "コンテナを入力します" + send_stats "コンテナに入る" read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end @@ -672,14 +672,14 @@ while true; do done ;; 3) - send_stats "ミラーを削除します" + send_stats "画像の削除" read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "すべての画像を削除します" + send_stats "すべての画像を削除する" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -765,7 +765,7 @@ install_crontab() { return fi - echo -e "${gl_lv}Crontabがインストールされ、Cronサービスが実行されています。${gl_bai}" + echo -e "${gl_lv}crontab がインストールされており、cron サービスが実行されています。${gl_bai}" } @@ -785,7 +785,7 @@ docker_ipv6_on() { # JQを使用して、構成ファイルの更新を処理します local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 現在の構成には既にIPv6設定があるかどうかを確認してください + # 現在の構成にすでに ipv6 設定があるかどうかを確認します local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') # 構成を更新し、IPv6を有効にします @@ -795,7 +795,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 元の構成と新しい構成を比較します + # 元の構成と新しい構成を比較する if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" else @@ -814,11 +814,11 @@ docker_ipv6_off() { # 構成ファイルが存在するかどうかを確認します if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" + echo -e "${gl_hong}設定ファイルが存在しません${gl_bai}" return fi - # 現在の構成をお読みください + # 現在の構成を読み取る local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # JQを使用して、構成ファイルの更新を処理します @@ -827,7 +827,7 @@ docker_ipv6_off() { # 現在のIPv6ステータスを確認してください local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較します + # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else @@ -920,7 +920,7 @@ close_port() { if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "ポートは閉じた$port" + echo "ポートが閉じられています$port" fi done @@ -1075,7 +1075,7 @@ manage_country_rules() { iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - echo "正常に許可されています$country_codeIPアドレス" + echo "正常に許可されました$country_codeIPアドレス" rm "${country_code,,}.zone" ;; @@ -1119,7 +1119,7 @@ iptables_panel() { echo "ファイアウォール管理" echo "------------------------" echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" + echo "3. すべてのポートを開く 4. すべてのポートを閉じる" echo "------------------------" echo "5。IPホワイトリスト6。IPブラックリスト" echo "7.指定されたIPをクリアします" @@ -1133,12 +1133,12 @@ iptables_panel() { echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) read -e -p "オープンポート番号を入力してください:" o_port open_port $o_port - send_stats "指定されたポートを開きます" + send_stats "指定したポートを開く" ;; 2) read -e -p "閉じたポート番号を入力してください:" c_port @@ -1218,12 +1218,12 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされた国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "許可された国$country_codeIP" ;; 16) - read -e -p "許可された国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code + read -e -p "許可されている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules allow $country_code send_stats "国をブロックします$country_codeIP" ;; @@ -1260,7 +1260,7 @@ add_swap() { mkswap -f "$partition" done - # /swapfileが使用されなくなったことを確認してください + # /swapfile が使用されていないことを確認してください swapoff /swapfile # 古い /swapfileを削除します @@ -1281,7 +1281,7 @@ add_swap() { rc-update add local fi - echo -e "仮想メモリサイズは変更されています${gl_huang}${new_swap}${gl_bai}M" + echo -e "仮想メモリのサイズは次のように調整されました。${gl_huang}${new_swap}${gl_bai}M" } @@ -1291,7 +1291,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 仮想メモリを作成する必要があるかどうかを判断します +# 仮想メモリを作成する必要があるかどうかを判断する [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1392,7 +1392,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされています" + echo "LDNMP環境がインストールされている" echo "------------------------" ldnmp_v @@ -1523,7 +1523,7 @@ certs_status() { else send_stats "ドメイン名証明書のアプリケーションは失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" - echo -e "1。ドメイン名スペリングエラーdomainドメイン名が正しく入力されているかどうかを確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" @@ -1551,7 +1551,7 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をローカルIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "まず、ドメイン名をローカル IP に解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1652,7 +1652,7 @@ cf_purge_cache() { # 構成ファイルが存在するかどうかを確認します if [ -f "$CONFIG_FILE" ]; then - # 構成ファイルからAPI_TOKENとZONE_IDを読み取ります + # 構成ファイルから API_TOKEN とzone_idを読み取ります read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" # ゾーン_idsを配列に変換します ZONE_IDS=($ZONE_IDS) @@ -1672,7 +1672,7 @@ cf_purge_cache() { # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" + echo "zone_id のキャッシュをクリアします:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1706,7 +1706,7 @@ web_del() { fi for yuming in $yuming_list; do - echo "ドメイン名の削除:$yuming" + echo "ドメイン名が削除されています:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 @@ -1865,7 +1865,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる:コメントを追加します + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1885,7 +1885,7 @@ nginx_br() { return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # nginx イメージを確認し、それに応じて処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1998,7 +1998,7 @@ web_security() { echo "------------------------" echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" echo "------------------------" - echo "21。CloudFlareモード22。5秒シールドの高負荷" + echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" echo "31。WAF32をオンにしてください。WAFをオフにします" echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" @@ -2092,7 +2092,7 @@ web_security() { echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CF のグローバル API キーを入力します。" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2116,7 +2116,7 @@ web_security() { echo "--------------" echo "CFパラメーターを取得します:" echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" - echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}リージョンID${gl_bai}" + echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CFアカウント番号を入力します:" cfuser @@ -2179,7 +2179,7 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processesの設定値を取得します +# 現在のworker_processes設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') # 値に応じてモード情報を設定します @@ -2288,7 +2288,7 @@ web_optimization() { sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf - # PHPチューニング + # PHPのチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini @@ -2386,7 +2386,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "アクセスアドレス:" +echo "訪問先住所:" ip_address @@ -2487,7 +2487,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2504,7 +2504,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークを確認してリリースします127.0.0.0/8 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2540,12 +2540,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 指定したIPを許可するルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2648,7 +2648,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "エラー: アクセスを許可するには、ポート番号と IP を入力してください。" echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" return 1 fi @@ -2677,7 +2677,7 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # ローカルアクセスを許可する明確なルール if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2862,8 +2862,8 @@ docker_app_plus() { echo "------------------------" echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. ドメイン名アクセスを追加します。 6. ドメイン名アクセスを削除します。" + echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -2910,7 +2910,7 @@ docker_app_plus() { clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "IPアクセスをブロックする${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -3110,7 +3110,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再度インストールできません" + send_stats "LDNMP環境を再インストールできません" echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" break_end linux_ldnmp @@ -3164,7 +3164,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "LDNMP環境を最初にインストールしてください" + send_stats "最初に LDNMP 環境をインストールしてください" ldnmp_install_all fi @@ -3207,7 +3207,7 @@ ldnmp_wp() { webname="WordPress" yuming="${1:-}" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3253,7 +3253,7 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "抗ジェネレーションIPを入力してください:" reverseproxy + read -e -p "アンチジェネレーション IP を入力してください:" reverseproxy fi if [ -z "$port" ]; then @@ -3386,7 +3386,7 @@ ldnmp_web_status() { case $sub_choice in 1) send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3403,7 +3403,7 @@ ldnmp_web_status() { install_ssltls certs_status - # MySQLの交換 + # mysqlの置換 add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') @@ -3421,7 +3421,7 @@ ldnmp_web_status() { done done - # ウェブサイトディレクトリの交換 + # Web サイトのディレクトリの置き換え mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3469,14 +3469,14 @@ ldnmp_web_status() { break_end ;; 7) - send_stats "グローバル構成を編集します" + send_stats "グローバル構成の編集" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "サイト構成を編集します" + send_stats "サイト構成を編集する" read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming install nano nano /home/web/conf.d/$yuming.conf @@ -3524,7 +3524,7 @@ while true; do check_panel_app echo -e "$panelname $check_panel" echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" - echo "公式ウェブサイトの紹介:$panelurl " + echo "公式サイト紹介:$panelurl " echo "" echo "------------------------" @@ -3598,7 +3598,7 @@ donlond_frp() { generate_frps_config() { - send_stats "FRPサーバーをインストールします" + send_stats "FRPサーバーをインストールする" # ランダムポートと資格情報を生成します local bind_port=8055 local dashboard_port=8056 @@ -3628,7 +3628,7 @@ EOF echo "token: $token" echo echo "FRPパネル情報" - echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" + echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" echo "FRPパネルのユーザー名:$dashboard_user" echo "FRPパネルパスワード:$dashboard_pwd" echo @@ -3642,7 +3642,7 @@ EOF configure_frpc() { send_stats "FRPクライアントをインストールします" read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr - read -e -p "外部ネットワークドッキングトークンを入力してください:" token + read -e -p "外部ネットワーク ドッキング トークンを入力してください:" token echo mkdir -p /home/frp @@ -3670,7 +3670,7 @@ add_forwarding_service() { read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネットポートを入力してください:" local_port - read -e -p "外部ネットワークポートを入力してください:" remote_port + read -e -p "外部ネットワーク ポートを入力してください:" remote_port # ユーザー入力を構成ファイルに書き込みます cat <> /home/frp/frpc.toml @@ -3815,7 +3815,7 @@ generate_access_urls() { fi done - # IPv6アドレスを処理する(存在する場合) + # IPv6 アドレスが存在する場合は処理します if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3875,7 +3875,7 @@ frps_panel() { echo "------------------------" echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" - echo "00。サービスのステータスを更新します0。前のメニューに戻ります" + echo "00. サービスステータスを更新します。 0. 前のメニューに戻ります。" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice case $choice in @@ -3912,7 +3912,7 @@ frps_panel() { echo "ドメイン名アクセスへの逆イントラネット侵入サービス" send_stats "FRP外部ドメイン名へのアクセス" add_yuming - read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port + read -e -p "イントラネット侵入サービス ポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; @@ -3922,14 +3922,14 @@ frps_panel() { ;; 7) - send_stats "IPアクセスを許可します" + send_stats "IPアクセスを許可する" read -e -p "リリースするポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合、この関数を使用して、より安全なIP+ポートアクセスをブロックできます。" + echo "アンチジェネレーションドメイン名にアクセスした場合は、この関数を使用して、より安全なIP+ポートアクセスをブロックします。" read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4054,7 +4054,7 @@ yt_menu_pro() { echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードされたビデオリスト:" + echo "ダウンロードしたビデオのリスト:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" echo "1。インストール2。更新3。アンインストール" @@ -4062,9 +4062,9 @@ yt_menu_pro() { echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" echo "-------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "-------------------------" - read -e -p "オプション番号を入力してください:" choice + read -e -p "オプション番号を入力してください:" choice case $choice in 1) @@ -4091,7 +4091,7 @@ yt_menu_pro() { rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。任意のキーを押して続行します..." + echo "アンインストールが完了しました。続行するには任意のキーを押してください..." read ;; 5) send_stats "単一のビデオダウンロード" @@ -4131,7 +4131,7 @@ yt_menu_pro() { read -e -p "実行が完了したら、キーを押して続行します..." ;; 8) send_stats "MP3ダウンロード" - read -e -p "ビデオリンクを入力してください:" url + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4247,7 +4247,7 @@ linux_clean() { apk cache clean echo "システムログを削除してください..." rm -rf /var/log/* - echo "APKキャッシュを削除してください..." + echo "APKキャッシュを削除..." rm -rf /var/cache/apk/* echo "一時ファイルを削除します..." rm -rf /tmp/* @@ -4344,7 +4344,7 @@ while true; do echo " v6: 2400:3200::1 2400:da00::6666" echo "3。DNS構成を手動で編集します" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" Limiting case "$Limiting" in @@ -4448,7 +4448,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" + echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4516,7 +4516,7 @@ clear dd_xitong() { - send_stats "システムを再インストールします" + send_stats "システムを再インストールする" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4551,7 +4551,7 @@ dd_xitong() { dd_xitong_4() { echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" dd_xitong_bin456789 } @@ -4746,7 +4746,7 @@ dd_xitong() { ;; 33) - send_stats "Kaliを再インストールします" + send_stats "kaliを再インストールする" dd_xitong_3 bash reinstall.sh kali reboot @@ -4810,7 +4810,7 @@ dd_xitong() { ;; 45) - send_stats "Windows Server 22を再インストールします" + send_stats "Windowsサーバー22を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -4864,7 +4864,7 @@ bbrv3() { echo "------------------------" echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" sub_choice @@ -4895,7 +4895,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" + echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" server_reboot ;; @@ -4982,7 +4982,7 @@ elrepo_install() { fi # 検出されたオペレーティングシステム情報を印刷します echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする + # システムのバージョンに応じて、対応する ELRepo ウェアハウス構成をインストールします。 if [[ "$os_version" == 8 ]]; then echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm @@ -4993,7 +4993,7 @@ elrepo_install() { echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "サポートされていないシステムバージョン:$os_version" + echo "サポートされていないシステム バージョン:$os_version" break_end linux_Settings fi @@ -5031,7 +5031,7 @@ elrepo() { dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hatカーネルを更新します" + send_stats "Red Hat カーネルを更新する" server_reboot ;; @@ -5056,7 +5056,7 @@ elrepo() { echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" - echo "Linuxカーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上する可能性があります。条件が許可され、生産環境を慎重にアップグレードする場合は、試してみることをお勧めします!" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "必ず続行しますか? (y/n):" choice @@ -5071,7 +5071,7 @@ elrepo() { echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac fi @@ -5139,12 +5139,12 @@ clamav() { while true; do clear echo "クラマブウイルススキャンツール" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" echo "------------------------" - echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3。カスタムディレクトリスキャン${gl_bai}" + echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3. カスタムディレクトリスキャン${gl_bai}" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -5227,7 +5227,7 @@ optimize_high_performance() { } -# イコライゼーションモード最適化関数 +# バランスモード最適化機能 optimize_balanced() { echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" @@ -5301,7 +5301,7 @@ restore_defaults() { sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" - # 透明なページを復元します + # 透明な巨大ページを復元する echo always > /sys/kernel/mm/transparent_hugepage/enabled # numaバランスを復元します sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5582,7 +5582,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムリサイクルステーション" + send_stats "システムのごみ箱" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5602,7 +5602,7 @@ linux_trash() { echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" echo "------------------------" - echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" + echo "1. ごみ箱を有効にする 2. ごみ箱を閉じる" echo "3。コンテンツを復元4。リサイクルビンをクリアします" echo "------------------------" echo "0。前のメニューに戻ります" @@ -5666,7 +5666,7 @@ create_backup() { echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input - # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリを使用します + # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリが使用されます。 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5698,7 +5698,7 @@ create_backup() { echo "- $path" done - # バックアップを作成します + # バックアップの作成 echo "バックアップを作成します$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -5718,13 +5718,13 @@ restore_backup() { # 復元するバックアップを選択します read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # バックアップファイルが存在するか確認する if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then echo "バックアップファイルは存在しません!" exit 1 fi - echo "バックアップの回復$BACKUP_NAME..." + echo "バックアップの復元$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then @@ -5745,7 +5745,7 @@ list_backups() { delete_backup() { send_stats "バックアップを削除します" - read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME + read -e -p "削除するバックアップ ファイル名を入力してください:" BACKUP_NAME # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -5816,7 +5816,7 @@ add_connection() { echo "- ユーザー名:root" echo "- ポート:22" echo "------------------------" - read -e -p "接続名を入力してください:" name + read -e -p "接続名を入力してください:" name read -e -p "IPアドレスを入力してください:" ip read -e -p "ユーザー名(デフォルト:root)を入力してください:" user local user=${user:-root} # 如果用户未输入,则使用默认值 root @@ -5982,13 +5982,13 @@ ssh_manager() { # 利用可能なハードディスクパーティションをリストします list_partitions() { - echo "利用可能なハードディスクパーティション:" + echo "利用可能なハードドライブのパーティション:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } # パーティションをマウントします mount_partition() { - send_stats "パーティションをマウントします" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION # パーティションが存在するかどうかを確認します @@ -6065,7 +6065,7 @@ format_partition() { fi # ファイルシステムタイプを選択します - echo "ファイルシステムタイプを選択してください:" + echo "ファイル システムのタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" @@ -6120,7 +6120,7 @@ disk_manager() { while true; do clear echo "ハードディスクパーティション管理" - echo -e "${gl_huang}この関数は、テスト期間中に内部的にテストされています。生産環境では使用しないでください。${gl_bai}" + echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" @@ -6161,7 +6161,7 @@ add_task() { echo "- ローカルディレクトリ: /var /www" echo "- リモートアドレス:user@192.168.1.100" echo "- リモートディレクトリ: /バックアップ /www" - echo "- ポート番号(デフォルト22)" + echo "- ポート番号 (デフォルトは 22)" echo "---------------------------------" read -e -p "タスク名を入力してください:" name read -e -p "ローカルディレクトリを入力してください:" local_path @@ -6227,7 +6227,7 @@ add_task() { install rsync rsync - echo "タスクが節約されました!" + echo "ミッションが保存されました!" } # タスクを削除します @@ -6285,7 +6285,7 @@ run_task() { # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then - echo "同期をローカルに引く:$remote:$local_path -> $remote_path" + echo "ローカルへのプルと同期:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -6328,7 +6328,7 @@ run_task() { echo "1。ネットワーク接続は正常ですか?" echo "2。リモートホストにアクセスできますか?" echo "3。認証情報は正しいですか?" - echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" + echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi } @@ -6390,7 +6390,7 @@ delete_task_schedule() { fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numタイミングタスク" + echo "削除されたタスク番号$numスケジュールされたタスク" } @@ -6521,7 +6521,7 @@ linux_info() { echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理的場所:${gl_bai}$country $city" + echo -e "${gl_kjlan}位置:${gl_bai}$country $city" echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" @@ -6541,17 +6541,17 @@ linux_tools() { echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" + echo -e "${gl_kjlan}3. ${gl_bai}sudo スーパー管理者特権ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" + echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}マトリックス画面保証${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" + echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" echo -e "${gl_kjlan}------------------------" @@ -6560,7 +6560,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice @@ -6615,7 +6615,7 @@ linux_tools() { clear install unzip clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" unzip send_stats "unzipをインストールします" ;; @@ -6771,7 +6771,7 @@ linux_tools() { ;; 42) clear - read -e -p "アンインストールされていないツール名(HTOP UFW TMUX CMATRIX)を入力してください。" removename + read -e -p "アンインストールされたツール名 (htop ufw tmux cmatrix) を入力してください:" removename remove $removename send_stats "指定されたソフトウェアをアンインストールします" ;; @@ -6810,7 +6810,7 @@ linux_bbr() { echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -6898,7 +6898,7 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}バックアップコンテナ:$c${NC}" + echo -e "${GREEN}バックアップコンテナ:$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" @@ -6913,7 +6913,7 @@ docker_ssh_migration() { # Composeプロジェクトがパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトを作成する[$project_name]バックアップ、複製パッケージをスキップ...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7001,7 +7001,7 @@ docker_ssh_migration() { # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}プロジェクトを作成する[$project_name]すでにコンテナが走っています、復元をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトを作成する[$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" continue fi @@ -7010,12 +7010,12 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}プロジェクトを作成する[$project_name]減圧:$original_path${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name]減圧:$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}プロジェクトを作成する[$project_name]復元が完了しました!${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name]復元が完了しました!${NC}" fi done @@ -7073,7 +7073,7 @@ docker_ssh_migration() { docker rm -f "$container" fi - # コンテナを起動します + # コンテナの起動 echo "restoreコマンドを実行します:docker run -d - name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done @@ -7085,7 +7085,7 @@ docker_ssh_migration() { echo -e "${BLUE}/home /dockerの下でファイルを復元します...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home /dockerの下のファイルが復元されました${NC}" + echo -e "${GREEN}/home/docker 下のファイルが復元されました${NC}" else echo -e "${YELLOW}/home /dockerの下のファイルのバックアップは見つかりませんでした、スキップ...${NC}" fi @@ -7177,7 +7177,7 @@ linux_docker() { echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境のインストールと更新${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -7194,8 +7194,8 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" - echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールします" + echo -e "${gl_kjlan}19. ${gl_bai}Docker環境のバックアップ/移行/復元" + echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールする" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7227,7 +7227,7 @@ linux_docker() { echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" @@ -7270,11 +7270,11 @@ linux_docker() { done echo "" - echo "ネットワーク操作" + echo "ネットワーク運用" echo "------------------------" echo "1.ネットワークを作成します" echo "2。インターネットに参加してください" - echo "3。ネットワークを終了します" + echo "3. ネットワークを終了します" echo "4.ネットワークを削除します" echo "------------------------" echo "0。前のメニューに戻ります" @@ -7339,7 +7339,7 @@ linux_docker() { case $sub_choice in 1) - send_stats "新しいボリュームを作成します" + send_stats "新しいボリュームを作成する" read -e -p "新しいボリューム名を設定します:" dockerjuan docker volume create $dockerjuan @@ -7376,7 +7376,7 @@ linux_docker() { ;; 7) clear - send_stats "Dockerクリーニング" + send_stats "Docker のクリーンアップ" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7413,7 +7413,7 @@ linux_docker() { 12) clear - send_stats "Docker V6レベル" + send_stats "Docker v6 閉じる" docker_ipv6_off ;; @@ -7469,13 +7469,13 @@ linux_test() { echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 品質チェック スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ネットワーク速度測定" echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" - echo -e "${gl_kjlan}13. ${gl_bai}SuperSpeed Three-Net速度測定" + echo -e "${gl_kjlan}13. ${gl_bai}超高速トリプルネットワーク速度テスト" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" @@ -7485,16 +7485,16 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU パフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}包括的なテスト" echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -7553,10 +7553,10 @@ linux_test() { echo "上海通信:202.96.209.133" echo "上海ユニコム:210.22.97.1" echo "上海モバイル:211.136.112.200" - echo "広州通信:58.60.188.222" + echo "広州電信: 58.60.188.222" echo "広州ユニコム:210.21.196.6" echo "広州モバイル:120.196.165.24" - echo "成都通信:61.139.2.69" + echo "成都電信: 61.139.2.69" echo "成都ユニコム:119.6.6.6" echo "成都モバイル:211.137.96.205" echo "Hunan Telecom:36.111.200.100" @@ -7651,13 +7651,13 @@ linux_Oracle() { 1) clear echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "必ずインストールしますか? (y/n):" choice + read -e -p "インストールしてもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) install_docker - # デフォルト値を設定します + # デフォルト値を設定する local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 @@ -7670,7 +7670,7 @@ linux_Oracle() { read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリ使用率を入力してください [デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval @@ -7712,7 +7712,7 @@ linux_Oracle() { case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice + read -e -p "再インストールするシステムを選択してください: 1. Debian12 | 2.Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7757,7 +7757,7 @@ linux_Oracle() { clear bash <(curl -L -s jhb.ovh/jb/v6.sh) echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + send_stats "IPv6修復" ;; 0) kejilion @@ -7806,7 +7806,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" + echo -e "${gl_lv}環境がインストールされています${gl_bai}サイト:$outputデータベース:$db_output" fi fi @@ -7854,9 +7854,9 @@ linux_ldnmp() { echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールする" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_huang}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -7899,7 +7899,7 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス:mysql" - echo "データベース名:$dbname" + echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "テーブルプレフィックス:discuz_" @@ -7978,7 +7978,7 @@ linux_ldnmp() { echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "データベースプレフィックス:mac_" + echo "データベース接頭辞: mac_" echo "------------------------" echo "インストールが成功した後、バックグラウンドアドレスにログインします" echo "https://$yuming/vip.php" @@ -8013,12 +8013,12 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス:mysql" echo "データベースポート:3306" - echo "データベース名:$dbname" + echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "" echo "Redisアドレス:Redis" - echo "Redisパスワード:デフォルトで記入されていません" + echo "redis パスワード: デフォルトでは入力されていません" echo "Redisポート:6379" echo "" echo "ウェブサイトURL:https://$yuming" @@ -8115,7 +8115,7 @@ linux_ldnmp() { ldnmp_web_on echo "データベースプレフィックス:typecho_" echo "データベースアドレス:mysql" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "データベース名:$dbname" @@ -8223,7 +8223,7 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}4/6${gl_bai}]指定された拡張機能をインストールします" + echo -e "[${gl_huang}4/6${gl_bai}] 指定された拡張機能をインストールします" echo "-------------" echo "インストールされた拡張機能" docker exec php php -m @@ -8282,7 +8282,7 @@ linux_ldnmp() { echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:$prefix" + echo "テーブルの接頭辞:$prefix" echo "管理者ログイン情報は自分で設定されます" ;; @@ -8297,7 +8297,7 @@ linux_ldnmp() { clear webname="站点重定向" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming read -e -p "ジャンプドメイン名を入力してください:" reverseproxy nginx_install_status @@ -8451,8 +8451,8 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリの下" + read -e -p "ダウンロード リンクを入力して、ソース コード パッケージをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8576,14 +8576,14 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "Enter キーを押して最新のバックアップを復元し、バックアップ ファイル名を入力して指定したバックアップを復元し、0 を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージが使用されます。 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8602,7 +8602,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージは見つかりませんでした。" + echo "圧縮パッケージが見つかりませんでした。" fi ;; @@ -8659,7 +8659,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version + read -e -p "入力してください${ldnmp_pods}バージョン番号 (例: 8.0 8.3 8.4 9.0) (Enter キーを押して最新バージョンを取得します):" version local version=${version:-latest} cd /home/web/ @@ -8710,7 +8710,7 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + echo "更新する${ldnmp_pods}仕上げる" ;; 4) @@ -8729,7 +8729,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境を完全に更新します" + send_stats "LDNMP環境の完全アップデート" cd /home/web/ docker compose down --rmi all @@ -8815,36 +8815,36 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" - echo -e "${gl_kjlan}5. ${color5}OpenListマルチストアファイルリストプログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Today スケジュールされたタスク管理フレームワーク" echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}プロメテウス(ホスト監視)" + echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" @@ -8863,7 +8863,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}同期ポイントツーポイントファイル同期ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AIビデオ生成ツール" + echo -e "${gl_kjlan}101. ${color101}AIビデオ生成ツール${gl_kjlan}102. ${color102}VoceChatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" @@ -9221,7 +9221,7 @@ while true; do add_app_id clear - echo "Poste.ioがインストールされています" + echo "poste.ioがインストールされました" echo "------------------------" echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" @@ -9248,7 +9248,7 @@ while true; do clear echo "Poste.ioがインストールされています" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "次のアドレスを使用して poste.io にアクセスできます。" echo "https://$yuming" echo "" ;; @@ -9259,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" ;; *) @@ -9556,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "サンダープールを構築します" + send_stats "雷のプールを作る" local app_id="19" local docker_name=safeline-mgt @@ -10276,7 +10276,7 @@ while true; do prometheus_install clear ip_address - echo "インストール" + echo "インストール完了" check_docker_app_ip echo "最初のユーザー名とパスワードは次のとおりです" } @@ -10673,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -11634,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11826,7 +11826,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; @@ -12235,7 +12257,7 @@ linux_work() { clear send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" - echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" echo -e "${gl_kjlan}------------------------" @@ -12246,20 +12268,20 @@ linux_work() { echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" - echo -e "${gl_kjlan}4. ${gl_bai}ワークスペースNo. 4" + echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo. 10" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice @@ -12433,7 +12455,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3加速度をセットアップします" + echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3アクセラレーションの設定" echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" @@ -12504,7 +12526,7 @@ linux_Settings() { if [[ "$py_new_v" == "0" ]]; then - send_stats "スクリプトPy管理" + send_stats "スクリプト PY 管理" break_end linux_Settings fi @@ -12567,7 +12589,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スイッチスクリプトPyバージョン" + send_stats "スクリプトPYバージョン切り替え" ;; @@ -12634,7 +12656,7 @@ EOF 9) root_use send_stats "新しいユーザーはルートを無効にします" - read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username + read -e -p "新しいユーザー名を入力してください (終了するには 0 を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12665,12 +12687,12 @@ EOF if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" echo "------------------------" - echo "1。IPv4優先度2。IPv6優先度3。IPv6修理ツール" + echo "1. IPv4 が先 2. IPv6 が先 3. IPv6 修復ツール" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -12680,7 +12702,7 @@ EOF 1) grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "IPv4の優先度に切り替えました" + echo "IPv4優先に切り替えました" send_stats "IPv4の優先度に切り替えました" ;; 2) @@ -12739,13 +12761,13 @@ EOF ;; 3) - send_stats "4G仮想メモリが設定されています" + send_stats "4G仮想メモリが設定されました" add_swap 4096 ;; 4) - read -e -p "仮想メモリサイズ(ユニットM)を入力してください:" new_swap + read -e -p "仮想メモリ サイズ (単位 M) を入力してください:" new_swap add_swap "$new_swap" send_stats "カスタム仮想メモリが設定されています" ;; @@ -12826,7 +12848,7 @@ EOF ;; 5) - read -e -p "削除するにはユーザー名を入力してください:" username + read -e -p "削除するユーザー名を入力してください:" username # ユーザーとそのホームディレクトリを削除します userdel -r "$username" ;; @@ -12863,11 +12885,11 @@ EOF done echo "" - echo "ランダムuuid" + echo "ランダムな UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "ランダムuuid$i: $uuid" + echo "ランダムな UUID$i: $uuid" done echo "" @@ -12912,7 +12934,7 @@ EOF echo "アジア" echo "1。中国の上海時間2。中国の香港時間" echo "3。日本の東京時間4。韓国のソウル時間" - echo "5。シンガポール時間6。インドのコルカタ時間" + echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" echo "9。タイのバンコクでの時間" echo "------------------------" @@ -12924,9 +12946,9 @@ EOF echo "アメリカ" echo "21。WesternTime22。東部時間" echo "23。カナダ時間24。メキシコの時間" - echo "25。ブラジル時間26。アルゼンチン時間" + echo "25. ブラジル時間 26. アルゼンチン時間" echo "------------------------" - echo "31。UTCグローバル標準時間" + echo "31. UTC 世界標準時" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -12973,7 +12995,7 @@ EOF 18) root_use - send_stats "ホスト名を変更します" + send_stats "ホスト名の変更" while true; do clear @@ -13030,7 +13052,7 @@ EOF case $choice in 1) - send_stats "中国本土のデフォルトソース" + send_stats "中国本土のデフォルトのソース" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -13064,16 +13086,16 @@ EOF echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest echo "------------------------" echo "1。毎月のタスク2。毎週のタスク" - echo "3。毎日のタスク4。時間ごとのタスク" + echo "3. 毎日のタスク 4. 時間ごとのタスク" echo "------------------------" - read -e -p "選択を入力してください:" dingshi + read -e -p "選択肢を入力してください:" dingshi case $dingshi in 1) @@ -13089,7 +13111,7 @@ EOF (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute + read -e -p "タスクを実行する時間を入力してください。 (分、0 ~ 60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) @@ -13105,7 +13127,7 @@ EOF ;; 3) crontab -e - send_stats "タイミングタスクを編集します" + send_stats "スケジュールされたタスクを編集する" ;; *) break # 跳出循环,退出菜单 @@ -13124,7 +13146,7 @@ EOF echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" cat /etc/hosts echo "" - echo "動作します" + echo "操作する" echo "------------------------" echo "1.新しい解析2を追加します。解析アドレスを削除します" echo "------------------------" @@ -13134,7 +13156,7 @@ EOF case $host_dns in 1) - read -e -p "新しい解析レコード形式を入力してください:110.25.5.33 Kejilion.pro:" addhost + read -e -p "新しい解析レコード形式を入力してください: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts send_stats "ローカルホストの解析が追加されました" @@ -13157,13 +13179,13 @@ EOF while true; do check_f2b_status - echo -e "SSH防衛プログラム$check_f2b_status" + echo -e "SSH防御プログラム$check_f2b_status" echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "2。SSH傍受記録を表示します" + echo "2. SSH インターセプト記録の表示" echo "3。リアルタイムログ監視" echo "------------------------" echo "9.防衛プログラムをアンインストールします" @@ -13192,7 +13214,7 @@ EOF 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban 防御プログラムがアンインストールされました" break ;; *) @@ -13213,12 +13235,12 @@ EOF echo "------------------------------------------------" echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" output_status - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}受け取った合計:${gl_bai}$rx" + echo -e "${gl_kjlan}送信合計:${gl_bai}$tx" - # limiting_shut_down.shファイルが存在するかどうかを確認してください + # Limiting_Shut_down.sh ファイルが存在するかどうかを確認します if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gbの値を取得します + # しきい値_gbの値を取得する local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" @@ -13295,7 +13317,7 @@ EOF case $host_dns in 1) - send_stats "新しいキーを生成します" + send_stats "新しいキーを生成する" add_sshkey break_end @@ -13328,7 +13350,7 @@ EOF 25) root_use - send_stats "電報警告" + send_stats "電報警報" echo "TG-BOTモニタリングと早期警告機能" echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" echo "------------------------------------------------" @@ -13361,7 +13383,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 〜/.Profileファイルに追加します + # ~/.profile ファイルに追加 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -13465,13 +13487,13 @@ EOF send_stats "ワンストップチューニング" echo "ワンストップシステムの最適化" echo "------------------------------------------------" - echo "以下が操作され、最適化されます" + echo "以下のコンテンツを運用・最適化していきます" echo "1.システムを最新の状態に更新します" echo "2。システムジャンクファイルをクリーンアップします" echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo -e "5.すべてのポートを開きます" - echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo -e "6.電源を入れます${gl_huang}BBR${gl_bai}加速します" echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" @@ -13500,7 +13522,7 @@ EOF new_ssh_port echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" + echo -e "[${gl_lv}OK${gl_bai}】5/10。すべてのポートを開く" echo "------------------------------------------------" bbr_on @@ -13525,7 +13547,7 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10。 DNSアドレスを自動的に最適化します${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】8/10。 DNSアドレスを自動的に最適化する${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker @@ -13609,9 +13631,9 @@ EOF 102) clear send_stats "テックライオンスクリプトをアンインストールします" - echo "テックライオンスクリプトをアンインストールします" + echo "Tech Lion スクリプトをアンインストールする" echo "------------------------------------------------" - echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + echo "kejilion スクリプトは、他の機能に影響を与えることなく完全にアンインストールされます。" read -e -p "必ず続行しますか? (y/n):" choice case "$choice" in @@ -13667,8 +13689,8 @@ linux_file() { echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1.ディレクトリ2を入力します。ディレクトリを作成3。ディレクトリアクセス許可を変更します。4。ディレクトリの名前を変更します" - echo "5.ディレクトリを削除6。前のメニューディレクトリに戻ります" + echo "1. ディレクトリを入力します。 2. ディレクトリを作成します。 3. ディレクトリのアクセス許可を変更します。 4. ディレクトリの名前を変更します。" + echo "5. ディレクトリを削除します。 6. 前のメニュー ディレクトリに戻ります。" echo "------------------------" echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" echo "15.ファイルを削除します" @@ -13694,7 +13716,7 @@ linux_file() { 3) # 修改目录权限 read -e -p "ディレクトリ名を入力してください:" dirname read -e -p "許可を入力してください(755など):" perm - chmod "$perm" "$dirname" && echo "許可が変更されました" || echo "変更に失敗しました" + chmod "$perm" "$dirname" && echo "権限が変更されました" || echo "変更に失敗しました" send_stats "ディレクトリ権限を変更します" ;; 4) # 重命名目录 @@ -13706,7 +13728,7 @@ linux_file() { 5) # 删除目录 read -e -p "削除するには、ディレクトリ名を入力してください。" dirname rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" - send_stats "ディレクトリを削除します" + send_stats "ディレクトリを削除する" ;; 6) # 返回上一级选单目录 cd .. @@ -13725,14 +13747,14 @@ linux_file() { ;; 13) # 修改文件权限 read -e -p "ファイル名を入力してください:" filename - read -e -p "許可を入力してください(755など):" perm + read -e -p "権限を入力してください (例: 755):" perm chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" send_stats "ファイル権限を変更します" ;; 14) # 重命名文件 read -e -p "現在のファイル名を入力してください:" current_name read -e -p "新しいファイル名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "名前の変更" || echo "名前変更に失敗しました" + mv "$current_name" "$new_name" && echo "ファイル名が変更されました" || echo "名前変更に失敗しました" send_stats "ファイルの名前を変更します" ;; 15) # 删除文件 @@ -13741,7 +13763,7 @@ linux_file() { send_stats "ファイルを削除します" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name + read -e -p "圧縮するファイル/ディレクトリ名を入力してください:" name install tar tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" send_stats "圧縮ファイル/ディレクトリ" @@ -13774,10 +13796,10 @@ linux_file() { 24) # 复制文件目录 - read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "コピーするファイルまたはディレクトリのパスを入力してください:" src_path if [ ! -e "$src_path" ]; then echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" + send_stats "ファイルまたはディレクトリのコピーに失敗しました: ファイルまたはディレクトリが存在しません" continue fi @@ -13805,7 +13827,7 @@ linux_file() { read -e -p "リモートサーバーIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then echo "エラー:リモートサーバーIPを入力してください。" - send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" + send_stats "ファイル転送に失敗しました: リモート サーバー IP が入力されていません" continue fi @@ -13834,7 +13856,7 @@ EOF if [ $? -eq 0 ]; then echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" - send_stats "ファイル転送に正常に転送します" + send_stats "ファイル転送が成功しました" else echo "ファイル転送に失敗しました。" send_stats "ファイル転送に失敗しました" @@ -13944,11 +13966,11 @@ while true; do ;; 2) send_stats "クラスターサーバーを削除します" - read -e -p "削除する必要があるキーワードを入力してください。" rmserver + read -e -p "削除するキーワードを入力してください:" rmserver sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) - send_stats "クラスターサーバーを編集します" + send_stats "クラスターサーバーの編集" install nano nano ~/cluster/servers.py ;; @@ -13964,7 +13986,7 @@ while true; do clear send_stats "クラスターを復元します" echo "Servers.pyをアップロードし、キーを押してアップロードを開始してください!" - echo -e "アップロードしてください${gl_huang}servers.py${gl_bai}にファイル${gl_huang}/root/cluster/${gl_bai}復元を完了してください!" + echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}にファイル${gl_huang}/root/cluster/${gl_bai}復元を完了してください!" break_end ;; @@ -14036,7 +14058,7 @@ echo "------------------------" echo -e "${gl_lan}dmit四半期あたり28ドルUS CN2GIA 1コア2Gメモリ20Gハードドライブ800gトラフィック${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://www.dmit.io/aff.php?aff = 4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS月額6.9 $ 6.9東京ソフトバンク2コア1Gメモリ20gハードドライブ1Tトラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?faffid=1355 &? affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}より人気のあるVPSオファー${gl_bai}" @@ -14100,7 +14122,7 @@ while true; do echo "------------------------" echo "0。メインメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case "$choice" in 1) clear @@ -14194,7 +14216,7 @@ read -e -p "選択を入力してください:" choice case $choice in 1) linux_info ;; - 2) clear ; send_stats "システムの更新" ; linux_update ;; + 2) clear ; send_stats "システムアップデート" ; linux_update ;; 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; @@ -14236,7 +14258,7 @@ echo "クリーンシステムガベージkクリーン| kきれい" echo "システムパネルk dd |を再インストールしますk再インストール" echo "BBR3コントロールパネルK BBR3 | K BBRV3" echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" -echo "仮想メモリkスワップ2048を設定します" +echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" @@ -14250,16 +14272,16 @@ echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" echo "ソフトウェア再起動k再起動sshd | k再起動sshd" echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" -echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書アプリケーション k ssl" echo "ドメイン名証明書の有効期限クエリK SSL PS" echo "Docker Management Plane K Docker" echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" echo "Docker Container Management K Docker PS | K Dockerコンテナ" echo "Docker Image Management K Docker IMG | K Docker画像" -echo "LDNMPサイト管理k Web" +echo "LDNMP サイト管理 k Web" echo "LDNMPキャッシュクリーンアップK Webキャッシュ" echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" -echo "リバースプロキシk fd | k rp | k抗ジェネレーション| k fd xxx.comをインストールする" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロードバランスkロードバランス| kロードバランシングをインストールします" echo "ファイアウォールパネルk fhq | kファイアウォール" echo "オープンポートK DKDK 8080 | Kオープンポート8080" @@ -14269,7 +14291,7 @@ echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" echo "コマンドお気に入りk fav | Kコマンドのお気に入り" echo "アプリ市場管理Kアプリ" echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" -echo "システム情報を表示k情報" +echo "システム情報を表示 k info" } @@ -14353,7 +14375,7 @@ else swap) shift - send_stats "仮想メモリをすばやく設定します" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; @@ -14412,7 +14434,7 @@ else ;; start|启动) shift - send_stats "ソフトウェアスタートアップ" + send_stats "ソフトウェアの起動" start "$@" ;; stop|停止) @@ -14452,7 +14474,7 @@ else shift case $1 in install|安装) - send_stats "Dockerをすばやくインストールします" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) @@ -14460,7 +14482,7 @@ else docker_ps ;; img|镜像) - send_stats "クイックミラー管理" + send_stats "素早い画像管理" docker_image ;; *) @@ -14487,7 +14509,7 @@ else app) shift - send_stats "$@を適用します" + send_stats "申し込む$@" linux_panel "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index a693df95d..9c65414f3 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -57,8 +57,8 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! -# 이 기능을 설계 해야하는 이유는 무엇입니까? 목적은 사용자가 사용하는 기능을 더 잘 이해하고 기능을 더욱 최적화하여 사용자 요구를 충족시키는 더 많은 기능을 시작하는 것입니다. +# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -221,10 +221,10 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}힌트:${gl_bai}불충분 한 디스크 공간!" - echo "현재 사용 가능한 공간 : $ ((uvery_space_mb/1024)) g" + echo "현재 사용 가능한 공간: $((available_space_mb/1024))G" echo "최소 수요 공간 :${required_gb}G" echo "설치를 계속할 수 없습니다. 디스크 공간을 청소하고 다시 시도하십시오." - send_stats "불충분 한 디스크 공간" + send_stats "디스크 공간이 부족합니다." break_end kejilion fi @@ -238,7 +238,7 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "패키지 매개 변수는 제공되지 않습니다!" + echo "패키지 매개변수가 제공되지 않았습니다!" return 1 fi @@ -281,7 +281,7 @@ systemctl() { } -# 서비스를 다시 시작하십시오 +# 서비스 다시 시작 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then @@ -311,7 +311,7 @@ stop() { fi } -# 서비스 상태를 확인하십시오 +# 서비스 상태 확인 status() { systemctl status "$1" if [ $? -eq 0 ]; then @@ -427,7 +427,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" + echo -e "${gl_huang}도커 환경 설치 중...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -512,10 +512,10 @@ while true; do echo "------------------------" echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" - echo "4. 지정된 컨테이너를 삭제합니다. 8. 모든 컨테이너를 삭제하십시오" + echo "4. 지정된 컨테이너 삭제 8. 모든 컨테이너 삭제" echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" echo "------------------------" - echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" + echo "11. 지정된 컨테이너를 입력합니다. 12. 컨테이너 로그를 봅니다." echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" echo "------------------------" echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." @@ -977,7 +977,7 @@ block_ip() { # 차단 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP 차단$ip" + echo "IP가 차단됨$ip" fi done @@ -1042,7 +1042,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "오류: 다운로드$country_codeIP 영역 파일이 실패했습니다" continue fi @@ -1062,7 +1062,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "오류: 다운로드$country_codeIP 영역 파일이 실패했습니다" continue fi @@ -1118,13 +1118,13 @@ iptables_panel() { echo "" echo "방화벽 관리" echo "------------------------" - echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." + echo "1. 지정 포트 열기 2. 지정 포트 닫기" echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" echo "7. 지정된 IP를 지우십시오" echo "------------------------" - echo "11. 핑 허용 12. 핑을 비활성화하십시오" + echo "11. PING 허용 12. PING 비활성화" echo "------------------------" echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" echo "------------------------" @@ -1141,12 +1141,12 @@ iptables_panel() { send_stats "지정된 포트를 엽니 다" ;; 2) - read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port + read -e -p "닫힌 포트 번호를 입력하세요:" c_port close_port $c_port send_stats "지정된 포트를 닫습니다" ;; 3) - # 모든 포트를 엽니 다 + # 모든 포트 열기 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1159,7 +1159,7 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 엽니 다" + send_stats "모든 포트 열기" ;; 4) # 모든 포트를 닫습니다 @@ -1204,7 +1204,7 @@ iptables_panel() { send_stats "핑을 허용하십시오" ;; 12) - # 핑을 비활성화합니다 + # 핑 비활성화 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1321,7 +1321,7 @@ ldnmp_v() { local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전을 얻으십시오 + # Redis 버전 받기 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1347,7 +1347,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일로 교체하십시오 + # docker-compose.yml 파일에서 교체 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1522,13 +1522,13 @@ certs_status() { send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" else send_stats "도메인 이름 인증서 신청에 실패했습니다" - echo -e "${gl_hong}알아채다:${gl_bai}인증서 응용 프로그램이 실패했습니다. 가능한 이유를 확인하고 다시 시도하십시오." + echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." - echo -e "3. 네트워크 구성 문제 ➠ CloudFlare Warp 및 기타 가상 네트워크를 사용하는 경우 임시로 종료하십시오." + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." - echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." break_end clear echo "다시 배포를 시도하십시오$webname" @@ -1552,7 +1552,7 @@ fi add_yuming() { ip_address echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IP 또는 해결 된 도메인 이름을 입력하십시오." yuming + read -e -p "귀하의 IP 또는 확인된 도메인 이름을 입력하십시오:" yuming } @@ -1657,12 +1657,12 @@ cf_purge_cache() { # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트합니다 + # 캐시 청소 여부를 사용자에게 프롬프트하십시오 read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" read -e -p "API_Token을 입력하십시오 :" API_TOKEN - read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL + read -e -p "CF 사용자 이름을 입력하세요:" EMAIL read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS mkdir -p /home/web/config/ @@ -1716,7 +1716,7 @@ web_del() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. + # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. echo "데이터베이스 삭제 :$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -2003,7 +2003,7 @@ web_security() { echo "31. WAF 32를 켜십시오. WAF를 끄십시오" echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 방어 프로그램 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -2107,7 +2107,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlare 모드는 CF 배경, Site-Security-Events에서 인터셉트 레코드를 보도록 구성됩니다." + echo "Cloudflare 모드가 구성되었으며, 차단 기록은 cf 백그라운드, site-security-events에서 볼 수 있습니다." ;; 22) @@ -2182,7 +2182,7 @@ CONFIG_FILE="/home/web/nginx.conf" # 현재 Worker_Processes 설정 값을 얻으십시오 current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 값에 따라 모드 정보를 설정합니다 +# 값에 따라 모드 정보 설정 if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2212,7 +2212,7 @@ check_nginx_compression() { br_status="" fi - # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 + # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2575,7 +2575,7 @@ clear_container_rules() { fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules } @@ -2626,12 +2626,12 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 로컬 액세스 허용 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 확립 및 관련 연결을 위해 트래픽을 허용합니다 + # 확립된 관련 연결에 대한 트래픽 허용 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi @@ -2649,7 +2649,7 @@ clear_host_port_rules() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." - echo "사용법 : CLEAR_HOST_PORT_RULES <포트 번호> <승인 IP>" + echo "사용법:clear_host_port_rules <포트 번호> <허용 IP>" return 1 fi @@ -2867,7 +2867,7 @@ docker_app_plus() { echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) setup_docker_dir @@ -2910,7 +2910,7 @@ docker_app_plus() { clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "IP 접근 차단${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -3138,7 +3138,7 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx 환경을 설치하십시오" +send_stats "nginx 환경 설치" root_use clear echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" @@ -3207,7 +3207,7 @@ ldnmp_wp() { webname="WordPress" yuming="${1:-}" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3287,7 +3287,7 @@ ldnmp_Proxy_backend() { fi if [ -z "$reverseproxy_port" ]; then - read -e -p "공간으로 분리 된 여러 반세대 IP+ 포트를 입력하십시오 (예 : 127.0.0.1:3000 127.0.1:3002) :" reverseproxy_port + read -e -p "여러 개의 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port fi nginx_install_status @@ -3386,7 +3386,7 @@ ldnmp_web_status() { case $sub_choice in 1) send_stats "도메인 이름 인증서를 신청하십시오" - read -e -p "도메인 이름을 입력하십시오 :" yuming + read -e -p "도메인 이름을 입력하세요:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3442,8 +3442,8 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "관련 사이트를 만듭니다" - echo -e "액세스 용 기존 사이트의 새 도메인 이름을 연결하십시오." + send_stats "연결된 사이트 만들기" + echo -e "액세스하려면 새 도메인 이름을 기존 사이트에 연결하세요." read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot @@ -3464,12 +3464,12 @@ ldnmp_web_status() { break_end ;; 6) - send_stats "오류 로그를 봅니다" + send_stats "오류 로그 보기" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "글로벌 구성 편집" + send_stats "전역 구성 편집" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload @@ -3620,7 +3620,7 @@ EOF donlond_frp frps - # 출력 생성 정보 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개 변수" @@ -3662,12 +3662,12 @@ EOF } add_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 추가하십시오" + send_stats "FRP 인트라넷 서비스 추가" # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 read -e -p "서비스 이름을 입력하십시오 :" service_name read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip + read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "인트라넷 포트를 입력하십시오 :" local_port read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port @@ -3695,9 +3695,9 @@ EOF delete_forwarding_service() { send_stats "FRP 인트라넷 서비스를 삭제하십시오" - # 삭제 해야하는 서비스 이름을 입력하라는 메시지 + # 삭제해야 하는 서비스 이름을 입력하라는 메시지를 사용자에게 표시합니다. read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name - # SED를 사용하여 서비스 및 관련 구성을 삭제하십시오. + # sed를 사용하여 서비스 및 관련 구성 삭제 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" @@ -3739,7 +3739,7 @@ list_forwarding_services() { type } - # 현재 서비스 이름을 업데이트하십시오 + # 현재 서비스 이름 업데이트 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -3804,7 +3804,7 @@ generate_access_urls() { fi done - # 유효한 포트가있을 때만 제목과 콘텐츠 표시 + # 유효한 포트가 있는 경우에만 제목과 내용 표시 if [ "$has_valid_ports" = true ]; then echo "FRP 서비스 외부 액세스 주소 :" @@ -3861,7 +3861,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP 서버$check_frp $update_status" echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -3929,7 +3929,7 @@ frps_panel() { 8) send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단할 수 있습니다." + echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." read -e -p "차단 해야하는 포트를 입력하십시오." frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4079,11 +4079,11 @@ yt_menu_pro() { read ;; 2) send_stats "yt-dlp 업데이트 ..." - echo "yt-dlp 업데이트 ..." + echo "yt-dlp 업데이트 중..." yt-dlp -U add_app_id - echo "업데이트가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "업데이트가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 3) send_stats "yt-dlp 제거 ..." @@ -4110,7 +4110,7 @@ yt_menu_pro() { echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "이제 배치 다운로드를 시작하십시오 ..." + echo "지금 일괄 다운로드를 시작하세요..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4118,7 +4118,7 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "배치 다운로드가 완료되었습니다. 키를 눌러 계속하십시오 ..." ;; + read -e -p "일괄 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 7) send_stats "맞춤형 비디오 다운로드" read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom @@ -4187,7 +4187,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" + echo -e "${gl_huang}시스템 업데이트 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4275,7 +4275,7 @@ linux_clean() { elif command -v pkg &>/dev/null; then echo "사용하지 않는 의존성 정리 ..." pkg autoremove -y - echo "패키지 관리자 캐시 청소 ..." + echo "패키지 관리자 캐시 정리..." pkg clean -y echo "시스템 로그 삭제 ..." rm -rf /var/log/* @@ -4392,7 +4392,7 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthentication이 발견되면 예로 설정하십시오 + # 발견된 경우 PasswordAuthentication이 yes로 설정되어 있습니다. if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4527,7 +4527,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" install wget @@ -4550,7 +4550,7 @@ dd_xitong() { } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 @@ -4682,7 +4682,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10을 다시 설치하십시오" + send_stats "oracle10 재설치" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4706,7 +4706,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41을 다시 설치하십시오" + send_stats "fedora41 재설치" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4818,7 +4818,7 @@ dd_xitong() { ;; 46) - send_stats "Windows Server 19를 다시 설치하십시오" + send_stats "윈도우 서버 19 재설치" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot @@ -4843,7 +4843,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3 관리" + send_stats "bbrv3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4909,7 +4909,7 @@ bbrv3() { clear echo "BBR3 가속도를 설정하십시오" - echo "비디오 소개 : https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투 만 지원합니다" echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." @@ -4949,7 +4949,7 @@ bbrv3() { bbr_on - echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4959,7 +4959,7 @@ bbrv3() { echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac fi @@ -5200,7 +5200,7 @@ optimize_high_performance() { sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5229,7 +5229,7 @@ optimize_high_performance() { # 이퀄라이제이션 모드 최적화 기능 optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" + echo -e "${gl_lv}이퀄라이제이션 모드로 전환...${gl_bai}" echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 32768 @@ -5241,7 +5241,7 @@ optimize_balanced() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5310,7 +5310,7 @@ restore_defaults() { -# 웹 사이트 구축 최적화 기능 +# 웹사이트 구축 최적화 기능 optimize_web_server() { echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" @@ -5343,9 +5343,9 @@ optimize_web_server() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # NUMA 밸런싱 비활성화 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5360,7 +5360,7 @@ Kernel_optimize() { echo "Linux 시스템에서 커널 매개 변수의 최적화" echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." + echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" echo "--------------------" echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." @@ -5452,7 +5452,7 @@ update_locale() { break_end ;; *) - echo "지원되지 않는 시스템 :$ID" + echo "지원되지 않는 시스템:$ID" break_end ;; esac @@ -5489,7 +5489,7 @@ while true; do ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "전통적인 중국어로 전환하십시오" + send_stats "중국어 번체로 전환" ;; *) break @@ -5656,7 +5656,7 @@ bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/ # 백업을 만듭니다 create_backup() { - send_stats "백업을 만듭니다" + send_stats "백업 만들기" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 @@ -5714,7 +5714,7 @@ create_backup() { # 백업을 복원하십시오 restore_backup() { - send_stats "백업을 복원하십시오" + send_stats "백업 복원" # 복원하려는 백업을 선택하십시오 read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME @@ -5728,14 +5728,14 @@ restore_backup() { tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "백업 및 복원을 성공적으로 복원하십시오!" + echo "백업 및 복원 성공!" else - echo "백업 복구 실패!" + echo "백업 복원에 실패했습니다!" exit 1 fi } -# 백업을 나열합니다 +# 백업 나열 list_backups() { echo "사용 가능한 백업 :" ls -1 "$BACKUP_DIR" @@ -5817,7 +5817,7 @@ add_connection() { echo "- 포트 : 22" echo "------------------------" read -e -p "연결 이름을 입력하십시오 :" name - read -e -p "IP 주소를 입력하십시오 :" ip + read -e -p "请输入IP地址: " ip read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user local user=${user:-root} # 如果用户未输入,则使用默认值 root read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port @@ -5867,7 +5867,7 @@ add_connection() { -# 연결을 삭제하십시오 +# 연결 삭제 delete_connection() { send_stats "연결을 삭제하십시오" read -e -p "삭제하려면 연결 번호를 입력하십시오." num @@ -5924,8 +5924,8 @@ use_connection() { sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "연결 실패! 다음을 확인하십시오." - echo "1. 사용자 이름과 비밀번호가 올바른지 여부." - echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." + echo "1. 사용자 이름과 비밀번호가 정확합니까?" + echo "2. 대상 서버에서 비밀번호 로그인을 허용하는지 여부." echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." fi fi @@ -6049,7 +6049,7 @@ list_mounted_partitions() { # 형식 파티션 format_partition() { - send_stats "형식 파티션" + send_stats "파티션 포맷" read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION # 파티션이 있는지 확인하십시오 @@ -6129,7 +6129,7 @@ disk_manager() { echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6161,13 +6161,13 @@ add_task() { echo "- 로컬 디렉토리 : /var /www" echo "- 원격 주소 : user@192.168.1.100" echo "- 원격 디렉토리 : /백업 /www" - echo "- 포트 번호 (기본 22)" + echo "- 포트 번호(기본값 22)" echo "---------------------------------" read -e -p "작업 이름을 입력하십시오 :" name read -e -p "로컬 디렉토리를 입력하십시오 :" local_path read -e -p "원격 디렉토리를 입력하십시오 :" remote_path read -e -p "원격 사용자 @IP를 입력하십시오 :" remote - read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port + read -e -p "SSH 포트(기본값 22)를 입력하세요." port port=${port:-22} echo "인증 방법을 선택하십시오 :" @@ -6177,7 +6177,7 @@ add_task() { case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "비밀번호를 입력하세요:" password_or_key echo # 换行 auth_method="password" ;; @@ -6189,7 +6189,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6299,7 +6299,7 @@ run_task() { if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." echo "설치 방법 :" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -6339,14 +6339,14 @@ schedule_task() { read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "오류: 유효한 작업 번호를 입력하십시오!" return fi echo "시간이 정한 실행 간격을 선택하십시오." echo "1) 한 시간에 한 번 실행하십시오" - echo "2) 하루에 한 번 수행하십시오" - echo "3) 일주일에 한 번 실행하십시오" + echo "2) 하루에 한 번 실행" + echo "3) 일주일에 한 번 실행" read -e -p "옵션을 입력하십시오 (1/2/3) :" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 @@ -6372,7 +6372,7 @@ schedule_task() { echo "타이밍 작업이 만들어졌습니다.$cron_job" } -# 예정된 작업을 봅니다 +# 예약된 작업 보기 view_tasks() { echo "현재 타이밍 작업 :" echo "---------------------------------" @@ -6503,7 +6503,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" - echo -e "${gl_kjlan}물리적 기억 :${gl_bai}$mem_info" + echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" @@ -6543,8 +6543,8 @@ linux_tools() { echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" - echo -e "${gl_kjlan}9. ${gl_bai}Tmux 다중 채널 배경 달리기 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" + echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" @@ -6552,7 +6552,7 @@ linux_tools() { echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" @@ -6713,14 +6713,14 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix를 설치하십시오" + send_stats "cmatrix 설치" ;; 22) clear install sl clear sl - send_stats "SL을 설치하십시오" + send_stats "sl 설치" ;; 26) clear @@ -6741,7 +6741,7 @@ linux_tools() { install ninvaders clear ninvaders - send_stats "Ninvaders를 설치하십시오" + send_stats "닌베이더 설치" ;; 31) @@ -6773,7 +6773,7 @@ linux_tools() { clear read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename remove $removename - send_stats "지정된 소프트웨어를 제거하십시오" + send_stats "지정된 소프트웨어 제거" ;; 0) @@ -6903,7 +6903,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}감지$c예, Docker-compose 컨테이너${NC}" + echo -e "${BLUE}감지됨$c예, Docker-compose 컨테이너${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -6913,7 +6913,7 @@ docker_ssh_migration() { # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}작곡 프로젝트 [$project_name] 백업, 중복 포장을 건너 뛰십시오 ...${NC}" + echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" continue fi @@ -6989,7 +6989,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # ----------------------------- + # --------- Compose 프로젝트 복원 우선순위 지정 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -6998,10 +6998,10 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path - # Compose 프로젝트 용 컨테이너가 이미 실행 중인지 확인하십시오. + # Compose 프로젝트의 컨테이너가 이미 실행 중인지 확인하세요. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" continue fi @@ -7080,7 +7080,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" - # /home /docker에서 파일을 복원하십시오 + # /home/docker 아래의 파일 복원 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home /docker에서 파일을 복원 ...${NC}" mkdir -p /home/docker @@ -7142,7 +7142,7 @@ docker_ssh_migration() { list_backups echo -e "" echo "------------------------" - echo -e "1. Docker 프로젝트를 백업하십시오" + echo -e "1. 도커 프로젝트 백업" echo -e "2. Docker 프로젝트를 마이그레이션합니다" echo -e "3. Docker 프로젝트를 복원하십시오" echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" @@ -7186,16 +7186,16 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너 및 미러 네트워크 데이터 볼륨을 청소하십시오" + echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너를 정리하고 네트워크 데이터 볼륨을 미러링하세요." echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" - echo -e "${gl_kjlan}12. ${gl_bai}Docker-IPV6 액세스를 닫습니다" + echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 액세스 끄기" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}19. ${gl_bai}백업/마이그레이션/복원 Docker 환경" - echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경을 제거하십시오" + echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경 제거" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7227,7 +7227,7 @@ linux_docker() { echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" + echo -e "Docker 볼륨:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" @@ -7283,7 +7283,7 @@ linux_docker() { case $sub_choice in 1) - send_stats "네트워크를 만듭니다" + send_stats "네트워크 생성" read -e -p "새 네트워크 이름 설정 :" dockernetwork docker network create $dockernetwork ;; @@ -7477,9 +7477,9 @@ linux_test() { echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC 다기능 속도 테스트 스크립트" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -7509,7 +7509,7 @@ linux_test() { ;; 3) clear - send_stats "YEAHWU 스트리밍 미디어 잠금 해제 탐지" + send_stats "예우 스트리밍 미디어 잠금 해제 감지" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; @@ -7552,7 +7552,7 @@ linux_test() { echo "베이징 모바일 : 221.179.155.161" echo "상하이 통신 : 202.96.209.133" echo "상하이 유니폼 : 210.22.97.1" - echo "상하이 모바일 : 211.136.112.200" + echo "상하이 모바일: 211.136.112.200" echo "광저우 통신 : 58.60.188.222" echo "광저우 유니폼 : 210.21.196.6" echo "광저우 모바일 : 120.196.165.24" @@ -7699,12 +7699,12 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" + send_stats "Oracle Cloud 제거 활성 스크립트" ;; 3) clear - echo "시스템을 다시 설치하십시오" + echo "시스템 재설치" echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." read -e -p "계속할거야? (Y/N) :" choice @@ -7838,13 +7838,13 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP 웹 사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPress를 설치하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginx 만 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" + echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -7944,7 +7944,7 @@ linux_ldnmp() { 5) clear - # Apple CMS + # AppleCMS webname="苹果CMS" send_stats "설치하다$webname" echo "배포를 시작하십시오$webname" @@ -7978,7 +7978,7 @@ linux_ldnmp() { echo "데이터베이스 이름 :$dbname" echo "사용자 이름 :$dbuse" echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사 : MAC_" + echo "데이터베이스 접두사: mac_" echo "------------------------" echo "설치가 성공한 후 배경 주소에 로그인하십시오." echo "https://$yuming/vip.php" @@ -8011,7 +8011,7 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 주소: mysql" echo "데이터베이스 포트 : 3306" echo "데이터베이스 이름 :$dbname" echo "사용자 이름 :$dbuse" @@ -8182,7 +8182,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리에서" read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then @@ -8451,7 +8451,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리에서" read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download if [ -n "$url_download" ]; then @@ -8462,7 +8462,7 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이 위치한 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} @@ -8583,7 +8583,7 @@ linux_ldnmp() { linux_ldnmp fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8825,29 +8825,29 @@ while true; do echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" + echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}Stirlingpdf 도구 컬렉션${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" - echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}Websh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" - echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdesk 원격 책상 (릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹 사이트 빌딩 관리 패널" + echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}점프 서버 오픈 소스 요새 기계" + echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" @@ -8858,12 +8858,12 @@ while true; do echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" - echo -e "${gl_kjlan}85. ${color85}Immich 사진 비디오 관리자${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" + echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" echo -e "${gl_kjlan}89. ${color89}filecodebox 파일 Express${gl_kjlan}90. ${color90}매트릭스 분산 채팅 프로토콜" echo -e "${gl_kjlan}------------------------" @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI 비디오 생성 도구" + echo -e "${gl_kjlan}101. ${color101}AI 비디오 생성 도구${gl_kjlan}102. ${color102}vecechat 멀티 플레이어 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" echo -e "${gl_kjlan}------------------------" @@ -9032,7 +9032,7 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 이름 설정:" admin read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop-ubuntu \ @@ -9075,7 +9075,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9157,7 +9157,7 @@ while true; do clear echo -e "우체국 서비스$check_docker $update_status" echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" echo "포트 감지" @@ -9166,7 +9166,7 @@ while true; do if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" else - echo -e "${gl_hong}포트$port현재 사용할 수 없습니다${gl_bai}" + echo -e "${gl_hong}포트$port현재는 이용할 수 없습니다${gl_bai}" fi echo "" @@ -9221,7 +9221,7 @@ while true; do add_app_id clear - echo "Poste.io가 설치되었습니다" + echo "poste.io가 설치되었습니다" echo "------------------------" echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." echo "https://$yuming" @@ -9313,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -9600,7 +9600,7 @@ while true; do add_app_id clear - echo "Thunder Pool WAF 패널이 업데이트되었습니다" + echo "Leichi WAF 패널이 업데이트되었습니다." check_docker_app_ip ;; 3) @@ -10278,7 +10278,7 @@ while true; do ip_address echo "설치" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" + echo "초기 사용자 이름과 비밀번호는 admin입니다." } docker_app_update() { @@ -10518,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -11568,7 +11568,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." + echo "초기 사용자 또는 관리자를 생성합니다. 다음 사용자 이름과 비밀번호를 설정하고 관리자인지 여부를 설정하세요." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11758,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11772,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; @@ -12173,7 +12195,7 @@ while true; do scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." else - echo "전송할 파일은 찾을 수 없었습니다." + echo "전송할 파일을 찾을 수 없습니다." fi break ;; @@ -12206,7 +12228,7 @@ while true; do fi if [ -n "$filename" ]; then - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." else @@ -12245,9 +12267,9 @@ linux_work() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" - echo -e "${gl_kjlan}3. ${gl_bai}작업 공간 번호 3" + echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" @@ -12269,7 +12291,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; @@ -12359,7 +12381,7 @@ linux_work() { install tmux local SESSION_NAME="sshd" send_stats "작업 공간을 시작하십시오$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n# 자동으로 tmux 세션을 입력 \ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 자동으로 tmux 세션 시작\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12375,7 +12397,7 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME + read -e -p "1001 kj001 work1과 같이 생성하거나 입력한 작업공간의 이름을 입력하세요." SESSION_NAME tmux_run send_stats "사용자 정의 작업 공간" ;; @@ -12425,20 +12447,20 @@ linux_Settings() { # Send_stats "시스템 도구" echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소를 최적화합니다${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속 설정" echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" - echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}타이밍 작업 관리" + echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}예약된 작업 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}루트 비공개 키 로그인 모드" + echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" @@ -12450,12 +12472,12 @@ linux_Settings() { echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 및 보안" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -12537,7 +12559,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "알 수없는 패키지 관리자!" + echo "알 수 없는 패키지 관리자입니다!" return fi @@ -12566,7 +12588,7 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" send_stats "스크립트 Py 버전을 스위치하십시오" ;; @@ -12608,8 +12630,8 @@ EOF send_stats "SSH 포트 수정을 종료하십시오" break else - echo "포트 번호는 유효하지 않으며 1에서 65535 사이의 숫자를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "포트 번호가 잘못되었습니다. 1~65535 사이의 숫자를 입력하세요." + send_stats "잘못된 SSH 포트가 입력되었습니다." break_end fi else @@ -12778,7 +12800,7 @@ EOF echo "------------------------" echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." echo "------------------------" - echo "5. 계정을 삭제하십시오" + echo "5. 계정 삭제" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -12814,7 +12836,7 @@ EOF ;; 3) read -e -p "사용자 이름을 입력하십시오 :" username - # 새로운 사용자에게 허가를 부여하십시오 + # 새 사용자에게 sudo 권한 부여 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12827,7 +12849,7 @@ EOF ;; 5) read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자와 홈 디렉토리를 삭제하십시오 + # 사용자 및 해당 홈 디렉터리 삭제 userdel -r "$username" ;; @@ -12849,7 +12871,7 @@ EOF done echo "" - echo "임의 이름" + echo "임의의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") @@ -12891,7 +12913,7 @@ EOF 15) root_use - send_stats "시간대를 변경하십시오" + send_stats "시간대 변경" while true; do clear echo "시스템 시간 정보" @@ -12912,7 +12934,7 @@ EOF echo "아시아" echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" - echo "5. 싱가포르 시간 6. 인도의 콜카타 시간" + echo "5. 싱가포르 시간 6. 콜카타, 인도 시간" echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" echo "9. 태국 방콕에서의 시간" echo "------------------------" @@ -12926,7 +12948,7 @@ EOF echo "23. 캐나다 시간 24. 멕시코 시간" echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC 글로벌 표준 시간" + echo "31. UTC 세계 표준시" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -13068,7 +13090,7 @@ EOF case $sub_choice in 1) - read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest + read -e -p "새 작업의 실행 명령을 입력하십시오:" newquest echo "------------------------" echo "1. 월간 작업 2. 주간 작업" echo "3. 일일 작업 4. 시간당 작업" @@ -13120,7 +13142,7 @@ EOF send_stats "지역 호스트 구문 분석" while true; do clear - echo "기본 호스트 구문 분석 목록" + echo "기본 호스트 확인 목록" echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." cat /etc/hosts echo "" @@ -13211,9 +13233,9 @@ EOF echo "현재 제한 종료 기능" echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" + echo "서버가 다시 시작되면 현재 트래픽 사용량이 지워집니다!" output_status - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" + echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" # limiting_shut_down.sh 파일이 있는지 확인하십시오 @@ -13231,9 +13253,9 @@ EOF echo "------------------------------------------------" echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" echo "------------------------" - echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" + echo "1. 전류 제한 종료 기능을 활성화합니다. 2. 전류 제한 종료 기능을 비활성화합니다." echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" Limiting @@ -13279,10 +13301,10 @@ EOF 24) root_use - send_stats "개인 키 로그인" + send_stats "개인키 로그인" while true; do clear - echo "루트 비공개 키 로그인 모드" + echo "ROOT 개인 키 로그인 모드" echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" @@ -13335,7 +13357,7 @@ EOF echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -13525,7 +13547,7 @@ EOF fi set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소를 자동으로 최적화합니다${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소 자동 최적화${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker @@ -13584,7 +13606,7 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 활성화되었습니다" + echo "수집이 시작되었습니다" send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" ;; 2) @@ -13668,7 +13690,7 @@ linux_file() { ls --color=auto -x echo "------------------------" echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" echo "------------------------" echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" echo "15. 파일을 삭제하십시오" @@ -13689,7 +13711,7 @@ linux_file() { 2) # 创建目录 read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" - send_stats "디렉토리를 만듭니다" + send_stats "디렉터리 생성" ;; 3) # 修改目录权限 read -e -p "디렉토리 이름을 입력하십시오 :" dirname @@ -13700,11 +13722,11 @@ linux_file() { 4) # 重命名目录 read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "디렉토리의 이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + mv "$current_name" "$new_name" && echo "디렉터리 이름이 변경되었습니다." || echo "이름 바꾸지 실패했습니다" send_stats "디렉토리의 이름을 바꿉니다" ;; 5) # 删除目录 - read -e -p "삭제하려면 디렉토리 이름을 입력하십시오." dirname + read -e -p "삭제할 디렉터리 이름을 입력하세요:" dirname rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" send_stats "디렉토리 삭제" ;; @@ -13737,7 +13759,7 @@ linux_file() { ;; 15) # 删除文件 read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제가 실패했습니다" + rm -f "$filename" && echo "파일이 삭제되었습니다." || echo "삭제가 실패했습니다" send_stats "파일 삭제" ;; 21) # 压缩文件/目录 @@ -13747,9 +13769,9 @@ linux_file() { send_stats "압축 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "파일 이름 (.tar.gz)을 입력하십시오." filename + read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오:" filename install tar - tar -xzvf "$filename" && echo "압축 압축$filename" || echo "감압이 실패했습니다" + tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "감압이 실패했습니다" send_stats "압축 파일/디렉토리 해제" ;; @@ -13757,7 +13779,7 @@ linux_file() { read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path if [ ! -e "$src_path" ]; then echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 이동 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -13805,17 +13827,17 @@ linux_file() { read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then echo "오류 : 원격 서버 IP를 입력하십시오." - send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" + send_stats "파일 전송 실패: 원격 서버 IP가 입력되지 않았습니다." continue fi - read -e -p "원격 서버 사용자 이름 (기본 루트)을 입력하십시오." remote_user + read -e -p "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" remote_user remote_user=${remote_user:-root} read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password echo if [ -z "$remote_password" ]; then - echo "오류 : 원격 서버 비밀번호를 입력하십시오." + echo "오류: 원격 서버 비밀번호를 입력하세요." send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" continue fi @@ -13920,9 +13942,9 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}백업 클러스터${gl_kjlan}5. ${gl_bai}클러스터를 복원하십시오" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}배치로 작업을 실행합니다${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}기술 라이온 스크립트를 설치하십시오${gl_kjlan}12. ${gl_bai}시스템을 업데이트하십시오${gl_kjlan}13. ${gl_bai}시스템을 청소하십시오" + echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템을 업데이트하십시오${gl_kjlan}13. ${gl_bai}시스템을 청소하십시오" echo -e "${gl_kjlan}14. ${gl_bai}Docker를 설치하십시오${gl_kjlan}15. ${gl_bai}BBR3을 설치하십시오${gl_kjlan}16. ${gl_bai}1G 가상 메모리를 설정하십시오" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정하십시오${gl_kjlan}18. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}51. ${gl_bai}맞춤 명령" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정하십시오${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 명령" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -13932,7 +13954,7 @@ while true; do 1) send_stats "클러스터 서버를 추가하십시오" read -e -p "서버 이름 :" server_name - read -e -p "서버 IP :" server_ip + read -e -p "서버 IP:" server_ip read -e -p "서버 포트 (22) :" server_port local server_port=${server_port:-22} read -e -p "서버 사용자 이름 (루트) :" server_username @@ -13956,7 +13978,7 @@ while true; do 4) clear send_stats "백업 클러스터" - echo -e "제발${gl_huang}/root/cluster/servers.py${gl_bai}파일을 다운로드하고 백업을 완료하십시오!" + echo -e "바꿔주세요${gl_huang}/root/cluster/servers.py${gl_bai}파일을 다운로드하고 백업을 완료하십시오!" break_end ;; @@ -14014,10 +14036,10 @@ done kejilion_Affiliates() { clear -send_stats "광고 열" +send_stats "광고 칼럼" echo "광고 열" echo "------------------------" -echo "그것은 사용자에게 더 간단하고 우아한 홍보 및 구매 경험을 제공 할 것입니다!" +echo "사용자에게 더욱 간단하고 우아한 프로모션 및 구매 경험을 제공할 것입니다!" echo "" echo -e "서버 제안" echo "------------------------" @@ -14080,7 +14102,7 @@ while true; do if [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}당신은 이미 최신 버전입니다!${gl_huang}v$sh_v${gl_bai}" - send_stats "스크립트는 최신 상태이며 업데이트가 필요하지 않습니다." + send_stats "스크립트가 이미 최신 상태이므로 업데이트할 필요가 없습니다." else echo "새 버전을 발견하십시오!" echo -e "현재 버전 v$sh_v최신 버전${gl_huang}v$sh_v_new${gl_bai}" @@ -14210,7 +14232,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ + p) send_stats "Eudemons Parlu 서버 오픈 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; @@ -14228,10 +14250,10 @@ send_stats "K 명령 참조 사용 사례" echo "-------------------" echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" echo "다음은 K 명령 참조 유스 케이스입니다." -echo "스크립트 시작 k" +echo "시작 스크립트 k" echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" -echo "업데이트 시스템 K 업데이트 | K 업데이트" +echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "깨끗한 시스템 쓰레기 K Clean | K 청소" echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" echo "BBR3 제어판 K BBR3 | K bbrv3" @@ -14251,13 +14273,13 @@ echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합 echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" echo "도메인 이름 인증서 응용 프로그램 K SSL" -echo "도메인 이름 인증서 만료 쿼리 K SSL PS" +echo "도메인 이름 인증서 만료 쿼리 k SSL ps" echo "Docker Management Plane K Docker" echo "도커 환경 설치 K 도커 설치 | K 도커 설치" echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" echo "Docker Image Management K Docker img | K Docker Image" echo "LDNMP 사이트 관리 K 웹" -echo "LDNMP 캐시 정리 K 웹 캐시" +echo "LDNMP 캐시 정리 k 웹 캐시" echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 5ee2d1c24..aadf4d9c8 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.7" +sh_v="4.1.8" gl_hui='\e[37m' @@ -7890,7 +7890,7 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20240520.zip + wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip unzip latest.zip rm latest.zip @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具" + echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -11531,8 +11531,8 @@ while true; do local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="" - local docker_passwd="" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -12140,6 +12140,28 @@ while true; do 102) + local app_id="102" + local docker_name="vocechat-server" + local docker_img="privoce/vocechat-server:latest" + local docker_port=8102 + + docker_rum() { + + docker run -d --restart=always \ + -p ${docker_port}:3000 \ + --name vocechat-server \ + -v /home/docker/vocechat/data:/home/vocechat-server/data \ + privoce/vocechat-server:latest + + } + + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + ;; From c8874154efacf73d2e689a264bda82e19e2211ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 7 Oct 2025 09:48:42 +0800 Subject: [PATCH 0261/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0fb6077be..67745a43f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" From a4caa2588d69710a0975781eee0ffce48b5e898a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 7 Oct 2025 09:49:09 +0800 Subject: [PATCH 0262/1285] Fix formatting of AI video generation tool entry --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e1b27b425..3c72a1e49 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" From 067ea5d3576f485e34dc54c99bef920aa8029c1a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 8 Oct 2025 14:26:08 +0000 Subject: [PATCH 0263/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-08=2014:26:08?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 1328 ++++++++++++++-------------- jp/kejilion.sh | 2266 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 2154 ++++++++++++++++++++++----------------------- tw/kejilion.sh | 2 +- 4 files changed, 2875 insertions(+), 2875 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d29734073..f8bf8ecbd 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -57,8 +57,8 @@ CheckFirstRun_true() { -# Functions that collect function buried point information, record the current script version number, usage time, system version, CPU architecture, the country of the machine and the function name used by the user. They absolutely do not involve any sensitive information, please rest assured! Please believe me! -# Why do we need to design this function? The purpose is to better understand the functions that users like to use, and further optimize the functions to launch more functions that meet user needs. +# This function collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! +# Why is this function designed? The purpose is to better understand the functions that users like to use, and to further optimize the functions and launch more functions that meet user needs. # For the full text, you can search for the send_stats function call location, transparent and open source, and you can refuse to use it if you have any concerns. @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# Prompt the user to agree to the terms +# Prompt user to agree to terms UserLicenseAgreement() { clear echo -e "${gl_kjlan}Welcome to the Tech lion script toolbox${gl_bai}" - echo "For the first time using the script, please read and agree to the user license agreement." + echo "When using the script for the first time, please read and agree to the User License Agreement." echo "User License Agreement: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "Do you agree to the above terms? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "License consent" + send_stats "License agreement" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "Rejection of permission" + send_stats "permission denied" clear exit fi @@ -220,7 +220,7 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}hint:${gl_bai}Insufficient disk space!" + echo -e "${gl_huang}hint:${gl_bai}Not enough disk space!" echo "Current available space: $((available_space_mb/1024))G" echo "Minimum demand space:${required_gb}G" echo "The installation cannot be continued. Please clean the disk space and try again." @@ -291,13 +291,13 @@ restart() { fi } -# Start the service +# Start service start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1The service has been started." + echo "$1The service has started." else - echo "Error: Start$1Service failed." + echo "Error: start$1Service failed." fi } @@ -305,9 +305,9 @@ start() { stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1Service has been stopped." + echo "$1Service has stopped." else - echo "Error: Stop$1Service failed." + echo "Error: stop$1Service failed." fi } @@ -315,7 +315,7 @@ stop() { status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1Service status is shown." + echo "$1The service status is displayed." else echo "Error: Unable to display$1Service status." fi @@ -330,7 +330,7 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAMESet to power on." + echo "$SERVICE_NAMEIt has been set to start automatically at boot." } @@ -506,7 +506,7 @@ while true; do echo "Docker container list" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "Container operation" + echo "Container operations" echo "------------------------" echo "1. Create a new container" echo "------------------------" @@ -516,9 +516,9 @@ while true; do echo "5. Restart the specified container 9. Restart all containers" echo "------------------------" echo "11. Enter the specified container 12. View the container log" - echo "13. View container network 14. View container occupancy" + echo "13. Check the container network 14. Check the container occupancy" echo "------------------------" - echo "15. Turn on container port access 16. Turn off container port access" + echo "15. Enable container port access 16. Close container port access" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -541,7 +541,7 @@ while true; do ;; 4) send_stats "Delete the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername docker rm -f $dockername ;; 5) @@ -582,7 +582,7 @@ while true; do break_end ;; 12) - send_stats "View container log" + send_stats "View container logs" read -e -p "Please enter the container name:" dockername docker logs $dockername break_end @@ -656,15 +656,15 @@ while true; do read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "Pull the mirror" + send_stats "Pull image" read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}Getting the image:$name${gl_bai}" + echo -e "${gl_huang}Obtaining image:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "Update the image" + send_stats "Update image" read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames for name in $imagenames; do echo -e "${gl_huang}Updating image:$name${gl_bai}" @@ -765,7 +765,7 @@ install_crontab() { return fi - echo -e "${gl_lv}crontab is installed and the cron service is running.${gl_bai}" + echo -e "${gl_lv}crontab is installed and cron service is running.${gl_bai}" } @@ -782,7 +782,7 @@ docker_ipv6_on() { echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # Use jq to handle updates of configuration files + # Use jq to handle configuration file updates local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # Check whether the current configuration already has ipv6 settings @@ -795,7 +795,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # Comparing original configuration with new configuration + # Compare original configuration to new configuration if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}IPv6 access is currently enabled${gl_bai}" else @@ -818,13 +818,13 @@ docker_ipv6_off() { return fi - # Read the current configuration + # Read current configuration local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # Use jq to handle updates of configuration files + # Use jq to handle configuration file updates local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # Check the current ipv6 status + # Check current ipv6 status local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') # Comparing original configuration with new configuration @@ -879,7 +879,7 @@ open_port() { install iptables for port in "${ports[@]}"; do - # Delete existing closing rules + # Delete existing shutdown rules iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null @@ -890,7 +890,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "The port has been opened$port" + echo "Port opened$port" fi done @@ -913,7 +913,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a close rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -928,7 +928,7 @@ close_port() { iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # Insert new rules to first + # Insert new rule into the first one iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT @@ -950,7 +950,7 @@ allow_ip() { # Delete existing blocking rules iptables -D INPUT -s $ip -j DROP 2>/dev/null - # Add allow rule + # Add allow rules if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "Released IP$ip" @@ -992,7 +992,7 @@ block_ip() { enable_ddos_defense() { - # Turn on defense DDoS + # Turn on DDoS protection iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1007,7 +1007,7 @@ enable_ddos_defense() { # Turn off DDoS Defense disable_ddos_defense() { - # Turn off defense DDoS + # Turn off DDoS protection iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1118,7 +1118,7 @@ iptables_panel() { echo "" echo "Firewall Management" echo "------------------------" - echo "1. Open the specified port 2. Close the specified port" + echo "1. Open the designated port 2. Close the designated port" echo "3. Open all ports 4. Close all ports" echo "------------------------" echo "5. IP whitelist 6. IP blacklist" @@ -1143,7 +1143,7 @@ iptables_panel() { 2) read -e -p "Please enter the closed port number:" c_port close_port $c_port - send_stats "Close specified port" + send_stats "Close the specified port" ;; 3) # Open all ports @@ -1180,7 +1180,7 @@ iptables_panel() { 5) # IP whitelist - read -e -p "Please enter the IP or IP segment to release:" o_ip + read -e -p "Please enter the allowed IP or IP segment:" o_ip allow_ip $o_ip ;; 6) @@ -1223,15 +1223,15 @@ iptables_panel() { send_stats "Allowed countries$country_codeIP" ;; 16) - read -e -p "Please enter the allowed country code (multiple country codes can be separated by spaces such as CN US JP):" country_code + read -e -p "Please enter the allowed country codes (multiple country codes can be separated by spaces, such as CN US JP):" country_code manage_country_rules allow $country_code - send_stats "Block the country$country_codeIP" + send_stats "block country$country_codeIP" ;; 17) - read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces such as CN US JP):" country_code + read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces, such as CN US JP):" country_code manage_country_rules unblock $country_code - send_stats "clear country$country_codeIP" + send_stats "Clear the country$country_codeIP" ;; *) @@ -1253,7 +1253,7 @@ add_swap() { # Get all swap partitions in the current system local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # Iterate over and delete all swap partitions + # Traverse and delete all swap partitions for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" @@ -1263,7 +1263,7 @@ add_swap() { # Make sure /swapfile is no longer used swapoff /swapfile - # Delete the old /swapfile + # Delete old /swapfile rm -f /swapfile # Create a new swap partition @@ -1317,7 +1317,7 @@ ldnmp_v() { local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # Get the php version + # Get php version local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" @@ -1463,7 +1463,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}Quickly apply for an SSL certificate, automatically renew your signature before expiration${gl_bai}" +echo -e "${gl_huang}Quickly apply for an SSL certificate and automatically renew it before expiration${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1479,7 +1479,7 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}The expiration of the applied certificate${gl_bai}" + echo -e "${gl_huang}Expiration status of applied certificates${gl_bai}" echo "Site information Certificate expiration time" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do @@ -1521,14 +1521,14 @@ certs_status() { if [ -f "$file_path" ]; then send_stats "Successful application for domain name certificate" else - send_stats "Application for domain name certificate failed" - echo -e "${gl_hong}Notice:${gl_bai}The certificate application failed. Please check the following possible reasons and try again:" - echo -e "1. Domain name spelling error ➠ Please check whether the domain name is entered correctly" - echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to this server IP" + send_stats "Domain name certificate application failed" + echo -e "${gl_hong}Notice:${gl_bai}Certificate application failed, please check the following possible reasons and try again:" + echo -e "1. Domain name is spelled incorrectly ➠ Please check whether the domain name is entered correctly" + echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to the server IP" echo -e "3. Network configuration issues ➠ If you use Cloudflare Warp and other virtual networks, please temporarily shut down" - echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open to ensure verification is accessible" + echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open and ensure that it is accessible" echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" - echo -e "6. Domestic registration restrictions ➠ Please confirm whether the domain name is registered in mainland China" + echo -e "6. Domestic registration restrictions ➠ For mainland China environment, please confirm whether the domain name is registered" break_end clear echo "Please try deploying again$webname" @@ -1551,8 +1551,8 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "Please enter your IP or the resolved domain name:" yuming + echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "Please enter your IP or resolved domain name:" yuming } @@ -1658,12 +1658,12 @@ cf_purge_cache() { ZONE_IDS=($ZONE_IDS) else # Prompt the user whether to clean the cache - read -e -p "Need to clean Cloudflare's cache? (y/n):" answer + read -e -p "Need to clear Cloudflare's cache? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF information is saved in$CONFIG_FILE, you can modify CF information later" + echo "CF information is saved in$CONFIG_FILE, you can modify the CF information later" read -e -p "Please enter your API_TOKEN:" API_TOKEN read -e -p "Please enter your CF username:" EMAIL - read -e -p "Please enter zone_id (multiple separated by spaces):" -a ZONE_IDS + read -e -p "Please enter zone_id (separate multiple with spaces):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" @@ -1686,7 +1686,7 @@ cf_purge_cache() { web_cache() { - send_stats "Clean up site cache" + send_stats "Clear site cache" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1706,7 +1706,7 @@ web_del() { fi for yuming in $yuming_list; do - echo "Deleting the domain name:$yuming" + echo "Domain name is being deleted:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 @@ -1740,7 +1740,7 @@ nginx_waf() { sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # Close WAF: Add Comments + # Turn off WAF: add comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1800,7 +1800,7 @@ patch_wp_memory_limit() { sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # Insert a new definition before the line with "Happy publishing" + # Insert the new definition before the line containing "Happy publishing" awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1851,7 +1851,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Turn on Brotli: Remove comments + # Turn on Brotli: remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1885,7 +1885,7 @@ nginx_br() { return 1 fi - # Check nginx images and handle them according to the situation + # Check the nginx image and handle it accordingly if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1907,7 +1907,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # Turn on Zstd: Remove comments + # Turn on Zstd: remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1994,11 +1994,11 @@ web_security() { echo "1. Install the defense program" echo "------------------------" echo "5. View SSH interception record 6. View website interception record" - echo "7. View the list of defense rules 8. View real-time monitoring of logs" + echo "7. View the list of defense rules 8. View logs for real-time monitoring" echo "------------------------" echo "11. Configure intercept parameters 12. Clear all blocked IPs" echo "------------------------" - echo "21. cloudflare mode 22. High load on 5 seconds shield" + echo "21. cloudflare mode 22. Enable 5 seconds shield under high load" echo "------------------------" echo "31. Turn on WAF 32. Turn off WAF" echo "33. Turn on DDOS Defense 34. Turn off DDOS Defense" @@ -2092,7 +2092,7 @@ web_security() { echo "Go to the upper right corner of the cf background, select the API token on the left, and obtain the Global API Key" echo "https://dash.cloudflare.com/login" read -e -p "Enter CF account number:" cfuser - read -e -p "Enter CF’s Global API Key:" cftoken + read -e -p "Enter the Global API Key for CF:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2107,21 +2107,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "Cloudflare mode is configured to view intercept records in the cf background, site-security-events" + echo "Cloudflare mode has been configured, and the interception record can be viewed in the cf background, site-security-events" ;; 22) - send_stats "High load on 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When high load is detected, the shield will be automatically turned on, and low load will be automatically turned off for 5 seconds.${gl_bai}" + send_stats "High load enables 5 seconds shield" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" echo -e "Go to the bottom right of the cf background domain name summary page to get${gl_huang}Region ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "Enter CF account number:" cfuser - read -e -p "Enter the Global API Key for CF:" cftoken - read -e -p "Enter the region ID of the domain name in CF:" cfzonID + read -e -p "Enter CF’s account number:" cfuser + read -e -p "Enter CF’s Global API Key:" cftoken + read -e -p "Enter the zone ID of the domain name in CF:" cfzonID cd ~ install jq bc @@ -2140,7 +2140,7 @@ web_security() { (crontab -l 2>/dev/null; echo "$cron_job") | crontab - echo "High load automatic shield opening script has been added" else - echo "Automatic shield script already exists, no need to add it" + echo "The automatic shield opening script already exists, no need to add it" fi ;; @@ -2182,7 +2182,7 @@ CONFIG_FILE="/home/web/nginx.conf" # Get the current worker_processes setting value current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# Set mode information according to value +# Set mode information based on value if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2198,21 +2198,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # Check whether zstd is enabled and not commented (the whole line starts with zstd on;) + # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Check if brotli is enabled and not commented + # Check if brotli is enabled and uncommented if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # Check if gzip is enabled and not commented + # Check if gzip is enabled and uncommented if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2231,7 +2231,7 @@ web_optimization() { send_stats "Optimize LDNMP environment" echo -e "Optimize LDNMP environment${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. Standard mode 2. High performance mode (recommended 2H4G or above)" + echo "1. Standard mode 2. High performance mode (2H4G or above recommended)" echo "------------------------" echo "3. Turn on gzip compression 4. Turn off gzip compression" echo "5. Turn on br compression 6. Turn off br compression" @@ -2242,7 +2242,7 @@ web_optimization() { read -e -p "Please enter your selection:" sub_choice case $sub_choice in 1) - send_stats "Site standard mode" + send_stats "site standards mode" # nginx tuning sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf @@ -2278,7 +2278,7 @@ web_optimization() { optimize_balanced - echo "LDNMP environment has been set to standard mode" + echo "The LDNMP environment has been set to standard mode" ;; 2) @@ -2316,7 +2316,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP environment has been set to high performance mode" + echo "The LDNMP environment has been set to high performance mode" ;; 3) @@ -2376,7 +2376,7 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker="${gl_lv}${gl_bai} installed" +# check_docker="${gl_lv} has installed ${gl_bai}" # else # check_docker="${gl_hui}${gl_bai} is not installed" # fi @@ -2386,7 +2386,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "Access address:" +echo "Visit address:" ip_address @@ -2429,11 +2429,11 @@ check_docker_image_update() { local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # Extract mirror warehouses and tags + # Extract image repository and tags local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # The default label is latest + # The default tag is latest [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" # Add support for official images @@ -2443,7 +2443,7 @@ check_docker_image_update() { local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # Verify the time of acquisition + # Verify the time obtained if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) @@ -2559,12 +2559,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules for releasing the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Clear the rules for release local network 127.0.0.0/8 + # Clear the rules that allow local network 127.0.0.0/8 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2575,7 +2575,7 @@ clear_container_rules() { fi - echo "IP+ports have been allowed to access the service" + echo "IP+port has been allowed to access the service" save_iptables_rules } @@ -2589,7 +2589,7 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "Error: Please provide the port number and the IP that is allowed to access." + echo "Error: Please provide port number and IP to allow access." echo "Usage: block_host_port " return 1 fi @@ -2597,7 +2597,7 @@ block_host_port() { install iptables - # Denied all other IP access + # Deny access from all other IPs if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -2616,12 +2616,12 @@ block_host_port() { - # Deny access from all other IPs + # Denied all other IP access if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # Allow specified IP access + # Allow access to specified IP if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2636,7 +2636,7 @@ block_host_port() { iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ ports have been blocked from accessing the service" + echo "IP+port has been blocked from accessing the service" save_iptables_rules } @@ -2656,7 +2656,7 @@ clear_host_port_rules() { install iptables - # Clear rules that block all other IP access + # Clear the rule that blocks access from all other IPs if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2672,12 +2672,12 @@ clear_host_port_rules() { fi - # Clear rules that block all other IP access + # Clear the rule that blocks access from all other IPs if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # Clear rules that allow local access + # Clear rules that allow native access if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2750,16 +2750,16 @@ while true; do echo "1. Install 2. Update 3. Uninstall" echo "------------------------" echo "5. Add domain name access 6. Delete domain name access" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "7. Allow IP+port access 8. Block IP+port access" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port + read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2786,7 +2786,7 @@ while true; do add_app_id clear - echo "$docker_nameInstalled" + echo "$docker_nameInstallation completed" check_docker_app_ip echo "" $docker_use @@ -2800,7 +2800,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -2867,12 +2867,12 @@ docker_app_plus() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "Enter the application external service port, and enter the default${docker_port}port:" app_port + read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2896,7 +2896,7 @@ docker_app_plus() { ;; 5) echo "${docker_name}Domain name access settings" - send_stats "${docker_name}Domain access settings" + send_stats "${docker_name}Domain name access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" @@ -3111,7 +3111,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear send_stats "Unable to install LDNMP environment again" - echo -e "${gl_huang}hint:${gl_bai}The website construction environment is installed. No need to install again!" + echo -e "${gl_huang}hint:${gl_bai}The website building environment has been installed. No need to install again!" break_end linux_ldnmp fi @@ -3124,7 +3124,7 @@ cd ~ send_stats "Install LDNMP environment" root_use clear -echo -e "${gl_huang}The LDNMP environment is not installed, start installing the LDNMP environment...${gl_bai}" +echo -e "${gl_huang}The LDNMP environment is not installed. Start installing the LDNMP environment...${gl_bai}" check_disk_space 3 /home check_port install_dependency @@ -3185,7 +3185,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "Yours$webnameBuilt!" + echo "your$webnameIt's built!" echo "https://$yuming" echo "------------------------" echo "$webnameThe installation information is as follows:" @@ -3287,7 +3287,7 @@ ldnmp_Proxy_backend() { fi if [ -z "$reverseproxy_port" ]; then - read -e -p "Please enter your multiple anti-generation IP+ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3365,7 +3365,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo "Site Directory" + echo "site directory" echo "------------------------" echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" @@ -3373,12 +3373,12 @@ ldnmp_web_status() { echo "operate" echo "------------------------" echo "1. Apply for/update the domain name certificate 2. Change the site domain name" - echo "3. Clean up the site cache 4. Create an associated site" - echo "5. View access log 6. View error log" + echo "3. Clear site cache 4. Create associated site" + echo "5. View the access log 6. View the error log" echo "7. Edit global configuration 8. Edit site configuration" echo "9. Manage site database 10. View site analysis report" echo "------------------------" - echo "20. Delete the specified site data" + echo "20. Delete specified site data" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -3396,7 +3396,7 @@ ldnmp_web_status() { 2) send_stats "Change the site domain name" - echo -e "${gl_hong}Highly recommended:${gl_bai}First back up the entire site data and then change the site domain name!" + echo -e "${gl_hong}Highly recommended:${gl_bai}Back up the entire site data first and then change the site domain name!" read -e -p "Please enter the old domain name:" oddyuming read -e -p "Please enter the new domain name:" yuming install_certbot @@ -3443,8 +3443,8 @@ ldnmp_web_status() { ;; 4) send_stats "Create an associated site" - echo -e "Associate a new domain name for the existing site for access" - read -e -p "Please enter the existing domain name:" oddyuming + echo -e "Associate a new domain name with the existing site for access" + read -e -p "Please enter an existing domain name:" oddyuming read -e -p "Please enter the new domain name:" yuming install_certbot install_ssltls @@ -3477,7 +3477,7 @@ ldnmp_web_status() { 8) send_stats "Edit site configuration" - read -e -p "To edit the site configuration, please enter the domain name you want to edit:" yuming + read -e -p "To edit site configuration, please enter the domain name you want to edit:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3523,12 +3523,12 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}It is a popular and powerful operation and maintenance management panel nowadays." + echo "${panelname}It is a popular and powerful operation and maintenance management panel." echo "Official website introduction:$panelurl " echo "" echo "------------------------" - echo "1. Install 2. Management 3. Uninstall" + echo "1. Install 2. Manage 3. Uninstall" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -3664,10 +3664,10 @@ EOF add_forwarding_service() { send_stats "Add FRP intranet service" # Prompt the user to enter the service name and forwarding information - read -e -p "Please enter the service name:" service_name - read -e -p "Please enter the forwarding type (tcp/udp) [Enter default tcp]:" service_type + read -e -p "Please enter service name:" service_name + read -e -p "Please enter the forwarding type (tcp/udp) [Enter to default to tcp]:" service_type local service_type=${service_type:-tcp} - read -e -p "Please enter the intranet IP [Enter default 127.0.0.1]:" local_ip + read -e -p "Please enter the intranet IP [default is 127.0.0.1 when pressing Enter]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "Please enter the intranet port:" local_port read -e -p "Please enter the external network port:" remote_port @@ -3682,7 +3682,7 @@ remote_port = ${remote_port} EOF - # Output generated information + # Output the generated information echo "Serve$service_nameAdded successfully to frpc.toml" docker restart frpc @@ -3694,9 +3694,9 @@ EOF delete_forwarding_service() { - send_stats "Delete the frp intranet service" - # Prompt the user to enter the service name that needs to be deleted - read -e -p "Please enter the service name that needs to be deleted:" service_name + send_stats "Delete frp intranet service" + # Prompt the user to enter the name of the service that needs to be deleted + read -e -p "Please enter the service name to be deleted:" service_name # Use sed to delete the service and its related configurations sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "Serve$service_nameDeleted successfully from frpc.toml" @@ -3709,7 +3709,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # Print the header + # Print header printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3730,7 +3730,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # If there is service information, print the current service before processing the new service + # If service information already exists, print the current service before processing the new service if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3739,7 +3739,7 @@ list_forwarding_services() { type } - # Update the current service name + # Update current service name if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -3772,7 +3772,7 @@ list_forwarding_services() { } END { - # Print the information for the last service + # Print information about the last service if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3808,7 +3808,7 @@ generate_access_urls() { if [ "$has_valid_ports" = true ]; then echo "FRP service external access address:" - # Process IPv4 address + # Handling IPv4 addresses for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" @@ -3862,7 +3862,7 @@ frps_panel() { echo -e "FRP server$check_frp $update_status" echo "Build an FRP intranet penetration service environment to expose devices without public IP to the Internet" echo "Official website introduction: https://github.com/fatedier/frp/" - echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports @@ -3871,7 +3871,7 @@ frps_panel() { echo "------------------------" echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "5. Domain name access for intranet service 6. Delete domain name access" + echo "5. Intranet service domain name access 6. Delete domain name access" echo "------------------------" echo "7. Allow IP+ port access 8. Block IP+ port access" echo "------------------------" @@ -3906,7 +3906,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -3917,13 +3917,13 @@ frps_panel() { block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "Domain name format example.com without https://" web_del ;; 7) send_stats "Allow IP access" - read -e -p "Please enter the port to be released:" frps_port + read -e -p "Please enter the port that needs to be released:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; @@ -3958,9 +3958,9 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP Client$check_frp $update_status" - echo "Connect with the server. After the connection, you can create an intranet penetration service to access the Internet." + echo "Docking with the server, after docking, you can create intranet penetration service to the Internet access" echo "Official website introduction: https://github.com/fatedier/frp/" - echo "Video teaching: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3970,11 +3970,11 @@ frpc_panel() { echo "------------------------" echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "4. Add external services 5. Delete external services 6. Configure services manually" + echo "4. Add external services 5. Delete external services 6. Manually configure services" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) install jq grep ss @@ -4060,11 +4060,11 @@ yt_menu_pro() { echo "1. Install 2. Update 3. Uninstall" echo "-------------------------" echo "5. Single video download 6. Batch video download 7. Custom parameter download" - echo "8. Download as MP3 audio 9. Delete the video directory 10. Cookie management (under development)" + echo "8. Download as MP3 audio 9. Delete video directory 10. Cookie management (under development)" echo "-------------------------" echo "0. Return to the previous menu" echo "-------------------------" - read -e -p "Please enter the option number:" choice + read -e -p "Please enter option number:" choice case $choice in 1) @@ -4079,7 +4079,7 @@ yt_menu_pro() { read ;; 2) send_stats "Update yt-dlp..." - echo "Update yt-dlp..." + echo "Updating yt-dlp..." yt-dlp -U add_app_id @@ -4091,7 +4091,7 @@ yt_menu_pro() { rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "Uninstall is complete. Press any key to continue..." + echo "Uninstallation completed. Press any key to continue..." read ;; 5) send_stats "Single video download" @@ -4102,7 +4102,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "After the download is complete, press any key to continue..." ;; + read -e -p "Download completed, press any key to continue..." ;; 6) send_stats "Batch video download" install nano @@ -4187,7 +4187,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}System update...${gl_bai}" + echo -e "${gl_huang}System update in progress...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4214,7 +4214,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}Cleaning up the system...${gl_bai}" + echo -e "${gl_huang}System cleaning in progress...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4243,9 +4243,9 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "Clean the package manager cache..." + echo "Clean package manager cache..." apk cache clean - echo "Delete the system log..." + echo "Delete system log..." rm -rf /var/log/* echo "Delete APK cache..." rm -rf /var/cache/apk/* @@ -4267,7 +4267,7 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "Delete system log..." + echo "Delete the system log..." rm -rf /var/log/* echo "Delete temporary files..." rm -rf /tmp/* @@ -4277,7 +4277,7 @@ linux_clean() { pkg autoremove -y echo "Clean the package manager cache..." pkg clean -y - echo "Delete the system log..." + echo "Delete system log..." rm -rf /var/log/* echo "Delete temporary files..." rm -rf /tmp/* @@ -4406,7 +4406,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # If neither PasswordAuthentication nor PubkeyAuthentication matches, set the default value + # Sets default value if neither PasswordAuthentication nor PubkeyAuthentication matches if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4448,7 +4448,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "The private key information has been generated. Be sure to copy and save it.${gl_huang}${ipv4_address}_ssh.key${gl_bai}File for future SSH login" + echo -e "The private key information has been generated. Be sure to copy and save it. It can be saved as${gl_huang}${ipv4_address}_ssh.key${gl_bai}file for future SSH logins" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4460,14 +4460,14 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login is enabled, ROOT password login has been closed, reconnection will take effect${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" } import_sshkey() { - read -e -p "Please enter your SSH public key contents (usually starting with 'ssh-rsa' or 'ssh-ed25519'):" public_key + read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key if [[ -z "$public_key" ]]; then echo -e "${gl_hong}Error: The public key content was not entered.${gl_bai}" @@ -4488,7 +4488,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}The public key has been successfully imported, the ROOT private key login has been enabled, the ROOT password login has been closed, and the reconnection will take effect${gl_bai}" + echo -e "${gl_lv}The public key has been successfully imported, ROOT private key login has been enabled, and ROOT password login has been closed. Reconnection will take effect.${gl_bai}" } @@ -4503,7 +4503,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login is set up!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } @@ -4561,7 +4561,7 @@ dd_xitong() { echo "Reinstall the system" echo "--------------------------------" echo -e "${gl_hong}Notice:${gl_bai}Reinstallation may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." - echo -e "${gl_hui}Thanks to the script support of leitbogioro and bin456789!${gl_bai} " + echo -e "${gl_hui}Thanks to boss leitbogioro and boss bin456789 for their script support!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4586,7 +4586,7 @@ dd_xitong() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please select the system to reinstall:" sys_choice + read -e -p "Please select the system you want to reinstall:" sys_choice case "$sys_choice" in @@ -4778,7 +4778,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4794,7 +4794,7 @@ dd_xitong() { ;; 43) - send_stats "Reinstall Windows 7" + send_stats "Reinstall windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4860,13 +4860,13 @@ bbrv3() { echo "Current kernel version:$kernel_version" echo "" - echo "Kernel Management" + echo "Kernel management" echo "------------------------" echo "1. Update the BBRv3 kernel 2. Uninstall the BBRv3 kernel" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) @@ -4876,7 +4876,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # Step 3: Add a repository + # Step 3: Add repository echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4885,7 +4885,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "The XanMod kernel has been updated. Take effect after restart" + echo "XanMod kernel has been updated. Take effect after restart" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4895,7 +4895,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "The XanMod kernel is uninstalled. Take effect after restart" + echo "The XanMod kernel has been uninstalled. Take effect after restart" server_reboot ;; @@ -4911,7 +4911,7 @@ bbrv3() { echo "Set up BBR3 acceleration" echo "Video introduction: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Only support Debian/Ubuntu" + echo "Only supports Debian/Ubuntu" echo "Please back up the data and will enable BBR3 for you to upgrade the Linux kernel." echo "------------------------------------------------" read -e -p "Are you sure to continue? (Y/N):" choice @@ -4971,7 +4971,7 @@ elrepo_install() { # Import ELRepo GPG public key echo "Import the ELRepo GPG public key..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # Check system version + # Detect system version local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) # Make sure we run on a supported operating system @@ -4981,13 +4981,13 @@ elrepo_install() { linux_Settings fi # Print detected operating system information - echo "Operating system detected:$os_name $os_version" + echo "Detected operating systems:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then echo "Install ELRepo repository configuration (version 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Install ELRepo repository configuration (version 9)..." + echo "Installing the ELRepo repository configuration (version 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "Install ELRepo repository configuration (version 10)..." @@ -5001,7 +5001,7 @@ elrepo_install() { echo "Enable the ELRepo kernel repository and install the latest mainline kernel..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "The ELRepo repository configuration is installed and updated to the latest mainline kernel." + echo "Installed ELRepo repository configuration and updated to latest mainline kernel." server_reboot } @@ -5020,26 +5020,26 @@ elrepo() { echo "" echo "Kernel Management" echo "------------------------" - echo "1. Update the elrepo kernel 2. Uninstall the elrepo kernel" + echo "1. Update elrepo kernel 2. Uninstall elrepo kernel" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Update the Red Hat kernel" + send_stats "Update Red Hat Kernel" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "The elrepo kernel is uninstalled. Take effect after restart" - send_stats "Uninstall the Red Hat kernel" + echo "The elrepo kernel has been uninstalled. Take effect after restart" + send_stats "Uninstall Red Hat Kernel" server_reboot ;; @@ -5052,19 +5052,19 @@ elrepo() { else clear - echo "Please back up the data and will upgrade the Linux kernel for you" + echo "Please back up your data and we will upgrade the Linux kernel for you." echo "Video introduction: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Only support Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" + echo "Only supports Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if conditions permit and upgrade the production environment with caution!" echo "------------------------------------------------" - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Upgrade the Red Hat kernel" + send_stats "Upgrade Red Hat kernel" server_reboot ;; [Nn]) @@ -5082,7 +5082,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}Update the virus database...${gl_bai}" + echo -e "${gl_huang}Updating virus database...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5092,7 +5092,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "Please specify the directory to scan." + echo "Please specify the directories to scan." return fi @@ -5142,13 +5142,13 @@ clamav() { echo "Video introduction: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "It is an open source antivirus software tool, mainly used to detect and remove various types of malware." - echo "Including viruses, Trojan horses, spyware, malicious scripts and other harmful software." + echo "Includes viruses, Trojan horses, spyware, malicious scripts and other harmful software." echo "------------------------" - echo -e "${gl_lv}1. Full disk scan${gl_bai} ${gl_huang}2. Scan the important directory${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" + echo -e "${gl_lv}1. Full disk scan${gl_bai} ${gl_huang}2. Scan important directories${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "Full disk scan" @@ -5186,7 +5186,7 @@ clamav() { -# High-performance mode optimization function +# High performance mode optimization function optimize_high_performance() { echo -e "${gl_lv}Switch to${tiaoyou_moshi}...${gl_bai}" @@ -5227,7 +5227,7 @@ optimize_high_performance() { } -# Equalization mode optimization function +# Balanced mode optimization function optimize_balanced() { echo -e "${gl_lv}Switch to equalization mode...${gl_bai}" @@ -5268,9 +5268,9 @@ optimize_balanced() { } -# Restore default settings function +# Restore the default settings function restore_defaults() { - echo -e "${gl_lv}Restore to default settings...${gl_bai}" + echo -e "${gl_lv}Revert to default settings...${gl_bai}" echo -e "${gl_lv}Restore file descriptor...${gl_bai}" ulimit -n 1024 @@ -5282,7 +5282,7 @@ restore_defaults() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}Reset network settings...${gl_bai}" + echo -e "${gl_lv}Restore network settings...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5300,8 +5300,8 @@ restore_defaults() { echo -e "${gl_lv}Restore CPU settings...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}Restore other optimizations...${gl_bai}" - # Restore transparent huge pages + echo -e "${gl_lv}Revert other optimizations...${gl_bai}" + # Restore transparent page echo always > /sys/kernel/mm/transparent_hugepage/enabled # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5312,7 +5312,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to the website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5343,7 +5343,7 @@ optimize_web_server() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable large transparent pages to reduce latency + # Disable transparent huge pages to reduce latency echo never > /sys/kernel/mm/transparent_hugepage/enabled # Disable NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5360,19 +5360,19 @@ Kernel_optimize() { echo "Optimization of kernel parameters in Linux system" echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "A variety of system parameter tuning modes are provided, and users can choose and switch according to their own usage scenarios." + echo "Provides a variety of system parameter tuning modes, and users can choose to switch according to their own usage scenarios." echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" echo "--------------------" echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." - echo "2. Balanced optimization mode: Balance between performance and resource consumption, suitable for daily use." + echo "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." echo "3. Website optimization mode: Optimize for the website server to improve concurrent connection processing capabilities, response speed and overall performance." echo "4. Live broadcast optimization mode: Optimize the special needs of live broadcast streaming to reduce latency and improve transmission performance." echo "5. Game server optimization mode: Optimize for game servers to improve concurrent processing capabilities and response speed." - echo "6. Restore the default settings: Restore the system settings to the default configuration." + echo "6. Restore default settings: Restore system settings to default configuration." echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) cd ~ @@ -5447,7 +5447,7 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" + echo -e "${gl_lv}The system language has been modified to:$langReconnect to SSH to take effect.${gl_bai}" hash -r break_end ;; @@ -5457,7 +5457,7 @@ update_locale() { ;; esac else - echo "Unsupported systems, system type cannot be recognized." + echo "Unsupported system, system type cannot be identified." break_end fi } @@ -5476,7 +5476,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -5537,7 +5537,7 @@ shell_bianse() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -5582,7 +5582,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "System Recycling Station" + send_stats "System Recycle Bin" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5597,17 +5597,17 @@ linux_trash() { fi clear - echo -e "Current recycling bin${trash_status}" - echo -e "After enabling, the files deleted by rm will first enter the recycling bin to prevent the mistaken deletion of important files!" + echo -e "Current recycle bin${trash_status}" + echo -e "After enabling it, files deleted by rm will be put into the recycle bin first to prevent accidental deletion of important files!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "The recycling bin is empty" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "Recycle bin is empty" echo "------------------------" echo "1. Enable the Recycle Bin 2. Close the Recycle Bin" echo "3. Restore content 4. Clear the recycling bin" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -5623,14 +5623,14 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "The recycling bin is closed and the file will be deleted directly." + echo "The recycle bin is closed and the files will be deleted directly." sleep 2 ;; 3) read -e -p "Enter the file name to restore:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreRestored to home directory." + echo "$file_to_restoreRestored to the home directory." else echo "The file does not exist." fi @@ -5656,14 +5656,14 @@ bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/ # Create a backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt the user to enter the backup directory - echo "Create a backup example:" + echo "Example of creating a backup:" echo "- Backup a single directory: /var/www" - echo "- Backup multiple directories: /etc /home /var/log" - echo "- Direct Enter will use the default directory (/etc /usr /home)" + echo "- Back up multiple directories: /etc /home /var/log" + echo "- Press Enter to use the default directory (/etc /usr /home)" read -r -p "Please enter the directory to back up (multiple directories are separated by spaces, and if you enter directly, use the default directory):" input # If the user does not enter a directory, use the default directory @@ -5674,7 +5674,7 @@ create_backup() { "/home" # 用户数据 ) else - # Separate the directory entered by the user into an array by spaces + # Separate the directories entered by the user into an array by spaces IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi @@ -5698,14 +5698,14 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating a backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" # Check if the command is successful if [ $? -eq 0 ]; then - echo "The backup was created successfully:$BACKUP_DIR/$BACKUP_NAME" + echo "Backup created successfully:$BACKUP_DIR/$BACKUP_NAME" else echo "Backup creation failed!" exit 1 @@ -5724,13 +5724,13 @@ restore_backup() { exit 1 fi - echo "Recovering backup$BACKUP_NAME..." + echo "Restoring backup$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "Backup and restore successfully!" + echo "Backup and restore successful!" else - echo "Backup recovery failed!" + echo "Backup restore failed!" exit 1 fi } @@ -5757,7 +5757,7 @@ delete_backup() { rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "The backup was deleted successfully!" + echo "Backup deleted successfully!" else echo "Backup deletion failed!" exit 1 @@ -5779,7 +5779,7 @@ linux_backup() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; @@ -5810,23 +5810,23 @@ list_connections() { # Add a new connection add_connection() { send_stats "Add a new connection" - echo "Example to create a new connection:" + echo "Example of creating a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" echo "- Username: root" echo "- Port: 22" echo "------------------------" - read -e -p "Please enter the connection name:" name + read -e -p "Please enter a connection name:" name read -e -p "Please enter your IP address:" ip read -e -p "Please enter the username (default: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root read -e -p "Please enter the port number (default: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "Please select the authentication method:" + echo "Please select an authentication method:" echo "1. Password" echo "2. Key" - read -e -p "Please enter the selection (1/2):" auth_choice + read -e -p "Please enter your choice (1/2):" auth_choice case $auth_choice in 1) @@ -5837,7 +5837,7 @@ add_connection() { echo "Please paste the key content (press press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # If the input is a blank line and the key content already contains the beginning, end the input + # If the input is empty and the key content already contains the beginning, the input ends if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -5862,7 +5862,7 @@ add_connection() { esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "The connection is saved!" + echo "Connection saved!" } @@ -5870,11 +5870,11 @@ add_connection() { # Delete a connection delete_connection() { send_stats "Delete a connection" - read -e -p "Please enter the connection number to delete:" num + read -e -p "Please enter the connection number to be deleted:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "Error: The corresponding connection was not found." + echo "Error: Corresponding connection not found." return fi @@ -5896,7 +5896,7 @@ use_connection() { local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "Error: The corresponding connection was not found." + echo "Error: Corresponding connection not found." return fi @@ -5909,7 +5909,7 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "Connection failed! Please check the following:" echo "1. Is the key file path correct?$password_or_key" - echo "2. Are the key file permissions correct (should be 600)." + echo "2. Whether the key file permissions are correct (should be 600)." echo "3. Whether the target server allows login using the key." fi else @@ -5924,7 +5924,7 @@ use_connection() { sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "Connection failed! Please check the following:" - echo "1. Whether the username and password are correct." + echo "1. Are the username and password correct?" echo "2. Whether the target server allows password login." echo "3. Whether the SSH service of the target server is running normally." fi @@ -5950,15 +5950,15 @@ ssh_manager() { while true; do clear - echo "SSH Remote Connection Tool" - echo "Can be connected to other Linux systems via SSH" + echo "SSH remote connection tool" + echo "Can connect to other Linux systems via SSH" echo "------------------------" list_connections - echo "1. Create a new connection 2. Use a connection 3. Delete a connection" + echo "1. Create a new connection 2. Use the connection 3. Delete the connection" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) add_connection ;; 2) use_connection ;; @@ -5982,14 +5982,14 @@ ssh_manager() { # List available hard disk partitions list_partitions() { - echo "Available hard disk partitions:" + echo "Available hard drive partitions:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } # Mount the partition mount_partition() { send_stats "Mount the partition" - read -e -p "Please enter the partition name to be mounted (for example, sda1):" PARTITION + read -e -p "Please enter the name of the partition to be mounted (e.g. sda1):" PARTITION # Check if the partition exists if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then @@ -5997,9 +5997,9 @@ mount_partition() { return fi - # Check if the partition is already mounted + # Check whether the partition is mounted if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "The partition is already mounted!" + echo "The partition has been mounted!" return fi @@ -6007,30 +6007,30 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # Mount partition + # Mount the partition mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "Partition mount successfully:$MOUNT_POINT" + echo "Partition mounted successfully:$MOUNT_POINT" else echo "Partition mount failed!" rmdir "$MOUNT_POINT" fi } -# Uninstall the partition +# Unmount partition unmount_partition() { - send_stats "Uninstall the partition" - read -e -p "Please enter the partition name (for example, sda1):" PARTITION + send_stats "Unmount partition" + read -e -p "Please enter the name of the partition to be unmounted (e.g. sda1):" PARTITION - # Check if the partition is already mounted + # Check whether the partition is mounted MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then echo "The partition is not mounted!" return fi - # Uninstall the partition + # Unmount partition umount "/dev/$PARTITION" if [ $? -eq 0 ]; then @@ -6060,17 +6060,17 @@ format_partition() { # Check if the partition is already mounted if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "The partition has been mounted, please uninstall it first!" + echo "The partition has been mounted, please unmount it first!" return fi - # Select a file system type + # Select file system type echo "Please select the file system type:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "Please enter your selection:" FS_CHOICE + read -e -p "Please enter your choice:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; @@ -6081,7 +6081,7 @@ format_partition() { esac # Confirm formatting - read -e -p "Confirm formatting partition /dev/$PARTITIONfor$FS_TYPEIs it? (y/n):" CONFIRM + read -e -p "Confirm formatted partition /dev/$PARTITIONfor$FS_TYPE? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "The operation has been cancelled." return @@ -6114,22 +6114,22 @@ check_partition() { fsck "/dev/$PARTITION" } -# Main Menu +# Main menu disk_manager() { send_stats "Hard disk management function" while true; do clear echo "Hard disk partition management" - echo -e "${gl_huang}This function is internally tested during the test period, please do not use it in the production environment.${gl_bai}" + echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. Mount the partition 2. Uninstall the partition 3. View mounted partition" + echo "1. Mount the partition 2. Unmount the partition 3. View the mounted partition" echo "4. Format the partition 5. Check the partition status" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6155,8 +6155,8 @@ list_tasks() { # Add a new task add_task() { - send_stats "Add a new synchronization task" - echo "Create a new synchronization task example:" + send_stats "Add new sync task" + echo "Example of creating a new sync task:" echo "- Task name: backup_www" echo "- Local Directory: /var/www" echo "- Remote address: user@192.168.1.100" @@ -6166,7 +6166,7 @@ add_task() { read -e -p "Please enter the task name:" name read -e -p "Please enter the local directory:" local_path read -e -p "Please enter the remote directory:" remote_path - read -e -p "Please enter the remote user @IP:" remote + read -e -p "Please enter remote user@IP:" remote read -e -p "Please enter the SSH port (default 22):" port port=${port:-22} @@ -6177,15 +6177,15 @@ add_task() { case $auth_choice in 1) - read -s -p "Please enter your password:" password_or_key + read -s -p "Please enter password:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "Please paste the key content (press press Enter twice after pasting):" + echo "Please paste the key content (press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # If the input is empty and the key content already contains the beginning, the input ends + # If the input is a blank line and the key content already contains the beginning, end the input if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6213,7 +6213,7 @@ add_task() { ;; esac - echo "Please select the synchronization mode:" + echo "Please select synchronization mode:" echo "1. Standard mode (-avz)" echo "2. Delete the target file (-avz --delete)" read -e -p "Please select (1/2):" mode @@ -6232,8 +6232,8 @@ add_task() { # Delete a task delete_task() { - send_stats "Delete synchronization tasks" - read -e -p "Please enter the task number to delete:" num + send_stats "Delete sync task" + read -e -p "Please enter the task number to be deleted:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then @@ -6249,7 +6249,7 @@ delete_task() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "Task deleted!" + echo "Task has been deleted!" } @@ -6289,7 +6289,7 @@ run_task() { source="$remote:$local_path" destination="$remote_path" else - echo "Push synchronization to the remote end:$local_path -> $remote:$remote_path" + echo "Pushing and synchronizing to the remote end:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi @@ -6322,9 +6322,9 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "Synchronization is complete!" + echo "Synchronization completed!" else - echo "Synchronization failed! Please check the following:" + echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" @@ -6333,9 +6333,9 @@ run_task() { } -# Create a timed task +# Create a scheduled task schedule_task() { - send_stats "Add synchronization scheduled tasks" + send_stats "Add synchronization timing tasks" read -e -p "Please enter the task number to be synchronized regularly:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6343,8 +6343,8 @@ schedule_task() { return fi - echo "Please select the timed execution interval:" - echo "1) Execute once an hour" + echo "Please select the scheduled execution interval:" + echo "1) Execute once every hour" echo "2) Perform once a day" echo "3) Execute once a week" read -e -p "Please enter options (1/2/3):" interval @@ -6355,7 +6355,7 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "Error: Please enter a valid option!" ; return ;; + *) echo "Error: Please enter valid options!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" @@ -6363,7 +6363,7 @@ schedule_task() { # Check if the same task already exists if crontab -l | grep -q "k rsync_run $num"; then - echo "Error: The timing synchronization of this task already exists!" + echo "Error: The scheduled synchronization for this task already exists!" return fi @@ -6374,7 +6374,7 @@ schedule_task() { # View scheduled tasks view_tasks() { - echo "Current timing tasks:" + echo "Current scheduled tasks:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" @@ -6383,7 +6383,7 @@ view_tasks() { # Delete scheduled tasks delete_task_schedule() { send_stats "Delete synchronization timing tasks" - read -e -p "Please enter the task number to delete:" num + read -e -p "Please enter the task number to be deleted:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then echo "Error: Please enter a valid task number!" return @@ -6394,7 +6394,7 @@ delete_task_schedule() { } -# Task Management Main Menu +# Task management main menu rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" @@ -6402,7 +6402,7 @@ rsync_manager() { while true; do clear echo "Rsync remote synchronization tool" - echo "Synchronization between remote directories supports incremental synchronization, efficient and stable." + echo "Synchronization between remote directories supports incremental synchronization, which is efficient and stable." echo "---------------------------------" list_tasks echo @@ -6410,11 +6410,11 @@ rsync_manager() { echo echo "1. Create a new task 2. Delete a task" echo "3. Perform local synchronization to the remote end 4. Perform remote synchronization to the local end" - echo "5. Create a timing task 6. Delete a timing task" + echo "5. Create a scheduled task 6. Delete a scheduled task" echo "---------------------------------" echo "0. Return to the previous menu" echo "---------------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6501,13 +6501,13 @@ linux_info() { echo -e "${gl_kjlan}Number of CPU cores:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU frequency:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU occupancy:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}CPU usage:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}System load:${gl_bai}$load" echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" echo -e "${gl_kjlan}Hard disk occupation:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Total received:${gl_bai}$rx" + echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" echo -e "${gl_kjlan}Total send:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" @@ -6541,19 +6541,19 @@ linux_tools() { echo -e "Basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo super management permission tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" + echo -e "${gl_kjlan}3. ${gl_bai}sudo super administrative privilege tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" echo -e "${gl_kjlan}5. ${gl_bai}htop system monitoring tool${gl_kjlan}6. ${gl_bai}iftop network traffic monitoring tool" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP compression decompression tool${gl_kjlan}8. ${gl_bai}tar GZ compression decompression tool" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP compression and decompression tool${gl_kjlan}8. ${gl_bai}tar GZ compression and decompression tool" echo -e "${gl_kjlan}9. ${gl_bai}tmux multi-channel background running tool${gl_kjlan}10. ${gl_bai}ffmpeg video encoding live streaming tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tools${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}range file management tool" + echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tool${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}range file management tool" echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk occupation viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" echo -e "${gl_kjlan}15. ${gl_bai}vim text editor${gl_kjlan}16. ${gl_bai}nano text editor${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git version control system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screen Guarantee${gl_kjlan}22. ${gl_bai}Train screen security" - echo -e "${gl_kjlan}26. ${gl_bai}Tetris game${gl_kjlan}27. ${gl_bai}Snake-eating game" - echo -e "${gl_kjlan}28. ${gl_bai}Space Invader Game" + echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Train screen security" + echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake-eating game" + echo -e "${gl_kjlan}28. ${gl_bai}space invaders mini game" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}All installations (excluding screen savers and games)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}Uninstall all" @@ -6562,7 +6562,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) @@ -6577,7 +6577,7 @@ linux_tools() { clear install wget clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" wget --help send_stats "Install wget" ;; @@ -6585,9 +6585,9 @@ linux_tools() { clear install sudo clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" sudo --help - send_stats "Install sudo" + send_stats "install sudo" ;; 4) clear @@ -6639,7 +6639,7 @@ linux_tools() { clear install ffmpeg clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" ffmpeg --help send_stats "Install ffmpeg" ;; @@ -6752,7 +6752,7 @@ linux_tools() { 32) clear - send_stats "Install all (excluding games and screen savers)" + send_stats "Install all (excluding games and screensavers)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; @@ -6804,18 +6804,18 @@ linux_bbr() { echo "Current TCP blocking algorithm:$congestion_algorithm $queue_algorithm" echo "" - echo "BBR management" + echo "BBR Management" echo "------------------------" - echo "1. Turn on BBRv3 2. Turn off BBRv3 (restarts)" + echo "1. Turn on BBRv3 2. Turn off BBRv3 (it will restart)" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) bbr_on - send_stats "Alpine enable bbr3" + send_stats "alpine opens bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6869,7 +6869,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Docker backup" - echo -e "${YELLOW}Backing up Docker container...${NC}" + echo -e "${YELLOW}Backing up Docker containers...${NC}" docker ps --format '{{.Names}}' read -e -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers @@ -6884,7 +6884,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}No container found${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}Container not found${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6894,7 +6894,7 @@ docker_ssh_migration() { echo "set -e" >> "$RESTORE_SCRIPT" echo "# Automatically generated restore script" >> "$RESTORE_SCRIPT" - # Record the path of the packaged Compose project to avoid duplicate packaging + # Record the packaged Compose project path to avoid repeated packaging declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -6903,7 +6903,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}Detected$cYes docker-compose container${NC}" + echo -e "${BLUE}detected$cYes docker-compose container${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -6911,9 +6911,9 @@ docker_ssh_migration() { read -e -p "The compose directory is not detected, please enter the path manually:" project_dir fi - # If the Compose project has been packaged, skip it + # If the Compose project has already been packaged, skip if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose project [$project_name] Already backed up, skip repeated packaging...${NC}" + echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" continue fi @@ -6921,19 +6921,19 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose restore:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 echo -e "${GREEN}Compose project [$project_name] Packed:${project_dir}${NC}" else - echo -e "${RED}docker-compose.yml not found, skip this container...${NC}" + echo -e "${RED}docker-compose.yml not found, skipping this container...${NC}" fi else - # Normal container backup volume + # Ordinary container backup volume local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "Packing rolls:$path" + echo "Packing volume:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6942,7 +6942,7 @@ docker_ssh_migration() { mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # Environment variables + # environment variables local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done @@ -6963,13 +6963,13 @@ docker_ssh_migration() { # Backup all files under /home/docker (excluding subdirectories) if [ -d "/home/docker" ]; then - echo -e "${BLUE}Backup the files under /home/docker...${NC}" + echo -e "${BLUE}Back up files under /home/docker...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}The file under /home/docker has been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}Backup is complete:${BACKUP_DIR}${NC}" + echo -e "${GREEN}Backup completed:${BACKUP_DIR}${NC}" echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" @@ -6981,10 +6981,10 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker restore" - read -e -p "Please enter the backup directory to restore:" BACKUP_DIR + read -e -p "Please enter the backup directory to be restored:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } - echo -e "${BLUE}Start the restore operation...${NC}" + echo -e "${BLUE}Starting the restore operation...${NC}" install tar jq gzip install_docker @@ -6996,16 +6996,16 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -e -p "The original path was not found, please enter the restore directory path:" original_path + [[ -z "$original_path" ]] && read -e -p "Original path not found, please enter the restore directory path:" original_path - # Check whether the container of the compose project is already running + # Check if the container for the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" continue fi - read -e -p "Confirm restoring the Compose project [$project_name] to path [$original_path] ? (y/n): " confirm + read -e -p "Confirm to restore Compose project [$project_name] to path [$original_path] ? (y/n): " confirm [[ "$confirm" != "y" ]] && read -e -p "Please enter a new restore path:" original_path mkdir -p "$original_path" @@ -7030,21 +7030,21 @@ docker_ssh_migration() { # Check if the container already exists and is running if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}Container [$container] is running, skip restore...${NC}" + echo -e "${YELLOW}container [$container] already running, skipping restore...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information was not found, skip:$container${NC}"; continue; } - # Port Mapping + # port mapping PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # Environment variables + # environment variables ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do @@ -7069,7 +7069,7 @@ docker_ssh_migration() { # Delete existing but not running containers if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}Container [$container] Exist but not running, delete the old container...${NC}" + echo -e "${YELLOW}container [$container] exists but is not running, delete the old container...${NC}" docker rm -f "$container" fi @@ -7078,16 +7078,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for normal containers was found${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for common containers found${NC}" # Restore the file under /home/docker if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}Restore the file under /home/docker...${NC}" + echo -e "${BLUE}Restoring files under /home/docker...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}The file under /home/docker has been restored${NC}" + echo -e "${GREEN}Files under /home/docker have been restored${NC}" else - echo -e "${YELLOW}No backup of the file under /home/docker was found, skip...${NC}" + echo -e "${YELLOW}The backup of the file under /home/docker was not found, skipping...${NC}" fi @@ -7110,7 +7110,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}Transfer backup...${NC}" + echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -7123,14 +7123,14 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker backup file deletion" - read -e -p "Please enter the backup directory to delete:" BACKUP_DIR + read -e -p "Please enter the backup directory to be deleted:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" } # ---------------------------- - # Main Menu + # Main menu # ---------------------------- main_menu() { send_stats "Docker backup migration and restore" @@ -7142,9 +7142,9 @@ docker_ssh_migration() { list_backups echo -e "" echo "------------------------" - echo -e "1. Backup the docker project" - echo -e "2. Migrate docker projects" - echo -e "3. Restore the docker project" + echo -e "1. Back up docker project" + echo -e "2. Migrate docker project" + echo -e "3. Restore docker project" echo -e "4. Delete the backup file of the docker project" echo "------------------------" echo -e "0. Return to the previous menu" @@ -7177,16 +7177,16 @@ linux_docker() { echo -e "Docker Management" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Install and update Docker environment${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Install and update the Docker environment${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}2. ${gl_bai}View Docker global status${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Docker container management${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}Docker image management" - echo -e "${gl_kjlan}5. ${gl_bai}Docker Network Management" + echo -e "${gl_kjlan}5. ${gl_bai}Docker network management" echo -e "${gl_kjlan}6. ${gl_bai}Docker volume management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}Clean useless docker containers and mirror network data volumes" + echo -e "${gl_kjlan}7. ${gl_bai}Clean up useless docker containers and mirror network data volumes" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Replace Docker source" echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" @@ -7194,7 +7194,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Backup/Migration/Restore Docker Environment" + echo -e "${gl_kjlan}19. ${gl_bai}Backup/migrate/restore Docker environment" echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -7215,7 +7215,7 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Docker global status" + send_stats "docker global status" echo "Docker version" docker -v docker compose version @@ -7227,10 +7227,10 @@ linux_docker() { echo -e "Docker container:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker volume:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker volumes:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker Network:${gl_lv}$network_count${gl_bai}" + echo -e "Docker network:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7245,7 +7245,7 @@ linux_docker() { 5) while true; do clear - send_stats "Docker Network Management" + send_stats "Docker network management" echo "Docker network list" echo "------------------------------------------------------------" docker network ls @@ -7270,26 +7270,26 @@ linux_docker() { done echo "" - echo "Network operation" + echo "network operations" echo "------------------------" echo "1. Create a network" - echo "2. Join the Internet" + echo "2. Join the network" echo "3. Exit the network" echo "4. Delete the network" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) - send_stats "Create a network" + send_stats "Create network" read -e -p "Set a new network name:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "Join the Internet" - read -e -p "Join the network name:" dockernetwork + send_stats "Join the network" + read -e -p "Add network name:" dockernetwork read -e -p "Those containers are added to the network (multiple container names are separated by spaces):" dockernames for dockername in $dockernames; do @@ -7297,9 +7297,9 @@ linux_docker() { done ;; 3) - send_stats "Join the Internet" + send_stats "Join the network" read -e -p "Exit network name:" dockernetwork - read -e -p "Those containers exit the network (multiple container names are separated by spaces):" dockernames + read -e -p "Those containers exit the network (please separate multiple container names with spaces):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7308,7 +7308,7 @@ linux_docker() { ;; 4) - send_stats "Delete the network" + send_stats "delete network" read -e -p "Please enter the network name to delete:" dockernetwork docker network rm $dockernetwork ;; @@ -7327,7 +7327,7 @@ linux_docker() { echo "Docker volume list" docker volume ls echo "" - echo "Volume operation" + echo "Volume operations" echo "------------------------" echo "1. Create a new volume" echo "2. Delete the specified volume" @@ -7335,12 +7335,12 @@ linux_docker() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "Create a new volume" - read -e -p "Set the new volume name:" dockerjuan + read -e -p "Set new volume name:" dockerjuan docker volume create $dockerjuan ;; @@ -7407,13 +7407,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 open" + send_stats "Docker v6 on" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 level" + send_stats "Docker v6 Close" docker_ipv6_off ;; @@ -7466,26 +7466,26 @@ linux_test() { echo -e "Test script collection" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP and unlock status detection" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT Unlock Status Detection" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT unlock status detection" echo -e "${gl_kjlan}2. ${gl_bai}Region streaming media unlock test" echo -e "${gl_kjlan}3. ${gl_bai}yeahwu streaming media unlock detection" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality physical examination script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}Network speed measurement" echo -e "${gl_kjlan}11. ${gl_bai}besttrace three network backhaul delay routing test" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace Three-network backhaul line test" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace triple network backhaul line test" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed three-net speed measurement" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace Specifies IP backhaul test script" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three-network line test" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunction speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality Network Quality Physical Examination Script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}Hardware performance testing" - echo -e "${gl_kjlan}21. ${gl_bai}yabs performance testing" - echo -e "${gl_kjlan}22. ${gl_bai}iicu/gb5 CPU performance test script" + echo -e "${gl_kjlan}21. ${gl_bai}yabs performance test" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU performance test script" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}Comprehensive test" @@ -7522,7 +7522,7 @@ linux_test() { 11) clear - send_stats "Besttrace three network backhaul delay routing test" + send_stats "besttrace triple network backhaul delay routing test" install wget wget -qO- git.io/besttrace | bash ;; @@ -7554,10 +7554,10 @@ linux_test() { echo "Shanghai Unicom: 210.22.97.1" echo "Shanghai Mobile: 211.136.112.200" echo "Guangzhou Telecom: 58.60.188.222" - echo "Guangzhou Unicom: 210.21.196.6" + echo "Guangzhou China Unicom: 210.21.196.6" echo "Guangzhou Mobile: 120.196.165.24" echo "Chengdu Telecom: 61.139.2.69" - echo "Chengdu Unicom: 119.6.6.6" + echo "Chengdu China Unicom: 119.6.6.6" echo "Chengdu Mobile: 211.137.96.205" echo "Hunan Telecom: 36.111.200.100" echo "Hunan Unicom: 42.48.16.100" @@ -7571,7 +7571,7 @@ linux_test() { 16) clear - send_stats "ludashi2020 three-network line test" + send_stats "ludashi2020 three network line test" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; @@ -7606,7 +7606,7 @@ linux_test() { curl -Lso- bench.sh | bash ;; 32) - send_stats "Spiritysdx Fusion Monster Review" + send_stats "spiritysdx fusion monster review" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7636,10 +7636,10 @@ linux_Oracle() { echo -e "Oracle Cloud Script Collection" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Install idle machine active script" - echo -e "${gl_kjlan}2. ${gl_bai}Uninstall idle machine active script" + echo -e "${gl_kjlan}2. ${gl_bai}Uninstall active scripts from idle machines" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD reinstall system script" - echo -e "${gl_kjlan}4. ${gl_bai}Detective R start script" + echo -e "${gl_kjlan}4. ${gl_bai}Detective R startup script" echo -e "${gl_kjlan}5. ${gl_bai}Turn on ROOT password login mode" echo -e "${gl_kjlan}6. ${gl_bai}IPV6 recovery tool" echo -e "${gl_kjlan}------------------------" @@ -7651,23 +7651,23 @@ linux_Oracle() { 1) clear echo "Active script: CPU occupies 10-20% memory occupies 20%" - read -e -p "Are you sure to install it? (Y/N):" choice + read -e -p "Are you sure you want to install it? (Y/N):" choice case "$choice" in [Yy]) install_docker - # Set default values + # Set default value local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 # Prompt the user to enter the number of CPU cores and occupancy percentage, and if entered, use the default value. - read -e -p "Please enter the number of CPU cores [Default:$DEFAULT_CPU_CORE]: " cpu_core + read -e -p "Please enter the number of CPU cores [default:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "Please enter the CPU usage percentage range (for example, 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "Please enter the CPU usage percentage range (e.g. 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} read -e -p "Please enter the memory usage percentage [default:$DEFAULT_MEM_UTIL]: " mem_util @@ -7706,7 +7706,7 @@ linux_Oracle() { clear echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation is risky to lose contact, and those who are worried should use it with caution. Reinstallation is expected to take 15 minutes, please back up the data in advance." + echo -e "${gl_hong}Notice:${gl_bai}Reinstallation may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in @@ -7729,7 +7729,7 @@ linux_Oracle() { esac done - read -e -p "Please enter your reinstalled password:" vpspasswd + read -e -p "Please enter your password after reinstallation:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 send_stats "Oracle Cloud Reinstall System Script" @@ -7756,7 +7756,7 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "This function is provided by the master jhb, thanks to him!" + echo "This function is provided by jhb, thank him!" send_stats "ipv6 fix" ;; 0) @@ -7840,20 +7840,20 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}Install LDNMP environment${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install the Kadao Cloud Desktop" - echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Film and Television Station${gl_huang}6. ${gl_bai}Install a Unicorn Digital Card Network" - echo -e "${gl_huang}7. ${gl_bai}Install the flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" - echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Customize dynamic site" + echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Movie and TV Station${gl_huang}6. ${gl_bai}Install Unicorn Digital Card Network" + echo -e "${gl_huang}7. ${gl_bai}Install flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" + echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Custom dynamic site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}Install nginx only${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}site redirect" - echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy - domain name" - echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden password management platform${gl_huang}26. ${gl_bai}Install Halo Blog Website" + echo -e "${gl_huang}21. ${gl_bai}Only install nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" + echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy-domain name" + echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden Password Management Platform${gl_huang}26. ${gl_bai}Install Halo Blog Site" echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" - echo -e "${gl_huang}30. ${gl_bai}Customize static site" + echo -e "${gl_huang}30. ${gl_bai}Custom static site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" - echo -e "${gl_huang}33. ${gl_bai}Timed remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" + echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up the entire site data" + echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environment${gl_huang}36. ${gl_bai}Optimize LDNMP environment" + echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environments${gl_huang}36. ${gl_bai}Optimize LDNMP environment" echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall LDNMP environment" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}Return to main menu" @@ -7944,7 +7944,7 @@ linux_ldnmp() { 5) clear - # Apple CMS + # AppleCMS webname="苹果CMS" send_stats "Install$webname" echo "Start deployment$webname" @@ -7980,7 +7980,7 @@ linux_ldnmp() { echo "password:$dbusepasswd" echo "Database prefix: mac_" echo "------------------------" - echo "Log in to the background address after installation is successful" + echo "After successful installation, log in to the backend address" echo "https://$yuming/vip.php" ;; @@ -8018,17 +8018,17 @@ linux_ldnmp() { echo "password:$dbusepasswd" echo "" echo "redis address: redis" - echo "Redis password: Not filled in by default" - echo "Redis port: 6379" + echo "redis password: not filled in by default" + echo "redis port: 6379" echo "" echo "Website url: https://$yuming" - echo "Background login path: /admin" + echo "Backend login path: /admin" echo "------------------------" echo "Username: admin" echo "Password: admin" echo "------------------------" echo "If a red error0 appears in the upper right corner when logging in, please use the following command:" - echo "I am also very angry that the unicorn number card is so troublesome, and there will be such problems!" + echo "I am also very angry about why the Unicorn Number Card is so troublesome and has such problems!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8080,7 +8080,7 @@ linux_ldnmp() { echo "username:$dbuse" echo "password:$dbusepasswd" echo "Table prefix: flarum_" - echo "Administrator information is set by yourself" + echo "Administrator information can be set by oneself" ;; @@ -8183,7 +8183,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/6${gl_bai}] Upload PHP source code" echo "-------------" echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" - read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download + read -e -p "You can also enter the download link to download the source code package remotely. Press Enter directly to skip the remote download:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8204,9 +8204,9 @@ linux_ldnmp() { sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] Please select the PHP version" + echo -e "[${gl_huang}3/6${gl_bai}] Please select PHP version" echo "-------------" - read -e -p "1. The latest version of php | 2. php7.4:" pho_v + read -e -p "1. php latest version | 2. php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8244,7 +8244,7 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}6/6${gl_bai}] Database Management" + echo -e "[${gl_huang}6/6${gl_bai}] Database management" echo "-------------" read -e -p "1. I build a new site 2. I build an old site and have a database backup:" use_db case $use_db in @@ -8263,7 +8263,7 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "Database import table data" + echo "Database imported table data" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql echo "Database import completed" @@ -8299,7 +8299,7 @@ linux_ldnmp() { send_stats "Install$webname" echo "Start deployment$webname" add_yuming - read -e -p "Please enter the jump domain name:" reverseproxy + read -e -p "Please enter the redirect domain name:" reverseproxy nginx_install_status install_ssltls certs_status @@ -8321,7 +8321,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ ports have been blocked from accessing the service" + echo "IP+port has been blocked from accessing the service" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8451,8 +8451,8 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}] Upload static source code" echo "-------------" - echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" - read -e -p "You can also enter the download link to remotely download the source code package. Directly press Enter to skip remote download:" url_download + echo "Currently, only source code packages in zip format are allowed to be uploaded. Please put the source code packages in /home/web/html/${yuming}In the directory" + read -e -p "You can also enter the download link to download the source code package remotely. Press Enter directly to skip the remote download:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8534,7 +8534,7 @@ linux_ldnmp() { 33) clear - send_stats "Timed remote backup" + send_stats "Scheduled remote backup" read -e -p "Enter the remote server IP:" useip read -e -p "Enter the remote server password:" usepasswd @@ -8547,7 +8547,7 @@ linux_ldnmp() { echo "------------------------" echo "1. Weekly backup 2. Daily backup" - read -e -p "Please enter your selection:" dingshi + read -e -p "Please enter your choice:" dingshi case $dingshi in 1) @@ -8576,7 +8576,7 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename + read -e -p "Press the Enter key to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename if [ "$filename" == "0" ]; then break_end @@ -8602,7 +8602,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "No compression package was found." + echo "No compressed package found." fi ;; @@ -8659,7 +8659,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "Please enter${ldnmp_pods}Version number (such as: 8.0 8.3 8.4 9.0) (Enter to get the latest version):" version + read -e -p "Please enter${ldnmp_pods}Version number (such as: 8.0 8.3 8.4 9.0) (press enter to get the latest version):" version local version=${version:-latest} cd /home/web/ @@ -8676,7 +8676,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "Please enter${ldnmp_pods}Version number (such as: 7.4 8.0 8.1 8.2 8.3) (Enter to get the latest version):" version + read -e -p "Please enter${ldnmp_pods}Version number (such as: 7.4 8.0 8.1 8.2 8.3) (press enter to get the latest version):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8729,7 +8729,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "Completely update the LDNMP environment" + send_stats "Complete update of LDNMP environment" cd /home/web/ docker compose down --rmi all @@ -8799,12 +8799,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "Application Market" + echo -e "application market" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # Set the color with loop + # Set color with loop for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8813,23 +8813,23 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager Visual Panel" + echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" + echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" + echo -e "${gl_kjlan}11. ${color11}ZenTao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome Adware${gl_kjlan}18. ${color18}onlyoffice online office OFFICE" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome removes adware${gl_kjlan}18. ${color18}onlyofficeOnline office OFFICE" echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" - echo -e "${gl_kjlan}23. ${color23}Memos web page memo${gl_kjlan}24. ${color24}Webtop remote desktop web version${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}23. ${color23}Memos web memo${gl_kjlan}24. ${color24}Webtop remote desktop web version${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" - echo -e "${gl_kjlan}29. ${color29}searxng aggregation search site${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" + echo -e "${gl_kjlan}29. ${color29}searxng aggregated search station${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" @@ -8838,42 +8838,42 @@ while true; do echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}Mouse Management Panel${gl_kjlan}42. ${color42}Nexte remote connection tool" - echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk Remote Desk (Relay)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}Prometheus Monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tools" + echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk remote desktop (relay)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub acceleration station${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}Prometheus monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE Chicken Panel${gl_kjlan}52. ${color52}DPanel Container Management Panel" - echo -e "${gl_kjlan}53. ${color53}llama3 chat AI model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" + echo -e "${gl_kjlan}51. ${color51}PVE open chick panel${gl_kjlan}52. ${color52}DPanel container management panel" + echo -e "${gl_kjlan}53. ${color53}llama3 chat AI large model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI big model${gl_kjlan}58. ${color58}Dify large model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI big model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI large model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow big model knowledge base" + echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow large model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" echo -e "${gl_kjlan}65. ${color65}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" echo -e "${gl_kjlan}67. ${color67}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL Certificate Management Platform" echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot Chat Robot Framework" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden Password Manager${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV Private Movie" - echo -e "${gl_kjlan}75. ${color75}Melody Music Elf${gl_kjlan}76. ${color76}Online DOS old games" - echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki Intelligent Document Management System" + echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden password manager${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV private movies" + echo -e "${gl_kjlan}75. ${color75}Melody music wizard${gl_kjlan}76. ${color76}Online DOS old games" + echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki intelligent document management system" echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" - echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tools" + echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tool" echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" - echo -e "${gl_kjlan}87. ${color87}SyncTV movie watching artifact${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" + echo -e "${gl_kjlan}87. ${color87}SyncTV is a great tool for watching movies together${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser File Manager" + echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser file manager" echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" - echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step validator" - echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server side)${gl_kjlan}98. ${color98}WireGuard networking (client)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing point-to-point file synchronization tool" + echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step authenticator" + echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server)${gl_kjlan}98. ${color98}WireGuard networking (client)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing peer-to-peer file synchronization tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" + echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multiplayer online chat system" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" echo -e "${gl_kjlan}------------------------" @@ -9033,7 +9033,7 @@ while true; do docker_rum() { read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password + read -e -p "Set login user password:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9076,7 +9076,7 @@ while true; do check_docker_image_update $docker_name clear echo -e "Nezha Monitoring$check_docker $update_status" - echo "Open source, lightweight and easy-to-use server monitoring and operation and maintenance tools" + echo "Open source, lightweight, easy-to-use server monitoring and operation and maintenance tool" echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -9088,7 +9088,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -9156,7 +9156,7 @@ while true; do clear echo -e "Post Office Services$check_docker $update_status" - echo "poste.io is an open source mail server solution." + echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" @@ -9166,13 +9166,13 @@ while true; do if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then echo -e "${gl_lv}port$portCurrently available${gl_bai}" else - echo -e "${gl_hong}port$portNot currently available${gl_bai}" + echo -e "${gl_hong}port$portCurrently unavailable${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "Access address:" + echo "Visit address:" echo "https://$yuming" fi @@ -9181,7 +9181,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -9313,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -9397,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -9556,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "Build a Thunder Pool" + send_stats "Build a thunder pool" local app_id="19" local docker_name=safeline-mgt @@ -9564,8 +9564,8 @@ while true; do while true; do check_docker_app clear - echo -e "Thunder Pool Service$check_docker" - echo "Lei Chi is a WAF site firewall program panel developed by Changting Technology, which can reverse the agency site for automated defense." + echo -e "Thunder pool service$check_docker" + echo "Leichi is a WAF site firewall program panel developed by Changting Technology, which can reverse the site for automated defense." echo "Video introduction: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -9600,7 +9600,7 @@ while true; do add_app_id clear - echo "Thunder Pool WAF panel has been updated" + echo "The Leichi WAF panel has been updated" check_docker_app_ip ;; 3) @@ -10072,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya family bucket" + send_stats "Xiaoya Family Bucket" clear install_docker check_disk_space 1 @@ -10276,7 +10276,7 @@ while true; do prometheus_install clear ip_address - echo "Installed" + echo "Installation completed" check_docker_app_ip echo "The initial username and password are: admin" } @@ -10546,7 +10546,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -10590,7 +10590,7 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "Installed" + echo "Installation completed" check_docker_app_ip echo "Initial username: admin" echo "Initial password: ChangeMe" @@ -10600,7 +10600,7 @@ while true; do docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "The app has been updated" + echo "App has been updated" } @@ -10610,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10935,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "Set the LibreTV login password:" app_passwd + read -e -p "Set LibreTV login password:" app_passwd docker run -d \ --name libretv \ @@ -10971,7 +10971,7 @@ while true; do docker_app_install() { read -e -p "Set login username:" admin read -e -p "Set the login user password:" admin_password - read -e -p "Enter the authorization code:" shouquanma + read -e -p "Enter authorization code:" shouquanma mkdir -p /home/docker/moontv @@ -11001,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "The app has been uninstalled" } docker_app_plus @@ -11191,11 +11191,11 @@ while true; do sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # Start the container + # Start container docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11394,7 +11394,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11407,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11620,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11634,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "The app has been uninstalled" } docker_app_plus @@ -11758,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11772,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11812,7 +11812,7 @@ while true; do block_container_port "$docker_name" "$ipv4_address" clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11844,7 +11844,7 @@ while true; do docker_rum() { - read -e -p "Please enter the number of clients to form the network (default 5):" COUNT + read -e -p "Please enter the number of clients in the network (default 5):" COUNT COUNT=${COUNT:-5} read -e -p "Please enter the WireGuard segment (default 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} @@ -11916,15 +11916,15 @@ while true; do sleep 2 echo - echo -e "${gl_huang}All client QR code configuration:${gl_bai}" + echo -e "${gl_huang}All client QR code configurations:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}All client configuration codes:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}All outputs are provided by each client. The usage method is as follows:${gl_bai}" - echo -e "${gl_lv}1. Download wg's APP on your mobile phone, scan the QR code above to quickly connect to the network${gl_bai}" + echo -e "${gl_lv}${COUNT}Configure all outputs for each client. The usage method is as follows:${gl_bai}" + echo -e "${gl_lv}1. Download the wg APP on your mobile phone and scan the QR code above to quickly connect to the Internet.${gl_bai}" echo -e "${gl_lv}2. Download the Windows client and copy the configuration code to connect to the network.${gl_bai}" echo -e "${gl_lv}3. Linux uses scripts to deploy WG clients and copy configuration code to connect to the network.${gl_bai}" echo -e "${gl_lv}Official client download method: https://www.wireguard.com/install/${gl_bai}" @@ -11955,12 +11955,12 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # Create directory if it does not exist + # Create a directory (if it does not exist) mkdir -p "$(dirname "$CONFIG_FILE")" echo "Please paste your client configuration and press Enter twice in a row to save:" - # Initialize variables + # initialize variables input="" empty_line_count=0 @@ -11980,7 +11980,7 @@ while true; do # Write to the configuration file echo "$input" > "$CONFIG_FILE" - echo "Client configuration has been saved to$CONFIG_FILE" + echo "Client configuration saved to$CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -12028,7 +12028,7 @@ while true; do read -e -p "Set the number of CPU cores (default 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "Set the memory size (default 4G):" RAM_SIZE + read -e -p "Set memory size (default 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -12045,7 +12045,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -12114,7 +12114,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -12129,7 +12129,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "The app has been uninstalled" } docker_app_plus @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" @@ -12193,7 +12193,7 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "The file has been transferred to the remote server/root directory." + echo "File transferred to remote server/root directory." else echo "The file to be transferred was not found." fi @@ -12215,7 +12215,7 @@ while true; do echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "Enter to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename + read -e -p "Press the Enter key to restore the latest backup, enter the backup file name to restore the specified backup, enter 0 to exit:" filename if [ "$filename" == "0" ]; then break_end @@ -12232,7 +12232,7 @@ while true; do cd / && tar -xzf "$filename" echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." else - echo "No compressed package found." + echo "No compression package was found." fi ;; @@ -12257,7 +12257,7 @@ linux_work() { clear send_stats "Backend workspace" echo -e "Backend workspace" - echo -e "The system will provide you with a workspace that can be run on the backend, which you can use to perform long-term tasks." + echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." echo -e "Even if you disconnect SSH, tasks in the workspace will not be interrupted, and tasks in the background will be resident." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" @@ -12266,24 +12266,24 @@ linux_work() { tmux list-sessions echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Workspace No. 1" - echo -e "${gl_kjlan}2. ${gl_bai}Workspace No. 2" + echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Workspace No. 3" echo -e "${gl_kjlan}4. ${gl_bai}Workspace No. 4" echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" - echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" + echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Workspace No. 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}Create/enter the workspace" + echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" echo -e "${gl_kjlan}24. ${gl_bai}Delete the specified workspace" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in @@ -12291,7 +12291,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; @@ -12306,7 +12306,7 @@ linux_work() { clear install tmux local SESSION_NAME="work3" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 4) @@ -12320,14 +12320,14 @@ linux_work() { clear install tmux local SESSION_NAME="work5" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 7) @@ -12341,21 +12341,21 @@ linux_work() { clear install tmux local SESSION_NAME="work8" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; @@ -12369,19 +12369,19 @@ linux_work() { fi send_stats "SSH resident mode" echo -e "SSH resident mode${tmux_sshd_status}" - echo "After opening the SSH connection, it will directly enter the resident mode and return directly to the previous working state." + echo "After SSH connection is enabled, it will directly enter the resident mode and return to the previous working state." echo "------------------------" echo "1. Turn on 2. Turn off" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" gongzuoqu_del + read -e -p "Please enter your choice:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" send_stats "Start the workspace$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# Automatically enter the tmux session\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# Automatically enter tmux session\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12412,7 +12412,7 @@ linux_work() { 24) read -e -p "Please enter the name of the workspace you want to delete:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "Delete the workspace" + send_stats "Delete workspace" ;; 0) @@ -12445,25 +12445,25 @@ linux_Settings() { while true; do clear # send_stats "System Tools" - echo -e "System Tools" + echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Change login password" echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" - echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" - echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}One-click reinstallation system${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account to create a new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" + echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify the SSH connection port" + echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" - echo -e "${gl_kjlan}13. ${gl_bai}User Management${gl_kjlan}14. ${gl_bai}User/Password Generator" + echo -e "${gl_kjlan}13. ${gl_bai}User Management${gl_kjlan}14. ${gl_bai}User/password generator" echo -e "${gl_kjlan}15. ${gl_bai}System time zone adjustment${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" - echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Timing task management" + echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Scheduled task management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}Native host parsing${gl_kjlan}22. ${gl_bai}SSH Defense Program" + echo -e "${gl_kjlan}21. ${gl_bai}Native host resolution${gl_kjlan}22. ${gl_bai}SSH defense program" echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Optimization of kernel parameters in Linux system${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tool${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}File Manager" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Linux system kernel parameter optimization${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tools${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}file manager" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Switch system language${gl_kjlan}32. ${gl_bai}Command line beautification tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}Set up system recycle bin${gl_kjlan}34. ${gl_bai}System backup and recovery" @@ -12471,8 +12471,8 @@ linux_Settings() { echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system tuning${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and Security" + echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and security" echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -12483,7 +12483,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "Please enter your shortcut key (enter 0 to exit):" kuaijiejian + read -e -p "Please enter your shortcut keys (enter 0 to exit):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -12491,7 +12491,7 @@ linux_Settings() { find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian echo "Shortcut keys are set" - send_stats "Script shortcut keys have been set" + send_stats "Script shortcut key has been set" break_end linux_Settings done @@ -12512,7 +12512,7 @@ linux_Settings() { 4) root_use send_stats "py version management" - echo "Python version management" + echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" echo "This feature seamlessly installs any version officially supported by python!" @@ -12526,7 +12526,7 @@ linux_Settings() { if [[ "$py_new_v" == "0" ]]; then - send_stats "Script PY Management" + send_stats "Script PY management" break_end linux_Settings fi @@ -12589,7 +12589,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" - send_stats "Switch script PY version" + send_stats "Script PY version switching" ;; @@ -12612,13 +12612,13 @@ EOF # Read the current SSH port number local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # Print the current SSH port number + # Print current SSH port number echo -e "The current SSH port number is:${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "Numbers with port numbers ranging from 1 to 65535. (Enter 0 to exit)" + echo "The port number ranges from 1 to 65535. (Enter 0 to exit)" - # Prompt the user to enter a new SSH port number + # Prompt user for new SSH port number read -e -p "Please enter the new SSH port number:" new_port # Determine whether the port number is within the valid range @@ -12636,7 +12636,7 @@ EOF fi else echo "The input is invalid, please enter the number." - send_stats "Invalid SSH port input" + send_stats "Invalid SSH port entered" break_end fi done @@ -12656,7 +12656,7 @@ EOF 9) root_use send_stats "New users disable root" - read -e -p "Please enter the new username (enter 0 to exit):" new_username + read -e -p "Please enter a new username (enter 0 to exit):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12671,7 +12671,7 @@ EOF passwd -l root - echo "The operation has been completed." + echo "The operation is complete." ;; @@ -12714,7 +12714,7 @@ EOF 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "This function is provided by the master jhb, thanks to him!" + echo "This function is provided by jhb, thank him!" send_stats "ipv6 fix" ;; @@ -12761,7 +12761,7 @@ EOF ;; 3) - send_stats "4G virtual memory has been set" + send_stats "4G virtual memory has been set up" add_swap 4096 ;; @@ -12769,7 +12769,7 @@ EOF 4) read -e -p "Please enter the virtual memory size (unit M):" new_swap add_swap "$new_swap" - send_stats "Custom virtual memory has been set" + send_stats "Custom virtual memory set" ;; *) @@ -12782,8 +12782,8 @@ EOF 13) while true; do root_use - send_stats "User Management" - echo "User List" + send_stats "User management" + echo "User list" echo "----------------------------------------------------------------------------" printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do @@ -12794,13 +12794,13 @@ EOF echo "" - echo "Account operations" + echo "Account operation" echo "------------------------" - echo "1. Create a normal account 2. Create a premium account" + echo "1. Create a regular account 2. Create a premium account" echo "------------------------" - echo "3. Give the highest permissions 4. Cancel the highest permissions" + echo "3. Grant the highest authority 4. Remove the highest authority" echo "------------------------" - echo "5. Delete the account" + echo "5. Delete account" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -12808,7 +12808,7 @@ EOF case $sub_choice in 1) - # Prompt the user to enter a new username + # Prompt user for new username read -e -p "Please enter a new username:" new_username # Create a new user and set a password @@ -12822,7 +12822,7 @@ EOF # Prompt the user to enter a new username read -e -p "Please enter a new username:" new_username - # Create a new user and set a password + # Create new user and set password useradd -m -s /bin/bash "$new_username" passwd "$new_username" @@ -12842,14 +12842,14 @@ EOF install sudo ;; 4) - read -e -p "Please enter your username:" username + read -e -p "Please enter username:" username # Remove user's sudo permissions from sudoers file sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) read -e -p "Please enter the username to delete:" username - # Delete the user and its home directory + # Delete users and their home directories userdel -r "$username" ;; @@ -12897,7 +12897,7 @@ EOF echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "Random password$i: $password" + echo "random password$i: $password" done echo "" @@ -12929,26 +12929,26 @@ EOF echo "Current system time:$current_time" echo "" - echo "Time zone switching" + echo "time zone switch" echo "------------------------" echo "Asia" - echo "1. Shanghai time in China 2. Hong Kong time in China" - echo "3. Tokyo time in Japan 4. Seoul time in South Korea" - echo "5. Singapore time 6. Kolkata time in India" + echo "1. Shanghai, China time 2. Hong Kong time, China" + echo "3. Tokyo, Japan time 4. Seoul, South Korea time" + echo "5. Singapore time 6. Kolkata, India time" echo "7. Dubai time in the UAE 8. Sydney time in Australia" echo "9. Time in Bangkok, Thailand" echo "------------------------" echo "Europe" echo "11. London time in the UK 12. Paris time in France" - echo "13. Berlin time, Germany 14. Moscow time, Russia" + echo "13. Berlin, Germany time 14. Moscow, Russia time" echo "15. Utrecht time in the Netherlands 16. Madrid time in Spain" echo "------------------------" echo "America" - echo "21. Western Time 22. Eastern Time" + echo "21. US Western Time 22. US Eastern Time" echo "23. Canadian time 24. Mexican time" echo "25. Brazil Time 26. Argentina Time" echo "------------------------" - echo "31. UTC Global Standard Time" + echo "31. UTC global standard time" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -13009,7 +13009,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Other systems, such as Debian, Ubuntu, CentOS, etc. + # Other systems such as Debian, Ubuntu, CentOS, etc. hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13027,8 +13027,8 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "The host name has been changed to:$new_hostname" - send_stats "Host name has been changed" + echo "The hostname has been changed to:$new_hostname" + send_stats "Hostname changed" sleep 1 else echo "Exited, hostname not changed." @@ -13044,7 +13044,7 @@ EOF echo "Select the update source area" echo "Connect to LinuxMirrors to switch system update source" echo "------------------------" - echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas Regions" + echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -13052,7 +13052,7 @@ EOF case $choice in 1) - send_stats "Default source in mainland China" + send_stats "Mainland China default source" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -13072,34 +13072,34 @@ EOF ;; 20) - send_stats "Timing task management" + send_stats "Scheduled task management" while true; do clear check_crontab_installed clear - echo "Timed task list" + echo "Scheduled task list" crontab -l echo "" echo "operate" echo "------------------------" - echo "1. Add timing tasks 2. Delete timing tasks 3. Edit timing tasks" + echo "1. Add a scheduled task 2. Delete a scheduled task 3. Edit a scheduled task" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) - read -e -p "Please enter the execution command for the new task:" newquest + read -e -p "Please enter the execution command of the new task:" newquest echo "------------------------" - echo "1. Monthly Tasks 2. Weekly Tasks" + echo "1. Monthly tasks 2. Weekly tasks" echo "3. Daily tasks 4. Hourly tasks" echo "------------------------" read -e -p "Please enter your selection:" dingshi case $dingshi in 1) - read -e -p "Choose what day of each month to perform tasks? (1-30):" day + read -e -p "On what day of the month do you choose to execute the task? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -13107,11 +13107,11 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "Choose what time to perform tasks every day? (Hours, 0-23):" hour + read -e -p "What time do you choose to perform the task every day? (hours, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "Enter what minute of the hour to perform the task? (mins, 0-60):" minute + read -e -p "Enter what time of the hour the task should be executed? (minutes, 0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) @@ -13139,7 +13139,7 @@ EOF 21) root_use - send_stats "Local host parsing" + send_stats "Local host resolution" while true; do clear echo "Native host parsing list" @@ -13148,11 +13148,11 @@ EOF echo "" echo "operate" echo "------------------------" - echo "1. Add a new parsing 2. Delete the parsing address" + echo "1. Add new resolution 2. Delete resolution address" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" host_dns + read -e -p "Please enter your choice:" host_dns case $host_dns in 1) @@ -13164,7 +13164,7 @@ EOF 2) read -e -p "Please enter the keywords of the parsed content that need to be deleted:" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "Local host parsing and deletion" + send_stats "Local host resolution and deletion" ;; *) break # 跳出循环,退出菜单 @@ -13179,7 +13179,7 @@ EOF while true; do check_f2b_status - echo -e "SSH Defense Program$check_f2b_status" + echo -e "SSH defense program$check_f2b_status" echo "fail2ban is an SSH tool to prevent brute force" echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" @@ -13192,7 +13192,7 @@ EOF echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -13230,20 +13230,20 @@ EOF send_stats "Current limit shutdown function" while true; do clear - echo "Current limit shutdown function" + echo "Current limiting shutdown function" echo "Video introduction: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "Current traffic usage, restarting the server traffic calculation will be cleared!" + echo "The current traffic usage will be cleared when the server is restarted!" output_status - echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" + echo -e "${gl_kjlan}Total received:${gl_bai}$rx" echo -e "${gl_kjlan}Total send:${gl_bai}$tx" - # Check if the Limiting_Shut_down.sh file exists + # Check if Limiting_Shut_down.sh file exists if [ -f ~/Limiting_Shut_down.sh ]; then # Get the value of threshold_gb local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}The current set entry-station current limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The current outbound current limit threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}Current limit shutdown function is not enabled${gl_bai}" @@ -13251,7 +13251,7 @@ EOF echo echo "------------------------------------------------" - echo "The system will detect whether the actual traffic reaches the threshold every minute, and the server will be automatically shut down after it arrives!" + echo "The system will detect whether the actual traffic reaches the threshold every minute, and will automatically shut down the server after reaching the threshold!" echo "------------------------" echo "1. Turn on the current limit shutdown function 2. Deactivate the current limit shutdown function" echo "------------------------" @@ -13262,12 +13262,12 @@ EOF case "$Limiting" in 1) # Enter the new virtual memory size - echo "If the actual server has 100G traffic, the threshold can be set to 95G and shut down the power in advance to avoid traffic errors or overflows." - read -e -p "Please enter the incoming traffic threshold (unit is G, default is 100G):" rx_threshold_gb + echo "If the actual server only has 100G traffic, you can set the threshold to 95G and shut down in advance to avoid traffic errors or overflows." + read -e -p "Please enter the inbound traffic threshold (unit is G, default is 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "Please enter the traffic reset date (default resets on the 1st of every month):" cz_day + read -e -p "Please enter the traffic reset date (default reset on the 1st of each month):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13317,7 +13317,7 @@ EOF case $host_dns in 1) - send_stats "Generate a new key" + send_stats "Generate new key" add_sshkey break_end @@ -13350,13 +13350,13 @@ EOF 25) root_use - send_stats "Telegram warning" + send_stats "Telegraph warning" echo "TG-bot monitoring and early warning function" echo "Video introduction: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "You need to configure the tg robot API and the user ID to receive alerts to achieve real-time monitoring and alerts of local CPU, memory, hard disk, traffic, and SSH login." echo "After reaching the threshold, the user will be sent to the user" - echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate-${gl_bai}" + echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate -${gl_bai}" read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in @@ -13394,7 +13394,7 @@ EOF source ~/.profile clear - echo "TG-bot early warning system has been started" + echo "TG-bot early warning system has been activated" echo -e "${gl_hui}You can also place the TG-check-notify.sh warning file in the root directory on other machines and use it directly!${gl_bai}" ;; [Nn]) @@ -13475,7 +13475,7 @@ EOF 41) clear - send_stats "Message board" + send_stats "message board" echo "Visit the official message board of Technology lion. If you have any ideas about scripts, please leave a message and communicate!" echo "https://board.kejilion.pro" echo "Public password: kejilion.sh" @@ -13485,9 +13485,9 @@ EOF root_use send_stats "One-stop tuning" - echo "One-stop system optimization" + echo "One-stop system tuning" echo "------------------------------------------------" - echo "The following will be operated and optimized" + echo "The following content will be operated and optimized" echo "1. Update the system to the latest" echo "2. Clean up system junk files" echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" @@ -13495,8 +13495,8 @@ EOF echo -e "5. Open all ports" echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" - echo -e "8. Automatically optimize DNS address${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "9. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "8. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" + echo -e "9. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice @@ -13530,7 +13530,7 @@ EOF echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set the time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set time zone to${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13590,13 +13590,13 @@ EOF fi echo "Privacy and security" - echo "The script will collect data on user functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the function used," + echo "The script will collect data on users’ use of functions, optimize the script experience, and create more fun and useful functions." + echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" - echo "1. Turn on collection" - echo "2. Close the collection" + echo "1. Start collection" + echo "2. Close collection" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" @@ -13606,15 +13606,15 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "Collection has been enabled" - send_stats "Privacy and security collection has been enabled" + echo "Collection has been started" + send_stats "Privacy and security collection has been turned on" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "Collection closed" - send_stats "Privacy and Security have been closed for collection" + send_stats "Privacy and security collection has been turned off" ;; *) break @@ -13633,7 +13633,7 @@ EOF send_stats "Uninstall tech lion script" echo "Uninstall tech lion script" echo "------------------------------------------------" - echo "Will completely uninstall the kejilion script and will not affect your other functions" + echo "The kejilion script will be completely uninstalled without affecting your other functions." read -e -p "Are you sure to continue? (Y/N):" choice case "$choice" in @@ -13682,9 +13682,9 @@ linux_file() { send_stats "File Manager" while true; do clear - echo "File Manager" + echo "file manager" echo "------------------------" - echo "Current path" + echo "current path" pwd echo "------------------------" ls --color=auto -x @@ -13696,22 +13696,22 @@ linux_file() { echo "15. Delete the file" echo "------------------------" echo "21. Compress file directory 22. Unzip file directory 23. Move file directory 24. Copy file directory" - echo "25. Pass the file to another server" + echo "25. Transfer files to other servers" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "Please enter your choice:" Limiting case "$Limiting" in 1) # 进入目录 read -e -p "Please enter the directory name:" dirname - cd "$dirname" 2>/dev/null || echo "Unable to enter directory" - send_stats "Go to the directory" + cd "$dirname" 2>/dev/null || echo "Unable to enter the directory" + send_stats "Enter directory" ;; 2) # 创建目录 - read -e -p "Please enter the directory name to create:" dirname + read -e -p "Please enter the directory name to be created:" dirname mkdir -p "$dirname" && echo "Directory created" || echo "Creation failed" - send_stats "Create a directory" + send_stats "Create directory" ;; 3) # 修改目录权限 read -e -p "Please enter the directory name:" dirname @@ -13721,13 +13721,13 @@ linux_file() { ;; 4) # 重命名目录 read -e -p "Please enter the current directory name:" current_name - read -e -p "Please enter the new directory name:" new_name + read -e -p "Please enter a new directory name:" new_name mv "$current_name" "$new_name" && echo "Directory has been renamed" || echo "Rename failed" send_stats "Rename the directory" ;; 5) # 删除目录 - read -e -p "Please enter the directory name to delete:" dirname - rm -rf "$dirname" && echo "Directory has been deleted" || echo "Delete failed" + read -e -p "Please enter the directory name to be deleted:" dirname + rm -rf "$dirname" && echo "Directory deleted" || echo "Delete failed" send_stats "Delete Directory" ;; 6) # 返回上一级选单目录 @@ -13743,19 +13743,19 @@ linux_file() { read -e -p "Please enter the file name to edit:" filename install nano nano "$filename" - send_stats "Edit files" + send_stats "Edit file" ;; 13) # 修改文件权限 - read -e -p "Please enter the file name:" filename - read -e -p "Please enter permissions (such as 755):" perm + read -e -p "Please enter a file name:" filename + read -e -p "Please enter permissions (e.g. 755):" perm chmod "$perm" "$filename" && echo "Permissions have been modified" || echo "Modification failed" send_stats "Modify file permissions" ;; 14) # 重命名文件 read -e -p "Please enter the current file name:" current_name read -e -p "Please enter a new file name:" new_name - mv "$current_name" "$new_name" && echo "File has been renamed" || echo "Rename failed" - send_stats "Rename the file" + mv "$current_name" "$new_name" && echo "File renamed" || echo "Rename failed" + send_stats "Rename file" ;; 15) # 删除文件 read -e -p "Please enter the file name to delete:" filename @@ -13771,22 +13771,22 @@ linux_file() { 22) # 解压文件/目录 read -e -p "Please enter the file name (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "Decompressed$filename" || echo "Decompression failed" + tar -xzvf "$filename" && echo "Unzipped$filename" || echo "Decompression failed" send_stats "Unzip files/directories" ;; 23) # 移动文件或目录 - read -e -p "Please enter the file or directory path to move:" src_path + read -e -p "Please enter the file or directory path to be moved:" src_path if [ ! -e "$src_path" ]; then echo "Error: The file or directory does not exist." - send_stats "Failed to move file or directory: File or directory does not exist" + send_stats "Failed to move a file or directory: The file or directory does not exist" continue fi read -e -p "Please enter the destination path (including new file or directory name):" dest_path if [ -z "$dest_path" ]; then - echo "Error: Please enter the target path." - send_stats "Moving file or directory failed: The destination path is not specified" + echo "Error: Please enter destination path." + send_stats "Failed to move file or directory: Destination path not specified" continue fi @@ -13803,10 +13803,10 @@ linux_file() { continue fi - read -e -p "Please enter the target path (including the new file name or directory name):" dest_path + read -e -p "Please enter the destination path (including new file or directory name):" dest_path if [ -z "$dest_path" ]; then - echo "Error: Please enter the target path." - send_stats "Failed to copy file or directory: Destination path not specified" + echo "Error: Please enter destination path." + send_stats "Copying file or directory failed: Destination path not specified" continue fi @@ -13819,15 +13819,15 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "Please enter the file path to be transferred:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "Error: The file does not exist." - send_stats "Failed to transfer the file: The file does not exist" + echo "Error: File does not exist." + send_stats "Failed to transfer file: file does not exist" continue fi read -e -p "Please enter the remote server IP:" remote_ip if [ -z "$remote_ip" ]; then echo "Error: Please enter the remote server IP." - send_stats "File transfer failed: Remote server IP was not entered" + send_stats "File transfer failed: Remote server IP not entered" continue fi @@ -13856,7 +13856,7 @@ EOF if [ $? -eq 0 ]; then echo "The file has been transferred to the remote server home directory." - send_stats "File transfer successfully" + send_stats "File transfer successful" else echo "File transfer failed." send_stats "File transfer failed" @@ -13868,7 +13868,7 @@ EOF 0) # 返回上一级选单 - send_stats "Return to the previous menu" + send_stats "Return to the previous menu menu" break ;; *) # 处理无效输入 @@ -13902,7 +13902,7 @@ run_commands_on_servers() { # Convert extracted information into an array IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # Iterate through the server and execute commands + # Traverse the server and execute commands for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -13932,18 +13932,18 @@ fi while true; do clear - send_stats "Cluster Control Center" + send_stats "Cluster control center" echo "Server cluster control" cat ~/cluster/servers.py echo echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}Server list management${gl_bai}" - echo -e "${gl_kjlan}1. ${gl_bai}Add a server${gl_kjlan}2. ${gl_bai}Delete the server${gl_kjlan}3. ${gl_bai}Edit the server" - echo -e "${gl_kjlan}4. ${gl_bai}Backup cluster${gl_kjlan}5. ${gl_bai}Restore the cluster" + echo -e "${gl_kjlan}Server List Management${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Add server${gl_kjlan}2. ${gl_bai}Delete server${gl_kjlan}3. ${gl_bai}Edit the server" + echo -e "${gl_kjlan}4. ${gl_bai}Backup cluster${gl_kjlan}5. ${gl_bai}Restore cluster" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}Install the tech lion script${gl_kjlan}12. ${gl_bai}Update the system${gl_kjlan}13. ${gl_bai}Clean the system" - echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set up 1G virtual memory" + echo -e "${gl_kjlan}11. ${gl_bai}Install the tech lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" + echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom commands" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -13955,7 +13955,7 @@ while true; do send_stats "Add a cluster server" read -e -p "Server name:" server_name read -e -p "Server IP:" server_ip - read -e -p "Server Port (22):" server_port + read -e -p "Server port (22):" server_port local server_port=${server_port:-22} read -e -p "Server username (root):" server_username local server_username=${server_username:-root} @@ -13986,7 +13986,7 @@ while true; do clear send_stats "Restore the cluster" echo "Please upload your servers.py and press any key to start uploading!" - echo -e "Please upload your${gl_huang}servers.py${gl_bai}File to${gl_huang}/root/cluster/${gl_bai}Complete the restore!" + echo -e "Please upload your${gl_huang}servers.py${gl_bai}file to${gl_huang}/root/cluster/${gl_bai}Complete the restore!" break_end ;; @@ -14017,8 +14017,8 @@ while true; do ;; 51) - send_stats "Customize the execution of commands" - read -e -p "Please enter the batch execution command:" mingling + send_stats "Custom execution command" + read -e -p "Please enter the command for batch execution:" mingling run_commands_on_servers "${mingling}" ;; @@ -14043,7 +14043,7 @@ echo "It will provide users with a simpler and more elegant promotion and purcha echo "" echo -e "Server Offers" echo "------------------------" -echo -e "${gl_lan}Leica Cloud Hong Kong CN2 GIA South Korea Dual ISP US CN2 GIA Discounts${gl_bai}" +echo -e "${gl_lan}Laika Cloud Hong Kong CN2 GIA Korean dual ISP US CN2 GIA promotions${gl_bai}" echo -e "${gl_bai}Website: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd $10.99 per year, USA, 1 core, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" @@ -14052,14 +14052,14 @@ echo "------------------------" echo -e "${gl_zi}Hostinger 52.7 dollars per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan SoftBank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" +echo -e "${gl_huang}Brickworker, $49 per quarter, US CN2GIA, Japan SoftBank, 2 cores, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT $28 per quarter US CN2GIA 1 core 2G memory 20G hard drive 800G traffic per month${gl_bai}" -echo -e "${gl_bai}Website: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" +echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" echo -e "${gl_zi}V.PS $6.9 per month Tokyo SoftBank 2 core 1G memory 20G hard drive 1T traffic per month${gl_bai}" -echo -e "${gl_bai}Website: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" +echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" @@ -14067,13 +14067,13 @@ echo "------------------------" echo "" echo -e "Domain name discount" echo "------------------------" -echo -e "${gl_lan}GNAME 8.8 dollars first year COM domain name 6.68 dollars first year CC domain name${gl_bai}" +echo -e "${gl_lan}GNAME $8.8 first-year COM domain name $6.68 first-year CC domain name${gl_bai}" echo -e "${gl_bai}Website: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" echo "------------------------" echo "" -echo -e "Technology lion surrounding" +echo -e "Technology lion peripherals" echo "------------------------" -echo -e "${gl_kjlan}B station:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}Oil pipe:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" +echo -e "${gl_kjlan}Station B:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}Oil pipe:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" echo -e "${gl_kjlan}Official website:${gl_bai}https://kejilion.pro/ ${gl_kjlan}navigation:${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}blog:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}Software Center:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" @@ -14092,7 +14092,7 @@ send_stats "Script update" cd ~ while true; do clear - echo "Update log" + echo "Change log" echo "------------------------" echo "All logs:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" @@ -14101,11 +14101,11 @@ while true; do local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) if [ "$sh_v" = "$sh_v_new" ]; then - echo -e "${gl_lv}You are already the latest version!${gl_huang}v$sh_v${gl_bai}" - send_stats "The script is up to date and no update is required" + echo -e "${gl_lv}You are already on the latest version!${gl_huang}v$sh_v${gl_bai}" + send_stats "The script is already up to date and does not need to be updated" else echo "Discover a new version!" - echo -e "Current version v$sh_vLatest version${gl_huang}v$sh_v_new${gl_bai}" + echo -e "Current version v$sh_vlatest version${gl_huang}v$sh_v_new${gl_bai}" fi @@ -14114,7 +14114,7 @@ while true; do if [ -n "$existing_cron" ]; then echo "------------------------" - echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" fi echo "------------------------" @@ -14157,7 +14157,7 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" send_stats "Turn on automatic script update" break_end ;; @@ -14193,20 +14193,20 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}System information query" echo -e "${gl_kjlan}2. ${gl_bai}System update" echo -e "${gl_kjlan}3. ${gl_bai}System Cleanup" -echo -e "${gl_kjlan}4. ${gl_bai}Basic tools" +echo -e "${gl_kjlan}4. ${gl_bai}basic tools" echo -e "${gl_kjlan}5. ${gl_bai}BBR Management" -echo -e "${gl_kjlan}6. ${gl_bai}Docker Management" -echo -e "${gl_kjlan}7. ${gl_bai}WARP Management" +echo -e "${gl_kjlan}6. ${gl_bai}Docker management" +echo -e "${gl_kjlan}7. ${gl_bai}WARP management" echo -e "${gl_kjlan}8. ${gl_bai}Test script collection" echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Script Collection" echo -e "${gl_huang}10. ${gl_bai}LDNMP website building" -echo -e "${gl_kjlan}11. ${gl_bai}Application Market" +echo -e "${gl_kjlan}11. ${gl_bai}application market" echo -e "${gl_kjlan}12. ${gl_bai}Backend workspace" -echo -e "${gl_kjlan}13. ${gl_bai}System Tools" +echo -e "${gl_kjlan}13. ${gl_bai}system tools" echo -e "${gl_kjlan}14. ${gl_bai}Server cluster control" echo -e "${gl_kjlan}15. ${gl_bai}Advertising column" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu server opening script" +echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu server opening script" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14217,7 +14217,7 @@ read -e -p "Please enter your selection:" choice case $choice in 1) linux_info ;; 2) clear ; send_stats "System update" ; linux_update ;; - 3) clear ; send_stats "System Cleanup" ; linux_clean ;; + 3) clear ; send_stats "System cleanup" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; @@ -14232,7 +14232,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu server opening script" ; cd ~ + p) send_stats "Eudemons Parlu server opening script" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; @@ -14249,15 +14249,15 @@ k_info() { send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "The following is the k command reference use case:" +echo "The following is a reference use case for the k command:" echo "Start script k" echo "Install software package k install nano wget | k add nano wget | k Install nano wget" echo "Uninstall the package k remove nano wget | k del nano wget | k uninstall nano wget | k Uninstall nano wget" echo "Update system k update | k update" echo "Clean system garbage k clean | k clean" -echo "Reinstall the system panel k dd | k Reinstall" +echo "Reinstall the system panel k dd | k reinstall" echo "bbr3 control panel k bbr3 | k bbrv3" -echo "Kernel Tuning Panel k nhyh | k kernel optimization" +echo "Kernel Tuning Panel k nhyh | k Kernel Optimization" echo "Set virtual memory k swap 2048" echo "Set virtual time zone k time Asia/Shanghai | k time zone Asia/Shanghai" echo "System Recycling Bin k trash | k hsz | k Recycling Bin" @@ -14265,13 +14265,13 @@ echo "System backup function k backup | k bf | k backup" echo "ssh remote connection tool k ssh | k remote connection" echo "rsync remote synchronization tool k rsync | k remote synchronization" echo "Hard disk management tool k disk | k hard disk management" -echo "Intranet penetration (server side) k frps" +echo "Intranet penetration (server) k frps" echo "Intranet penetration (client) k frpc" echo "Software start k start sshd | k start sshd" echo "Software stop k stop sshd | k stop sshd" echo "Software restart k restart sshd | k restart sshd" echo "Check software status k status sshd | k status sshd" -echo "Software boot k enable docker | k autostart docke | k startup docker" +echo "k enable docker | k autostart docker | k enable docker when booting the software" echo "Domain name certificate application k ssl" echo "Domain name certificate expiration query k ssl ps" echo "docker management plane k docker" @@ -14281,7 +14281,7 @@ echo "docker image management k docker img |k docker image" echo "LDNMP site management k web" echo "LDNMP cache cleanup k web cache" echo "Install WordPress k wp |k wordpress |k wp xxx.com" -echo "Install the reverse proxy k fd |k rp |k anti-generation |k fd xxx.com" +echo "Install reverse proxy k fd |k rp |k reverse proxy |k fd xxx.com" echo "Install load balancing k loadbalance |k load balancing" echo "Firewall panel k fhq |k firewall" echo "Open port k dkdk 8080 |k Open port 8080" @@ -14290,14 +14290,14 @@ echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" echo "Command favorites k fav | k command favorites" echo "App Market Management k app" -echo "Application number quick management k app 26 | k app 1panel | k app npm" +echo "Quick management of application numbers k app 26 | k app 1panel | k app npm" echo "Display system information k info" } if [ "$#" -eq 0 ]; then - # If there are no parameters, run interactive logic + # Without arguments, run interactive logic kejilion_sh else # If there are parameters, execute the corresponding function @@ -14429,7 +14429,7 @@ else status|状态) shift - send_stats "Software status view" + send_stats "Check software status" status "$@" ;; start|启动) @@ -14439,7 +14439,7 @@ else ;; stop|停止) shift - send_stats "Software pause" + send_stats "software pause" stop "$@" ;; restart|重启) @@ -14450,18 +14450,18 @@ else enable|autostart|开机启动) shift - send_stats "Software boots up" + send_stats "Software starts automatically when booting" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "Check the certificate status" + send_stats "View certificate status" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "Quickly apply for a certificate" + send_stats "Apply for a certificate quickly" elif [ -n "$1" ]; then add_ssl "$1" send_stats "Quickly apply for a certificate" @@ -14509,7 +14509,7 @@ else app) shift - send_stats "Apply $@" + send_stats "Apply$@" linux_panel "$@" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index f3f6a02e1..a96968ff1 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# 関数の埋もポイント情報を収集し、現在のスクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、ユーザーが使用する関数名を記録する関数。彼らは絶対に機密情報を伴わない、安心してください!私を信じてください! -# なぜこの関数を設計する必要があるのですか?目的は、ユーザーが使用する機能をよりよく理解し、関数をさらに最適化して、ユーザーのニーズを満たすより多くの関数を起動することです。 -# 全文の場合、send_stats関数の呼び出し場所、透明性、オープンソースを検索できます。懸念がある場合は、使用を拒否できます。 +# この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! +# なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# ユーザーに条件に同意するように促します +# ユーザーに規約への同意を求めるプロンプトを表示する UserLicenseAgreement() { clear echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" - echo "スクリプトを初めて使用して、ユーザーライセンス契約を読んで同意してください。" + echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "上記の条件に同意しますか? (y/n):" user_input + read -r -p "上記の条件に同意しますか? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "ライセンスの同意" + send_stats "ライセンス契約" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "許可の拒否" + send_stats "許可が拒否されました" clear exit fi @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメータが指定されていません!" + echo "パッケージパラメーターは提供されていません!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}インストール$package...${gl_bai}" + echo -e "${gl_huang}インストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -220,11 +220,11 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}ヒント:${gl_bai}ディスクスペースが不十分です!" - echo "現在利用可能なスペース:$((available_space_mb/1024))g" + echo -e "${gl_huang}ヒント:${gl_bai}ディスク容量が足りません!" + echo "現在の利用可能なスペース: $((available_space_mb/1024))G" echo "最小需要スペース:${required_gb}G" - echo "インストールは継続できません。ディスクスペースを掃除して、もう一度お試しください。" - send_stats "ディスクスペースが不十分です" + echo "インストールを続行できません。ディスク容量をクリアして、再試行してください。" + send_stats "ディスク容量が足りない" break_end kejilion fi @@ -238,7 +238,7 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "パッケージパラメータが指定されていません!" return 1 fi @@ -261,14 +261,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "不明なパッケージマネージャー!" + echo "不明なパッケージマネージャーです!" return 1 fi done } -# さまざまなディストリビューションに適したユニバーサル systemctl 関数 +# さまざまな分布に適したUniversal SystemCTL関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -297,17 +297,17 @@ start() { if [ $? -eq 0 ]; then echo "$1サービスが開始されました。" else - echo "エラー:開始$1サービスは失敗しました。" + echo "エラー: 開始$1サービスが失敗しました。" fi } -# サービスを停止します +# サービスを停止する stop() { systemctl stop "$1" if [ $? -eq 0 ]; then echo "$1サービスは停止しました。" else - echo "エラー:停止します$1サービスは失敗しました。" + echo "エラー: 停止$1サービスに失敗しました。" fi } @@ -315,9 +315,9 @@ stop() { status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1サービスステータスが表示されます。" + echo "$1サービスのステータスが表示されます。" else - echo "エラー:表示できません$1サービスステータス。" + echo "エラー: 表示できません$1サービスステータス。" fi } @@ -506,12 +506,12 @@ while true; do echo "Dockerコンテナリスト" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "コンテナ操作" + echo "コンテナの運用" echo "------------------------" - echo "1. 新しいコンテナを作成する" + echo "1.新しいコンテナを作成します" echo "------------------------" echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" - echo "3.指定された容器を停止します7。すべての容器を停止します" + echo "3. 指定したコンテナを停止します。 7. すべてのコンテナを停止します。" echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" echo "------------------------" @@ -525,27 +525,27 @@ while true; do read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新しいコンテナを作成します" - read -e -p "作成コマンドを入力してください:" dockername + send_stats "新しいコンテナを作成する" + read -e -p "作成コマンドを入力してください:" dockername $dockername ;; 2) - send_stats "指定された容器を起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + send_stats "指定したコンテナを起動する" + read -e -p "コンテナ名を入力してください (複数のコンテナ名はスペースで区切ってください):" dockername docker start $dockername ;; 3) - send_stats "指定された容器を停止します" + send_stats "指定したコンテナを停止する" read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker stop $dockername ;; 4) send_stats "指定したコンテナを削除します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + read -e -p "コンテナ名を入力してください (複数のコンテナ名はスペースで区切ってください):" dockername docker rm -f $dockername ;; 5) - send_stats "指定された容器を再起動します" + send_stats "指定したコンテナを再起動します" read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername docker restart $dockername ;; @@ -582,13 +582,13 @@ while true; do break_end ;; 12) - send_stats "コンテナログを表示します" + send_stats "コンテナログの表示" read -e -p "コンテナ名を入力してください:" dockername docker logs $dockername break_end ;; 13) - send_stats "コンテナネットワークを表示します" + send_stats "コンテナネットワークを表示する" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -606,7 +606,7 @@ while true; do break_end ;; 14) - send_stats "コンテナの占有を表示します" + send_stats "コンテナ占有率の表示" docker stats --no-stream break_end ;; @@ -623,7 +623,7 @@ while true; do 16) send_stats "コンテナポートアクセスをブロックします" - read -e -p "コンテナ名を入力してください:" docker_name + read -e -p "コンテナ名を入力してください:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -643,37 +643,37 @@ docker_image() { while true; do clear send_stats "Docker画像管理" - echo "Docker画像リスト" + echo "Dockerイメージリスト" docker image ls echo "" echo "ミラー操作" echo "------------------------" - echo "1.指定された画像を取得する3。指定された画像を削除します" - echo "2。指定された画像4を更新します。すべての画像を削除します" + echo "1. 指定した画像を取得 3. 指定した画像を削除" + echo "2. 指定した画像を更新 4. すべての画像を削除" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) send_stats "鏡を引っ張ります" read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}画像を取得する:$name${gl_bai}" + echo -e "${gl_huang}画像の取得:$name${gl_bai}" docker pull $name done ;; 2) send_stats "画像を更新します" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}更新された画像:$name${gl_bai}" + echo -e "${gl_huang}画像の更新:$name${gl_bai}" docker pull $name done ;; 3) send_stats "画像の削除" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do docker rmi -f $name done @@ -688,7 +688,7 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -756,7 +756,7 @@ install_crontab() { service cron start ;; *) - echo "サポートされていない分布:$ID" + echo "サポートされていないディストリビューション:$ID" return ;; esac @@ -777,18 +777,18 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、ファイルが存在しない場合はファイルを作成し、デフォルト設定を書き込む + # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成し、デフォルト設定を書き込みます if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQを使用して、構成ファイルの更新を処理します + # jq を使用して構成ファイルの更新を処理する local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # 現在の構成にすでに ipv6 設定があるかどうかを確認します local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 構成を更新し、IPv6を有効にします + # 構成を更新してIPv6を有効にする if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else @@ -814,20 +814,20 @@ docker_ipv6_off() { # 構成ファイルが存在するかどうかを確認します if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}設定ファイルが存在しません${gl_bai}" + echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" return fi - # 現在の構成を読み取る + # 現在の構成をお読みください local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # JQを使用して、構成ファイルの更新を処理します local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 現在のIPv6ステータスを確認してください + # 現在のIPv6ステータスを確認する local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較する + # 元の構成と新しい構成を比較します if [[ "$CURRENT_IPV6" == "false" ]]; then echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" else @@ -879,7 +879,7 @@ open_port() { install iptables for port in "${ports[@]}"; do - # 既存のクロージングルールを削除します + # 既存のシャットダウン ルールを削除する iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null @@ -895,7 +895,7 @@ open_port() { done save_iptables_rules - send_stats "ポートが開かれました" + send_stats "ポートがオープンされました" } @@ -913,7 +913,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 緊密なルールを追加します + # シャットダウンルールを追加する if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -924,7 +924,7 @@ close_port() { fi done - # 既存のルールを削除する(ある場合) + # 既存のルール (存在する場合) を削除します。 iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null @@ -933,21 +933,21 @@ close_port() { iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "ポートは閉じた" + send_stats "ポートが閉じられています" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "少なくとも 1 つの IP アドレスまたは IP セグメントを入力してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存のブロッキングルールを削除します + # 既存のブロック ルールを削除する iptables -D INPUT -s $ip -j DROP 2>/dev/null # 許可ルールを追加します @@ -958,7 +958,7 @@ allow_ip() { done save_iptables_rules - send_stats "IPをリリースしました" + send_stats "リリースされたIP" } block_ip() { @@ -982,7 +982,7 @@ block_ip() { done save_iptables_rules - send_stats "IPブロック" + send_stats "IPがブロックされました" } @@ -1002,10 +1002,10 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS防御をオンにします" + send_stats "DDoS 防御をオンにする" } -# DDOS防御をオフにします +# DDoS 防御をオフにする disable_ddos_defense() { # 防御DDOをオフにします iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null @@ -1017,14 +1017,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS防御をオフにします" + send_stats "DDoS 防御をオフにする" } -# 国家IPルールを管理する機能 +# 国内の知財ルールを管理する機能 manage_country_rules() { local action="$1" shift # 去掉第一个参数,剩下的全是国家代码 @@ -1042,7 +1042,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "エラー: ダウンロード$country_codeIPゾーンファイルが失敗しました" continue fi @@ -1062,7 +1062,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "エラー:ダウンロード$country_codeIPゾーンファイルが失敗しました" + echo "エラー: ダウンロード$country_codeIPゾーンファイルが失敗しました" continue fi @@ -1090,7 +1090,7 @@ manage_country_rules() { ;; *) - echo "使用法:manage_country_rules {block | lock | block} " + echo "使用法: manage_country_rules {block|allow|unblock} " ;; esac done @@ -1119,19 +1119,19 @@ iptables_panel() { echo "ファイアウォール管理" echo "------------------------" echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3. すべてのポートを開く 4. すべてのポートを閉じる" + echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" echo "------------------------" - echo "5。IPホワイトリスト6。IPブラックリスト" + echo "5. IP ホワイトリスト 6. IP ブラックリスト" echo "7.指定されたIPをクリアします" echo "------------------------" - echo "11. ping 12を許可します。Pingを無効にします" + echo "11. PING を許可する 12. PING を無効にする" echo "------------------------" - echo "13。DDOS防衛を開始14。DDOS防衛をオフにします" + echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" echo "17.指定国でのIP制限をリリースします" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -1141,12 +1141,12 @@ iptables_panel() { send_stats "指定したポートを開く" ;; 2) - read -e -p "閉じたポート番号を入力してください:" c_port + read -e -p "閉じられたポート番号を入力してください:" c_port close_port $c_port - send_stats "指定されたポートを閉じます" + send_stats "指定したポートを閉じる" ;; 3) - # すべてのポートを開きます + # すべてのポートを開く current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1185,12 +1185,12 @@ iptables_panel() { ;; 6) # IPブラックリスト - read -e -p "ブロックされたIPまたはIPセグメントを入力してください:" c_ip + read -e -p "ブロックされた IP または IP 範囲を入力してください:" c_ip block_ip $c_ip ;; 7) - # 指定されたIPをクリアします - read -e -p "クリアされたIPを入力してください:" d_ip + # 指定したIPをクリア + read -e -p "クリアされた IP を入力してください:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1208,7 +1208,7 @@ iptables_panel() { iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "pingを無効にします" + send_stats "PINGを無効にする" ;; 13) enable_ddos_defense @@ -1220,7 +1220,7 @@ iptables_panel() { 15) read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code - send_stats "許可された国$country_codeIP" + send_stats "国を許可する$country_codeIP" ;; 16) read -e -p "許可されている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code @@ -1229,7 +1229,7 @@ iptables_panel() { ;; 17) - read -e -p "クリアされた国コードを入力してください(複数の国コードは、CN US JPなどのスペースで区切ることができます):" country_code + read -e -p "クリアされた国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules unblock $country_code send_stats "国をきれいにします$country_codeIP" ;; @@ -1260,7 +1260,7 @@ add_swap() { mkswap -f "$partition" done - # /swapfile が使用されていないことを確認してください + # /swapfileが使用されなくなったことを確認してください swapoff /swapfile # 古い /swapfileを削除します @@ -1307,7 +1307,7 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginxバージョンを取得します + # nginxのバージョンを取得する local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" @@ -1317,11 +1317,11 @@ ldnmp_v() { local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHPバージョンを取得します + # PHPのバージョンを取得する local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redisバージョンを取得します + # Redis バージョンを取得する local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1334,7 +1334,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 必要なディレクトリとファイルを作成します + # 必要なディレクトリとファイルを作成する cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1392,7 +1392,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされている" + echo "LDNMP環境がインストールされています" echo "------------------------" ldnmp_v @@ -1452,9 +1452,9 @@ install_ssltls_text() { echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}証明書ストレージパス${gl_bai}" - echo "公開鍵:/etc/letsencrypt/live/$yuming/fullchain.pem" - echo "秘密鍵:/etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}証明書の保存パス${gl_bai}" + echo "公開キー: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "秘密鍵: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1519,16 +1519,16 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "ドメイン名証明書の成功したアプリケーション" + send_stats "ドメイン名証明書の申請が成功しました" else - send_stats "ドメイン名証明書のアプリケーションは失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書申請が失敗しました。次の考えられる理由を確認して、もう一度やり直してください。" + send_stats "ドメイン名証明書の申請に失敗しました" + echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" - echo -e "3.ネットワーク構成の問題cloudflareワープやその他の仮想ネットワークを使用する場合は、一時的にシャットダウンしてください" - echo -e "4。ファイアウォールの制限orポート80/443が開かれているかどうかを確認して、検証がアクセス可能であることを確認してください" + echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" + echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" - echo -e "6.国内登録制限domainドメイン名が中国本土で登録されているかどうかを確認してください" + echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" break_end clear echo "もう一度展開してみてください$webname" @@ -1551,7 +1551,7 @@ fi add_yuming() { ip_address - echo -e "まず、ドメイン名をローカル IP に解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming } @@ -1617,7 +1617,7 @@ nginx_upgrade() { docker restart $ldnmp_pods > /dev/null 2>&1 send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + echo "更新する${ldnmp_pods}仕上げる" } @@ -1657,13 +1657,13 @@ cf_purge_cache() { # ゾーン_idsを配列に変換します ZONE_IDS=($ZONE_IDS) else - # キャッシュをクリーニングするかどうかをユーザーに促します - read -e -p "CloudFlareのキャッシュをきれいにする必要がありますか? (y/n):" answer + # キャッシュをクリアするかどうかをユーザーに確認する + read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報が保存されます$CONFIG_FILE、後でCF情報を変更できます" - read -e -p "API_TOKENを入力してください:" API_TOKEN + echo "CF情報が保存されます$CONFIG_FILECF 情報は後で変更できます。" + read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CFユーザ​​ー名を入力してください:" EMAIL - read -e -p "ゾーン_id(スペースで区切られた複数)を入力してください。" -a ZONE_IDS + read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" @@ -1672,7 +1672,7 @@ cf_purge_cache() { # 各ZONE_IDをループして、Clear Cacheコマンドを実行します for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "zone_id のキャッシュをクリアします:$ZONE_ID" + echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1696,10 +1696,10 @@ web_cache() { web_del() { - send_stats "サイトデータを削除します" + send_stats "サイトデータを削除する" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "サイトデータを削除するには、ドメイン名を入力してください(複数のドメイン名がスペースで区切られています):" yuming_list + read -e -p "サイト データを削除するには、ドメイン名を入力してください (複数のドメイン名はスペースで区切ります)。" yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1716,7 +1716,7 @@ web_del() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認します + # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認してください。 echo "データベースの削除:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1733,14 +1733,14 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # モードパラメーターに従ってWAFをオンまたはオフにすることにしました + # モードパラメータに従ってWAFをオンにするかオフにするかを決定します。 if [ "$mode" == "on" ]; then # WAFをオンにしてください:コメントを削除します sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # WAFを閉じる:コメントを追加します + # WAF をオフにする: コメントを追加する sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1796,11 +1796,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 古い定義を削除する sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 「Happy Publishing」を含む行の前に新しい定義を挿入します。 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1823,7 +1823,7 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 古い定義を削除します + # 古い定義を削除する sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" @@ -1851,7 +1851,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotliをオンにする:コメントを削除します + # Brotli をオンにする: コメントを削除する sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1865,7 +1865,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # Brotliを閉じる:コメントを追加します sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1885,7 +1885,7 @@ nginx_br() { return 1 fi - # nginx イメージを確認し、それに応じて処理します + # nginx画像を確認し、状況に応じてそれらを処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1942,7 +1942,7 @@ nginx_zstd() { return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # nginx イメージを確認し、それに応じて処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1993,19 +1993,19 @@ web_security() { echo "------------------------" echo "1.防衛プログラムをインストールします" echo "------------------------" - echo "5。SSHインターセプトレコードを表示6。ウェブサイト傍受記録を見る" - echo "7。防衛ルールのリストを表示8。ログのリアルタイム監視を表示" + echo "5。SSHインターセプトレコード6を表示6。ウェブサイト傍受記録を見る" + echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11.インターセプトパラメーターを構成12。すべてのブロックされたipsをクリアします" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" - echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" + echo "21。CloudFlareモード22。5秒シールドの高負荷" echo "------------------------" - echo "31。WAF32をオンにしてください。WAFをオフにします" - echo "33。DDOS防衛をオンにする34。DDOS防衛をオフにする" + echo "31. WAF をオンにする 32. WAF をオフにする" + echo "33. DDOS 防御をオンにする 34. DDOS 防御をオフにする" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 防御プログラムをアンインストールする" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" sub_choice case $sub_choice in @@ -2088,10 +2088,10 @@ web_security() { ;; 21) - send_stats "CloudFlareモード" + send_stats "クラウドフレアモード" echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" echo "https://dash.cloudflare.com/login" - read -e -p "CFアカウント番号を入力します:" cfuser + read -e -p "CF の口座番号を入力してください:" cfuser read -e -p "CF のグローバル API キーを入力します。" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf @@ -2107,20 +2107,20 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "CloudFlareモードは、CFバックグラウンド、サイトセキュリティイベントでインターセプトレコードを表示するように構成されています" + echo "Cloudflare モードが設定されており、傍受記録は cf バックグラウンド、site-security-events で表示できます。" ;; 22) send_stats "5秒シールドでの高負荷" - echo -e "${gl_huang}ウェブサイトは5分ごとに自動的に検出されます。高負荷が検出されると、シールドが自動的にオンになり、低負荷が5秒間自動的にオフになります。${gl_bai}" + echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメーターを取得します:" echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" - echo -e "CFバックグラウンドドメイン名の概要ページの右下に移動して${gl_huang}エリアID${gl_bai}" + echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CFアカウント番号を入力します:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください:" cftoken + read -e -p "CF の口座番号を入力してください:" cfuser + read -e -p "CFのグローバルAPIキーを入力してください。" cftoken read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID cd ~ @@ -2140,7 +2140,7 @@ web_security() { (crontab -l 2>/dev/null; echo "$cron_job") | crontab - echo "高負荷自動シールドオープニングスクリプトが追加されました" else - echo "自動シールドスクリプトはすでに存在しています、それを追加する必要はありません" + echo "自動シールド開放スクリプトはすでに存在するため、追加する必要はありません" fi ;; @@ -2154,7 +2154,7 @@ web_security() { 32) nginx_waf off echo "サイトWAFは閉鎖されています" - send_stats "サイトWAFは閉鎖されています" + send_stats "サイト WAF がダウンしています" ;; 33) @@ -2179,7 +2179,7 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processes設定値を取得します +# 現在のworker_processesの設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') # 値に応じてモード情報を設定します @@ -2198,21 +2198,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTDが有効になっていてコメントされていないかどうかを確認します(ZSTDで行全体が開始されます;) + # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotliが有効であり、コメントされていないかどうかを確認してください + # Brotliが有効になっており、コメントされていないかどうかを確認してください if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # GZIPが有効になっており、コメントされていないかどうかを確認してください + # gzip が有効になっていてコメントが解除されているかどうかを確認します if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2229,22 +2229,22 @@ web_optimization() { check_nginx_compression clear send_stats "LDNMP環境を最適化します" - echo -e "LDNMP環境を最適化します${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1。標準モード2。高性能モード(推奨2H4g以上)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" - echo "5。BR圧縮をオンにします6。BR圧縮をオフにします" - echo "7。ZSTD圧縮をオンにします8。ZSTD圧縮をオフにします" + echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" + echo "7. zstd 圧縮をオンにする 8. zstd 圧縮をオフにする" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) send_stats "サイト標準モード" - # nginxチューニング + # nginxのチューニング sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf @@ -2254,7 +2254,7 @@ web_optimization() { docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # PHPのチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2266,7 +2266,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysqlのチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2282,7 +2282,7 @@ web_optimization() { ;; 2) - send_stats "サイトの高性能モード" + send_stats "サイトハイパフォーマンスモード" # nginxチューニング sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf @@ -2294,7 +2294,7 @@ web_optimization() { docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHPチューニング + # PHPのチューニング wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2316,7 +2316,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP環境は、高性能モードに設定されています" + echo "LDNMP 環境が高パフォーマンス モードに設定されている" ;; 3) @@ -2376,7 +2376,7 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker = "$ {gl_lv} $ {gl_bai}インストール" +# check_docker="${gl_lv} は ${gl_bai} をインストールしました" # else # check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" # fi @@ -2424,19 +2424,19 @@ check_docker_image_update() { return fi - # コンテナの作成時間と画像名を取得します + # コンテナの作成時刻とイメージ名を取得します。 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # ミラーウェアハウスとタグを抽出します + # 画像リポジトリとタグを抽出する local image_repo=${image_name%%:*} local image_tag=${image_name##*:} # デフォルトのラベルは最新です [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 公式画像のサポートを追加します + # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" # Docker Hub APIから画像公開時間を取得します @@ -2487,19 +2487,19 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 他のすべてのIPSを確認してブロックします + # 他のすべての IP をチェックしてブロックします if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 指定したIPの確認と解放 if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2525,7 +2525,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # コンテナのIPアドレスを取得する local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2535,17 +2535,17 @@ clear_container_rules() { install iptables - # 他のすべてのIPをブロックするルールを明確にします + # 他のすべての IP をブロックする明確なルール if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定したIPを許可するルールをクリアします + # 指定されたIPをリリースするためのルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2559,12 +2559,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 指定したIPを許可するルールをクリアします if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2575,7 +2575,7 @@ clear_container_rules() { fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "IP+ポートによるサービスへのアクセスが許可されました" save_iptables_rules } @@ -2589,8 +2589,8 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" - echo "使用法:block_host_port <ポート番号> <承認IP>" + echo "エラー: アクセスを許可するには、ポート番号と IP を入力してください。" + echo "使用法: block_host_port <ポート番号> <許可された IP>" return 1 fi @@ -2602,7 +2602,7 @@ block_host_port() { iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 指定したIPへのアクセスを許可する if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2616,7 +2616,7 @@ block_host_port() { - # 他のすべてのIPアクセスを拒否しました + # 他のすべての IP からのアクセスを拒否する if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi @@ -2626,7 +2626,7 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # ローカルアクセスを許可する if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2648,15 +2648,15 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー: アクセスを許可するには、ポート番号と IP を入力してください。" - echo "使用法:CLEAR_HOST_PORT_RULES <ポート番号> <認定IP>" + echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "使用法: clear_host_port_rules <ポート番号> <許可された IP>" return 1 fi install iptables - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 他のすべての IP からのアクセスをブロックするルールをクリアします if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2672,12 +2672,12 @@ clear_host_port_rules() { fi - # 他のすべてのIPアクセスをブロックするルールをクリアします + # 他のすべての IP からのアクセスをブロックするルールをクリアします if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ローカルアクセスを許可する明確なルール + # ネイティブアクセスを可能にするルールを明確にします if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2791,7 +2791,7 @@ while true; do echo "" $docker_use $docker_passwd - send_stats "更新します$docker_name" + send_stats "更新する$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2800,8 +2800,8 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" - send_stats "アンインストール$docker_name" + echo "アプリがアンインストールされました" + send_stats "アンインストールする$docker_name" ;; 5) @@ -2818,12 +2818,12 @@ while true; do ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "IPアクセスを許可する${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "IPアクセスをブロックする${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2862,8 +2862,8 @@ docker_app_plus() { echo "------------------------" echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5. ドメイン名アクセスを追加します。 6. ドメイン名アクセスを削除します。" - echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" + echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" + echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -2872,7 +2872,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,8 +2895,8 @@ docker_app_plus() { ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}ドメイン名アクセス設定" + send_stats "${docker_name}ドメイン名アクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" @@ -2910,7 +2910,7 @@ docker_app_plus() { clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックする${docker_name}" + send_stats "IPアクセスをブロックします${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -2995,7 +2995,7 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# セッションが存在するかどうかを確認する関数 +# セッションが存在するかどうかを確認する機能 session_exists() { tmux has-session -t $1 2>/dev/null } @@ -3110,7 +3110,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再インストールできません" + send_stats "LDNMP環境を再度インストールできません" echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" break_end linux_ldnmp @@ -3138,10 +3138,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "Nginx環境をインストールします" +send_stats "nginx環境をインストールする" root_use clear -echo -e "${gl_huang}nginxはインストールされていません、nginx環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}nginx がインストールされていません。nginx 環境のインストールを開始してください...${gl_bai}" check_disk_space 1 /home check_port install_dependency @@ -3152,7 +3152,7 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginxがインストールされています" +echo "nginxがインストールされました" echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" echo "" @@ -3164,7 +3164,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "最初に LDNMP 環境をインストールしてください" + send_stats "LDNMP環境を最初にインストールしてください" ldnmp_install_all fi @@ -3185,7 +3185,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "あなたの$webname建てられた!" + echo "あなたの$webname建てられました!" echo "https://$yuming" echo "------------------------" echo "$webnameインストール情報は次のとおりです。" @@ -3207,7 +3207,7 @@ ldnmp_wp() { webname="WordPress" yuming="${1:-}" send_stats "インストール$webname" - echo "導入を開始する$webname" + echo "展開を開始します$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3281,7 +3281,7 @@ ldnmp_Proxy_backend() { reverseproxy_port="${2:-}" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3340,7 +3340,7 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMPサイト管理" + send_stats "LDNMP サイト管理" echo "LDNMP環境" echo "------------------------" ldnmp_v @@ -3374,11 +3374,11 @@ ldnmp_web_status() { echo "------------------------" echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" - echo "5.アクセスログを表示6。エラーログを表示します" - echo "7.グローバル構成の編集8。サイト構成の編集" + echo "5. アクセスログの表示 6. エラーログの表示" + echo "7. グローバル構成の編集 8. サイト構成の編集" echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" echo "------------------------" - echo "20.指定されたサイトデータを削除します" + echo "20. 指定したサイトデータを削除する" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -3386,7 +3386,7 @@ ldnmp_web_status() { case $sub_choice in 1) send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3395,8 +3395,8 @@ ldnmp_web_status() { ;; 2) - send_stats "サイトドメイン名を変更します" - echo -e "${gl_hong}強くお勧めします:${gl_bai}最初にサイトデータ全体をバックアップしてから、サイトドメイン名を変更します!" + send_stats "サイトのドメイン名を変更する" + echo -e "${gl_hong}強くお勧めします:${gl_bai}まずサイト全体のデータをバックアップしてから、サイトのドメイン名を変更してください。" read -e -p "古いドメイン名を入力してください:" oddyuming read -e -p "新しいドメイン名を入力してください:" yuming install_certbot @@ -3421,7 +3421,7 @@ ldnmp_web_status() { done done - # Web サイトのディレクトリの置き換え + # ウェブサイトディレクトリの交換 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3443,9 +3443,9 @@ ldnmp_web_status() { ;; 4) send_stats "関連するサイトを作成します" - echo -e "アクセスのための既存のサイトの新しいドメイン名を関連付ける" - read -e -p "既存のドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスします" + read -e -p "既存のドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status @@ -3469,7 +3469,7 @@ ldnmp_web_status() { break_end ;; 7) - send_stats "グローバル構成の編集" + send_stats "グローバル構成を編集します" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload @@ -3477,7 +3477,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください。" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3487,7 +3487,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "サイトデータを表示します" + send_stats "サイトデータの表示" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3523,16 +3523,16 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}最近では人気のある強力な運用および保守管理パネルです。" + echo "${panelname}人気の強力な運用保守管理盤です。" echo "公式サイト紹介:$panelurl " echo "" echo "------------------------" - echo "1。インストール2。管理3。アンインストール" + echo "1. インストール 2. 管理 3. アンインストール" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) check_disk_space 1 @@ -3599,7 +3599,7 @@ donlond_frp() { generate_frps_config() { send_stats "FRPサーバーをインストールする" - # ランダムポートと資格情報を生成します + # ランダムなポートと認証情報を生成する local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3620,7 +3620,7 @@ EOF donlond_frp frps - # 出力生成情報 + # 生成された情報を出力する ip_address echo "------------------------" echo "クライアントの展開に必要なパラメーター" @@ -3641,7 +3641,7 @@ EOF configure_frpc() { send_stats "FRPクライアントをインストールします" - read -e -p "外部ネットワークドッキングIPを入力してください:" server_addr + read -e -p "外部ネットワークのドッキング IP を入力してください:" server_addr read -e -p "外部ネットワーク ドッキング トークンを入力してください:" token echo @@ -3662,17 +3662,17 @@ EOF } add_forwarding_service() { - send_stats "FRPイントラネットサービスを追加します" + send_stats "FRPイントラネットサービスを追加" # ユーザーにサービス名と転送情報を入力するように促します read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ(TCP/UDP)を入力してください[デフォルトTCPを入力]:" service_type + read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネットIPを入力してください[デフォルト127.0.0.1を入力]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "イントラネットポートを入力してください:" local_port + read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port - # ユーザー入力を構成ファイルに書き込みます + # ユーザー入力を構成ファイルに書き込む cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3682,8 +3682,8 @@ remote_port = ${remote_port} EOF - # 出力生成情報 - echo "仕える$service_nameFRPC.TOMLに正常に追加されました" + # 生成された情報を出力する + echo "仕える$service_namefrpc.toml に正常に追加されました" docker restart frpc @@ -3696,7 +3696,7 @@ EOF delete_forwarding_service() { send_stats "FRPイントラネットサービスを削除します" # ユーザーに削除する必要があるサービス名を入力するように促します - read -e -p "削除する必要があるサービス名を入力してください:" service_name + read -e -p "削除するサービス名を入力してください:" service_name # SEDを使用して、サービスとその関連構成を削除します sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "仕える$service_nameFRPC.TOMLから削除されました" @@ -3730,7 +3730,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # サービス情報がある場合は、新しいサービスを処理する前に現在のサービスを印刷します + # サービス情報がすでに存在する場合は、新しいサービスを処理する前に現在のサービスを出力します。 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3785,17 +3785,17 @@ list_forwarding_services() { -# FRPサーバーポートを取得します +# FRPサーバーポートの取得 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# アクセスアドレスを生成します +# アクセスアドレスの生成 generate_access_urls() { # 最初にすべてのポートを取得します get_frp_ports - # 8055/8056以外のポートがあるかどうかを確認してください + # 8055/8056以外のポートがあるか確認する local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3808,14 +3808,14 @@ generate_access_urls() { if [ "$has_valid_ports" = true ]; then echo "FRPサービス外部アクセスアドレス:" - # IPv4アドレスを処理します + # IPv4 アドレスの処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # IPv6 アドレスが存在する場合は処理します + # IPv6アドレスを処理する(存在する場合) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3860,9 +3860,9 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRPサーバー$check_frp $update_status" - echo "FRPイントラネット侵入サービス環境を構築して、パブリックIPなしでインターネットにデバイスを公開する" + echo "FRPイントラネットペネトレーションサービス環境を構築し、パブリックIPを持たないデバイスをインターネットに公開" echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo "ビデオチュートリアル: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports @@ -3871,9 +3871,9 @@ frps_panel() { echo "------------------------" echo "1。インストール2。更新3。アンインストール" echo "------------------------" - echo "5。イントラネットサービスのドメイン名アクセス6。ドメイン名アクセスを削除する" + echo "5. イントラネット サービスのドメイン名アクセス 6. ドメイン名アクセスの削除" echo "------------------------" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" echo "------------------------" echo "00. サービスステータスを更新します。 0. 前のメニューに戻ります。" echo "------------------------" @@ -3906,30 +3906,30 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" ;; 5) - echo "ドメイン名アクセスへの逆イントラネット侵入サービス" + echo "ドメイン名アクセスへのイントラネット侵入サービスのリバース" send_stats "FRP外部ドメイン名へのアクセス" add_yuming - read -e -p "イントラネット侵入サービス ポートを入力してください:" frps_port + read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "ドメイン名の形式 example.com (https:// なし)" web_del ;; 7) - send_stats "IPアクセスを許可する" + send_stats "IPアクセスを許可します" read -e -p "リリースするポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) send_stats "IPアクセスをブロックします" - echo "アンチジェネレーションドメイン名にアクセスした場合は、この関数を使用して、より安全なIP+ポートアクセスをブロックします。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックする必要があるポートを入力してください。" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -3958,7 +3958,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRPクライアント$check_frp $update_status" - echo "サーバーでドッキングした後、ドッキングした後、インターネットへのアクセスにイントラネット侵入サービスを作成できます" + echo "サーバーに接続します。接続後、インターネットにアクセスするためのイントラネット侵入サービスを作成できます。" echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" echo "------------------------" @@ -3968,13 +3968,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) install jq grep ss @@ -4049,26 +4049,26 @@ yt_menu_pro() { fi clear - send_stats "YT-DLPダウンロードツール" + send_stats "yt-dlp ダウンロードツール" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLPは、YouTube、Bilibili、Twitterなどを含む何千ものサイトをサポートする強力なビデオダウンロードツールです。" - echo -e "公式ウェブサイトの住所:https://github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp は、YouTube、Bilibili、Twitter などの何千ものサイトをサポートする強力な動画ダウンロード ツールです。" + echo -e "公式サイトアドレス:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードしたビデオのリスト:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" + echo "ダウンロードされたビデオリスト:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" echo "1。インストール2。更新3。アンインストール" echo "-------------------------" - echo "5。シングルビデオダウンロード6。バッチビデオダウンロード7。カスタムパラメーターダウンロード" - echo "8。mp3オーディオ9としてダウンロードします。ビデオディレクトリ10を削除します。クッキー管理(開発中)" + echo "5. 単一ビデオのダウンロード 6. バッチビデオのダウンロード 7. カスタムパラメータのダウンロード" + echo "8. MP3 オーディオとしてダウンロード 9. ビデオ ディレクトリを削除 10. Cookie 管理 (開発中)" echo "-------------------------" - echo "0. 前のメニューに戻る" + echo "0。前のメニューに戻ります" echo "-------------------------" read -e -p "オプション番号を入力してください:" choice case $choice in 1) - send_stats "YT-DLPのインストール..." + send_stats "yt-dlp をインストールしています..." echo "YT-DLPのインストール..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp @@ -4086,15 +4086,15 @@ yt_menu_pro() { echo "更新が完了しました。任意のキーを押して続行します..." read ;; 3) - send_stats "yt-dlpのアンインストール..." - echo "yt-dlpのアンインストール..." + send_stats "yt-dlp をアンインストールしています..." + echo "yt-dlp をアンインストールしています..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。続行するには任意のキーを押してください..." + echo "アンインストールが完了しました。任意のキーを押して続行します..." read ;; 5) - send_stats "単一のビデオダウンロード" + send_stats "単一のビデオのダウンロード" read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ @@ -4104,13 +4104,13 @@ yt_menu_pro() { --no-overwrites --no-post-overwrites "$url" read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; 6) - send_stats "バッチビデオのダウンロード" + send_stats "ビデオのバッチダウンロード" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "#複数のビデオリンクアドレスを入力\ n#https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.Episode.0" > "$URL_FILE" + echo -e "# 複数のビデオ リンク アドレスを入力します\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "バッチダウンロードを開始します..." + echo "今すぐバッチダウンロードを開始してください..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4118,7 +4118,7 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "バッチのダウンロードが完了し、任意のキーを押して続行します..." ;; + read -e -p "バッチダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 7) send_stats "カスタムビデオのダウンロード" read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom @@ -4128,7 +4128,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "実行が完了したら、キーを押して続行します..." ;; + read -e -p "実行が完了しました。続行するには任意のキーを押してください..." ;; 8) send_stats "MP3ダウンロード" read -e -p "ビデオリンクを入力してください:" url @@ -4138,11 +4138,11 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "オーディオのダウンロードが完了しました、任意のキーを押して続行します..." ;; + read -e -p "音声のダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 9) send_stats "ビデオを削除します" - read -e -p "削除ビデオの名前を入力してください:" rmdir + read -e -p "削除されたビデオの名前を入力してください:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4178,7 +4178,7 @@ set_timedate() { -# DPKG割り込みの問題を修正します +# dpkgの中断問題を修正 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4206,7 +4206,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "不明なパッケージマネージャー!" + echo "不明なパッケージマネージャーです!" return fi } @@ -4214,7 +4214,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}システムのクリーンアップ...${gl_bai}" + echo -e "${gl_huang}システムクリーニング中...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4243,7 +4243,7 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "パッケージマネージャーのキャッシュをクリーンアップ..." apk cache clean echo "システムログを削除してください..." rm -rf /var/log/* @@ -4267,15 +4267,15 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "システムログを削除してください..." + echo "システムログを削除します..." rm -rf /var/log/* echo "一時ファイルを削除します..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "未使用の依存関係をクリーンアップ..." + echo "未使用の依存関係をクリーンアップします..." pkg autoremove -y - echo "パッケージマネージャーのキャッシュを掃除します..." + echo "パッケージマネージャーのキャッシュをクリーンアップ..." pkg clean -y echo "システムログを削除してください..." rm -rf /var/log/* @@ -4283,7 +4283,7 @@ linux_clean() { rm -rf /tmp/* else - echo "不明なパッケージマネージャー!" + echo "不明なパッケージマネージャーです!" return fi return @@ -4342,11 +4342,11 @@ while true; do echo "2。国内のDNS最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3。DNS構成を手動で編集します" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "選択肢を入力してください:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4369,7 +4369,7 @@ while true; do chattr -i /etc/resolv.conf nano /etc/resolv.conf chattr +i /etc/resolv.conf - send_stats "DNS構成を手動で編集します" + send_stats "DNS 構成を手動で編集する" ;; *) break @@ -4392,13 +4392,13 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # PasswordAuthenticationが見つかった場合は、はいに設定します + # 見つかった場合は、PasswordAuthentication が Yes に設定されます if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 発見された場合、pubkeyauthenticationはyesに設定されています + # 見つかった場合、PubkeyAuthentication は Yes に設定されます if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4406,7 +4406,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthenticationもPubKeyAuthenticationが一致しない場合は、デフォルト値を設定します + # PasswordAuthentication も PubkeyAuthentication も一致しない場合にデフォルト値を設定します if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4430,7 +4430,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSHポートは次のように変更されています。$new_port" + echo "SSH ポートは次のように変更されました。$new_port" sleep 1 @@ -4448,7 +4448,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}将来のSSHログイン用のファイル" + echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4470,7 +4470,7 @@ import_sshkey() { read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}エラー:公開キーのコンテンツは入力されませんでした。${gl_bai}" + echo -e "${gl_hong}エラー: 公開キーの内容が入力されていません。${gl_bai}" return 1 fi @@ -4488,7 +4488,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}公開キーが正常にインポートされ、ルート秘密キーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}公開キーは正常にインポートされ、ROOT 秘密キーのログインが有効になり、ROOT パスワードのログインが閉じられました。再接続が有効になります。${gl_bai}" } @@ -4503,14 +4503,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ルートログインがセットアップされます!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能には、ルートユーザーを実行する必要があります!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion } @@ -4527,16 +4527,16 @@ dd_xitong() { } dd_xitong_1() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}初期パスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}初期パスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau @@ -4551,14 +4551,14 @@ dd_xitong() { dd_xitong_4() { echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "続行するには任意のキーを押してください..." + echo -e "任意のキーを押して続行します..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "システムを再インストールします" + echo "システムを再インストールする" echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " @@ -4584,14 +4584,14 @@ dd_xitong() { echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in 1) - send_stats "Debian 13を再インストールします" + send_stats "debian13を再インストールする" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4599,21 +4599,21 @@ dd_xitong() { ;; 2) - send_stats "Debian 12を再インストールします" + send_stats "debian12を再インストールする" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "Debian 11を再インストールします" + send_stats "debian11を再インストールする" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "Debian 10を再インストールします" + send_stats "debian10を再インストールする" dd_xitong_1 bash InstallNET.sh -debian 10 reboot @@ -4627,21 +4627,21 @@ dd_xitong() { exit ;; 12) - send_stats "Ubuntu 22.04を再インストールします" + send_stats "ubuntu 22.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "Ubuntu 20.04を再インストールします" + send_stats "ubuntu 20.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "Ubuntu 18.04を再インストールします" + send_stats "ubuntu 18.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4650,7 +4650,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10を再インストールします" + send_stats "Rockylinux10を再インストールする" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4658,7 +4658,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9を再インストールします" + send_stats "Rockylinux9 を再インストールする" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4674,7 +4674,7 @@ dd_xitong() { ;; 24) - send_stats "alma9を再インストールします" + send_stats "alma9を再インストールする" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4682,7 +4682,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10を再インストールします" + send_stats "oracle10を再インストールする" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4690,7 +4690,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9を再インストールします" + send_stats "oracle9を再インストールする" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4698,7 +4698,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42を再インストールします" + send_stats "fedora42を再インストールする" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4706,7 +4706,7 @@ dd_xitong() { ;; 28) - send_stats "Fedora41を再インストールします" + send_stats "fedora41を再インストールする" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -4730,7 +4730,7 @@ dd_xitong() { ;; 31) - send_stats "アルパインを再インストールします" + send_stats "アルパインを再インストールする" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4762,7 +4762,7 @@ dd_xitong() { ;; 35) - send_stats "OpenSuseを再インストールします" + send_stats "opensuse を再インストールする" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4770,7 +4770,7 @@ dd_xitong() { ;; 36) - send_stats "飛ぶ牛をリロードします" + send_stats "Feiniu を再インストールする" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4778,7 +4778,7 @@ dd_xitong() { ;; 41) - send_stats "Windows11を再インストールします" + send_stats "Windows 11を再インストールする" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4787,14 +4787,14 @@ dd_xitong() { 42) dd_xitong_2 - send_stats "Windows 10を再インストールします" + send_stats "Windows 10を再インストールする" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows 7を再インストールします" + send_stats "Windows7を再インストールする" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4818,7 +4818,7 @@ dd_xitong() { ;; 46) - send_stats "Windows Server 19を再インストールします" + send_stats "Windowsサーバー19を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot @@ -4862,7 +4862,7 @@ bbrv3() { echo "" echo "カーネル管理" echo "------------------------" - echo "1。BBRV3カーネルを更新する2。BBRV3カーネルをアンインストールします" + echo "1。BBRV3カーネルを更新します2。BBRV3カーネルをアンインストールします" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4876,7 +4876,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # ステップ 3: リポジトリを追加する echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4885,7 +4885,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmodカーネルが更新されました。再起動後に有効になります" + echo "XanMod カーネルが更新されました。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4895,7 +4895,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" + echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" server_reboot ;; @@ -4908,13 +4908,13 @@ bbrv3() { else clear - echo "BBR3加速度をセットアップします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv14k421x7bs?t=0.1" + echo "BBR3アクセラレーションの設定" + echo "ビデオ紹介: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "Debian/Ubuntuのみをサポートします" - echo "データをバックアップしてください。Linuxカーネルをアップグレードできるようになります。" + echo "データをバックアップしてください。Linux カーネルをアップグレードして BBR3 を有効にします。" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) @@ -4922,12 +4922,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境はそれをサポートせず、DebianとUbuntuシステムのみをサポートしています" + echo "現在の環境では対応しておりません。 Debian および Ubuntu システムのみがサポートされています。" break_end linux_Settings fi else - echo "オペレーティングシステムの種類を決定できません" + echo "オペレーティング システムの種類を特定できません" break_end linux_Settings fi @@ -4938,7 +4938,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # ステップ3:リポジトリを追加します + # ステップ 3: リポジトリを追加する echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4968,7 +4968,7 @@ bbrv3() { elrepo_install() { - # Elrepo GPG公開キーをインポートします + # ELRepo GPG 公開キーをインポートする echo "Elrepo GPG公開キーをインポートしてください..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org # システムバージョンを検出します @@ -4976,13 +4976,13 @@ elrepo_install() { local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) # サポートされているオペレーティングシステムで実行されていることを確認してください if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "サポートされていないオペレーティングシステム:$os_name" + echo "サポートされていないオペレーティング システム:$os_name" break_end linux_Settings fi # 検出されたオペレーティングシステム情報を印刷します echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムのバージョンに応じて、対応する ELRepo ウェアハウス構成をインストールします。 + # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする if [[ "$os_version" == 8 ]]; then echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm @@ -4997,8 +4997,8 @@ elrepo_install() { break_end linux_Settings fi - # Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールします - echo "Elrepoカーネルリポジトリを有効にし、最新のメインラインカーネルをインストールしてください..." + # ELRepo カーネル リポジトリを有効にし、最新のメインライン カーネルをインストールします。 + echo "ELRepo カーネル リポジトリを有効にし、最新のメインライン カーネルをインストールします..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" @@ -5015,14 +5015,14 @@ elrepo() { clear kernel_version=$(uname -r) echo "Elrepo Kernelをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" echo "------------------------" - echo "1. Elrepo Kernel 2を更新します。ElrepoKernelをアンインストールします" + echo "1. elrepo カーネルを更新します。 2. elrepo カーネルをアンインストールします。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" sub_choice @@ -5052,19 +5052,19 @@ elrepo() { else clear - echo "データをバックアップしてください、そしてあなたのためにLinuxカーネルをアップグレードします" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "データをバックアップしてください。Linux カーネルをアップグレードします。" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hatカーネルをアップグレードします" + send_stats "Red Hat カーネルをアップグレードする" server_reboot ;; [Nn]) @@ -5082,7 +5082,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}ウイルスデータベースを更新してください...${gl_bai}" + echo -e "${gl_huang}ウイルスデータベースを更新しています...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5098,7 +5098,7 @@ clamav_scan() { echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" - # マウントパラメーターを構築します + # ビルドマウントパラメータ local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " @@ -5113,7 +5113,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Dockerコマンドを実行します + # Dockerコマンドを実行する docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5123,7 +5123,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイルで見つかったキーワードを検索して、ウイルスの場所を確認する${gl_bai}" + echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイル内で FOUND キーワードを検索して、ウイルスの場所を確認します。${gl_bai}" } @@ -5138,17 +5138,17 @@ clamav() { send_stats "ウイルススキャン管理" while true; do clear - echo "クラマブウイルススキャンツール" - echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "Clamav ウイルス スキャン ツール" + echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" echo "------------------------" - echo "これは、主にさまざまな種類のマルウェアを検出および除去するために使用されるオープンソースのウイルス対策ソフトウェアツールです。" - echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアを含む。" + echo "これは、主にさまざまな種類のマルウェアを検出して削除するために使用されるオープンソースのウイルス対策ソフトウェア ツールです。" + echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアが含まれます。" echo "------------------------" echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3. カスタムディレクトリスキャン${gl_bai}" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) send_stats "フルディスクスキャン" @@ -5169,7 +5169,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スペースで区切られたスキャンにディレクトリを入力してください(例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5219,7 +5219,7 @@ optimize_high_performance() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + # 透明な巨大ページを無効にして遅延を軽減する echo never > /sys/kernel/mm/transparent_hugepage/enabled # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5227,7 +5227,7 @@ optimize_high_performance() { } -# バランスモード最適化機能 +# イコライゼーションモード最適化関数 optimize_balanced() { echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" @@ -5300,7 +5300,7 @@ restore_defaults() { echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}他の最適化を復元します...${gl_bai}" + echo -e "${gl_lv}他の最適化を元に戻します...${gl_bai}" # 透明な巨大ページを復元する echo always > /sys/kernel/mm/transparent_hugepage/enabled # numaバランスを復元します @@ -5310,9 +5310,9 @@ restore_defaults() { -# ウェブサイトの構築最適化機能 +# Webサイト構築最適化機能 optimize_web_server() { - echo -e "${gl_lv}ウェブサイトの構築最適化モードに切り替えます...${gl_bai}" + echo -e "${gl_lv}ウェブサイト構築最適化モードに切り替えます...${gl_bai}" echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 @@ -5343,7 +5343,7 @@ optimize_web_server() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}その他の最適化...${gl_bai}" - # レイテンシを減らすために、大きな透明なページを無効にします + # 透明な巨大ページを無効にして遅延を軽減する echo never > /sys/kernel/mm/transparent_hugepage/enabled # numaバランスを無効にします sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5358,17 +5358,17 @@ Kernel_optimize() { clear send_stats "Linuxカーネルチューニング管理" echo "Linuxシステムにおけるカーネルパラメーターの最適化" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1kb421j7yg?t=0.1" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "さまざまなシステムパラメーターチューニングモードが提供され、ユーザーは独自の使用シナリオに従って選択および切り替えることができます。" - echo -e "${gl_huang}ヒント:${gl_bai}生産環境では注意して使用してください!" + echo "さまざまなシステムパラメータチューニングモードを提供し、ユーザーは独自の使用シナリオに応じて切り替えることができます。" + echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" - echo "1.高性能最適化モード:システムパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU設定を最適化します。" + echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" - echo "3.ウェブサイトの最適化モード:Webサイトサーバーを最適化して、接続処理機能、応答速度、全体的なパフォーマンスを並行します。" - echo "4。ライブブロードキャスト最適化モード:ライブブロードキャストストリーミングの特別なニーズを最適化して、遅延を減らし、伝送パフォーマンスを向上させます。" + echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" + echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" - echo "6.デフォルト設定を復元します:システム設定をデフォルトの構成に復元します。" + echo "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo "--------------------" echo "0。前のメニューに戻ります" echo "--------------------" @@ -5411,7 +5411,7 @@ Kernel_optimize() { cd ~ clear restore_defaults - send_stats "デフォルト設定を復元します" + send_stats "デフォルト設定を復元する" ;; *) break @@ -5447,7 +5447,7 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されました。$langSSHの再接続が有効になります。${gl_bai}" hash -r break_end ;; @@ -5457,7 +5457,7 @@ update_locale() { ;; esac else - echo "サポートされていないシステム、システムタイプは認識できません。" + echo "サポートされていないシステムです。システムの種類を識別できません。" break_end fi } @@ -5472,24 +5472,24 @@ while true; do clear echo "現在のシステム言語:$LANG" echo "------------------------" - echo "1。英語2。簡素化された中国語3。伝統的な中国語" + echo "1. 英語 2. 簡体字中国語 3. 繁体字中国語" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えます" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "簡素化された中国人に切り替えます" + send_stats "簡体字中国語に切り替える" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "伝統的な中国人に切り替えます" + send_stats "繁体字中国語に切り替える" ;; *) break @@ -5525,7 +5525,7 @@ shell_bianse() { send_stats "コマンドラインの美化ツール" while true; do clear - echo "コマンドラインの美化ツール" + echo "コマンドライン美化ツール" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5582,7 +5582,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムのごみ箱" + send_stats "システムリサイクルステーション" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5598,16 +5598,16 @@ linux_trash() { clear echo -e "現在のリサイクルビン${trash_status}" - echo -e "有効になった後、RMによって削除されたファイルは、最初にリサイクルビンに入り、重要なファイルの誤った削除を防ぎます!" + echo -e "有効にすると、重要なファイルを誤って削除することを防ぐために、rm によって削除されたファイルは最初にごみ箱に入れられます。" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" echo "------------------------" - echo "1. ごみ箱を有効にする 2. ごみ箱を閉じる" + echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" echo "3。コンテンツを復元4。リサイクルビンをクリアします" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -5632,7 +5632,7 @@ linux_trash() { mv "$TRASH_DIR/$file_to_restore" "$HOME/" echo "$file_to_restoreホームディレクトリに復元されました。" else - echo "ファイルは存在しません。" + echo "ファイルが存在しません。" fi ;; 4) @@ -5656,11 +5656,11 @@ bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/ # バックアップを作成します create_backup() { - send_stats "バックアップを作成します" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # ユーザーにバックアップディレクトリを入力するように求めます - echo "バックアップ例を作成します:" + # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する + echo "バックアップの作成例:" echo "- 単一のディレクトリをバックアップします: /var /www" echo "- バックアップ複数のディレクトリ: /etc /home /var /log" echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" @@ -5674,11 +5674,11 @@ create_backup() { "/home" # 用户数据 ) else - # ユーザーが入力したディレクトリをスペースごとに配列に分離します + # ユーザーが配列に入力したディレクトリをスペースで区切ります。 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # バックアップファイルプレフィックスを生成します + # バックアップ ファイルのプレフィックスを生成する local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do # ディレクトリ名を抽出し、スラッシュを削除します @@ -5689,77 +5689,77 @@ create_backup() { # 最後のアンダースコアを削除します local PREFIX=${PREFIX%_} - # バックアップファイル名を生成します + # バックアップファイル名の生成 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" # ユーザーが選択したディレクトリを印刷します - echo "選択したバックアップディレクトリは次のとおりです。" + echo "選択したバックアップ ディレクトリは次のとおりです。" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done # バックアップの作成 - echo "バックアップを作成します$BACKUP_NAME..." + echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # コマンドが成功しているかどうかを確認してください + # コマンドが成功したかどうかを確認する if [ $? -eq 0 ]; then - echo "バックアップは正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" + echo "バックアップが正常に作成されました:$BACKUP_DIR/$BACKUP_NAME" else - echo "バックアップの作成に失敗しました!" + echo "バックアップの作成に失敗しました!" exit 1 fi } -# バックアップを復元します +# バックアップを復元する restore_backup() { - send_stats "バックアップを復元します" + send_stats "バックアップを復元する" # 復元するバックアップを選択します read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME - # バックアップファイルが存在するか確認する + # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then echo "バックアップファイルは存在しません!" exit 1 fi - echo "バックアップの復元$BACKUP_NAME..." + echo "バックアップの回復$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then echo "バックアップと復元を正常に!" else - echo "バックアップリカバリに失敗しました!" + echo "バックアップリカバリが失敗しました!" exit 1 fi } # バックアップをリストします list_backups() { - echo "利用可能なバックアップ:" + echo "利用可能なバックアップ:" ls -1 "$BACKUP_DIR" } -# バックアップを削除します +# バックアップの削除 delete_backup() { - send_stats "バックアップを削除します" + send_stats "バックアップの削除" - read -e -p "削除するバックアップ ファイル名を入力してください:" BACKUP_NAME + read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME # バックアップファイルが存在するかどうかを確認します if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "バックアップファイルが存在しません!" exit 1 fi - # バックアップを削除します + # バックアップの削除 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then echo "バックアップは正常に削除されました!" else - echo "バックアップの削除が失敗しました!" + echo "バックアップの削除に失敗しました!" exit 1 fi } @@ -5775,7 +5775,7 @@ linux_backup() { echo "------------------------" list_backups echo "------------------------" - echo "1.バックアップを作成する2。バックアップを復元3。バックアップを削除します" + echo "1. バックアップの作成 2. バックアップの復元 3. バックアップの削除" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -5798,9 +5798,9 @@ linux_backup() { -# 接続リストを表示します +# 接続リストを表示 list_connections() { - echo "接続の保存:" + echo "保存された接続:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" @@ -5809,23 +5809,23 @@ list_connections() { # 新しい接続を追加します add_connection() { - send_stats "新しい接続を追加します" - echo "新しい接続を作成する例:" - echo "- 接続名:my_server" - echo "- IPアドレス:192.168.1.100" + send_stats "新しい接続を追加" + echo "新しい接続を作成する例:" + echo "- 接続名: my_server" + echo "- IP アドレス: 192.168.1.100" echo "- ユーザー名:root" echo "- ポート:22" echo "------------------------" - read -e -p "接続名を入力してください:" name + read -e -p "接続名を入力してください:" name read -e -p "IPアドレスを入力してください:" ip read -e -p "ユーザー名(デフォルト:root)を入力してください:" user local user=${user:-root} # 如果用户未输入,则使用默认值 root read -e -p "ポート番号を入力してください(デフォルト:22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "認証方法を選択してください:" - echo "1。パスワード" - echo "2。キー" + echo "認証方法を選択してください:" + echo "1. パスワード" + echo "2. キー" read -e -p "選択(1/2)を入力してください:" auth_choice case $auth_choice in @@ -5834,7 +5834,7 @@ add_connection() { echo # 换行 ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "キーの内容を貼り付けてください (貼り付け後に Enter を 2 回押します)。" local password_or_key="" while IFS= read -r line; do # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します @@ -5856,13 +5856,13 @@ add_connection() { fi ;; *) - echo "無効な選択!" + echo "無効な選択です!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "接続が保存されます!" + echo "接続が保存されました!" } @@ -5874,7 +5874,7 @@ delete_connection() { local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続​​は見つかりませんでした。" + echo "エラー: 対応する接続​​が見つかりません。" return fi @@ -5889,10 +5889,10 @@ delete_connection() { echo "接続が削除されました!" } -# 接続を使用します +# 接続を使用する use_connection() { send_stats "接続を使用します" - read -e -p "使用するには、接続番号を入力してください。" num + read -e -p "使用する接続番号を入力してください:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -5902,31 +5902,31 @@ use_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "接続$name ($ip)..." + echo "接続先$name ($ip)..." if [[ -f "$password_or_key" ]]; then # キーに接続します ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "接続に失敗しました!以下を確認してください。" echo "1。キーファイルパスは正しいですか?$password_or_key" - echo "2。キーファイルの権限が正しいかどうか(600である必要があります)。" - echo "3.ターゲットサーバーがキーを使用してログインできるかどうか。" + echo "2. キー ファイルのアクセス許可は正しいか (600 である必要があります)。" + echo "3. ターゲットサーバーがキーを使用したログインを許可するかどうか。" fi else - # パスワードで接続します + # パスワードを使用して接続する if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "エラー: sshpass がインストールされていません。最初に sshpass をインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1.ユーザー名とパスワードが正しいかどうか。" + echo "接続に失敗しました!以下の点をご確認ください。" + echo "1. ユーザー名とパスワードは正しいですか?" echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" - echo "3.ターゲットサーバーのSSHサービスが正常に実行されているかどうか。" + echo "3. 対象サーバのSSHサービスが正常に動作しているか。" fi fi } @@ -5938,7 +5938,7 @@ ssh_manager() { CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 構成ファイルとキーディレクトリが存在するかどうかを確認し、それが存在しない場合は、それを作成します + # 設定ファイルとキーディレクトリが存在するかどうかを確認し、存在しない場合は作成します。 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5954,9 +5954,9 @@ ssh_manager() { echo "SSHを介して他のLinuxシステムに接続できます" echo "------------------------" list_connections - echo "1.新しい接続を作成する2。接続を使用する3。接続を削除します" + echo "1. 新しい接続を作成します。 2. 接続を使用します。 3. 接続を削除します。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" choice case $choice in @@ -5964,7 +5964,7 @@ ssh_manager() { 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "選択が無効です。もう一度お試しください。" ;; esac done } @@ -5980,7 +5980,7 @@ ssh_manager() { -# 利用可能なハードディスクパーティションをリストします +# 利用可能なハードディスクのパーティションをリストする list_partitions() { echo "利用可能なハードドライブのパーティション:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" @@ -5988,22 +5988,22 @@ list_partitions() { # パーティションをマウントします mount_partition() { - send_stats "パーティションをマウントする" - read -e -p "マウントするパーティション名を入力してください(たとえば、SDA1):" PARTITION + send_stats "パーティションをマウントします" + read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION - # パーティションが存在するかどうかを確認します + # パーティションが存在するかどうかを確認する if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "パーティションは存在しません!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # パーティションがマウントされているかどうかを確認する if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションはすでに取り付けられています!" + echo "パーティションが取り付けられました!" return fi - # マウントポイントを作成します + # マウントポイントの作成 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" @@ -6023,7 +6023,7 @@ unmount_partition() { send_stats "パーティションをアンインストールします" read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION - # パーティションが既にマウントされているかどうかを確認してください + # パーティションがマウントされているかどうかを確認する MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then echo "パーティションはマウントされていません!" @@ -6050,11 +6050,11 @@ list_mounted_partitions() { # フォーマットパーティション format_partition() { send_stats "フォーマットパーティション" - read -e -p "パーティション名を入力してフォーマット(たとえば、SDA1):" PARTITION + read -e -p "フォーマットするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認します if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "パーティションが存在しません!" return fi @@ -6064,13 +6064,13 @@ format_partition() { return fi - # ファイルシステムタイプを選択します - echo "ファイル システムのタイプを選択してください:" + # ファイルシステムの種類を選択してください + echo "ファイルシステムタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "選択を入力してください:" FS_CHOICE + read -e -p "選択肢を入力してください:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; @@ -6080,37 +6080,37 @@ format_partition() { *) echo "無効な選択!"; return ;; esac - # フォーマットを確認します - read -e -p "フォーマットパーティション /dev /$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM + # フォーマットの確認 + read -e -p "フォーマットされたパーティション /dev/ を確認します$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作はキャンセルされました。" return fi - # フォーマットパーティション + # パーティションをフォーマットする echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then echo "パーティション形式は成功しました!" else - echo "パーティションのフォーマットが失敗しました!" + echo "パーティションのフォーマットに失敗しました!" fi } -# パーティションステータスを確認します +# パーティションのステータスを確認する check_partition() { - send_stats "パーティションステータスを確認します" - read -e -p "パーティション名を入力して確認してください(たとえばSDA1):" PARTITION + send_stats "パーティションのステータスを確認する" + read -e -p "確認するパーティション名を入力してください (例: sda1):" PARTITION - # パーティションが存在するかどうかを確認します + # パーティションが存在するかどうかを確認する if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "パーティションは存在しません!" return fi # パーティションステータスを確認します - echo "パーティション /dev /$PARTITION状態:" + echo "パーティション /dev/ を確認してください$PARTITION状態:" fsck "/dev/$PARTITION" } @@ -6124,12 +6124,12 @@ disk_manager() { echo "------------------------" list_partitions echo "------------------------" - echo "1。パーティションをマウント2。パーティションをアンインストールする3。マウントされたパーティションを表示" - echo "4。パーティション5をフォーマットします。パーティションステータスを確認します" + echo "1. パーティションをマウントします。 2. パーティションをアンマウントします。 3. マウントされたパーティションを表示します。" + echo "4. パーティションをフォーマットします。 5. パーティションのステータスを確認します。" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -6145,7 +6145,7 @@ disk_manager() { -# タスクリストを表示します +# タスクリストを表示 list_tasks() { echo "保存された同期タスク:" echo "---------------------------------" @@ -6155,24 +6155,24 @@ list_tasks() { # 新しいタスクを追加します add_task() { - send_stats "新しい同期タスクを追加します" - echo "新しい同期タスクを作成する例:" - echo "- タスク名:backup_www" + send_stats "新しい同期タスクを追加する" + echo "新しい同期タスクの作成例:" + echo "- タスク名:backup_www" echo "- ローカルディレクトリ: /var /www" echo "- リモートアドレス:user@192.168.1.100" - echo "- リモートディレクトリ: /バックアップ /www" + echo "- リモートディレクトリ: /backup/www" echo "- ポート番号 (デフォルトは 22)" echo "---------------------------------" - read -e -p "タスク名を入力してください:" name - read -e -p "ローカルディレクトリを入力してください:" local_path - read -e -p "リモートディレクトリを入力してください:" remote_path + read -e -p "タスク名を入力してください:" name + read -e -p "ローカル ディレクトリを入力してください:" local_path + read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモートユーザー@IPを入力してください:" remote - read -e -p "SSHポートを入力してください(デフォルト22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" echo "1。パスワード" - echo "2。キー" + echo "2. キー" read -e -p "(1/2)を選択してください:" auth_choice case $auth_choice in @@ -6195,7 +6195,7 @@ add_task() { fi done - # キーコンテンツのかどうかを確認してください + # キーコンテンツかどうかを確認する if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6203,20 +6203,20 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "無効なキーコンテンツ!" + echo "キーの内容が無効です!" return fi ;; *) - echo "無効な選択!" + echo "無効な選択です!" return ;; esac - echo "同期モードを選択してください:" - echo "1。標準モード(-AVZ)" + echo "同期モードを選択してください:" + echo "1. 標準モード (-avz)" echo "2。ターゲットファイル(-avz - delete)を削除します" - read -e -p "(1/2)を選択してください:" mode + read -e -p "(1/2) を選択してください:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; @@ -6230,36 +6230,36 @@ add_task() { echo "ミッションが保存されました!" } -# タスクを削除します +# タスクの削除 delete_task() { - send_stats "同期タスクを削除します" + send_stats "同期タスクの削除" read -e -p "削除するには、タスク番号を入力してください。" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:対応するタスクは見つかりませんでした。" + echo "エラー: 対応するタスクが見つかりませんでした。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # タスクがキーファイルを使用している場合、キーファイルを削除します + # タスクがキー ファイルを使用している場合は、キー ファイルを削除します if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "削除されたタスク!" + echo "タスクが削除されました!" } run_task() { - send_stats "同期タスクを実行します" + send_stats "同期タスクを実行する" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # パラメーターを分析します + # パラメータを解析する local direction="push" # 默认是推送到远端 local num @@ -6270,14 +6270,14 @@ run_task() { num="$1" fi - # 着信タスク番号がない場合は、ユーザーに入力するように促します + # タスク番号が渡されない場合、ユーザーは入力を求められます。 if [[ -z "$num" ]]; then - read -e -p "実行するタスク番号を入力してください:" num + read -e -p "実行するタスク番号を入力してください:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "エラー:タスクは見つかりませんでした!" + echo "エラー: タスクが見つかりませんでした。" return fi @@ -6285,7 +6285,7 @@ run_task() { # 同期の方向に従ってソースとターゲットのパスを調整します if [[ "$direction" == "pull" ]]; then - echo "ローカルへのプルと同期:$remote:$local_path -> $remote_path" + echo "同期をローカルに引く:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -6299,8 +6299,8 @@ run_task() { if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "エラー:SSHPassはインストールされていません。最初にSSHPassをインストールしてください。" - echo "インストール方法:" + echo "エラー: sshpass がインストールされていません。最初に sshpass をインストールしてください。" + echo "インストール方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return @@ -6314,7 +6314,7 @@ run_task() { fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:キーファイルのアクセス許可が正しくなく、修理されています..." + echo "警告:キーファイルの権限が正しくなく、修理されています..." chmod 600 "$password_or_key" fi @@ -6325,10 +6325,10 @@ run_task() { echo "同期は完了です!" else echo "同期は失敗しました!以下を確認してください。" - echo "1。ネットワーク接続は正常ですか?" + echo "1. ネットワーク接続は正常ですか?" echo "2。リモートホストにアクセスできますか?" echo "3。認証情報は正しいですか?" - echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" + echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" fi } @@ -6337,15 +6337,15 @@ run_task() { schedule_task() { send_stats "同期タイミングタスクを追加します" - read -e -p "定期的に同期するには、タスク番号を入力してください。" num + read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then echo "エラー:有効なタスク番号を入力してください!" return fi - echo "時限実行間隔を選択してください:" - echo "1)1時間に1回実行します" - echo "2)1日1回実行します" + echo "スケジュールされた実行間隔を選択してください:" + echo "1) 1時間に1回実行" + echo "2) 1日1回実行" echo "3)週に1回実行します" read -e -p "オプションを入力してください(1/2/3):" interval @@ -6361,18 +6361,18 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 同じタスクが既に存在するかどうかを確認してください + # 同じタスクがすでに存在するかどうかを確認する if crontab -l | grep -q "k rsync_run $num"; then echo "エラー:このタスクのタイミング同期はすでに存在しています!" return fi - # ユーザーにクロンタブを作成します + # ユーザーのcrontabに作成 (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "タイミングタスクが作成されました。$cron_job" + echo "スケジュールされたタスクが作成されました:$cron_job" } -# スケジュールされたタスクを表示します +# スケジュールされたタスクを表示する view_tasks() { echo "現在のタイミングタスク:" echo "---------------------------------" @@ -6382,15 +6382,15 @@ view_tasks() { # タイミングタスクを削除します delete_task_schedule() { - send_stats "同期タイミングタスクを削除します" + send_stats "同期のスケジュールされたタスクを削除する" read -e -p "削除するには、タスク番号を入力してください。" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "エラー: 有効なタスク番号を入力してください。" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numスケジュールされたタスク" + echo "削除されたタスク番号$numタイミングタスク" } @@ -6408,11 +6408,11 @@ rsync_manager() { echo view_tasks echo - echo "1.新しいタスクを作成します2。タスクを削除します" + echo "1. 新しいタスクを作成します。 2. タスクを削除します。" echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6。タイミングタスクを削除します" + echo "5.タイミングタスクを作成6.タイミングタスクを削除します" echo "---------------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "---------------------------------" read -e -p "選択を入力してください:" choice case $choice in @@ -6423,7 +6423,7 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "無効な選択、もう一度やり直してください。" ;; + *) echo "選択が無効です。もう一度お試しください。" ;; esac read -e -p "Enterを押して続行します..." done @@ -6492,22 +6492,22 @@ linux_info() { echo "" echo -e "システム情報クエリ" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" - echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linuxバージョン:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" + echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux バージョン:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPUアーキテクチャ:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU アーキテクチャ:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU頻度:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU周波数:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}システムの負荷:${gl_bai}$load" + echo -e "${gl_kjlan}システム負荷:${gl_bai}$load" echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" - echo -e "${gl_kjlan}ハードディスクの職業:${gl_bai}$disk_info" + echo -e "${gl_kjlan}ハードドライブの使用状況:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}受け取った合計:${gl_bai}$rx" echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" @@ -6520,11 +6520,11 @@ linux_info() { if [ -n "$ipv6_address" ]; then echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNSアドレス:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}DNS アドレス:${gl_bai}$dns_addresses" echo -e "${gl_kjlan}位置:${gl_bai}$country $city" echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ランタイム:${gl_bai}$runtime" + echo -e "${gl_kjlan}実行時間:${gl_bai}$runtime" echo @@ -6540,25 +6540,25 @@ linux_tools() { # send_stats「基本ツール」 echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGETダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo スーパー管理者特権ツール${gl_kjlan}4. ${gl_bai}Socat Communication Connection Tool" - echo -e "${gl_kjlan}5. ${gl_bai}HTOPシステム監視ツール${gl_kjlan}6. ${gl_bai}IFTOPネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}ジップzip圧縮減圧ツールを解凍します${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" + echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}socat通信接続ツール" + echo -e "${gl_kjlan}5. ${gl_bai}htop システム監視ツール${gl_kjlan}6. ${gl_bai}iftop ネットワークトラフィック監視ツール" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP圧縮・解凍ツール${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" - echo -e "${gl_kjlan}13. ${gl_bai}NCDUディスク職業視聴ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" - echo -e "${gl_kjlan}15. ${gl_bai}VIMテキストエディター${gl_kjlan}16. ${gl_bai}ナノテキストエディター${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" + echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}列車のスクリーンのセキュリティ" - echo -e "${gl_kjlan}26. ${gl_bai}テトリスゲーム${gl_kjlan}27. ${gl_bai}ヘビを食べるゲーム" + echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" + echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールします${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールする${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -6571,15 +6571,15 @@ linux_tools() { clear echo "ツールがインストールされており、使用方法は次のとおりです。" curl --help - send_stats "カールをインストールします" + send_stats "カールをインストールする" ;; 2) clear install wget clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" wget --help - send_stats "WGETをインストールします" + send_stats "wgetをインストールする" ;; 3) clear @@ -6593,16 +6593,16 @@ linux_tools() { clear install socat clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" socat -h - send_stats "SOCATをインストールします" + send_stats "socatをインストールする" ;; 5) clear install htop clear htop - send_stats "HTOPをインストールします" + send_stats "htopをインストールする" ;; 6) clear @@ -6615,9 +6615,9 @@ linux_tools() { clear install unzip clear - echo "ツールはインストールされており、次のように使用されます。" + echo "ツールがインストールされており、使用方法は次のとおりです。" unzip - send_stats "unzipをインストールします" + send_stats "Unzipをインストールします" ;; 8) clear @@ -6625,23 +6625,23 @@ linux_tools() { clear echo "ツールがインストールされており、使用方法は次のとおりです。" tar --help - send_stats "タールをインストールします" + send_stats "tarをインストールする" ;; 9) clear install tmux clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" tmux --help - send_stats "tmuxをインストールします" + send_stats "tmuxをインストールする" ;; 10) clear install ffmpeg clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" ffmpeg --help - send_stats "ffmpegをインストールします" + send_stats "FFMPEGをインストールします" ;; 11) @@ -6649,7 +6649,7 @@ linux_tools() { install btop clear btop - send_stats "BTOPをインストールします" + send_stats "btopをインストールする" ;; 12) clear @@ -6676,7 +6676,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZFをインストールします" + send_stats "fzfをインストールする" ;; 15) clear @@ -6720,14 +6720,14 @@ linux_tools() { install sl clear sl - send_stats "SLをインストールします" + send_stats "SLをインストールする" ;; 26) clear install bastet clear bastet - send_stats "バステットをインストールします" + send_stats "バステトをインストールする" ;; 27) clear @@ -6741,7 +6741,7 @@ linux_tools() { install ninvaders clear ninvaders - send_stats "Ninvadersをインストールします" + send_stats "ニンベーダーをインストールする" ;; 31) @@ -6759,13 +6759,13 @@ linux_tools() { 33) clear - send_stats "すべてをアンインストールします" + send_stats "すべてアンインストールする" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 41) clear - read -e -p "インストールされているツール名(Wget Curl Sudo htop)を入力してください。" installname + read -e -p "インストールされているツール名 (wgetcurlsudohtop) を入力してください:" installname install $installname send_stats "指定されたソフトウェアをインストールします" ;; @@ -6781,7 +6781,7 @@ linux_tools() { ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -6806,16 +6806,16 @@ linux_bbr() { echo "" echo "BBR管理" echo "------------------------" - echo "1。BBRV3 2をオンにします。BBRV3(再起動)をオフにします" + echo "1. BBRv3 をオンにする 2. BBRv3 をオフにする (再起動します)" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択肢を入力してください:" sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) bbr_on - send_stats "AlpineはBBR3を有効にします" + send_stats "アルパインがBBR3をオープン" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6857,7 +6857,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}現在のバックアップリスト:${NC}" + echo -e "${BLUE}現在のバックアップ リスト:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" } @@ -6884,7 +6884,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナは見つかりません${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナが見つかりません${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6892,7 +6892,7 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "#自動的に生成された復元スクリプト" >> "$RESTORE_SCRIPT" + echo "# 自動生成された復元スクリプト" >> "$RESTORE_SCRIPT" # パッケージ化されたプロジェクトのパスを記録して、パッケージの重複を避ける declare -A PACKED_COMPOSE_PATHS=() @@ -6903,15 +6903,15 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cはい、Docker-Composeコンテナ${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "Compose Directoryは検出されません。手動でパスを入力してください。" project_dir + read -e -p "作成ディレクトリが検出されません。パスを手動で入力してください。" project_dir fi - # Composeプロジェクトがパッケージ化されている場合は、スキップしてください + # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue @@ -6924,16 +6924,16 @@ docker_ssh_migration() { echo "#docker-compose Recovery:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトを作成する[$project_name]パック:${project_dir}${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name]パック:${project_dir}${NC}" else - echo -e "${RED}docker-compose.ymlが見つかりません、このコンテナをスキップしてください...${NC}" + echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" fi else # 通常のコンテナバックアップボリューム local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包ロール:$path" + echo "梱包体積:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6963,14 +6963,14 @@ docker_ssh_migration() { # /home /dockerのすべてのファイルをバックアップします(サブディレクトリを除く) if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home /dockerの下のファイルをバックアップ...${NC}" + echo -e "${BLUE}/home/docker 下のファイルをバックアップします...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home /dockerの下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" - echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" + echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" } @@ -6981,15 +6981,15 @@ docker_ssh_migration() { restore_docker() { send_stats "Dockerの復元" - read -e -p "復元するには、バックアップディレクトリを入力してください。" BACKUP_DIR + read -e -p "復元するバックアップ ディレクトリを入力してください:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - echo -e "${BLUE}復元操作を開始します...${NC}" + echo -e "${BLUE}復元操作を開始しています...${NC}" install tar jq gzip install_docker - # ------------------------------ + # --------- Compose プロジェクトの復元を優先します --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -7010,27 +7010,27 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}プロジェクトの作成 [$project_name]減圧:$original_path${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name] は次のように抽出されました。$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}プロジェクトの作成 [$project_name]復元が完了しました!${NC}" + echo -e "${GREEN}プロジェクトを作成する[$project_name】レストア完了!${NC}" fi done - # ------------------------------ + # --------- 通常のコンテナの復元を続行 --------- echo -e "${BLUE}通常のDockerコンテナを確認して復元します...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}コンテナの処理:$container${NC}" + echo -e "${GREEN}処理容器:$container${NC}" - # 容器が既に存在し、実行中かどうかを確認してください + # コンテナがすでに存在し、実行されているかどうかを確認します if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container]走っています、復元をスキップします...${NC}" + echo -e "${YELLOW}容器 [$container] すでに実行中のため、復元をスキップしています...${NC}" continue fi @@ -7051,7 +7051,7 @@ docker_ssh_migration() { ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # ボリュームマッピング +ボリュームデータリカバリ + # ボリュームマッピング + ボリュームデータリカバリ VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7062,19 +7062,19 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "ボリュームデータの回復:$VOL_SRC" + echo "ボリュームデータを復元します。$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 既存のが実行されていないコンテナを削除します + # 既存だが実行されていないコンテナを削除する if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container]存在しますが、実行していません。古いコンテナを削除してください...${NC}" + echo -e "${YELLOW}容器 [$container]存在しますが、実行していない、古いコンテナを削除してください...${NC}" docker rm -f "$container" fi - # コンテナの起動 - echo "restoreコマンドを実行します:docker run -d - name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # コンテナを起動します + echo "復元コマンドを実行します: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done @@ -7082,12 +7082,12 @@ docker_ssh_migration() { # /home /dockerの下でファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home /dockerの下でファイルを復元します...${NC}" + echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / echo -e "${GREEN}/home/docker 下のファイルが復元されました${NC}" else - echo -e "${YELLOW}/home /dockerの下のファイルのバックアップは見つかりませんでした、スキップ...${NC}" + echo -e "${YELLOW}/home/docker の下にあるファイルのバックアップが見つかりませんでした。スキップしています...${NC}" fi @@ -7098,14 +7098,14 @@ docker_ssh_migration() { # 移動します # ---------------------------- migrate_docker() { - send_stats "Dockerの移行" + send_stats "Docker の移行" install jq read -e -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } - read -e -p "ターゲットサーバーIP:" TARGET_IP - read -e -p "ターゲットサーバーSSHユーザー名:" TARGET_USER - read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + read -e -p "ターゲットサーバーIP:" TARGET_IP + read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" @@ -7123,8 +7123,8 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Dockerバックアップファイルの削除" - read -e -p "削除するには、バックアップディレクトリを入力してください。" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + read -e -p "削除するバックアップ ディレクトリを入力してください:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" } @@ -7133,7 +7133,7 @@ docker_ssh_migration() { # メインメニュー # ---------------------------- main_menu() { - send_stats "Dockerバックアップの移行と復元" + send_stats "Docker バックアップ 移行 復元" while true; do clear echo "------------------------" @@ -7142,10 +7142,10 @@ docker_ssh_migration() { list_backups echo -e "" echo "------------------------" - echo -e "1。Dockerプロジェクトをバックアップします" - echo -e "2。Dockerプロジェクトを移行します" + echo -e "1. Docker プロジェクトをバックアップする" + echo -e "2. Docker プロジェクトを移行する" echo -e "3. Dockerプロジェクトを復元します" - echo -e "4. Dockerプロジェクトのバックアップファイルを削除します" + echo -e "4. Dockerプロジェクトのバックアップファイルを削除する" echo "------------------------" echo -e "0。前のメニューに戻ります" echo "------------------------" @@ -7177,14 +7177,14 @@ linux_docker() { echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境のインストールと更新${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker画像管理" + echo -e "${gl_kjlan}4. ${gl_bai}Dockerイメージ管理" echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" - echo -e "${gl_kjlan}6. ${gl_bai}Dockerボリューム管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" echo -e "${gl_kjlan}------------------------" @@ -7192,14 +7192,14 @@ linux_docker() { echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" - echo -e "${gl_kjlan}12. ${gl_bai}docker-ipv6アクセスを閉じます" + echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 アクセスをオフにする" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Docker環境のバックアップ/移行/復元" + echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールする" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -7215,8 +7215,8 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "Dockerグローバルステータス" - echo "Dockerバージョン" + send_stats "ドッカーのグローバルステータス" + echo "Docker のバージョン" docker -v docker compose version @@ -7227,10 +7227,10 @@ linux_docker() { echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7270,14 +7270,14 @@ linux_docker() { done echo "" - echo "ネットワーク運用" + echo "ネットワーク操作" echo "------------------------" - echo "1.ネットワークを作成します" + echo "1. ネットワークを作成する" echo "2。インターネットに参加してください" - echo "3. ネットワークを終了します" + echo "3。ネットワークを終了します" echo "4.ネットワークを削除します" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" sub_choice @@ -7290,16 +7290,16 @@ linux_docker() { 2) send_stats "インターネットに参加してください" read -e -p "ネットワーク名に参加してください:" dockernetwork - read -e -p "これらのコンテナはネットワークに追加されます(複数のコンテナ名はスペースで区切られています):" dockernames + read -e -p "どのコンテナがネットワークに参加しますか (複数のコンテナ名はスペースで区切ってください):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "インターネットに参加してください" - read -e -p "出口ネットワーク名:" dockernetwork - read -e -p "これらのコンテナはネットワークを終了します(複数のコンテナ名はスペースで区切られています):" dockernames + send_stats "ネットワークに参加する" + read -e -p "出口ネットワーク名:" dockernetwork + read -e -p "これらのコンテナはネットワークから終了します (複数のコンテナ名はスペースで区切ってください)。" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7308,8 +7308,8 @@ linux_docker() { ;; 4) - send_stats "ネットワークを削除します" - read -e -p "削除するには、ネットワーク名を入力してください。" dockernetwork + send_stats "ネットワークを削除する" + read -e -p "削除するネットワーク名を入力してください:" dockernetwork docker network rm $dockernetwork ;; @@ -7329,17 +7329,17 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1.新しいボリュームを作成します" + echo "1. 新しいボリュームを作成します" echo "2。指定されたボリュームを削除します" echo "3.すべてのボリュームを削除します" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "新しいボリュームを作成する" + send_stats "新しいボリュームを作成します" read -e -p "新しいボリューム名を設定します:" dockerjuan docker volume create $dockerjuan @@ -7363,7 +7363,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -7376,7 +7376,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker のクリーンアップ" + send_stats "Dockerクリーニング" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7385,7 +7385,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -7407,13 +7407,13 @@ linux_docker() { 11) clear - send_stats "Docker V6が開いています" + send_stats "Docker v6 がオン" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 閉じる" + send_stats "Docker V6レベル" docker_ipv6_off ;; @@ -7424,7 +7424,7 @@ linux_docker() { 20) clear - send_stats "Dockerアンインストール" + send_stats "Docker のアンインストール" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7436,7 +7436,7 @@ linux_docker() { [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -7445,7 +7445,7 @@ linux_docker() { kejilion ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -7462,14 +7462,14 @@ linux_test() { while true; do clear - # send_stats「テストスクリプトコレクション」 + # send_stats "テストスクリプト集" echo -e "テストスクリプトコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IPおよびロック解除ステータス検出" + echo -e "${gl_kjlan}IPおよびロック解除ステータスの検出" echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" - echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアのロック解除テスト" + echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアロック解除テスト" echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 品質チェック スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ネットワーク速度測定" @@ -7477,29 +7477,29 @@ linux_test() { echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" echo -e "${gl_kjlan}13. ${gl_bai}超高速トリプルネットワーク速度テスト" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" - echo -e "${gl_kjlan}15. ${gl_bai}Nxtraceは、IPバックホールテストスクリプトを指定します" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3ネットワークラインテスト" - echo -e "${gl_kjlan}17. ${gl_bai}I-ABC多機能速度テストスクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}ネットワーク品質の高品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace は IP バックホール テスト スクリプトを指定します" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 3つのネットワーク回線テスト" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多機能速度テスト スクリプト" + echo -e "${gl_kjlan}18. ${gl_bai}Networt Network品質の身体診断スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU パフォーマンステストスクリプト" + echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}包括的なテスト" echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) clear - send_stats "CHATGPTはステータス検出のロックを解除します" + send_stats "ChatGPTロック解除状態検出" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) @@ -7509,7 +7509,7 @@ linux_test() { ;; 3) clear - send_stats "YeahWUストリーミングメディアのロック解除検出" + send_stats "Yeawu ストリーミング メディアのロック解除の検出" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; @@ -7522,7 +7522,7 @@ linux_test() { 11) clear - send_stats "BestTrace 3ネットワークバックホール遅延ルーティングテスト" + send_stats "besttrace トリプル ネットワーク バックホール遅延ルーティング テスト" install wget wget -qO- git.io/besttrace | bash ;; @@ -7538,30 +7538,30 @@ linux_test() { ;; 14) clear - send_stats "nxtrace高速バックホールテストスクリプト" + send_stats "nxtrace 高速バックホール テスト スクリプト" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "Nxtraceは、IPバックホールテストスクリプトを指定します" + send_stats "nxtrace は IP バックホール テスト スクリプトを指定します" echo "参照できるIPのリスト" echo "------------------------" echo "北京テレコム:219.141.136.12" - echo "北京ユニコム:202.106.50.1" + echo "北京ユニコム: 202.106.50.1" echo "北京モバイル:221.179.155.161" - echo "上海通信:202.96.209.133" - echo "上海ユニコム:210.22.97.1" - echo "上海モバイル:211.136.112.200" - echo "広州電信: 58.60.188.222" + echo "上海電信: 202.96.209.133" + echo "上海ユニコム: 210.22.97.1" + echo "上海モバイル: 211.136.112.200" + echo "広州の通信:58.60.188.222" echo "広州ユニコム:210.21.196.6" - echo "広州モバイル:120.196.165.24" + echo "広州モバイル: 120.196.165.24" echo "成都電信: 61.139.2.69" - echo "成都ユニコム:119.6.6.6" + echo "成都チャイナユニコム: 119.6.6.6" echo "成都モバイル:211.137.96.205" echo "Hunan Telecom:36.111.200.100" - echo "Hunan Unicom:42.48.16.100" - echo "Hunan Mobile:39.134.254.6" + echo "湖南ユニコム: 42.48.16.100" + echo "湖南省モバイル: 39.134.254.6" echo "------------------------" read -e -p "指定されたIPを入力してください:" testip @@ -7595,7 +7595,7 @@ linux_test() { ;; 22) clear - send_stats "IICU/GB5 CPUパフォーマンステストスクリプト" + send_stats "icu/gb5 CPU パフォーマンステストスクリプト" check_swap bash <(curl -sL bash.icu/gb5) ;; @@ -7635,15 +7635,15 @@ linux_Oracle() { send_stats "Oracle Cloud Scriptコレクション" echo -e "Oracle Cloud Scriptコレクション" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}アイドルマシンアクティブスクリプトをインストールします" + echo -e "${gl_kjlan}1. ${gl_bai}アイドル状態のマシンのアクティブ スクリプトをインストールする" echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DDシステムスクリプトを再インストールします" - echo -e "${gl_kjlan}4. ${gl_bai}探偵r開始スクリプト" - echo -e "${gl_kjlan}5. ${gl_bai}ルートパスワードログインモードをオンにします" + echo -e "${gl_kjlan}3. ${gl_bai}DD 再インストール システム スクリプト" + echo -e "${gl_kjlan}4. ${gl_bai}探偵R起動スクリプト" + echo -e "${gl_kjlan}5. ${gl_bai}ROOTパスワードログインモードを有効にする" echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice @@ -7651,7 +7651,7 @@ linux_Oracle() { 1) clear echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "インストールしてもよろしいですか? (はい/いいえ):" choice + read -e -p "必ずインストールしますか? (y/n):" choice case "$choice" in [Yy]) @@ -7663,20 +7663,20 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーにCPUコアの数と占有率の数を入力するように促し、入力した場合はデフォルト値を使用します。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU使用率の範囲(たとえば、10-20)を入力してください[デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 使用率の範囲 (例: 10 ~ 20) を入力してください [デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリ使用率を入力してください [デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Dockerコンテナを実行します + # Dockerコンテナを実行する docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7691,7 +7691,7 @@ linux_Oracle() { ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -7699,7 +7699,7 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloudはアクティブスクリプトをアンインストールします" + send_stats "Oracle Cloudアンインストール・アクティブ・スクリプト" ;; 3) @@ -7707,12 +7707,12 @@ linux_Oracle() { echo "システムを再インストールします" echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - read -e -p "必ず続行しますか? (y/n):" choice + read -e -p "必ず続けますか? (y/n):" choice case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください: 1. Debian12 | 2.Ubuntu20.04:" sys_choice + read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7724,7 +7724,7 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "選択の無効な、再入力してください。" + echo "選択が無効です。再入力してください。" ;; esac done @@ -7745,7 +7745,7 @@ linux_Oracle() { 4) clear - send_stats "探偵r開始スクリプト" + send_stats "探偵R起動スクリプト" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -7834,29 +7834,29 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp webサイトビルディング" - echo -e "${gl_huang}LDNMP Webサイトビルディング" + # send_stats "LDNMP Web サイトの構築" + echo -e "${gl_huang}LDNMP Web サイトの構築" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールします${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" + echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールする${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" - echo -e "${gl_huang}5. ${gl_bai}Apple CMSフィルムとテレビ局をインストールします${gl_huang}6. ${gl_bai}ユニコーンデジタルカードネットワークをインストールします" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum Webサイトをインストールします${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" - echo -e "${gl_huang}9. ${gl_bai}LinkStack共有リンクプラットフォームをインストールします${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS ムービーおよび TV ステーションをインストールする${gl_huang}6. ${gl_bai}Unicorn デジタル カード ネットワークをインストールする" + echo -e "${gl_huang}7. ${gl_bai}flarumフォーラムWebサイトをインストールする${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 共有リンク プラットフォームをインストールする${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールします${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" + echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwardenパスワード管理プラットフォームをインストールします${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" - echo -e "${gl_huang}27. ${gl_bai}AIペイントプロンプトワードジェネレーターをインストールします${gl_huang}28. ${gl_bai}サイトの逆プロキシロードバランス" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" + echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイトデータ全体をバックアップします" + echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイト全体のデータをバックアップする" echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールする" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻る" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_huang}------------------------${gl_bai}" read -e -p "選択を入力してください:" sub_choice @@ -7875,7 +7875,7 @@ linux_ldnmp() { # ディスクフォーラム webname="Discuz论坛" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,7 +7898,7 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" + echo "データベースアドレス: mysql" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -7909,10 +7909,10 @@ linux_ldnmp() { 4) clear - # Kedao Cloudデスクトップ + # Kedao クラウド デスクトップ webname="可道云桌面" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7934,10 +7934,10 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "データベースアドレス:mysql" + echo "データベースアドレス: mysql" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" + echo "データベース名:$dbname" echo "Redisホスト:Redis" ;; @@ -7947,7 +7947,7 @@ linux_ldnmp() { # Apple CMS webname="苹果CMS" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,21 +7973,21 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" + echo "データベースアドレス: mysql" + echo "データベースポート: 3306" echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "データベース接頭辞: mac_" + echo "データベースプレフィックス:mac_" echo "------------------------" - echo "インストールが成功した後、バックグラウンドアドレスにログインします" + echo "インストールが成功したら、バックエンド アドレスにログインします。" echo "https://$yuming/vip.php" ;; 6) clear - # 一本足のカウントカード + # 一本足のナンバーカード webname="独脚数卡" send_stats "インストール$webname" echo "展開を開始します$webname" @@ -8012,7 +8012,7 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス:mysql" - echo "データベースポート:3306" + echo "データベースポート: 3306" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -8021,14 +8021,14 @@ linux_ldnmp() { echo "redis パスワード: デフォルトでは入力されていません" echo "Redisポート:6379" echo "" - echo "ウェブサイトURL:https://$yuming" + echo "ウェブサイトURL:https://$yuming" echo "バックグラウンドログインパス: /admin" echo "------------------------" - echo "ユーザー名:admin" - echo "パスワード:管理者" + echo "ユーザー名: 管理者" + echo "パスワード: 管理者" echo "------------------------" - echo "ログインするときに右上隅に赤いerror0が表示される場合は、次のコマンドを使用してください。" - echo "また、ユニコーン番号カードがとても面倒で、そのような問題があることに非常に腹を立てています!" + echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" + echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8075,9 +8075,9 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "データベースアドレス: mysql" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "テーブルプレフィックス:flarum_" echo "管理者情報は自分で設定されます" @@ -8113,7 +8113,7 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースプレフィックス:typecho_" + echo "データベース接頭辞: typecho_" echo "データベースアドレス:mysql" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -8155,7 +8155,7 @@ linux_ldnmp() { echo "データベースアドレス:mysql" echo "データベースポート:3306" echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" ;; @@ -8163,7 +8163,7 @@ linux_ldnmp() { clear webname="PHP动态站点" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8183,7 +8183,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" echo "-------------" echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + read -e -p "ダウンロード リンクを入力して、ソース コード パッケージをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8193,12 +8193,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.phpが配置されているパス" + echo -e "[${gl_huang}2/6${gl_bai}]index.phpが配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.phpのパスを入力してください$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/ のような、index.php へのパスを入力してください)$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8206,7 +8206,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}3/6${gl_bai}] PHPバージョンを選択してください" echo "-------------" - read -e -p "1。PHPの最新バージョン| 2。Php7.4:" pho_v + read -e -p "1.php最新バージョン | 2.php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8217,7 +8217,7 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "選択の無効な、再入力してください。" + echo "選択が無効です。再入力してください。" ;; esac @@ -8225,7 +8225,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}4/6${gl_bai}] 指定された拡張機能をインストールします" echo "-------------" - echo "インストールされた拡張機能" + echo "インストールされている拡張機能" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8235,16 +8235,16 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}]サイト構成を編集します" + echo -e "[${gl_huang}5/6${gl_bai}] サイト構成を編集する" echo "-------------" - echo "任意のキーを押して続行すると、擬似静的コンテンツなど、サイト構成を詳細に設定できます。" + echo "続行するには任意のキーを押してください。擬似静的コンテンツなどのサイト構成を詳細に設定できます。" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}]データベース管理" + echo -e "[${gl_huang}6/6${gl_bai}] データベース管理" echo "-------------" read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db case $use_db in @@ -8252,8 +8252,8 @@ linux_ldnmp() { echo ;; 2) - echo "データベースのバックアップは、.GZ-endコンプレッションパッケージである必要があります。 Pagoda/1panelのバックアップデータのインポートをサポートするために、/home/directoryに入れてください。" - read -e -p "ダウンロードリンクを入力して、バックアップデータをリモートでダウンロードすることもできます。 Enterを直接押して、リモートダウンロードをスキップします:" url_download_db + echo "データベースのバックアップは、.gz で終わる圧縮パッケージである必要があります。 Pagoda/1panel バックアップ データのインポートをサポートするには、/home/ ディレクトリに配置してください。" + read -e -p "ダウンロード リンクを入力してバックアップ データをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8263,7 +8263,7 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "データベースインポートテーブルデータ" + echo "データベースにインポートされたテーブルデータ" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql echo "データベースのインポートが完了しました" @@ -8279,11 +8279,11 @@ linux_ldnmp() { ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" echo "データベースアドレス:mysql" - echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "データベース名:$dbname" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "テーブルの接頭辞:$prefix" - echo "管理者ログイン情報は自分で設定されます" + echo "管理者のログイン情報は自分で設定します" ;; @@ -8297,9 +8297,9 @@ linux_ldnmp() { clear webname="站点重定向" send_stats "インストール$webname" - echo "導入を開始する$webname" + echo "展開を開始します$webname" add_yuming - read -e -p "ジャンプドメイン名を入力してください:" reverseproxy + read -e -p "リダイレクト ドメイン名を入力してください:" reverseproxy nginx_install_status install_ssltls certs_status @@ -8333,10 +8333,10 @@ linux_ldnmp() { clear webname="反向代理-域名" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" - read -e -p "抗ジェネレーションドメイン名を入力してください。" fandai_yuming + read -e -p "リバース プロキシ ドメイン名を入力してください:" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8451,8 +8451,8 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリの下" - read -e -p "ダウンロード リンクを入力して、ソース コード パッケージをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download + echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8467,7 +8467,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/に似たindex.htmlへのパスを入力してください$yuming/index/): " index_lujing + read -e -p "(/home/web/html/ のような、index.html へのパスを入力してください)$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8495,7 +8495,7 @@ linux_ldnmp() { send_stats "LDNMP環境バックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -8505,10 +8505,10 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "エラー: リモート サーバーの IP を入力してください。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8518,7 +8518,7 @@ linux_ldnmp() { scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" else - echo "転送されるファイルは見つかりませんでした。" + echo "転送するファイルが見つかりませんでした。" fi break ;; @@ -8526,7 +8526,7 @@ linux_ldnmp() { break ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac done @@ -8534,7 +8534,7 @@ linux_ldnmp() { 33) clear - send_stats "タイミングのリモートバックアップ" + send_stats "スケジュールされたリモートバックアップ" read -e -p "リモートサーバーIPを入力してください:" useip read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd @@ -8557,7 +8557,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "毎日のバックアップの時間を選択します(時間、0-23):" hour + read -e -p "毎日のバックアップ時間 (時間、0 ~ 23) を選択します。" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8583,7 +8583,7 @@ linux_ldnmp() { linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージが使用されます。 + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8602,7 +8602,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージが見つかりませんでした。" + echo "圧縮パッケージは見つかりませんでした。" fi ;; @@ -8620,11 +8620,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP環境を更新します" + send_stats "LDNMP環境を更新する" echo "LDNMP環境を更新します" echo "------------------------" ldnmp_v - echo "コンポーネントの新しいバージョンを発見します" + echo "新しいバージョンのコンポーネントが見つかりました" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8644,13 +8644,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1。更新nginx2。mysql3を更新します。php4を更新します。redisを更新します" + echo "1. nginx を更新します。 2. mysql を更新します。 3. php を更新します。 4. redis を更新します。" echo "------------------------" echo "5。完全な環境を更新します" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8659,7 +8659,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号 (例: 8.0 8.3 8.4 9.0) (Enter キーを押して最新バージョンを取得します):" version + read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version local version=${version:-latest} cd /home/web/ @@ -8670,13 +8670,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" + send_stats "更新する$ldnmp_pods" echo "更新します${ldnmp_pods}仕上げる" ;; 3) local ldnmp_pods="php" - read -e -p "入力してください${ldnmp_pods}バージョン番号(7.4 8.0 8.1 8.2 8.3)(最新バージョンを入手するには入力):" version + read -e -p "入力してください${ldnmp_pods}バージョン番号 (例: 7.4 8.0 8.1 8.2 8.3) (Enter キーを押して最新バージョンを取得します):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8710,7 +8710,7 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml send_stats "更新します$ldnmp_pods" - echo "更新する${ldnmp_pods}仕上げる" + echo "更新します${ldnmp_pods}仕上げる" ;; 4) @@ -8729,7 +8729,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境の完全アップデート" + send_stats "LDNMP環境を完全に更新します" cd /home/web/ docker compose down --rmi all @@ -8755,7 +8755,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP環境をアンインストールします" + send_stats "LDNMP環境をアンインストールする" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8804,7 +8804,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # ループで色を設定します + # ループで色を設定する for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8814,72 +8814,72 @@ while true; do done echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1パネルの新世代管理パネル${gl_kjlan}4. ${color4}nginxproxymanagerビジュアルパネル" + echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}Rocketchatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" + echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendaoプロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" + echo -e "${gl_kjlan}11. ${color11}ZenTao プロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}Emby Multimedia Management System${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}AdGuardhomeアドウェア${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" - echo -e "${gl_kjlan}19. ${color19}サンダープールWAFファイアウォールパネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" + echo -e "${gl_kjlan}17. ${color17}Adguardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}vscode webバージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" + echo -e "${gl_kjlan}21. ${color21}VScode Web バージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Today スケジュールされたタスク管理フレームワーク" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Managementパネル${gl_kjlan}28. ${color28}librespeed速度テストツール" - echo -e "${gl_kjlan}29. ${color29}searxng集約検索サイト${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}フォトプリズムプライベートアルバムシステム" + echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}27. ${color27}Dockge コンテナ スタック管理パネル${gl_kjlan}28. ${color28}LibreSpeed 速度テストツール" + echo -e "${gl_kjlan}29. ${color29}searxng 集約検索ステーション${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrismプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDFツールコレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Shareファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}友達のミニマリストのサークル${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" - echo -e "${gl_kjlan}37. ${color37}MyIPツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}WebSH WebバージョンSSH接続ツール" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF ツール コレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Share ファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}ミニマリストの友達の輪${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" + echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}Rustdeskリモートデスク(リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHubアクセラレーションステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHub加速ステーション${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVEチキンパネル${gl_kjlan}52. ${color52}dPanelコンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" + echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify Big Model Knowledge Base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi Big Model Asset Management${gl_kjlan}60. ${color60}Jumpserverオープンソースバス剤マシン" + echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}Ragflow Big Model Knowledge Base" - echo -e "${gl_kjlan}63. ${color63}OpenWebui自己ホストAIプラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" - echo -e "${gl_kjlan}65. ${color65}N8Nオートメーションワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLPビデオダウンロードツール" - echo -e "${gl_kjlan}67. ${color67}DDNS-GOダイナミックDNS管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinsSL証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGOファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" + echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidromeプライベートミュージックサーバー${gl_kjlan}72. ${color72}Bitwardenパスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MOONTVプライベート映画" + echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${color77}サンダーオフラインダウンロードツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" - echo -e "${gl_kjlan}79. ${color79}Beszelサーバーの監視${gl_kjlan}80. ${color80}Linkwardenブックマーク管理" + echo -e "${gl_kjlan}77. ${color77}Thunder オフライン ダウンロード ツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}79. ${color79}Beszel サーバーの監視${gl_kjlan}80. ${color80}リンクワーデンのブックマーク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeetビデオ会議${gl_kjlan}82. ${color82}GPT-Load High-Performance AI透明プロキシ" - echo -e "${gl_kjlan}83. ${color83}コマリサーバー監視ツール${gl_kjlan}84. ${color84}Wallos個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}Jellyfinメディア管理システム" - echo -e "${gl_kjlan}87. ${color87}synctvムービーウォッチングアーティファクト${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" + echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos Personal Financial Management Tools" + echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" - echo -e "${gl_kjlan}93. ${color93}DUFS Minimalist Static File Server${gl_kjlan}94. ${color94}ゴープ高速ダウンロードツール" - echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2Fauth自己ホストの2段階検証装置" - echo -e "${gl_kjlan}97. ${color97}ワイヤガードネットワーキング(サーバー側)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}同期ポイントツーポイントファイル同期ツール" + echo -e "${gl_kjlan}93. ${color93}Dufs のミニマリスト静的ファイル サーバー${gl_kjlan}94. ${color94}Gopeed高速ダウンロードツール" + echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2FAuth セルフホスト型 2 段階認証システム" + echo -e "${gl_kjlan}97. ${color97}WireGuard ネットワーキング (サーバー)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AIビデオ生成ツール${gl_kjlan}102. ${color102}VoceChatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChatマルチプレイヤーオンラインチャットシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーションデータをバックアップします${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" + echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice fi case $sub_choice in @@ -9032,7 +9032,7 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザー名を設定します:" admin read -e -p "ログインユーザーパスワードを設定します。" admin_password docker run -d \ --name=webtop-ubuntu \ @@ -9075,8 +9075,8 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezhaの監視$check_docker $update_status" - echo "オープンソース、軽量で使いやすいサーバーの監視と操作およびメンテナンスツール" + echo -e "ネザモニタリング$check_docker $update_status" + echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -9086,7 +9086,7 @@ while true; do echo "------------------------" echo "1。使用します" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice @@ -9155,9 +9155,9 @@ while true; do check_docker_image_update $docker_name clear - echo -e "郵便局サービス$check_docker $update_status" - echo "Poste.ioはオープンソースメールサーバーソリューションです。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo -e "郵便サービス$check_docker $update_status" + echo "poste.io はオープンソースのメール サーバー ソリューションです。" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" echo "ポート検出" @@ -9172,14 +9172,14 @@ while true; do if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "アクセスアドレス:" + echo "訪問先住所:" echo "https://$yuming" fi echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice @@ -9221,7 +9221,7 @@ while true; do add_app_id clear - echo "poste.ioがインストールされました" + echo "Poste.ioがインストールされています" echo "------------------------" echo "次のアドレスを使用してposte.ioにアクセスできます。" echo "https://$yuming" @@ -9303,7 +9303,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chatがインストールされています" + echo "rocket.chat がインストールされました" check_docker_app_ip } @@ -9313,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -9397,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -9556,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "雷のプールを作る" + send_stats "サンダープールを構築します" local app_id="19" local docker_name=safeline-mgt @@ -9573,11 +9573,11 @@ while true; do echo "" echo "------------------------" - echo "1。インストール2。更新3。パスワードのリセット4。アンインストール" + echo "1. インストール 2. アップデート 3. パスワードのリセット 4. アンインストール" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -9611,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "デフォルトのインストールディレクトリである場合、プロジェクトはアンインストールされました。インストールディレクトリをカスタマイズする場合は、インストールディレクトリにアクセスして自分で実行する必要があります。" + echo "デフォルトのインストール ディレクトリにいる場合、プロジェクトはすでにアンインストールされています。インストール ディレクトリをカスタマイズする場合は、インストール ディレクトリに移動して自分で実行する必要があります。" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -10019,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="公式ウェブサイトの紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10072,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoyaファミリーバケット" + send_stats "シャオヤファミリーバケツ" clear install_docker check_disk_space 1 @@ -10276,7 +10276,7 @@ while true; do prometheus_install clear ip_address - echo "インストール完了" + echo "インストール" check_docker_app_ip echo "最初のユーザー名とパスワードは次のとおりです" } @@ -10383,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVEチキン" + send_stats "PVE オープンひよこ" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10503,7 +10503,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -10518,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -10546,7 +10546,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -10569,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -10657,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -10673,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリがアンインストールされました" + echo "アプリはアンインストールされています" } docker_app_plus @@ -10969,8 +10969,8 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーのパスワードを設定します。" admin_password read -e -p "承認コードを入力してください:" shouquanma @@ -10987,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11001,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11075,7 +11075,7 @@ while true; do docker_rum() { read -e -p "ログインユーザー名を設定します:" app_use - read -e -p "ログインパスワードの設定:" app_passwd + read -e -p "ログインパスワードを設定します:" app_passwd docker run -d \ --name xunlei \ @@ -11172,7 +11172,7 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 公式のDocker-ComposeおよびEnvファイルをダウンロードします + # 公式の docker-compose および env ファイルをダウンロードする curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" @@ -11191,7 +11191,7 @@ while true; do sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # コンテナを起動します + # コンテナの起動 docker compose up -d clear @@ -11272,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11290,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}SK-159KEJILIONYYDS163などのログインキー(SKターニング文字と数字の組み合わせ):" app_passwd + read -e -p "設定${docker_name}ログイン キー (sk- で始まる文字と数字の組み合わせ) 例: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11620,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11709,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" app_use - read -e -p "ログインパスワードの設定:" app_passwd + read -e -p "ログインユーザー名を設定します:" app_use + read -e -p "ログインパスワードを設定します:" app_passwd docker run -d \ --name ${docker_name} \ @@ -11812,7 +11812,7 @@ while true; do block_container_port "$docker_name" "$ipv4_address" clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11826,7 +11826,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "アプリがアンインストールされました" + echo "アプリはアンインストールされています" } docker_app_plus @@ -11844,7 +11844,7 @@ while true; do docker_rum() { - read -e -p "ネットワークを形成するためにクライアントの数を入力してください(デフォルト5):" COUNT + read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} read -e -p "WireGuardセグメントを入力してください(デフォルト10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} @@ -11923,10 +11923,10 @@ while true; do echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}すべての出力は各クライアントによって提供されます。使用方法は次のとおりです。${gl_bai}" + echo -e "${gl_lv}${COUNT}各クライアントのすべての出力を構成します。利用方法は以下の通りです。${gl_bai}" echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" echo -e "${gl_lv}2。Windowsクライアントをダウンロードし、構成コードをコピーしてネットワークに接続します。${gl_bai}" - echo -e "${gl_lv}3。Linuxはスクリプトを使用してWGクライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" + echo -e "${gl_lv}3. スクリプトを使用して Linux に WG クライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" echo -e "${gl_lv}公式クライアントのダウンロード方法:https://www.wireguard.com/install/${gl_bai}" break_end @@ -11958,9 +11958,9 @@ while true; do # ディレクトリを作成する(存在しない場合) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアントの構成を貼り付け、Enterを2回連続で押して保存してください。" + echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" - # 変数を初期化します + # 変数を初期化する input="" empty_line_count=0 @@ -11980,7 +11980,7 @@ while true; do # 構成ファイルに書き込みます echo "$input" > "$CONFIG_FILE" - echo "クライアントの構成が保存されています$CONFIG_FILE" + echo "クライアント設定の保存場所$CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -12028,7 +12028,7 @@ while true; do read -e -p "CPUコアの数を設定します(デフォルト2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "メモリサイズを設定します(デフォルト4G):" RAM_SIZE + read -e -p "メモリ サイズを設定します (デフォルトは 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -12059,7 +12059,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -12114,7 +12114,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -12129,7 +12129,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" @@ -12168,24 +12168,24 @@ while true; do b) clear - send_stats "すべてのアプリケーションバックアップ" + send_stats "すべてのアプリケーションのバックアップ" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ$backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "バックアップファイルが作成されました: /$backup_filename" + echo "バックアップファイルが作成されました: /$backup_filename" read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice case "$choice" in [Yy]) read -e -p "リモートサーバーIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーSSHポート[デフォルト22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" + echo "エラー: リモート サーバーの IP を入力してください。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -12193,14 +12193,14 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "ファイルは、リモートサーバー/ルートディレクトリに転送されました。" + echo "ファイルはリモート サーバー/ルート ディレクトリに転送されます。" else - echo "転送されるファイルは見つかりませんでした。" + echo "転送するファイルが見つかりませんでした。" fi break ;; *) - echo "注:現在、バックアップにはDockerプロジェクトのみが含まれており、Pagodaや1PanelなどのWebサイトビルディングパネルのデータバックアップは含まれていません。" + echo "注: 現在のバックアップには Docker プロジェクトのみが含まれており、Pagoda や 1panel などの Web サイト構築パネルのデータ バックアップは含まれていません。" break ;; esac @@ -12211,18 +12211,18 @@ while true; do r) root_use send_stats "すべてのアプリケーションが復元されます" - echo "利用可能なアプリバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "入力して最新のバックアップを復元し、バックアップファイル名を入力して指定されたバックアップを復元し、0を入力して終了します。" filename + read -e -p "Enter キーを押して最新のバックアップを復元し、バックアップ ファイル名を入力して指定したバックアップを復元し、0 を入力して終了します。" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージが使用されます。 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi @@ -12257,8 +12257,8 @@ linux_work() { clear send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" - echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSHを切断したとしても、ワークスペースのタスクは中断されず、バックグラウンドのタスクが居住します。" + echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" echo -e "${gl_kjlan}------------------------" echo "現在既存のワークスペースのリスト" @@ -12270,20 +12270,20 @@ linux_work() { echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" - echo -e "${gl_kjlan}6. ${gl_bai}ワークスペースNo. 6" - echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo. 7" + echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" + echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" - echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo. 9" + echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースを作成/入力します" + echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" - echo -e "${gl_kjlan}24. ${gl_bai}指定されたワークスペースを削除します" + echo -e "${gl_kjlan}24. ${gl_bai}指定したワークスペースを削除します" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -12299,14 +12299,14 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 4) @@ -12320,7 +12320,7 @@ linux_work() { clear install tmux local SESSION_NAME="work5" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 6) @@ -12341,14 +12341,14 @@ linux_work() { clear install tmux local SESSION_NAME="work8" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 10) @@ -12369,9 +12369,9 @@ linux_work() { fi send_stats "SSH常駐モード" echo -e "SSH常駐モード${tmux_sshd_status}" - echo "SSH接続が有効になった後、レジデントモードに直接入力し、以前の作業状態に戻ります。" + echo "SSH 接続を開いた後、直接常駐モードに入り、前の動作状態に直接戻ります。" echo "------------------------" - echo "1。2をオンにします。オフにします" + echo "1. オン 2. オフ" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -12397,7 +12397,7 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1など、作成または入力したワークスペースの名前を入力してください。" SESSION_NAME + read -e -p "作成または入力したワークスペースの名前を入力してください (1001 kj001 work1 など)。" SESSION_NAME tmux_run send_stats "カスタムワークスペース" ;; @@ -12406,13 +12406,13 @@ linux_work() { 23) read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd tmux_run_d - send_stats "バックグラウンドワークスペースにコマンドを注入します" + send_stats "バックグラウンドワークスペースにコマンドを挿入する" ;; 24) read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "ワークスペースを削除します" + send_stats "ワークスペースの削除" ;; 0) @@ -12449,41 +12449,41 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開きます${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更します" - echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化します${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3アクセラレーションの設定" - echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール上級マネージャー${gl_kjlan}18. ${gl_bai}ホスト名を変更します" + echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール アドバンスト マネージャー${gl_kjlan}18. ${gl_bai}ホスト名の変更" echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホストの解析${gl_kjlan}22. ${gl_bai}SSH防衛プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ルート秘密キーログインモード" - echo -e "${gl_kjlan}25. ${gl_bai}TGボットシステムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSHの高リスクの脆弱性を修正します" + echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト解像度${gl_kjlan}22. ${gl_bai}SSH防御プログラム" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ROOT秘密鍵ログインモード" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot システムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSH の高リスク脆弱性を修正" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替えます${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムリサイクルビンをセットアップします${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" + echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替える${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}システムのごみ箱をセットアップする${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" - echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}RSYNCリモート同期ツール" + echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}rsync リモート同期ツール" echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}メッセージボード${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "ショートカットキーを入力してください(出口に0を入力してください):" kuaijiejian + read -e -p "ショートカット キーを入力してください (終了するには 0 を入力してください):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -12491,7 +12491,7 @@ linux_Settings() { find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian echo "ショートカットキーが設定されています" - send_stats "スクリプトのショートカットキーが設定されています" + send_stats "スクリプトのショートカットキーが設定されました" break_end linux_Settings done @@ -12499,30 +12499,30 @@ linux_Settings() { 2) clear - send_stats "ログインパスワードを設定します" + send_stats "ログインパスワードを設定する" echo "ログインパスワードを設定します" passwd ;; 3) root_use - send_stats "ルートパスワードモード" + send_stats "rootパスワードモード" add_sshpasswd ;; 4) root_use send_stats "Pyバージョン管理" - echo "Pythonバージョン管理" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + echo "Pythonのバージョン管理" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" + echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" echo "クエリの詳細:https://www.python.org/downloads/" echo "------------" - read -e -p "インストールするPythonバージョン番号を入力します(Enter 0からExit):" py_new_v + read -e -p "インストールするpythonバージョン番号を入力します(0を入力して終了します):" py_new_v if [[ "$py_new_v" == "0" ]]; then @@ -12588,14 +12588,14 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "現在のPythonバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スクリプトPYバージョン切り替え" + echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" + send_stats "スイッチスクリプトPyバージョン" ;; 5) root_use - send_stats "オープンポート" + send_stats "ポートを開く" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "すべてのポートが開いています" @@ -12603,25 +12603,25 @@ EOF ;; 6) root_use - send_stats "SSHポートを変更します" + send_stats "SSHポートを変更する" while true; do clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 現在のSSHポート番号をお読みください + # 現在の SSH ポート番号を読み取ります local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') # 現在のSSHポート番号を印刷します - echo -e "現在のSSHポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" + echo -e "現在の SSH ポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "ポート番号が1〜65535の範囲の数字(0を入力して終了)" + echo "ポート番号の範囲は 1 ~ 65535 です (終了するには 0 を入力します)。" # ユーザーに新しいSSHポート番号を入力するように促します read -e -p "新しいSSHポート番号を入力してください:" new_port - # ポート番号が有効な範囲内にあるかどうかを判断します + # ポート番号が有効な範囲内であるかどうかを確認します。 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSHポートが変更されました" @@ -12635,8 +12635,8 @@ EOF break_end fi else - echo "入力が無効です。番号を入力してください。" - send_stats "無効なSSHポート入力" + echo "入力が無効です。数値を入力してください。" + send_stats "無効な SSH ポートが入力されました" break_end fi done @@ -12655,8 +12655,8 @@ EOF ;; 9) root_use - send_stats "新しいユーザーはルートを無効にします" - read -e -p "新しいユーザー名を入力してください (終了するには 0 を入力してください):" new_username + send_stats "新規ユーザーの root を無効にする" + read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12671,7 +12671,7 @@ EOF passwd -l root - echo "操作が完了しました。" + echo "操作は完了です。" ;; @@ -12680,42 +12680,42 @@ EOF send_stats "V4/V6の優先度を設定します" while true; do clear - echo "V4/V6の優先度を設定します" + echo "v4/v6 の優先順位を設定する" echo "------------------------" if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" echo "------------------------" echo "1. IPv4 が先 2. IPv6 が先 3. IPv6 修復ツール" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "優先ネットワークを選択します。" choice + read -e -p "優先ネットワークを選択してください:" choice case $choice in 1) grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf echo "IPv4優先に切り替えました" - send_stats "IPv4の優先度に切り替えました" + send_stats "IPv4優先に切り替えました" ;; 2) rm -f /etc/gai.conf - echo "IPv6の優先度に切り替えました" - send_stats "IPv6の優先度に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" - send_stats "IPv6修正" + echo "この機能は jhb によって提供されています。ありがとう!" + send_stats "IPv6修復" ;; *) @@ -12733,15 +12733,15 @@ EOF 12) root_use - send_stats "仮想メモリを設定します" + send_stats "仮想メモリを設定する" while true; do clear - echo "仮想メモリを設定します" + echo "仮想メモリを設定する" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" + echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" echo "------------------------" echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" echo "------------------------" @@ -12798,29 +12798,29 @@ EOF echo "------------------------" echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" echo "------------------------" - echo "3.最高の権限を与える4。最高の権限をキャンセルします" + echo "3. 最高の権限を付与する 4. 最高の権限を削除する" echo "------------------------" - echo "5.アカウントを削除します" + echo "5. アカウントを削除する" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - # ユーザーに新しいユーザー名を入力するように求めます + # ユーザーに新しいユーザー名の入力を求める read -e -p "新しいユーザー名を入力してください:" new_username - # 新しいユーザーを作成し、パスワードを設定します + # 新しいユーザーを作成してパスワードを設定する useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "操作が完了しました。" + echo "操作は完了です。" ;; 2) - # ユーザーに新しいユーザー名を入力するように求めます - read -e -p "新しいユーザー名を入力してください:" new_username + # ユーザーに新しいユーザー名の入力を求める + read -e -p "新しいユーザー名を入力してください:" new_username # 新しいユーザーを作成し、パスワードを設定します useradd -m -s /bin/bash "$new_username" @@ -12835,21 +12835,21 @@ EOF ;; 3) - read -e -p "ユーザー名を入力してください:" username + read -e -p "ユーザー名を入力してください:" username # 新規ユーザーのsudo許可を付与します echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "ユーザー名を入力してください:" username - # sudoersファイルからユーザーのsudoアクセス許可を削除します + read -e -p "ユーザー名を入力してください:" username + # sudoers ファイルからユーザーの sudo 権限を削除する sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) read -e -p "削除するユーザー名を入力してください:" username - # ユーザーとそのホームディレクトリを削除します + # ユーザーとそのホームディレクトリを削除する userdel -r "$username" ;; @@ -12863,7 +12863,7 @@ EOF 14) clear send_stats "ユーザー情報ジェネレーター" - echo "ランダムユーザー名" + echo "ランダムなユーザー名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" @@ -12876,7 +12876,7 @@ EOF local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5つのランダムユーザー名を生成します + # 5 つのランダムなユーザー名を生成する for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) @@ -12885,7 +12885,7 @@ EOF done echo "" - echo "ランダムな UUID" + echo "ランダムuuid" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) @@ -12893,7 +12893,7 @@ EOF done echo "" - echo "16ビットランダムパスワード" + echo "16桁のランダムなパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) @@ -12913,10 +12913,10 @@ EOF 15) root_use - send_stats "タイムゾーンを変更します" + send_stats "タイムゾーンを変更する" while true; do clear - echo "システム時間情報" + echo "システム時刻情報" # 現在のシステムタイムゾーンを取得します local timezone=$(current_timezone) @@ -12925,34 +12925,34 @@ EOF local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示します - echo "現在のシステムタイムゾーン:$timezone" - echo "現在のシステム時間:$current_time" + echo "現在のシステムのタイムゾーン:$timezone" + echo "現在のシステム時間:$current_time" echo "" echo "タイムゾーンの切り替え" echo "------------------------" echo "アジア" - echo "1。中国の上海時間2。中国の香港時間" + echo "1. 中国上海時間 2. 中国香港時間" echo "3。日本の東京時間4。韓国のソウル時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" echo "9。タイのバンコクでの時間" echo "------------------------" echo "ヨーロッパ" - echo "11。英国のロンドン時間12。パリの時間フランスの時間" - echo "13。ベルリン時代、ドイツ14。モスクワ・タイム、ロシア" + echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" + echo "13。ベルリン・タイム、ドイツ14。モスクワ・タイム、ロシア" echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" echo "------------------------" echo "アメリカ" - echo "21。WesternTime22。東部時間" - echo "23。カナダ時間24。メキシコの時間" + echo "21. 米国西部時間 22. 米国東部時間" + echo "23. カナダ時間 24. メキシコ時間" echo "25. ブラジル時間 26. アルゼンチン時間" echo "------------------------" echo "31. UTC 世界標準時" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -12995,14 +12995,14 @@ EOF 18) root_use - send_stats "ホスト名の変更" + send_stats "ホスト名を変更します" while true; do clear local current_hostname=$(uname -n) - echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" + echo -e "現在のホスト名:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "新しいホスト名を入力してください(出口に0を入力してください):" new_hostname + read -e -p "新しいホスト名を入力してください (終了するには 0 を入力してください):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine @@ -13039,14 +13039,14 @@ EOF 19) root_use - send_stats "システムの更新ソースを変更します" + send_stats "システムアップデートソースを変更する" clear echo "更新ソース領域を選択します" - echo "LinuxMirrorsに接続して、システム更新ソースを切り替えます" + echo "LinuxMirror にアクセスしてシステム アップデート ソースを切り替える" echo "------------------------" - echo "1。中国本土[デフォルト]2。中国本土[教育ネットワーク]3。海外地域" + echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "あなたの選択を入力してください:" choice @@ -13077,25 +13077,25 @@ EOF clear check_crontab_installed clear - echo "タイミングされたタスクリスト" + echo "スケジュールされたタスクのリスト" crontab -l echo "" echo "動作します" echo "------------------------" - echo "1.タイミングタスクの追加2。タイミングタスクを削除する3。タイミングタスクの編集" + echo "1. スケジュールされたタスクを追加します。 2. スケジュールされたタスクを削除します。 3. スケジュールされたタスクを編集します。" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択肢を入力してください:" sub_choice + read -e -p "選択を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "新しいタスクについては、実行コマンドを入力してください。" newquest + read -e -p "新しいタスクの実行コマンドを入力してください:" newquest echo "------------------------" - echo "1。毎月のタスク2。毎週のタスク" - echo "3. 毎日のタスク 4. 時間ごとのタスク" + echo "1. 月次タスク 2. 週次タスク" + echo "3。毎日のタスク4。時間ごとのタスク" echo "------------------------" - read -e -p "選択肢を入力してください:" dingshi + read -e -p "選択を入力してください:" dingshi case $dingshi in 1) @@ -13103,22 +13103,22 @@ EOF (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "タスクを実行するためにどの週を選択しますか? (0-6、0は日曜日を表します):" weekday + read -e -p "タスクを実行する曜日を選択しますか? (0 ~ 6、0 は日曜日を表します):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "毎日タスクを実行する時間を選択しますか? (時間、0-23):" hour + read -e -p "毎日、そのタスクを実行する時刻を選択しますか? (時、0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行する時間を入力してください。 (分、0 ~ 60):" minute + read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "時限タスクを追加します" + send_stats "タイムされたタスクを追加します" ;; 2) read -e -p "削除する必要があるキーワードを入力してください。" kquest @@ -13139,11 +13139,11 @@ EOF 21) root_use - send_stats "ローカルホストの解析" + send_stats "ローカルホストの解決" while true; do clear echo "ネイティブホストのペルシングリスト" - echo "ここに解析の一致を追加すると、動的な解析はもはや使用されなくなります" + echo "ここに解析一致を追加すると、動的解析は使用されなくなります" cat /etc/hosts echo "" echo "操作する" @@ -13152,7 +13152,7 @@ EOF echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "選択肢を入力してください:" host_dns case $host_dns in 1) @@ -13162,9 +13162,9 @@ EOF ;; 2) - read -e -p "削除する必要があるコンテンツの解析のキーワードを入力してください。" delhost + read -e -p "削除する必要がある解析済みコンテンツのキーワードを入力してください:" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "ローカルホストの解析と削除" + send_stats "ローカルホストの解決と削除" ;; *) break # 跳出循环,退出菜单 @@ -13183,16 +13183,16 @@ EOF echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 防御プログラムをインストールする" echo "------------------------" - echo "2. SSH インターセプト記録の表示" + echo "2。SSH傍受記録を表示します" echo "3。リアルタイムログ監視" echo "------------------------" echo "9.防衛プログラムをアンインストールします" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -13214,7 +13214,7 @@ EOF 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2Ban 防御プログラムがアンインストールされました" + echo "Fail2Ban防衛プログラムがアンインストールされています" break ;; *) @@ -13231,31 +13231,31 @@ EOF while true; do clear echo "電流制限シャットダウン機能" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" output_status - echo -e "${gl_kjlan}受け取った合計:${gl_bai}$rx" - echo -e "${gl_kjlan}送信合計:${gl_bai}$tx" + echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" + echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" - # Limiting_Shut_down.sh ファイルが存在するかどうかを確認します + # limiting_shut_down.shファイルが存在するかどうかを確認してください if [ -f ~/Limiting_Shut_down.sh ]; then - # しきい値_gbの値を取得する + # threshold_gbの値を取得します local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}現在の制限シャットダウン機能は有効になりません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo echo "------------------------------------------------" echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" echo "------------------------" - echo "1。現在の制限シャットダウン関数をオンにします2。現在の制限シャットダウン機能を無効にします" + echo "1. 電流制限シャットダウン機能を有効にする 2. 電流制限シャットダウン機能を無効にする" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択を入力してください:" Limiting @@ -13263,11 +13263,11 @@ EOF 1) # 新しい仮想メモリサイズを入力します echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" - read -e -p "着信トラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" rx_threshold_gb + read -e -p "受信トラフィックのしきい値を入力してください (単位は G、デフォルトは 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "アウトバウンドトラフィックのしきい値を入力してください(ユニットはG、デフォルトは100gです):" tx_threshold_gb + read -e -p "送信トラフィックのしきい値を入力してください (単位は G、デフォルトは 100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "トラフィックリセット日を入力してください(デフォルトのリセットは、毎月1日目にリセットされます):" cz_day + read -e -p "トラフィックのリセット日を入力してください (デフォルトは毎月 1 日にリセットされます)。" cz_day cz_day=${cz_day:-1} cd ~ @@ -13288,7 +13288,7 @@ EOF crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "現在の制限シャットダウン関数はオフになっています" + echo "電流制限シャットダウン機能がオフになる" ;; *) break @@ -13305,11 +13305,11 @@ EOF while true; do clear echo "ルート秘密キーログインモード" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" - echo "キーペアが生成され、SSHログインのより安全な方法" + echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" echo "------------------------" - echo "1.新しいキーを生成する2。既存のキーをインポートする3。ネイティブキーを表示します" + echo "1. 新しいキーを生成します。 2. 既存のキーをインポートします。 3. ローカルキーを表示します。" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" @@ -13317,7 +13317,7 @@ EOF case $host_dns in 1) - send_stats "新しいキーを生成する" + send_stats "新しいキーを生成します" add_sshkey break_end @@ -13350,18 +13350,18 @@ EOF 25) root_use - send_stats "電報警報" - echo "TG-BOTモニタリングと早期警告機能" - echo "ビデオの紹介:https://youtu.be/vll-eb3z_ty" + send_stats "電報警告" + echo "TG-bot監視・早期警告機能" + echo "動画紹介:https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "ネイティブCPU、メモリ、ハードディスク、トラフィック、およびSSHログインのリアルタイム監視と早期警告を実現するために、TG Robot APIとユーザーIDを構成する必要があります。" + echo "ローカル CPU、メモリ、ハードディスク、トラフィック、SSH ログインのリアルタイム監視とアラートを実現するには、tg robot API とアラートを受信するユーザー ID を設定する必要があります。" echo "しきい値に達した後、ユーザーはユーザーに送信されます" - echo -e "${gl_hui}- トラフィックに関しては、サーバーの再起動が再計算されます -${gl_bai}" - read -e -p "必ず続行しますか? (y/n):" choice + echo -e "${gl_hui}- 通信量についてはサーバーを再起動すると再計算されます -${gl_bai}" + read -e -p "必ず続けますか? (y/n):" choice case "$choice" in [Yy]) - send_stats "電報警告が有効になっています" + send_stats "テレグラム警告が有効になっています" cd ~ install nano tmux bc jq check_crontab_installed @@ -13394,7 +13394,7 @@ EOF source ~/.profile clear - echo "TG-BOT早期警告システムが開始されました" + echo "TG-bot早期警戒システムが作動しました" echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" ;; [Nn]) @@ -13475,7 +13475,7 @@ EOF 41) clear - send_stats "メッセージボード" + send_stats "掲示板" echo "公式のメッセージ技術委員会ライオンをご覧ください。スクリプトについて何かアイデアがある場合は、メッセージを残してコミュニケーションをとってください!" echo "https://board.kejilion.pro" echo "パスワード:kejilion.sh" @@ -13485,33 +13485,33 @@ EOF root_use send_stats "ワンストップチューニング" - echo "ワンストップシステムの最適化" + echo "ワンストップのシステムチューニング" echo "------------------------------------------------" - echo "以下のコンテンツを運用・最適化していきます" + echo "以下が操作され、最適化されます" echo "1.システムを最新の状態に更新します" echo "2。システムジャンクファイルをクリーンアップします" - echo -e "3.仮想メモリを設定します${gl_huang}1G${gl_bai}" - echo -e "4. SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" + echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo -e "5.すべてのポートを開きます" - echo -e "6.電源を入れます${gl_huang}BBR${gl_bai}加速します" + echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速する" echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" - echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8国内:223.5.5.5${gl_bai}" + echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10。Linuxシステムのカーネルパラメーター最適化に切り替えます${gl_huang}バランスの取れた最適化モード${gl_bai}" + echo -e "10. Linux システムのカーネル パラメータの最適化が次のように切り替わります。${gl_huang}バランスのとれた最適化モード${gl_bai}" echo "------------------------------------------------" - read -e -p "ワンクリックメンテナンスは必ずありますか? (y/n):" choice + read -e -p "ワンクリックメンテナンスを実行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングスタート" + send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10。システムジャンクファイルをクリーンアップします" + echo -e "[${gl_lv}OK${gl_bai}】2/10。システムのジャンクファイルをクリーンアップする" echo "------------------------------------------------" add_swap 1024 @@ -13520,17 +13520,17 @@ EOF echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10。 SSHポート番号をに設定します${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】4/10。 SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}】5/10。すべてのポートを開く" + echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速します" + echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速する" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10。タイムゾーンをに設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】7/10。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13557,7 +13557,7 @@ EOF echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10。 Linuxシステムのカーネルパラメーターの最適化" + echo -e "[${gl_lv}OK${gl_bai}】10/10。 Linuxシステムのカーネルパラメータの最適化" echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" ;; @@ -13565,7 +13565,7 @@ EOF echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac @@ -13590,23 +13590,23 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトは、ユーザー機能に関するデータを収集し、スクリプトエクスペリエンスを最適化し、より楽しく便利な機能を作成します。" - echo "スクリプトバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、および使用される関数の名前を収集します。" + echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" - echo -e "現在のステータス:$status_message" + echo -e "現在のステータス:$status_message" echo "--------------------" echo "1。コレクションをオンにします" - echo "2。コレクションを閉じます" + echo "2. コレクションを閉じる" echo "--------------------" echo "0。前のメニューに戻ります" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "コレクションが有効になっています" + echo "収集が開始されました" send_stats "プライバシーとセキュリティコレクションが有効になっています" ;; 2) @@ -13614,7 +13614,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "コレクションは閉じた" - send_stats "プライバシーとセキュリティは収集のために閉鎖されています" + send_stats "プライバシーとセキュリティの収集がオフになっています" ;; *) break @@ -13630,11 +13630,11 @@ EOF 102) clear - send_stats "テックライオンスクリプトをアンインストールします" + send_stats "Tech Lion スクリプトをアンインストールする" echo "Tech Lion スクリプトをアンインストールする" echo "------------------------------------------------" - echo "kejilion スクリプトは、他の機能に影響を与えることなく完全にアンインストールされます。" - read -e -p "必ず続行しますか? (y/n):" choice + echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) @@ -13661,7 +13661,7 @@ EOF ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -13695,18 +13695,18 @@ linux_file() { echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" echo "15.ファイルを削除します" echo "------------------------" - echo "21。ファイルディレクトリの圧縮22。UNZIPファイルディレクトリ23。ファイルディレクトリの移動24。ファイルディレクトリをコピーする" + echo "21. ファイル ディレクトリの圧縮 22. ファイル ディレクトリの解凍 23. ファイル ディレクトリの移動 24. ファイル ディレクトリのコピー" echo "25。ファイルを別のサーバーに渡します" echo "------------------------" echo "0。前のメニューに戻ります" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "選択肢を入力してください:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "ディレクトリ名を入力してください:" dirname + read -e -p "ディレクトリ名を入力してください:" dirname cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" - send_stats "ディレクトリに移動します" + send_stats "ディレクトリを入力してください" ;; 2) # 创建目录 read -e -p "作成するにはディレクトリ名を入力してください。" dirname @@ -13715,9 +13715,9 @@ linux_file() { ;; 3) # 修改目录权限 read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可を入力してください(755など):" perm + read -e -p "許可(755など)を入力してください。" perm chmod "$perm" "$dirname" && echo "権限が変更されました" || echo "変更に失敗しました" - send_stats "ディレクトリ権限を変更します" + send_stats "ディレクトリの権限を変更する" ;; 4) # 重命名目录 read -e -p "現在のディレクトリ名を入力してください:" current_name @@ -13736,8 +13736,8 @@ linux_file() { ;; 11) # 创建文件 read -e -p "作成するにはファイル名を入力してください。" filename - touch "$filename" && echo "作成されたファイル" || echo "作成に失敗しました" - send_stats "ファイルを作成します" + touch "$filename" && echo "ファイルが作成されました" || echo "作成に失敗しました" + send_stats "ファイルの作成" ;; 12) # 编辑文件 read -e -p "編集するにはファイル名を入力してください:" filename @@ -13748,22 +13748,22 @@ linux_file() { 13) # 修改文件权限 read -e -p "ファイル名を入力してください:" filename read -e -p "権限を入力してください (例: 755):" perm - chmod "$perm" "$filename" && echo "許可が変更されました" || echo "変更に失敗しました" + chmod "$perm" "$filename" && echo "権限が変更されました" || echo "変更に失敗しました" send_stats "ファイル権限を変更します" ;; 14) # 重命名文件 read -e -p "現在のファイル名を入力してください:" current_name - read -e -p "新しいファイル名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ファイル名が変更されました" || echo "名前変更に失敗しました" - send_stats "ファイルの名前を変更します" + read -e -p "新しいファイル名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "ファイル名が変更されました" || echo "名前の変更に失敗しました" + send_stats "ファイル名の変更" ;; 15) # 删除文件 - read -e -p "削除するには、ファイル名を入力してください。" filename + read -e -p "削除するファイル名を入力してください:" filename rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" - send_stats "ファイルを削除します" + send_stats "ファイルの削除" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するファイル/ディレクトリ名を入力してください:" name + read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name install tar tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" send_stats "圧縮ファイル/ディレクトリ" @@ -13771,7 +13771,7 @@ linux_file() { 22) # 解压文件/目录 read -e -p "ファイル名(.tar.gz)を入力してください:" filename install tar - tar -xzvf "$filename" && echo "減圧$filename" || echo "減圧が失敗しました" + tar -xzvf "$filename" && echo "解凍された$filename" || echo "解凍に失敗しました" send_stats "ファイル/ディレクトリを解凍します" ;; @@ -13785,78 +13785,78 @@ linux_file() { read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" + echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリが移動されました$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" - send_stats "ファイルまたはディレクトリを移動します" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリの移動先$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + send_stats "ファイルまたはディレクトリを移動する" ;; 24) # 复制文件目录 - read -e -p "コピーするファイルまたはディレクトリのパスを入力してください:" src_path + read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path if [ ! -e "$src_path" ]; then echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました: ファイルまたはディレクトリが存在しません" + send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then - echo "エラー:ターゲットパスを入力してください。" + echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" continue fi # -Rオプションを使用して、ディレクトリを再帰的にコピーします - cp -r "$src_path" "$dest_path" && echo "ファイルまたはディレクトリがコピーされています$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" - send_stats "ファイルまたはディレクトリをコピーします" + cp -r "$src_path" "$dest_path" && echo "コピー先のファイルまたはディレクトリ$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" + send_stats "ファイルまたはディレクトリをコピーする" ;; 25) # 传送文件至远端服务器 - read -e -p "転送されるファイルパスを入力してください。" file_to_transfer + read -e -p "転送するファイル パスを入力してください:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "エラー:ファイルは存在しません。" send_stats "ファイルの転送に失敗しました:ファイルは存在しません" continue fi - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "リモートサーバーのIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then - echo "エラー:リモートサーバーIPを入力してください。" - send_stats "ファイル転送に失敗しました: リモート サーバー IP が入力されていません" + echo "エラー: リモート サーバーの IP を入力してください。" + send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" continue fi - read -e -p "リモートサーバーのユーザー名(デフォルトルート)を入力してください。" remote_user + read -e -p "リモート サーバーのユーザー名 (デフォルトの root) を入力してください:" remote_user remote_user=${remote_user:-root} - read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password + read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "エラー:リモートサーバーのパスワードを入力してください。" + echo "エラー: リモート サーバーのパスワードを入力してください。" send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" continue fi - read -e -p "ログインポートを入力してください(デフォルト22):" remote_port + read -e -p "ログイン ポートを入力してください (デフォルトは 22):" remote_port remote_port=${remote_port:-22} # 既知のホストの古いエントリをクリアします ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCPを使用してファイルを転送します + # scpを使用してファイルを転送する scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}スクリプトは最新バージョンに更新されました!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}スクリプトが最新バージョンに更新されました。${gl_huang}v$sh_v_new${gl_bai}" send_stats "スクリプトは最新です$sh_v_new" break_end ~/kejilion.sh @@ -14157,15 +14157,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自動更新が有効になり、スクリプトは毎日午前2時に自動的に更新されます!${gl_bai}" - send_stats "自動スクリプトの更新をオンにします" + echo -e "${gl_lv}自動更新がオンになっており、スクリプトは毎日午前 2 時に自動的に更新されます。${gl_bai}" + send_stats "スクリプトの自動更新を有効にする" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自動更新は閉じられています${gl_bai}" - send_stats "スクリプト自動更新を閉じます" + echo -e "${gl_lv}自動更新はオフになっています${gl_bai}" + send_stats "スクリプトの自動更新をオフにする" break_end ;; *) @@ -14187,24 +14187,24 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "テクノロジーライオンスクリプトツールボックスv$sh_v" +echo -e "テクノロジー ライオン スクリプト ツールボックス v$sh_v" echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}システム情報クエリ" +echo -e "${gl_kjlan}1. ${gl_bai}システム情報の問い合わせ" echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" echo -e "${gl_kjlan}7. ${gl_bai}ワープ管理" -echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプトコレクション" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud Scriptコレクション" -echo -e "${gl_huang}10. ${gl_bai}LDNMP Webサイトビルディング" +echo -e "${gl_kjlan}8. ${gl_bai}テストスクリプト集" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloudスクリプト・コレクション" +echo -e "${gl_huang}10. ${gl_bai}LDNMP Web サイトの構築" echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" echo -e "${gl_kjlan}13. ${gl_bai}システムツール" echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" -echo -e "${gl_kjlan}15. ${gl_bai}広告列" +echo -e "${gl_kjlan}15. ${gl_bai}広告コラム" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14216,12 +14216,12 @@ read -e -p "選択を入力してください:" choice case $choice in 1) linux_info ;; - 2) clear ; send_stats "システムアップデート" ; linux_update ;; + 2) clear ; send_stats "システムの更新" ; linux_update ;; 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "ワープ管理" ; install wget + 7) clear ; send_stats "反り管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -14248,49 +14248,49 @@ done k_info() { send_stats "Kコマンド参照ユースケース" echo "-------------------" -echo "ビデオの紹介:https://www.bilibili.com/video/bv1ib421e7it?t=0.1" +echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、Kコマンドリファレンスユースケースです。" echo "スクリプトkを開始します" -echo "ソフトウェアパッケージkをインストールしますnano wgetをインストールします| k nano wgetを追加| K nano wgetをインストールします" +echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" echo "システムKアップデートを更新| Kアップデート" -echo "クリーンシステムガベージkクリーン| kきれい" +echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルk dd |を再インストールしますk再インストール" echo "BBR3コントロールパネルK BBR3 | K BBRV3" echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" echo "仮想メモリ k スワップを設定 2048" -echo "仮想タイムゾーンKタイムアジア/上海|を設定しますKタイムゾーンアジア/上海" -echo "システムリサイクルビンKトラッシュ| K HSZ | Kリサイクルビン" -echo "システムバックアップ関数Kバックアップ| k bf | Kバックアップ" +echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" +echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" +echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" echo "SSHリモート接続ツールK SSH | Kリモート接続" -echo "rsyncリモート同期ツールk rsync | Kリモート同期" -echo "ハードディスク管理ツールKディスク| Kハードディスク管理" -echo "イントラネット浸透(サーバー側)K FRP" -echo "イントラネット浸透(クライアント)K FRPC" -echo "ソフトウェアStart K Start SSHD | k sshdを開始します" +echo "rsync リモート同期ツール k rsync | k リモート同期" +echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" +echo "イントラネット普及率 (サーバー) k frps" +echo "イントラネット浸透率 (クライアント) k frpc" +echo "ソフトウェア起動 k start sshd | sshdを起動します" echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" echo "ソフトウェア再起動k再起動sshd | k再起動sshd" -echo "ソフトウェアステータスビューKステータスSSHD | KステータスSSHD" -echo "ソフトウェアブートk dockerを有効にする| K AutoStart Docke | Kスタートアップドッカー" -echo "ドメイン名証明書アプリケーション k ssl" -echo "ドメイン名証明書の有効期限クエリK SSL PS" -echo "Docker Management Plane K Docker" +echo "ソフトウェアのステータスを確認します。 k ステータス sshd | kステータスsshd" +echo "k ドッカーを有効にする | k 自動開始ドッカー | k ソフトウェアの起動時に Docker を有効にする" +echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書の有効期限のクエリ k ssl ps" +echo "docker 管理プレーン k docker" echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" echo "Docker Container Management K Docker PS | K Dockerコンテナ" echo "Docker Image Management K Docker IMG | K Docker画像" echo "LDNMP サイト管理 k Web" -echo "LDNMPキャッシュクリーンアップK Webキャッシュ" +echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" -echo "ロードバランスkロードバランス| kロードバランシングをインストールします" -echo "ファイアウォールパネルk fhq | kファイアウォール" -echo "オープンポートK DKDK 8080 | Kオープンポート8080" -echo "ポートK GBDK 7800を閉じる| kポート7800を閉じます" +echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" +echo "ファイアウォール パネル k fhq |k ファイアウォール" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" -echo "コマンドお気に入りk fav | Kコマンドのお気に入り" +echo "コマンド お気に入り k お気に入り | k コマンドのお気に入り" echo "アプリ市場管理Kアプリ" -echo "アプリケーション番号クイックマネジメントKアプリ26 | Kアプリ1Panel | KアプリNPM" +echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "システム情報を表示 k info" } @@ -14300,7 +14300,7 @@ if [ "$#" -eq 0 ]; then # パラメーターがない場合は、インタラクティブロジックを実行します kejilion_sh else - # パラメーターがある場合は、対応する関数を実行します + # パラメータがある場合は、対応する関数を実行します case $1 in install|add|安装) shift @@ -14309,7 +14309,7 @@ else ;; remove|del|uninstall|卸载) shift - send_stats "ソフトウェアをアンインストールします" + send_stats "ソフトウェアのアンインストール" remove "$@" ;; update|更新) @@ -14375,13 +14375,13 @@ else swap) shift - send_stats "仮想メモリをすばやくセットアップする" + send_stats "仮想メモリをすばやく設定します" add_swap "$@" ;; time|时区) shift - send_stats "タイムゾーンをすばやく設定します" + send_stats "タイムゾーンを素早く設定" set_timedate "$@" ;; @@ -14450,14 +14450,14 @@ else enable|autostart|开机启动) shift - send_stats "ソフトウェアが起動します" + send_stats "起動時にソフトウェアが自動的に起動します" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "証明書のステータスを確認してください" + send_stats "証明書ステータスの表示" ssl_ps elif [ -z "$1" ]; then add_ssl @@ -14478,7 +14478,7 @@ else install_docker ;; ps|容器) - send_stats "クイックコンテナ管理" + send_stats "迅速なコンテナ管理" docker_ps ;; img|镜像) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 9c65414f3..4bffecd80 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -34,7 +34,7 @@ quanju_canshu -# 명령을 실행할 함수를 정의합니다 +# 명령을 실행하는 함수 정의 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 기능 매장 지점 정보를 수집하는 기능, 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 컴퓨터 국가 및 사용자가 사용하는 기능 이름을 기록합니다. 그들은 절대적으로 민감한 정보를 포함하지 않습니다. 제발 나를 믿으세요! +# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. # 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. @@ -114,11 +114,11 @@ CheckFirstRun_false() { # 사용자에게 이용 약관에 동의하라는 메시지 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolbox에 오신 것을 환영합니다${gl_bai}" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" echo "스크립트를 처음 사용하면 사용자 라이센스 계약을 읽고 동의하십시오." - echo "사용자 라이센스 계약 : https://blog.kejilion.pro/user-license-agreement/" + echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "위의 용어에 동의하십니까? (Y/N) :" user_input + read -r -p "위의 약관에 동의하십니까? (예/아니요):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -170,13 +170,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "패키지 매개 변수는 제공되지 않습니다!" + echo "패키지 매개변수가 제공되지 않았습니다!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}설치$package...${gl_bai}" + echo -e "${gl_huang}설치 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "알 수없는 패키지 관리자!" + echo "알 수 없는 패키지 관리자입니다!" return 1 fi fi @@ -220,11 +220,11 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}힌트:${gl_bai}불충분 한 디스크 공간!" + echo -e "${gl_huang}힌트:${gl_bai}디스크 공간이 부족합니다!" echo "현재 사용 가능한 공간: $((available_space_mb/1024))G" echo "최소 수요 공간 :${required_gb}G" - echo "설치를 계속할 수 없습니다. 디스크 공간을 청소하고 다시 시도하십시오." - send_stats "디스크 공간이 부족합니다." + echo "설치를 계속할 수 없습니다. 디스크 공간을 비운 후 다시 시도하십시오." + send_stats "불충분 한 디스크 공간" break_end kejilion fi @@ -238,12 +238,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "패키지 매개변수가 제공되지 않았습니다!" + echo "패키지 매개 변수는 제공되지 않습니다!" return 1 fi for package in "$@"; do - echo -e "${gl_huang}제거$package...${gl_bai}" + echo -e "${gl_huang}제거 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -268,7 +268,7 @@ remove() { } -# 다양한 분포에 적합한 범용 SystemCTL 기능 +# 다양한 배포판에 적합한 범용 systemctl 기능 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -297,7 +297,7 @@ start() { if [ $? -eq 0 ]; then echo "$1서비스가 시작되었습니다." else - echo "오류 : 시작$1서비스가 실패했습니다." + echo "오류: 시작$1서비스가 실패했습니다." fi } @@ -305,7 +305,7 @@ start() { stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 중단되었습니다." + echo "$1서비스가 중지되었습니다." else echo "오류 : 중지$1서비스가 실패했습니다." fi @@ -427,7 +427,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}도커 환경 설치 중...${gl_bai}" + echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -506,37 +506,37 @@ while true; do echo "도커 컨테이너 목록" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "컨테이너 작동" + echo "컨테이너 운영" echo "------------------------" echo "1. 새 컨테이너를 만듭니다" echo "------------------------" - echo "2. 지정된 컨테이너를 시작하십시오. 6. 모든 컨테이너를 시작하십시오" - echo "3. 지정된 컨테이너를 중지하십시오. 7. 모든 컨테이너를 중지하십시오" + echo "2. 지정된 컨테이너 시작 6. 모든 컨테이너 시작" + echo "3. 지정된 컨테이너를 중지합니다. 7. 모든 컨테이너를 중지합니다." echo "4. 지정된 컨테이너 삭제 8. 모든 컨테이너 삭제" echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" echo "------------------------" - echo "11. 지정된 컨테이너를 입력합니다. 12. 컨테이너 로그를 봅니다." - echo "13. 컨테이너 네트워크보기 14. 컨테이너 점유보기" + echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" + echo "13. 컨테이너 네트워크 확인 14. 컨테이너 점유율 확인" echo "------------------------" echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "새 컨테이너를 만듭니다" + send_stats "새 컨테이너 만들기" read -e -p "창조 명령을 입력하십시오 :" dockername $dockername ;; 2) send_stats "지정된 컨테이너를 시작하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) - send_stats "지정된 컨테이너를 중지하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "지정된 컨테이너 중지" + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) @@ -546,7 +546,7 @@ while true; do ;; 5) send_stats "지정된 컨테이너를 다시 시작하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) @@ -554,11 +554,11 @@ while true; do docker start $(docker ps -a -q) ;; 7) - send_stats "모든 컨테이너를 중지하십시오" + send_stats "모든 컨테이너 중지" docker stop $(docker ps -q) ;; 8) - send_stats "모든 컨테이너를 삭제하십시오" + send_stats "모든 컨테이너 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -567,7 +567,7 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -577,13 +577,13 @@ while true; do ;; 11) send_stats "컨테이너를 입력하십시오" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + read -e -p "컨테이너 이름을 입력하세요:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) send_stats "컨테이너 로그를 봅니다" - read -e -p "컨테이너 이름을 입력하십시오 :" dockername + read -e -p "컨테이너 이름을 입력하세요:" dockername docker logs $dockername break_end ;; @@ -622,7 +622,7 @@ while true; do ;; 16) - send_stats "컨테이너 포트 액세스 차단" + send_stats "컨테이너 포트 접근 차단" read -e -p "컨테이너 이름을 입력하십시오 :" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" @@ -656,7 +656,7 @@ while true; do read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - send_stats "거울을 당기십시오" + send_stats "이미지 가져오기" read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" @@ -664,7 +664,7 @@ while true; do done ;; 2) - send_stats "이미지를 업데이트하십시오" + send_stats "이미지 업데이트" read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames for name in $imagenames; do echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" @@ -673,13 +673,13 @@ while true; do ;; 3) send_stats "거울을 삭제하십시오" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "모든 이미지를 삭제합니다" + send_stats "모든 이미지 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -761,11 +761,11 @@ install_crontab() { ;; esac else - echo "운영 체제를 결정할 수 없습니다." + echo "운영 체제를 확인할 수 없습니다." return fi - echo -e "${gl_lv}Crontab이 설치되고 Cron 서비스가 실행 중입니다.${gl_bai}" + echo -e "${gl_lv}crontab이 설치되어 있고 cron 서비스가 실행 중입니다.${gl_bai}" } @@ -788,7 +788,7 @@ docker_ipv6_on() { # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 구성 업데이트 및 IPv6을 활성화하십시오 + # 구성 업데이트 및 IPv6 활성화 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else @@ -797,7 +797,7 @@ docker_ipv6_on() { # 원래 구성과 새로운 구성을 비교합니다 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}IPv6 액세스가 현재 활성화되어 있습니다${gl_bai}" + echo -e "${gl_huang}현재 IPv6 액세스가 활성화되어 있습니다.${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -814,7 +814,7 @@ docker_ipv6_off() { # 구성 파일이 있는지 확인하십시오 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}구성 파일이 존재하지 않습니다${gl_bai}" + echo -e "${gl_hong}구성 파일이 존재하지 않습니다.${gl_bai}" return fi @@ -824,7 +824,7 @@ docker_ipv6_off() { # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 현재 IPv6 상태를 확인하십시오 + # 현재 ipv6 상태 확인 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') # 원래 구성과 새로운 구성을 비교합니다 @@ -879,7 +879,7 @@ open_port() { install iptables for port in "${ports[@]}"; do - # 기존 마감 규칙을 삭제하십시오 + # 기존 종료 규칙 삭제 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null @@ -890,12 +890,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "포트가 열렸습니다$port" + echo "포트가 열렸습니다.$port" fi done save_iptables_rules - send_stats "포트가 열렸습니다" + send_stats "포트가 열렸습니다." } @@ -909,7 +909,7 @@ close_port() { install iptables for port in "${ports[@]}"; do - # 기존 열린 규칙을 삭제합니다 + # 기존 공개 규칙 삭제 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null @@ -928,7 +928,7 @@ close_port() { iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 새로운 규칙을 먼저 삽입하십시오 + # 첫 번째 규칙에 새 규칙을 삽입합니다. iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT @@ -947,13 +947,13 @@ allow_ip() { install iptables for ip in "${ips[@]}"; do - # 기존 차단 규칙을 삭제하십시오 + # 기존 차단 규칙 삭제 iptables -D INPUT -s $ip -j DROP 2>/dev/null # 허용 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP 출시$ip" + echo "공개된 IP$ip" fi done @@ -971,18 +971,18 @@ block_ip() { install iptables for ip in "${ips[@]}"; do - # 기존 허용 규칙을 삭제합니다 + # 기존 허용 규칙 삭제 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null # 차단 규칙을 추가하십시오 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP가 차단됨$ip" + echo "IP 차단$ip" fi done save_iptables_rules - send_stats "IP 차단" + send_stats "IP가 차단됨" } @@ -1002,10 +1002,10 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDOS 방어를 켜십시오" + send_stats "DDoS 방어 켜기" } -# DDOS 방어를 끕니다 +# DDoS 방어 끄기 disable_ddos_defense() { # 방어 DDO를 끄십시오 iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null @@ -1042,7 +1042,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류: 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "오류 : 다운로드$country_codeIP 영역 파일 실패" continue fi @@ -1062,7 +1062,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류: 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" continue fi @@ -1075,7 +1075,7 @@ manage_country_rules() { iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - echo "성공적으로 허용됩니다$country_codeIP 주소" + echo "허용되었습니다.$country_codeIP 주소" rm "${country_code,,}.zone" ;; @@ -1086,7 +1086,7 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "성공적으로 해제했습니다$country_codeIP 주소 제한" + echo "성공적으로 제거되었습니다$country_codeIP 주소 제한" ;; *) @@ -1118,7 +1118,7 @@ iptables_panel() { echo "" echo "방화벽 관리" echo "------------------------" - echo "1. 지정 포트 열기 2. 지정 포트 닫기" + echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" @@ -1126,12 +1126,12 @@ iptables_panel() { echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" - echo "13. DDOS 방어 시작 14. DDOS 방어를 끄십시오" + echo "13. DDOS 방어 시작 14. DDOS 방어 끄기" echo "------------------------" - echo "15. 지정된 국가 IP 16. 지정된 국가 IP 만 허용됩니다." - echo "17. 지정된 국가에서 IP 제한을 해제합니다" + echo "15. 특정 국가 IP 차단 16. 특정 국가 IP만 허용" + echo "17. 지정된 국가에서 IP 제한을 해제합니다." echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in @@ -1141,7 +1141,7 @@ iptables_panel() { send_stats "지정된 포트를 엽니 다" ;; 2) - read -e -p "닫힌 포트 번호를 입력하세요:" c_port + read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port close_port $c_port send_stats "지정된 포트를 닫습니다" ;; @@ -1162,7 +1162,7 @@ iptables_panel() { send_stats "모든 포트 열기" ;; 4) - # 모든 포트를 닫습니다 + # 모든 포트를 닫으세요 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1180,17 +1180,17 @@ iptables_panel() { 5) # IP 화이트리스트 - read -e -p "릴리스하려면 IP 또는 IP 세그먼트를 입력하십시오." o_ip + read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip allow_ip $o_ip ;; 6) # IP 블랙리스트 - read -e -p "차단 된 IP 또는 IP 세그먼트를 입력하십시오." c_ip + read -e -p "차단된 IP 또는 IP 범위를 입력하세요." c_ip block_ip $c_ip ;; 7) # 지정된 IP를 지우십시오 - read -e -p "청산 된 IP를 입력하십시오 :" d_ip + read -e -p "삭제된 IP를 입력하세요:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1204,7 +1204,7 @@ iptables_panel() { send_stats "핑을 허용하십시오" ;; 12) - # 핑 비활성화 + # 핑을 비활성화합니다 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1223,7 +1223,7 @@ iptables_panel() { send_stats "허용 국가$country_codeIP" ;; 16) - read -e -p "허용 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code + read -e -p "허용되는 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분할 수 있음)." country_code manage_country_rules allow $country_code send_stats "나라를 차단하십시오$country_codeIP" ;; @@ -1253,20 +1253,20 @@ add_swap() { # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 모든 스왑 파티션을 반복하고 삭제하십시오 + # 모든 스왑 파티션을 탐색하고 삭제합니다. for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfile이 더 이상 사용되지 않도록하십시오 + # /swapfile이 더 이상 사용되지 않는지 확인하세요. swapoff /swapfile # 이전 /스왑 파일을 삭제하십시오 rm -f /swapfile - # 새 스왑 파티션을 만듭니다 + # 새로운 스왑 파티션 생성 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1281,7 +1281,7 @@ add_swap() { rc-update add local fi - echo -e "가상 메모리 크기가 크기가 커졌습니다${gl_huang}${new_swap}${gl_bai}M" + echo -e "가상 메모리 크기가 다음과 같이 조정되었습니다.${gl_huang}${new_swap}${gl_bai}M" } @@ -1291,7 +1291,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야하는지 확인하십시오 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1321,7 +1321,7 @@ ldnmp_v() { local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전 받기 + # Redis 버전을 얻으십시오 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1334,7 +1334,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 필요한 디렉토리 및 파일을 만듭니다 + # 필요한 디렉토리 및 파일 생성 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1409,7 +1409,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "갱신 작업이 업데이트되었습니다" + echo "갱신 작업이 업데이트되었습니다." } @@ -1446,14 +1446,14 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming공개 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming공개키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" echo -e "${gl_huang}인증서 저장 경로${gl_bai}" - echo "공개 키 :/etc/letsencrypt/live/$yuming/fullchain.pem" + echo "공개 키: /etc/letsencrypt/live/$yuming/fullchain.pem" echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1519,19 +1519,19 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "도메인 이름 인증서에 대한 성공적인 응용 프로그램" + send_stats "도메인 이름 인증서 신청이 성공했습니다." else send_stats "도메인 이름 인증서 신청에 실패했습니다" echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." - echo -e "1. 도메인 이름 철자 오류 ➠ 도메인 이름이 올바르게 입력되었는지 확인하십시오." - echo -e "2. DNS 해상도 문제 ➠ 도메인 이름 이이 서버 IP로 올바르게 해결되었는지 확인합니다." + echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." + echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." - echo -e "4. 방화벽 제한 ➠ 검증에 액세스 할 수 있도록 포트 80/443이 열려 있는지 확인" + echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." break_end clear - echo "다시 배포를 시도하십시오$webname" + echo "다시 배포해 보세요.$webname" add_yuming install_ssltls certs_status @@ -1551,7 +1551,7 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 해결합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "먼저 도메인 이름을 로컬 IP로 확인합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "귀하의 IP 또는 확인된 도메인 이름을 입력하십시오:" yuming } @@ -1636,11 +1636,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "로그인 정보 :" - echo "사용자 이름 :$dbuse" + echo "로그인 정보:" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo - send_stats "시작$ldnmp_pods" + send_stats "시작하다$ldnmp_pods" } @@ -1650,19 +1650,19 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 구성 파일이 있는지 확인하십시오 + # 구성 파일이 있는지 확인하십시오. if [ -f "$CONFIG_FILE" ]; then # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" # Zone_ids를 배열로 변환합니다 ZONE_IDS=($ZONE_IDS) else - # 캐시 청소 여부를 사용자에게 프롬프트하십시오 + # 캐시를 지울지 여부를 사용자에게 묻습니다. read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer if [[ "$answer" == "y" ]]; then - echo "CF 정보가 저장됩니다$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다" - read -e -p "API_Token을 입력하십시오 :" API_TOKEN - read -e -p "CF 사용자 이름을 입력하세요:" EMAIL + echo "CF 정보는 다음 위치에 저장됩니다.$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다." + read -e -p "API_TOKEN을 입력하세요:" API_TOKEN + read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS mkdir -p /home/web/config/ @@ -1670,9 +1670,9 @@ cf_purge_cache() { fi fi - # 각 Zone_ID를 루프하고 CLEAR CACHE 명령을 실행하십시오. + # 각 zone_id를 반복하고 캐시 지우기 명령을 실행합니다. for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "Zone_ID의 캐시 지우기 :$ZONE_ID" + echo "zone_id에 대한 캐시 지우기:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1680,13 +1680,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "캐시 클리어 요청이 전송되었습니다." + echo "캐시 삭제 요청이 전송되었습니다." } web_cache() { - send_stats "사이트 캐시를 정리하십시오" + send_stats "사이트 캐시 지우기" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1699,7 +1699,7 @@ web_del() { send_stats "사이트 데이터 삭제" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하십시오 (여러 도메인 이름이 공간별로 분리됩니다)." yuming_list + read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1712,11 +1712,11 @@ web_del() { rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 도메인 이름을 데이터베이스 이름으로 변환합니다 + # 도메인 이름을 데이터베이스 이름으로 변환 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. + # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. echo "데이터베이스 삭제 :$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1733,7 +1733,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 모드 매개 변수에 따라 WAF를 켜거나 끄기로 결정 + # 모드 매개변수에 따라 WAF를 켤지 끌지 결정합니다. if [ "$mode" == "on" ]; then # WAF 켜기 : 주석을 제거하십시오 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1745,11 +1745,11 @@ nginx_waf() { sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1823,12 +1823,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 이전 정의 삭제 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1885,7 +1885,7 @@ nginx_br() { return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1922,7 +1922,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Zstd를 닫습니다 : 주석을 추가하십시오 + # Zstd 닫기: 설명 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1989,25 +1989,25 @@ web_security() { check_waf_status check_cf_mode clear - echo -e "서버 웹 사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "서버 웹사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 방어 프로그램을 설치하십시오" echo "------------------------" - echo "5. SSH 차단 레코드보기 6. 웹 사이트 차단 레코드보기" + echo "5. SSH 차단 기록 보기 6. 웹사이트 차단 기록 보기" echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" echo "------------------------" - echo "11. 인터셉트 매개 변수 구성 12. 차단 된 모든 IP를 지우십시오" + echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" echo "------------------------" echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" echo "------------------------" - echo "31. WAF 32를 켜십시오. WAF를 끄십시오" + echo "31. WAF 켜기 32. WAF 끄기" echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2072,7 +2072,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban 방어 프로그램이 제거되었습니다." break ;; @@ -2088,11 +2088,11 @@ web_security() { ;; 21) - send_stats "CloudFlare 모드" + send_stats "클라우드플레어 모드" echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." echo "https://dash.cloudflare.com/login" read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2112,15 +2112,15 @@ web_security() { 22) send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 부하가 감지되면 방패가 자동으로 켜지고 5 초 동안 낮은 부하가 자동으로 꺼집니다.${gl_bai}" + echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" echo "--------------" echo "CF 매개 변수 가져 오기 :" echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CF 계정 번호를 입력하십시오." cfuser - read -e -p "CF의 글로벌 API 키를 입력하십시오." cftoken + read -e -p "CF의 계좌번호를 입력하세요:" cfuser + read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID cd ~ @@ -2138,9 +2138,9 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "고 부하 자동 방패 오프닝 스크립트가 추가되었습니다" + echo "고부하 자동 쉴드 오픈 스크립트가 추가되었습니다." else - echo "자동 방패 스크립트가 이미 존재합니다. 추가 할 필요가 없습니다." + echo "자동 방패 열기 스크립트가 이미 있으므로 추가할 필요가 없습니다." fi ;; @@ -2154,7 +2154,7 @@ web_security() { 32) nginx_waf off echo "사이트 waf가 닫혔습니다" - send_stats "사이트 waf가 닫혔습니다" + send_stats "사이트 WAF가 다운되었습니다" ;; 33) @@ -2198,21 +2198,21 @@ check_nginx_compression() { CONFIG_FILE="/home/web/nginx.conf" - # ZSTD가 활성화되어 있고 주석이 없는지 확인하십시오 (전체 라인은 ZSTD 켜기로 시작합니다.) + # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status=" zstd压缩已开启" else zstd_status="" fi - # Brotli가 활성화되어 있고 댓글이 없는지 확인하십시오 + # brotli가 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else br_status="" fi - # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. + # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2229,17 +2229,17 @@ web_optimization() { check_nginx_compression clear send_stats "LDNMP 환경을 최적화하십시오" - echo -e "LDNMP 환경을 최적화하십시오${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + echo -e "LDNMP 환경 최적화${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" echo "------------------------" echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" - echo "5. BR 압축 켜기 6. BR 압축 끄기" + echo "5. br 압축을 켭니다. 6. br 압축을 끕니다." echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) send_stats "사이트 표준 모드" @@ -2316,7 +2316,7 @@ web_optimization() { restart_redis optimize_web_server - echo "LDNMP 환경은 고성능 모드로 설정되었습니다" + echo "LDNMP 환경이 고성능 모드로 설정되었습니다." ;; 3) @@ -2386,7 +2386,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "액세스 주소 :" +echo "방문 주소:" ip_address @@ -2424,7 +2424,7 @@ check_docker_image_update() { return fi - # 컨테이너 생성 시간과 이미지 이름을 얻으십시오 + # 컨테이너의 생성 시간과 이미지 이름을 가져옵니다. local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) @@ -2439,16 +2439,16 @@ check_docker_image_update() { # 공식 이미지에 대한 지원을 추가하십시오 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub API에서 이미지 게시 시간을 얻으십시오 + # Docker Hub API에서 이미지 릴리스 시간 가져오기 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득 시간을 확인하십시오 + # 획득한 시간을 확인 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # 타임 스탬프를 비교하십시오 + # 타임스탬프 비교 if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2477,7 +2477,7 @@ block_container_port() { install iptables - # 다른 모든 IP를 점검하고 차단하십시오 + # 다른 모든 IP를 확인하고 차단하세요. if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi @@ -2494,7 +2494,7 @@ block_container_port() { - # 다른 모든 IP를 점검하고 차단하십시오 + # 다른 모든 IP를 확인하고 차단하세요. if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi @@ -2504,7 +2504,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 로컬 네트워크 127.0.0.0/8 확인 및 허용 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2514,7 +2514,7 @@ block_container_port() { fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "IP+포트가 서비스 접근을 차단했습니다." save_iptables_rules } @@ -2540,7 +2540,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2559,7 +2559,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 공개하기위한 규칙을 지우십시오 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2575,7 +2575,7 @@ clear_container_rules() { fi - echo "IP+포트로 서비스 접속이 허용되었습니다" + echo "IP+포트는 서비스에 액세스 할 수있었습니다" save_iptables_rules } @@ -2589,7 +2589,7 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" return 1 fi @@ -2597,17 +2597,17 @@ block_host_port() { install iptables - # 다른 모든 IP 액세스를 거부했습니다 + # 다른 모든 IP의 접근을 거부 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 지정된 IP에 대한 접근을 허용 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 로컬 액세스 허용 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2621,12 +2621,12 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 지정된 IP 액세스를 허용합니다 + # 지정된 IP에 대한 접근을 허용 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스 허용 + # 로컬 액세스를 허용합니다 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2648,7 +2648,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류 : 액세스 할 수있는 포트 번호와 IP를 제공하십시오." + echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." echo "사용법:clear_host_port_rules <포트 번호> <허용 IP>" return 1 fi @@ -2656,23 +2656,23 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 로컬 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 다른 모든 IP 액세스를 차단하는 명확한 규칙 + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2688,7 +2688,7 @@ clear_host_port_rules() { fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules } @@ -2750,11 +2750,11 @@ while true; do echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) setup_docker_dir @@ -2771,7 +2771,7 @@ while true; do add_app_id clear - echo "$docker_name설치" + echo "$docker_name설치 완료" check_docker_app_ip echo "" $docker_use @@ -2786,7 +2786,7 @@ while true; do add_app_id clear - echo "$docker_name설치" + echo "$docker_name설치 완료" check_docker_app_ip echo "" $docker_use @@ -2801,11 +2801,11 @@ while true; do sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다" - send_stats "제거하십시오$docker_name" + send_stats "제거$docker_name" ;; 5) - echo "${docker_name}도메인 액세스 설정" + echo "${docker_name}도메인 이름 액세스 설정" send_stats "${docker_name}도메인 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -2813,7 +2813,7 @@ while true; do ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; @@ -2823,7 +2823,7 @@ while true; do ;; 8) - send_stats "IP 액세스를 차단하십시오${docker_name}" + send_stats "IP 접근 차단${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2902,7 +2902,7 @@ docker_app_plus() { block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; 7) @@ -2995,17 +2995,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 세션이 존재하는지 확인하는 기능 +# 세션이 존재하는지 확인하는 함수 session_exists() { tmux has-session -t $1 2>/dev/null } -# 존재하지 않는 세션 이름이 발견 될 때까지 루프 +# 존재하지 않는 세션 이름을 찾을 때까지 반복 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 새로운 TMUX 세션을 만듭니다 +# 새 tmux 세션 만들기 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3063,7 +3063,7 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "다시 시작" + echo "다시 시작됨" reboot ;; *) @@ -3111,7 +3111,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear send_stats "LDNMP 환경을 다시 설치할 수 없습니다" - echo -e "${gl_huang}힌트:${gl_bai}웹 사이트 구성 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" + echo -e "${gl_huang}힌트:${gl_bai}홈페이지 구축 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" break_end linux_ldnmp fi @@ -3124,7 +3124,7 @@ cd ~ send_stats "LDNMP 환경을 설치하십시오" root_use clear -echo -e "${gl_huang}LDNMP 환경이 설치되지 않았으며 LDNMP 환경 설치를 시작하십시오 ...${gl_bai}" +echo -e "${gl_huang}LDNMP 환경이 설치되지 않았습니다. LDNMP 환경 설치를 시작합니다...${gl_bai}" check_disk_space 3 /home check_port install_dependency @@ -3152,8 +3152,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "Nginx가 설치되었습니다" -echo -e "현재 버전 :${gl_huang}v$nginx_version${gl_bai}" +echo "nginx가 설치되었습니다" +echo -e "현재 버전:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3164,7 +3164,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "먼저 LDNMP 환경을 설치하십시오" + send_stats "먼저 LDNMP 환경을 설치해 주세요" ldnmp_install_all fi @@ -3185,7 +3185,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신 것$webname세워짐!" + echo "당신의$webname세워짐!" echo "https://$yuming" echo "------------------------" echo "$webname설치 정보는 다음과 같습니다." @@ -3194,7 +3194,7 @@ ldnmp_web_on() { nginx_web_on() { clear - echo "당신 것$webname세워짐!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" } @@ -3374,19 +3374,19 @@ ldnmp_web_status() { echo "------------------------" echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" - echo "5. 액세스 로그보기 6. 오류 로그보기" - echo "7. 글로벌 구성 편집 8. 사이트 구성 편집" - echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서보기" + echo "5. 접속 로그 보기 6. 오류 로그 보기" + echo "7. 전역 구성 편집 8. 사이트 구성 편집" + echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서 보기" echo "------------------------" - echo "20. 지정된 사이트 데이터를 삭제합니다" + echo "20. 특정 사이트 데이터 삭제" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) send_stats "도메인 이름 인증서를 신청하십시오" - read -e -p "도메인 이름을 입력하세요:" yuming + read -e -p "도메인 이름을 입력하십시오 :" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3395,8 +3395,8 @@ ldnmp_web_status() { ;; 2) - send_stats "사이트 도메인 이름을 변경하십시오" - echo -e "${gl_hong}적극 권장 :${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" + send_stats "사이트 도메인 이름 변경" + echo -e "${gl_hong}적극 권장:${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming read -e -p "새 도메인 이름을 입력하십시오 :" yuming install_certbot @@ -3421,7 +3421,7 @@ ldnmp_web_status() { done done - # 웹 사이트 디렉토리 교체 + # 웹사이트 디렉토리 교체 mv /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3442,10 +3442,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "연결된 사이트 만들기" + send_stats "관련 사이트를 만듭니다" echo -e "액세스하려면 새 도메인 이름을 기존 사이트에 연결하세요." read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + read -e -p "새 도메인 이름을 입력하세요:" yuming install_certbot install_ssltls certs_status @@ -3464,7 +3464,7 @@ ldnmp_web_status() { break_end ;; 6) - send_stats "오류 로그 보기" + send_stats "오류 로그를 봅니다" tail -n 200 /home/web/log/nginx/error.log break_end ;; @@ -3487,7 +3487,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "사이트 데이터를 봅니다" + send_stats "사이트 데이터 보기" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3523,7 +3523,7 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}요즘 인기 있고 강력한 운영 및 유지 관리 패널입니다." + echo "${panelname}대중적이고 강력한 운영 및 유지 관리 관리 패널입니다." echo "공식 웹 사이트 소개 :$panelurl " echo "" @@ -3598,8 +3598,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRP 서버를 설치하십시오" - # 임의의 포트 및 자격 증명을 생성합니다 + send_stats "FRP 서버 설치" + # 임의의 포트 및 자격 증명 생성 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -3620,15 +3620,15 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 출력 생성 정보 ip_address echo "------------------------" - echo "클라이언트 배포에 필요한 매개 변수" - echo "서비스 IP :$ipv4_address" + echo "클라이언트 배포에 필요한 매개변수" + echo "서비스 IP:$ipv4_address" echo "token: $token" echo echo "FRP 패널 정보" - echo "FRP 패널 주소 : http : //$ipv4_address:$dashboard_port" + echo "FRP 패널 주소: http://$ipv4_address:$dashboard_port" echo "FRP 패널 사용자 이름 :$dashboard_user" echo "FRP 패널 비밀번호 :$dashboard_pwd" echo @@ -3641,8 +3641,8 @@ EOF configure_frpc() { send_stats "FRP 클라이언트를 설치하십시오" - read -e -p "외부 네트워크 도킹 IP를 입력하십시오." server_addr - read -e -p "외부 네트워크 도킹 토큰을 입력하십시오." token + read -e -p "외부 네트워크 도킹 IP를 입력하세요." server_addr + read -e -p "외부 네트워크 도킹 토큰을 입력하세요." token echo mkdir -p /home/frp @@ -3664,15 +3664,15 @@ EOF add_forwarding_service() { send_stats "FRP 인트라넷 서비스 추가" # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 - read -e -p "서비스 이름을 입력하십시오 :" service_name - read -e -p "전달 유형 (TCP/UDP)을 입력하십시오 [기본 TCP 입력] :" service_type + read -e -p "서비스 이름을 입력하세요:" service_name + read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip + read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "인트라넷 포트를 입력하십시오 :" local_port - read -e -p "외부 네트워크 포트를 입력하십시오 :" remote_port + read -e -p "인트라넷 포트를 입력하십시오:" local_port + read -e -p "외부 네트워크 포트를 입력하세요:" remote_port - # 구성 파일에 사용자 입력을 쓰십시오 + # 구성 파일에 사용자 입력 쓰기 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -3683,7 +3683,7 @@ remote_port = ${remote_port} EOF # 출력 생성 정보 - echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다" + echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -3696,10 +3696,10 @@ EOF delete_forwarding_service() { send_stats "FRP 인트라넷 서비스를 삭제하십시오" # 삭제해야 하는 서비스 이름을 입력하라는 메시지를 사용자에게 표시합니다. - read -e -p "삭제 해야하는 서비스 이름을 입력하십시오." service_name + read -e -p "삭제할 서비스 이름을 입력하세요:" service_name # sed를 사용하여 서비스 및 관련 구성 삭제 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "제공하다$service_namefrpc.toml에서 성공적으로 삭제되었습니다" + echo "제공하다$service_namefrpc.toml에서 성공적으로 제거되었습니다." docker restart frpc @@ -3730,7 +3730,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 서비스 정보가있는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. + # 서비스 정보가 이미 존재하는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3743,7 +3743,7 @@ list_forwarding_services() { if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 이전 값을 지우십시오 + # 이전 값 지우기 local_ip="" local_port="" remote_port="" @@ -3785,17 +3785,17 @@ list_forwarding_services() { -# FRP 서버 포트를 가져옵니다 +# FRP 서버 포트 가져오기 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } # 액세스 주소를 생성합니다 generate_access_urls() { - # 모든 포트를 먼저 얻으십시오 + # 먼저 모든 포트를 확보하십시오. get_frp_ports - # 8055/8056 이외의 포트가 있는지 확인하십시오 + # 8055/8056 이외의 포트가 있는지 확인하세요. local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3860,9 +3860,9 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 서버$check_frp $update_status" - echo "FRP 인트라넷 침투 서비스 환경을 구축하여 인터넷에 공개 IP없이 장치를 노출시킵니다." + echo "FRP 인트라넷 침투 서비스 환경을 구축하고 공인 IP가 없는 장치를 인터넷에 노출시킵니다." echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=124.0" + echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports @@ -3871,13 +3871,13 @@ frps_panel() { echo "------------------------" echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 인트라넷 서비스에 대한 도메인 이름 액세스 6. 도메인 이름 액세스 삭제" + echo "5. 인트라넷 서비스 도메인 이름 접근 6. 도메인 이름 접근 삭제" echo "------------------------" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "00. 서비스 상태 새로 고침 0. 이전 메뉴로 돌아갑니다." + echo "00. 서비스 상태 새로고침 0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) install jq grep ss @@ -3910,9 +3910,9 @@ frps_panel() { ;; 5) echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" - send_stats "외부 도메인 이름에 대한 FRP 액세스" + send_stats "FRP 외부 도메인 이름 액세스" add_yuming - read -e -p "인트라넷 침투 서비스 포트를 입력하십시오 :" frps_port + read -e -p "인트라넷 침투 서비스 포트를 입력하십시오:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; @@ -3935,7 +3935,7 @@ frps_panel() { ;; 00) - send_stats "FRP 서비스 상태를 새로 고치십시오" + send_stats "FRP 서비스 상태 새로 고침" echo "FRP 서비스 상태가 새로 고쳐졌습니다" ;; @@ -3958,9 +3958,9 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버로 도킹, 도킹 후 인터넷 액세스에 인트라넷 침투 서비스를 만들 수 있습니다." + echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" - echo "비디오 교육 : https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3974,7 +3974,7 @@ frpc_panel() { echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) install jq grep ss @@ -3992,7 +3992,7 @@ frpc_panel() { donlond_frp frpc add_app_id - echo "FRP 클라이언트가 업데이트되었습니다" + echo "FRP 클라이언트가 업데이트되었습니다." ;; 3) @@ -4003,7 +4003,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." ;; 4) @@ -4049,22 +4049,22 @@ yt_menu_pro() { fi clear - send_stats "YT-DLP 다운로드 도구" + send_stats "yt-dlp 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "YT-DLP는 YouTube, Bilibili, Twitter 등을 포함한 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." + echo -e "yt-dlp는 YouTube, Bilibili, Twitter 등과 같은 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "다운로드 된 비디오 목록 :" + echo "다운로드한 동영상 목록:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" echo "-------------------------" echo "1. 설치 2. 업데이트 3. 제거" echo "-------------------------" - echo "5. 단일 비디오 다운로드 6. 배치 비디오 다운로드 7. 사용자 정의 매개 변수 다운로드" - echo "8. MP3 오디오 9. 비디오 디렉토리 삭제 10. 쿠키 관리 (개발 중)" + echo "5. 단일 비디오 다운로드 6. 일괄 비디오 다운로드 7. 사용자 정의 매개변수 다운로드" + echo "8. MP3 오디오로 다운로드 9. 비디오 디렉터리 삭제 10. 쿠키 관리(개발 중)" echo "-------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "-------------------------" - read -e -p "옵션 번호를 입력하십시오 :" choice + read -e -p "옵션 번호를 입력하세요:" choice case $choice in 1) @@ -4086,8 +4086,8 @@ yt_menu_pro() { echo "업데이트가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 3) - send_stats "yt-dlp 제거 ..." - echo "yt-dlp 제거 ..." + send_stats "yt-dlp 제거 중..." + echo "yt-dlp 제거 중..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt @@ -4095,7 +4095,7 @@ yt_menu_pro() { read ;; 5) send_stats "단일 비디오 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + read -e -p "동영상 링크를 입력하세요:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4121,7 +4121,7 @@ yt_menu_pro() { read -e -p "일괄 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 7) send_stats "맞춤형 비디오 다운로드" - read -e -p "전체 YT-DLP 매개 변수를 입력하십시오 (YT-DLP 제외) :" custom + read -e -p "전체 yt-dlp 매개변수를 입력하세요(yt-dlp 제외)." custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4131,18 +4131,18 @@ yt_menu_pro() { read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; 8) send_stats "MP3 다운로드" - read -e -p "비디오 링크를 입력하십시오 :" url + read -e -p "동영상 링크를 입력하세요:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "오디오 다운로드가 완료되었습니다. 키를 누르면 계속하십시오 ..." ;; + read -e -p "오디오 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 9) send_stats "비디오 삭제" - read -e -p "삭제 비디오의 이름을 입력하십시오." rmdir + read -e -p "삭제된 동영상의 이름을 입력하세요:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4187,7 +4187,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 진행 중...${gl_bai}" + echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4243,13 +4243,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "패키지 관리자 캐시 청소 ..." + echo "패키지 관리자 캐시 정리..." apk cache clean echo "시스템 로그 삭제 ..." rm -rf /var/log/* echo "APK 캐시 삭제 ..." rm -rf /var/cache/apk/* - echo "임시 파일 삭제 ..." + echo "임시 파일 삭제..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4267,23 +4267,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "시스템 로그 삭제 ..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "임시 파일 삭제..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then echo "사용하지 않는 의존성 정리 ..." pkg autoremove -y - echo "패키지 관리자 캐시 정리..." + echo "패키지 관리자 캐시 청소 ..." pkg clean -y - echo "시스템 로그 삭제 ..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "임시 파일 삭제 ..." + echo "임시 파일 삭제..." rm -rf /tmp/* else - echo "알 수없는 패키지 관리자!" + echo "알 수 없는 패키지 관리자입니다!" return fi return @@ -4330,21 +4330,21 @@ root_use send_stats "DNS 최적화" while true; do clear - echo "DNS 주소를 최적화합니다" + echo "DNS 주소 최적화" echo "------------------------" echo "현재 DNS 주소" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 외국 DNS 최적화 :" + echo "1. 외국 DNS 최적화:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 국내 DNS 최적화 :" + echo "2. 국내 DNS 최적화:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 구성을 수동으로 편집합니다" + echo "3. DNS 구성을 수동으로 편집" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in @@ -4417,7 +4417,7 @@ correct_ssh_config() { new_ssh_port() { - # 백업 SSH 구성 파일 + # SSH 구성 파일 백업 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4430,7 +4430,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 포트는 다음으로 수정되었습니다.$new_port" + echo "SSH 포트가 다음과 같이 수정되었습니다.$new_port" sleep 1 @@ -4448,7 +4448,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "개인 키 정보가 생성되었습니다. 복사하고 저장하십시오.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인 파일" + echo -e "개인키 정보가 생성되었습니다. 꼭 복사해서 저장하세요. 다음과 같이 저장될 수 있습니다.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인을 위한 파일" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4467,10 +4467,10 @@ add_sshkey() { import_sshkey() { - read -e -p "SSH 공개 키 내용을 입력하십시오 (일반적으로 'SSH-RSA'또는 'SSH-ED25519'로 시작) :" public_key + read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}오류 : 공개 키 컨텐츠가 입력되지 않았습니다.${gl_bai}" + echo -e "${gl_hong}오류: 공개 키 내용이 입력되지 않았습니다.${gl_bai}" return 1 fi @@ -4503,14 +4503,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}루트 로그인이 설정되었습니다!${gl_bai}" +echo -e "${gl_lv}ROOT 로그인 설정이 완료되었습니다!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능은 루트 사용자가 실행해야합니다!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능을 실행하려면 루트 사용자가 필요합니다!" && break_end && kejilion } @@ -4527,30 +4527,30 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}Teddysun.com${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}22${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" + echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" echo -e "계속하려면 키를 누르십시오 ..." read -n 1 -s -r -p "" dd_xitong_bin456789 @@ -4561,7 +4561,7 @@ dd_xitong() { echo "시스템을 다시 설치하십시오" echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - echo -e "${gl_hui}Leitbogioro 및 Bin456789의 스크립트 지원 덕분에!${gl_bai} " + echo -e "${gl_hui}스크립트를 지원해주신 leitbogioro 보스와 bin456789 보스에게 감사드립니다!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4577,14 +4577,14 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. OpenSuse Tumbleweed 36. FNOS FEINIU 공개 베타 버전" + echo "35. openSUSE Tumbleweed 36. fnos Feiniu 공개 베타 버전" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice case "$sys_choice" in @@ -4599,14 +4599,14 @@ dd_xitong() { ;; 2) - send_stats "데비안 12를 다시 설치하십시오" + send_stats "데비안 12 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "데비안 11을 다시 설치하십시오" + send_stats "데비안 11 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 11 reboot @@ -4634,7 +4634,7 @@ dd_xitong() { exit ;; 13) - send_stats "Ubuntu 20.04를 다시 설치하십시오" + send_stats "우분투 20.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot @@ -4650,7 +4650,7 @@ dd_xitong() { 21) - send_stats "Rockylinux10을 다시 설치하십시오" + send_stats "rockylinux10 재설치" dd_xitong_3 bash reinstall.sh rocky reboot @@ -4674,7 +4674,7 @@ dd_xitong() { ;; 24) - send_stats "Alma9를 다시 설치하십시오" + send_stats "alma9 재설치" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -4682,7 +4682,7 @@ dd_xitong() { ;; 25) - send_stats "oracle10 재설치" + send_stats "Oracle10을 다시 설치하십시오" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4690,7 +4690,7 @@ dd_xitong() { ;; 26) - send_stats "Oracle9를 다시 설치하십시오" + send_stats "oracle9 재설치" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -4722,7 +4722,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9를 다시 설치하십시오" + send_stats "centos9 재설치" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4746,7 +4746,7 @@ dd_xitong() { ;; 33) - send_stats "칼리를 다시 설치하십시오" + send_stats "칼리 재설치" dd_xitong_3 bash reinstall.sh kali reboot @@ -4762,7 +4762,7 @@ dd_xitong() { ;; 35) - send_stats "재설치 OpenSuse" + send_stats "Openuse 다시 설치" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -4794,7 +4794,7 @@ dd_xitong() { ;; 43) - send_stats "Windows 7을 다시 설치하십시오" + send_stats "Windows7을 다시 설치하세요." dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -4802,7 +4802,7 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 25를 다시 설치하십시오" + send_stats "Windows Server 25를 다시 설치하세요." dd_xitong_2 bash InstallNET.sh -windows 2025 -lang "cn" reboot @@ -4810,7 +4810,7 @@ dd_xitong() { ;; 45) - send_stats "Windows Server 22를 다시 설치하십시오" + send_stats "윈도우 서버 22 재설치" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -4826,7 +4826,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11 Arm을 다시 설치하십시오" + send_stats "windows11 ARM 재설치" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4843,7 +4843,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3 관리" + send_stats "BBRV3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4856,17 +4856,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "Xanmod의 BBRV3 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "xanmod의 BBRv3 커널이 설치되어 있습니다." + echo "현재 커널 버전:$kernel_version" echo "" echo "커널 관리" echo "------------------------" - echo "1. BBRV3 커널 업데이트 2. BBRV3 커널 제거" + echo "1. BBRv3 커널 업데이트 2. BBRv3 커널 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -4876,7 +4876,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 3단계: 저장소 추가 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4885,7 +4885,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "Xanmod 커널이 업데이트되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4895,7 +4895,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmod 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -4908,7 +4908,7 @@ bbrv3() { else clear - echo "BBR3 가속도를 설정하십시오" + echo "BBR3 가속 설정" echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투 만 지원합니다" @@ -4927,7 +4927,7 @@ bbrv3() { linux_Settings fi else - echo "운영 체제 유형을 결정할 수 없습니다" + echo "운영 체제 유형을 확인할 수 없습니다." break_end linux_Settings fi @@ -4938,7 +4938,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3 단계 : 저장소를 추가합니다 + # 3단계: 저장소 추가 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4949,7 +4949,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4959,7 +4959,7 @@ bbrv3() { echo "취소" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "잘못된 선택, y 또는 N을 입력하십시오." ;; esac fi @@ -4976,18 +4976,18 @@ elrepo_install() { local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) # 지원되는 운영 체제에서 실행하십시오 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "지원되지 않는 운영 체제 :$os_name" + echo "지원되지 않는 운영 체제:$os_name" break_end linux_Settings fi - # 감지 된 운영 체제 정보를 인쇄합니다 - echo "운영 체제 감지 :$os_name $os_version" + # 감지된 운영 체제 정보 인쇄 + echo "감지 된 운영 체제 :$os_name $os_version" # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepo 저장소 구성 (버전 9)을 설치하십시오 ..." + echo "ELRepo 저장소 구성(버전 9) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." @@ -4997,11 +4997,11 @@ elrepo_install() { break_end linux_Settings fi - # Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오. + # ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치합니다. echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepo 저장소 구성이 설치되어 최신 메인 라인 커널로 업데이트됩니다." + echo "ELRepo 저장소 구성을 설치하고 최신 메인라인 커널로 업데이트했습니다." server_reboot } @@ -5022,7 +5022,7 @@ elrepo() { echo "------------------------" echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" sub_choice @@ -5056,9 +5056,9 @@ elrepo() { echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" - echo "Linux 커널을 업그레이드하면 시스템 성능 및 보안이 향상 될 수 있습니다. 조건이 허용되고 생산 환경을 조심스럽게 업그레이드하는 경우 시도하는 것이 좋습니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -5071,7 +5071,7 @@ elrepo() { echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac fi @@ -5092,11 +5092,11 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔 할 디렉토리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi - echo -e "${gl_huang}스캔 디렉토리 $@...${gl_bai}" + echo -e "${gl_huang}$@ 디렉터리를 검색하는 중...${gl_bai}" # 마운트 매개 변수를 빌드하십시오 local MOUNT_PARAMS="" @@ -5138,20 +5138,20 @@ clamav() { send_stats "바이러스 스캔 관리" while true; do clear - echo "Clamav 바이러스 스캐닝 도구" - echo "비디오 소개 : https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "clamav 바이러스 검사 도구" + echo "영상 소개: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "오픈 소스 바이러스 백신 소프트웨어 도구로 주로 다양한 유형의 맬웨어를 감지하고 제거하는 데 사용됩니다." + echo "다양한 유형의 악성 코드를 탐지하고 제거하는 데 주로 사용되는 오픈 소스 바이러스 백신 소프트웨어 도구입니다." echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." echo "------------------------" - echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리를 스캔하십시오${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" + echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리 스캔${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "전체 디스크 스캔" + send_stats "전체 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5169,7 +5169,7 @@ clamav() { ;; 3) send_stats "사용자 정의 디렉토리 스캔" - read -e -p "스캔 할 디렉토리를 입력하십시오." directories + read -e -p "스캔할 디렉터리를 공백으로 구분하여 입력하십시오(예: /etc /var /usr /home /root)." directories install_docker clamav_freshclam clamav_scan $directories @@ -5193,7 +5193,7 @@ optimize_high_performance() { echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null @@ -5212,16 +5212,16 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" + echo -e "${gl_lv}기타 최적화...${gl_bai}" # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 비활성화합니다 + # NUMA 밸런싱 비활성화 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5229,7 +5229,7 @@ optimize_high_performance() { # 이퀄라이제이션 모드 최적화 기능 optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환...${gl_bai}" + echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 32768 @@ -5241,7 +5241,7 @@ optimize_balanced() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5262,7 +5262,7 @@ optimize_balanced() { echo -e "${gl_lv}기타 최적화 ...${gl_bai}" # 투명 페이지를 복원하십시오 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # NUMA 밸런싱 복원 sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5270,9 +5270,9 @@ optimize_balanced() { # 기본 설정 기능을 복원하십시오 restore_defaults() { - echo -e "${gl_lv}기본 설정으로 복원하십시오 ...${gl_bai}" + echo -e "${gl_lv}기본 설정으로 되돌리기...${gl_bai}" - echo -e "${gl_lv}파일 디스크립터 복원 ...${gl_bai}" + echo -e "${gl_lv}파일 설명자를 복원합니다...${gl_bai}" ulimit -n 1024 echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" @@ -5294,16 +5294,16 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}캐시 관리 복원 ...${gl_bai}" + echo -e "${gl_lv}캐시 관리 복원...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}CPU 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}CPU 설정 복원...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}다른 최적화를 복원 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}다른 최적화 되돌리기...${gl_bai}" + # 투명한 대용량 페이지 복원 echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱을 복원하십시오 + # NUMA 밸런싱 복원 sysctl -w kernel.numa_balancing=1 2>/dev/null } @@ -5312,12 +5312,12 @@ restore_defaults() { # 웹사이트 구축 최적화 기능 optimize_web_server() { - echo -e "${gl_lv}웹 사이트 구축 최적화 모드로 전환하십시오 ...${gl_bai}" + echo -e "${gl_lv}웹사이트 구축 최적화 모드로 전환...${gl_bai}" echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null @@ -5343,7 +5343,7 @@ optimize_web_server() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. + # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 echo never > /sys/kernel/mm/transparent_hugepage/enabled # NUMA 밸런싱 비활성화 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5358,21 +5358,21 @@ Kernel_optimize() { clear send_stats "Linux 커널 튜닝 관리" echo "Linux 시스템에서 커널 매개 변수의 최적화" - echo "비디오 소개 : https://www.bilibili.com/video/bv1kb421j7 yg?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." - echo -e "${gl_huang}힌트:${gl_bai}생산 환경에서주의해서 사용하십시오!" + echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." + echo -e "${gl_huang}힌트:${gl_bai}프로덕션 환경에서는 주의해서 사용해주세요!" echo "--------------------" - echo "1. 고성능 최적화 모드 : 시스템 성능을 극대화하고 파일 설명기, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." - echo "2. 균형 최적화 모드 : 매일 사용하기에 적합한 성능과 자원 소비 사이의 균형." - echo "3. 웹 사이트 최적화 모드 : 웹 사이트 서버에 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." + echo "1. 고성능 최적화 모드: 시스템 성능을 최대화하고 파일 설명자, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." + echo "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." + echo "3. 웹사이트 최적화 모드: 웹사이트 서버를 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." - echo "6. 기본 설정을 복원하십시오. 시스템 설정을 기본 구성으로 복원하십시오." + echo "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." echo "--------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) cd ~ @@ -5438,7 +5438,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end @@ -5447,7 +5447,7 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}시스템 언어는 다음으로 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" hash -r break_end ;; @@ -5457,7 +5457,7 @@ update_locale() { ;; esac else - echo "지원되지 않는 시스템, 시스템 유형을 인식 할 수 없습니다." + echo "지원되지 않는 시스템, 시스템 유형을 식별할 수 없습니다." break_end fi } @@ -5470,7 +5470,7 @@ root_use send_stats "스위치 시스템 언어" while true; do clear - echo "현재 시스템 언어 :$LANG" + echo "현재 시스템 언어:$LANG" echo "------------------------" echo "1. 영어 2. 중국어 3. 전통 중국어" echo "------------------------" @@ -5522,10 +5522,10 @@ break_end shell_bianse() { root_use - send_stats "명령 라인 미화 도구" + send_stats "명령줄 미화 도구" while true; do clear - echo "명령 라인 미화 도구" + echo "명령줄 미화 도구" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -5582,7 +5582,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "시스템 재활용 스테이션" + send_stats "시스템 휴지통" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5597,17 +5597,17 @@ linux_trash() { fi clear - echo -e "현재 재활용 쓰레기통${trash_status}" + echo -e "현재 휴지통${trash_status}" echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "재활용 쓰레기통은 비어 있습니다" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" - echo "1. 재활용 빈을 활성화합니다. 2. 재활용 쓰레기통을 닫습니다." + echo "1. 휴지통 활성화 2. 휴지통 닫기" echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -5615,7 +5615,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "Recycle Bin이 활성화되고 삭제 된 파일이 Recycle Bin으로 이동됩니다." + echo "휴지통이 활성화되면 삭제된 파일은 휴지통으로 이동됩니다." sleep 2 ;; 2) @@ -5627,7 +5627,7 @@ linux_trash() { sleep 2 ;; 3) - read -e -p "복원 할 파일 이름을 입력하십시오." file_to_restore + read -e -p "복원할 파일 이름을 입력하세요:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" echo "$file_to_restore홈 디렉토리로 복원되었습니다." @@ -5636,7 +5636,7 @@ linux_trash() { fi ;; 4) - read -e -p "재활용 쓰레기통을 지우셨습니까? [Y/N] :" confirm + read -e -p "휴지통을 비우시겠습니까? [예/아니요]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty echo "재활용 쓰레기통이 지워졌습니다." @@ -5650,7 +5650,7 @@ linux_trash() { } linux_fav() { -send_stats "명령 즐겨 찾기" +send_stats "명령 즐겨찾기" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } @@ -5659,14 +5659,14 @@ create_backup() { send_stats "백업 만들기" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 사용자에게 백업 디렉토리를 입력하라는 메시지를 표시하십시오 + # 사용자에게 백업 디렉터리를 묻는 메시지 표시 echo "백업 예제 :" - echo "- 단일 디렉토리를 백업 : /var /www" - echo "- 여러 디렉토리 백업 : /etc /home /var /log" - echo "- Direct Enter는 기본 디렉토리 ( /etc /usr /home)를 사용합니다." + echo "- 단일 디렉터리 백업: /var/www" + echo "- 여러 디렉터리 백업: /etc /home /var/log" + echo "- Enter를 눌러 기본 디렉터리(/etc/usr/home)를 사용합니다." read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input - # 사용자가 디렉토리를 입력하지 않으면 기본 디렉토리를 사용하십시오. + # 사용자가 디렉터리를 입력하지 않으면 기본 디렉터리가 사용됩니다. if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5674,14 +5674,14 @@ create_backup() { "/home" # 用户数据 ) else - # 사용자가 입력 한 디렉토리를 공백 별 배열로 분리합니다. + # 사용자가 입력한 디렉토리를 공백으로 배열로 구분합니다. IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 백업 파일 접두사를 생성합니다 + # 백업 파일 접두사 생성 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 디렉토리 이름을 추출하고 슬래시를 제거하십시오 + # 디렉토리 이름 추출 및 슬래시 제거 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done @@ -5689,34 +5689,34 @@ create_backup() { # 마지막 밑줄을 제거하십시오 local PREFIX=${PREFIX%_} - # 백업 파일 이름을 생성합니다 + # 백업 파일 이름 생성 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" # 사용자가 선택한 디렉토리를 인쇄하십시오 - echo "선택한 백업 디렉토리는 다음과 같습니다." + echo "선택한 백업 디렉터리는 다음과 같습니다." for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 백업을 만듭니다 + # 백업 만들기 echo "백업 생성$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 명령이 성공했는지 확인하십시오 + # 명령이 성공했는지 확인 if [ $? -eq 0 ]; then - echo "백업은 성공적으로 생성되었습니다.$BACKUP_DIR/$BACKUP_NAME" + echo "백업이 성공적으로 생성되었습니다:$BACKUP_DIR/$BACKUP_NAME" else - echo "백업 생성이 실패했습니다!" + echo "백업 생성에 실패했습니다!" exit 1 fi } -# 백업을 복원하십시오 +# 백업 복원 restore_backup() { - send_stats "백업 복원" + send_stats "백업을 복원하십시오" # 복원하려는 백업을 선택하십시오 - read -e -p "복원하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + read -e -p "복원할 백업 파일 이름을 입력하십시오:" BACKUP_NAME # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -5724,18 +5724,18 @@ restore_backup() { exit 1 fi - echo "백업 복구$BACKUP_NAME..." + echo "백업 복원 중$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then echo "백업 및 복원 성공!" else - echo "백업 복원에 실패했습니다!" + echo "백업 복구 실패!" exit 1 fi } -# 백업 나열 +# 백업을 나열합니다 list_backups() { echo "사용 가능한 백업 :" ls -1 "$BACKUP_DIR" @@ -5743,9 +5743,9 @@ list_backups() { # 백업을 삭제하십시오 delete_backup() { - send_stats "백업을 삭제하십시오" + send_stats "백업 삭제" - read -e -p "삭제하려면 백업 파일 이름을 입력하십시오." BACKUP_NAME + read -e -p "삭제할 백업 파일 이름을 입력하십시오:" BACKUP_NAME # 백업 파일이 있는지 확인하십시오 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -5759,7 +5759,7 @@ delete_backup() { if [ $? -eq 0 ]; then echo "백업이 성공적으로 삭제되었습니다!" else - echo "백업 삭제가 실패했습니다!" + echo "백업 삭제에 실패했습니다!" exit 1 fi } @@ -5775,11 +5775,11 @@ linux_backup() { echo "------------------------" list_backups echo "------------------------" - echo "1. 백업 만들기 2. 백업 복원 3. 백업 삭제" + echo "1. 백업 생성 2. 백업 복원 3. 백업 삭제" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; @@ -5807,18 +5807,18 @@ list_connections() { } -# 새 연결을 추가하십시오 +# 새 연결 추가 add_connection() { send_stats "새 연결을 추가하십시오" - echo "새 연결을 만드는 예 :" - echo "- 연결 이름 : my_server" - echo "-IP 주소 : 192.168.1.100" - echo "- 사용자 이름 : 루트" - echo "- 포트 : 22" + echo "새 연결 생성의 예:" + echo "- 연결 이름: my_server" + echo "- IP 주소: 192.168.1.100" + echo "- 사용자 이름: 루트" + echo "- 포트: 22" echo "------------------------" read -e -p "연결 이름을 입력하십시오 :" name - read -e -p "请输入IP地址: " ip - read -e -p "사용자 이름 (기본값 : 루트)을 입력하십시오 :" user + read -e -p "IP 주소를 입력하십시오 :" ip + read -e -p "사용자 이름을 입력하십시오(기본값: 루트):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 @@ -5834,20 +5834,20 @@ add_connection() { echo # 换行 ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 핵심 내용인지 확인해보세요 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5856,25 +5856,25 @@ add_connection() { fi ;; *) - echo "잘못된 선택!" + echo "잘못된 선택입니다!" return ;; esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "연결이 저장됩니다!" + echo "연결이 저장되었습니다!" } # 연결 삭제 delete_connection() { - send_stats "연결을 삭제하십시오" + send_stats "연결 삭제" read -e -p "삭제하려면 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "오류: 해당 연결을 찾을 수 없습니다." return fi @@ -5891,7 +5891,7 @@ delete_connection() { # 연결을 사용하십시오 use_connection() { - send_stats "연결을 사용하십시오" + send_stats "연결 사용" read -e -p "사용할 연결 번호를 입력하십시오." num local connection=$(sed -n "${num}p" "$CONFIG_FILE") @@ -5902,21 +5902,21 @@ use_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "연결$name ($ip)..." + echo "연결 중$name ($ip)..." if [[ -f "$password_or_key" ]]; then # 키와 연결하십시오 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "연결 실패! 다음을 확인하십시오." echo "1. 키 파일 경로가 정확합니까?$password_or_key" - echo "2. 키 파일 권한이 올바른지 여부 (600이어야 함)." - echo "3. 대상 서버가 키를 사용하여 로그인 할 수 있는지 여부." + echo "2. 키 파일 권한이 올바른가요(600이어야 함)." + echo "3. 대상 서버에서 키를 이용한 로그인을 허용하는지 여부." fi else # 비밀번호로 연결하십시오 if ! command -v sshpass &> /dev/null; then echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." - echo "설치 방법 :" + echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return @@ -5924,8 +5924,8 @@ use_connection() { sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "연결 실패! 다음을 확인하십시오." - echo "1. 사용자 이름과 비밀번호가 정확합니까?" - echo "2. 대상 서버에서 비밀번호 로그인을 허용하는지 여부." + echo "1. 사용자 이름과 비밀번호가 올바른지 여부." + echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." fi fi @@ -5951,12 +5951,12 @@ ssh_manager() { while true; do clear echo "SSH 원격 연결 도구" - echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다" + echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다." echo "------------------------" list_connections - echo "1. 새 연결 만들기 2. 연결 사용 3. 연결 삭제" + echo "1. 새 연결 생성 2. 연결 사용 3. 연결 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" choice case $choice in @@ -5964,7 +5964,7 @@ ssh_manager() { 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; esac done } @@ -5980,9 +5980,9 @@ ssh_manager() { -# 사용 가능한 하드 디스크 파티션을 나열하십시오 +# 사용 가능한 하드 디스크 파티션 나열 list_partitions() { - echo "사용 가능한 하드 디스크 파티션 :" + echo "사용 가능한 하드 드라이브 파티션:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } @@ -5991,15 +5991,15 @@ mount_partition() { send_stats "파티션을 장착하십시오" read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION - # 파티션이 있는지 확인하십시오 + # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "파티션이 존재하지 않습니다!" return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 파티션이 마운트되었는지 확인 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션은 이미 장착되어 있습니다!" + echo "파티션이 마운트되었습니다!" return fi @@ -6011,22 +6011,22 @@ mount_partition() { mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "파티션 마운트 성공적으로 :$MOUNT_POINT" + echo "파티션이 성공적으로 마운트되었습니다:$MOUNT_POINT" else echo "파티션 마운트 실패!" rmdir "$MOUNT_POINT" fi } -# 파티션을 제거하십시오 +# 파티션 마운트 해제 unmount_partition() { - send_stats "파티션을 제거하십시오" + send_stats "파티션 마운트 해제" read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION # 파티션이 이미 장착되어 있는지 확인하십시오 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "파티션이 장착되지 않았습니다!" + echo "파티션이 마운트되지 않았습니다!" return fi @@ -6034,7 +6034,7 @@ unmount_partition() { umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 분할 해제 성공 :$MOUNT_POINT" + echo "파티션이 성공적으로 제거되었습니다:$MOUNT_POINT" rmdir "$MOUNT_POINT" else echo "파티션 제거 실패!" @@ -6043,14 +6043,14 @@ unmount_partition() { # 목록 장착 파티션 list_mounted_partitions() { - echo "마운트 파티션 :" + echo "마운트된 파티션:" df -h | grep -v "tmpfs\|udev\|overlay" } # 형식 파티션 format_partition() { send_stats "파티션 포맷" - read -e -p "파티션 이름을 형식 (예 : SDA1)에 입력하십시오." PARTITION + read -e -p "포맷할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION # 파티션이 있는지 확인하십시오 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then @@ -6058,13 +6058,13 @@ format_partition() { return fi - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 파티션이 마운트되었는지 확인 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 장착되었습니다. 먼저 제거하십시오!" + echo "파티션이 마운트되었습니다. 먼저 마운트를 해제하세요!" return fi - # 파일 시스템 유형을 선택하십시오 + # 파일 시스템 유형 선택 echo "파일 시스템 유형을 선택하십시오 :" echo "1. ext4" echo "2. xfs" @@ -6077,11 +6077,11 @@ format_partition() { 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "잘못된 선택!"; return ;; + *) echo "잘못된 선택입니다!"; return ;; esac # 형식을 확인하십시오 - read -e -p "파티션 형식 확인 /dev /$PARTITION~을 위한$FS_TYPE그게? (Y/N) :" CONFIRM + read -e -p "포맷된 파티션 /dev/ 확인$PARTITION~을 위한$FS_TYPE? (예/아니요):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "작업이 취소되었습니다." return @@ -6092,7 +6092,7 @@ format_partition() { mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션 형식이 성공적이었습니다!" + echo "파티션이 성공적으로 포맷되었습니다!" else echo "파티션 형식이 실패했습니다!" fi @@ -6109,8 +6109,8 @@ check_partition() { return fi - # 파티션 상태를 확인하십시오 - echo "파티션 /개발자 /$PARTITION상태:" + # 파티션 상태 확인 + echo "파티션 확인 /dev/$PARTITION상태:" fsck "/dev/$PARTITION" } @@ -6120,12 +6120,12 @@ disk_manager() { while true; do clear echo "하드 디스크 파티션 관리" - echo -e "${gl_huang}이 기능은 테스트 기간 동안 내부적으로 테스트되므로 생산 환경에서 사용하지 마십시오.${gl_bai}" + echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" - echo "4. 파티션 형식 5. 파티션 상태를 확인하십시오" + echo "4. 파티션 포맷 5. 파티션 상태 확인" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -6138,7 +6138,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "계속하려면 Enter를 누르세요..." done } @@ -6157,17 +6157,17 @@ list_tasks() { add_task() { send_stats "새 동기화 작업을 추가하십시오" echo "새 동기화 작업 작성 예 :" - echo "- 작업 이름 : Backup_www" + echo "- 작업 이름: backup_www" echo "- 로컬 디렉토리 : /var /www" echo "- 원격 주소 : user@192.168.1.100" echo "- 원격 디렉토리 : /백업 /www" echo "- 포트 번호(기본값 22)" echo "---------------------------------" read -e -p "작업 이름을 입력하십시오 :" name - read -e -p "로컬 디렉토리를 입력하십시오 :" local_path + read -e -p "로컬 디렉토리를 입력하십시오:" local_path read -e -p "원격 디렉토리를 입력하십시오 :" remote_path read -e -p "원격 사용자 @IP를 입력하십시오 :" remote - read -e -p "SSH 포트(기본값 22)를 입력하세요." port + read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port port=${port:-22} echo "인증 방법을 선택하십시오 :" @@ -6185,17 +6185,17 @@ add_task() { echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 주요 내용인지 확인하십시오 + # 핵심 내용인지 확인해보세요 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6208,7 +6208,7 @@ add_task() { fi ;; *) - echo "잘못된 선택!" + echo "잘못된 선택입니다!" return ;; esac @@ -6216,18 +6216,18 @@ add_task() { echo "동기화 모드를 선택하십시오 :" echo "1. 표준 모드 (-avz)" echo "2. 대상 파일 삭제 (-avz-delete)" - read -e -p "선택하십시오 (1/2) :" mode + read -e -p "(1/2)을 선택하세요:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "유효하지 않은 선택, 기본값 -AVZ를 사용하십시오"; options="-avz" ;; + *) echo "선택이 잘못되었습니다. 기본값 -avz를 사용하세요."; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "작업을 저장했습니다!" + echo "임무가 저장되었습니다!" } # 작업을 삭제하십시오 @@ -6283,7 +6283,7 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 동기화 방향에 따라 소스 및 대상 경로를 조정하십시오 + # 동기화 방향에 따라 소스 및 대상 경로 조정 if [[ "$direction" == "pull" ]]; then echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" source="$remote:$local_path" @@ -6294,13 +6294,13 @@ run_task() { destination="$remote:$remote_path" fi - # SSH 연결 공통 매개 변수를 추가하십시오 + # SSH 연결 공통 매개변수 추가 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." - echo "설치 방법 :" + echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return @@ -6326,28 +6326,28 @@ run_task() { else echo "동기화 실패! 다음을 확인하십시오." echo "1. 네트워크 연결이 정상입니까?" - echo "2. 원격 호스트가 액세스 할 수 있습니까?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증 정보가 정확합니까?" - echo "4. 로컬 및 원격 디렉토리에 올바른 액세스 권한이 있습니까?" + echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi } -# 시간이 정한 작업을 만듭니다 +# 예약된 작업 만들기 schedule_task() { - send_stats "동기화 타이밍 작업을 추가하십시오" + send_stats "동기화 예약 작업 추가" - read -e -p "정기적으로 동기화 할 작업 번호를 입력하십시오." num + read -e -p "정기적으로 동기화할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류: 유효한 작업 번호를 입력하십시오!" + echo "오류 : 유효한 작업 번호를 입력하십시오!" return fi - echo "시간이 정한 실행 간격을 선택하십시오." - echo "1) 한 시간에 한 번 실행하십시오" - echo "2) 하루에 한 번 실행" + echo "예약된 실행 간격을 선택하십시오." + echo "1) 매 시간마다 한 번씩 실행" + echo "2) 하루에 한 번 수행하십시오" echo "3) 일주일에 한 번 실행" - read -e -p "옵션을 입력하십시오 (1/2/3) :" interval + read -e -p "옵션을 입력하세요(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6355,7 +6355,7 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "오류 : 유효한 옵션을 입력하십시오!" ; return ;; + *) echo "오류: 유효한 옵션을 입력하십시오!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" @@ -6363,18 +6363,18 @@ schedule_task() { # 동일한 작업이 이미 존재하는지 확인하십시오 if crontab -l | grep -q "k rsync_run $num"; then - echo "오류 :이 작업의 타이밍 동기화가 이미 존재합니다!" + echo "오류: 이 작업에 대해 예약된 동기화가 이미 존재합니다!" return fi - # 사용자에게 크론AB를 만듭니다 + # 사용자의 crontab에 생성 (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "타이밍 작업이 만들어졌습니다.$cron_job" + echo "예약된 작업이 생성되었습니다:$cron_job" } -# 예약된 작업 보기 +# 예정된 작업을 봅니다 view_tasks() { - echo "현재 타이밍 작업 :" + echo "현재 예약된 작업:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" @@ -6383,14 +6383,14 @@ view_tasks() { # 타이밍 작업을 삭제하십시오 delete_task_schedule() { send_stats "동기화 타이밍 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + read -e -p "삭제할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "오류: 유효한 작업 번호를 입력하십시오!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "삭제 된 작업 번호$num타이밍 작업" + echo "태스크 번호가 삭제되었습니다.$num예약된 작업" } @@ -6401,7 +6401,7 @@ rsync_manager() { while true; do clear - echo "RSYNC 원격 동기화 도구" + echo "Rsync 원격 동기화 도구" echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." echo "---------------------------------" list_tasks @@ -6409,7 +6409,7 @@ rsync_manager() { view_tasks echo echo "1. 새 작업 생성 2. 작업을 삭제하십시오" - echo "3. 원격 끝에 로컬 동기화 수행 4. 로컬 엔드에 대한 원격 동기화 수행" + echo "3. 원격 사이트에 대한 로컬 동기화 수행 4. 로컬 사이트에 대한 원격 동기화 수행" echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" echo "---------------------------------" echo "0. 이전 메뉴로 돌아갑니다" @@ -6423,7 +6423,7 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "잘못된 선택, 다시 시도하십시오." ;; + *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; esac read -e -p "계속하려면 Enter를 누르십시오 ..." done @@ -6492,29 +6492,29 @@ linux_info() { echo "" echo -e "시스템 정보 쿼리" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}호스트 이름 :${gl_bai}$hostname" - echo -e "${gl_kjlan}시스템 버전 :${gl_bai}$os_info" + echo -e "${gl_kjlan}호스트 이름:${gl_bai}$hostname" + echo -e "${gl_kjlan}시스템 버전:${gl_bai}$os_info" echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU 모델 :${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU 코어 수 :${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU 모델:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU 코어 수:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}시스템 부하 :${gl_bai}$load" + echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" - echo -e "${gl_kjlan}가상 메모리 :${gl_bai}$swap_info" + echo -e "${gl_kjlan}가상 메모리:${gl_bai}$swap_info" echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}총 수신 :${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" + echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}네트워크 알고리즘 :${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}네트워크 알고리즘:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 주소 :${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4 주소:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then @@ -6541,24 +6541,24 @@ linux_tools() { echo -e "기본 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}소사이어티 커뮤니케이션 연결 도구" - echo -e "${gl_kjlan}5. ${gl_bai}HTOP 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}IFTOP 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}FFMPEG 비디오 라이브 스트리밍 도구 인코딩" + echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" + echo -e "${gl_kjlan}5. ${gl_bai}htop 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}iftop 네트워크 트래픽 모니터링 도구" + echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOP 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" - echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}FZF 글로벌 검색 도구" + echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" + echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}열차 스크린 보안" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 게임" + echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 미니 게임" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구 제거" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -6593,9 +6593,9 @@ linux_tools() { clear install socat clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." socat -h - send_stats "Socat을 설치하십시오" + send_stats "socat 설치" ;; 5) clear @@ -6615,7 +6615,7 @@ linux_tools() { clear install unzip clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." unzip send_stats "압축을 설치하십시오" ;; @@ -6623,9 +6623,9 @@ linux_tools() { clear install tar clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." tar --help - send_stats "타르를 설치하십시오" + send_stats "타르 설치" ;; 9) clear @@ -6639,7 +6639,7 @@ linux_tools() { clear install ffmpeg clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." ffmpeg --help send_stats "FFMPEG를 설치하십시오" ;; @@ -6667,7 +6667,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDU를 설치하십시오" + send_stats "ncdu 설치" ;; 14) clear @@ -6676,7 +6676,7 @@ linux_tools() { clear fzf cd ~ - send_stats "FZF를 설치하십시오" + send_stats "fzf 설치" ;; 15) clear @@ -6685,7 +6685,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIM을 설치하십시오" + send_stats "vim 설치" ;; 16) clear @@ -6705,7 +6705,7 @@ linux_tools() { clear git --help cd ~ - send_stats "git을 설치하십시오" + send_stats "자식 설치" ;; 21) @@ -6713,7 +6713,7 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix 설치" + send_stats "cmatrix를 설치하십시오" ;; 22) clear @@ -6727,21 +6727,21 @@ linux_tools() { install bastet clear bastet - send_stats "Bastet을 설치하십시오" + send_stats "바스테트 설치" ;; 27) clear install nsnake clear nsnake - send_stats "NSNAKE를 설치하십시오" + send_stats "nsnake 설치" ;; 28) clear install ninvaders clear ninvaders - send_stats "닌베이더 설치" + send_stats "Ninvaders를 설치하십시오" ;; 31) @@ -6765,15 +6765,15 @@ linux_tools() { 41) clear - read -e -p "설치된 도구 이름 (WGET CURL SUDO HTOP)을 입력하십시오." installname + read -e -p "설치된 도구 이름을 입력하십시오(wget 컬 sudo htop):" installname install $installname send_stats "지정된 소프트웨어를 설치하십시오" ;; 42) clear - read -e -p "제거되지 않은 도구 이름 (HTOP UFW TMUX CMATRIX)을 입력하십시오." removename + read -e -p "제거된 도구 이름(htop ufw tmux cmatrix)을 입력하십시오." removename remove $removename - send_stats "지정된 소프트웨어 제거" + send_stats "지정된 소프트웨어를 제거하십시오" ;; 0) @@ -6781,7 +6781,7 @@ linux_tools() { ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -6806,7 +6806,7 @@ linux_bbr() { echo "" echo "BBR 관리" echo "------------------------" - echo "1. BBRV3 켜기 2. BBRV3 끄기 (재시작)" + echo "1. BBRv3를 켭니다. 2. BBRv3을 끕니다(다시 시작됩니다)." echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -6815,7 +6815,7 @@ linux_bbr() { case $sub_choice in 1) bbr_on - send_stats "알파인 활성화 BBR3" + send_stats "알파인이 열립니다 bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf @@ -6871,7 +6871,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업 할 컨테이너 이름을 입력하십시오 (여러 공간으로 분리하면 입력 백업이 모두 실행 중입니다)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -6884,7 +6884,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너가 없습니다${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너를 찾을 수 없습니다.${NC}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -6892,9 +6892,9 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 자동으로 생성 된 복원 스크립트" >> "$RESTORE_SCRIPT" + echo "# 자동으로 생성된 복원 스크립트" >> "$RESTORE_SCRIPT" - # 중복 포장을 피하기 위해 패키지 작곡 프로젝트의 경로를 기록하십시오. + # 반복되는 패키징을 피하기 위해 패키징된 Compose 프로젝트 경로를 기록하세요. declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -6903,7 +6903,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}감지됨$c예, Docker-compose 컨테이너${NC}" + echo -e "${BLUE}감지$c도커 작성 컨테이너입니다${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -6911,9 +6911,9 @@ docker_ssh_migration() { read -e -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir fi - # Compose 프로젝트가 포장 된 경우 건너 뛰십시오 + # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}작곡 프로젝트 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" continue fi @@ -6921,10 +6921,10 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# Docker-Compose Recovery :$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 복원:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}작곡 프로젝트 [$project_name] 포장 :${project_dir}${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name] 포장 :${project_dir}${NC}" else echo -e "${RED}docker-compose.yml을 찾을 수 없고이 컨테이너를 건너 뛰십시오 ...${NC}" fi @@ -6933,7 +6933,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "포장 롤 :$path" + echo "포장량:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6955,21 +6955,21 @@ docker_ssh_migration() { local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\ n# 복원 컨테이너 :$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 복원 컨테이너:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # /home /docker 아래의 모든 파일을 백업 (하위 디렉터 제외) + # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then echo -e "${BLUE}/home /docker 아래 파일을 백업 ...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home /docker의 파일은 다음과 같이 포장되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}백업이 완료되었습니다.${BACKUP_DIR}${NC}" + echo -e "${GREEN}백업 완료:${BACKUP_DIR}${NC}" echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" @@ -6989,7 +6989,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # --------- Compose 프로젝트 복원 우선순위 지정 --------- + # ----------------------------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -7005,21 +7005,21 @@ docker_ssh_migration() { continue fi - read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로로 [$original_path] ? (y/n): " confirm + read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로 [$original_path] ? (y/n): " confirm [[ "$confirm" != "y" ]] && read -e -p "새로운 복원 경로를 입력하십시오 :" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}작곡 프로젝트 [$project_name] 압축 압축 : :$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name] 압축 압축 : :$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원이 완료되었습니다!${NC}" + echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원 완료!${NC}" fi done - # ----------------------------- + # --------- 일반 컨테이너를 계속 복원합니다 --------- echo -e "${BLUE}일반적인 도커 컨테이너를 확인하고 복원하십시오 ...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do @@ -7028,14 +7028,14 @@ docker_ssh_migration() { container=$(basename "$json" | sed 's/_inspect.json//') echo -e "${GREEN}처리 컨테이너 :$container${NC}" - # 컨테이너가 이미 존재하고 실행 중인지 확인하십시오 + # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container]는 실행 중입니다. 회복을 건너 뛰십시오 ...${NC}" + echo -e "${YELLOW}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${NC}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}거울 정보는 찾을 수 없었습니다.$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}미러 정보를 찾을 수 없습니다. 건너뛰세요:$container${NC}"; continue; } # 포트 매핑 PORT_ARGS="" @@ -7062,32 +7062,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "볼륨 데이터 복구 :$VOL_SRC" + echo "볼륨 데이터 복구:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done # 기존이지만 실행되지 않은 컨테이너를 삭제하십시오 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container] 존재하지만 실행되지 않고 오래된 컨테이너를 삭제합니다 ...${NC}" + echo -e "${YELLOW}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${NC}" docker rm -f "$container" fi # 컨테이너를 시작하십시오 - echo "복원 명령 실행 : docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + echo "복원 명령을 실행합니다: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}일반 컨테이너에 대한 백업 정보는 발견되지 않았습니다${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}공통 컨테이너에 대한 백업 정보가 없습니다.${NC}" - # /home/docker 아래의 파일 복원 + # /home /docker에서 파일을 복원하십시오 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home /docker에서 파일을 복원 ...${NC}" + echo -e "${BLUE}/home/docker 아래의 파일을 복원하는 중...${NC}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home /docker의 파일이 복원되었습니다${NC}" + echo -e "${GREEN}/home/docker 아래의 파일이 복원되었습니다.${NC}" else - echo -e "${YELLOW}/home /docker 아래 파일의 백업이 발견되지 않았습니다.${NC}" + echo -e "${YELLOW}/home/docker 아래의 파일 백업을 찾을 수 없습니다. 건너뛰는 중...${NC}" fi @@ -7101,10 +7101,10 @@ docker_ssh_migration() { send_stats "도커 마이그레이션" install jq read -e -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } read -e -p "대상 서버 IP :" TARGET_IP - read -e -p "대상 서버 SSH 사용자 이름 :" TARGET_USER + read -e -p "대상 서버 SSH 사용자 이름:" TARGET_USER read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} @@ -7112,18 +7112,18 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 ...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인하십시오 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 백업을 삭제하십시오 + # 백업 삭제 # ---------------------------- delete_backup() { send_stats "Docker 백업 파일 삭제" - read -e -p "삭제하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + read -e -p "삭제할 백업 디렉터리를 입력하십시오:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } rm -rf "$BACKUP_DIR" echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" @@ -7133,7 +7133,7 @@ docker_ssh_migration() { # 메인 메뉴 # ---------------------------- main_menu() { - send_stats "도커 백업 마이그레이션 및 복원" + send_stats "Docker 백업 마이그레이션 복원" while true; do clear echo "------------------------" @@ -7144,12 +7144,12 @@ docker_ssh_migration() { echo "------------------------" echo -e "1. 도커 프로젝트 백업" echo -e "2. Docker 프로젝트를 마이그레이션합니다" - echo -e "3. Docker 프로젝트를 복원하십시오" + echo -e "3. 도커 프로젝트 복원" echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" echo "------------------------" - echo -e "0. 이전 메뉴로 돌아갑니다" + echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택하십시오 :" choice + read -e -p "선택하세요:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -7188,18 +7188,18 @@ linux_docker() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너를 정리하고 네트워크 데이터 볼륨을 미러링하세요." echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스를 교체하십시오" + echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스 변경" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 액세스 끄기" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}백업/마이그레이션/복원 Docker 환경" + echo -e "${gl_kjlan}19. ${gl_bai}Docker 환경 백업/마이그레이션/복원" echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -7221,16 +7221,16 @@ linux_docker() { docker compose version echo "" - echo -e "도커 이미지 :${gl_lv}$image_count${gl_bai} " + echo -e "도커 이미지:${gl_lv}$image_count${gl_bai} " docker image ls echo "" echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker 볼륨:${gl_lv}$volume_count${gl_bai}" + echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "도커 네트워크 :${gl_lv}$network_count${gl_bai}" + echo -e "도커 네트워크:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7270,11 +7270,11 @@ linux_docker() { done echo "" - echo "네트워크 작동" + echo "네트워크 운영" echo "------------------------" - echo "1. 네트워크를 만듭니다" + echo "1. 네트워크 생성" echo "2. 인터넷에 가입하십시오" - echo "3. 네트워크를 종료하십시오" + echo "3. 네트워크 종료" echo "4. 네트워크를 삭제합니다" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" @@ -7288,8 +7288,8 @@ linux_docker() { docker network create $dockernetwork ;; 2) - send_stats "인터넷에 가입하십시오" - read -e -p "네트워크 이름에 가입 :" dockernetwork + send_stats "네트워크에 가입하세요" + read -e -p "네트워크 이름 추가:" dockernetwork read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames for dockername in $dockernames; do @@ -7299,7 +7299,7 @@ linux_docker() { 3) send_stats "인터넷에 가입하십시오" read -e -p "종료 네트워크 이름 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다 (여러 컨테이너 이름은 공간별로 분리됩니다)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7308,7 +7308,7 @@ linux_docker() { ;; 4) - send_stats "네트워크를 삭제하십시오" + send_stats "네트워크 삭제" read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork docker network rm $dockernetwork ;; @@ -7329,13 +7329,13 @@ linux_docker() { echo "" echo "볼륨 작동" echo "------------------------" - echo "1. 새 볼륨을 만듭니다" + echo "1. 새 볼륨 생성" echo "2. 지정된 볼륨을 삭제합니다" echo "3. 모든 볼륨을 삭제하십시오" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -7345,7 +7345,7 @@ linux_docker() { ;; 2) - read -e -p "볼륨 삭제 이름을 입력하십시오 (공백으로 여러 볼륨 이름을 분리하십시오)." dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7354,7 +7354,7 @@ linux_docker() { ;; 3) - send_stats "모든 볼륨을 삭제하십시오" + send_stats "모든 볼륨 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7385,7 +7385,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -7413,7 +7413,7 @@ linux_docker() { 12) clear - send_stats "Docker V6 레벨" + send_stats "도커 v6 닫기" docker_ipv6_off ;; @@ -7436,7 +7436,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -7463,28 +7463,28 @@ linux_test() { while true; do clear # Send_stats "테스트 스크립트 컬렉션" - echo -e "스크립트 수집 테스트" + echo -e "테스트 스크립트 수집" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGpt는 상태 감지를 잠금 해제합니다" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 잠금 해제 상태 감지" echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 품질 확인 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}네트워크 속도 측정" - echo -e "${gl_kjlan}11. ${gl_bai}Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + echo -e "${gl_kjlan}네트워크 회선 속도 테스트" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 3 네트워크 백홀 지연 라우팅 테스트" echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}하드웨어 성능 테스트" - echo -e "${gl_kjlan}21. ${gl_bai}YABS 성능 테스트" + echo -e "${gl_kjlan}21. ${gl_bai}Yabs 성능 테스트" echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" echo -e "${gl_kjlan}------------------------" @@ -7492,7 +7492,7 @@ linux_test() { echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택을 입력하십시오 :" sub_choice @@ -7528,12 +7528,12 @@ linux_test() { ;; 12) clear - send_stats "MTR_TRACE 3 개의 네트워크 리턴 라인 테스트" + send_stats "mtr_trace 삼중 네트워크 백홀 회선 테스트" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed 3 Net 속도 측정" + send_stats "초고속 트리플 네트워크 속도 테스트" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) @@ -7547,20 +7547,20 @@ linux_test() { send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" echo "참조 할 수있는 IP 목록" echo "------------------------" - echo "베이징 통신 : 219.141.136.12" + echo "베이징 통신: 219.141.136.12" echo "베이징 유니폼 : 202.106.50.1" - echo "베이징 모바일 : 221.179.155.161" - echo "상하이 통신 : 202.96.209.133" + echo "베이징 모바일: 221.179.155.161" + echo "상하이 통신: 202.96.209.133" echo "상하이 유니폼 : 210.22.97.1" echo "상하이 모바일: 211.136.112.200" - echo "광저우 통신 : 58.60.188.222" - echo "광저우 유니폼 : 210.21.196.6" - echo "광저우 모바일 : 120.196.165.24" - echo "청두 통신 : 61.139.2.69" + echo "광저우 통신: 58.60.188.222" + echo "광저우 차이나 유니콤: 210.21.196.6" + echo "광저우 모바일: 120.196.165.24" + echo "청두통신: 61.139.2.69" echo "청두 유니폼 : 119.6.6.6" echo "청두 모바일 : 211.137.96.205" echo "Hunan Telecom : 36.111.200.100" - echo "후난 유니폼 : 42.48.16.100" + echo "후난 유니콤: 42.48.16.100" echo "후난 모바일 : 39.134.254.6" echo "------------------------" @@ -7571,7 +7571,7 @@ linux_test() { 16) clear - send_stats "Ludashi2020 3 네트워크 라인 테스트" + send_stats "ludashi2020 세 개의 네트워크 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; @@ -7589,13 +7589,13 @@ linux_test() { 21) clear - send_stats "YABS 성능 테스트" + send_stats "Yabs 성능 테스트" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "IICU/GB5 CPU 성능 테스트 스크립트" + send_stats "icu/gb5 CPU 성능 테스트 스크립트" check_swap bash <(curl -sL bash.icu/gb5) ;; @@ -7606,7 +7606,7 @@ linux_test() { curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX 퓨전 몬스터 검토" + send_stats "spiritysdx 퓨전 몬스터 리뷰" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7616,7 +7616,7 @@ linux_test() { ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -7639,9 +7639,9 @@ linux_Oracle() { echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" - echo -e "${gl_kjlan}4. ${gl_bai}형사 R 스크립트 시작" - echo -e "${gl_kjlan}5. ${gl_bai}루트 비밀번호 로그인 모드를 켭니다" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6 복구 도구" + echo -e "${gl_kjlan}4. ${gl_bai}R 형사 시작 스크립트" + echo -e "${gl_kjlan}5. ${gl_bai}ROOT 비밀번호 로그인 모드 활성화" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6 복구 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7699,12 +7699,12 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud 제거 활성 스크립트" + send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" ;; 3) clear - echo "시스템 재설치" + echo "시스템을 다시 설치하십시오" echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." read -e -p "계속할거야? (Y/N) :" choice @@ -7724,21 +7724,21 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "선택이 잘못되었습니다. 다시 입력해 주세요." ;; esac done - read -e -p "다시 설치 한 비밀번호를 입력하십시오." vpspasswd + read -e -p "재설치 후 비밀번호를 입력해주세요:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud 회복 시스템 스크립트" + send_stats "Oracle Cloud 재설치 시스템 스크립트" ;; [Nn]) echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -7756,8 +7756,8 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." - send_stats "IPv6 수정" + echo "이 기능은 jhb에서 제공합니다. 감사합니다!" + send_stats "IPv6 수리" ;; 0) kejilion @@ -7806,7 +7806,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치됩니다${gl_bai}대지:$output데이터 베이스:$db_output" + echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}대지:$output데이터 베이스:$db_output" fi fi @@ -7834,31 +7834,31 @@ linux_ldnmp() { while true; do clear - # send_stats "ldnmp 웹 사이트 빌딩" - echo -e "${gl_huang}LDNMP 웹 사이트 구축" + # send_stats "LDNMP 웹사이트 구축" + echo -e "${gl_huang}LDNMP 웹사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼을 설치하십시오${gl_huang}4. ${gl_bai}Kadao 클라우드 데스크탑을 설치하십시오" + echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼 설치${gl_huang}4. ${gl_bai}Kedao 클라우드 데스크탑 설치" echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}Typecho Lightweight 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼을 설치하십시오${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" - echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 리버스 프록시 - 도메인 이름" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼을 설치하십시오${gl_huang}26. ${gl_bai}후광 블로그 웹 사이트를 설치하십시오" - echo -e "${gl_huang}27. ${gl_bai}AI 페인팅 프롬프트 워드 생성기를 설치하십시오${gl_huang}28. ${gl_bai}사이트 리버스 프록시로드 밸런싱" - echo -e "${gl_huang}30. ${gl_bai}정적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" + echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" + echo -e "${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}전체 사이트 데이터를 백업합니다" + echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" - echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경을 제거하십시오" + echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경 제거" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -7875,7 +7875,7 @@ linux_ldnmp() { # Discuz 포럼 webname="Discuz论坛" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7898,11 +7898,11 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 이름:$dbname" echo "사용자 이름 :$dbuse" echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : discuz_" + echo "테이블 접두사: discuz_" ;; @@ -7934,10 +7934,10 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 주소: mysql" echo "사용자 이름 :$dbuse" echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" + echo "데이터베이스 이름:$dbname" echo "Redis 호스트 : Redis" ;; @@ -7947,7 +7947,7 @@ linux_ldnmp() { # AppleCMS webname="苹果CMS" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7973,12 +7973,12 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 주소: mysql" echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사: mac_" + echo "데이터베이스 접두사 : MAC_" echo "------------------------" echo "설치가 성공한 후 배경 주소에 로그인하십시오." echo "https://$yuming/vip.php" @@ -7987,7 +7987,7 @@ linux_ldnmp() { 6) clear - # 한 다리 카운팅 카드 + # 한쪽다리 숫자카드 webname="独脚数卡" send_stats "설치하다$webname" echo "배포를 시작하십시오$webname" @@ -8011,7 +8011,7 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소: mysql" + echo "데이터베이스 주소 : MySQL" echo "데이터베이스 포트 : 3306" echo "데이터베이스 이름 :$dbname" echo "사용자 이름 :$dbuse" @@ -8019,26 +8019,26 @@ linux_ldnmp() { echo "" echo "Redis 주소 : Redis" echo "Redis Password : 기본적으로 채워지지 않습니다" - echo "Redis Port : 6379" + echo "레디스 포트: 6379" echo "" - echo "웹 사이트 URL : https : //$yuming" + echo "웹사이트 URL: https://$yuming" echo "백그라운드 로그인 경로 : /admin" echo "------------------------" - echo "사용자 이름 : 관리자" + echo "사용자 이름: 관리자" echo "비밀번호 : 관리자" echo "------------------------" - echo "로그인 할 때 오른쪽 상단에 빨간색 Error0이 나타나면 다음 명령을 사용하십시오." - echo "나는 또한 유니콘 번호 카드가 너무 귀찮다는 것에 대해 매우 화가 났으며 그러한 문제가있을 것입니다!" + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # Flarum 포럼 + # 플라럼 포럼 webname="flarum论坛" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8077,9 +8077,9 @@ linux_ldnmp() { ldnmp_web_on echo "데이터베이스 주소 : MySQL" echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 : flarum_" + echo "테이블 접두사: flarum_" echo "관리자 정보는 직접 설정됩니다" ;; @@ -8089,7 +8089,7 @@ linux_ldnmp() { # typecho webname="typecho" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8113,11 +8113,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 접두사 : typecho_" - echo "데이터베이스 주소 : MySQL" - echo "사용자 이름 :$dbuse" + echo "데이터베이스 접두사: typecho_" + echo "데이터베이스 주소: mysql" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름 :$dbname" + echo "데이터베이스 이름:$dbname" ;; @@ -8152,7 +8152,7 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 주소: mysql" echo "데이터베이스 포트 : 3306" echo "데이터베이스 이름 :$dbname" echo "사용자 이름 :$dbuse" @@ -8180,10 +8180,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드 업로드" echo "-------------" - echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리 아래" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8198,7 +8198,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 Index.php의 경로를 입력하십시오.$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/과 유사하게 index.php 경로를 입력하세요.$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8217,7 +8217,7 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "유효하지 않은 선택, 다시 입력하십시오." + echo "선택이 잘못되었습니다. 다시 입력해 주세요." ;; esac @@ -8252,7 +8252,7 @@ linux_ldnmp() { echo ;; 2) - echo "데이터베이스 백업은 .gz-end 압축 패키지 여야합니다. Pagoda/1Panel의 백업 데이터 가져 오기를 지원하려면/홈/디렉토리에 넣으십시오." + echo "데이터베이스 백업은 .gz로 끝나는 압축 패키지여야 합니다. Pagoda/1panel 백업 데이터 가져오기를 지원하려면 /home/ 디렉토리에 넣으십시오." read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db cd /home/ @@ -8263,10 +8263,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "데이터베이스 가져 오기 테이블 데이터" + echo "데이터베이스에서 가져온 테이블 데이터" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "데이터베이스 가져 오기가 완료되었습니다" + echo "데이터베이스 가져오기 완료" ;; *) echo @@ -8279,10 +8279,10 @@ linux_ldnmp() { ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" - echo "테이블 접두사 :$prefix" + echo "테이블 접두사:$prefix" echo "관리자 로그인 정보는 직접 설정됩니다" ;; @@ -8297,7 +8297,7 @@ linux_ldnmp() { clear webname="站点重定向" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy nginx_install_status @@ -8321,7 +8321,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8335,7 +8335,7 @@ linux_ldnmp() { send_stats "설치하다$webname" echo "배포를 시작하십시오$webname" add_yuming - echo -e "도메인 이름 형식 :${gl_huang}google.com${gl_bai}" + echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming nginx_install_status install_ssltls @@ -8398,7 +8398,7 @@ linux_ldnmp() { clear webname="AI绘画提示词生成器" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming nginx_install_status install_ssltls @@ -8449,10 +8449,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드를 업로드하십시오" + echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드 업로드" echo "-------------" - echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리에서" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드 할 수도 있습니다. 원격 다운로드를 건너 뛰려면 Enter를 직접 누르십시오." url_download + echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,12 +8462,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이 위치한 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/와 유사한 index.html로가는 경로를 입력하십시오.$yuming/index/): " index_lujing + read -e -p "(/home/web/html/과 유사하게 index.html 경로를 입력하세요.$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8495,7 +8495,7 @@ linux_ldnmp() { send_stats "LDNMP 환경 백업" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + echo -e "${gl_huang}백업 중$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -8505,10 +8505,10 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip - read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." + echo "오류: 원격 서버 IP를 입력하세요." continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -8518,7 +8518,7 @@ linux_ldnmp() { scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." else - echo "전송할 파일은 찾을 수 없었습니다." + echo "전송할 파일을 찾을 수 없습니다." fi break ;; @@ -8535,8 +8535,8 @@ linux_ldnmp() { 33) clear send_stats "시간이 지정된 원격 백업" - read -e -p "원격 서버 IP를 입력하십시오." useip - read -e -p "원격 서버 비밀번호를 입력하십시오." usepasswd + read -e -p "원격 서버 IP를 입력하세요." useip + read -e -p "원격 서버 비밀번호를 입력하세요:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8547,7 +8547,7 @@ linux_ldnmp() { echo "------------------------" echo "1. 주간 백업 2. 매일 백업" - read -e -p "선택을 입력하십시오 :" dingshi + read -e -p "선택사항을 입력하세요:" dingshi case $dingshi in 1) @@ -8583,7 +8583,7 @@ linux_ldnmp() { linux_ldnmp fi - # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. + # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8593,7 +8593,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8602,7 +8602,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "압축 패키지가 발견되지 않았습니다." + echo "압축된 패키지를 찾을 수 없습니다." fi ;; @@ -8621,7 +8621,7 @@ linux_ldnmp() { while true; do clear send_stats "LDNMP 환경을 업데이트하십시오" - echo "LDNMP 환경을 업데이트하십시오" + echo "LDNMP 환경 업데이트" echo "------------------------" ldnmp_v echo "구성 요소의 새 버전을 발견하십시오" @@ -8646,7 +8646,7 @@ linux_ldnmp() { echo echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" echo "------------------------" - echo "5. 전체 환경을 업데이트하십시오" + echo "5. 전체 환경 업데이트" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -8659,7 +8659,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 8.0 8.3 8.4 9.0) (최신 버전을 얻으려면 입력) :" version + read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 8.0 8.3 8.4 9.0)(최신 버전을 얻으려면 Enter 키를 누르세요):" version local version=${version:-latest} cd /home/web/ @@ -8676,7 +8676,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "입력하십시오${ldnmp_pods}버전 번호 (예 : 7.4 8.0 8.1 8.2 8.3) (최신 버전을 얻으려면 입력) :" version + read -e -p "입력하십시오${ldnmp_pods}버전 번호(예: 7.4 8.0 8.1 8.2 8.3)(최신 버전을 얻으려면 Enter 키를 누르세요):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8729,7 +8729,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP 환경을 완전히 업데이트하십시오" + send_stats "LDNMP 환경 전체 업데이트" cd /home/web/ docker compose down --rmi all @@ -8779,7 +8779,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" esac break_end @@ -8799,12 +8799,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "응용 프로그램 시장" + echo -e "응용 시장" echo -e "${gl_kjlan}------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 루프로 색상을 설정하십시오 + # 루프를 사용하여 색상 설정 for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -8813,69 +8813,69 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}Aapanel International Edition" - echo -e "${gl_kjlan}3. ${color3}1 파넬 신세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}우분투 원격 데스크탑 웹 에디션" + echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" + echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" - echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}Rocketchat 멀티 플레이어 온라인 채팅 시스템" + echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}Zendao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" + echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${color15}EMBY 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" + echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${color23}메모 웹 페이지 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 타이밍 작업 관리 프레임 워크" - echo -e "${gl_kjlan}27. ${color27}도크 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}Librespeed 속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}Photoprism 개인 앨범 시스템" + echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}Drawio 무료 온라인 차트 소프트웨어${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}썬 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" - echo -e "${gl_kjlan}43. ${color43}Rustdesk 원격 책상 (서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}Github Acceleration Station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}프로 메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" + echo -e "${gl_kjlan}43. ${color43}RustDesk 원격 데스크톱(서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}GitHub 가속 스테이션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE 치킨 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" + echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" - echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투 (서버 측)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}Dify Big Model 지식 기반${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}래그 플로 큰 모델 지식 기반" + echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${color67}DDNS-GO 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllInsSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${color69}sftpgo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" + echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}Bitwarden 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}Libretv 개인 영화 및 텔레비전${gl_kjlan}74. ${color74}Moontv 개인 영화" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}Jitsimeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" - echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리 핀 미디어 관리 시스템" - echo -e "${gl_kjlan}87. ${color87}synctv 영화 시청 인공물${gl_kjlan}88. ${color88}자체 호스팅 라이브 방송 플랫폼" - echo -e "${gl_kjlan}89. ${color89}filecodebox 파일 Express${gl_kjlan}90. ${color90}매트릭스 분산 채팅 프로토콜" + echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" + echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" - echo -e "${gl_kjlan}93. ${color93}DUFS 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" - echo -e "${gl_kjlan}95. ${color95}종이없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAUTH 자체 호스팅 2 단계 유효성 검사기" - echo -e "${gl_kjlan}97. ${color97}와이어 가드 네트워킹 (서버 측)${gl_kjlan}98. ${color98}와이어 가드 네트워킹 (클라이언트)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" + echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" + echo -e "${gl_kjlan}95. ${color95}종이 없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAuth 자체 호스팅 2단계 인증자" + echo -e "${gl_kjlan}97. ${color97}WireGuard 네트워킹(서버)${gl_kjlan}98. ${color98}WireGuard 네트워킹(클라이언트)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 비디오 생성 도구${gl_kjlan}102. ${color102}vecechat 멀티 플레이어 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 응용 프로그램 데이터를 복원하십시오" + echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9032,7 +9032,7 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 이름 설정 :" admin read -e -p "로그인 사용자 비밀번호 설정 :" admin_password docker run -d \ --name=webtop-ubuntu \ @@ -9066,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "Nezha를 구축하십시오" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9075,9 +9075,9 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" - echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 작동 및 유지 보수 도구" - echo "공식 웹 사이트 구성 문서 : https://nezha.wiki/guide/dashboard.html" + echo -e "Nezha 모니터링$check_docker $update_status" + echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" + echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip @@ -9086,7 +9086,7 @@ while true; do echo "------------------------" echo "1. 사용" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" choice @@ -9156,8 +9156,8 @@ while true; do clear echo -e "우체국 서비스$check_docker $update_status" - echo "Poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." + echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" echo "" echo "포트 감지" @@ -9172,14 +9172,14 @@ while true; do if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "액세스 주소 :" + echo "방문 주소:" echo "https://$yuming" fi echo "------------------------" echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" choice @@ -9192,7 +9192,7 @@ while true; do echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "이 DNS 레코드를 먼저 구문 분석하십시오" + echo "먼저 이 DNS 레코드를 구문 분석하세요." echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9202,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "계속하려면 키를 누르십시오 ..." + echo "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install jq @@ -9293,7 +9293,7 @@ while true; do clear ip_address - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -9313,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다." + echo "앱이 제거되었습니다" } docker_app_plus @@ -9411,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -9565,7 +9565,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "Lei Chi는 변경 기술이 개발 한 WAF 사이트 방화벽 프로그램 패널로, 자동 방어를 위해 대행사 사이트를 역전시킬 수 있습니다." + echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -9575,9 +9575,9 @@ while true; do echo "------------------------" echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -9587,7 +9587,7 @@ while true; do add_app_id clear - echo "Thunder Pool WAF 패널이 설치되었습니다" + echo "Leichi WAF 패널이 설치되었습니다." check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9600,7 +9600,7 @@ while true; do add_app_id clear - echo "Leichi WAF 패널이 업데이트되었습니다." + echo "Thunder Pool WAF 패널이 업데이트되었습니다" check_docker_app_ip ;; 3) @@ -9730,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 비밀번호 설정:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10278,7 +10278,7 @@ while true; do ip_address echo "설치" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 admin입니다." + echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" } docker_app_update() { @@ -10383,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE 치킨" + send_stats "PVE 오픈 병아리" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10503,7 +10503,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -10518,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다." + echo "앱이 제거되었습니다" } docker_app_plus @@ -10546,7 +10546,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -10561,7 +10561,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -10569,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -10590,9 +10590,9 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "설치" + echo "설치 완료" check_docker_app_ip - echo "초기 사용자 이름 : 관리자" + echo "초기 사용자 이름: admin" echo "초기 비밀번호 : changeme" } @@ -10610,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -10657,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -10673,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -10970,7 +10970,7 @@ while true; do docker_app_install() { read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "로그인 사용자 비밀번호 설정:" admin_password read -e -p "인증 코드를 입력하십시오." shouquanma @@ -10987,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11001,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11074,7 +11074,7 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" app_use + read -e -p "로그인 사용자 이름 설정:" app_use read -e -p "로그인 비밀번호 설정 :" app_passwd docker run -d \ @@ -11222,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11272,7 +11272,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11568,7 +11568,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "초기 사용자 또는 관리자를 생성합니다. 다음 사용자 이름과 비밀번호를 설정하고 관리자인지 여부를 설정하세요." + echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11620,7 +11620,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11709,8 +11709,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" app_use - read -e -p "로그인 비밀번호 설정 :" app_passwd + read -e -p "로그인 사용자 이름 설정:" app_use + read -e -p "로그인 비밀번호 설정:" app_passwd docker run -d \ --name ${docker_name} \ @@ -11826,7 +11826,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11846,7 +11846,7 @@ while true; do read -e -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT COUNT=${COUNT:-5} - read -e -p "Wireguard 세그먼트를 입력하십시오 (기본값 10.13.13.0) :" NETWORK + read -e -p "WireGuard 네트워크 세그먼트(기본값 10.13.13.0)를 입력하세요." NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11923,10 +11923,10 @@ while true; do echo -e "${gl_huang}모든 클라이언트 구성 코드 :${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}모든 출력은 각 클라이언트가 제공합니다. 사용법은 다음과 같습니다.${gl_bai}" - echo -e "${gl_lv}1. 휴대 전화에서 WG의 앱을 다운로드하고 위의 QR 코드를 스캔하여 네트워크에 빠르게 연결하십시오.${gl_bai}" + echo -e "${gl_lv}${COUNT}모든 출력은 모두 각 클라이언트에 의해 구성되며 사용 방법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}1. 휴대폰에 wg APP을 다운로드하고 위의 QR 코드를 스캔하면 빠르게 인터넷에 연결됩니다.${gl_bai}" echo -e "${gl_lv}2. Windows 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결하십시오.${gl_bai}" - echo -e "${gl_lv}3. Linux는 스크립트를 사용하여 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" + echo -e "${gl_lv}3. 스크립트를 사용하여 Linux에 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" echo -e "${gl_lv}공식 클라이언트 다운로드 방법 : https://www.wireguard.com/install/${gl_bai}" break_end @@ -11977,10 +11977,10 @@ while true; do fi done - # 구성 파일에 쓰십시오 + # 구성 파일 쓰기 echo "$input" > "$CONFIG_FILE" - echo "클라이언트 구성이 저장되었습니다$CONFIG_FILE" + echo "클라이언트 구성이 다음에 저장되었습니다.$CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -12025,10 +12025,10 @@ while true; do docker_app_install() { - read -e -p "CPU 코어 수를 설정 (기본값 2) :" CPU_CORES + read -e -p "CPU 코어 수를 설정합니다(기본값 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "메모리 크기를 설정 (기본 4G) :" RAM_SIZE + read -e -p "메모리 크기 설정(기본 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -12059,7 +12059,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -12129,7 +12129,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" @@ -12168,24 +12168,24 @@ while true; do b) clear - send_stats "모든 응용 프로그램 백업" + send_stats "모든 애플리케이션 백업" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업$backup_filename ...${gl_bai}" + echo -e "${gl_huang}백업 중$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "백업 파일이 작성되었습니다 : /$backup_filename" + echo "생성된 백업 파일: /$backup_filename" read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip - read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + read -e -p "원격 서버 IP를 입력하세요:" remote_ip + read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." + echo "오류: 원격 서버 IP를 입력하세요." continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -12193,9 +12193,9 @@ while true; do ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "파일은 원격 서버/루트 디렉토리로 전송되었습니다." + echo "원격 서버/루트 디렉터리로 파일이 전송되었습니다." else - echo "전송할 파일을 찾을 수 없습니다." + echo "전송할 파일은 찾을 수 없었습니다." fi break ;; @@ -12210,12 +12210,12 @@ while true; do r) root_use - send_stats "모든 응용 프로그램이 복원됩니다" + send_stats "모든 앱 복원" echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename if [ "$filename" == "0" ]; then break_end @@ -12228,11 +12228,11 @@ while true; do fi if [ -n "$filename" ]; then - echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" + echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." else - echo "압축 패키지가 발견되지 않았습니다." + echo "압축된 패키지를 찾을 수 없습니다." fi ;; @@ -12255,35 +12255,35 @@ linux_work() { while true; do clear - send_stats "백엔드 작업 공간" + send_stats "백엔드 작업공간" echo -e "백엔드 작업 공간" echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." - echo -e "SSH를 분리하더라도 작업 공간의 작업이 중단되지 않으며 백그라운드의 작업이 거주됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" echo -e "${gl_kjlan}------------------------" - echo "현재 기존 작업 공간 목록" + echo "현재 존재하는 작업공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" - echo -e "${gl_kjlan}2. ${gl_bai}작업 공간 2 번" + echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" - echo -e "${gl_kjlan}6. ${gl_bai}작업 공간 No. 6" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" - echo -e "${gl_kjlan}8. ${gl_bai}작업 공간 번호 8" + echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" - echo -e "${gl_kjlan}23. ${gl_bai}배경 작업 공간에 명령을 주입합니다" + echo -e "${gl_kjlan}23. ${gl_bai}백그라운드 작업 공간에 명령 삽입" echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -12291,7 +12291,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "작업 공간을 시작하십시오$SESSION_NAME" tmux_run ;; @@ -12299,14 +12299,14 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 4) @@ -12320,7 +12320,7 @@ linux_work() { clear install tmux local SESSION_NAME="work5" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 6) @@ -12367,20 +12367,20 @@ linux_work() { else local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH 거주 모드" - echo -e "SSH 거주 모드${tmux_sshd_status}" - echo "SSH 연결이 활성화 된 후에는 거주 모드에 직접 입력하여 이전 작업 상태로 돌아갑니다." + send_stats "SSH 상주 모드" + echo -e "SSH 상주 모드${tmux_sshd_status}" + echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" echo "1. 2를 켜십시오. 2를 끕니다" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" gongzuoqu_del + read -e -p "선택사항을 입력하세요:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 자동으로 tmux 세션 시작\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run @@ -12397,29 +12397,29 @@ linux_work() { ;; 22) - read -e -p "1001 kj001 work1과 같이 생성하거나 입력한 작업공간의 이름을 입력하세요." SESSION_NAME + read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME tmux_run - send_stats "사용자 정의 작업 공간" + send_stats "맞춤형 작업공간" ;; 23) - read -e -p "Curl -fssl https://get.docker.com | 쉿:" tmuxd + read -e -p "다음과 같이 백그라운드에서 실행하려는 명령을 입력하십시오. 컬 -fsSL https://get.docker.com | 쉿:" tmuxd tmux_run_d - send_stats "배경 작업 공간에 명령을 주입합니다" + send_stats "백그라운드 작업 공간에 명령 삽입" ;; 24) read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "작업 공간을 삭제합니다" + send_stats "작업공간 삭제" ;; 0) kejilion ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -12444,46 +12444,46 @@ linux_Settings() { while true; do clear - # Send_stats "시스템 도구" + # send_stats "시스템 도구" echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python을 설치하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" + echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 IPv4/IPv6을 전환하십시오" + echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속 설정" - echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름을 수정하십시오" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름 수정" echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}예약된 작업 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}현재 한도의 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-BOT 시스템 모니터링 및 조기 경고${gl_kjlan}26. ${gl_bai}OpenSsh 고위험 취약점을 수정하십시오" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템에서 커널 매개 변수의 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령 라인 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령 줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" + echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}게시판${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하십시오${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" - echo -e "${gl_kjlan}101. ${gl_bai}K 명령의 고급 사용${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 라이온 스크립트를 제거하십시오" + echo -e "${gl_kjlan}41. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하세요${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" + echo -e "${gl_kjlan}101. ${gl_bai}k 명령의 고급 사용법${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 사자 스크립트 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "바로 가기 키를 입력하십시오 (종료하려면 0을 입력하십시오) :" kuaijiejian + read -e -p "바로가기 키를 입력하십시오(종료하려면 0을 입력하십시오):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -12491,7 +12491,7 @@ linux_Settings() { find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian echo "바로 가기 키가 설정되어 있습니다" - send_stats "스크립트 바로 가기 키가 설정되었습니다" + send_stats "스크립트 단축키가 설정되었습니다" break_end linux_Settings done @@ -12499,7 +12499,7 @@ linux_Settings() { 2) clear - send_stats "로그인 비밀번호를 설정하십시오" + send_stats "로그인 비밀번호를 설정하세요" echo "로그인 비밀번호를 설정하십시오" passwd ;; @@ -12511,15 +12511,15 @@ linux_Settings() { 4) root_use - send_stats "PY 버전 관리" + send_stats "py 버전 관리" echo "파이썬 버전 관리" echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원되는 모든 버전을 완벽하게 설치합니다!" + echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "권장 버전 : 3.12 3.11 3.10 3.9 3.8 2.7" + echo "권장 버전: 3.12 3.11 3.10 3.9 3.8 2.7" echo "더 많은 버전 : https://www.python.org/downloads/" echo "------------" read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v @@ -12595,7 +12595,7 @@ EOF 5) root_use - send_stats "포트 열기" + send_stats "열린 포트" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "모든 포트가 열려 있습니다" @@ -12609,17 +12609,17 @@ EOF clear sed -i 's/#Port/Port/' /etc/ssh/sshd_config - # 현재 SSH 포트 번호를 읽으십시오 + # 현재 SSH 포트 번호 읽기 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 현재 SSH 포트 번호를 인쇄하십시오 + # 현재 SSH 포트 번호 인쇄 echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 - read -e -p "새로운 SSH 포트 번호를 입력하십시오 :" new_port + read -e -p "새 SSH 포트 번호를 입력하세요." new_port # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 @@ -12627,7 +12627,7 @@ EOF send_stats "SSH 포트가 수정되었습니다" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH 포트 수정을 종료하십시오" + send_stats "SSH 포트 수정 종료" break else echo "포트 번호가 잘못되었습니다. 1~65535 사이의 숫자를 입력하세요." @@ -12635,8 +12635,8 @@ EOF break_end fi else - echo "입력이 유효하지 않으므로 번호를 입력하십시오." - send_stats "잘못된 SSH 포트 입력" + echo "입력이 잘못되었습니다. 숫자를 입력하세요." + send_stats "잘못된 SSH 포트가 입력되었습니다." break_end fi done @@ -12655,8 +12655,8 @@ EOF ;; 9) root_use - send_stats "신규 사용자는 루트를 비활성화합니다" - read -e -p "새 사용자 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_username + send_stats "신규 사용자에 대한 루트 비활성화" + read -e -p "새 사용자 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12677,26 +12677,26 @@ EOF 10) root_use - send_stats "V4/V6 우선 순위를 설정하십시오" + send_stats "v4/v6 우선순위 설정" while true; do clear - echo "V4/V6 우선 순위를 설정하십시오" + echo "v4/v6 우선순위 설정" echo "------------------------" if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv4${gl_bai}우선 사항" + echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv4${gl_bai}우선 사항" else echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" - echo "1. IPv4 우선 순위 2. IPv6 우선 순위 3. IPv6 수리 도구" + echo "1. IPv4 우선 2. IPv6 우선 3. IPv6 복구 도구" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선호하는 네트워크를 선택하십시오." choice + read -e -p "선호하는 네트워크를 선택하세요:" choice case $choice in 1) @@ -12714,7 +12714,7 @@ EOF 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 마스터 JHB가 제공합니다." + echo "이 기능은 jhb에서 제공합니다. 감사합니다!" send_stats "IPv6 수정" ;; @@ -12733,10 +12733,10 @@ EOF 12) root_use - send_stats "가상 메모리를 설정합니다" + send_stats "가상 메모리 설정" while true; do clear - echo "가상 메모리를 설정합니다" + echo "가상 메모리 설정" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') @@ -12745,9 +12745,9 @@ EOF echo "------------------------" echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case "$choice" in 1) @@ -12761,7 +12761,7 @@ EOF ;; 3) - send_stats "4G 가상 메모리가 설정되었습니다" + send_stats "4G 가상 메모리가 설정되었습니다." add_swap 4096 ;; @@ -12769,7 +12769,7 @@ EOF 4) read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap add_swap "$new_swap" - send_stats "사용자 정의 가상 메모리가 설정되었습니다" + send_stats "사용자 정의 가상 메모리 세트" ;; *) @@ -12796,22 +12796,22 @@ EOF echo "" echo "계정 운영" echo "------------------------" - echo "1. 일반 계정 만들기 2. 프리미엄 계정 만들기" + echo "1. 일반 계정 생성 2. 프리미엄 계정 생성" echo "------------------------" - echo "3. 최고 권한을 부여 4. 최고 권한을 취소하십시오." + echo "3. 가장 높은 권한을 부여합니다. 4. 가장 높은 권한을 제거합니다." echo "------------------------" echo "5. 계정 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + read -e -p "새 사용자 이름을 입력하세요:" new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 새로운 사용자 생성 및 비밀번호 설정 useradd -m -s /bin/bash "$new_username" passwd "$new_username" @@ -12819,7 +12819,7 @@ EOF ;; 2) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + # 사용자에게 새 사용자 이름을 묻는 메시지 표시 read -e -p "새 사용자 이름을 입력하십시오 :" new_username # 새 사용자를 생성하고 비밀번호를 설정하십시오 @@ -12835,21 +12835,21 @@ EOF ;; 3) - read -e -p "사용자 이름을 입력하십시오 :" username + read -e -p "사용자 이름을 입력하세요:" username # 새 사용자에게 sudo 권한 부여 echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo ;; 4) - read -e -p "사용자 이름을 입력하십시오 :" username - # Sudoers 파일에서 사용자의 Sudo 권한을 제거하십시오 + read -e -p "사용자 이름을 입력하세요:" username + # sudoers 파일에서 사용자의 sudo 권한을 제거합니다. sed -i "/^$username\sALL=(ALL:ALL)\sALL/d" /etc/sudoers ;; 5) read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자 및 해당 홈 디렉터리 삭제 + # 사용자와 홈 디렉토리를 삭제하십시오 userdel -r "$username" ;; @@ -12871,12 +12871,12 @@ EOF done echo "" - echo "임의의 이름" + echo "임의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5 개의 임의의 사용자 이름을 생성합니다 + # 5개의 무작위 사용자 이름 생성 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) @@ -12885,11 +12885,11 @@ EOF done echo "" - echo "무작위 uuid" + echo "무작위 UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "무작위 uuid$i: $uuid" + echo "무작위 UUID$i: $uuid" done echo "" @@ -12897,15 +12897,15 @@ EOF echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "랜덤 비밀번호$i: $password" + echo "임의의 비밀번호$i: $password" done echo "" - echo "32 비트 랜덤 비밀번호" + echo "32비트 임의 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "랜덤 비밀번호$i: $password" + echo "임의의 비밀번호$i: $password" done echo "" @@ -12913,7 +12913,7 @@ EOF 15) root_use - send_stats "시간대 변경" + send_stats "시간대를 변경하십시오" while true; do clear echo "시스템 시간 정보" @@ -12925,30 +12925,30 @@ EOF local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대와 시간을 보여줍니다 - echo "현재 시스템 시간대 :$timezone" + echo "현재 시스템 시간대:$timezone" echo "현재 시스템 시간 :$current_time" echo "" echo "시간대 스위칭" echo "------------------------" echo "아시아" - echo "1. 중국의 상하이 시간 2. 중국의 홍콩 시간" + echo "1. 중국 상하이 시간 2. 중국 홍콩 시간" echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" echo "5. 싱가포르 시간 6. 콜카타, 인도 시간" - echo "7. UAE 8의 두바이 시간. 호주 시드니 시간" + echo "7. 아랍에미리트 두바이 시간 8. 호주 시드니 시간" echo "9. 태국 방콕에서의 시간" echo "------------------------" echo "유럽" - echo "11. 영국의 런던 시간 12. 프랑스의 파리 시간" - echo "13. 베를린 시간, 독일 14. 모스크바 시간, 러시아" - echo "15. 네덜란드에서 우트레흐트 시간 16. 스페인의 마드리드 시간" + echo "11. 영국 런던 시간 12. 프랑스 파리 시간" + echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" - echo "21. 서양 시간 22. 동부 시간" + echo "21. 미국 서부 시간 22. 미국 동부 시간" echo "23. 캐나다 시간 24. 멕시코 시간" echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC 세계 표준시" + echo "31. UTC 글로벌 표준 시간" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -13000,7 +13000,7 @@ EOF while true; do clear local current_hostname=$(uname -n) - echo -e "현재 호스트 이름 :${gl_huang}$current_hostname${gl_bai}" + echo -e "현재 호스트 이름:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then @@ -13009,7 +13009,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, Centos 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13027,11 +13027,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "호스트 이름은 다음으로 변경되었습니다.$new_hostname" + echo "호스트 이름이 다음으로 변경되었습니다.$new_hostname" send_stats "호스트 이름이 변경되었습니다" sleep 1 else - echo "종료, 호스트 이름이 변경되지 않았습니다." + echo "호스트 이름을 변경하지 않고 종료되었습니다." break fi done @@ -13039,14 +13039,14 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스를 변경하십시오" + send_stats "시스템 업데이트 소스 변경" clear - echo "업데이트 소스 영역을 선택하십시오" + echo "업데이트 소스 지역 선택" echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" echo "------------------------" echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" choice @@ -13056,11 +13056,11 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "중국 본토의 교육 원" + send_stats "중국 본토 교육 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "해외 출신" + send_stats "해외 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) @@ -13072,7 +13072,7 @@ EOF ;; 20) - send_stats "타이밍 작업 관리" + send_stats "예약된 작업 관리" while true; do clear check_crontab_installed @@ -13084,13 +13084,13 @@ EOF echo "------------------------" echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택을 입력하십시오 :" sub_choice case $sub_choice in 1) - read -e -p "새 작업의 실행 명령을 입력하십시오:" newquest + read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest echo "------------------------" echo "1. 월간 작업 2. 주간 작업" echo "3. 일일 작업 4. 시간당 작업" @@ -13103,7 +13103,7 @@ EOF (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "작업을 수행 할 일주일을 선택합니까? (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "작업을 수행할 요일을 선택하시겠습니까? (0-6, 0은 일요일을 나타냄):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) @@ -13111,17 +13111,17 @@ EOF (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "작업을 수행하기 위해 몇 분의 시간을 입력합니까? (Mins, 0-60) :" minute + read -e -p "작업을 실행해야 하는 시간을 입력하세요. (분, 0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "시간이 정한 작업을 추가하십시오" + send_stats "예약된 작업 추가" ;; 2) - read -e -p "삭제 해야하는 키워드를 입력하십시오." kquest + read -e -p "삭제할 작업의 키워드를 입력하세요:" kquest crontab -l | grep -v "$kquest" | crontab - send_stats "타이밍 작업을 삭제하십시오" ;; @@ -13148,21 +13148,21 @@ EOF echo "" echo "작동하다" echo "------------------------" - echo "1. 새 구문 분석 추가 2. 구문 분석 주소 삭제" + echo "1. 새로운 해상도 추가 2. 해상도 주소 삭제" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "선택사항을 입력하세요:" host_dns case $host_dns in 1) read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost echo "$addhost" >> /etc/hosts - send_stats "로컬 호스트 구문 분석이 추가되었습니다" + send_stats "로컬 호스트 해상도가 추가되었습니다." ;; 2) - read -e -p "삭제 해야하는 구문 분석 컨텐츠의 키워드를 입력하십시오." delhost + read -e -p "삭제해야 하는 구문 분석된 콘텐츠의 키워드를 입력하세요." delhost sed -i "/$delhost/d" /etc/hosts send_stats "로컬 호스트 구문 분석 및 삭제" ;; @@ -13183,12 +13183,12 @@ EOF echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 방어 프로그램 설치" echo "------------------------" - echo "2. SSH 차단 레코드보기" + echo "2. SSH 차단 기록 보기" echo "3. 실시간 로그 모니터링" echo "------------------------" - echo "9. 방어 프로그램을 제거하십시오" + echo "9. 방어 프로그램 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" @@ -13214,7 +13214,7 @@ EOF 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2ban 방어 프로그램은 제거되었습니다" + echo "Fail2Ban 방어 프로그램이 제거되었습니다." break ;; *) @@ -13227,41 +13227,41 @@ EOF 23) root_use - send_stats "현재 제한 종료 기능" + send_stats "전류 제한 차단 기능" while true; do clear echo "현재 제한 종료 기능" echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" echo "------------------------------------------------" - echo "서버가 다시 시작되면 현재 트래픽 사용량이 지워집니다!" + echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" output_status echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" - # limiting_shut_down.sh 파일이 있는지 확인하십시오 + # Limiting_Shut_down.sh 파일이 있는지 확인하세요. if [ -f ~/Limiting_Shut_down.sh ]; then # threshold_gb의 값을 얻으십시오 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}현재 세트 입력-스테이션 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}전류 제한 종료 기능이 활성화되지 않았습니다${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo echo "------------------------------------------------" echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" echo "------------------------" - echo "1. 전류 제한 종료 기능을 활성화합니다. 2. 전류 제한 종료 기능을 비활성화합니다." + echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 이전 메뉴로 돌아갑니다" echo "------------------------" read -e -p "선택을 입력하십시오 :" Limiting case "$Limiting" in 1) - # 새 가상 메모리 크기를 입력하십시오 + # 새 가상 메모리 크기 입력 echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} @@ -13280,7 +13280,7 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "전류 제한 종료가 설정되었습니다" + echo "전류 제한 종료가 설정되었습니다." send_stats "전류 제한 종료가 설정되었습니다" ;; 2) @@ -13288,7 +13288,7 @@ EOF crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 종료 기능이 꺼졌습니다" + echo "전류 제한 차단 기능이 꺼졌습니다." ;; *) break @@ -13301,19 +13301,19 @@ EOF 24) root_use - send_stats "개인키 로그인" + send_stats "개인 키 로그인" while true; do clear echo "ROOT 개인 키 로그인 모드" echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" echo "------------------------------------------------" - echo "키 쌍이 생성되며 SSH 로그인을위한보다 안전한 방법" + echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" host_dns + read -e -p "선택사항을 입력하세요:" host_dns case $host_dns in 1) @@ -13323,15 +13323,15 @@ EOF ;; 2) - send_stats "기존 공개 키를 가져옵니다" + send_stats "기존 공개 키 가져오기" import_sshkey break_end ;; 3) - send_stats "로컬 비밀 키를보십시오" + send_stats "로컬 키 보기" echo "------------------------" - echo "공개 키 정보" + echo "공개키 정보" cat ~/.ssh/authorized_keys echo "------------------------" echo "개인 키 정보" @@ -13351,13 +13351,13 @@ EOF 25) root_use send_stats "전보 경고" - echo "TG-BOT 모니터링 및 조기 경고 기능" - echo "비디오 소개 : https://youtu.be/vll-eb3z_ty" + echo "TG-bot 모니터링 및 조기경보 기능" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "기본 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인의 실시간 모니터링 및 조기 경고를 실현하려면 조기 경고를 받으려면 TG Robot API 및 사용자 ID를 구성해야합니다." + echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속하시겠습니까? (예/아니요):" choice + read -e -p "계속할거야? (Y/N) :" choice case "$choice" in [Yy]) @@ -13394,7 +13394,7 @@ EOF source ~/.profile clear - echo "TG-BOT 조기 경고 시스템이 시작되었습니다" + echo "TG-bot 조기경보 시스템이 활성화되었습니다." echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) @@ -13408,7 +13408,7 @@ EOF 26) root_use - send_stats "SSH에서 고위험 취약점을 수정하십시오" + send_stats "고위험 SSH 취약점 수정" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13475,31 +13475,31 @@ EOF 41) clear - send_stats "게시판" - echo "공식 게시위원회의 기술 사자를 방문하십시오. 스크립트에 대한 아이디어가 있으시면 메시지를 남겨두고 의사 소통하십시오!" + send_stats "메시지 보드" + echo "Technology Lion 공식 게시판을 방문해 보세요. 스크립트에 대한 아이디어가 있으시면 교환 메시지를 남겨주세요!" echo "https://board.kejilion.pro" - echo "공개 비밀번호 : Kejilion.sh" + echo "공개 비밀번호: kejilion.sh" ;; 66) root_use send_stats "원 스톱 튜닝" - echo "원 스톱 시스템 최적화" + echo "원스톱 시스템 튜닝" echo "------------------------------------------------" echo "다음은 작동하고 최적화됩니다" - echo "1. 시스템을 최신으로 업데이트하십시오" + echo "1. 시스템을 최신으로 업데이트하세요" echo "2. 시스템 정크 파일 정리" - echo -e "3. 가상 메모리를 설정하십시오${gl_huang}1G${gl_bai}" + echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" echo -e "5. 모든 포트를 엽니 다" - echo -e "6. 켜십시오${gl_huang}BBR${gl_bai}가속" - echo -e "7. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "6. 켜기${gl_huang}BBR${gl_bai}가속하다" + echo -e "7. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" - echo -e "9. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "9. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" echo "------------------------------------------------" - read -e -p "한 번의 클릭 유지 보수가 있습니까? (Y/N) :" choice + read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice case "$choice" in [Yy]) @@ -13507,7 +13507,7 @@ EOF send_stats "원 스톱 튜닝 시작" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하십시오" + echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하세요" echo "------------------------------------------------" linux_clean @@ -13520,7 +13520,7 @@ EOF echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" echo "------------------------------------------------" echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" @@ -13530,7 +13530,7 @@ EOF echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 설정하십시오${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" local country=$(curl -s ipinfo.io/country) @@ -13573,7 +13573,7 @@ EOF 99) clear - send_stats "시스템을 다시 시작하십시오" + send_stats "시스템을 다시 시작하세요" server_reboot ;; 100) @@ -13589,31 +13589,31 @@ EOF local status_message="无法确定的状态" fi - echo "개인 정보 및 보안" - echo "스크립트는 사용자 기능에 대한 데이터를 수집하고 스크립트 경험을 최적화하며보다 재미 있고 유용한 기능을 만듭니다." + echo "개인 정보 보호 및 보안" + echo "스크립트는 사용자의 기능 사용에 대한 데이터를 수집하고 스크립트 경험을 최적화하며 더 재미 있고 유용한 기능을 만듭니다." echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." echo "------------------------------------------------" - echo -e "현재 상태 :$status_message" + echo -e "현재 상태:$status_message" echo "--------------------" - echo "1. 수집을 켭니다" - echo "2. 컬렉션을 닫습니다" + echo "1. 수집 시작" + echo "2. 수집 종료" echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh echo "수집이 시작되었습니다" - send_stats "개인 정보 보호 및 보안 컬렉션이 활성화되었습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 설정되었습니다." ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "컬렉션이 닫혔습니다" + echo "컬렉션이 닫혔습니다." send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" ;; *) @@ -13631,9 +13631,9 @@ EOF 102) clear send_stats "기술 라이온 스크립트를 제거하십시오" - echo "기술 라이온 스크립트를 제거하십시오" + echo "기술 사자 스크립트 제거" echo "------------------------------------------------" - echo "Kejilion 스크립트를 완전히 제거하고 다른 기능에 영향을 미치지 않습니다." + echo "kejilion 스크립트는 다른 기능에 영향을 주지 않고 완전히 제거됩니다." read -e -p "계속할거야? (Y/N) :" choice case "$choice" in @@ -13642,7 +13642,7 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "대본은 제거되었습니다." + echo "스크립트가 제거되었습니다. 안녕!" break_end clear exit @@ -13690,9 +13690,9 @@ linux_file() { ls --color=auto -x echo "------------------------" echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." echo "------------------------" - echo "11. 파일 만들기 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" + echo "11. 파일 생성 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" echo "15. 파일을 삭제하십시오" echo "------------------------" echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" @@ -13710,13 +13710,13 @@ linux_file() { ;; 2) # 创建目录 read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname - mkdir -p "$dirname" && echo "디렉토리가 생성되었습니다" || echo "창조가 실패했습니다" - send_stats "디렉터리 생성" + mkdir -p "$dirname" && echo "디렉터리가 생성되었습니다." || echo "생성 실패" + send_stats "디렉토리를 만듭니다" ;; 3) # 修改目录权限 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + read -e -p "디렉토리 이름을 입력하십시오:" dirname + read -e -p "권한을 입력하세요(예: 755):" perm + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다." || echo "수정이 실패했습니다" send_stats "디렉토리 권한을 수정하십시오" ;; 4) # 重命名目录 @@ -13727,7 +13727,7 @@ linux_file() { ;; 5) # 删除目录 read -e -p "삭제할 디렉터리 이름을 입력하세요:" dirname - rm -rf "$dirname" && echo "디렉토리가 삭제되었습니다" || echo "삭제가 실패했습니다" + rm -rf "$dirname" && echo "디렉터리가 삭제되었습니다." || echo "삭제 실패" send_stats "디렉토리 삭제" ;; 6) # 返回上一级选单目录 @@ -13736,8 +13736,8 @@ linux_file() { ;; 11) # 创建文件 read -e -p "작성하려면 파일 이름을 입력하십시오." filename - touch "$filename" && echo "생성 된 파일" || echo "창조가 실패했습니다" - send_stats "파일을 만듭니다" + touch "$filename" && echo "생성 된 파일" || echo "생성 실패" + send_stats "파일 생성" ;; 12) # 编辑文件 read -e -p "편집 할 파일 이름을 입력하십시오." filename @@ -13748,22 +13748,22 @@ linux_file() { 13) # 修改文件权限 read -e -p "파일 이름을 입력하십시오 :" filename read -e -p "권한을 입력하십시오 (예 : 755) :" perm - chmod "$perm" "$filename" && echo "권한이 수정되었습니다" || echo "수정이 실패했습니다" + chmod "$perm" "$filename" && echo "권한이 수정되었습니다." || echo "수정 실패" send_stats "파일 권한을 수정하십시오" ;; 14) # 重命名文件 - read -e -p "현재 파일 이름을 입력하십시오 :" current_name - read -e -p "새 파일 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "이름이 바뀌 었습니다" || echo "이름 바꾸지 실패했습니다" + read -e -p "현재 파일 이름을 입력하십시오:" current_name + read -e -p "새 파일 이름을 입력하세요:" new_name + mv "$current_name" "$new_name" && echo "파일 이름이 변경되었습니다." || echo "이름 바꾸지 실패했습니다" send_stats "파일의 이름을 바꿉니다" ;; 15) # 删除文件 read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다." || echo "삭제가 실패했습니다" + rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제 실패" send_stats "파일 삭제" ;; 21) # 压缩文件/目录 - read -e -p "압축 할 파일/디렉토리 이름을 입력하십시오." name + read -e -p "압축할 파일/디렉터리 이름을 입력하십시오:" name install tar tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" send_stats "압축 파일/디렉토리" @@ -13772,80 +13772,80 @@ linux_file() { read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오:" filename install tar tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "감압이 실패했습니다" - send_stats "압축 파일/디렉토리 해제" + send_stats "파일/디렉토리 압축 풀기" ;; 23) # 移动文件或目录 - read -e -p "이동하려면 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "이동할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 이동 실패: 파일 또는 디렉터리가 존재하지 않습니다." + echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." + echo "오류: 대상 경로를 입력하십시오." send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." continue fi - mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 이동했습니다$dest_path" || echo "파일이나 디렉토리를 이동하지 못했습니다" - send_stats "파일 또는 디렉토리를 이동하십시오" + mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 다음으로 이동되었습니다.$dest_path" || echo "파일 또는 디렉터리를 이동하지 못했습니다." + send_stats "파일 또는 디렉터리 이동" ;; 24) # 复制文件目录 - read -e -p "복사 할 파일 또는 디렉토리 경로를 입력하십시오." src_path + read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then - echo "오류 : 파일 또는 디렉토리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 복사하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." continue fi - read -e -p "대상 경로를 입력하십시오 (새 파일 이름 또는 디렉토리 이름 포함) :" dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then echo "오류 : 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉토리 복사에 실패 : 지정되지 않은 대상 경로" + send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." continue fi - # -r 옵션을 사용하여 디렉토리를 재귀 적으로 복사하십시오 - cp -r "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 복사되었습니다$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사합니다" + # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. + cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" + send_stats "파일 또는 디렉토리를 복사하십시오" ;; 25) # 传送文件至远端服务器 - read -e -p "전송할 파일 경로를 입력하십시오." file_to_transfer + read -e -p "전송할 파일 경로를 입력하십시오:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "오류 : 파일이 존재하지 않습니다." - send_stats "파일을 전송하지 못했습니다 : 파일이 존재하지 않습니다." + send_stats "파일 전송 실패: 파일이 존재하지 않습니다." continue fi read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip if [ -z "$remote_ip" ]; then - echo "오류 : 원격 서버 IP를 입력하십시오." - send_stats "파일 전송 실패: 원격 서버 IP가 입력되지 않았습니다." + echo "오류: 원격 서버 IP를 입력하세요." + send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" continue fi read -e -p "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" remote_user remote_user=${remote_user:-root} - read -e -p "원격 서버 비밀번호를 입력하십시오 :" -s remote_password + read -e -p "원격 서버 비밀번호를 입력하세요:" -s remote_password echo if [ -z "$remote_password" ]; then echo "오류: 원격 서버 비밀번호를 입력하세요." - send_stats "파일 전송 실패 : 원격 서버 비밀번호를 입력하지 않았습니다" + send_stats "파일 전송 실패: 원격 서버 비밀번호가 입력되지 않았습니다." continue fi read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port remote_port=${remote_port:-22} - # 알려진 호스트를위한 오래된 항목을 명확하게합니다 + # 알려진 호스트에 대한 이전 항목 지우기 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 @@ -13859,7 +13859,7 @@ EOF send_stats "파일 전송이 성공적으로 전송됩니다" else echo "파일 전송이 실패했습니다." - send_stats "파일 전송이 실패했습니다" + send_stats "파일 전송 실패" fi break_end @@ -13872,7 +13872,7 @@ EOF break ;; *) # 处理无效输入 - echo "유효하지 않은 선택, 다시 입력하십시오" + echo "선택이 잘못되었습니다. 다시 입력해 주세요." send_stats "잘못된 선택" ;; esac @@ -13902,7 +13902,7 @@ run_commands_on_servers() { # 추출 된 정보를 배열로 변환합니다 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 통해 반복하고 명령을 실행하십시오 + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -13910,7 +13910,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하십시오$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -13939,12 +13939,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}서버 목록 관리${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}서버를 추가하십시오${gl_kjlan}2. ${gl_bai}서버를 삭제하십시오${gl_kjlan}3. ${gl_bai}서버를 편집하십시오" - echo -e "${gl_kjlan}4. ${gl_bai}백업 클러스터${gl_kjlan}5. ${gl_bai}클러스터를 복원하십시오" + echo -e "${gl_kjlan}4. ${gl_bai}백업 클러스터${gl_kjlan}5. ${gl_bai}클러스터 복원" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}배치로 작업을 실행합니다${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템을 업데이트하십시오${gl_kjlan}13. ${gl_bai}시스템을 청소하십시오" - echo -e "${gl_kjlan}14. ${gl_bai}Docker를 설치하십시오${gl_kjlan}15. ${gl_bai}BBR3을 설치하십시오${gl_kjlan}16. ${gl_bai}1G 가상 메모리를 설정하십시오" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정하십시오${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 명령" + echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3을 설치하십시오${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정하십시오${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -13953,13 +13953,13 @@ while true; do case $sub_choice in 1) send_stats "클러스터 서버를 추가하십시오" - read -e -p "서버 이름 :" server_name - read -e -p "서버 IP:" server_ip + read -e -p "서버 이름:" server_name + read -e -p "서버 IP :" server_ip read -e -p "서버 포트 (22) :" server_port local server_port=${server_port:-22} - read -e -p "서버 사용자 이름 (루트) :" server_username + read -e -p "서버 사용자 이름(루트):" server_username local server_username=${server_username:-root} - read -e -p "서버 사용자 비밀번호 :" server_password + read -e -p "서버 사용자 비밀번호:" server_password sed -i "/servers = \[/a\ {\"name\": \"$server_name\", \"hostname\": \"$server_ip\", \"port\": $server_port, \"username\": \"$server_username\", \"password\": \"$server_password\", \"remote_path\": \"/home/\"}," ~/cluster/servers.py @@ -13970,7 +13970,7 @@ while true; do sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) - send_stats "클러스터 서버를 편집합니다" + send_stats "클러스터 서버 편집" install nano nano ~/cluster/servers.py ;; @@ -13978,7 +13978,7 @@ while true; do 4) clear send_stats "백업 클러스터" - echo -e "바꿔주세요${gl_huang}/root/cluster/servers.py${gl_bai}파일을 다운로드하고 백업을 완료하십시오!" + echo -e "제발${gl_huang}/root/cluster/servers.py${gl_bai}파일을 다운로드하고 백업을 완료하세요!" break_end ;; @@ -13986,7 +13986,7 @@ while true; do clear send_stats "클러스터를 복원하십시오" echo "servers.py를 업로드하고 키를 눌러 업로드를 시작하십시오!" - echo -e "업로드하십시오${gl_huang}servers.py${gl_bai}파일로${gl_huang}/root/cluster/${gl_bai}복원을 완료하십시오!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일로${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -14018,7 +14018,7 @@ while true; do 51) send_stats "명령 실행을 사용자 정의하십시오" - read -e -p "배치 실행 명령을 입력하십시오." mingling + read -e -p "일괄 실행을 위한 명령을 입력하십시오:" mingling run_commands_on_servers "${mingling}" ;; @@ -14036,48 +14036,48 @@ done kejilion_Affiliates() { clear -send_stats "광고 칼럼" -echo "광고 열" +send_stats "광고 열" +echo "광고 칼럼" echo "------------------------" echo "사용자에게 더욱 간단하고 우아한 프로모션 및 구매 경험을 제공할 것입니다!" echo "" -echo -e "서버 제안" +echo -e "서버할인" echo "------------------------" echo -e "${gl_lan}Leica Cloud Hong Kong CN2 Gia 한국 이중 ISP US CN2 GIA 할인${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://www.lcayun.com/aff/zexuqbim${gl_bai}" +echo -e "${gl_bai}홈페이지: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}Racknerd $ 10.99 미국 1 코어 1G 메모리 20G 하드 드라이브 1T 트래픽 월에 한 달에 트래픽${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" +echo -e "${gl_bai}URL: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" -echo -e "${gl_zi}Hostinger 52.7 달러 미국 1 코어 4G 메모리 50G 하드 드라이브 4T 트래픽 월${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-8ab010ef94f?_ga=ga1.3.942352702.1711283207${gl_bai}" +echo -e "${gl_zi}Hostinger 연간 $52.7 미국 1 코어 4G 메모리 50G 하드 드라이브 월별 4T 트래픽${gl_bai}" +echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Brickworker, 분기당 $ 49, 미국 CN2GIA, 일본 소프트 뱅크, 2 코어, 1G 메모리, 20G 하드 드라이브, 월 1 일 트래픽${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" +echo -e "${gl_huang}벽돌공 분기당 49달러 미국 CN2GIA 일본 SoftBank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_bai}웹사이트: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" -echo -e "${gl_lan}DMIT 분기 당 $ 28 미국 CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 800G 월에 트래픽${gl_bai}" +echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}웹 사이트 : https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" echo -e "${gl_zi}v.ps $ 6.9 월 월 $ 6.9 도쿄 소프트 뱅크 2 코어 1G 메모리 20G 하드 드라이브 1T 트래픽 월${gl_bai}" echo -e "${gl_bai}웹 사이트 : https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기있는 VPS가 제공합니다${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "도메인 이름 할인" echo "------------------------" echo -e "${gl_lan}GNAME 8.8 달러 첫해 COM 도메인 이름 6.68 달러 첫해 CC 도메인 이름${gl_bai}" -echo -e "${gl_bai}웹 사이트 : https://www.gname.com/register?tt=86836&ttcode=kejilion86836&ttbj=sh${gl_bai}" +echo -e "${gl_bai}웹사이트: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" echo "------------------------" echo "" -echo -e "주변 기술 사자" +echo -e "기술 사자 주변기기" echo "------------------------" -echo -e "${gl_kjlan}B 스테이션 :${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}오일 파이프 :${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" -echo -e "${gl_kjlan}공식 웹 사이트 :${gl_bai}https://kejilion.pro/ ${gl_kjlan}항해:${gl_bai}https://dh.kejilion.pro/${gl_bai}" -echo -e "${gl_kjlan}블로그 :${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}소프트웨어 센터 :${gl_bai}https://app.kejilion.pro/${gl_bai}" +echo -e "${gl_kjlan}B 스테이션 :${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}오일 파이프:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" +echo -e "${gl_kjlan}공식 웹사이트:${gl_bai}https://kejilion.pro/ ${gl_kjlan}항해:${gl_bai}https://dh.kejilion.pro/${gl_bai}" +echo -e "${gl_kjlan}블로그 :${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}소프트웨어 센터:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}스크립트 공식 웹 사이트 :${gl_bai}https://kejilion.sh ${gl_kjlan}Github 주소 :${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}스크립트 공식 웹사이트:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub 주소:${gl_bai}https://github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -14092,9 +14092,9 @@ send_stats "스크립트 업데이트" cd ~ while true; do clear - echo "로그 업데이트" + echo "변경 로그" echo "------------------------" - echo "모든 로그 :${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" + echo "모든 로그:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 @@ -14102,7 +14102,7 @@ while true; do if [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}당신은 이미 최신 버전입니다!${gl_huang}v$sh_v${gl_bai}" - send_stats "스크립트가 이미 최신 상태이므로 업데이트할 필요가 없습니다." + send_stats "스크립트는 최신 상태이며 업데이트가 필요하지 않습니다." else echo "새 버전을 발견하십시오!" echo -e "현재 버전 v$sh_v최신 버전${gl_huang}v$sh_v_new${gl_bai}" @@ -14114,7 +14114,7 @@ while true; do if [ -n "$existing_cron" ]; then echo "------------------------" - echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" + echo -e "${gl_lv}자동 업데이트가 켜져 있고 매일 새벽 2시에 스크립트가 자동으로 업데이트됩니다!${gl_bai}" fi echo "------------------------" @@ -14137,7 +14137,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트는 최신입니다$sh_v_new" + send_stats "스크립트가 최신 상태입니다.$sh_v_new" break_end ~/kejilion.sh exit @@ -14157,15 +14157,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}자동 업데이트가 활성화되고 스크립트는 매일 오전 2시에 자동으로 업데이트됩니다!${gl_bai}" - send_stats "자동 스크립트 업데이트를 켜십시오" + echo -e "${gl_lv}자동 업데이트가 켜져 있고 매일 새벽 2시에 스크립트가 자동으로 업데이트됩니다!${gl_bai}" + send_stats "자동 스크립트 업데이트 활성화" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" - send_stats "스크립트 자동 업데이트를 닫습니다" + send_stats "자동 스크립트 업데이트 끄기" break_end ;; *) @@ -14187,8 +14187,8 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "기술 라이온 스크립트 도구 상자 v$sh_v" -echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}스크립트를 신속하게 시작하십시오${gl_bai}" +echo -e "기술 사자 스크립트 도구 상자 v$sh_v" +echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}빠른 시작 스크립트${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" @@ -14197,20 +14197,20 @@ echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" -echo -e "${gl_kjlan}8. ${gl_bai}스크립트 수집 테스트" +echo -e "${gl_kjlan}8. ${gl_bai}테스트 스크립트 수집" echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" -echo -e "${gl_kjlan}11. ${gl_bai}응용 프로그램 시장" +echo -e "${gl_kjlan}11. ${gl_bai}응용 시장" echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" -echo -e "${gl_kjlan}15. ${gl_bai}광고 열" +echo -e "${gl_kjlan}15. ${gl_bai}광고 칼럼" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu 서버 오프닝 스크립트" +echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu 서버 오픈 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" +echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택을 입력하십시오 :" choice @@ -14232,7 +14232,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Eudemons Parlu 서버 오픈 스크립트" ; cd ~ + p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; @@ -14248,56 +14248,56 @@ done k_info() { send_stats "K 명령 참조 사용 사례" echo "-------------------" -echo "비디오 소개 : https://www.bilibili.com/video/bv1ib421e7it?t=0.1" -echo "다음은 K 명령 참조 유스 케이스입니다." -echo "시작 스크립트 k" +echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "다음은 k 명령의 참조 사용 사례입니다." +echo "스크립트 시작 k" echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" echo "시스템 k 업데이트 업데이트 | k 업데이트" -echo "깨끗한 시스템 쓰레기 K Clean | K 청소" -echo "시스템 패널 k dd |를 다시 설치하십시오 K 재설치" -echo "BBR3 제어판 K BBR3 | K bbrv3" -echo "커널 튜닝 패널 K nhyh | K 커널 최적화" -echo "가상 메모리 K 스왑 2048을 설정하십시오" -echo "가상 시간대 k 시간 아시아/상하이 설정 | k 시내 아시아/상하이" -echo "시스템 재활용 빈 K 쓰레기 | K hsz | K 재활용 빈" -echo "시스템 백업 기능 K 백업 | K bf | K 백업" -echo "SSH 원격 연결 도구 K SSH | K 원격 연결" +echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" +echo "시스템 패널을 다시 설치하십시오. k dd | k 다시 설치하다" +echo "bbr3 제어판 k bbr3 | kbbrv3" +echo "커널 튜닝 패널 k nhyh | k 커널 최적화" +echo "가상 메모리 k 스왑 2048 설정" +echo "가상 시간대 설정 k 시간 아시아/상하이 | k 시간대 아시아/상하이" +echo "시스템 휴지통 k 쓰레기 | khsz | k 휴지통" +echo "시스템 백업 기능 k 백업 | k bf | k 백업" +echo "SSH 원격 연결 도구 k SSH | k 원격 연결" echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" echo "인트라넷 침투 (서버 측) K frps" echo "인트라넷 침투 (클라이언트) K frpc" -echo "소프트웨어 시작 K 시작 SSHD | K 시작 SSHD" -echo "소프트웨어 중지 K 중지 SSHD | K 중지 SSHD" -echo "소프트웨어 재시작 K 재시작 SSHD | K는 sshd를 다시 시작합니다" -echo "소프트웨어 상태보기 K 상태 SSHD | K 상태 SSHD" -echo "소프트웨어 부트 K 활성화 Docker | K autostart docke | K 스타트 업 Docker" -echo "도메인 이름 인증서 응용 프로그램 K SSL" +echo "소프트웨어 시작 k start sshd | k sshd를 시작하세요" +echo "소프트웨어 중지 k 중지 sshd | k sshd 중지" +echo "소프트웨어 재시작 k 재시작 sshd | k sshd를 다시 시작하세요" +echo "소프트웨어 상태 확인 k status sshd | k 상태 sshd" +echo "k 도커 활성화 | k 자동 시작 도커 | k 소프트웨어를 부팅할 때 도커를 활성화합니다." +echo "도메인 이름 인증서 신청 k SSL" echo "도메인 이름 인증서 만료 쿼리 k SSL ps" echo "Docker Management Plane K Docker" echo "도커 환경 설치 K 도커 설치 | K 도커 설치" -echo "도커 컨테이너 관리 K 도커 PS | K 도커 컨테이너" +echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "Docker Image Management K Docker img | K Docker Image" echo "LDNMP 사이트 관리 K 웹" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp | K WordPress | k wp xxx.com을 설치하십시오" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." -echo "로드 밸런싱 k loadbalance | k로드 밸런싱을 설치하십시오" +echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "방화벽 패널 K FHQ | K 방화벽" -echo "포트 k dkdk 8080 | k 오픈 포트 8080" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "포트 K GBDK 7800 | K 닫기 포트 7800" echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" echo "앱 시장 관리 K 앱" -echo "응용 프로그램 번호 빠른 관리 K 앱 26 | K app 1panel | K app npm" +echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "디스플레이 시스템 정보 K 정보" } if [ "$#" -eq 0 ]; then - # 매개 변수가없는 경우 대화식 로직을 실행하십시오 + # 인수 없이 대화형 논리를 실행합니다. kejilion_sh else # 매개 변수가있는 경우 해당 함수를 실행하십시오 @@ -14309,7 +14309,7 @@ else ;; remove|del|uninstall|卸载) shift - send_stats "소프트웨어를 제거하십시오" + send_stats "소프트웨어 제거" remove "$@" ;; update|更新) @@ -14343,7 +14343,7 @@ else rsync_run) shift - send_stats "시간이 정한 RSYNC 동기화" + send_stats "예약된 rsync 동기화" run_task "$@" ;; @@ -14362,7 +14362,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14375,7 +14375,7 @@ else swap) shift - send_stats "가상 메모리를 신속하게 설정했습니다" + send_stats "가상 메모리를 빠르게 설정하세요" add_swap "$@" ;; @@ -14429,7 +14429,7 @@ else status|状态) shift - send_stats "소프트웨어 상태보기" + send_stats "소프트웨어 상태 확인" status "$@" ;; start|启动) @@ -14439,7 +14439,7 @@ else ;; stop|停止) shift - send_stats "소프트웨어 일시 정지" + send_stats "소프트웨어 일시 중지" stop "$@" ;; restart|重启) @@ -14450,21 +14450,21 @@ else enable|autostart|开机启动) shift - send_stats "소프트웨어 부츠" + send_stats "부팅 시 소프트웨어가 자동으로 시작됩니다." enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "인증서 상태를 확인하십시오" + send_stats "인증서 상태 보기" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "인증서를 신속하게 신청하십시오" + send_stats "빨리 자격증 신청하세요" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "인증서를 신속하게 신청하십시오" + send_stats "빨리 자격증 신청하세요" else k_info fi @@ -14474,7 +14474,7 @@ else shift case $1 in install|安装) - send_stats "Docker를 신속하게 설치하십시오" + send_stats "도커를 빠르게 설치하세요" install_docker ;; ps|容器) @@ -14482,7 +14482,7 @@ else docker_ps ;; img|镜像) - send_stats "빠른 미러 관리" + send_stats "빠른 이미지 관리" docker_image ;; *) @@ -14509,7 +14509,7 @@ else app) shift - send_stats "$@ 적용" + send_stats "신청$@" linux_panel "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index aadf4d9c8..56f7acff1 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -12138,7 +12138,7 @@ while true; do - 102) + 102|vocechat) local app_id="102" local docker_name="vocechat-server" From fb25422c4ba5d66c6dc562f851beedf7f2b03866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:02:20 +0800 Subject: [PATCH 0264/1285] Update kejilion.sh --- kejilion.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3c72a1e49..e65a52b25 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -3372,7 +3372,7 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "1. 申请/更新域名证书 2. 克隆站点域名" echo "3. 清理站点缓存 4. 创建关联站点" echo "5. 查看访问日志 6. 查看错误日志" echo "7. 编辑全局配置 8. 编辑站点配置" @@ -3395,8 +3395,7 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + send_stats "克隆站点域名" read -e -p "请输入旧域名: " oddyuming read -e -p "请输入新域名: " yuming install_certbot @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3422,16 +3421,16 @@ ldnmp_web_status() { done # 网站目录替换 - mv /home/web/html/$oddyuming /home/web/html/$yuming + cp /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem docker exec nginx nginx -s reload From ae1c7dcab5847091572a25468b8977a7e0ed53a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:03:13 +0800 Subject: [PATCH 0265/1285] Update kejilion.sh --- cn/kejilion.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 67745a43f..60d57f928 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -3372,7 +3372,7 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申请/更新域名证书 2. 更换站点域名" + echo "1. 申请/更新域名证书 2. 克隆站点域名" echo "3. 清理站点缓存 4. 创建关联站点" echo "5. 查看访问日志 6. 查看错误日志" echo "7. 编辑全局配置 8. 编辑站点配置" @@ -3395,8 +3395,7 @@ ldnmp_web_status() { ;; 2) - send_stats "更换站点域名" - echo -e "${gl_hong}强烈建议: ${gl_bai}先备份好全站数据再更换站点域名!" + send_stats "克隆站点域名" read -e -p "请输入旧域名: " oddyuming read -e -p "请输入新域名: " yuming install_certbot @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3422,16 +3421,16 @@ ldnmp_web_status() { done # 网站目录替换 - mv /home/web/html/$oddyuming /home/web/html/$yuming + cp /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem docker exec nginx nginx -s reload From 5bef45b176ad58d3701adf26c2a979649f3c708e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:05:04 +0800 Subject: [PATCH 0266/1285] Update changelog for version 4.1.9 --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index a1a777973..53f79e83f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1321,4 +1321,7 @@ k快捷命令增加了 k info 系统信息快速查询。 应用市场FileCodeBox文件快递增加管理员入口的提示路径与密码。 应用市场新增了VoceChat多人聊天系统的安装及使用。 ------------------------ +2025-10-09 v4.1.9 +LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可以保留老站点,让用户自己处决。 +------------------------ From f3d57de13fbbe5139f89cdbe77cd988c0466e0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:34:20 +0800 Subject: [PATCH 0267/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 60d57f928..aa8f1a0dc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3421,7 +3421,7 @@ ldnmp_web_status() { done # 网站目录替换 - cp /home/web/html/$oddyuming /home/web/html/$yuming + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + From dcaab6563ae2b1b28dae9308edbf749760e95958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:35:22 +0800 Subject: [PATCH 0268/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index e65a52b25..f730e01bf 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3421,7 +3421,7 @@ ldnmp_web_status() { done # 网站目录替换 - cp /home/web/html/$oddyuming /home/web/html/$yuming + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + From 849384f446dc1d25afb6f06f26dfc4c64f0c6a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:01:37 +0800 Subject: [PATCH 0269/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index aa8f1a0dc..12dfbc6b6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3432,7 +3432,7 @@ ldnmp_web_status() { # rm /home/web/certs/${oddyuming}_key.pem # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; From eee11cfa421f2fc436e737bdf49b219ecfd7fffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:02:07 +0800 Subject: [PATCH 0270/1285] Change Nginx reload to Docker Compose restart --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index f730e01bf..7d85d67aa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3432,7 +3432,7 @@ ldnmp_web_status() { # rm /home/web/certs/${oddyuming}_key.pem # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; From d66b82d50227a19eb4c02c5ab17b72260d2d26f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:13:03 +0800 Subject: [PATCH 0271/1285] Update kejilion.sh --- cn/kejilion.sh | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 12dfbc6b6..76e3736cf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3376,7 +3376,7 @@ ldnmp_web_status() { echo "3. 清理站点缓存 4. 创建关联站点" echo "5. 查看访问日志 6. 查看错误日志" echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" echo "20. 删除指定站点数据" echo "------------------------" @@ -8873,6 +8873,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12164,6 +12165,47 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名: admin" + echo "初始密码: umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "应用已卸载" + } + + docker_app_plus + + ;; + + b) clear From 62d88502c94cf8c741c7e0745e92303c54d84924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:13:35 +0800 Subject: [PATCH 0272/1285] Implement Umami website analytics tool management Added Umami website analytics tool installation, update, and uninstall functions. --- kejilion.sh | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7d85d67aa..4b835c421 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3376,7 +3376,7 @@ ldnmp_web_status() { echo "3. 清理站点缓存 4. 创建关联站点" echo "5. 查看访问日志 6. 查看错误日志" echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" echo "20. 删除指定站点数据" echo "------------------------" @@ -8873,6 +8873,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12164,6 +12165,47 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + echo "初始用户名: admin" + echo "初始密码: umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "应用已卸载" + } + + docker_app_plus + + ;; + + b) clear From c20df5383c0620e7de62bd404fe801cf93c1ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:14:31 +0800 Subject: [PATCH 0273/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 53f79e83f..d24b25ed2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1323,5 +1323,6 @@ k快捷命令增加了 k info 系统信息快速查询。 ------------------------ 2025-10-09 v4.1.9 LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可以保留老站点,让用户自己处决。 +应用市场新增了Umami网站统计工具的安装及使用。 ------------------------ From f1766439178d786ba7bdeaf5c1c7fb9487e5e09d Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 12 Oct 2025 04:18:43 +0000 Subject: [PATCH 0274/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-12=2004:18:43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 1293 ++++++++++++++------------- jp/kejilion.sh | 2287 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 2229 +++++++++++++++++++++++----------------------- tw/kejilion.sh | 63 +- 4 files changed, 3018 insertions(+), 2854 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index f8bf8ecbd..305b75111 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# Define a function to execute commands +# Define a function to execute the command run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -59,7 +59,7 @@ CheckFirstRun_true() { # This function collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! # Why is this function designed? The purpose is to better understand the functions that users like to use, and to further optimize the functions and launch more functions that meet user needs. -# For the full text, you can search for the send_stats function call location, transparent and open source, and you can refuse to use it if you have any concerns. +# The full text can be searched for the send_stats function call location. It is transparent and open source. If you have any concerns, you can refuse to use it. @@ -114,7 +114,7 @@ CheckFirstRun_false() { # Prompt user to agree to terms UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Welcome to the Tech lion script toolbox${gl_bai}" + echo -e "${gl_kjlan}Welcome to the technology lion script toolbox${gl_bai}" echo "When using the script for the first time, please read and agree to the User License Agreement." echo "User License Agreement: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -170,7 +170,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "Package parameters are not provided!" + echo "No package parameters provided!" return 1 fi @@ -222,9 +222,9 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}hint:${gl_bai}Not enough disk space!" echo "Current available space: $((available_space_mb/1024))G" - echo "Minimum demand space:${required_gb}G" - echo "The installation cannot be continued. Please clean the disk space and try again." - send_stats "Insufficient disk space" + echo "Minimum required space:${required_gb}G" + echo "The installation cannot continue. Please clear the disk space and try again." + send_stats "Not enough disk space" break_end kejilion fi @@ -238,7 +238,7 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "Package parameters are not provided!" + echo "No package parameters provided!" return 1 fi @@ -281,7 +281,7 @@ systemctl() { } -# Restart the service +# Restart service restart() { systemctl restart "$1" if [ $? -eq 0 ]; then @@ -315,9 +315,9 @@ stop() { status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1The service status is displayed." + echo "$1Service status is shown." else - echo "Error: Unable to display$1Service status." + echo "Error: cannot be displayed$1Service status." fi } @@ -522,21 +522,21 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "Create a new container" - read -e -p "Please enter the creation command:" dockername + read -e -p "Please enter the create command:" dockername $dockername ;; 2) send_stats "Start the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername docker start $dockername ;; 3) - send_stats "Stop the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + send_stats "Stop specified container" + read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername docker stop $dockername ;; 4) @@ -546,7 +546,7 @@ while true; do ;; 5) send_stats "Restart the specified container" - read -e -p "Please enter the container name (multiple container names separated by spaces):" dockername + read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername docker restart $dockername ;; 6) @@ -653,11 +653,11 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "Pull image" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + read -e -p "Please enter the image name (please separate multiple image names with spaces):" imagenames for name in $imagenames; do echo -e "${gl_huang}Obtaining image:$name${gl_bai}" docker pull $name @@ -665,15 +665,15 @@ while true; do ;; 2) send_stats "Update image" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + read -e -p "Please enter the image name (please separate multiple image names with spaces):" imagenames for name in $imagenames; do echo -e "${gl_huang}Updating image:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "Delete the mirror" - read -e -p "Please enter the mirror name (please separate multiple mirror names with spaces):" imagenames + send_stats "Delete image" + read -e -p "Please enter the image name (please separate multiple image names with spaces):" imagenames for name in $imagenames; do docker rmi -f $name done @@ -761,7 +761,7 @@ install_crontab() { ;; esac else - echo "The operating system cannot be determined." + echo "Unable to determine operating system." return fi @@ -777,7 +777,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # Check if the configuration file exists, create the file and write the default settings if it does not exist + # Check if the configuration file exists, if not create the file and write the default settings if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -785,7 +785,7 @@ docker_ipv6_on() { # Use jq to handle configuration file updates local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # Check whether the current configuration already has ipv6 settings + # Check if the current configuration already has ipv6 settings local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') # Update configuration and enable IPv6 @@ -814,7 +814,7 @@ docker_ipv6_off() { # Check if the configuration file exists if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}The configuration file does not exist${gl_bai}" + echo -e "${gl_hong}Configuration file does not exist${gl_bai}" return fi @@ -827,7 +827,7 @@ docker_ipv6_off() { # Check current ipv6 status local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # Comparing original configuration with new configuration + # Compare original configuration to new configuration if [[ "$CURRENT_IPV6" == "false" ]]; then echo -e "${gl_huang}IPv6 access is currently closed${gl_bai}" else @@ -883,7 +883,7 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # Add Open Rules + # Add open rule if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi @@ -895,7 +895,7 @@ open_port() { done save_iptables_rules - send_stats "The port has been opened" + send_stats "Port opened" } @@ -950,7 +950,7 @@ allow_ip() { # Delete existing blocking rules iptables -D INPUT -s $ip -j DROP 2>/dev/null - # Add allow rules + # Add allow rule if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "Released IP$ip" @@ -974,7 +974,7 @@ block_ip() { # Delete existing allow rules iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # Add blocking rules + # Add blocking rule if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP echo "IP blocked$ip" @@ -1005,7 +1005,7 @@ enable_ddos_defense() { send_stats "Turn on DDoS defense" } -# Turn off DDoS Defense +# Turn off DDoS defense disable_ddos_defense() { # Turn off DDoS protection iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null @@ -1086,7 +1086,7 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "Successfully lifted$country_codeIP address restrictions" + echo "Removed successfully$country_codeIP address restrictions" ;; *) @@ -1111,12 +1111,12 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "Advanced Firewall Management" + echo "Advanced firewall management" send_stats "Advanced firewall management" echo "------------------------" iptables -L INPUT echo "" - echo "Firewall Management" + echo "Firewall management" echo "------------------------" echo "1. Open the designated port 2. Close the designated port" echo "3. Open all ports 4. Close all ports" @@ -1126,14 +1126,14 @@ iptables_panel() { echo "------------------------" echo "11. Allow PING 12. Disable PING" echo "------------------------" - echo "13. Start DDOS Defense 14. Turn off DDOS Defense" + echo "13. Start DDOS defense 14. Turn off DDOS defense" echo "------------------------" - echo "15. Block specified country IP 16. Only specified country IPs are allowed" - echo "17. Release IP restrictions in designated countries" + echo "15. Block specified country IPs 16. Allow only specified country IPs" + echo "17. Lift IP restrictions in designated countries" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) read -e -p "Please enter the open port number:" o_port @@ -1143,7 +1143,7 @@ iptables_panel() { 2) read -e -p "Please enter the closed port number:" c_port close_port $c_port - send_stats "Close the specified port" + send_stats "Close specified port" ;; 3) # Open all ports @@ -1185,16 +1185,16 @@ iptables_panel() { ;; 6) # IP blacklist - read -e -p "Please enter the blocked IP or IP segment:" c_ip + read -e -p "Please enter the blocked IP or IP range:" c_ip block_ip $c_ip ;; 7) - # Clear the specified IP + # Clear specified IP read -e -p "Please enter the cleared IP:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "Clear the specified IP" + send_stats "Clear specified IP" ;; 11) # Allow PING @@ -1218,9 +1218,9 @@ iptables_panel() { ;; 15) - read -e -p "Please enter the blocked country code (multiple country codes can be separated by spaces such as CN US JP):" country_code + read -e -p "Please enter the blocked country code (multiple country codes can be separated by spaces, such as CN US JP):" country_code manage_country_rules block $country_code - send_stats "Allowed countries$country_codeIP" + send_stats "allow countries$country_codeIP" ;; 16) read -e -p "Please enter the allowed country codes (multiple country codes can be separated by spaces, such as CN US JP):" country_code @@ -1231,7 +1231,7 @@ iptables_panel() { 17) read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces, such as CN US JP):" country_code manage_country_rules unblock $country_code - send_stats "Clear the country$country_codeIP" + send_stats "clear country$country_codeIP" ;; *) @@ -1260,7 +1260,7 @@ add_swap() { mkswap -f "$partition" done - # Make sure /swapfile is no longer used + # Make sure /swapfile is no longer in use swapoff /swapfile # Delete old /swapfile @@ -1281,7 +1281,7 @@ add_swap() { rc-update add local fi - echo -e "The virtual memory size has been resized to${gl_huang}${new_swap}${gl_bai}M" + echo -e "The virtual memory size has been adjusted to${gl_huang}${new_swap}${gl_bai}M" } @@ -1321,7 +1321,7 @@ ldnmp_v() { local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Get the redis version + # Get redis version local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1392,7 +1392,7 @@ install_ldnmp() { clear - echo "LDNMP environment has been installed" + echo "The LDNMP environment is installed" echo "------------------------" ldnmp_v @@ -1409,7 +1409,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "Renewal task has been updated" + echo "The renewal task has been updated" } @@ -1519,13 +1519,13 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "Successful application for domain name certificate" + send_stats "Domain name certificate application successful" else send_stats "Domain name certificate application failed" echo -e "${gl_hong}Notice:${gl_bai}Certificate application failed, please check the following possible reasons and try again:" echo -e "1. Domain name is spelled incorrectly ➠ Please check whether the domain name is entered correctly" echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to the server IP" - echo -e "3. Network configuration issues ➠ If you use Cloudflare Warp and other virtual networks, please temporarily shut down" + echo -e "3. Network configuration issues ➠ If you use virtual networks such as Cloudflare Warp, please temporarily shut down" echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open and ensure that it is accessible" echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" echo -e "6. Domestic registration restrictions ➠ For mainland China environment, please confirm whether the domain name is registered" @@ -1551,7 +1551,7 @@ fi add_yuming() { ip_address - echo -e "First resolve the domain name to the native IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or resolved domain name:" yuming } @@ -1652,15 +1652,15 @@ cf_purge_cache() { # Check if the configuration file exists if [ -f "$CONFIG_FILE" ]; then - # Read API_TOKEN and zone_id from configuration files + # Read API_TOKEN and zone_id from configuration file read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # Convert ZONE_IDS to an array + # Convert ZONE_IDS to array ZONE_IDS=($ZONE_IDS) else - # Prompt the user whether to clean the cache + # Prompt user whether to clear cache read -e -p "Need to clear Cloudflare's cache? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF information is saved in$CONFIG_FILE, you can modify the CF information later" + echo "CF information is stored in$CONFIG_FILE, you can modify the CF information later" read -e -p "Please enter your API_TOKEN:" API_TOKEN read -e -p "Please enter your CF username:" EMAIL read -e -p "Please enter zone_id (separate multiple with spaces):" -a ZONE_IDS @@ -1680,7 +1680,7 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "The cache clear request has been sent." + echo "Cache clearing request has been sent." } @@ -1717,7 +1717,7 @@ web_del() { dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') # Check whether the database exists before deleting it to avoid errors. - echo "Deleting the database:$dbname" + echo "Deleting database:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1733,9 +1733,9 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # Decide to turn on or off WAF according to the mode parameter + # Determine whether to turn on or off WAF according to the mode parameter if [ "$mode" == "on" ]; then - # Turn on WAF: Remove comments + # Turn on WAF: remove comments sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1745,11 +1745,11 @@ nginx_waf() { sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "Invalid parameter: Use 'on' or 'off'" + echo "Invalid argument: use 'on' or 'off'" return 1 fi - # Check nginx images and handle them according to the situation + # Check the nginx image and handle it accordingly if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1828,7 +1828,7 @@ patch_wp_debug() { sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # Insert a new definition before the line with "Happy publishing" + # Insert the new definition before the line containing "Happy publishing" awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1865,7 +1865,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Close Brotli: Add comments + # Close Brotli: add comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1881,7 +1881,7 @@ nginx_br() { }' /home/web/nginx.conf else - echo "Invalid parameter: Use 'on' or 'off'" + echo "Invalid argument: use 'on' or 'off'" return 1 fi @@ -1922,7 +1922,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Close Zstd: Add comments + # Close Zstd: add comments sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1942,7 +1942,7 @@ nginx_zstd() { return 1 fi - # Check nginx images and handle them according to the situation + # Check the nginx image and handle it accordingly if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1969,7 +1969,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "Invalid parameter: Use 'on' or 'off'" + echo "Invalid argument: use 'on' or 'off'" return 1 fi @@ -1991,17 +1991,17 @@ web_security() { clear echo -e "Server website defense program${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. Install the defense program" + echo "1. Install a defense program" echo "------------------------" - echo "5. View SSH interception record 6. View website interception record" + echo "5. View SSH interception records 6. View website interception records" echo "7. View the list of defense rules 8. View logs for real-time monitoring" echo "------------------------" - echo "11. Configure intercept parameters 12. Clear all blocked IPs" + echo "11. Configure interception parameters 12. Clear all blocked IPs" echo "------------------------" echo "21. cloudflare mode 22. Enable 5 seconds shield under high load" echo "------------------------" echo "31. Turn on WAF 32. Turn off WAF" - echo "33. Turn on DDOS Defense 34. Turn off DDOS Defense" + echo "33. Turn on DDOS defense 34. Turn off DDOS defense" echo "------------------------" echo "9. Uninstall the defense program" echo "------------------------" @@ -2089,10 +2089,10 @@ web_security() { 21) send_stats "cloudflare mode" - echo "Go to the upper right corner of the cf background, select the API token on the left, and obtain the Global API Key" + echo "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get the Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "Enter CF account number:" cfuser - read -e -p "Enter the Global API Key for CF:" cftoken + read -e -p "Enter CF’s account number:" cfuser + read -e -p "Enter CF’s Global API Key:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2115,8 +2115,8 @@ web_security() { echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to the upper right corner of the cf background, select the API token on the left, and obtain it${gl_huang}Global API Key${gl_bai}" - echo -e "Go to the bottom right of the cf background domain name summary page to get${gl_huang}Region ID${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" + echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "Enter CF’s account number:" cfuser @@ -2153,8 +2153,8 @@ web_security() { 32) nginx_waf off - echo "Site WAF has been closed" - send_stats "Site WAF has been closed" + echo "Site WAF is down" + send_stats "Site WAF is down" ;; 33) @@ -2239,7 +2239,7 @@ web_optimization() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "site standards mode" @@ -2378,7 +2378,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv} has installed ${gl_bai}" # else -# check_docker="${gl_hui}${gl_bai} is not installed" +# check_docker="${gl_hui} is not installed ${gl_bai}" # fi # } @@ -2424,7 +2424,7 @@ check_docker_image_update() { return fi - # Get the container creation time and image name + # Get the creation time and image name of the container local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) @@ -2439,7 +2439,7 @@ check_docker_image_update() { # Add support for official images [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Get image publishing time from Docker Hub API + # Get image release time from Docker Hub API local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) @@ -2487,7 +2487,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Check and release the local network 127.0.0.0/8 + # Check and allow local network 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2504,7 +2504,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Check and release the local network 127.0.0.0/8 + # Check and allow local network 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2514,7 +2514,7 @@ block_container_port() { fi - echo "IP+ ports have been blocked from accessing the service" + echo "IP+port has been blocked from accessing the service" save_iptables_rules } @@ -2540,12 +2540,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # Clear the rules for release local network 127.0.0.0/8 + # Clear the rules that allow local network 127.0.0.0/8 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2559,7 +2559,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules for releasing the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2590,7 +2590,7 @@ block_host_port() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "Error: Please provide port number and IP to allow access." - echo "Usage: block_host_port " + echo "Usage: block_host_port " return 1 fi @@ -2602,7 +2602,7 @@ block_host_port() { iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # Allow specified IP access + # Allow access to specified IP if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2616,7 +2616,7 @@ block_host_port() { - # Denied all other IP access + # Deny access from all other IPs if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi @@ -2648,7 +2648,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "Error: Please provide the port number and the IP that is allowed to access." + echo "Error: Please provide port number and IP to allow access." echo "Usage: clear_host_port_rules " return 1 fi @@ -2661,12 +2661,12 @@ clear_host_port_rules() { iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # Clear rules that allow native access + # Clear rules that allow local access if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Clear rules that allow specified IP access + # Clear rules that allow access from specified IPs if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2677,18 +2677,18 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # Clear rules that allow native access + # Clear rules that allow local access if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Clear rules that allow specified IP access + # Clear rules that allow access from specified IPs if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ports have been allowed to access the service" + echo "IP+port has been allowed to access the service" save_iptables_rules } @@ -2771,7 +2771,7 @@ while true; do add_app_id clear - echo "$docker_nameInstalled" + echo "$docker_nameInstallation completed" check_docker_app_ip echo "" $docker_use @@ -2805,15 +2805,15 @@ while true; do ;; 5) - echo "${docker_name}Domain access settings" - send_stats "${docker_name}Domain access settings" + echo "${docker_name}Domain name access settings" + send_stats "${docker_name}Domain name access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "Domain name format example.com without https://" web_del ;; @@ -2863,7 +2863,7 @@ docker_app_plus() { echo "1. Install 2. Update 3. Uninstall" echo "------------------------" echo "5. Add domain name access 6. Delete domain name access" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "7. Allow IP+port access 8. Block IP+port access" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -2902,7 +2902,7 @@ docker_app_plus() { block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "Domain name format example.com does not come with https://" + echo "Domain name format example.com without https://" web_del ;; 7) @@ -2995,7 +2995,7 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# Functions that check whether the session exists +# Function to check if session exists session_exists() { tmux has-session -t $1 2>/dev/null } @@ -3194,7 +3194,7 @@ ldnmp_web_on() { nginx_web_on() { clear - echo "Yours$webnameBuilt!" + echo "your$webnameIt's built!" echo "https://$yuming" } @@ -3287,7 +3287,7 @@ ldnmp_Proxy_backend() { fi if [ -z "$reverseproxy_port" ]; then - read -e -p "Please enter your multiple anti-generation IP+ ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "Please enter your multiple anti-generation IP+ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3372,17 +3372,17 @@ ldnmp_web_status() { echo "" echo "operate" echo "------------------------" - echo "1. Apply for/update the domain name certificate 2. Change the site domain name" + echo "1. Apply/update domain name certificate 2. Clone site domain name" echo "3. Clear site cache 4. Create associated site" echo "5. View the access log 6. View the error log" echo "7. Edit global configuration 8. Edit site configuration" - echo "9. Manage site database 10. View site analysis report" + echo "9. Manage site database 10. View site analysis reports" echo "------------------------" echo "20. Delete specified site data" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) send_stats "Apply for a domain name certificate" @@ -3395,10 +3395,9 @@ ldnmp_web_status() { ;; 2) - send_stats "Change the site domain name" - echo -e "${gl_hong}Highly recommended:${gl_bai}Back up the entire site data first and then change the site domain name!" + send_stats "Clone site domain name" read -e -p "Please enter the old domain name:" oddyuming - read -e -p "Please enter the new domain name:" yuming + read -e -p "Please enter new domain name:" yuming install_certbot install_ssltls certs_status @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3422,18 +3421,18 @@ ldnmp_web_status() { done # Website directory replacement - mv /home/web/html/$oddyuming /home/web/html/$yuming + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; @@ -3442,10 +3441,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "Create an associated site" + send_stats "Create associated sites" echo -e "Associate a new domain name with the existing site for access" read -e -p "Please enter an existing domain name:" oddyuming - read -e -p "Please enter the new domain name:" yuming + read -e -p "Please enter new domain name:" yuming install_certbot install_ssltls certs_status @@ -3532,7 +3531,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case $choice in 1) check_disk_space 1 @@ -3598,7 +3597,7 @@ donlond_frp() { generate_frps_config() { - send_stats "Install the frp server" + send_stats "Install frp server" # Generate random ports and credentials local bind_port=8055 local dashboard_port=8056 @@ -3620,7 +3619,7 @@ EOF donlond_frp frps - # Output generated information + # Output the generated information ip_address echo "------------------------" echo "Parameters required for client deployment" @@ -3640,7 +3639,7 @@ EOF configure_frpc() { - send_stats "Install the frp client" + send_stats "Install frp client" read -e -p "Please enter the external network docking IP:" server_addr read -e -p "Please enter the external network docking token:" token echo @@ -3662,8 +3661,8 @@ EOF } add_forwarding_service() { - send_stats "Add FRP intranet service" - # Prompt the user to enter the service name and forwarding information + send_stats "Add frp intranet service" + # Prompts user for service name and forwarding information read -e -p "Please enter service name:" service_name read -e -p "Please enter the forwarding type (tcp/udp) [Enter to default to tcp]:" service_type local service_type=${service_type:-tcp} @@ -3683,7 +3682,7 @@ remote_port = ${remote_port} EOF # Output the generated information - echo "Serve$service_nameAdded successfully to frpc.toml" + echo "Serve$service_nameSuccessfully added to frpc.toml" docker restart frpc @@ -3697,9 +3696,9 @@ delete_forwarding_service() { send_stats "Delete frp intranet service" # Prompt the user to enter the name of the service that needs to be deleted read -e -p "Please enter the service name to be deleted:" service_name - # Use sed to delete the service and its related configurations + # Use sed to delete the service and its related configuration sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "Serve$service_nameDeleted successfully from frpc.toml" + echo "Serve$service_nameSuccessfully removed from frpc.toml" docker restart frpc @@ -3743,7 +3742,7 @@ list_forwarding_services() { if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # Clear the previous value + # Clear previous value local_ip="" local_port="" remote_port="" @@ -3785,14 +3784,14 @@ list_forwarding_services() { -# Get the FRP server port +# Get FRP server port get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } # Generate access address generate_access_urls() { - # Get all ports first + # First get all ports get_frp_ports # Check if there is a port other than 8055/8056 @@ -3804,7 +3803,7 @@ generate_access_urls() { fi done - # Show title and content only when there is a valid port + # Show title and content only if there is a valid port if [ "$has_valid_ports" = true ]; then echo "FRP service external access address:" @@ -3815,7 +3814,7 @@ generate_access_urls() { fi done - # Process IPv6 addresses (if present) + # Handle IPv6 address if present if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3860,7 +3859,7 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP server$check_frp $update_status" - echo "Build an FRP intranet penetration service environment to expose devices without public IP to the Internet" + echo "Build an FRP intranet penetration service environment and expose devices without public IP to the Internet" echo "Official website introduction: https://github.com/fatedier/frp/" echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then @@ -3873,11 +3872,11 @@ frps_panel() { echo "------------------------" echo "5. Intranet service domain name access 6. Delete domain name access" echo "------------------------" - echo "7. Allow IP+ port access 8. Block IP+ port access" + echo "7. Allow IP+port access 8. Block IP+port access" echo "------------------------" echo "00. Refresh service status 0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) install jq grep ss @@ -3910,7 +3909,7 @@ frps_panel() { ;; 5) echo "Reverse intranet penetration service into domain name access" - send_stats "FRP access to external domain names" + send_stats "FRP external domain name access" add_yuming read -e -p "Please enter your intranet penetration service port:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} @@ -3935,7 +3934,7 @@ frps_panel() { ;; 00) - send_stats "Refresh the FRP service status" + send_stats "Refresh FRP service status" echo "FRP service status has been refreshed" ;; @@ -3949,7 +3948,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP Client" + send_stats "FRP client" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -3957,8 +3956,8 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP Client$check_frp $update_status" - echo "Docking with the server, after docking, you can create intranet penetration service to the Internet access" + echo -e "FRP client$check_frp $update_status" + echo "Connect with the server. After the connection, you can create an intranet penetration service to access the Internet." echo "Official website introduction: https://github.com/fatedier/frp/" echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4003,7 +4002,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "App has been uninstalled" ;; 4) @@ -4051,7 +4050,7 @@ yt_menu_pro() { clear send_stats "yt-dlp download tool" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp is a powerful video download tool that supports thousands of sites including YouTube, Bilibili, Twitter, etc." + echo -e "yt-dlp is a powerful video download tool that supports thousands of sites such as YouTube, Bilibili, Twitter, etc." echo -e "Official website address: https://github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "Downloaded video list:" @@ -4078,7 +4077,7 @@ yt_menu_pro() { echo "The installation is complete. Press any key to continue..." read ;; 2) - send_stats "Update yt-dlp..." + send_stats "Updating yt-dlp..." echo "Updating yt-dlp..." yt-dlp -U @@ -4095,7 +4094,7 @@ yt_menu_pro() { read ;; 5) send_stats "Single video download" - read -e -p "Please enter the video link:" url + read -e -p "Please enter video link:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4110,7 +4109,7 @@ yt_menu_pro() { echo -e "# Enter multiple video link addresses\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "Now start batch download..." + echo "Start batch download now..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4118,10 +4117,10 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "The batch download is completed, press any key to continue..." ;; + read -e -p "Batch download completed, press any key to continue..." ;; 7) send_stats "Custom video download" - read -e -p "Please enter the full yt-dlp parameter (excluding yt-dlp):" custom + read -e -p "Please enter the complete yt-dlp parameters (excluding yt-dlp):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4131,18 +4130,18 @@ yt_menu_pro() { read -e -p "Execution completed, press any key to continue..." ;; 8) send_stats "MP3 download" - read -e -p "Please enter the video link:" url + read -e -p "Please enter video link:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "The audio download is completed, press any key to continue..." ;; + read -e -p "Audio download complete, press any key to continue..." ;; 9) send_stats "Delete video" - read -e -p "Please enter the name of the delete video:" rmdir + read -e -p "Please enter the name of the deleted video:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4178,7 +4177,7 @@ set_timedate() { -# Fix dpkg interrupt problem +# Fix dpkg interruption problem fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4267,7 +4266,7 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "Delete the system log..." + echo "Delete system log..." rm -rf /var/log/* echo "Delete temporary files..." rm -rf /tmp/* @@ -4275,7 +4274,7 @@ linux_clean() { elif command -v pkg &>/dev/null; then echo "Clean up unused dependencies..." pkg autoremove -y - echo "Clean the package manager cache..." + echo "Clean package manager cache..." pkg clean -y echo "Delete system log..." rm -rf /var/log/* @@ -4346,7 +4345,7 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "Please enter your choice:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4392,7 +4391,7 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # If PasswordAuthentication is found, set to yes + # If found PasswordAuthentication is set to yes if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4417,7 +4416,7 @@ correct_ssh_config() { new_ssh_port() { - # Backup SSH configuration files + # Back up SSH configuration files cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4470,7 +4469,7 @@ import_sshkey() { read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}Error: The public key content was not entered.${gl_bai}" + echo -e "${gl_hong}Error: Public key content not entered.${gl_bai}" return 1 fi @@ -4503,14 +4502,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -4560,7 +4559,7 @@ dd_xitong() { root_use echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." + echo -e "${gl_hong}Notice:${gl_bai}Reinstalling may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." echo -e "${gl_hui}Thanks to boss leitbogioro and boss bin456789 for their script support!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" @@ -4770,7 +4769,7 @@ dd_xitong() { ;; 36) - send_stats "Reload flying cow" + send_stats "Reinstall Feiniu" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4856,13 +4855,13 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "You have installed xanmod's BBRv3 kernel" + echo "You have xanmod's BBRv3 kernel installed" echo "Current kernel version:$kernel_version" echo "" echo "Kernel management" echo "------------------------" - echo "1. Update the BBRv3 kernel 2. Uninstall the BBRv3 kernel" + echo "1. Update BBRv3 kernel 2. Uninstall BBRv3 kernel" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -4912,9 +4911,9 @@ bbrv3() { echo "Video introduction: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "Only supports Debian/Ubuntu" - echo "Please back up the data and will enable BBR3 for you to upgrade the Linux kernel." + echo "Please back up your data and we will upgrade your Linux kernel and enable BBR3." echo "------------------------------------------------" - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) @@ -4922,12 +4921,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "The current environment does not support it, only supports Debian and Ubuntu systems" + echo "The current environment does not support it. Only Debian and Ubuntu systems are supported." break_end linux_Settings fi else - echo "Unable to determine the operating system type" + echo "Unable to determine operating system type" break_end linux_Settings fi @@ -4938,7 +4937,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # Step 3: Add a repository + # Step 3: Add repository echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -4949,7 +4948,7 @@ bbrv3() { bbr_on - echo "XanMod kernel is installed and BBR3 is enabled successfully. Take effect after restart" + echo "The XanMod kernel is installed and BBR3 is enabled successfully. Take effect after restart" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4968,13 +4967,13 @@ bbrv3() { elrepo_install() { - # Import ELRepo GPG public key + # Import the ELRepo GPG public key echo "Import the ELRepo GPG public key..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # Detect system version + # Check system version local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # Make sure we run on a supported operating system + # Make sure we're running on a supported operating system if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "Unsupported operating systems:$os_name" break_end @@ -4984,13 +4983,13 @@ elrepo_install() { echo "Detected operating systems:$os_name $os_version" # Install the corresponding ELRepo warehouse configuration according to the system version if [[ "$os_version" == 8 ]]; then - echo "Install ELRepo repository configuration (version 8)..." + echo "Installing the ELRepo repository configuration (version 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then echo "Installing the ELRepo repository configuration (version 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Install ELRepo repository configuration (version 10)..." + echo "Installing the ELRepo repository configuration (version 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else echo "Unsupported system versions:$os_version" @@ -5014,11 +5013,11 @@ elrepo() { while true; do clear kernel_version=$(uname -r) - echo "You have installed the elrepo kernel" + echo "You have installed elrepo kernel" echo "Current kernel version:$kernel_version" echo "" - echo "Kernel Management" + echo "Kernel management" echo "------------------------" echo "1. Update elrepo kernel 2. Uninstall elrepo kernel" echo "------------------------" @@ -5056,7 +5055,7 @@ elrepo() { echo "Video introduction: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Only supports Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" - echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if conditions permit and upgrade the production environment with caution!" + echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if possible, and upgrade the production environment with caution!" echo "------------------------------------------------" read -e -p "Are you sure you want to continue? (Y/N):" choice @@ -5113,7 +5112,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Execute Docker commands + # Execute Docker command docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5122,8 +5121,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ Scan is completed, virus report is stored${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}If there is a virus, please${gl_huang}scan.log${gl_lv}Search for FOUND keyword in the file to confirm the location of the virus${gl_bai}" + echo -e "${gl_lv}$@ The scan is completed and the virus report is stored in${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}If there is a virus please${gl_huang}scan.log${gl_lv}Search the file for the FOUND keyword to confirm the location of the virus${gl_bai}" } @@ -5141,17 +5140,17 @@ clamav() { echo "clamav virus scanning tool" echo "Video introduction: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "It is an open source antivirus software tool, mainly used to detect and remove various types of malware." + echo "It is an open source antivirus software tool mainly used to detect and remove various types of malware." echo "Includes viruses, Trojan horses, spyware, malicious scripts and other harmful software." echo "------------------------" - echo -e "${gl_lv}1. Full disk scan${gl_bai} ${gl_huang}2. Scan important directories${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" + echo -e "${gl_lv}1. Full scan${gl_bai} ${gl_huang}2. Scan important directories${gl_bai} ${gl_kjlan}3. Custom directory scanning${gl_bai}" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) - send_stats "Full disk scan" + send_stats "Full scan" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5168,8 +5167,8 @@ clamav() { break_end ;; 3) - send_stats "Custom directory scanning" - read -e -p "Please enter the directory to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories + send_stats "Custom directory scan" + read -e -p "Please enter the directories to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5188,7 +5187,7 @@ clamav() { # High performance mode optimization function optimize_high_performance() { - echo -e "${gl_lv}Switch to${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}switch to${tiaoyou_moshi}...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5219,7 +5218,7 @@ optimize_high_performance() { sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable large transparent pages to reduce latency + # Disable transparent huge pages to reduce latency echo never > /sys/kernel/mm/transparent_hugepage/enabled # Disable NUMA balancing sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5268,11 +5267,11 @@ optimize_balanced() { } -# Restore the default settings function +# Restore default settings function restore_defaults() { echo -e "${gl_lv}Revert to default settings...${gl_bai}" - echo -e "${gl_lv}Restore file descriptor...${gl_bai}" + echo -e "${gl_lv}Restore file descriptors...${gl_bai}" ulimit -n 1024 echo -e "${gl_lv}Restore virtual memory...${gl_bai}" @@ -5282,7 +5281,7 @@ restore_defaults() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}Restore network settings...${gl_bai}" + echo -e "${gl_lv}Reset network settings...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5301,7 +5300,7 @@ restore_defaults() { sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}Revert other optimizations...${gl_bai}" - # Restore transparent page + # Restore transparent huge pages echo always > /sys/kernel/mm/transparent_hugepage/enabled # Restore NUMA balancing sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5312,7 +5311,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5357,17 +5356,17 @@ Kernel_optimize() { while true; do clear send_stats "Linux kernel tuning management" - echo "Optimization of kernel parameters in Linux system" + echo "Linux system kernel parameter optimization" echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "Provides a variety of system parameter tuning modes, and users can choose to switch according to their own usage scenarios." - echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in the production environment!" + echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in production environment!" echo "--------------------" echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." echo "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." - echo "3. Website optimization mode: Optimize for the website server to improve concurrent connection processing capabilities, response speed and overall performance." - echo "4. Live broadcast optimization mode: Optimize the special needs of live broadcast streaming to reduce latency and improve transmission performance." - echo "5. Game server optimization mode: Optimize for game servers to improve concurrent processing capabilities and response speed." + echo "3. Website optimization mode: Optimize the website server to improve concurrent connection processing capabilities, response speed and overall performance." + echo "4. Live broadcast optimization mode: Optimize the special needs of live streaming to reduce delays and improve transmission performance." + echo "5. Game server optimization mode: Optimize the game server to improve concurrent processing capabilities and response speed." echo "6. Restore default settings: Restore system settings to default configuration." echo "--------------------" echo "0. Return to the previous menu" @@ -5391,7 +5390,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -5438,7 +5437,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}The system language has been modified to:$langReconnecting SSH takes effect.${gl_bai}" + echo -e "${gl_lv}The system language has been modified to:$langReconnect to SSH to take effect.${gl_bai}" hash -r break_end @@ -5481,7 +5480,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "Switch to English" + send_stats "switch to english" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -5511,7 +5510,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}Change is completed. Reconnect SSH to view changes!${gl_bai}" +echo -e "${gl_lv}Change completed. Reconnect to SSH to see the changes!${gl_bai}" hash -r break_end @@ -5602,8 +5601,8 @@ linux_trash() { echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "Recycle bin is empty" echo "------------------------" - echo "1. Enable the Recycle Bin 2. Close the Recycle Bin" - echo "3. Restore content 4. Clear the recycling bin" + echo "1. Enable Recycle Bin 2. Close Recycle Bin" + echo "3. Restore content 4. Empty Recycle Bin" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -5615,7 +5614,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "The Recycle Bin is enabled and deleted files will be moved to the Recycle Bin." + echo "Recycle Bin is enabled, deleted files will be moved to Recycle Bin." sleep 2 ;; 2) @@ -5627,19 +5626,19 @@ linux_trash() { sleep 2 ;; 3) - read -e -p "Enter the file name to restore:" file_to_restore + read -e -p "Enter the file name to be restored:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restoreRestored to the home directory." + echo "$file_to_restoreRestored to home directory." else - echo "The file does not exist." + echo "File does not exist." fi ;; 4) - read -e -p "Confirm to clear the recycling bin? [y/n]:" confirm + read -e -p "Are you sure you want to empty the Recycle Bin? [y/n]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "The recycling bin has been cleared." + echo "Recycle Bin has been emptied." fi ;; *) @@ -5654,19 +5653,19 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # Prompt the user to enter the backup directory + # Prompt user for backup directory echo "Example of creating a backup:" - echo "- Backup a single directory: /var/www" + echo "- Back up a single directory: /var/www" echo "- Back up multiple directories: /etc /home /var/log" echo "- Press Enter to use the default directory (/etc /usr /home)" - read -r -p "Please enter the directory to back up (multiple directories are separated by spaces, and if you enter directly, use the default directory):" input + read -r -p "Please enter the directory to be backed up (separate multiple directories with spaces, and press Enter to use the default directory):" input - # If the user does not enter a directory, use the default directory + # If the user does not enter a directory, the default directory is used if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -5692,18 +5691,18 @@ create_backup() { # Generate backup file name local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # Print the directory selected by the user + # Print directory selected by user echo "The backup directory you selected is:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done # Create backup - echo "Creating a backup$BACKUP_NAME..." + echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # Check if the command is successful + # Check if the command was successful if [ $? -eq 0 ]; then echo "Backup created successfully:$BACKUP_DIR/$BACKUP_NAME" else @@ -5715,7 +5714,7 @@ create_backup() { # Restore backup restore_backup() { send_stats "Restore backup" - # Select the backup you want to restore + # Select the backup to restore read -e -p "Please enter the backup file name to be restored:" BACKUP_NAME # Check if the backup file exists @@ -5745,7 +5744,7 @@ list_backups() { delete_backup() { send_stats "Delete backup" - read -e -p "Please enter the backup file name to delete:" BACKUP_NAME + read -e -p "Please enter the backup file name to be deleted:" BACKUP_NAME # Check if the backup file exists if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -5775,7 +5774,7 @@ linux_backup() { echo "------------------------" list_backups echo "------------------------" - echo "1. Create a backup 2. Restore a backup 3. Delete the backup" + echo "1. Create backup 2. Restore backup 3. Delete backup" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -5800,16 +5799,16 @@ linux_backup() { # Show connection list list_connections() { - echo "Saved connection:" + echo "Saved connections:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# Add a new connection +# Add new connection add_connection() { - send_stats "Add a new connection" + send_stats "Add new connection" echo "Example of creating a new connection:" echo "- Connection name: my_server" echo "- IP address: 192.168.1.100" @@ -5817,8 +5816,8 @@ add_connection() { echo "- Port: 22" echo "------------------------" read -e -p "Please enter a connection name:" name - read -e -p "Please enter your IP address:" ip - read -e -p "Please enter the username (default: root):" user + read -e -p "Please enter IP address:" ip + read -e -p "Please enter username (default: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root read -e -p "Please enter the port number (default: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 @@ -5830,18 +5829,18 @@ add_connection() { case $auth_choice in 1) - read -s -p "Please enter your password:" password_or_key + read -s -p "Please enter password:" password_or_key echo # 换行 ;; 2) - echo "Please paste the key content (press press Enter twice after pasting):" + echo "Please paste the key content (press Enter twice after pasting):" local password_or_key="" while IFS= read -r line; do - # If the input is empty and the key content already contains the beginning, the input ends + # If the input is a blank line and the key content already contains the beginning, end the input if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or the key content has been entered, continue to add + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -5867,9 +5866,9 @@ add_connection() { -# Delete a connection +# Delete connection delete_connection() { - send_stats "Delete a connection" + send_stats "Delete connection" read -e -p "Please enter the connection number to be deleted:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") @@ -5886,7 +5885,7 @@ delete_connection() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "The connection has been deleted!" + echo "Connection deleted!" } # Use connection @@ -5904,16 +5903,16 @@ use_connection() { echo "Connecting to$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # Connect with a key + # Connect using a key ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "Connection failed! Please check the following:" echo "1. Is the key file path correct?$password_or_key" - echo "2. Whether the key file permissions are correct (should be 600)." - echo "3. Whether the target server allows login using the key." + echo "2. Are the key file permissions correct (should be 600)." + echo "3. Whether the target server allows login using a key." fi else - # Connect with a password + # Connect using password if ! command -v sshpass &> /dev/null; then echo "Error: sshpass is not installed, please install sshpass first." echo "Installation method:" @@ -5938,7 +5937,7 @@ ssh_manager() { CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # Check if the configuration file and key directory exist, and if it does not exist, create it + # Check if the configuration file and key directory exist, create them if they do not exist if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5986,9 +5985,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# Mount the partition +# Mount partition mount_partition() { - send_stats "Mount the partition" + send_stats "Mount partition" read -e -p "Please enter the name of the partition to be mounted (e.g. sda1):" PARTITION # Check if the partition exists @@ -6003,11 +6002,11 @@ mount_partition() { return fi - # Create a mount point + # Create mount point MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # Mount the partition + # Mount partition mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6034,10 +6033,10 @@ unmount_partition() { umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "Partition uninstallation successfully:$MOUNT_POINT" + echo "Partition uninstalled successfully:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "Partition uninstallation failed!" + echo "Partition uninstall failed!" fi } @@ -6058,14 +6057,14 @@ format_partition() { return fi - # Check if the partition is already mounted + # Check whether the partition is mounted if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then echo "The partition has been mounted, please unmount it first!" return fi # Select file system type - echo "Please select the file system type:" + echo "Please select a file system type:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" @@ -6092,7 +6091,7 @@ format_partition() { mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "The partition format was successful!" + echo "Partition formatted successfully!" else echo "Partition formatting failed!" fi @@ -6110,7 +6109,7 @@ check_partition() { fi # Check partition status - echo "Check partition /dev/$PARTITIONStatus:" + echo "Check partition /dev/$PARTITIONstatus:" fsck "/dev/$PARTITION" } @@ -6125,7 +6124,7 @@ disk_manager() { list_partitions echo "------------------------" echo "1. Mount the partition 2. Unmount the partition 3. View the mounted partition" - echo "4. Format the partition 5. Check the partition status" + echo "4. Format partition 5. Check partition status" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -6147,20 +6146,20 @@ disk_manager() { # Show task list list_tasks() { - echo "Saved synchronization tasks:" + echo "Saved sync tasks:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# Add a new task +# Add new task add_task() { send_stats "Add new sync task" echo "Example of creating a new sync task:" echo "- Task name: backup_www" - echo "- Local Directory: /var/www" + echo "- Local directory: /var/www" echo "- Remote address: user@192.168.1.100" - echo "- Remote Directory: /backup/www" + echo "- Remote directory: /backup/www" echo "- Port number (default 22)" echo "---------------------------------" read -e -p "Please enter the task name:" name @@ -6170,7 +6169,7 @@ add_task() { read -e -p "Please enter the SSH port (default 22):" port port=${port:-22} - echo "Please select the authentication method:" + echo "Please select an authentication method:" echo "1. Password" echo "2. Key" read -e -p "Please select (1/2):" auth_choice @@ -6189,7 +6188,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or the key content has been entered, continue to add + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6227,10 +6226,10 @@ add_task() { install rsync rsync - echo "Task saved!" + echo "Mission saved!" } -# Delete a task +# Delete task delete_task() { send_stats "Delete sync task" read -e -p "Please enter the task number to be deleted:" num @@ -6259,7 +6258,7 @@ run_task() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # Analyze parameters + # Parse parameters local direction="push" # 默认是推送到远端 local num @@ -6270,7 +6269,7 @@ run_task() { num="$1" fi - # If there is no incoming task number, prompt the user to enter + # If no task number is passed in, the user is prompted to enter if [[ -z "$num" ]]; then read -e -p "Please enter the task number to be executed:" num fi @@ -6283,9 +6282,9 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # Adjust source and target path according to synchronization direction + # Adjust source and destination paths based on synchronization direction if [[ "$direction" == "pull" ]]; then - echo "Pulling synchronization to local:$remote:$local_path -> $remote_path" + echo "Pulling and synchronizing to local:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -6309,12 +6308,12 @@ run_task() { else # Check whether the key file exists and whether the permissions are correct if [[ ! -f "$password_or_key" ]]; then - echo "Error: The key file does not exist:$password_or_key" + echo "Error: Key file does not exist:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "Warning: The key file permissions are incorrect, and are being repaired..." + echo "Warning: Incorrect key file permissions, fixing..." chmod 600 "$password_or_key" fi @@ -6326,16 +6325,16 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" - echo "4. Do local and remote directories have correct access permissions" + echo "4. Do the local and remote directories have correct access permissions?" fi } # Create a scheduled task schedule_task() { - send_stats "Add synchronization timing tasks" + send_stats "Add synchronization scheduled tasks" read -e -p "Please enter the task number to be synchronized regularly:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6345,7 +6344,7 @@ schedule_task() { echo "Please select the scheduled execution interval:" echo "1) Execute once every hour" - echo "2) Perform once a day" + echo "2) Execute once a day" echo "3) Execute once a week" read -e -p "Please enter options (1/2/3):" interval @@ -6369,7 +6368,7 @@ schedule_task() { # Create to user's crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "The timing task has been created:$cron_job" + echo "Scheduled task has been created:$cron_job" } # View scheduled tasks @@ -6382,7 +6381,7 @@ view_tasks() { # Delete scheduled tasks delete_task_schedule() { - send_stats "Delete synchronization timing tasks" + send_stats "Delete synchronization scheduled tasks" read -e -p "Please enter the task number to be deleted:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then echo "Error: Please enter a valid task number!" @@ -6390,7 +6389,7 @@ delete_task_schedule() { fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "Deleted task number$numTiming tasks" + echo "Task number deleted$numscheduled tasks" } @@ -6409,7 +6408,7 @@ rsync_manager() { view_tasks echo echo "1. Create a new task 2. Delete a task" - echo "3. Perform local synchronization to the remote end 4. Perform remote synchronization to the local end" + echo "3. Perform local synchronization to the remote site 4. Perform remote synchronization to the local site" echo "5. Create a scheduled task 6. Delete a scheduled task" echo "---------------------------------" echo "0. Return to the previous menu" @@ -6505,10 +6504,10 @@ linux_info() { echo -e "${gl_kjlan}System load:${gl_bai}$load" echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" - echo -e "${gl_kjlan}Hard disk occupation:${gl_bai}$disk_info" + echo -e "${gl_kjlan}Hard drive usage:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Total Receive:${gl_bai}$rx" - echo -e "${gl_kjlan}Total send:${gl_bai}$tx" + echo -e "${gl_kjlan}Total received:${gl_bai}$rx" + echo -e "${gl_kjlan}Total sent:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" @@ -6521,10 +6520,10 @@ linux_info() { echo -e "${gl_kjlan}IPv6 address:${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNS address:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}Geographical location:${gl_bai}$country $city" + echo -e "${gl_kjlan}Location:${gl_bai}$country $city" echo -e "${gl_kjlan}System time:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Runtime:${gl_bai}$runtime" + echo -e "${gl_kjlan}Running time:${gl_bai}$runtime" echo @@ -6537,8 +6536,8 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" - echo -e "Basic tools" + # send_stats "Basic tools" + echo -e "basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo super administrative privilege tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" @@ -6546,19 +6545,19 @@ linux_tools() { echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP compression and decompression tool${gl_kjlan}8. ${gl_bai}tar GZ compression and decompression tool" echo -e "${gl_kjlan}9. ${gl_bai}tmux multi-channel background running tool${gl_kjlan}10. ${gl_bai}ffmpeg video encoding live streaming tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tool${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}range file management tool" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk occupation viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" + echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tool${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger file management tool" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk usage viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" echo -e "${gl_kjlan}15. ${gl_bai}vim text editor${gl_kjlan}16. ${gl_bai}nano text editor${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git version control system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Train screen security" - echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake-eating game" + echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Running train screensaver" + echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake mini game" echo -e "${gl_kjlan}28. ${gl_bai}space invaders mini game" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}All installations (excluding screen savers and games)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}Install all (excluding screensavers and games)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}Uninstall all" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Install the specified tool${gl_kjlan}42. ${gl_bai}Uninstall the specified tool" + echo -e "${gl_kjlan}41. ${gl_bai}Install specified tools${gl_kjlan}42. ${gl_bai}Uninstall the specified tool" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -6569,7 +6568,7 @@ linux_tools() { clear install curl clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" curl --help send_stats "Install curl" ;; @@ -6593,7 +6592,7 @@ linux_tools() { clear install socat clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" socat -h send_stats "Install socat" ;; @@ -6615,15 +6614,15 @@ linux_tools() { clear install unzip clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" unzip - send_stats "Install unzip" + send_stats "installunzip" ;; 8) clear install tar clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" tar --help send_stats "Install tar" ;; @@ -6631,7 +6630,7 @@ linux_tools() { clear install tmux clear - echo "The tool has been installed and the usage method is as follows:" + echo "The tool has been installed and is used as follows:" tmux --help send_stats "Install tmux" ;; @@ -6767,13 +6766,13 @@ linux_tools() { clear read -e -p "Please enter the installed tool name (wget curl sudo htop):" installname install $installname - send_stats "Install the specified software" + send_stats "Install specified software" ;; 42) clear read -e -p "Please enter the uninstalled tool name (htop ufw tmux cmatrix):" removename remove $removename - send_stats "Uninstall the specified software" + send_stats "Uninstall specified software" ;; 0) @@ -6804,7 +6803,7 @@ linux_bbr() { echo "Current TCP blocking algorithm:$congestion_algorithm $queue_algorithm" echo "" - echo "BBR Management" + echo "BBR management" echo "------------------------" echo "1. Turn on BBRv3 2. Turn off BBRv3 (it will restart)" echo "------------------------" @@ -6864,14 +6863,14 @@ docker_ssh_migration() { # ---------------------------- - # Backup + # backup # ---------------------------- backup_docker() { send_stats "Docker backup" echo -e "${YELLOW}Backing up Docker containers...${NC}" docker ps --format '{{.Names}}' - read -e -p "Please enter the name of the container to be backed up (separated by multiple spaces, and the Enter backup is all running containers):" containers + read -e -p "Please enter the name of the container to be backed up (separate multiple spaces and press Enter to back up all running containers):" containers install tar jq gzip install_docker @@ -6903,7 +6902,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}detected$cYes docker-compose container${NC}" + echo -e "${BLUE}detected$cis a docker-compose container${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -6913,7 +6912,7 @@ docker_ssh_migration() { # If the Compose project has already been packaged, skip if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose project [$project_name] Backed up, skip duplicate packaging...${NC}" + echo -e "${YELLOW}Compose project [$project_name] Already backed up, skip repeated packaging...${NC}" continue fi @@ -6924,7 +6923,7 @@ docker_ssh_migration() { echo "# docker-compose restore:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose project [$project_name] Packed:${project_dir}${NC}" + echo -e "${GREEN}Compose project [$project_name] Packaged:${project_dir}${NC}" else echo -e "${RED}docker-compose.yml not found, skipping this container...${NC}" fi @@ -6947,11 +6946,11 @@ docker_ssh_migration() { mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # Volume Mapping + # volume mapping local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -6961,11 +6960,11 @@ docker_ssh_migration() { done - # Backup all files under /home/docker (excluding subdirectories) + # Back up all files under /home/docker (excluding subdirectories) if [ -d "/home/docker" ]; then echo -e "${BLUE}Back up files under /home/docker...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}The file under /home/docker has been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}Files under /home/docker have been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" @@ -6989,7 +6988,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # ------------------------- + # --------- Prioritize restoring Compose projects --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -6998,10 +6997,10 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "Original path not found, please enter the restore directory path:" original_path - # Check if the container for the compose project is already running + # Check whether the container of the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose project [$project_name] There is already a container running, skip restore...${NC}" + echo -e "${YELLOW}Compose project [$project_name] Containers are already running, skip restore...${NC}" continue fi @@ -7010,17 +7009,17 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose project [$project_name] Decompressed to:$original_path${NC}" + echo -e "${GREEN}Compose project [$project_name] has been extracted to:$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose project [$project_name] Restore is complete!${NC}" + echo -e "${GREEN}Compose project [$project_name] Restore completed!${NC}" fi done - # ------------------------- - echo -e "${BLUE}Check and restore a normal Docker container...${NC}" + # --------- Continue to restore normal containers --------- + echo -e "${BLUE}Check and restore normal Docker containers...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue @@ -7035,7 +7034,7 @@ docker_ssh_migration() { fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information was not found, skip:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information not found, skip:$container${NC}"; continue; } # port mapping PORT_ARGS="" @@ -7073,14 +7072,14 @@ docker_ssh_migration() { docker rm -f "$container" fi - # Start the container + # Start container echo "Execute the restore command: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for common containers found${NC}" - # Restore the file under /home/docker + # Restore files under /home/docker if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}Restoring files under /home/docker...${NC}" mkdir -p /home/docker @@ -7100,7 +7099,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker migration" install jq - read -e -p "Please enter the backup directory to migrate:" BACKUP_DIR + read -e -p "Please enter the backup directory to be migrated:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } read -e -p "Target server IP:" TARGET_IP @@ -7112,7 +7111,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7133,7 +7132,7 @@ docker_ssh_migration() { # Main menu # ---------------------------- main_menu() { - send_stats "Docker backup migration and restore" + send_stats "Docker backup migration restore" while true; do clear echo "------------------------" @@ -7174,7 +7173,7 @@ linux_docker() { while true; do clear # send_stats "docker management" - echo -e "Docker Management" + echo -e "Docker management" docker_tato echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Install and update the Docker environment${gl_huang}★${gl_bai}" @@ -7188,18 +7187,18 @@ linux_docker() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}7. ${gl_bai}Clean up useless docker containers and mirror network data volumes" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Replace Docker source" + echo -e "${gl_kjlan}8. ${gl_bai}Change Docker source" echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" - echo -e "${gl_kjlan}12. ${gl_bai}Close Docker-ipv6 access" + echo -e "${gl_kjlan}12. ${gl_bai}Turn off Docker-ipv6 access" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}19. ${gl_bai}Backup/migrate/restore Docker environment" echo -e "${gl_kjlan}20. ${gl_bai}Uninstall the Docker environment" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) @@ -7275,7 +7274,7 @@ linux_docker() { echo "1. Create a network" echo "2. Join the network" echo "3. Exit the network" - echo "4. Delete the network" + echo "4. Delete network" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -7284,13 +7283,13 @@ linux_docker() { case $sub_choice in 1) send_stats "Create network" - read -e -p "Set a new network name:" dockernetwork + read -e -p "Set new network name:" dockernetwork docker network create $dockernetwork ;; 2) send_stats "Join the network" read -e -p "Add network name:" dockernetwork - read -e -p "Those containers are added to the network (multiple container names are separated by spaces):" dockernames + read -e -p "Which containers join the network (please separate multiple container names with spaces):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername @@ -7309,7 +7308,7 @@ linux_docker() { 4) send_stats "delete network" - read -e -p "Please enter the network name to delete:" dockernetwork + read -e -p "Please enter the network name to be deleted:" dockernetwork docker network rm $dockernetwork ;; @@ -7339,7 +7338,7 @@ linux_docker() { case $sub_choice in 1) - send_stats "Create a new volume" + send_stats "Create new volume" read -e -p "Set new volume name:" dockerjuan docker volume create $dockerjuan @@ -7376,7 +7375,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker cleaning" + send_stats "Docker cleanup" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7472,15 +7471,15 @@ linux_test() { echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Network speed measurement" + echo -e "${gl_kjlan}Network line speed test" echo -e "${gl_kjlan}11. ${gl_bai}besttrace three network backhaul delay routing test" echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace triple network backhaul line test" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed three-net speed measurement" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed triple network speed test" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunction speed test script" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality Network Quality Physical Examination Script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}Hardware performance testing" @@ -7488,13 +7487,13 @@ linux_test() { echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU performance test script" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Comprehensive test" + echo -e "${gl_kjlan}Comprehensive testing" echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" - echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx fusion monster evaluation${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) @@ -7515,7 +7514,7 @@ linux_test() { ;; 4) clear - send_stats "xykt_IP quality physical examination script" + send_stats "xykt_IP quality check script" bash <(curl -Ls IP.Check.Place) ;; @@ -7528,12 +7527,12 @@ linux_test() { ;; 12) clear - send_stats "mtr_trace three network return line test" + send_stats "mtr_trace triple network backhaul line test" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed three-net speed measurement" + send_stats "Superspeed triple network speed test" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) @@ -7545,7 +7544,7 @@ linux_test() { 15) clear send_stats "nxtrace specifies IP backhaul test script" - echo "List of IPs that can be referenced" + echo "Reference IP list" echo "------------------------" echo "Beijing Telecom: 219.141.136.12" echo "Beijing Unicom: 202.106.50.1" @@ -7564,7 +7563,7 @@ linux_test() { echo "Hunan Mobile: 39.134.254.6" echo "------------------------" - read -e -p "Enter a specified IP:" testip + read -e -p "Enter a specific IP:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; @@ -7577,7 +7576,7 @@ linux_test() { 17) clear - send_stats "i-abc multifunction speed test script" + send_stats "i-abc multifunctional speed test script" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; @@ -7589,13 +7588,13 @@ linux_test() { 21) clear - send_stats "yabs performance testing" + send_stats "yabs performance test" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "iicu/gb5 CPU performance test script" + send_stats "icu/gb5 CPU performance test script" check_swap bash <(curl -sL bash.icu/gb5) ;; @@ -7640,17 +7639,17 @@ linux_Oracle() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD reinstall system script" echo -e "${gl_kjlan}4. ${gl_bai}Detective R startup script" - echo -e "${gl_kjlan}5. ${gl_bai}Turn on ROOT password login mode" + echo -e "${gl_kjlan}5. ${gl_bai}Enable ROOT password login mode" echo -e "${gl_kjlan}6. ${gl_bai}IPV6 recovery tool" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) clear - echo "Active script: CPU occupies 10-20% memory occupies 20%" + echo "Active script: CPU usage 10-20% Memory usage 20%" read -e -p "Are you sure you want to install it? (Y/N):" choice case "$choice" in [Yy]) @@ -7663,17 +7662,17 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # Prompt the user to enter the number of CPU cores and occupancy percentage, and if entered, use the default value. - read -e -p "Please enter the number of CPU cores [default:$DEFAULT_CPU_CORE]: " cpu_core + # Prompts the user to enter the number of CPU cores and occupancy percentage. If the user presses Enter, the default value will be used. + read -e -p "Please enter the number of CPU cores [Default:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "Please enter the CPU usage percentage range (e.g. 10-20) [Default:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "Please enter the memory usage percentage [default:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "Please enter the memory usage percentage [Default:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "Please enter the Speedtest interval time (seconds) [default:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "Please enter Speedtest interval time (seconds) [Default:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # Run Docker container @@ -7706,13 +7705,13 @@ linux_Oracle() { clear echo "Reinstall the system" echo "--------------------------------" - echo -e "${gl_hong}Notice:${gl_bai}Reinstallation may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." - read -e -p "Are you sure to continue? (Y/N):" choice + echo -e "${gl_hong}Notice:${gl_bai}Reinstalling may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." + read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) while true; do - read -e -p "Please select the system to reinstall: 1. Debian12 | 2. Ubuntu20.04:" sys_choice + read -e -p "Please select the system you want to reinstall: 1. Debian12 | 2. Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7732,7 +7731,7 @@ linux_Oracle() { read -e -p "Please enter your password after reinstallation:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud Reinstall System Script" + send_stats "Oracle Cloud reinstall system script" ;; [Nn]) echo "Canceled" @@ -7745,7 +7744,7 @@ linux_Oracle() { 4) clear - send_stats "Detective R start script" + send_stats "Detective R startup script" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -7757,7 +7756,7 @@ linux_Oracle() { clear bash <(curl -L -s jhb.ovh/jb/v6.sh) echo "This function is provided by jhb, thank him!" - send_stats "ipv6 fix" + send_stats "ipv6 repair" ;; 0) kejilion @@ -7806,7 +7805,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}The environment is installed${gl_bai}Site:$outputdatabase:$db_output" + echo -e "${gl_lv}Environment is installed${gl_bai}Site:$outputdatabase:$db_output" fi fi @@ -7839,26 +7838,26 @@ linux_ldnmp() { ldnmp_tato echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}Install LDNMP environment${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install the Kadao Cloud Desktop" + echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install Kedao Cloud Desktop" echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Movie and TV Station${gl_huang}6. ${gl_bai}Install Unicorn Digital Card Network" echo -e "${gl_huang}7. ${gl_bai}Install flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" - echo -e "${gl_huang}9. ${gl_bai}Install LinkStack Shared Link Platform${gl_huang}20. ${gl_bai}Custom dynamic site" + echo -e "${gl_huang}9. ${gl_bai}Install LinkStack sharing link platform${gl_huang}20. ${gl_bai}Custom dynamic site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}Only install nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}Site redirection" + echo -e "${gl_huang}21. ${gl_bai}Only install nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}site redirect" echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy-domain name" echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden Password Management Platform${gl_huang}26. ${gl_bai}Install Halo Blog Site" - echo -e "${gl_huang}27. ${gl_bai}Install AI Painting Prompt Word Generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" + echo -e "${gl_huang}27. ${gl_bai}Install the AI ​​painting prompt word generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" echo -e "${gl_huang}30. ${gl_bai}Custom static site" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up the entire site data" - echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore the entire site data" + echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" + echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore whole site data" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environments${gl_huang}36. ${gl_bai}Optimize LDNMP environment" - echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall LDNMP environment" + echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall the LDNMP environment" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}Return to main menu" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in @@ -7909,7 +7908,7 @@ linux_ldnmp() { 4) clear - # Kedao Cloud Desktop + # Kedao cloud desktop webname="可道云桌面" send_stats "Install$webname" echo "Start deployment$webname" @@ -7987,7 +7986,7 @@ linux_ldnmp() { 6) clear - # One-legged counting card + # One-legged number card webname="独脚数卡" send_stats "Install$webname" echo "Start deployment$webname" @@ -8035,7 +8034,7 @@ linux_ldnmp() { 7) clear - # Flarum Forum + # flarum forum webname="flarum论坛" send_stats "Install$webname" echo "Start deployment$webname" @@ -8182,7 +8181,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] Upload PHP source code" echo "-------------" - echo "Currently, only zip-format source code packages are allowed. Please put the source code packages in /home/web/html/${yuming}In the directory" + echo "Currently, only source code packages in zip format are allowed to be uploaded. Please put the source code packages in /home/web/html/${yuming}under directory" read -e -p "You can also enter the download link to download the source code package remotely. Press Enter directly to skip the remote download:" url_download if [ -n "$url_download" ]; then @@ -8198,7 +8197,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "Please enter the path of index.php, similar to (/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "Please enter the path to index.php, similar to (/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8223,7 +8222,7 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}4/6${gl_bai}] Install the specified extension" + echo -e "[${gl_huang}4/6${gl_bai}] Install specified extension" echo "-------------" echo "Installed extensions" docker exec php php -m @@ -8252,8 +8251,8 @@ linux_ldnmp() { echo ;; 2) - echo "The database backup must be a .gz-end compressed package. Please put it in the /home/ directory to support the import of backup data of Pagoda/1panel." - read -e -p "You can also enter the download link to remotely download the backup data. Directly press Enter will skip remote download:" url_download_db + echo "Database backup must be a compressed package ending in .gz. Please put it in the /home/ directory to support the import of Pagoda/1panel backup data." + read -e -p "You can also enter the download link to download the backup data remotely. Press Enter directly to skip the remote download:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8336,7 +8335,7 @@ linux_ldnmp() { echo "Start deployment$webname" add_yuming echo -e "Domain name format:${gl_huang}google.com${gl_bai}" - read -e -p "Please enter your anti-generation domain name:" fandai_yuming + read -e -p "Please enter your reverse proxy domain name:" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8451,7 +8450,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}] Upload static source code" echo "-------------" - echo "Currently, only source code packages in zip format are allowed to be uploaded. Please put the source code packages in /home/web/html/${yuming}In the directory" + echo "Currently, only source code packages in zip format are allowed to be uploaded. Please put the source code packages in /home/web/html/${yuming}under directory" read -e -p "You can also enter the download link to download the source code package remotely. Press Enter directly to skip the remote download:" url_download if [ -n "$url_download" ]; then @@ -8557,7 +8556,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "Select the time for daily backup (hours, 0-23):" hour + read -e -p "Select daily backup time (hour, 0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8583,7 +8582,7 @@ linux_ldnmp() { linux_ldnmp fi - # If the user does not enter the file name, use the latest compressed package + # If the user does not enter a file name, the latest compressed package is used if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8593,7 +8592,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" + echo -e "${gl_huang}Unzipping$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8650,7 +8649,7 @@ linux_ldnmp() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8755,7 +8754,7 @@ linux_ldnmp() { 38) root_use - send_stats "Uninstall LDNMP environment" + send_stats "Uninstall the LDNMP environment" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8813,58 +8812,58 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Official version of Baota Panel${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" + echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" - echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB Offline BT Magnetic Download Panel" - echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multiplayer online chat system" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" + echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao project management software${gl_kjlan}12. ${color12}Qinglong Panel Timed Task Management Platform" + echo -e "${gl_kjlan}11. ${color11}ZenTao project management software${gl_kjlan}12. ${color12}Qinglong panel scheduled task management platform" echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" echo -e "${gl_kjlan}17. ${color17}AdGuardHome removes adware${gl_kjlan}18. ${color18}onlyofficeOnline office OFFICE" - echo -e "${gl_kjlan}19. ${color19}Thunder Pool WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" echo -e "${gl_kjlan}23. ${color23}Memos web memo${gl_kjlan}24. ${color24}Webtop remote desktop web version${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today timing task management framework" - echo -e "${gl_kjlan}27. ${color27}Dockge Container Stack Management Panel${gl_kjlan}28. ${color28}LibreSpeed ​​Speed ​​Test Tool" + echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today scheduled task management framework" + echo -e "${gl_kjlan}27. ${color27}Dockge container stack management panel${gl_kjlan}28. ${color28}LibreSpeed ​​speed test tool" echo -e "${gl_kjlan}29. ${color29}searxng aggregated search station${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF tool collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF Tools Collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" - echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI Chat Aggregation Website" + echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI chat aggregation website" echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}Mouse Management Panel${gl_kjlan}42. ${color42}Nexte remote connection tool" - echo -e "${gl_kjlan}43. ${color43}RustDesk Remote Desk (Server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk remote desktop (relay)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${color41}Mouse management panel${gl_kjlan}42. ${color42}Nexterm remote connection tool" + echo -e "${gl_kjlan}43. ${color43}RustDesk remote desktop (server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk remote desktop (relay)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub acceleration station${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}Prometheus monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (Container Monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tool" + echo -e "${gl_kjlan}49. ${color49}Prometheus (container monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}51. ${color51}PVE open chick panel${gl_kjlan}52. ${color52}DPanel container management panel" - echo -e "${gl_kjlan}53. ${color53}llama3 chat AI large model${gl_kjlan}54. ${color54}AMH Host Website Building Management Panel" - echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server side)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI large model${gl_kjlan}58. ${color58}Dify big model knowledge base${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI Big Model Asset Management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" + echo -e "${gl_kjlan}53. ${color53}llama3 chat AI large model${gl_kjlan}54. ${color54}AMH host website building management panel" + echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI large model${gl_kjlan}58. ${color58}Dify large model knowledge base${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI large model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow large model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" - echo -e "${gl_kjlan}65. ${color65}n8n Automation Workflow Platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" - echo -e "${gl_kjlan}67. ${color67}ddns-go Dynamic DNS Management Tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL Certificate Management Platform" - echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot Chat Robot Framework" + echo -e "${gl_kjlan}65. ${color65}n8n automated workflow platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" + echo -e "${gl_kjlan}67. ${color67}ddns-go dynamic DNS management tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL certificate management platform" + echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot chatbot framework" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome Private Music Server${gl_kjlan}72. ${color72}bitwarden password manager${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV Private Film and Television${gl_kjlan}74. ${color74}MoonTV private movies" + echo -e "${gl_kjlan}71. ${color71}Navidrome private music server${gl_kjlan}72. ${color72}bitwarden password manager${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV Private Movies${gl_kjlan}74. ${color74}MoonTV private movies" echo -e "${gl_kjlan}75. ${color75}Melody music wizard${gl_kjlan}76. ${color76}Online DOS old games" echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki intelligent document management system" echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet Video Conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet video conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tool" echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" - echo -e "${gl_kjlan}87. ${color87}SyncTV is a great tool for watching movies together${gl_kjlan}88. ${color88}Owncast self-hosted live broadcast platform" + echo -e "${gl_kjlan}87. ${color87}SyncTV is a great tool for watching movies together${gl_kjlan}88. ${color88}Owncast self-hosted live streaming platform" echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser file manager" @@ -8873,13 +8872,14 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing peer-to-peer file synchronization tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multiplayer online chat system" + echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" + echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all application data" + echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice fi case $sub_choice in @@ -9075,9 +9075,9 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha Monitoring$check_docker $update_status" + echo -e "Nezha monitoring$check_docker $update_status" echo "Open source, lightweight, easy-to-use server monitoring and operation and maintenance tool" - echo "Official website construction document: https://nezha.wiki/guide/dashboard.html" + echo "Official website construction documentation: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip @@ -9155,7 +9155,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "Post Office Services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9192,7 +9192,7 @@ while true; do echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "Parse these DNS records first" + echo "First parse these DNS records" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9259,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "The app has been uninstalled" + echo "App has been uninstalled" ;; *) @@ -9293,7 +9293,7 @@ while true; do clear ip_address - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -9411,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -9573,7 +9573,7 @@ while true; do echo "" echo "------------------------" - echo "1. Install 2. Update 3. Reset Password 4. Uninstall" + echo "1. Install 2. Update 3. Reset password 4. Uninstall" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -9587,7 +9587,7 @@ while true; do add_app_id clear - echo "The Thunder Pool WAF panel has been installed" + echo "The Leichi WAF panel has been installed" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9611,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "If you are the default installation directory, the project has now been uninstalled. If you are customizing the installation directory, you need to go to the installation directory to execute it yourself:" + echo "If you are in the default installation directory, the project has been uninstalled now. If you customize the installation directory, you need to go to the installation directory and execute it yourself:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -9731,7 +9731,7 @@ while true; do docker_rum() { read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password + read -e -p "Set login user password:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10072,7 +10072,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya Family Bucket" + send_stats "Xiaoya family bucket" clear install_docker check_disk_space 1 @@ -10296,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10383,7 +10383,7 @@ while true; do 51|pve) clear - send_stats "PVE Chicken" + send_stats "PVE open chick" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -10503,7 +10503,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -10518,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10561,7 +10561,7 @@ while true; do docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -10569,7 +10569,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10657,7 +10657,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -10673,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10970,7 +10970,7 @@ while true; do docker_app_install() { read -e -p "Set login username:" admin - read -e -p "Set the login user password:" admin_password + read -e -p "Set login user password:" admin_password read -e -p "Enter authorization code:" shouquanma @@ -10987,7 +10987,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "Installed" + echo "Installation completed" check_docker_app_ip } @@ -11001,7 +11001,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11222,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11290,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "set up${docker_name}The login key (sk-staring letters and numbers combinations) such as: sk-159kejilionyyds163:" app_passwd + read -e -p "set up${docker_name}Login key (sk-a combination of letters and numbers starting with) such as: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11634,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11826,7 +11826,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11846,7 +11846,7 @@ while true; do read -e -p "Please enter the number of clients in the network (default 5):" COUNT COUNT=${COUNT:-5} - read -e -p "Please enter the WireGuard segment (default 10.13.13.0):" NETWORK + read -e -p "Please enter the WireGuard network segment (default 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11925,8 +11925,8 @@ while true; do sleep 2 echo -e "${gl_lv}${COUNT}Configure all outputs for each client. The usage method is as follows:${gl_bai}" echo -e "${gl_lv}1. Download the wg APP on your mobile phone and scan the QR code above to quickly connect to the Internet.${gl_bai}" - echo -e "${gl_lv}2. Download the Windows client and copy the configuration code to connect to the network.${gl_bai}" - echo -e "${gl_lv}3. Linux uses scripts to deploy WG clients and copy configuration code to connect to the network.${gl_bai}" + echo -e "${gl_lv}2. Download the client for Windows and copy the configuration code to connect to the network.${gl_bai}" + echo -e "${gl_lv}3. Use a script to deploy the WG client on Linux and copy the configuration code to connect to the network.${gl_bai}" echo -e "${gl_lv}Official client download method: https://www.wireguard.com/install/${gl_bai}" break_end @@ -11955,10 +11955,10 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # Create a directory (if it does not exist) + # Create directory if it does not exist mkdir -p "$(dirname "$CONFIG_FILE")" - echo "Please paste your client configuration and press Enter twice in a row to save:" + echo "Please paste your client configuration and press Enter twice to save:" # initialize variables input="" @@ -11977,7 +11977,7 @@ while true; do fi done - # Write to the configuration file + # Write configuration file echo "$input" > "$CONFIG_FILE" echo "Client configuration saved to$CONFIG_FILE" @@ -12059,7 +12059,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12129,7 +12129,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "The app has been uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12165,10 +12165,51 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "Installation completed" + check_docker_app_ip + echo "Initial username: admin" + echo "Initial password: umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "App has been uninstalled" + } + + docker_app_plus + + ;; + + b) clear - send_stats "All applications backup" + send_stats "All application backup" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" @@ -12176,7 +12217,7 @@ while true; do while true; do clear - echo "The backup file has been created: /$backup_filename" + echo "Backup file created: /$backup_filename" read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) @@ -12200,7 +12241,7 @@ while true; do break ;; *) - echo "Note: Currently, the backup only includes docker projects, and does not include data backup of website building panels such as Pagoda and 1panel." + echo "Note: The current backup only includes docker projects, and does not include data backup of website building panels such as Pagoda and 1panel." break ;; esac @@ -12210,8 +12251,8 @@ while true; do r) root_use - send_stats "All applications restore" - echo "Available app backups" + send_stats "Restore all apps" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12222,17 +12263,17 @@ while true; do linux_panel fi - # If the user does not enter the file name, use the latest compressed package + # If the user does not enter a file name, the latest compressed package is used if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}Decompression is being done$filename ...${gl_bai}" + echo -e "${gl_huang}Unzipping$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "The application data has been restored. Please manually enter the specified application menu and update the application to restore the application." + echo "The application data has been restored. Currently, please manually enter the specified application menu and update the application to restore the application." else - echo "No compression package was found." + echo "No compressed package found." fi ;; @@ -12258,28 +12299,28 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, tasks in the workspace will not be interrupted, and tasks in the background will be resident." - echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and press d alone to exit the workspace!" + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Workspace No. 1" + echo -e "${gl_kjlan}1. ${gl_bai}Work Area 1" echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" - echo -e "${gl_kjlan}3. ${gl_bai}Workspace No. 3" - echo -e "${gl_kjlan}4. ${gl_bai}Workspace No. 4" + echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" + echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" - echo -e "${gl_kjlan}8. ${gl_bai}Workspace No. 8" + echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" - echo -e "${gl_kjlan}24. ${gl_bai}Delete the specified workspace" + echo -e "${gl_kjlan}24. ${gl_bai}Delete specified workspace" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -12299,7 +12340,7 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 3) @@ -12334,7 +12375,7 @@ linux_work() { clear install tmux local SESSION_NAME="work7" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" tmux_run ;; 8) @@ -12369,9 +12410,9 @@ linux_work() { fi send_stats "SSH resident mode" echo -e "SSH resident mode${tmux_sshd_status}" - echo "After SSH connection is enabled, it will directly enter the resident mode and return to the previous working state." + echo "After opening the SSH connection, it will directly enter the resident mode and return directly to the previous working state." echo "------------------------" - echo "1. Turn on 2. Turn off" + echo "1. On 2. Off" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -12380,7 +12421,7 @@ linux_work() { 1) install tmux local SESSION_NAME="sshd" - send_stats "Start the workspace$SESSION_NAME" + send_stats "Start workspace$SESSION_NAME" grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# Automatically enter tmux session\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run @@ -12447,20 +12488,20 @@ linux_Settings() { # send_stats "System Tools" echo -e "system tools" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut keys${gl_kjlan}2. ${gl_bai}Change login password" + echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" - echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify the SSH connection port" + echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" - echo -e "${gl_kjlan}13. ${gl_bai}User Management${gl_kjlan}14. ${gl_bai}User/password generator" + echo -e "${gl_kjlan}13. ${gl_bai}User management${gl_kjlan}14. ${gl_bai}User/password generator" echo -e "${gl_kjlan}15. ${gl_bai}System time zone adjustment${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" - echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify the host name" + echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify hostname" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Scheduled task management" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}Native host resolution${gl_kjlan}22. ${gl_bai}SSH defense program" - echo -e "${gl_kjlan}23. ${gl_bai}Automatic shutdown of current limit${gl_kjlan}24. ${gl_bai}ROOT private key login mode" + echo -e "${gl_kjlan}23. ${gl_bai}Current limiting automatic shutdown${gl_kjlan}24. ${gl_bai}ROOT private key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Linux system kernel parameter optimization${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tools${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}file manager" @@ -12471,13 +12512,13 @@ linux_Settings() { echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}Message board${gl_kjlan}66. ${gl_bai}One-stop system optimization${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}message board${gl_kjlan}66. ${gl_bai}One-stop system tuning${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and security" echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) @@ -12490,7 +12531,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "Shortcut keys are set" + echo "Shortcut keys have been set" send_stats "Script shortcut key has been set" break_end linux_Settings @@ -12515,12 +12556,12 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This feature seamlessly installs any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "Recommended version: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "Query more versions: https://www.python.org/downloads/" + echo "Recommended versions: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "Check more versions: https://www.python.org/downloads/" echo "------------" read -e -p "Enter the python version number you want to install (enter 0 to exit):" py_new_v @@ -12630,12 +12671,12 @@ EOF send_stats "Exit SSH port modification" break else - echo "The port number is invalid, please enter a number between 1 and 65535." - send_stats "Invalid SSH port input" + echo "The port number is invalid. Please enter a number between 1 and 65535." + send_stats "Invalid SSH port entered" break_end fi else - echo "The input is invalid, please enter the number." + echo "Invalid input, please enter a number." send_stats "Invalid SSH port entered" break_end fi @@ -12655,7 +12696,7 @@ EOF ;; 9) root_use - send_stats "New users disable root" + send_stats "Disable root for new users" read -e -p "Please enter a new username (enter 0 to exit):" new_username if [ "$new_username" == "0" ]; then break_end @@ -12692,11 +12733,11 @@ EOF echo "" echo "------------------------" - echo "1. IPv4 priority 2. IPv6 priority 3. IPv6 repair tool" + echo "1. IPv4 first 2. IPv6 first 3. IPv6 repair tool" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Choose a preferred network:" choice + read -e -p "Choose your preferred network:" choice case $choice in 1) @@ -12715,7 +12756,7 @@ EOF clear bash <(curl -L -s jhb.ovh/jb/v6.sh) echo "This function is provided by jhb, thank him!" - send_stats "ipv6 fix" + send_stats "ipv6 repair" ;; *) @@ -12743,11 +12784,11 @@ EOF echo -e "Current virtual memory:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. Assign 1024M 2. Assign 2048M 3. Assign 4096M 4. Custom size" + echo "1. Allocate 1024M 2. Allocate 2048M 3. Allocate 4096M 4. Custom size" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case "$choice" in 1) @@ -12794,7 +12835,7 @@ EOF echo "" - echo "Account operation" + echo "Account operations" echo "------------------------" echo "1. Create a regular account 2. Create a premium account" echo "------------------------" @@ -12804,29 +12845,29 @@ EOF echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) # Prompt user for new username read -e -p "Please enter a new username:" new_username - # Create a new user and set a password + # Create new user and set password useradd -m -s /bin/bash "$new_username" passwd "$new_username" - echo "The operation has been completed." + echo "The operation is complete." ;; 2) - # Prompt the user to enter a new username + # Prompt user for new username read -e -p "Please enter a new username:" new_username # Create new user and set password useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # Grant new users sudo permissions + # Give the new user sudo permissions echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12835,8 +12876,8 @@ EOF ;; 3) - read -e -p "Please enter your username:" username - # Grant new users sudo permissions + read -e -p "Please enter username:" username + # Give the new user sudo permissions echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12848,7 +12889,7 @@ EOF ;; 5) - read -e -p "Please enter the username to delete:" username + read -e -p "Please enter the username you want to delete:" username # Delete users and their home directories userdel -r "$username" ;; @@ -12862,12 +12903,12 @@ EOF 14) clear - send_stats "User Information Generator" - echo "Random username" + send_stats "User information generator" + echo "random username" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "Random username$i: $username" + echo "random username$i: $username" done echo "" @@ -12893,7 +12934,7 @@ EOF done echo "" - echo "16-bit random password" + echo "16-digit random password" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) @@ -12905,7 +12946,7 @@ EOF echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "Random password$i: $password" + echo "random password$i: $password" done echo "" @@ -12935,24 +12976,24 @@ EOF echo "1. Shanghai, China time 2. Hong Kong time, China" echo "3. Tokyo, Japan time 4. Seoul, South Korea time" echo "5. Singapore time 6. Kolkata, India time" - echo "7. Dubai time in the UAE 8. Sydney time in Australia" - echo "9. Time in Bangkok, Thailand" + echo "7. Dubai, United Arab Emirates time 8. Sydney, Australia time" + echo "9. Bangkok, Thailand time" echo "------------------------" echo "Europe" - echo "11. London time in the UK 12. Paris time in France" + echo "11. London, UK time 12. Paris, France time" echo "13. Berlin, Germany time 14. Moscow, Russia time" - echo "15. Utrecht time in the Netherlands 16. Madrid time in Spain" + echo "15. Utracht Time, Netherlands 16. Madrid Time, Spain" echo "------------------------" echo "America" echo "21. US Western Time 22. US Eastern Time" - echo "23. Canadian time 24. Mexican time" - echo "25. Brazil Time 26. Argentina Time" + echo "23. Canada time 24. Mexico time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in @@ -13000,9 +13041,9 @@ EOF while true; do clear local current_hostname=$(uname -n) - echo -e "Current host name:${gl_huang}$current_hostname${gl_bai}" + echo -e "Current hostname:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "Please enter the new host name (enter 0 to exit):" new_hostname + read -e -p "Please enter a new hostname (enter 0 to exit):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine @@ -13031,7 +13072,7 @@ EOF send_stats "Hostname changed" sleep 1 else - echo "Exited, hostname not changed." + echo "Exited without changing hostname." break fi done @@ -13039,16 +13080,16 @@ EOF 19) root_use - send_stats "Change the system update source" + send_stats "Change system update source" clear - echo "Select the update source area" - echo "Connect to LinuxMirrors to switch system update source" + echo "Select update source region" + echo "Access LinuxMirrors to switch system update sources" echo "------------------------" echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your choice:" choice + read -e -p "Enter your selection:" choice case $choice in 1) @@ -13060,7 +13101,7 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "Overseas origin" + send_stats "Overseas sources" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) @@ -13095,7 +13136,7 @@ EOF echo "1. Monthly tasks 2. Weekly tasks" echo "3. Daily tasks 4. Hourly tasks" echo "------------------------" - read -e -p "Please enter your selection:" dingshi + read -e -p "Please enter your choice:" dingshi case $dingshi in 1) @@ -13103,7 +13144,7 @@ EOF (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "Choose what week to perform the task? (0-6, 0 represents Sunday):" weekday + read -e -p "Choose a day of the week to perform the task? (0-6, 0 represents Sunday):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) @@ -13118,16 +13159,16 @@ EOF break # 跳出 ;; esac - send_stats "Add timed tasks" + send_stats "Add a scheduled task" ;; 2) - read -e -p "Please enter the keywords that need to be deleted:" kquest + read -e -p "Please enter the keyword of the task to be deleted:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "Delete timing tasks" + send_stats "Delete scheduled tasks" ;; 3) crontab -e - send_stats "Edit timing tasks" + send_stats "Edit scheduled tasks" ;; *) break # 跳出循环,退出菜单 @@ -13142,8 +13183,8 @@ EOF send_stats "Local host resolution" while true; do clear - echo "Native host parsing list" - echo "If you add parse matches here, dynamic parsing will no longer be used" + echo "Native host resolution list" + echo "If you add parsing matching here, dynamic parsing will no longer be used" cat /etc/hosts echo "" echo "operate" @@ -13156,9 +13197,9 @@ EOF case $host_dns in 1) - read -e -p "Please enter a new parsing record Format: 110.25.5.33 kejilion.pro:" addhost + read -e -p "Please enter a new parsing record format: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "Local host parsing has been added" + send_stats "Local host resolution is added" ;; 2) @@ -13180,10 +13221,10 @@ EOF check_f2b_status echo -e "SSH defense program$check_f2b_status" - echo "fail2ban is an SSH tool to prevent brute force" + echo "fail2ban is an SSH tool to prevent brute force cracking" echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. Install the defense program" + echo "1. Install a defense program" echo "------------------------" echo "2. View SSH interception records" echo "3. Real-time log monitoring" @@ -13227,7 +13268,7 @@ EOF 23) root_use - send_stats "Current limit shutdown function" + send_stats "Current limiting shutdown function" while true; do clear echo "Current limiting shutdown function" @@ -13236,38 +13277,38 @@ EOF echo "The current traffic usage will be cleared when the server is restarted!" output_status echo -e "${gl_kjlan}Total received:${gl_bai}$rx" - echo -e "${gl_kjlan}Total send:${gl_bai}$tx" + echo -e "${gl_kjlan}Total sent:${gl_bai}$tx" # Check if Limiting_Shut_down.sh file exists if [ -f ~/Limiting_Shut_down.sh ]; then # Get the value of threshold_gb local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}The current set entry-station current limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}The current outbound current limit threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limit shutdown function is not enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo echo "------------------------------------------------" echo "The system will detect whether the actual traffic reaches the threshold every minute, and will automatically shut down the server after reaching the threshold!" echo "------------------------" - echo "1. Turn on the current limit shutdown function 2. Deactivate the current limit shutdown function" + echo "1. Enable the current limiting shutdown function 2. Disable the current limiting shutdown function" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" Limiting + read -e -p "Please enter your choice:" Limiting case "$Limiting" in 1) - # Enter the new virtual memory size + # Enter new virtual memory size echo "If the actual server only has 100G traffic, you can set the threshold to 95G and shut down in advance to avoid traffic errors or overflows." read -e -p "Please enter the inbound traffic threshold (unit is G, default is 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "Please enter the traffic reset date (default reset on the 1st of each month):" cz_day + read -e -p "Please enter the traffic reset date (default resets on the 1st of every month):" cz_day cz_day=${cz_day:-1} cd ~ @@ -13280,15 +13321,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "Current limit shutdown has been set" - send_stats "Current limit shutdown has been set" + echo "Current limiting shutdown has been set" + send_stats "Current limiting shutdown has been set" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "Current limit shutdown function has been turned off" + echo "Current limiting shutdown function is turned off" ;; *) break @@ -13309,11 +13350,11 @@ EOF echo "------------------------------------------------" echo "A key pair will be generated, a more secure way to log in via SSH" echo "------------------------" - echo "1. Generate a new key 2. Import an existing key 3. View the native key" + echo "1. Generate a new key 2. Import an existing key 3. View the local key" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your selection:" host_dns + read -e -p "Please enter your choice:" host_dns case $host_dns in 1) @@ -13323,13 +13364,13 @@ EOF ;; 2) - send_stats "Import an existing public key" + send_stats "Import existing public key" import_sshkey break_end ;; 3) - send_stats "View the local secret key" + send_stats "View local key" echo "------------------------" echo "Public key information" cat ~/.ssh/authorized_keys @@ -13355,13 +13396,13 @@ EOF echo "Video introduction: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "You need to configure the tg robot API and the user ID to receive alerts to achieve real-time monitoring and alerts of local CPU, memory, hard disk, traffic, and SSH login." - echo "After reaching the threshold, the user will be sent to the user" + echo "When the threshold is reached, a warning message will be sent to the user." echo -e "${gl_hui}- Regarding traffic, restarting the server will recalculate -${gl_bai}" read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) - send_stats "Telegram warning is enabled" + send_stats "Telegram warning enabled" cd ~ install nano tmux bc jq check_crontab_installed @@ -13395,7 +13436,7 @@ EOF clear echo "TG-bot early warning system has been activated" - echo -e "${gl_hui}You can also place the TG-check-notify.sh warning file in the root directory on other machines and use it directly!${gl_bai}" + echo -e "${gl_hui}You can also put the TG-check-notify.sh warning file in the root directory on other machines and use it directly!${gl_bai}" ;; [Nn]) echo "Canceled" @@ -13476,7 +13517,7 @@ EOF 41) clear send_stats "message board" - echo "Visit the official message board of Technology lion. If you have any ideas about scripts, please leave a message and communicate!" + echo "Visit the official message board of Technology Lion. If you have any ideas about the script, please leave a message to exchange!" echo "https://board.kejilion.pro" echo "Public password: kejilion.sh" ;; @@ -13494,17 +13535,17 @@ EOF echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" echo -e "5. Open all ports" echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" - echo -e "7. Set the time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "7. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "8. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" echo -e "9. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Switch to kernel parameter optimization in Linux system${gl_huang}Balanced optimization mode${gl_bai}" + echo -e "10. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" - read -e -p "Are you sure to have one-click maintenance? (Y/N):" choice + read -e -p "Are you sure you want one-click maintenance? (Y/N):" choice case "$choice" in [Yy]) clear - send_stats "One-stop tuning start" + send_stats "One-stop tuning starts" echo "------------------------------------------------" linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/10. Update the system to the latest" @@ -13552,12 +13593,12 @@ EOF echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. Install the basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Optimization of kernel parameters for Linux system" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux system kernel parameter optimization" echo -e "${gl_lv}One-stop system tuning has been completed${gl_bai}" ;; @@ -13591,7 +13632,7 @@ EOF echo "Privacy and security" echo "The script will collect data on users’ use of functions, optimize the script experience, and create more fun and useful functions." - echo "Will collect the script version number, usage time, system version, CPU architecture, country of the machine and the name of the functions used," + echo "The script version number, time of use, system version, CPU architecture, country of the machine and name of the function used will be collected," echo "------------------------------------------------" echo -e "Current status:$status_message" echo "--------------------" @@ -13634,7 +13675,7 @@ EOF echo "Uninstall tech lion script" echo "------------------------------------------------" echo "The kejilion script will be completely uninstalled without affecting your other functions." - read -e -p "Are you sure to continue? (Y/N):" choice + read -e -p "Are you sure you want to continue? (Y/N):" choice case "$choice" in [Yy]) @@ -13642,7 +13683,7 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "The script has been uninstalled, goodbye!" + echo "The script has been uninstalled, bye!" break_end clear exit @@ -13679,7 +13720,7 @@ EOF linux_file() { root_use - send_stats "File Manager" + send_stats "file manager" while true; do clear echo "file manager" @@ -13689,11 +13730,11 @@ linux_file() { echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. Enter the directory 2. Create the directory 3. Modify the directory permissions 4. Rename the directory" + echo "1. Enter the directory 2. Create the directory 3. Modify directory permissions 4. Rename the directory" echo "5. Delete the directory 6. Return to the previous menu directory" echo "------------------------" - echo "11. Create a file 12. Edit a file 13. Modify file permissions 14. Rename a file" - echo "15. Delete the file" + echo "11. Create files 12. Edit files 13. Modify file permissions 14. Rename files" + echo "15. Delete files" echo "------------------------" echo "21. Compress file directory 22. Unzip file directory 23. Move file directory 24. Copy file directory" echo "25. Transfer files to other servers" @@ -13705,7 +13746,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 read -e -p "Please enter the directory name:" dirname - cd "$dirname" 2>/dev/null || echo "Unable to enter the directory" + cd "$dirname" 2>/dev/null || echo "Unable to enter directory" send_stats "Enter directory" ;; 2) # 创建目录 @@ -13715,7 +13756,7 @@ linux_file() { ;; 3) # 修改目录权限 read -e -p "Please enter the directory name:" dirname - read -e -p "Please enter permissions (such as 755):" perm + read -e -p "Please enter permissions (e.g. 755):" perm chmod "$perm" "$dirname" && echo "Permissions have been modified" || echo "Modification failed" send_stats "Modify directory permissions" ;; @@ -13723,24 +13764,24 @@ linux_file() { read -e -p "Please enter the current directory name:" current_name read -e -p "Please enter a new directory name:" new_name mv "$current_name" "$new_name" && echo "Directory has been renamed" || echo "Rename failed" - send_stats "Rename the directory" + send_stats "Rename directory" ;; 5) # 删除目录 read -e -p "Please enter the directory name to be deleted:" dirname rm -rf "$dirname" && echo "Directory deleted" || echo "Delete failed" - send_stats "Delete Directory" + send_stats "delete directory" ;; 6) # 返回上一级选单目录 cd .. send_stats "Return to the previous menu directory" ;; 11) # 创建文件 - read -e -p "Please enter the file name to create:" filename + read -e -p "Please enter the file name to be created:" filename touch "$filename" && echo "File created" || echo "Creation failed" - send_stats "Create a file" + send_stats "Create file" ;; 12) # 编辑文件 - read -e -p "Please enter the file name to edit:" filename + read -e -p "Please enter the file name to be edited:" filename install nano nano "$filename" send_stats "Edit file" @@ -13754,12 +13795,12 @@ linux_file() { 14) # 重命名文件 read -e -p "Please enter the current file name:" current_name read -e -p "Please enter a new file name:" new_name - mv "$current_name" "$new_name" && echo "File renamed" || echo "Rename failed" + mv "$current_name" "$new_name" && echo "File has been renamed" || echo "Rename failed" send_stats "Rename file" ;; 15) # 删除文件 - read -e -p "Please enter the file name to delete:" filename - rm -f "$filename" && echo "File deleted" || echo "Deletion failed" + read -e -p "Please enter the file name to be deleted:" filename + rm -f "$filename" && echo "File deleted" || echo "Delete failed" send_stats "Delete files" ;; 21) # 压缩文件/目录 @@ -13769,7 +13810,7 @@ linux_file() { send_stats "Compressed files/directories" ;; 22) # 解压文件/目录 - read -e -p "Please enter the file name (.tar.gz):" filename + read -e -p "Please enter the file name to be extracted (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "Unzipped$filename" || echo "Decompression failed" send_stats "Unzip files/directories" @@ -13778,8 +13819,8 @@ linux_file() { 23) # 移动文件或目录 read -e -p "Please enter the file or directory path to be moved:" src_path if [ ! -e "$src_path" ]; then - echo "Error: The file or directory does not exist." - send_stats "Failed to move a file or directory: The file or directory does not exist" + echo "Error: File or directory does not exist." + send_stats "Failed to move file or directory: File or directory does not exist" continue fi @@ -13790,16 +13831,16 @@ linux_file() { continue fi - mv "$src_path" "$dest_path" && echo "The file or directory has been moved to$dest_path" || echo "Failed to move files or directories" - send_stats "Move files or directories" + mv "$src_path" "$dest_path" && echo "File or directory moved to$dest_path" || echo "Failed to move file or directory" + send_stats "Move a file or directory" ;; 24) # 复制文件目录 read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then - echo "Error: The file or directory does not exist." - send_stats "Failed to copy a file or directory: The file or directory does not exist" + echo "Error: File or directory does not exist." + send_stats "Copying file or directory failed: File or directory does not exist" continue fi @@ -13810,9 +13851,9 @@ linux_file() { continue fi - # Use the -r option to copy the directory recursively - cp -r "$src_path" "$dest_path" && echo "The file or directory has been copied to$dest_path" || echo "Failed to copy a file or directory" - send_stats "Copy files or directories" + # Use the -r option to copy directories recursively + cp -r "$src_path" "$dest_path" && echo "File or directory copied to$dest_path" || echo "Failed to copy file or directory" + send_stats "Copy a file or directory" ;; @@ -13868,7 +13909,7 @@ EOF 0) # 返回上一级选单 - send_stats "Return to the previous menu menu" + send_stats "Return to the previous menu" break ;; *) # 处理无效输入 @@ -13899,7 +13940,7 @@ run_commands_on_servers() { local SERVERS_FILE="$HOME/cluster/servers.py" local SERVERS=$(grep -oP '{"name": "\K[^"]+|"hostname": "\K[^"]+|"port": \K[^,]+|"username": "\K[^"]+|"password": "\K[^"]+' "$SERVERS_FILE") - # Convert extracted information into an array + # Convert the extracted information into an array IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" # Traverse the server and execute commands @@ -13937,22 +13978,22 @@ while true; do cat ~/cluster/servers.py echo echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}Server List Management${gl_bai}" - echo -e "${gl_kjlan}1. ${gl_bai}Add server${gl_kjlan}2. ${gl_bai}Delete server${gl_kjlan}3. ${gl_bai}Edit the server" + echo -e "${gl_kjlan}Server list management${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Add server${gl_kjlan}2. ${gl_bai}Delete server${gl_kjlan}3. ${gl_bai}Edit server" echo -e "${gl_kjlan}4. ${gl_bai}Backup cluster${gl_kjlan}5. ${gl_bai}Restore cluster" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}Install the tech lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" + echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom commands" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "Please enter your selection:" sub_choice + read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) - send_stats "Add a cluster server" + send_stats "Add cluster server" read -e -p "Server name:" server_name read -e -p "Server IP:" server_ip read -e -p "Server port (22):" server_port @@ -13965,12 +14006,12 @@ while true; do ;; 2) - send_stats "Delete the cluster server" - read -e -p "Please enter the keywords you need to delete:" rmserver + send_stats "Delete cluster server" + read -e -p "Please enter the keywords to be deleted:" rmserver sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) - send_stats "Edit the cluster server" + send_stats "Edit cluster server" install nano nano ~/cluster/servers.py ;; @@ -13978,15 +14019,15 @@ while true; do 4) clear send_stats "Backup cluster" - echo -e "Please${gl_huang}/root/cluster/servers.py${gl_bai}Download the file and complete the backup!" + echo -e "please change${gl_huang}/root/cluster/servers.py${gl_bai}Download the file and complete the backup!" break_end ;; 5) clear - send_stats "Restore the cluster" + send_stats "Restore cluster" echo "Please upload your servers.py and press any key to start uploading!" - echo -e "Please upload your${gl_huang}servers.py${gl_bai}file to${gl_huang}/root/cluster/${gl_bai}Complete the restore!" + echo -e "Please upload your${gl_huang}servers.py${gl_bai}file to${gl_huang}/root/cluster/${gl_bai}Restore completed!" break_end ;; @@ -14041,27 +14082,27 @@ echo "Advertising column" echo "------------------------" echo "It will provide users with a simpler and more elegant promotion and purchasing experience!" echo "" -echo -e "Server Offers" +echo -e "Server Discount" echo "------------------------" echo -e "${gl_lan}Laika Cloud Hong Kong CN2 GIA Korean dual ISP US CN2 GIA promotions${gl_bai}" echo -e "${gl_bai}Website: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd $10.99 per year, USA, 1 core, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" -echo -e "${gl_bai}Website: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" +echo -e "${gl_bai}URL: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" -echo -e "${gl_zi}Hostinger 52.7 dollars per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" +echo -e "${gl_zi}Hostinger $52.7 per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Brickworker, $49 per quarter, US CN2GIA, Japan SoftBank, 2 cores, 1G memory, 20G hard drive, 1T traffic per month${gl_bai}" +echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan SoftBank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT $28 per quarter US CN2GIA 1 core 2G memory 20G hard drive 800G traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS $6.9 per month Tokyo SoftBank 2 core 1G memory 20G hard drive 1T traffic per month${gl_bai}" +echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14104,7 +14145,7 @@ while true; do echo -e "${gl_lv}You are already on the latest version!${gl_huang}v$sh_v${gl_bai}" send_stats "The script is already up to date and does not need to be updated" else - echo "Discover a new version!" + echo "New version discovered!" echo -e "Current version v$sh_vlatest version${gl_huang}v$sh_v_new${gl_bai}" fi @@ -14114,15 +14155,15 @@ while true; do if [ -n "$existing_cron" ]; then echo "------------------------" - echo -e "${gl_lv}Automatic update is enabled, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" fi echo "------------------------" - echo "1. Update now 2. Turn on automatic update 3. Turn off automatic update" + echo "1. Update now 2. Turn on automatic updates 3. Turn off automatic updates" echo "------------------------" echo "0. Return to main menu" echo "------------------------" - read -e -p "Please enter your selection:" choice + read -e -p "Please enter your choice:" choice case "$choice" in 1) clear @@ -14158,14 +14199,14 @@ while true; do # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" - send_stats "Turn on automatic script update" + send_stats "Enable automatic script updates" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}Automatic update is closed${gl_bai}" - send_stats "Close script automatic update" + echo -e "${gl_lv}Automatic updates are turned off${gl_bai}" + send_stats "Turn off automatic script updates" break_end ;; *) @@ -14188,13 +14229,13 @@ echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" echo -e "Technology lion script toolbox v$sh_v" -echo -e "Command line input${gl_huang}k${gl_kjlan}Quickly start scripts${gl_bai}" +echo -e "Command line input${gl_huang}k${gl_kjlan}Quick start script${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}System information query" echo -e "${gl_kjlan}2. ${gl_bai}System update" -echo -e "${gl_kjlan}3. ${gl_bai}System Cleanup" +echo -e "${gl_kjlan}3. ${gl_bai}System cleanup" echo -e "${gl_kjlan}4. ${gl_bai}basic tools" -echo -e "${gl_kjlan}5. ${gl_bai}BBR Management" +echo -e "${gl_kjlan}5. ${gl_bai}BBR management" echo -e "${gl_kjlan}6. ${gl_bai}Docker management" echo -e "${gl_kjlan}7. ${gl_bai}WARP management" echo -e "${gl_kjlan}8. ${gl_bai}Test script collection" @@ -14212,7 +14253,7 @@ echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Exit script" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "Please enter your selection:" choice +read -e -p "Please enter your choice:" choice case $choice in 1) linux_info ;; @@ -14251,45 +14292,45 @@ echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" echo "Start script k" -echo "Install software package k install nano wget | k add nano wget | k Install nano wget" -echo "Uninstall the package k remove nano wget | k del nano wget | k uninstall nano wget | k Uninstall nano wget" +echo "Install packages k install nano wget | k add nano wget | k install nano wget" +echo "Uninstall a package k remove nano wget | k del nano wget | k uninstall nano wget | k uninstall nano wget" echo "Update system k update | k update" -echo "Clean system garbage k clean | k clean" +echo "Clean system junk k clean | k clean" echo "Reinstall the system panel k dd | k reinstall" echo "bbr3 control panel k bbr3 | k bbrv3" echo "Kernel Tuning Panel k nhyh | k Kernel Optimization" echo "Set virtual memory k swap 2048" echo "Set virtual time zone k time Asia/Shanghai | k time zone Asia/Shanghai" -echo "System Recycling Bin k trash | k hsz | k Recycling Bin" +echo "System Recycle Bin k trash | k hsz | k Recycle Bin" echo "System backup function k backup | k bf | k backup" echo "ssh remote connection tool k ssh | k remote connection" echo "rsync remote synchronization tool k rsync | k remote synchronization" echo "Hard disk management tool k disk | k hard disk management" echo "Intranet penetration (server) k frps" echo "Intranet penetration (client) k frpc" -echo "Software start k start sshd | k start sshd" +echo "Software startup k start sshd | k start sshd" echo "Software stop k stop sshd | k stop sshd" echo "Software restart k restart sshd | k restart sshd" echo "Check software status k status sshd | k status sshd" echo "k enable docker | k autostart docker | k enable docker when booting the software" echo "Domain name certificate application k ssl" -echo "Domain name certificate expiration query k ssl ps" +echo "Domain name certificate expiry query k ssl ps" echo "docker management plane k docker" echo "docker environment installation k docker install |k docker installation" echo "docker container management k docker ps |k docker container" echo "docker image management k docker img |k docker image" echo "LDNMP site management k web" -echo "LDNMP cache cleanup k web cache" -echo "Install WordPress k wp |k wordpress |k wp xxx.com" +echo "LDNMP cache cleaning k web cache" +echo "Install WordPress k wp | k wordpress | k wp xxx.com" echo "Install reverse proxy k fd |k rp |k reverse proxy |k fd xxx.com" echo "Install load balancing k loadbalance |k load balancing" -echo "Firewall panel k fhq |k firewall" -echo "Open port k dkdk 8080 |k Open port 8080" +echo "firewall panel k fhq |k firewall" +echo "open port k dkdk 8080 |k open port 8080" echo "Close port k gbdk 7800 |k Close port 7800" echo "Release IP k fxip 127.0.0.0/8 |k Release IP 127.0.0.0/8" echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" -echo "Command favorites k fav | k command favorites" -echo "App Market Management k app" +echo "command favorites k fav | k command favorites" +echo "Application market management k app" echo "Quick management of application numbers k app 26 | k app 1panel | k app npm" echo "Display system information k info" } @@ -14309,7 +14350,7 @@ else ;; remove|del|uninstall|卸载) shift - send_stats "Uninstall the software" + send_stats "Uninstall software" remove "$@" ;; update|更新) @@ -14343,7 +14384,7 @@ else rsync_run) shift - send_stats "Timed rsync synchronization" + send_stats "Scheduled rsync synchronization" run_task "$@" ;; @@ -14362,7 +14403,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ ports have been blocked from accessing the service" + echo "IP+port has been blocked from accessing the service" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14464,7 +14505,7 @@ else send_stats "Apply for a certificate quickly" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "Quickly apply for a certificate" + send_stats "Apply for a certificate quickly" else k_info fi diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a96968ff1..146f811f2 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -34,7 +34,7 @@ quanju_canshu -# コマンドを実行する関数を定義します +# コマンドを実行する関数を定義する run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -59,7 +59,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -114,9 +114,9 @@ CheckFirstRun_false() { # ユーザーに規約への同意を求めるプロンプトを表示する UserLicenseAgreement() { clear - echo -e "${gl_kjlan}Tech Lion Script Toolboxへようこそ${gl_bai}" + echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "上記の条件に同意しますか? (y/n):" user_input @@ -170,7 +170,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメーターは提供されていません!" + echo "パッケージパラメータが指定されていません!" return 1 fi @@ -204,7 +204,7 @@ install() { pkg update pkg install -y "$package" else - echo "不明なパッケージマネージャー!" + echo "不明なパッケージマネージャーです!" return 1 fi fi @@ -221,8 +221,8 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}ヒント:${gl_bai}ディスク容量が足りません!" - echo "現在の利用可能なスペース: $((available_space_mb/1024))G" - echo "最小需要スペース:${required_gb}G" + echo "現在利用可能なスペース: $((available_space_mb/1024))G" + echo "最低限必要なスペース:${required_gb}G" echo "インストールを続行できません。ディスク容量をクリアして、再試行してください。" send_stats "ディスク容量が足りない" break_end @@ -243,7 +243,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストール$package...${gl_bai}" + echo -e "${gl_huang}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -268,7 +268,7 @@ remove() { } -# さまざまな分布に適したUniversal SystemCTL関数 +# さまざまなディストリビューションに適したユニバーサル systemctl 関数 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -281,17 +281,17 @@ systemctl() { } -# サービスを再起動します +# サービスを再起動する restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1サービスは再開されました。" + echo "$1サービスが再開されました。" else - echo "エラー:再起動$1サービスが失敗しました。" + echo "エラー: 再起動$1サービスが失敗しました。" fi } -# サービスを開始します +# サービス開始 start() { systemctl start "$1" if [ $? -eq 0 ]; then @@ -305,19 +305,19 @@ start() { stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1サービスは停止しました。" + echo "$1サービスが停止されました。" else - echo "エラー: 停止$1サービスに失敗しました。" + echo "エラー: 停止$1サービスが失敗しました。" fi } -# サービスのステータスを確認します +# サービスステータスを確認する status() { systemctl status "$1" if [ $? -eq 0 ]; then echo "$1サービスのステータスが表示されます。" else - echo "エラー: 表示できません$1サービスステータス。" + echo "エラー: 表示できません$1サービスのステータス。" fi } @@ -330,7 +330,7 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME電源を入れるように設定します。" + echo "$SERVICE_NAME起動時に自動で起動するように設定してあります。" } @@ -427,7 +427,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker環境のインストール...${gl_bai}" + echo -e "${gl_huang}Docker 環境をインストールしています...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -508,17 +508,17 @@ while true; do echo "" echo "コンテナの運用" echo "------------------------" - echo "1.新しいコンテナを作成します" + echo "1. 新しいコンテナを作成する" echo "------------------------" - echo "2。指定されたコンテナを起動します。6。すべての容器を起動します" + echo "2. 指定したコンテナを起動します。 6. すべてのコンテナを起動します。" echo "3. 指定したコンテナを停止します。 7. すべてのコンテナを停止します。" - echo "4.指定されたコンテナ8を削除します。すべてのコンテナを削除します" - echo "5。指定されたコンテナを再起動9。すべてのコンテナを再起動します" + echo "4. 指定したコンテナを削除します。 8. すべてのコンテナを削除します。" + echo "5. 指定したコンテナを再起動します。 9. すべてのコンテナを再起動します。" echo "------------------------" - echo "11。指定されたコンテナを入力します12。コンテナログを表示します" - echo "13.コンテナネットワークを表示14。コンテナ占有を表示します" + echo "11. 指定したコンテナを入力します。 12. コンテナのログを表示します。" + echo "13. コンテナネットワークを確認します。 14. コンテナ占有率を確認します。" echo "------------------------" - echo "15.コンテナポートアクセスをオンにする16.コンテナポートアクセスをオフにする" + echo "15. コンテナ ポート アクセスを有効にする 16. コンテナ ポート アクセスを閉じる" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -536,7 +536,7 @@ while true; do ;; 3) send_stats "指定したコンテナを停止する" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + read -e -p "コンテナ名を入力してください (複数のコンテナ名はスペースで区切ってください):" dockername docker stop $dockername ;; 4) @@ -546,7 +546,7 @@ while true; do ;; 5) send_stats "指定したコンテナを再起動します" - read -e -p "コンテナ名(スペースで区切られた複数のコンテナ名)を入力してください。" dockername + read -e -p "コンテナ名を入力してください (複数のコンテナ名はスペースで区切ってください):" dockername docker restart $dockername ;; 6) @@ -558,7 +558,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "すべてのコンテナを削除します" + send_stats "すべてのコンテナを削除する" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -567,7 +567,7 @@ while true; do [Nn]) ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -577,13 +577,13 @@ while true; do ;; 11) send_stats "コンテナに入る" - read -e -p "コンテナ名を入力してください:" dockername + read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) send_stats "コンテナログの表示" - read -e -p "コンテナ名を入力してください:" dockername + read -e -p "コンテナ名を入力してください:" dockername docker logs $dockername break_end ;; @@ -612,8 +612,8 @@ while true; do ;; 15) - send_stats "コンテナポートアクセスを許可します" - read -e -p "コンテナ名を入力してください:" docker_name + send_stats "コンテナポートへのアクセスを許可する" + read -e -p "コンテナ名を入力してください:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -622,7 +622,7 @@ while true; do ;; 16) - send_stats "コンテナポートアクセスをブロックします" + send_stats "コンテナポートへのアクセスをブロックする" read -e -p "コンテナ名を入力してください:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" @@ -642,7 +642,7 @@ done docker_image() { while true; do clear - send_stats "Docker画像管理" + send_stats "Dockerイメージ管理" echo "Dockerイメージリスト" docker image ls echo "" @@ -656,15 +656,15 @@ while true; do read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "鏡を引っ張ります" - read -e -p "ミラー名を入力してください(スペースで複数のミラー名を分離してください):" imagenames + send_stats "イメージをプルする" + read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do echo -e "${gl_huang}画像の取得:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "画像を更新します" + send_stats "画像を更新" read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do echo -e "${gl_huang}画像の更新:$name${gl_bai}" @@ -761,7 +761,7 @@ install_crontab() { ;; esac else - echo "オペレーティングシステムを決定することはできません。" + echo "オペレーティング システムを特定できません。" return fi @@ -797,7 +797,7 @@ docker_ipv6_on() { # 元の構成と新しい構成を比較する if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}現在、IPv6アクセスが有効になっています${gl_bai}" + echo -e "${gl_huang}IPv6 アクセスは現在有効です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -812,28 +812,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 構成ファイルが存在するかどうかを確認します + # 設定ファイルが存在するかどうかを確認する if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}構成ファイルは存在しません${gl_bai}" + echo -e "${gl_hong}設定ファイルが存在しません${gl_bai}" return fi - # 現在の構成をお読みください + # 現在の構成を読み取る local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQを使用して、構成ファイルの更新を処理します + # jq を使用して構成ファイルの更新を処理する local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') # 現在のIPv6ステータスを確認する local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 元の構成と新しい構成を比較します + # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在閉じられています${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在停止中です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6アクセスは正常に閉じられています${gl_bai}" + echo -e "${gl_huang}IPv6 アクセスが正常に終了しました${gl_bai}" fi } @@ -872,7 +872,7 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "少なくとも 1 つのポート番号を入力してください" return 1 fi @@ -883,14 +883,14 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # オープンルールを追加します + # オープンルールを追加 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートが開かれました$port" + echo "ポートがオープンされました$port" fi done @@ -902,14 +902,14 @@ open_port() { close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "少なくとも1つのポート番号を提供してください" + echo "少なくとも 1 つのポート番号を入力してください" return 1 fi install iptables for port in "${ports[@]}"; do - # 既存のオープンルールを削除します + # 既存のオープンルールを削除する iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null @@ -928,7 +928,7 @@ close_port() { iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 最初に新しいルールを挿入します + # 最初のルールに新しいルールを挿入します iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT @@ -950,34 +950,34 @@ allow_ip() { # 既存のブロック ルールを削除する iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 許可ルールを追加します + # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IPをリリースしました$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "少なくとも1つのIPアドレスまたはIPセグメントを提供してください" + echo "少なくとも 1 つの IP アドレスまたは IP セグメントを入力してください" return 1 fi install iptables for ip in "${ips[@]}"; do - # 既存の許可ルールを削除します + # 既存の許可ルールを削除する iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # ブロッキングルールを追加します + # ブロックルールを追加する if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IPブロック$ip" + echo "IPがブロックされました$ip" fi done @@ -992,7 +992,7 @@ block_ip() { enable_ddos_defense() { - # 防御DDOをオンにします + # DDoS 保護を有効にする iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1007,7 +1007,7 @@ enable_ddos_defense() { # DDoS 防御をオフにする disable_ddos_defense() { - # 防御DDOをオフにします + # DDoS 保護をオフにする iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1086,7 +1086,7 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "正常に持ち上げられました$country_codeIPアドレスの制限" + echo "正常に削除されました$country_codeIPアドレス制限" ;; *) @@ -1118,25 +1118,25 @@ iptables_panel() { echo "" echo "ファイアウォール管理" echo "------------------------" - echo "1.指定されたポート2を開きます。指定されたポートを閉じます" - echo "3.すべてのポートを開きます。4。すべてのポートを閉じます" + echo "1. 指定されたポートをオープンします。 2. 指定されたポートを閉じます。" + echo "3. すべてのポートを開く 4. すべてのポートを閉じる" echo "------------------------" echo "5. IP ホワイトリスト 6. IP ブラックリスト" - echo "7.指定されたIPをクリアします" + echo "7. 指定したIPをクリアします" echo "------------------------" echo "11. PING を許可する 12. PING を無効にする" echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" - echo "15.ブロック指定された国IP16。指定された国のIPのみが許可されます" - echo "17.指定国でのIP制限をリリースします" + echo "15. 指定した国の IP をブロックする 16. 指定した国の IP のみを許可する" + echo "17. 指定国における知的財産制限を解除する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - read -e -p "オープンポート番号を入力してください:" o_port + read -e -p "開いているポート番号を入力してください:" o_port open_port $o_port send_stats "指定したポートを開く" ;; @@ -1159,7 +1159,7 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "すべてのポートを開きます" + send_stats "すべてのポートを開く" ;; 4) # すべてのポートを閉じます @@ -1180,7 +1180,7 @@ iptables_panel() { 5) # IPホワイトリスト - read -e -p "リリースするには、IPまたはIPセグメントを入力してください。" o_ip + read -e -p "許可された IP または IP セグメントを入力してください:" o_ip allow_ip $o_ip ;; 6) @@ -1194,17 +1194,17 @@ iptables_panel() { iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "指定されたIPをクリアします" + send_stats "指定したIPをクリア" ;; 11) - # pingを許可します + # PINGを許可する iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "pingを許可します" + send_stats "PINGを許可する" ;; 12) - # pingを無効にします + # PINGを無効にする iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1218,20 +1218,20 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; 16) read -e -p "許可されている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules allow $country_code - send_stats "国をブロックします$country_codeIP" + send_stats "ブロック国$country_codeIP" ;; 17) read -e -p "クリアされた国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules unblock $country_code - send_stats "国をきれいにします$country_codeIP" + send_stats "澄んだ国$country_codeIP" ;; *) @@ -1250,23 +1250,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 現在のシステムですべてのスワップパーティションを取得します + # 現在のシステム内のすべてのスワップ パーティションを取得します local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 反復して、すべてのスワップパーティションを削除します + # すべてのスワップ パーティションを走査して削除します for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfileが使用されなくなったことを確認してください + # /swapfile が使用されていないことを確認してください swapoff /swapfile - # 古い /swapfileを削除します + # 古い /swapfile を削除する rm -f /swapfile - # 新しいスワップパーティションを作成します + # 新しいスワップ パーティションを作成する fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1312,7 +1312,7 @@ ldnmp_v() { local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQLバージョンを取得します + # mysqlのバージョンを取得する local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" @@ -1343,11 +1343,11 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.ymlファイルをダウンロードして置き換えます + # docker-compose.yml ファイルをダウンロードして置き換えます wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.ymlファイルに置き換えます + # docker-compose.yml ファイル内で置き換えます sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1392,7 +1392,7 @@ install_ldnmp() { clear - echo "LDNMP環境がインストールされています" + echo "LDNMP環境がインストールされている" echo "------------------------" ldnmp_v @@ -1449,7 +1449,7 @@ install_ssltls_text() { echo -e "${gl_huang}$yuming公開鍵情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming秘密のキー情報${gl_bai}" + echo -e "${gl_huang}$yuming秘密鍵情報${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" echo -e "${gl_huang}証明書の保存パス${gl_bai}" @@ -1463,7 +1463,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL証明書をすばやく申請し、有効期限が切れる前に署名を自動的に更新します${gl_bai}" +echo -e "${gl_huang}SSL 証明書をすばやく申請し、有効期限が切れる前に自動的に更新します${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1479,8 +1479,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}適用された証明書の有効期限${gl_bai}" - echo "サイト情報証明書の有効期限" + echo -e "${gl_huang}適用された証明書の有効期限ステータス${gl_bai}" + echo "サイト情報 証明書の有効期限" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1524,14 +1524,14 @@ certs_status() { send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" - echo -e "2。DNS解像度の問題domainドメイン名がこのサーバーIPに対して正しく解決されたことを確認します" + echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" - echo -e "5.アプリケーションの数が制限を超えています➠暗号化を毎週制限(5回/ドメイン名/週)があります" + echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" break_end clear - echo "もう一度展開してみてください$webname" + echo "もう一度デプロイしてみてください$webname" add_yuming install_ssltls certs_status @@ -1551,8 +1551,8 @@ fi add_yuming() { ip_address - echo -e "最初にドメイン名をネイティブIPに解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "IPまたは解決されたドメイン名を入力してください:" yuming + echo -e "まず、ドメイン名をローカル IP に解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "IP または解決されたドメイン名を入力してください:" yuming } @@ -1616,7 +1616,7 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新します$ldnmp_pods" + send_stats "更新する$ldnmp_pods" echo "更新する${ldnmp_pods}仕上げる" } @@ -1636,8 +1636,8 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "ログイン情報:" - echo "ユーザー名:$dbuse" + echo "ログイン情報:" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo send_stats "起動する$ldnmp_pods" @@ -1650,19 +1650,19 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 構成ファイルが存在するかどうかを確認します + # 設定ファイルが存在するかどうかを確認する if [ -f "$CONFIG_FILE" ]; then # 構成ファイルから API_TOKEN とzone_idを読み取ります read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ゾーン_idsを配列に変換します + # ZONE_IDS を配列に変換する ZONE_IDS=($ZONE_IDS) else # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報が保存されます$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN - read -e -p "CFユーザ​​ー名を入力してください:" EMAIL + read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS mkdir -p /home/web/config/ @@ -1670,9 +1670,9 @@ cf_purge_cache() { fi fi - # 各ZONE_IDをループして、Clear Cacheコマンドを実行します + # 各zone_idをループし、キャッシュクリアコマンドを実行します。 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "ゾーン_idのキャッシュのクリア:$ZONE_ID" + echo "zone_id のキャッシュをクリアします:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1686,7 +1686,7 @@ cf_purge_cache() { web_cache() { - send_stats "サイトキャッシュをクリーンアップします" + send_stats "サイトキャッシュをクリアする" cf_purge_cache cd /home/web && docker compose restart restart_redis @@ -1712,12 +1712,12 @@ web_del() { rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # ドメイン名をデータベース名に変換します + # ドメイン名をデータベース名に変換する dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認してください。 - echo "データベースの削除:$dbname" + echo "データベースを削除しています:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1735,7 +1735,7 @@ nginx_waf() { # モードパラメータに従ってWAFをオンにするかオフにするかを決定します。 if [ "$mode" == "on" ]; then - # WAFをオンにしてください:コメントを削除します + # WAF をオンにする: コメントを削除する sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1745,11 +1745,11 @@ nginx_waf() { sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "無効な引数: 'on' または 'off' を使用してください" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # nginx イメージを確認し、それに応じて処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1828,7 +1828,7 @@ patch_wp_debug() { sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 「Happy Publishing」で行の前に新しい定義を挿入する + # 「Happy Publishing」を含む行の前に新しい定義を挿入します。 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1865,7 +1865,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる:コメントを追加します + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1881,11 +1881,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "無効な引数: 'on' または 'off' を使用してください" return 1 fi - # nginx画像を確認し、状況に応じてそれらを処理します + # nginx イメージを確認し、それに応じて処理します if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1907,7 +1907,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTDをオンにしてください:コメントを削除します + # Zstd をオンにする: コメントを削除する sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1922,7 +1922,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # ZSTDを閉じる:コメントを追加します + # Zstdを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1938,7 +1938,7 @@ nginx_zstd() { else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "無効な引数: 'on' または 'off' を使用してください" return 1 fi @@ -1969,7 +1969,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "無効なパラメーター:「オン」または「オフ」を使用します" + echo "無効な引数: 'on' または 'off' を使用してください" return 1 fi @@ -1989,16 +1989,16 @@ web_security() { check_waf_status check_cf_mode clear - echo -e "サーバーWebサイト防衛プログラム${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "サーバー Web サイト防御プログラム${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1.防衛プログラムをインストールします" + echo "1. 防御プログラムをインストールする" echo "------------------------" - echo "5。SSHインターセプトレコード6を表示6。ウェブサイト傍受記録を見る" + echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" - echo "21。CloudFlareモード22。5秒シールドの高負荷" + echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" echo "31. WAF をオンにする 32. WAF をオフにする" echo "33. DDOS 防御をオンにする 34. DDOS 防御をオフにする" @@ -2007,7 +2007,7 @@ web_security() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2072,7 +2072,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban 防御プログラムがアンインストールされました" break ;; @@ -2089,7 +2089,7 @@ web_security() { 21) send_stats "クラウドフレアモード" - echo "CF背景の右上隅に移動し、左側のAPIトークンを選択し、グローバルAPIキーを取得します" + echo "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択し、グローバル API キーを取得します。" echo "https://dash.cloudflare.com/login" read -e -p "CF の口座番号を入力してください:" cfuser read -e -p "CF のグローバル API キーを入力します。" cftoken @@ -2111,17 +2111,17 @@ web_security() { ;; 22) - send_stats "5秒シールドでの高負荷" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメーターを取得します:" - echo -e "CFバックグラウンドの右上隅に移動し、左側のAPIトークンを選択して、取得します${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CF の口座番号を入力してください:" cfuser - read -e -p "CFのグローバルAPIキーを入力してください。" cftoken - read -e -p "CFにドメイン名の領域IDを入力します。" cfzonID + read -e -p "CF のグローバル API キーを入力します。" cftoken + read -e -p "CF にドメイン名のゾーン ID を入力します。" cfzonID cd ~ install jq bc @@ -2138,7 +2138,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負荷自動シールドオープニングスクリプトが追加されました" + echo "高負荷自動シールド開放スクリプトを追加しました" else echo "自動シールド開放スクリプトはすでに存在するため、追加する必要はありません" fi @@ -2153,7 +2153,7 @@ web_security() { 32) nginx_waf off - echo "サイトWAFは閉鎖されています" + echo "サイト WAF がダウンしています" send_stats "サイト WAF がダウンしています" ;; @@ -2179,10 +2179,10 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 現在のworker_processesの設定値を取得します +# 現在のworker_processes設定値を取得します current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') -# 値に応じてモード情報を設定します +# 値に基づいてモード情報を設定します if [ "$current_value" = "8" ]; then mode_info=" 高性能模式" else @@ -2205,7 +2205,7 @@ check_nginx_compression() { zstd_status="" fi - # Brotliが有効になっており、コメントされていないかどうかを確認してください + # Brotli が有効になっていてコメントが解除されているかどうかを確認します if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status=" br压缩已开启" else @@ -2228,12 +2228,12 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP環境を最適化します" + send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" - echo "3。GZIP圧縮をオンにします4。GZIP圧縮をオフにします" + echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" echo "7. zstd 圧縮をオンにする 8. zstd 圧縮をオフにする" echo "------------------------" @@ -2248,7 +2248,7 @@ web_optimization() { sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf - # PHPチューニング + # PHPのチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini @@ -2284,7 +2284,7 @@ web_optimization() { 2) send_stats "サイトハイパフォーマンスモード" - # nginxチューニング + # nginxのチューニング sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf @@ -2306,7 +2306,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysqlチューニング + # mysqlのチューニング wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2378,7 +2378,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv} は ${gl_bai} をインストールしました" # else -# check_docker = "$ {gl_hui} $ {gl_bai}はインストールされていません" +# check_docker="${gl_hui} がインストールされていません ${gl_bai}" # fi # } @@ -2433,22 +2433,22 @@ check_docker_image_update() { local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # デフォルトのラベルは最新です + # デフォルトのタグはlatestです [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIから画像公開時間を取得します + # Docker Hub APIからイメージのリリース時刻を取得する local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 買収の時間を確認します + # 取得した時間を確認する if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) - # タイムスタンプを比較します + # タイムスタンプを比較する if [[ $container_created_ts -lt $last_updated_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" else @@ -2467,7 +2467,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # コンテナのIPアドレスを取得します + # コンテナのIPアドレスを取得する local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2477,12 +2477,12 @@ block_container_port() { install iptables - # 他のすべてのIPSを確認してブロックします + # 他のすべての IP をチェックしてブロックします if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPを確認してリリースします + # 指定したIPの確認と解放 if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2514,7 +2514,7 @@ block_container_port() { fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "IP+ポートはサービスへのアクセスをブロックされています" save_iptables_rules } @@ -2540,12 +2540,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 指定されたIPをリリースするためのルールをクリアします + # 指定したIPを許可するルールをクリアします if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワークをリリースするためのルールをクリア127.0.0.0/8 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2554,7 +2554,7 @@ clear_container_rules() { - # 他のすべてのIPをブロックするルールを明確にします + # 他のすべての IP をブロックする明確なルール if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi @@ -2564,7 +2564,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2597,7 +2597,7 @@ block_host_port() { install iptables - # 他のすべてのIPアクセスを拒否しました + # 他のすべての IP からのアクセスを拒否する if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -2607,7 +2607,7 @@ block_host_port() { iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # ローカルアクセスを許可します + # ローカルアクセスを許可する if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2621,7 +2621,7 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 指定されたIPアクセスを許可します + # 指定したIPへのアクセスを許可する if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2631,12 +2631,12 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 確立された関連接続および関連する接続のトラフィックを許可します + # 確立された接続と関連する接続のトラフィックを許可する if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "IP+ポートはサービスへのアクセスをブロックされています" save_iptables_rules } @@ -2648,7 +2648,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "エラー:アクセスを許可されているポート番号とIPを提供してください。" + echo "エラー: アクセスを許可するには、ポート番号と IP を入力してください。" echo "使用法: clear_host_port_rules <ポート番号> <許可された IP>" return 1 fi @@ -2661,12 +2661,12 @@ clear_host_port_rules() { iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # ローカルアクセスを許可する明確なルール if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 指定したIPからのアクセスを許可する明確なルール if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2677,18 +2677,18 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # ネイティブアクセスを可能にするルールを明確にします + # ローカルアクセスを許可する明確なルール if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 指定されたIPアクセスを許可するルールを明確にします + # 指定したIPからのアクセスを許可する明確なルール if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+ポートはサービスにアクセスすることが許可されています" + echo "IP+ポートによるサービスへのアクセスが許可されました" save_iptables_rules } @@ -2747,19 +2747,19 @@ while true; do fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. ドメイン名アクセスを追加します。 6. ドメイン名アクセスを削除します。" + echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーション外部サービスポートを入力し、デフォルトを入力します${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2771,7 +2771,7 @@ while true; do add_app_id clear - echo "$docker_nameインストール" + echo "$docker_nameインストール完了" check_docker_app_ip echo "" $docker_use @@ -2786,7 +2786,7 @@ while true; do add_app_id clear - echo "$docker_nameインストール" + echo "$docker_nameインストール完了" check_docker_app_ip echo "" $docker_use @@ -2805,15 +2805,15 @@ while true; do ;; 5) - echo "${docker_name}ドメインアクセス設定" - send_stats "${docker_name}ドメインアクセス設定" + echo "${docker_name}ドメイン名アクセス設定" + send_stats "${docker_name}ドメイン名アクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "ドメイン名の形式 example.com (https:// なし)" web_del ;; @@ -2860,14 +2860,14 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" - echo "5.ドメイン名アクセスを追加6。ドメイン名アクセスを削除する" - echo "7. IP+ポートアクセスを許可8。BlockIP+ポートアクセス" + echo "5. ドメイン名アクセスを追加します。 6. ドメイン名アクセスを削除します。" + echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) setup_docker_dir @@ -2902,15 +2902,15 @@ docker_app_plus() { block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "ドメイン名フォーマットexample.comにはhttps://が付属していません" + echo "ドメイン名の形式 example.com (https:// なし)" web_del ;; 7) - send_stats "IPアクセスを許可します${docker_name}" + send_stats "IPアクセスを許可する${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします${docker_name}" + send_stats "IPアクセスをブロックする${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -3005,7 +3005,7 @@ while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 新しいTMUXセッションを作成します +# 新しい tmux セッションを作成する tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3063,7 +3063,7 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "再起動" + echo "再起動しました" reboot ;; *) @@ -3110,8 +3110,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP環境を再度インストールできません" - echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイトの建設環境がインストールされています。再度インストールする必要はありません!" + send_stats "LDNMP環境を再インストールできません" + echo -e "${gl_huang}ヒント:${gl_bai}ウェブサイト構築環境を導入しました。再度インストールする必要はありません。" break_end linux_ldnmp fi @@ -3121,10 +3121,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP環境をインストールします" +send_stats "LDNMP環境をインストールする" root_use clear -echo -e "${gl_huang}LDNMP環境はインストールされていません。LDNMP環境のインストールを開始します...${gl_bai}" +echo -e "${gl_huang}LDNMP環境がインストールされていません。 LDNMP 環境のインストールを開始します...${gl_bai}" check_disk_space 3 /home check_port install_dependency @@ -3153,7 +3153,7 @@ clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo "nginxがインストールされました" -echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" +echo -e "現在のバージョン:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3164,7 +3164,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "LDNMP環境を最初にインストールしてください" + send_stats "最初に LDNMP 環境をインストールしてください" ldnmp_install_all fi @@ -3174,7 +3174,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "最初にNGINX環境をインストールしてください" + send_stats "まずnginx環境をインストールしてください" nginx_install_all fi @@ -3194,7 +3194,7 @@ ldnmp_web_on() { nginx_web_on() { clear - echo "あなたの$webname建てられた!" + echo "あなたの$webname建てられました!" echo "https://$yuming" } @@ -3207,7 +3207,7 @@ ldnmp_wp() { webname="WordPress" yuming="${1:-}" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3248,7 +3248,7 @@ ldnmp_Proxy() { port="${3:-}" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3257,7 +3257,7 @@ ldnmp_Proxy() { fi if [ -z "$port" ]; then - read -e -p "発生防止ポートを入力してください。" port + read -e -p "アンチジェネレーションポートを入力してください:" port fi nginx_install_status install_ssltls @@ -3287,7 +3287,7 @@ ldnmp_Proxy_backend() { fi if [ -z "$reverseproxy_port" ]; then - read -e -p "スペースで区切られた複数の生成防止IP+ポートを入力してください(たとえば、127.0.0.1:3000 127.0.1:3002):" reverseproxy_port + read -e -p "複数のアンチジェネレーション IP + ポートをスペースで区切って入力してください (例: 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3358,7 +3358,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "データベース:${db_output}" + echo -e "データベース:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -3370,23 +3370,23 @@ ldnmp_web_status() { echo -e "データ${gl_hui}/home/web/html${gl_bai}証明書${gl_hui}/home/web/certs${gl_bai}構成${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "動作します" + echo "操作する" echo "------------------------" - echo "1.ドメイン名証明書を適用/更新する2。サイトドメイン名を変更します" - echo "3.サイトキャッシュをクリーンアップ4。関連するサイトを作成する" + echo "1. ドメイン名証明書の適用/更新 2. サイトのドメイン名の複製" + echo "3. サイトのキャッシュをクリアします。 4. 関連するサイトを作成します。" echo "5. アクセスログの表示 6. エラーログの表示" echo "7. グローバル構成の編集 8. サイト構成の編集" - echo "9.サイトデータベースの管理10。サイト分析レポートを表示します" + echo "9. サイトデータベースの管理 10. サイト分析レポートの表示" echo "------------------------" echo "20. 指定したサイトデータを削除する" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "ドメイン名証明書を申請します" - read -e -p "ドメイン名を入力してください:" yuming + send_stats "ドメイン名証明書を申請する" + read -e -p "ドメイン名を入力してください:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3395,10 +3395,9 @@ ldnmp_web_status() { ;; 2) - send_stats "サイトのドメイン名を変更する" - echo -e "${gl_hong}強くお勧めします:${gl_bai}まずサイト全体のデータをバックアップしてから、サイトのドメイン名を変更してください。" - read -e -p "古いドメイン名を入力してください:" oddyuming - read -e -p "新しいドメイン名を入力してください:" yuming + send_stats "クローンサイトのドメイン名" + read -e -p "古いドメイン名を入力してください:" oddyuming + read -e -p "新しいドメイン名を入力してください:" yuming install_certbot install_ssltls certs_status @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3421,19 +3420,19 @@ ldnmp_web_status() { done done - # ウェブサイトディレクトリの交換 - mv /home/web/html/$oddyuming /home/web/html/$yuming + # Web サイトのディレクトリの置き換え + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; @@ -3442,8 +3441,8 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "関連するサイトを作成します" - echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスします" + send_stats "関連サイトの作成" + echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスする" read -e -p "既存のドメイン名を入力してください:" oddyuming read -e -p "新しいドメイン名を入力してください:" yuming install_certbot @@ -3459,17 +3458,17 @@ ldnmp_web_status() { ;; 5) - send_stats "アクセスログを表示します" + send_stats "アクセスログを見る" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "エラーログを表示します" + send_stats "エラーログを表示する" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "グローバル構成を編集します" + send_stats "グローバル構成の編集" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload @@ -3477,7 +3476,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3554,7 +3553,7 @@ while true; do panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}アンインストール" + send_stats "${panelname}アンインストールする" ;; *) break @@ -3623,14 +3622,14 @@ EOF # 生成された情報を出力する ip_address echo "------------------------" - echo "クライアントの展開に必要なパラメーター" - echo "サービスIP:$ipv4_address" + echo "クライアントの展開に必要なパラメータ" + echo "サービスIP:$ipv4_address" echo "token: $token" echo echo "FRPパネル情報" echo "FRPパネルアドレス:http://$ipv4_address:$dashboard_port" - echo "FRPパネルのユーザー名:$dashboard_user" - echo "FRPパネルパスワード:$dashboard_pwd" + echo "FRP パネルのユーザー名:$dashboard_user" + echo "FRPパネルのパスワード:$dashboard_pwd" echo open_port 8055 8056 @@ -3640,7 +3639,7 @@ EOF configure_frpc() { - send_stats "FRPクライアントをインストールします" + send_stats "FRPクライアントをインストールする" read -e -p "外部ネットワークのドッキング IP を入力してください:" server_addr read -e -p "外部ネットワーク ドッキング トークンを入力してください:" token echo @@ -3663,8 +3662,8 @@ EOF add_forwarding_service() { send_stats "FRPイントラネットサービスを追加" - # ユーザーにサービス名と転送情報を入力するように促します - read -e -p "サービス名を入力してください:" service_name + # ユーザーにサービス名と転送情報の入力を求めるプロンプトを表示します + read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip @@ -3694,12 +3693,12 @@ EOF delete_forwarding_service() { - send_stats "FRPイントラネットサービスを削除します" - # ユーザーに削除する必要があるサービス名を入力するように促します + send_stats "FRPイントラネットサービスの削除" + # 削除する必要があるサービスの名前を入力するようにユーザーに求めます read -e -p "削除するサービス名を入力してください:" service_name - # SEDを使用して、サービスとその関連構成を削除します + # sed を使用してサービスとその関連構成を削除します sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "仕える$service_nameFRPC.TOMLから削除されました" + echo "仕える$service_namefrpc.toml から正常に削除されました" docker restart frpc @@ -3743,7 +3742,7 @@ list_forwarding_services() { if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 前の値をクリアします + # 前回の値をクリア local_ip="" local_port="" remote_port="" @@ -3772,7 +3771,7 @@ list_forwarding_services() { } END { - # 最後のサービスの情報を印刷します + # 最後のサービスに関する情報を出力します if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3792,7 +3791,7 @@ get_frp_ports() { # アクセスアドレスの生成 generate_access_urls() { - # 最初にすべてのポートを取得します + # まずすべてのポートを取得します get_frp_ports # 8055/8056以外のポートがあるか確認する @@ -3815,7 +3814,7 @@ generate_access_urls() { fi done - # IPv6アドレスを処理する(存在する場合) + # IPv6 アドレスが存在する場合は処理します if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3824,7 +3823,7 @@ generate_access_urls() { done fi - # HTTPS構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -3861,7 +3860,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRPサーバー$check_frp $update_status" echo "FRPイントラネットペネトレーションサービス環境を構築し、パブリックIPを持たないデバイスをインターネットに公開" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" + echo "公式サイト紹介:https://github.com/fatedier/frp/" echo "ビデオチュートリアル: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -3869,7 +3868,7 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" echo "5. イントラネット サービスのドメイン名アクセス 6. ドメイン名アクセスの削除" echo "------------------------" @@ -3877,7 +3876,7 @@ frps_panel() { echo "------------------------" echo "00. サービスステータスを更新します。 0. 前のメニューに戻ります。" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) install jq grep ss @@ -3885,7 +3884,7 @@ frps_panel() { generate_frps_config add_app_id - echo "FRPサーバーがインストールされています" + echo "FRPサーバーを導入しました" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3895,7 +3894,7 @@ frps_panel() { donlond_frp frps add_app_id - echo "FRPサーバーが更新されました" + echo "FRPサーバーを更新しました" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -3910,9 +3909,9 @@ frps_panel() { ;; 5) echo "ドメイン名アクセスへのイントラネット侵入サービスのリバース" - send_stats "FRP外部ドメイン名へのアクセス" + send_stats "FRP 外部ドメイン名アクセス" add_yuming - read -e -p "イントラネット侵入サービスポートを入力してください:" frps_port + read -e -p "イントラネット侵入サービス ポートを入力してください:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; @@ -3922,21 +3921,21 @@ frps_panel() { ;; 7) - send_stats "IPアクセスを許可します" - read -e -p "リリースするポートを入力してください:" frps_port + send_stats "IPアクセスを許可する" + read -e -p "解放する必要があるポートを入力してください:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IPアクセスをブロックします" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" - read -e -p "ブロックする必要があるポートを入力してください。" frps_port + send_stats "IPアクセスをブロックする" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRPサービスステータスを更新します" - echo "FRPサービスステータスは更新されました" + send_stats "FRPサービスステータスを更新" + echo "FRPサービスステータスが更新されました" ;; *) @@ -3959,8 +3958,8 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRPクライアント$check_frp $update_status" echo "サーバーに接続します。接続後、インターネットにアクセスするためのイントラネット侵入サービスを作成できます。" - echo "公式ウェブサイトの紹介:https://github.com/fatedier/frp/" - echo "ビデオ教育:https://www.bilibili.com/video/bv1ymw6e2ewl?t=173.9" + echo "公式サイト紹介:https://github.com/fatedier/frp/" + echo "ビデオチュートリアル: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -3970,7 +3969,7 @@ frpc_panel() { echo "------------------------" echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" - echo "4.外部サービスの追加5.外部サービスを削除6。サービスを手動で構成する" + echo "4. 外部サービスの追加 5. 外部サービスの削除 6. サービスの手動構成" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4003,7 +4002,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" ;; 4) @@ -4054,36 +4053,36 @@ yt_menu_pro() { echo -e "yt-dlp は、YouTube、Bilibili、Twitter などの何千ものサイトをサポートする強力な動画ダウンロード ツールです。" echo -e "公式サイトアドレス:https://github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "ダウンロードされたビデオリスト:" + echo "ダウンロードしたビデオのリスト:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" echo "-------------------------" - echo "1。インストール2。更新3。アンインストール" + echo "1. インストール 2. アップデート 3. アンインストール" echo "-------------------------" echo "5. 単一ビデオのダウンロード 6. バッチビデオのダウンロード 7. カスタムパラメータのダウンロード" echo "8. MP3 オーディオとしてダウンロード 9. ビデオ ディレクトリを削除 10. Cookie 管理 (開発中)" echo "-------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "-------------------------" read -e -p "オプション番号を入力してください:" choice case $choice in 1) send_stats "yt-dlp をインストールしています..." - echo "YT-DLPのインストール..." + echo "yt-dlp をインストールしています..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id - echo "インストールが完了しました。任意のキーを押して続行します..." + echo "インストールが完了しました。続行するには任意のキーを押してください..." read ;; 2) - send_stats "yt-dlpを更新..." - echo "yt-dlpを更新..." + send_stats "yt-dlp を更新しています..." + echo "yt-dlp を更新しています..." yt-dlp -U add_app_id - echo "更新が完了しました。任意のキーを押して続行します..." + echo "アップデートが完了しました。続行するには任意のキーを押してください..." read ;; 3) send_stats "yt-dlp をアンインストールしています..." @@ -4091,18 +4090,18 @@ yt_menu_pro() { rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アンインストールが完了しました。任意のキーを押して続行します..." + echo "アンインストールが完了しました。続行するには任意のキーを押してください..." read ;; 5) send_stats "単一のビデオのダウンロード" - read -e -p "ビデオリンクを入力してください:" url + read -e -p "ビデオリンクを入力してください:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "ダウンロードが完了したら、任意のキーを押して続行します..." ;; + read -e -p "ダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 6) send_stats "ビデオのバッチダウンロード" install nano @@ -4121,7 +4120,7 @@ yt_menu_pro() { read -e -p "バッチダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 7) send_stats "カスタムビデオのダウンロード" - read -e -p "完全なYT-DLPパラメーター(YT-DLPを除く)を入力してください。" custom + read -e -p "完全な yt-dlp パラメータを入力してください (yt-dlp を除く)。" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4141,7 +4140,7 @@ yt_menu_pro() { read -e -p "音声のダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 9) - send_stats "ビデオを削除します" + send_stats "ビデオを削除する" read -e -p "削除されたビデオの名前を入力してください:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; @@ -4187,7 +4186,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}システムの更新...${gl_bai}" + echo -e "${gl_huang}システムアップデート中です...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4245,7 +4244,7 @@ linux_clean() { elif command -v apk &>/dev/null; then echo "パッケージマネージャーのキャッシュをクリーンアップ..." apk cache clean - echo "システムログを削除してください..." + echo "システムログを削除します..." rm -rf /var/log/* echo "APKキャッシュを削除..." rm -rf /var/cache/apk/* @@ -4277,7 +4276,7 @@ linux_clean() { pkg autoremove -y echo "パッケージマネージャーのキャッシュをクリーンアップ..." pkg clean -y - echo "システムログを削除してください..." + echo "システムログを削除します..." rm -rf /var/log/* echo "一時ファイルを削除します..." rm -rf /tmp/* @@ -4327,19 +4326,19 @@ chattr +i /etc/resolv.conf set_dns_ui() { root_use -send_stats "DNSを最適化します" +send_stats "DNSの最適化" while true; do clear - echo "DNSアドレスを最適化します" + echo "DNSアドレスを最適化する" echo "------------------------" echo "現在のDNSアドレス" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1。外国DNS最適化:" + echo "1. 外部 DNS の最適化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2。国内のDNS最適化:" + echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" echo "3. DNS 設定を手動で編集する" @@ -4354,7 +4353,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "外国のDNS最適化" + send_stats "外部DNSの最適化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4362,7 +4361,7 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内のDNS最適化" + send_stats "国内DNS最適化" ;; 3) install nano @@ -4417,7 +4416,7 @@ correct_ssh_config() { new_ssh_port() { - # バックアップSSH構成ファイル + # SSH設定ファイルをバックアップする cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config @@ -4448,7 +4447,7 @@ add_sshkey() { chmod 600 ~/.ssh/authorized_keys ip_address - echo -e "秘密のキー情報が生成されました。必ずコピーして保存してください。${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" + echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" echo "--------------------------------" cat ~/.ssh/sshkey @@ -4460,14 +4459,14 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ルートプライベートキーログインが有効になり、ルートパスワードログインが閉じられ、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" } import_sshkey() { - read -e -p "SSH公開キーの内容を入力してください(通常は「SSH-RSA」または「SSH-ED25519」から始まります):" public_key + read -e -p "SSH 公開キーの内容を入力してください (通常は「ssh-rsa」または「ssh-ed25519」で始まります):" public_key if [[ -z "$public_key" ]]; then echo -e "${gl_hong}エラー: 公開キーの内容が入力されていません。${gl_bai}" @@ -4497,20 +4496,20 @@ import_sshkey() { add_sshpasswd() { -echo "ルートパスワードを設定します" +echo "ROOTパスワードを設定する" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -4527,7 +4526,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}初期パスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}初期パスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install wget @@ -4535,7 +4534,7 @@ dd_xitong() { } dd_xitong_2() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}初期パスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}初期パスワード:${gl_huang}Teddysun.com${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install wget @@ -4543,15 +4542,15 @@ dd_xitong() { } dd_xitong_3() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}初期パスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}最初のパスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" - echo -e "任意のキーを押して続行します..." + echo -e "再インストール後の初期ユーザー名:${gl_huang}Administrator${gl_bai}初期パスワード:${gl_huang}123@@@${gl_bai}初期ポート:${gl_huang}3389${gl_bai}" + echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" dd_xitong_bin456789 } @@ -4560,8 +4559,8 @@ dd_xitong() { root_use echo "システムを再インストールする" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - echo -e "${gl_hui}LeitbogioroとBin456789のスクリプトサポートのおかげです!${gl_bai} " + echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" + echo -e "${gl_hui}スクリプトをサポートしてくれたボス leitbogioro とボス bin456789 に感謝します。${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -4577,7 +4576,7 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35。OpenSuseTumbleWeed36。FNOSFEINIU PUBLIC BETAバージョン" + echo "35. openSUSE Tumbleweed 36. fnos Feiniu パブリックベータ版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" @@ -4586,7 +4585,7 @@ dd_xitong() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "再インストールするシステムを選択してください:" sys_choice + read -e -p "再インストールするシステムを選択してください:" sys_choice case "$sys_choice" in @@ -4620,7 +4619,7 @@ dd_xitong() { exit ;; 11) - send_stats "Ubuntu 24.04を再インストールします" + send_stats "ubuntu 24.04を再インストールします" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot @@ -4666,7 +4665,7 @@ dd_xitong() { ;; 23) - send_stats "alma10を再インストールします" + send_stats "alma10を再インストールする" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4714,7 +4713,7 @@ dd_xitong() { ;; 29) - send_stats "CENTOS10を再インストールします" + send_stats "centos10を再インストールする" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4722,7 +4721,7 @@ dd_xitong() { ;; 30) - send_stats "CENTOS9を再インストールします" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -4738,7 +4737,7 @@ dd_xitong() { ;; 32) - send_stats "アーチを再インストールします" + send_stats "アーチを再インストールする" dd_xitong_3 bash reinstall.sh arch reboot @@ -4754,7 +4753,7 @@ dd_xitong() { ;; 34) - send_stats "Openeulerを再インストールします" + send_stats "オープニューラーを再インストールする" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4802,7 +4801,7 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 25を再インストールします" + send_stats "Windowsサーバー25を再インストールします" dd_xitong_2 bash InstallNET.sh -windows 2025 -lang "cn" reboot @@ -4826,7 +4825,7 @@ dd_xitong() { ;; 47) - send_stats "Windows11アームを再インストールします" + send_stats "Windows11 ARMを再インストールする" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -4843,7 +4842,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3管理" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4856,17 +4855,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "XanmodのBBRV3カーネルをインストールしました" - echo "現在のカーネルバージョン:$kernel_version" + echo "xanmod の BBRv3 カーネルがインストールされている" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" echo "------------------------" - echo "1。BBRV3カーネルを更新します2。BBRV3カーネルをアンインストールします" + echo "1. BBRv3 カーネルを更新します。 2. BBRv3 カーネルをアンインストールします。" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -4895,7 +4894,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "Xanmodカーネルはアンインストールされています。再起動後に有効になります" + echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" server_reboot ;; @@ -4911,7 +4910,7 @@ bbrv3() { echo "BBR3アクセラレーションの設定" echo "ビデオ紹介: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "Debian/Ubuntuのみをサポートします" + echo "Debian/Ubuntu のみをサポートします" echo "データをバックアップしてください。Linux カーネルをアップグレードして BBR3 を有効にします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -4949,7 +4948,7 @@ bbrv3() { bbr_on - echo "Xanmodカーネルがインストールされ、BBR3が正常に有効になります。再起動後に有効になります" + echo "XanMod カーネルがインストールされ、BBR3 が正常に有効になります。再起動後に有効になります" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4959,7 +4958,7 @@ bbrv3() { echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac fi @@ -4969,28 +4968,28 @@ bbrv3() { elrepo_install() { # ELRepo GPG 公開キーをインポートする - echo "Elrepo GPG公開キーをインポートしてください..." + echo "ELRepo GPG 公開キーをインポートします..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # システムバージョンを検出します + # システムバージョンを確認する local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # サポートされているオペレーティングシステムで実行されていることを確認してください + # サポートされているオペレーティング システムで実行されていることを確認してください if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "サポートされていないオペレーティング システム:$os_name" break_end linux_Settings fi - # 検出されたオペレーティングシステム情報を印刷します - echo "検出されたオペレーティングシステム:$os_name $os_version" - # システムバージョンに応じて、対応するElrepo Warehouse構成をインストールする + # 検出されたオペレーティング システム情報を印刷する + echo "検出されたオペレーティング システム:$os_name $os_version" + # システムのバージョンに応じて、対応する ELRepo ウェアハウス構成をインストールします。 if [[ "$os_version" == 8 ]]; then - echo "Elrepoリポジトリ構成(バージョン8)をインストールしてください..." + echo "ELRepo リポジトリ構成 (バージョン 8) をインストールしています..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Elrepoリポジトリ構成(バージョン9)をインストールしてください..." + echo "ELRepo リポジトリ構成 (バージョン 9) をインストールしています..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepoリポジトリ構成(バージョン10)をインストールしてください..." + echo "ELRepo リポジトリ構成 (バージョン 10) をインストールしています..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else echo "サポートされていないシステム バージョン:$os_version" @@ -5001,7 +5000,7 @@ elrepo_install() { echo "ELRepo カーネル リポジトリを有効にし、最新のメインライン カーネルをインストールします..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "Elrepoリポジトリ構成がインストールされ、最新のメインラインカーネルに更新されます。" + echo "ELRepo リポジトリ構成をインストールし、最新のメインライン カーネルに更新しました。" server_reboot } @@ -5009,12 +5008,12 @@ elrepo_install() { elrepo() { root_use - send_stats "レッドハットカーネル管理" + send_stats "Red Hat カーネル管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo Kernelをインストールしました" + echo "elrepo カーネルがインストールされています" echo "現在のカーネル バージョン:$kernel_version" echo "" @@ -5024,7 +5023,7 @@ elrepo() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -5038,8 +5037,8 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepoカーネルはアンインストールされています。再起動後に有効になります" - send_stats "レッドハットカーネルをアンインストールします" + echo "elrepo カーネルがアンインストールされました。再起動後に有効になります" + send_stats "Red Hat カーネルをアンインストールする" server_reboot ;; @@ -5055,8 +5054,8 @@ elrepo() { echo "データをバックアップしてください。Linux カーネルをアップグレードします。" echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "レッドハットシリーズの分布のみをサポートしますCentos/Redhat/Alma/Rocky/Oracle" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5096,7 +5095,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}スキャンディレクトリ$@...${gl_bai}" + echo -e "${gl_huang}ディレクトリ $@ をスキャンしています...${gl_bai}" # ビルドマウントパラメータ local MOUNT_PARAMS="" @@ -5104,7 +5103,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # CLAMSCANコマンドパラメーターを作成します + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5122,8 +5121,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@スキャンが完了し、ウイルスレポートが保存されます${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}ウイルスがある場合は、お願いします${gl_huang}scan.log${gl_lv}ファイル内で FOUND キーワードを検索して、ウイルスの場所を確認します。${gl_bai}" + echo -e "${gl_lv}$@ スキャンが完了し、ウイルス レポートが保存されます。${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}ウイルスがある場合はお願いします${gl_huang}scan.log${gl_lv}ファイル内で FOUND キーワードを検索して、ウイルスの場所を確認します。${gl_bai}" } @@ -5139,19 +5138,19 @@ clamav() { while true; do clear echo "Clamav ウイルス スキャン ツール" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1tqvze4eqm?t=0.1" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "これは、主にさまざまな種類のマルウェアを検出して削除するために使用されるオープンソースのウイルス対策ソフトウェア ツールです。" echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアが含まれます。" echo "------------------------" - echo -e "${gl_lv}1。フルディスクスキャン${gl_bai} ${gl_huang}2.重要なディレクトリをスキャンします${gl_bai} ${gl_kjlan}3. カスタムディレクトリスキャン${gl_bai}" + echo -e "${gl_lv}1.フルスキャン${gl_bai} ${gl_huang}2. 重要なディレクトリをスキャンする${gl_bai} ${gl_kjlan}3. カスタムディレクトリスキャン${gl_bai}" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "フルディスクスキャン" + send_stats "フルスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5160,7 +5159,7 @@ clamav() { ;; 2) - send_stats "重要なディレクトリスキャン" + send_stats "重要なディレクトリのスキャン" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5186,9 +5185,9 @@ clamav() { -# 高性能モード最適化関数 +# ハイパフォーマンスモード最適化機能 optimize_high_performance() { - echo -e "${gl_lv}に切り替えます${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}に切り替える${tiaoyou_moshi}...${gl_bai}" echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" ulimit -n 65535 @@ -5221,13 +5220,13 @@ optimize_high_performance() { echo -e "${gl_lv}その他の最適化...${gl_bai}" # 透明な巨大ページを無効にして遅延を軽減する echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # NUMA バランシングを無効にする sysctl -w kernel.numa_balancing=0 2>/dev/null } -# イコライゼーションモード最適化関数 +# バランスモード最適化機能 optimize_balanced() { echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" @@ -5260,17 +5259,17 @@ optimize_balanced() { sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明なページを復元します + # 透明な巨大ページを復元する echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # NUMA バランスを復元する sysctl -w kernel.numa_balancing=1 2>/dev/null } -# デフォルト設定関数を復元します +# デフォルト設定に戻す機能 restore_defaults() { - echo -e "${gl_lv}デフォルト設定に復元します...${gl_bai}" + echo -e "${gl_lv}デフォルト設定に戻す...${gl_bai}" echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" ulimit -n 1024 @@ -5282,7 +5281,7 @@ restore_defaults() { sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}ネットワーク設定を復元します...${gl_bai}" + echo -e "${gl_lv}ネットワーク設定をリセットします...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5303,7 +5302,7 @@ restore_defaults() { echo -e "${gl_lv}他の最適化を元に戻します...${gl_bai}" # 透明な巨大ページを復元する echo always > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを復元します + # NUMA バランスを復元する sysctl -w kernel.numa_balancing=1 2>/dev/null } @@ -5345,7 +5344,7 @@ optimize_web_server() { echo -e "${gl_lv}その他の最適化...${gl_bai}" # 透明な巨大ページを無効にして遅延を軽減する echo never > /sys/kernel/mm/transparent_hugepage/enabled - # numaバランスを無効にします + # NUMA バランシングを無効にする sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5357,29 +5356,29 @@ Kernel_optimize() { while true; do clear send_stats "Linuxカーネルチューニング管理" - echo "Linuxシステムにおけるカーネルパラメーターの最適化" + echo "Linuxシステムのカーネルパラメータの最適化" echo "ビデオ紹介: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "さまざまなシステムパラメータチューニングモードを提供し、ユーザーは独自の使用シナリオに応じて切り替えることができます。" echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2。バランスの取れた最適化モード:毎日の使用に適したパフォーマンスとリソース消費のバランス。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" - echo "5。ゲームサーバーの最適化モード:ゲームサーバーを最適化して、同時処理機能と応答速度を改善します。" + echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" echo "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "--------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) cd ~ clear local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "高性能モードの最適化" + send_stats "ハイパフォーマンスモードの最適化" ;; 2) cd ~ @@ -5391,14 +5390,14 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイトの最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ clear local tiaoyou_moshi="直播优化模式" optimize_high_performance - send_stats "ライブストリーミング最適化" + send_stats "ライブストリーミングの最適化" ;; 5) cd ~ @@ -5438,7 +5437,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}システム言語は次のように変更されています。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されました。$lang有効にするには、SSH に再接続します。${gl_bai}" hash -r break_end @@ -5447,12 +5446,12 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}システム言語は次のように変更されました。$langSSHの再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}システム言語は次のように変更されました。$lang有効にするには、SSH に再接続します。${gl_bai}" hash -r break_end ;; *) - echo "サポートされていないシステム:$ID" + echo "サポートされていないシステム:$ID" break_end ;; esac @@ -5467,16 +5466,16 @@ update_locale() { linux_language() { root_use -send_stats "システム言語を切り替えます" +send_stats "システム言語を切り替える" while true; do clear - echo "現在のシステム言語:$LANG" + echo "現在のシステム言語:$LANG" echo "------------------------" echo "1. 英語 2. 簡体字中国語 3. 繁体字中国語" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -5511,7 +5510,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}変更が完了します。 SSHを再接続して変更を表示します!${gl_bai}" +echo -e "${gl_lv}変更が完了しました。 SSH に再接続して変更を確認してください。${gl_bai}" hash -r break_end @@ -5522,7 +5521,7 @@ break_end shell_bianse() { root_use - send_stats "コマンドラインの美化ツール" + send_stats "コマンドライン美化ツール" while true; do clear echo "コマンドライン美化ツール" @@ -5535,9 +5534,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -5582,7 +5581,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "システムリサイクルステーション" + send_stats "システムのごみ箱" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -5597,13 +5596,13 @@ linux_trash() { fi clear - echo -e "現在のリサイクルビン${trash_status}" + echo -e "現在のごみ箱${trash_status}" echo -e "有効にすると、重要なファイルを誤って削除することを防ぐために、rm によって削除されたファイルは最初にごみ箱に入れられます。" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "リサイクルビンは空です" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "ごみ箱が空です" echo "------------------------" - echo "1.リサイクルビン2を有効にします。リサイクルビンを閉じます" - echo "3。コンテンツを復元4。リサイクルビンをクリアします" + echo "1. ごみ箱を有効にする 2. ごみ箱を閉じる" + echo "3. コンテンツを復元する 4. ごみ箱を空にする" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5615,7 +5614,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが有効になり、削除されたファイルがリサイクルビンに移動されます。" + echo "ごみ箱が有効になっていると、削除されたファイルはごみ箱に移動されます。" sleep 2 ;; 2) @@ -5623,11 +5622,11 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "リサイクルビンが閉じられ、ファイルが直接削除されます。" + echo "ごみ箱が閉じられ、ファイルは直接削除されます。" sleep 2 ;; 3) - read -e -p "復元するにはファイル名を入力してください。" file_to_restore + read -e -p "復元するファイル名を入力してください:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" echo "$file_to_restoreホームディレクトリに復元されました。" @@ -5636,10 +5635,10 @@ linux_trash() { fi ;; 4) - read -e -p "リサイクルビンをクリアすることを確認しますか? [Y/N]:" confirm + read -e -p "ごみ箱を空にしてもよろしいですか? [y/n]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "リサイクルビンがクリアされました。" + echo "ごみ箱が空になりました。" fi ;; *) @@ -5654,17 +5653,17 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成します +# バックアップの作成 create_backup() { send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する echo "バックアップの作成例:" - echo "- 単一のディレクトリをバックアップします: /var /www" - echo "- バックアップ複数のディレクトリ: /etc /home /var /log" - echo "-directEnterはデフォルトのディレクトリ( /etc /usr /home)を使用します" - read -r -p "ディレクトリを入力してバックアップしてください(複数のディレクトリがスペースで区切られています。直接入力する場合は、デフォルトのディレクトリを使用してください):" input + echo "- 単一ディレクトリをバックアップします: /var/www" + echo "- 複数のディレクトリをバックアップします: /etc /home /var/log" + echo "- Enter キーを押して、デフォルトのディレクトリ (/etc /usr /home) を使用します。" + read -r -p "バックアップするディレクトリを入力してください (複数のディレクトリをスペースで区切って、Enter キーを押してデフォルトのディレクトリを使用します)。" input # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリが使用されます。 if [ -z "$input" ]; then @@ -5692,7 +5691,7 @@ create_backup() { # バックアップファイル名の生成 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # ユーザーが選択したディレクトリを印刷します + # ユーザーが選択した印刷ディレクトリ echo "選択したバックアップ ディレクトリは次のとおりです。" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" @@ -5715,27 +5714,27 @@ create_backup() { # バックアップを復元する restore_backup() { send_stats "バックアップを復元する" - # 復元するバックアップを選択します - read -e -p "復元するには、バックアップファイル名を入力してください。" BACKUP_NAME + # 復元するバックアップを選択してください + read -e -p "復元するバックアップ ファイル名を入力してください:" BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # バックアップファイルが存在するか確認する if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "バックアップファイルは存在しません!" + echo "バックアップファイルが存在しません!" exit 1 fi - echo "バックアップの回復$BACKUP_NAME..." + echo "バックアップの復元$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "バックアップと復元を正常に!" + echo "バックアップと復元が成功しました。" else - echo "バックアップリカバリが失敗しました!" + echo "バックアップ復元に失敗しました!" exit 1 fi } -# バックアップをリストします +# バックアップの一覧表示 list_backups() { echo "利用可能なバックアップ:" ls -1 "$BACKUP_DIR" @@ -5745,9 +5744,9 @@ list_backups() { delete_backup() { send_stats "バックアップの削除" - read -e -p "削除するには、バックアップファイル名を入力してください。" BACKUP_NAME + read -e -p "削除するバックアップ ファイル名を入力してください:" BACKUP_NAME - # バックアップファイルが存在するかどうかを確認します + # バックアップファイルが存在するか確認する if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then echo "バックアップファイルが存在しません!" exit 1 @@ -5757,7 +5756,7 @@ delete_backup() { rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "バックアップは正常に削除されました!" + echo "バックアップが正常に削除されました。" else echo "バックアップの削除に失敗しました!" exit 1 @@ -5777,16 +5776,16 @@ linux_backup() { echo "------------------------" echo "1. バックアップの作成 2. バックアップの復元 3. バックアップの削除" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -5807,47 +5806,47 @@ list_connections() { } -# 新しい接続を追加します +# 新しい接続を追加 add_connection() { send_stats "新しい接続を追加" echo "新しい接続を作成する例:" echo "- 接続名: my_server" echo "- IP アドレス: 192.168.1.100" - echo "- ユーザー名:root" - echo "- ポート:22" + echo "- ユーザー名: root" + echo "- ポート: 22" echo "------------------------" - read -e -p "接続名を入力してください:" name - read -e -p "IPアドレスを入力してください:" ip - read -e -p "ユーザー名(デフォルト:root)を入力してください:" user + read -e -p "接続名を入力してください:" name + read -e -p "IP アドレスを入力してください:" ip + read -e -p "ユーザー名を入力してください (デフォルト: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "ポート番号を入力してください(デフォルト:22):" port + read -e -p "ポート番号を入力してください (デフォルト: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 echo "認証方法を選択してください:" echo "1. パスワード" echo "2. キー" - read -e -p "選択(1/2)を入力してください:" auth_choice + read -e -p "選択肢を入力してください (1/2):" auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 ;; 2) echo "キーの内容を貼り付けてください (貼り付け後に Enter を 2 回押します)。" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 入力が空行で、キーの内容にすでに先頭が含まれている場合は、入力を終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # それが最初の行である場合、またはすでにキーコンテンツの入力を開始している場合は、追加を続けます。 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # キーコンテンツのかどうかを確認してください + # キーコンテンツかどうかを確認する if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -5867,10 +5866,10 @@ add_connection() { -# 接続を削除します +# 接続の削除 delete_connection() { - send_stats "接続を削除します" - read -e -p "削除するには、接続番号を入力してください。" num + send_stats "接続の削除" + read -e -p "削除する接続番号を入力してください:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -5880,23 +5879,23 @@ delete_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 接続がキーファイルを使用している場合、キーファイルを削除します + # 接続にキー ファイルが使用されている場合は、キー ファイルを削除します if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "接続が削除されました!" + echo "接続が削除されました!" } # 接続を使用する use_connection() { - send_stats "接続を使用します" + send_stats "接続を使用する" read -e -p "使用する接続番号を入力してください:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "エラー:対応する接続​​は見つかりませんでした。" + echo "エラー: 対応する接続​​が見つかりません。" return fi @@ -5904,11 +5903,11 @@ use_connection() { echo "接続先$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # キーに接続します + # キーを使用して接続する ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "接続に失敗しました!以下を確認してください。" - echo "1。キーファイルパスは正しいですか?$password_or_key" + echo "接続に失敗しました!以下の点をご確認ください。" + echo "1. キーファイルのパスは正しいですか?$password_or_key" echo "2. キー ファイルのアクセス許可は正しいか (600 である必要があります)。" echo "3. ターゲットサーバーがキーを使用したログインを許可するかどうか。" fi @@ -5925,7 +5924,7 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "接続に失敗しました!以下の点をご確認ください。" echo "1. ユーザー名とパスワードは正しいですか?" - echo "2。ターゲットサーバーがパスワードログインを許可するかどうか。" + echo "2. ターゲットサーバーがパスワードログインを許可するかどうか。" echo "3. 対象サーバのSSHサービスが正常に動作しているか。" fi fi @@ -5951,14 +5950,14 @@ ssh_manager() { while true; do clear echo "SSHリモート接続ツール" - echo "SSHを介して他のLinuxシステムに接続できます" + echo "SSH経由で他のLinuxシステムに接続可能" echo "------------------------" list_connections echo "1. 新しい接続を作成します。 2. 接続を使用します。 3. 接続を削除します。" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) add_connection ;; 2) use_connection ;; @@ -5986,14 +5985,14 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントします +# パーティションのマウント mount_partition() { - send_stats "パーティションをマウントします" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "パーティションが存在しません!" return fi @@ -6007,65 +6006,65 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントします + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then - echo "パーティションマウントに正常に:$MOUNT_POINT" + echo "パーティションは正常にマウントされました:$MOUNT_POINT" else - echo "パーティションマウントは失敗しました!" + echo "パーティションのマウントに失敗しました!" rmdir "$MOUNT_POINT" fi } -# パーティションをアンインストールします +# パーティションをアンマウントする unmount_partition() { - send_stats "パーティションをアンインストールします" - read -e -p "パーティション名(たとえば、SDA1)を入力してください。" PARTITION + send_stats "パーティションをアンマウントする" + read -e -p "アンマウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションがマウントされているかどうかを確認する MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "パーティションはマウントされていません!" + echo "パーティションがマウントされていません!" return fi - # パーティションをアンインストールします + # パーティションをアンマウントする umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティションのアンインストールに正常に:$MOUNT_POINT" + echo "パーティションが正常にアンインストールされました:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "パーティションのアンインストールに失敗しました!" + echo "パーティションのアンインストールに失敗しました!" fi } -# マウントされたパーティションをリストします +# マウントされたパーティションをリストする list_mounted_partitions() { - echo "マウントされたパーティション:" + echo "マウントされたパーティション:" df -h | grep -v "tmpfs\|udev\|overlay" } -# フォーマットパーティション +# パーティションをフォーマットする format_partition() { - send_stats "フォーマットパーティション" + send_stats "パーティションをフォーマットする" read -e -p "フォーマットするパーティションの名前を入力してください (例: sda1):" PARTITION - # パーティションが存在するかどうかを確認します + # パーティションが存在するかどうかを確認する if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "パーティションが存在しません!" return fi - # パーティションが既にマウントされているかどうかを確認してください + # パーティションがマウントされているかどうかを確認する if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "パーティションがマウントされました。最初にアンインストールしてください!" + echo "パーティションはマウントされています。最初にアンマウントしてください。" return fi # ファイルシステムの種類を選択してください - echo "ファイルシステムタイプを選択してください:" + echo "ファイル システムのタイプを選択してください:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" @@ -6077,22 +6076,22 @@ format_partition() { 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "無効な選択!"; return ;; + *) echo "無効な選択です!"; return ;; esac # フォーマットの確認 - read -e -p "フォーマットされたパーティション /dev/ を確認します$PARTITIONのために$FS_TYPEそれですか? (y/n):" CONFIRM + read -e -p "フォーマットされたパーティション /dev/ を確認します$PARTITIONのために$FS_TYPE? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作はキャンセルされました。" return fi # パーティションをフォーマットする - echo "パーティション /dev /のフォーマット /$PARTITIONのために$FS_TYPE ..." + echo "パーティション /dev/ をフォーマットしています$PARTITIONのために$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "パーティション形式は成功しました!" + echo "パーティションが正常にフォーマットされました。" else echo "パーティションのフォーマットに失敗しました!" fi @@ -6105,11 +6104,11 @@ check_partition() { # パーティションが存在するかどうかを確認する if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "パーティションは存在しません!" + echo "パーティションが存在しません!" return fi - # パーティションステータスを確認します + # パーティションのステータスを確認する echo "パーティション /dev/ を確認してください$PARTITION状態:" fsck "/dev/$PARTITION" } @@ -6119,7 +6118,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6127,7 +6126,7 @@ disk_manager() { echo "1. パーティションをマウントします。 2. パーティションをアンマウントします。 3. マウントされたパーティションを表示します。" echo "4. パーティションをフォーマットします。 5. パーティションのステータスを確認します。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" choice case $choice in @@ -6138,7 +6137,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6147,49 +6146,49 @@ disk_manager() { # タスクリストを表示 list_tasks() { - echo "保存された同期タスク:" + echo "保存された同期タスク:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 新しいタスクを追加します +# 新しいタスクを追加する add_task() { send_stats "新しい同期タスクを追加する" echo "新しい同期タスクの作成例:" echo "- タスク名:backup_www" - echo "- ローカルディレクトリ: /var /www" - echo "- リモートアドレス:user@192.168.1.100" + echo "- ローカルディレクトリ: /var/www" + echo "- リモートアドレス: user@192.168.1.100" echo "- リモートディレクトリ: /backup/www" echo "- ポート番号 (デフォルトは 22)" echo "---------------------------------" read -e -p "タスク名を入力してください:" name read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path - read -e -p "リモートユーザー@IPを入力してください:" remote + read -e -p "リモート ユーザー@IP を入力してください:" remote read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} - echo "認証方法を選択してください:" - echo "1。パスワード" + echo "認証方法を選択してください:" + echo "1. パスワード" echo "2. キー" - read -e -p "(1/2)を選択してください:" auth_choice + read -e -p "(1/2) を選択してください:" auth_choice case $auth_choice in 1) - read -s -p "パスワードを入力してください:" password_or_key + read -s -p "パスワードを入力してください:" password_or_key echo # 换行 auth_method="password" ;; 2) - echo "キーコンテンツを貼り付けてください(貼り付け後に2回Enterを押します)を押してください):" + echo "キーの内容を貼り付けてください (貼り付け後に Enter を 2 回押します)。" local password_or_key="" while IFS= read -r line; do - # 入力が空で、キーコンテンツにすでに開始が含まれている場合、入力は終了します + # 入力が空行で、キーの内容にすでに先頭が含まれている場合は、入力を終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行であるか、キーコンテンツが入力されている場合は、さらに追加し続けます + # それが最初の行である場合、またはすでにキーコンテンツの入力を開始している場合は、追加を続けます。 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6215,12 +6214,12 @@ add_task() { echo "同期モードを選択してください:" echo "1. 標準モード (-avz)" - echo "2。ターゲットファイル(-avz - delete)を削除します" + echo "2. 対象ファイルを削除(-avz --delete)" read -e -p "(1/2) を選択してください:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無効な選択、デフォルト-AVZを使用します"; options="-avz" ;; + *) echo "選択が無効です。デフォルトの -avz を使用してください"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" @@ -6233,7 +6232,7 @@ add_task() { # タスクの削除 delete_task() { send_stats "同期タスクの削除" - read -e -p "削除するには、タスク番号を入力してください。" num + read -e -p "削除するタスク番号を入力してください:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then @@ -6283,18 +6282,18 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 同期の方向に従ってソースとターゲットのパスを調整します + # 同期方向に基づいてソースパスと宛先パスを調整する if [[ "$direction" == "pull" ]]; then - echo "同期をローカルに引く:$remote:$local_path -> $remote_path" + echo "ローカルへのプルと同期:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "同期をリモートエンドに押します:$local_path -> $remote:$remote_path" + echo "リモートエンドへのプッシュと同期:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH接続の共通パラメーターを追加します + # SSH接続の共通パラメータを追加する local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then @@ -6307,14 +6306,14 @@ run_task() { fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # キーファイルが存在するかどうか、およびアクセス許可が正しいかどうかを確認します + # キーファイルが存在するかどうか、および権限が正しいかどうかを確認してください if [[ ! -f "$password_or_key" ]]; then - echo "エラー:キーファイルが存在しません:$password_or_key" + echo "エラー: キー ファイルが存在しません:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:キーファイルの権限が正しくなく、修理されています..." + echo "警告: キー ファイルのアクセス許可が正しくありません。修正中です..." chmod 600 "$password_or_key" fi @@ -6322,32 +6321,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同期は完了です!" + echo "同期が完了しました!" else - echo "同期は失敗しました!以下を確認してください。" + echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2。リモートホストにアクセスできますか?" - echo "3。認証情報は正しいですか?" - echo "4.ローカルおよびリモートディレクトリには正しいアクセス許可がありますか" + echo "2. リモートホストにアクセスできるかどうか" + echo "3. 認証情報は正しいですか?" + echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi } -# 時限タスクを作成します +# スケジュールされたタスクを作成する schedule_task() { - send_stats "同期タイミングタスクを追加します" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "エラー:有効なタスク番号を入力してください!" + echo "エラー: 有効なタスク番号を入力してください。" return fi echo "スケジュールされた実行間隔を選択してください:" echo "1) 1時間に1回実行" echo "2) 1日1回実行" - echo "3)週に1回実行します" - read -e -p "オプションを入力してください(1/2/3):" interval + echo "3) 週に1回実行" + read -e -p "オプションを入力してください (1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -6355,7 +6354,7 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "エラー:有効なオプションを入力してください!" ; return ;; + *) echo "エラー: 有効なオプションを入力してください。" ; return ;; esac local cron_job="$cron_time k rsync_run $num" @@ -6363,7 +6362,7 @@ schedule_task() { # 同じタスクがすでに存在するかどうかを確認する if crontab -l | grep -q "k rsync_run $num"; then - echo "エラー:このタスクのタイミング同期はすでに存在しています!" + echo "エラー: このタスクのスケジュールされた同期はすでに存在します。" return fi @@ -6374,23 +6373,23 @@ schedule_task() { # スケジュールされたタスクを表示する view_tasks() { - echo "現在のタイミングタスク:" + echo "現在スケジュールされているタスク:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# タイミングタスクを削除します +# スケジュールされたタスクを削除する delete_task_schedule() { send_stats "同期のスケジュールされたタスクを削除する" - read -e -p "削除するには、タスク番号を入力してください。" num + read -e -p "削除するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then echo "エラー: 有効なタスク番号を入力してください。" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "削除されたタスク番号$numタイミングタスク" + echo "タスク番号が削除されました$numスケジュールされたタスク" } @@ -6401,20 +6400,20 @@ rsync_manager() { while true; do clear - echo "RSYNCリモート同期ツール" - echo "リモートディレクトリ間の同期は、増分同期、効率的、安定性をサポートします。" + echo "Rsync リモート同期ツール" + echo "リモート ディレクトリ間の同期は、効率的で安定した増分同期をサポートしています。" echo "---------------------------------" list_tasks echo view_tasks echo echo "1. 新しいタスクを作成します。 2. タスクを削除します。" - echo "3.リモートエンドにローカル同期を実行する4。ローカルエンドにリモート同期を実行する" - echo "5.タイミングタスクを作成6.タイミングタスクを削除します" + echo "3. リモート サイトへのローカル同期を実行します。 4. ローカル サイトへのリモート同期を実行します。" + echo "5. スケジュールされたタスクを作成します。 6. スケジュールされたタスクを削除します。" echo "---------------------------------" echo "0. 前のメニューに戻る" echo "---------------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6425,7 +6424,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enterを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6440,7 +6439,7 @@ rsync_manager() { linux_info() { clear - send_stats "システム情報クエリ" + send_stats "システム情報の問い合わせ" ip_address @@ -6490,7 +6489,7 @@ linux_info() { echo "" - echo -e "システム情報クエリ" + echo -e "システム情報の問い合わせ" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" @@ -6498,31 +6497,31 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU アーキテクチャ:${gl_bai}$cpu_arch" echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPUコアの数:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU周波数:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占有:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}CPU使用率:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}システム負荷:${gl_bai}$load" - echo -e "${gl_kjlan}物理的記憶:${gl_bai}$mem_info" - echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" + echo -e "${gl_kjlan}物理メモリ:${gl_bai}$mem_info" + echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" echo -e "${gl_kjlan}ハードドライブの使用状況:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}受け取った合計:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}送信合計:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}ネットワークアルゴリズム:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}オペレーター:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4アドレス:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6アドレス:${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNS アドレス:${gl_bai}$dns_addresses" echo -e "${gl_kjlan}位置:${gl_bai}$country $city" - echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}実行時間:${gl_bai}$runtime" echo @@ -6537,39 +6536,39 @@ linux_tools() { while true; do clear - # send_stats「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}SUDOスーパー管理許可ツール${gl_kjlan}4. ${gl_bai}socat通信接続ツール" + echo -e "${gl_kjlan}3. ${gl_bai}sudo スーパー管理者特権ツール${gl_kjlan}4. ${gl_bai}socat通信接続ツール" echo -e "${gl_kjlan}5. ${gl_bai}htop システム監視ツール${gl_kjlan}6. ${gl_bai}iftop ネットワークトラフィック監視ツール" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP圧縮・解凍ツール${gl_kjlan}8. ${gl_bai}TAR GZ圧縮減圧ツール" - echo -e "${gl_kjlan}9. ${gl_bai}TMUXマルチチャネルバックグラウンドランニングツール${gl_kjlan}10. ${gl_bai}Live StreamingツールをエンコードするFFMPEGビデオ" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP圧縮・解凍ツール${gl_kjlan}8. ${gl_bai}tar GZ 圧縮および解凍ツール" + echo -e "${gl_kjlan}9. ${gl_bai}tmux マルチチャネル バックグラウンド実行ツール${gl_kjlan}10. ${gl_bai}ffmpeg ビデオエンコードライブストリーミングツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}BTOPモダン監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}範囲ファイル管理ツール" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}FZFグローバル検索ツール" + echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}gitバージョン制御システム" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" - echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーゲーム" + echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーのミニゲーム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}すべてをインストールします${gl_kjlan}32. ${gl_bai}すべてのインストール(スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}すべてをアンインストールします" + echo -e "${gl_kjlan}31. ${gl_bai}すべてインストールする${gl_kjlan}32. ${gl_bai}すべてインストール (スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}すべてアンインストールする" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールする${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) clear install curl clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" curl --help send_stats "カールをインストールする" ;; @@ -6585,9 +6584,9 @@ linux_tools() { clear install sudo clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" sudo --help - send_stats "sudoをインストールします" + send_stats "sudoをインストールする" ;; 4) clear @@ -6609,21 +6608,21 @@ linux_tools() { install iftop clear iftop - send_stats "IFTOPをインストールします" + send_stats "iftopをインストールする" ;; 7) clear install unzip clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" unzip - send_stats "Unzipをインストールします" + send_stats "インストール解凍" ;; 8) clear install tar clear - echo "ツールがインストールされており、使用方法は次のとおりです。" + echo "ツールはインストールされており、次のように使用されます。" tar --help send_stats "tarをインストールする" ;; @@ -6641,7 +6640,7 @@ linux_tools() { clear echo "ツールはインストールされており、次のように使用されます。" ffmpeg --help - send_stats "FFMPEGをインストールします" + send_stats "ffmpegをインストールする" ;; 11) @@ -6658,7 +6657,7 @@ linux_tools() { clear ranger cd ~ - send_stats "レンジャーをインストールします" + send_stats "レンジャーをインストールする" ;; 13) clear @@ -6667,7 +6666,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "NCDUをインストールします" + send_stats "ncdu をインストールする" ;; 14) clear @@ -6685,7 +6684,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "VIMをインストールします" + send_stats "vimをインストールする" ;; 16) clear @@ -6694,7 +6693,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "ナノをインストールします" + send_stats "ナノをインストールする" ;; @@ -6705,7 +6704,7 @@ linux_tools() { clear git --help cd ~ - send_stats "gitをインストールします" + send_stats "gitをインストールする" ;; 21) @@ -6713,7 +6712,7 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrixをインストールします" + send_stats "cmatrix をインストールする" ;; 22) clear @@ -6734,7 +6733,7 @@ linux_tools() { install nsnake clear nsnake - send_stats "nsnakeをインストールします" + send_stats "nsnakeをインストールする" ;; 28) clear @@ -6746,13 +6745,13 @@ linux_tools() { 31) clear - send_stats "すべてをインストールします" + send_stats "すべてインストールする" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "すべてをインストールします(ゲームやスクリーンセーバーを除く)" + send_stats "すべてインストール (ゲームとスクリーンセーバーを除く)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; @@ -6767,13 +6766,13 @@ linux_tools() { clear read -e -p "インストールされているツール名 (wgetcurlsudohtop) を入力してください:" installname install $installname - send_stats "指定されたソフトウェアをインストールします" + send_stats "指定されたソフトウェアをインストールする" ;; 42) clear read -e -p "アンインストールされたツール名 (htop ufw tmux cmatrix) を入力してください:" removename remove $removename - send_stats "指定されたソフトウェアをアンインストールします" + send_stats "指定したソフトウェアをアンインストールする" ;; 0) @@ -6801,16 +6800,16 @@ linux_bbr() { clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "現在のTCPブロッキングアルゴリズム:$congestion_algorithm $queue_algorithm" + echo "現在の TCP ブロック アルゴリズム:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" echo "1. BBRv3 をオンにする 2. BBRv3 をオフにする (再起動します)" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) @@ -6869,9 +6868,9 @@ docker_ssh_migration() { backup_docker() { send_stats "Dockerバックアップ" - echo -e "${YELLOW}Dockerコンテナのバックアップ...${NC}" + echo -e "${YELLOW}Docker コンテナをバックアップしています...${NC}" docker ps --format '{{.Names}}' - read -e -p "バックアップするコンテナの名前を入力してください(複数のスペースで区切られていて、Enterバックアップはすべて実行中のコンテナです):" containers + read -e -p "バックアップするコンテナの名前を入力してください (実行中のすべてのコンテナをバックアップするには、複数のスペースを区切って Enter キーを押します)。" containers install tar jq gzip install_docker @@ -6894,7 +6893,7 @@ docker_ssh_migration() { echo "set -e" >> "$RESTORE_SCRIPT" echo "# 自動生成された復元スクリプト" >> "$RESTORE_SCRIPT" - # パッケージ化されたプロジェクトのパスを記録して、パッケージの重複を避ける + # パッケージ化の繰り返しを避けるために、パッケージ化された Compose プロジェクトのパスを記録します。 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -6913,7 +6912,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -6921,10 +6920,10 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "#docker-compose Recovery:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 復元:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトの作成 [$project_name]パック:${project_dir}${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name] パッケージ内容:${project_dir}${NC}" else echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" fi @@ -6933,7 +6932,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包体積:$path" + echo "梱包量:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -6955,17 +6954,17 @@ docker_ssh_migration() { local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\ n#復元コンテナ:$c" >> "$RESTORE_SCRIPT" + echo -e "\n# コンテナを復元:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # /home /dockerのすべてのファイルをバックアップします(サブディレクトリを除く) + # /home/docker 下のすべてのファイルをバックアップします (サブディレクトリを除く)。 if [ -d "/home/docker" ]; then echo -e "${BLUE}/home/docker 下のファイルをバックアップします...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home /dockerの下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${GREEN}/home/docker 下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" @@ -6980,9 +6979,9 @@ docker_ssh_migration() { # ---------------------------- restore_docker() { - send_stats "Dockerの復元" + send_stats "Docker の復元" read -e -p "復元するバックアップ ディレクトリを入力してください:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } echo -e "${BLUE}復元操作を開始しています...${NC}" @@ -6996,17 +6995,17 @@ docker_ssh_migration() { project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりませんでした。復元ディレクトリパスを入力してください。" original_path + [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # Composeプロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}プロジェクトを作成する[$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" continue fi - read -e -p "Composeプロジェクトの復元を確認します[$project_name]パスへ[$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -e -p "新しい復元パスを入力してください:" original_path + read -e -p "Compose プロジェクトの復元を確認します [$project_name] からパス [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "新しい復元パスを入力してください:" original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" @@ -7015,12 +7014,12 @@ docker_ssh_migration() { cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}プロジェクトを作成する[$project_name】レストア完了!${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name】レストア完了!${NC}" fi done # --------- 通常のコンテナの復元を続行 --------- - echo -e "${BLUE}通常のDockerコンテナを確認して復元します...${NC}" + echo -e "${BLUE}通常の Docker コンテナを確認して復元します...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue @@ -7035,7 +7034,7 @@ docker_ssh_migration() { fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報は見つかりませんでした、スキップ:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報が見つかりません。スキップしてください:$container${NC}"; continue; } # ポートマッピング PORT_ARGS="" @@ -7069,18 +7068,18 @@ docker_ssh_migration() { # 既存だが実行されていないコンテナを削除する if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container]存在しますが、実行していない、古いコンテナを削除してください...${NC}" + echo -e "${YELLOW}容器 [$container] は存在しますが実行されていない場合は、古いコンテナを削除してください...${NC}" docker rm -f "$container" fi - # コンテナを起動します + # コンテナの起動 echo "復元コマンドを実行します: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}通常のコンテナのバックアップ情報は見つかりませんでした${NC}" + [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home /dockerの下でファイルを復元します + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7095,13 +7094,13 @@ docker_ssh_migration() { # ---------------------------- - # 移動します + # 移行する # ---------------------------- migrate_docker() { send_stats "Docker の移行" install jq - read -e -p "移行するには、バックアップディレクトリを入力してください。" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリは存在しません${NC}"; return; } + read -e -p "移行するバックアップ ディレクトリを入力してください:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER @@ -7110,23 +7109,23 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}バックアップを転送...${NC}" + echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログインします + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # バックアップを削除します + # バックアップの削除 # ---------------------------- delete_backup() { send_stats "Dockerバックアップファイルの削除" read -e -p "削除するバックアップ ディレクトリを入力してください:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" + echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" } # ---------------------------- @@ -7137,19 +7136,19 @@ docker_ssh_migration() { while true; do clear echo "------------------------" - echo -e "Dockerバックアップ/移行/復元ツール" + echo -e "Docker バックアップ/移行/復元ツール" echo "------------------------" list_backups echo -e "" echo "------------------------" echo -e "1. Docker プロジェクトをバックアップする" echo -e "2. Docker プロジェクトを移行する" - echo -e "3. Dockerプロジェクトを復元します" + echo -e "3. Docker プロジェクトを復元する" echo -e "4. Dockerプロジェクトのバックアップファイルを削除する" echo "------------------------" - echo -e "0。前のメニューに戻ります" + echo -e "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択してください:" choice + read -e -p "選択してください:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -7173,28 +7172,28 @@ linux_docker() { while true; do clear - # send_stats「Docker Management」 + # send_stats "ドッカー管理" echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker環境をインストールして更新します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker環境のインストールと更新${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Dockerグローバルステータスを表示します${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Docker のグローバル ステータスを表示する${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Dockerコンテナ管理${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}Dockerイメージ管理" echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清潔な役に立たないドッカーコンテナとミラーネットワークデータボリューム" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを交換します" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.jsonファイルを編集します" + echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}docker-ipv6アクセスを有効にします" + echo -e "${gl_kjlan}11. ${gl_bai}Docker-ipv6 アクセスを有効にする" echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 アクセスをオフにする" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}バックアップ/移行/復元Docker環境" + echo -e "${gl_kjlan}19. ${gl_bai}Docker環境のバックアップ/移行/復元" echo -e "${gl_kjlan}20. ${gl_bai}Docker環境をアンインストールする" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" @@ -7204,7 +7203,7 @@ linux_docker() { case $sub_choice in 1) clear - send_stats "Docker環境をインストールします" + send_stats "Docker環境をインストールする" install_add_docker ;; @@ -7221,16 +7220,16 @@ linux_docker() { docker compose version echo "" - echo -e "Docker画像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker イメージ:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Dockerコンテナ:${gl_lv}$container_count${gl_bai}" + echo -e "Docker コンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Dockerボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7270,26 +7269,26 @@ linux_docker() { done echo "" - echo "ネットワーク操作" + echo "ネットワーク運用" echo "------------------------" echo "1. ネットワークを作成する" - echo "2。インターネットに参加してください" - echo "3。ネットワークを終了します" - echo "4.ネットワークを削除します" + echo "2. ネットワークに参加する" + echo "3. ネットワークを終了します" + echo "4. ネットワークの削除" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) - send_stats "ネットワークを作成します" - read -e -p "新しいネットワーク名を設定します:" dockernetwork + send_stats "ネットワークの作成" + read -e -p "新しいネットワーク名を設定します。" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "インターネットに参加してください" - read -e -p "ネットワーク名に参加してください:" dockernetwork + send_stats "ネットワークに参加する" + read -e -p "ネットワーク名を追加します:" dockernetwork read -e -p "どのコンテナがネットワークに参加しますか (複数のコンテナ名はスペースで区切ってください):" dockernames for dockername in $dockernames; do @@ -7323,15 +7322,15 @@ linux_docker() { 6) while true; do clear - send_stats "Dockerボリューム管理" + send_stats "Docker ボリューム管理" echo "Dockerボリュームリスト" docker volume ls echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" - echo "2。指定されたボリュームを削除します" - echo "3.すべてのボリュームを削除します" + echo "1. 新しいボリュームを作成する" + echo "2. 指定したボリュームを削除します" + echo "3. すべてのボリュームを削除します" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -7339,13 +7338,13 @@ linux_docker() { case $sub_choice in 1) - send_stats "新しいボリュームを作成します" - read -e -p "新しいボリューム名を設定します:" dockerjuan + send_stats "新しいボリュームを作成する" + read -e -p "新しいボリューム名を設定します。" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "削除ボリューム名を入力します(スペースで複数のボリューム名を分離してください):" dockerjuans + read -e -p "削除ボリューム名を入力します (複数のボリューム名はスペースで区切ってください):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7354,7 +7353,7 @@ linux_docker() { ;; 3) - send_stats "すべてのボリュームを削除します" + send_stats "すべてのボリュームを削除する" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7376,7 +7375,7 @@ linux_docker() { ;; 7) clear - send_stats "Dockerクリーニング" + send_stats "Docker のクリーンアップ" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7391,7 +7390,7 @@ linux_docker() { ;; 8) clear - send_stats "Dockerソース" + send_stats "Docker ソース" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -7413,7 +7412,7 @@ linux_docker() { 12) clear - send_stats "Docker V6レベル" + send_stats "Docker v6 閉じる" docker_ipv6_off ;; @@ -7463,34 +7462,34 @@ linux_test() { while true; do clear # send_stats "テストスクリプト集" - echo -e "テストスクリプトコレクション" + echo -e "テストスクリプト集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IPおよびロック解除ステータスの検出" - echo -e "${gl_kjlan}1. ${gl_bai}CHATGPTはステータス検出のロックを解除します" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPTロック解除状態検出" echo -e "${gl_kjlan}2. ${gl_bai}リージョンストリーミングメディアロック解除テスト" - echo -e "${gl_kjlan}3. ${gl_bai}YeahWUストリーミングメディアのロック解除検出" - echo -e "${gl_kjlan}4. ${gl_bai}XYKT IP品質の身体検査スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}Yeawu ストリーミング メディアのロック解除の検出" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 品質チェック スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}ネットワーク速度測定" - echo -e "${gl_kjlan}11. ${gl_bai}BestTrace 3ネットワークバックホール遅延ルーティングテスト" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3ネットワークバックホールラインテスト" + echo -e "${gl_kjlan}ネットワーク回線速度テスト" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 3 ネットワーク バックホール遅延ルーティング テスト" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace トリプルネットワークバックホール回線テスト" echo -e "${gl_kjlan}13. ${gl_bai}超高速トリプルネットワーク速度テスト" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace高速バックホールテストスクリプト" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 高速バックホール テスト スクリプト" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace は IP バックホール テスト スクリプトを指定します" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 3つのネットワーク回線テスト" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多機能速度テスト スクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}Networt Network品質の身体診断スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality ネットワーク品質チェック スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" - echo -e "${gl_kjlan}21. ${gl_bai}YABSパフォーマンステスト" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPUパフォーマンステストスクリプト" + echo -e "${gl_kjlan}21. ${gl_bai}yabsパフォーマンステスト" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU パフォーマンステストスクリプト" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}包括的なテスト" + echo -e "${gl_kjlan}総合的なテスト" echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX Fusion Monster Review${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7504,7 +7503,7 @@ linux_test() { ;; 2) clear - send_stats "リージョンストリーミングメディアのロック解除テスト" + send_stats "リージョンストリーミングメディアロック解除テスト" bash <(curl -L -s check.unlock.media) ;; 3) @@ -7515,7 +7514,7 @@ linux_test() { ;; 4) clear - send_stats "XYKT_IP品質の身体検査スクリプト" + send_stats "xykt_IP 品質チェック スクリプト" bash <(curl -Ls IP.Check.Place) ;; @@ -7528,12 +7527,12 @@ linux_test() { ;; 12) clear - send_stats "MTR_TRACE 3ネットワークリターンラインテスト" + send_stats "mtr_trace トリプルネットワークバックホール回線テスト" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "SuperSpeed Three-Net速度測定" + send_stats "超高速トリプルネットワーク速度テスト" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) @@ -7545,51 +7544,51 @@ linux_test() { 15) clear send_stats "nxtrace は IP バックホール テスト スクリプトを指定します" - echo "参照できるIPのリスト" + echo "参照IPリスト" echo "------------------------" - echo "北京テレコム:219.141.136.12" + echo "北京電信: 219.141.136.12" echo "北京ユニコム: 202.106.50.1" - echo "北京モバイル:221.179.155.161" + echo "北京モバイル: 221.179.155.161" echo "上海電信: 202.96.209.133" echo "上海ユニコム: 210.22.97.1" echo "上海モバイル: 211.136.112.200" - echo "広州の通信:58.60.188.222" - echo "広州ユニコム:210.21.196.6" + echo "広州電信: 58.60.188.222" + echo "広州チャイナユニコム: 210.21.196.6" echo "広州モバイル: 120.196.165.24" echo "成都電信: 61.139.2.69" echo "成都チャイナユニコム: 119.6.6.6" - echo "成都モバイル:211.137.96.205" - echo "Hunan Telecom:36.111.200.100" + echo "成都携帯電話: 211.137.96.205" + echo "湖南電信: 36.111.200.100" echo "湖南ユニコム: 42.48.16.100" echo "湖南省モバイル: 39.134.254.6" echo "------------------------" - read -e -p "指定されたIPを入力してください:" testip + read -e -p "特定の IP を入力します。" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "Ludashi2020 3ネットワークラインテスト" + send_stats "ludashi2020 3つのネットワーク回線テスト" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "I-ABC多機能速度テストスクリプト" + send_stats "i-abc 多機能速度テスト スクリプト" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "ネットワーク品質のテストスクリプト" + send_stats "ネットワーク品質テストスクリプト" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "YABSパフォーマンステスト" + send_stats "yabsパフォーマンステスト" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; @@ -7606,7 +7605,7 @@ linux_test() { curl -Lso- bench.sh | bash ;; 32) - send_stats "SpiritySDX Fusion Monster Review" + send_stats "Spiritysdx フュージョンモンスター レビュー" clear curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -7616,7 +7615,7 @@ linux_test() { ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -7632,26 +7631,26 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Scriptコレクション" - echo -e "Oracle Cloud Scriptコレクション" + send_stats "Oracle Cloudスクリプト・コレクション" + echo -e "Oracle Cloudスクリプト・コレクション" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}アイドル状態のマシンのアクティブ スクリプトをインストールする" - echo -e "${gl_kjlan}2. ${gl_bai}アイドルマシンアクティブスクリプトをアンインストールします" + echo -e "${gl_kjlan}2. ${gl_bai}アイドル状態のマシンからアクティブなスクリプトをアンインストールする" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD 再インストール システム スクリプト" echo -e "${gl_kjlan}4. ${gl_bai}探偵R起動スクリプト" echo -e "${gl_kjlan}5. ${gl_bai}ROOTパスワードログインモードを有効にする" - echo -e "${gl_kjlan}6. ${gl_bai}IPv6回復ツール" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6回復ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) clear - echo "アクティブスクリプト:CPUが10-20%を占めるメモリは20%を占めています" - read -e -p "必ずインストールしますか? (y/n):" choice + echo "アクティブ スクリプト: CPU 使用率 10 ~ 20% メモリ使用率 20%" + read -e -p "インストールしてもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) @@ -7664,16 +7663,16 @@ linux_Oracle() { local DEFAULT_SPEEDTEST_INTERVAL=120 # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 - read -e -p "CPUコアの数を入力してください[デフォルト:$DEFAULT_CPU_CORE]: " cpu_core + read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "CPU 使用率の範囲 (例: 10 ~ 20) を入力してください [デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリの使用率を入力してください[デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "メモリ使用率を入力してください [デフォルト:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "SpeedTest間隔時間(秒)を入力してください[デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "Speedtest の間隔時間 (秒) を入力してください [デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # Dockerコンテナを実行する @@ -7684,7 +7683,7 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloudインストールアクティブスクリプト" + send_stats "Oracle Cloudインストール・アクティブ・スクリプト" ;; [Nn]) @@ -7704,15 +7703,15 @@ linux_Oracle() { 3) clear - echo "システムを再インストールします" + echo "システムを再インストールする" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールは接触を失う危険であり、心配している人はそれを注意して使用する必要があります。再インストールには15分かかると予想されます。事前にデータをバックアップしてください。" - read -e -p "必ず続けますか? (y/n):" choice + echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" + read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) while true; do - read -e -p "再インストールするシステムを選択してください:1。Debian12| 2。Ubuntu20.04:" sys_choice + read -e -p "再インストールするシステムを選択してください: 1. Debian12 | 2.Ubuntu20.04:" sys_choice case "$sys_choice" in 1) @@ -7729,7 +7728,7 @@ linux_Oracle() { esac done - read -e -p "再インストールされたパスワードを入力してください:" vpspasswd + read -e -p "再インストール後にパスワードを入力してください:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 send_stats "Oracle Cloud再インストールシステムスクリプト" @@ -7738,7 +7737,7 @@ linux_Oracle() { echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -7756,7 +7755,7 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "この関数は、彼のおかげで、マスターJHBによって提供されます!" + echo "この機能は jhb によって提供されています。ありがとう!" send_stats "IPv6修復" ;; 0) @@ -7764,7 +7763,7 @@ linux_Oracle() { ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -7785,7 +7784,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境がインストールされています${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境がインストールされました${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡:${gl_lv}$image_count${gl_bai}ネットワーク:${gl_lv}$network_count${gl_bai}ロール:${gl_lv}$volume_count${gl_bai}" fi } @@ -7838,27 +7837,27 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP Web サイトの構築" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールする${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールします${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuzフォーラムをインストールします${gl_huang}4. ${gl_bai}Kadao Cloudデスクトップをインストールします" + echo -e "${gl_huang}1. ${gl_bai}LDNMP環境をインストールする${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}WordPressをインストールする${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuz フォーラムをインストールする${gl_huang}4. ${gl_bai}Kedao クラウド デスクトップをインストールする" echo -e "${gl_huang}5. ${gl_bai}Apple CMS ムービーおよび TV ステーションをインストールする${gl_huang}6. ${gl_bai}Unicorn デジタル カード ネットワークをインストールする" - echo -e "${gl_huang}7. ${gl_bai}flarumフォーラムWebサイトをインストールする${gl_huang}8. ${gl_bai}Typecho Lightweight Blog Webサイトをインストールします" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 共有リンク プラットフォームをインストールする${gl_huang}20. ${gl_bai}動的サイトをカスタマイズします" + echo -e "${gl_huang}7. ${gl_bai}flarumフォーラムWebサイトをインストールする${gl_huang}8. ${gl_bai}typecho 軽量ブログ Web サイトをインストールする" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 共有リンク プラットフォームをインストールする${gl_huang}20. ${gl_bai}カスタム動的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}サイトリバースプロキシ-IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイトリバースプロキシ - ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}HaloブログのWebサイトをインストールします" + echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" - echo -e "${gl_huang}30. ${gl_bai}静的サイトをカスタマイズします" + echo -e "${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイト全体のデータをバックアップする" - echo -e "${gl_huang}33. ${gl_bai}タイミングのリモートバックアップ${gl_huang}34. ${gl_bai}サイトデータ全体を復元します" + echo -e "${gl_huang}33. ${gl_bai}スケジュールされたリモートバックアップ${gl_huang}34. ${gl_bai}サイト全体のデータを復元する" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護します${gl_huang}36. ${gl_bai}LDNMP環境を最適化します" - echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新します${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールします" + echo -e "${gl_huang}35. ${gl_bai}LDNMP環境を保護する${gl_huang}36. ${gl_bai}LDNMP環境の最適化" + echo -e "${gl_huang}37. ${gl_bai}LDNMP環境を更新する${gl_huang}38. ${gl_bai}LDNMP環境をアンインストールする" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -7872,7 +7871,7 @@ linux_ldnmp() { 3) clear - # ディスクフォーラム + # ディスカスフォーラム webname="Discuz论坛" send_stats "インストール$webname" echo "導入を開始する$webname" @@ -7900,9 +7899,9 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス: mysql" echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:discuz_" + echo "テーブル接頭辞: discuz_" ;; @@ -7935,16 +7934,16 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス: mysql" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "データベース名:$dbname" - echo "Redisホスト:Redis" + echo "redisホスト: redis" ;; 5) clear - # Apple CMS + # AppleCMS webname="苹果CMS" send_stats "インストール$webname" echo "導入を開始する$webname" @@ -7975,10 +7974,10 @@ linux_ldnmp() { ldnmp_web_on echo "データベースアドレス: mysql" echo "データベースポート: 3306" - echo "データベース名:$dbname" + echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "データベースプレフィックス:mac_" + echo "データベース接頭辞: mac_" echo "------------------------" echo "インストールが成功したら、バックエンド アドレスにログインします。" echo "https://$yuming/vip.php" @@ -7990,7 +7989,7 @@ linux_ldnmp() { # 一本足のナンバーカード webname="独脚数卡" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,24 +8010,24 @@ linux_ldnmp() { ldnmp_web_on - echo "データベースアドレス:mysql" + echo "データベースアドレス: mysql" echo "データベースポート: 3306" echo "データベース名:$dbname" - echo "ユーザー名:$dbuse" + echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" echo "" - echo "Redisアドレス:Redis" + echo "redisアドレス: redis" echo "redis パスワード: デフォルトでは入力されていません" - echo "Redisポート:6379" + echo "Redis ポート: 6379" echo "" echo "ウェブサイトURL:https://$yuming" - echo "バックグラウンドログインパス: /admin" + echo "バックエンドのログイン パス: /admin" echo "------------------------" echo "ユーザー名: 管理者" echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8038,7 +8037,7 @@ linux_ldnmp() { # フララムフォーラム webname="flarum论坛" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8079,8 +8078,8 @@ linux_ldnmp() { echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "テーブルプレフィックス:flarum_" - echo "管理者情報は自分で設定されます" + echo "テーブル接頭辞: flarum_" + echo "管理者情報を自分で設定可能" ;; @@ -8089,7 +8088,7 @@ linux_ldnmp() { # typecho webname="typecho" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8114,10 +8113,10 @@ linux_ldnmp() { clear ldnmp_web_on echo "データベース接頭辞: typecho_" - echo "データベースアドレス:mysql" + echo "データベースアドレス: mysql" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" - echo "データベース名:$dbname" + echo "データベース名:$dbname" ;; @@ -8127,7 +8126,7 @@ linux_ldnmp() { # LinkStack webname="LinkStack" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8152,9 +8151,9 @@ linux_ldnmp() { clear ldnmp_web_on - echo "データベースアドレス:mysql" - echo "データベースポート:3306" - echo "データベース名:$dbname" + echo "データベースアドレス: mysql" + echo "データベースポート: 3306" + echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" ;; @@ -8180,9 +8179,9 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードします" + echo -e "[${gl_huang}1/6${gl_bai}] PHPソースコードをアップロードする" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" + echo "現在、zip 形式のソース コード パッケージのみをアップロードできます。ソースコードパッケージを/home/web/html/に置いてください。${yuming}ディレクトリの下" read -e -p "ダウンロード リンクを入力して、ソース コード パッケージをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then @@ -8246,7 +8245,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] データベース管理" echo "-------------" - read -e -p "1.新しいサイトを構築します2。古いサイトを構築し、データベースのバックアップがあります。" use_db + read -e -p "1. 新しいサイトを構築します。 2. 古いサイトを構築し、データベースのバックアップを作成します。" use_db case $use_db in 1) echo @@ -8278,7 +8277,7 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "データベースアドレス:mysql" + echo "データベースアドレス: mysql" echo "データベース名:$dbname" echo "ユーザー名:$dbuse" echo "パスワード:$dbusepasswd" @@ -8297,7 +8296,7 @@ linux_ldnmp() { clear webname="站点重定向" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming read -e -p "リダイレクト ドメイン名を入力してください:" reverseproxy nginx_install_status @@ -8321,7 +8320,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "IP+ポートはサービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -8335,7 +8334,7 @@ linux_ldnmp() { send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming - echo -e "ドメイン名形式:${gl_huang}google.com${gl_bai}" + echo -e "ドメイン名の形式:${gl_huang}google.com${gl_bai}" read -e -p "リバース プロキシ ドメイン名を入力してください:" fandai_yuming nginx_install_status install_ssltls @@ -8357,7 +8356,7 @@ linux_ldnmp() { clear webname="Bitwarden" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming nginx_install_status install_ssltls @@ -8380,7 +8379,7 @@ linux_ldnmp() { clear webname="halo" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming nginx_install_status install_ssltls @@ -8398,7 +8397,7 @@ linux_ldnmp() { clear webname="AI绘画提示词生成器" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming nginx_install_status install_ssltls @@ -8432,7 +8431,7 @@ linux_ldnmp() { clear webname="静态站点" send_stats "インストール$webname" - echo "展開を開始します$webname" + echo "導入を開始する$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8449,10 +8448,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}]静的ソースコードをアップロードします" + echo -e "[${gl_huang}1/2${gl_bai}] 静的ソースコードをアップロードする" echo "-------------" - echo "現在、zip-formatソースコードパッケージのみが許可されています。ソースコードパッケージを/home/web/html/に入れてください${yuming}ディレクトリ内" - read -e -p "ダウンロードリンクを入力して、ソースコードパッケージをリモートでダウンロードすることもできます。 Enterを直接押してリモートダウンロードをスキップします。" url_download + echo "現在、zip 形式のソース コード パッケージのみをアップロードできます。ソースコードパッケージを/home/web/html/に置いてください。${yuming}ディレクトリの下" + read -e -p "ダウンロード リンクを入力して、ソース コード パッケージをリモートでダウンロードすることもできます。 Enter を直接押して、リモート ダウンロードをスキップします。" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -8462,7 +8461,7 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.htmlが配置されているパス" + echo -e "[${gl_huang}2/2${gl_bai}]index.html が配置されているパス" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} @@ -8492,7 +8491,7 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境バックアップ" + send_stats "LDNMP環境のバックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" @@ -8500,11 +8499,11 @@ linux_ldnmp() { while true; do clear - echo "バックアップファイルが作成されました: /home /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + echo "バックアップファイルが作成されました: /home/$backup_filename" + read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "リモートサーバーのIPを入力してください:" remote_ip read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -8516,7 +8515,7 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" + echo "ファイルはリモート サーバーのホーム ディレクトリに転送されました。" else echo "転送するファイルが見つかりませんでした。" fi @@ -8535,8 +8534,8 @@ linux_ldnmp() { 33) clear send_stats "スケジュールされたリモートバックアップ" - read -e -p "リモートサーバーIPを入力してください:" useip - read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd + read -e -p "リモート サーバーの IP を入力します。" useip + read -e -p "リモートサーバーのパスワードを入力してください:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -8546,13 +8545,13 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1。毎週のバックアップ2。毎日のバックアップ" - read -e -p "選択を入力してください:" dingshi + echo "1. 毎週のバックアップ 2. 毎日のバックアップ" + read -e -p "選択肢を入力してください:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "毎週のバックアップ(0-6、0は日曜日を表す)の曜日を選択します。" weekday + read -e -p "毎週のバックアップの曜日を選択します (0 ~ 6、0 は日曜日を表します)。" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) @@ -8571,8 +8570,8 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP環境修復" - echo "利用可能なサイトバックアップ" + send_stats "LDNMP環境の復元" + echo "利用可能なサイトのバックアップ" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" @@ -8583,7 +8582,7 @@ linux_ldnmp() { linux_ldnmp fi - # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージを使用します + # ユーザーがファイル名を入力しない場合は、最新の圧縮パッケージが使用されます。 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8593,7 +8592,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}解凍中$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" check_port @@ -8602,7 +8601,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "圧縮パッケージは見つかりませんでした。" + echo "圧縮パッケージが見つかりませんでした。" fi ;; @@ -8621,7 +8620,7 @@ linux_ldnmp() { while true; do clear send_stats "LDNMP環境を更新する" - echo "LDNMP環境を更新します" + echo "LDNMP環境を更新する" echo "------------------------" ldnmp_v echo "新しいバージョンのコンポーネントが見つかりました" @@ -8646,9 +8645,9 @@ linux_ldnmp() { echo echo "1. nginx を更新します。 2. mysql を更新します。 3. php を更新します。 4. redis を更新します。" echo "------------------------" - echo "5。完全な環境を更新します" + echo "5. 環境全体を更新する" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -8659,7 +8658,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "入力してください${ldnmp_pods}バージョン番号(8.0 8.3 8.4 9.0など)(最新バージョンを取得するには入力):" version + read -e -p "入力してください${ldnmp_pods}バージョン番号 (例: 8.0 8.3 8.4 9.0) (Enter キーを押して最新バージョンを取得します):" version local version=${version:-latest} cd /home/web/ @@ -8671,7 +8670,7 @@ linux_ldnmp() { docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml send_stats "更新する$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + echo "更新する${ldnmp_pods}仕上げる" ;; 3) @@ -8709,8 +8708,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新する$ldnmp_pods" + echo "更新する${ldnmp_pods}仕上げる" ;; 4) @@ -8721,15 +8720,15 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 restart_redis - send_stats "更新します$ldnmp_pods" - echo "更新します${ldnmp_pods}仕上げる" + send_stats "更新する$ldnmp_pods" + echo "更新する${ldnmp_pods}仕上げる" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境を完全に更新します" + send_stats "LDNMP環境の完全アップデート" cd /home/web/ docker compose down --rmi all @@ -8769,7 +8768,7 @@ linux_ldnmp() { ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -8779,7 +8778,7 @@ linux_ldnmp() { ;; *) - echo "無効な入力!" + echo "無効な入力です!" esac break_end @@ -8813,69 +8812,70 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baotaパネルの公式バージョン${gl_kjlan}2. ${color2}Aapanel International Edition" + echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}UbuntuリモートデスクトップWebエディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" - echo -e "${gl_kjlan}9. ${color9}poste.ioメールサーバープログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" + echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao プロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglongパネルの時限タスク管理プラットフォーム" - echo -e "${gl_kjlan}13. ${color13}CloudReveネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルな写真ベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}SpeedTest速度テストパネル" - echo -e "${gl_kjlan}17. ${color17}Adguardhomeアドウェア${gl_kjlan}18. ${color18}唯一のオフィスオンラインオフィスオフィス" - echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}Portainerコンテナ管理パネル" + echo -e "${gl_kjlan}11. ${color11}ZenTao プロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglong パネルのスケジュールされたタスク管理プラットフォーム" + echo -e "${gl_kjlan}13. ${color13}Cloudreve ネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルなピクチャーベッド画像管理プログラム" + echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}Speedtest スピードテストパネル" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome はアドウェアを削除します${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode Web バージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${color23}メモWebページメモ${gl_kjlan}24. ${color24}webtopリモートデスクトップWebエディション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloudネットワークディスク${gl_kjlan}26. ${color26}QD-Todayタイミングタスク管理フレームワーク" + echo -e "${gl_kjlan}23. ${color23}メモウェブメモ${gl_kjlan}24. ${color24}Webtop リモート デスクトップ Web バージョン${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud ネットワーク ディスク${gl_kjlan}26. ${color26}QD-Today スケジュールされたタスク管理フレームワーク" echo -e "${gl_kjlan}27. ${color27}Dockge コンテナ スタック管理パネル${gl_kjlan}28. ${color28}LibreSpeed 速度テストツール" echo -e "${gl_kjlan}29. ${color29}searxng 集約検索ステーション${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrismプライベートアルバムシステム" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF ツール コレクション${gl_kjlan}32. ${color32}Drawio無料のオンラインチャートソフトウェア${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}サンパネルナビゲーションパネル${gl_kjlan}34. ${color34}Pingvin-Share ファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}ミニマリストの友達の輪${gl_kjlan}36. ${color36}Lobechataiチャット集約Webサイト" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF ツール コレクション${gl_kjlan}32. ${color32}無料のオンライングラフ作成ソフトウェアdrawio${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel ナビゲーション パネル${gl_kjlan}34. ${color34}Pingvin-Share ファイル共有プラットフォーム" + echo -e "${gl_kjlan}35. ${color35}ミニマリストの友達の輪${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive Live Broadcast Recording Tool${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" + echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}NEXTEリモート接続ツール" - echo -e "${gl_kjlan}43. ${color43}Rustdeskリモートデスク(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速ステーション${gl_kjlan}46. ${color46}GitHub加速ステーション${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}プロメテウス監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" - echo -e "${gl_kjlan}49. ${color49}プロメテウス(コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nexterm リモート接続ツール" + echo -e "${gl_kjlan}43. ${color43}RustDesk リモート デスクトップ (サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker アクセラレーション ステーション${gl_kjlan}46. ${color46}GitHub アクセラレーション ステーション${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}プロメテウスの監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" + echo -e "${gl_kjlan}49. ${color49}Prometheus (コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" - echo -e "${gl_kjlan}53. ${color53}llama3チャットAIモデル${gl_kjlan}54. ${color54}AMHホストWebサイトビルディングマネジメントパネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー側)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット浸透(クライアント)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}deepseekチャットaiビッグモデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}IT-Toolsツールボックス" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}アストロボットチャットロボットフレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}libretvプライベート映画とテレビ${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" - echo -e "${gl_kjlan}75. ${color75}メロディーミュージックエルフ${gl_kjlan}76. ${color76}オンラインDOS古いゲーム" - echo -e "${gl_kjlan}77. ${color77}Thunder オフライン ダウンロード ツール${gl_kjlan}78. ${color78}Pandawikiインテリジェントドキュメント管理システム" + echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" + echo -e "${gl_kjlan}75. ${color75}メロディー音楽の魔法使い${gl_kjlan}76. ${color76}オンライン DOS 古いゲーム" + echo -e "${gl_kjlan}77. ${color77}Thunder オフライン ダウンロード ツール${gl_kjlan}78. ${color78}PandaWiki インテリジェント文書管理システム" echo -e "${gl_kjlan}79. ${color79}Beszel サーバーの監視${gl_kjlan}80. ${color80}リンクワーデンのブックマーク管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" - echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos Personal Financial Management Tools" - echo -e "${gl_kjlan}85. ${color85}Immich Picture Video Manager${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" - echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}独自の自己ホストのライブブロードキャストプラットフォーム" - echo -e "${gl_kjlan}89. ${color89}FileCodeBoxファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" + echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}Giteaプライベートコードリポジトリ${gl_kjlan}92. ${color92}FileBrowserファイルマネージャー" + echo -e "${gl_kjlan}91. ${color91}gitea プライベート コード リポジトリ${gl_kjlan}92. ${color92}FileBrowser ファイルマネージャー" echo -e "${gl_kjlan}93. ${color93}Dufs のミニマリスト静的ファイル サーバー${gl_kjlan}94. ${color94}Gopeed高速ダウンロードツール" - echo -e "${gl_kjlan}95. ${color95}ペーパーレスドキュメント管理プラットフォーム${gl_kjlan}96. ${color96}2FAuth セルフホスト型 2 段階認証システム" - echo -e "${gl_kjlan}97. ${color97}WireGuard ネットワーキング (サーバー)${gl_kjlan}98. ${color98}ワイヤガードネットワーキング(クライアント)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" + echo -e "${gl_kjlan}95. ${color95}ペーパーレス文書管理プラットフォーム${gl_kjlan}96. ${color96}2FAuth セルフホスト型 2 段階認証システム" + echo -e "${gl_kjlan}97. ${color97}WireGuard ネットワーキング (サーバー)${gl_kjlan}98. ${color98}WireGuard ネットワーキング (クライアント)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology 仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChatマルチプレイヤーオンラインチャットシステム" + echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat 複数人オンライン チャット システム" + echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリケーションデータを復元します" + echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -9033,7 +9033,7 @@ while true; do docker_rum() { read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "ログインユーザーのパスワードを設定します。" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9066,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "ネザを作る" + send_stats "ネザを構築する" local app_id="7" local docker_name="nezha-dashboard" @@ -9077,18 +9077,18 @@ while true; do clear echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" - echo "公式ウェブサイトの建設文書:https://nezha.wiki/guide/dashboard.html" + echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1。使用します" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -9145,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "郵便局を建設します" + send_stats "郵便局を建てる" clear install telnet local app_id="9" @@ -9164,9 +9164,9 @@ while true; do port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}ポート$port現在利用可能です${gl_bai}" + echo -e "${gl_lv}ポート$port現在利用可能${gl_bai}" else - echo -e "${gl_hong}ポート$port現在利用できません${gl_bai}" + echo -e "${gl_hong}ポート$port現在利用不可${gl_bai}" fi echo "" @@ -9181,18 +9181,18 @@ while true; do echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "たとえば、mail.yuming.comなど、電子メールドメイン名を設定してください。" yuming + read -e -p "電子メールのドメイン名を設定してください (例: mail.yuming.com)。" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "これらのDNSレコードを最初に解析します" + echo "まずこれらの DNS レコードを解析します" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -9202,7 +9202,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "任意のキーを押して続行します..." + echo "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install jq @@ -9221,9 +9221,9 @@ while true; do add_app_id clear - echo "Poste.ioがインストールされています" + echo "poste.ioがインストールされました" echo "------------------------" - echo "次のアドレスを使用してposte.ioにアクセスできます。" + echo "次のアドレスを使用して poste.io にアクセスできます。" echo "https://$yuming" echo "" @@ -9246,7 +9246,7 @@ while true; do add_app_id clear - echo "Poste.ioがインストールされています" + echo "poste.ioがインストールされました" echo "------------------------" echo "次のアドレスを使用して poste.io にアクセスできます。" echo "https://$yuming" @@ -9293,7 +9293,7 @@ while true; do clear ip_address - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -9411,7 +9411,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -9556,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "サンダープールを構築します" + send_stats "雷のプールを作る" local app_id="19" local docker_name=safeline-mgt @@ -9565,8 +9565,8 @@ while true; do check_docker_app clear echo -e "サンダープールサービス$check_docker" - echo "Lei Chiは、Changting Technologyによって開発されたWAFサイトファイアウォールプログラムパネルであり、自動防衛のために代理店サイトを逆転させることができます。" - echo "ビデオの紹介:https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo "Leichi は、Changting Technology によって開発された WAF サイト ファイアウォール プログラム パネルで、自動防御のためにサイトを反転できます。" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi @@ -9587,7 +9587,7 @@ while true; do add_app_id clear - echo "サンダープールWAFパネルがインストールされています" + echo "Leichi WAFパネルを導入しました" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -9600,7 +9600,7 @@ while true; do add_app_id clear - echo "サンダープールWAFパネルが更新されました" + echo "Leichi WAF パネルが更新されました" check_docker_app_ip ;; 3) @@ -9730,8 +9730,8 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーパスワードを設定します。" admin_password + read -e -p "ログインユーザー名を設定します:" admin + read -e -p "ログインユーザーのパスワードを設定します。" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -10276,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "インストール" + echo "インストール完了" check_docker_app_ip - echo "最初のユーザー名とパスワードは次のとおりです" + echo "初期のユーザー名とパスワードは次のとおりです: admin" } docker_app_update() { @@ -10296,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -10561,7 +10561,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -10590,10 +10590,10 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "インストール" + echo "インストール完了" check_docker_app_ip - echo "初期ユーザー名:admin" - echo "最初のパスワード:changeme" + echo "初期ユーザー名: admin" + echo "初期パスワード:ChangeMe" } @@ -10610,7 +10610,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -10673,7 +10673,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -10935,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "libretvログインパスワードを設定します。" app_passwd + read -e -p "LibreTV のログイン パスワードを設定します。" app_passwd docker run -d \ --name libretv \ @@ -10971,7 +10971,7 @@ while true; do docker_app_install() { read -e -p "ログインユーザー名を設定します:" admin read -e -p "ログインユーザーのパスワードを設定します。" admin_password - read -e -p "承認コードを入力してください:" shouquanma + read -e -p "認証コードを入力してください:" shouquanma mkdir -p /home/docker/moontv @@ -11074,7 +11074,7 @@ while true; do docker_rum() { - read -e -p "ログインユーザー名を設定します:" app_use + read -e -p "ログインユーザー名を設定します:" app_use read -e -p "ログインパスワードを設定します:" app_passwd docker run -d \ @@ -11176,7 +11176,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # ランダムキーとパスワードを生成します + # ランダムなキーとパスワードを生成する local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11185,7 +11185,7 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 管理者アカウント情報を追加します + # 管理者アカウント情報を追加する echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env @@ -11195,7 +11195,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11205,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 元の変数を保持します + # 元の変数を保持する source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11222,7 +11222,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11394,7 +11394,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11407,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11568,7 +11568,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "初期ユーザーまたは管理者を作成します。次のユーザー名とパスワード、およびあなたが管理者であるかどうかを設定してください。" + echo "初期ユーザーまたは管理者を作成します。以下のユーザー名とパスワード、および管理者であるかどうかを設定してください。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11758,7 +11758,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -11772,7 +11772,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11826,7 +11826,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "アプリはアンインストールされています" + echo "アプリがアンインストールされました" } docker_app_plus @@ -11846,7 +11846,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuardセグメントを入力してください(デフォルト10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -11916,18 +11916,18 @@ while true; do sleep 2 echo - echo -e "${gl_huang}すべてのクライアントQRコード構成:${gl_bai}" + echo -e "${gl_huang}すべてのクライアント QR コード構成:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo - echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" + echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}各クライアントのすべての出力を構成します。利用方法は以下の通りです。${gl_bai}" - echo -e "${gl_lv}1.携帯電話にWGのアプリをダウンロードして、上のQRコードをスキャンしてネットワークにすばやく接続します${gl_bai}" - echo -e "${gl_lv}2。Windowsクライアントをダウンロードし、構成コードをコピーしてネットワークに接続します。${gl_bai}" + echo -e "${gl_lv}1. 携帯電話に wg APP をダウンロードし、上の QR コードをスキャンして、すぐにインターネットに接続します。${gl_bai}" + echo -e "${gl_lv}2. Windows 用クライアントをダウンロードし、ネットワークに接続するための構成コードをコピーします。${gl_bai}" echo -e "${gl_lv}3. スクリプトを使用して Linux に WG クライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" - echo -e "${gl_lv}公式クライアントのダウンロード方法:https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}公式クライアントのダウンロード方法:https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11955,16 +11955,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # ディレクトリを作成する(存在しない場合) + # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" empty_line_count=0 - # ユーザーの入力を行ごとに読み取ります + # ユーザー入力を 1 行ずつ読み取ります while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -11977,7 +11977,7 @@ while true; do fi done - # 構成ファイルに書き込みます + # 設定ファイルの書き込み echo "$input" > "$CONFIG_FILE" echo "クライアント設定の保存場所$CONFIG_FILE" @@ -12025,7 +12025,7 @@ while true; do docker_app_install() { - read -e -p "CPUコアの数を設定します(デフォルト2):" CPU_CORES + read -e -p "CPU コアの数を設定します (デフォルトは 2)。" CPU_CORES local CPU_CORES=${CPU_CORES:-2} read -e -p "メモリ サイズを設定します (デフォルトは 4G):" RAM_SIZE @@ -12045,7 +12045,7 @@ while true; do docker compose up -d clear - echo "インストール" + echo "インストール完了" check_docker_app_ip } @@ -12165,6 +12165,47 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "インストール完了" + check_docker_app_ip + echo "初期ユーザー名: admin" + echo "初期パスワード:umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "アプリがアンインストールされました" + } + + docker_app_plus + + ;; + + b) clear @@ -12177,10 +12218,10 @@ while true; do while true; do clear echo "バックアップファイルが作成されました: /$backup_filename" - read -e -p "バックアップデータをリモートサーバーに転送しますか? (y/n):" choice + read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - read -e -p "リモートサーバーIPを入力してください:" remote_ip + read -e -p "リモートサーバーのIPを入力してください:" remote_ip read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} @@ -12210,8 +12251,8 @@ while true; do r) root_use - send_stats "すべてのアプリケーションが復元されます" - echo "利用可能なアプリのバックアップ" + send_stats "すべてのアプリを復元する" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12228,11 +12269,11 @@ while true; do fi if [ -n "$filename" ]; then - echo -e "${gl_huang}減圧が行われています$filename ...${gl_bai}" + echo -e "${gl_huang}解凍中$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "アプリケーションデータが復元されました。指定されたアプリケーションメニューを手動で入力し、アプリケーションを更新してアプリケーションを復元してください。" + echo "アプリケーションデータが復元されました。現在、アプリケーションを復元するには、手動で指定されたアプリケーションメニューに入り、アプリケーションを更新してください。" else - echo "圧縮パッケージは見つかりませんでした。" + echo "圧縮パッケージが見つかりませんでした。" fi ;; @@ -12257,28 +12298,28 @@ linux_work() { clear send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" - echo -e "このシステムは、バックエンドで実行できるワークスペースを提供し、長期タスクを実行するために使用できます。" + echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入った後、Ctrl+Bを使用してDを押してワークスペースを終了します!" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" - echo "現在既存のワークスペースのリスト" + echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}ワークスペース番号1" - echo -e "${gl_kjlan}2. ${gl_bai}ワークスペースNo. 2" - echo -e "${gl_kjlan}3. ${gl_bai}ワークスペース番号3" + echo -e "${gl_kjlan}1. ${gl_bai}作業エリア1" + echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" + echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo. 5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" - echo -e "${gl_kjlan}8. ${gl_bai}ワークスペースNo. 8" + echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" - echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを注入します" + echo -e "${gl_kjlan}23. ${gl_bai}バックグラウンドワークスペースにコマンドを挿入する" echo -e "${gl_kjlan}24. ${gl_bai}指定したワークスペースを削除します" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" @@ -12291,7 +12332,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; @@ -12313,7 +12354,7 @@ linux_work() { clear install tmux local SESSION_NAME="work4" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 5) @@ -12327,14 +12368,14 @@ linux_work() { clear install tmux local SESSION_NAME="work6" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; 8) @@ -12355,7 +12396,7 @@ linux_work() { clear install tmux local SESSION_NAME="work10" - send_stats "ワークスペースを開始します$SESSION_NAME" + send_stats "ワークスペースの開始$SESSION_NAME" tmux_run ;; @@ -12373,15 +12414,15 @@ linux_work() { echo "------------------------" echo "1. オン 2. オフ" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" gongzuoqu_del + read -e -p "選択肢を入力してください:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "ワークスペースを開始します$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\ n#tmuxセッション\ nif [[-z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "ワークスペースの開始$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自動的に tmux セッションに入ります\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -12404,13 +12445,13 @@ linux_work() { 23) - read -e -p "次のようなバックグラウンドで実行するコマンドを入力してください:curl -fssl https://get.docker.com SH:" tmuxd + read -e -p "バックグラウンドで実行するコマンドを入力してください。たとえば、curl -fsSL https://get.docker.com |し:" tmuxd tmux_run_d send_stats "バックグラウンドワークスペースにコマンドを挿入する" ;; 24) - read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name + read -e -p "削除するワークスペースの名前を入力してください:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name send_stats "ワークスペースの削除" ;; @@ -12419,7 +12460,7 @@ linux_work() { kejilion ;; *) - echo "無効な入力!" + echo "無効な入力です!" ;; esac break_end @@ -12444,38 +12485,38 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 + # send_stats 「システムツール」 echo -e "システムツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}スクリプトの起動ショートカットキーを設定します${gl_kjlan}2. ${gl_bai}ログインパスワードを変更します" - echo -e "${gl_kjlan}3. ${gl_bai}ルートパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンのPythonをインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" - echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリック再インストールシステム${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ルートアカウントを無効にして新しいアカウントを作成します${gl_kjlan}10. ${gl_bai}優先順位IPv4/IPv6を切り替えます" + echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" + echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}ポートの職業ステータスを確認してください${gl_kjlan}12. ${gl_bai}仮想メモリサイズを変更します" - echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワードジェネレーター" - echo -e "${gl_kjlan}15. ${gl_bai}システムタイムゾーンの調整${gl_kjlan}16. ${gl_bai}BBR3アクセラレーションの設定" + echo -e "${gl_kjlan}11. ${gl_bai}ポートの占有状況を確認する${gl_kjlan}12. ${gl_bai}仮想メモリのサイズを変更する" + echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワード生成器" + echo -e "${gl_kjlan}15. ${gl_bai}システムのタイムゾーン調整${gl_kjlan}16. ${gl_bai}BBR3アクセラレーションの設定" echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール アドバンスト マネージャー${gl_kjlan}18. ${gl_bai}ホスト名の変更" - echo -e "${gl_kjlan}19. ${gl_bai}システムの更新ソースを切り替えます${gl_kjlan}20. ${gl_bai}タイミングタスク管理" + echo -e "${gl_kjlan}19. ${gl_bai}システムアップデート元の切り替え${gl_kjlan}20. ${gl_bai}スケジュールされたタスクの管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト解像度${gl_kjlan}22. ${gl_bai}SSH防御プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限の自動シャットダウン${gl_kjlan}24. ${gl_bai}ROOT秘密鍵ログインモード" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限自動シャットダウン${gl_kjlan}24. ${gl_bai}ROOT秘密鍵ログインモード" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot システムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSH の高リスク脆弱性を修正" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linuxカーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムにおけるカーネルパラメーターの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux カーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムのカーネルパラメータの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替える${gl_kjlan}32. ${gl_bai}コマンドラインの美化ツール${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}システムのごみ箱をセットアップする${gl_kjlan}34. ${gl_bai}システムのバックアップと回復" + echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替える${gl_kjlan}32. ${gl_bai}コマンドライン美化ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}システムのごみ箱をセットアップする${gl_kjlan}34. ${gl_bai}システムのバックアップとリカバリ" echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}rsync リモート同期ツール" echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップシステムの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップのシステムチューニング${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" - echo -e "${gl_kjlan}101. ${gl_bai}Kコマンドの高度な使用${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}テックライオンスクリプトをアンインストールします" + echo -e "${gl_kjlan}101. ${gl_bai}k コマンドの高度な使用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Tech Lion スクリプトをアンインストールする" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻ります" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" sub_choice @@ -12490,7 +12531,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "ショートカットキーが設定されています" + echo "ショートカットキーが設定されている" send_stats "スクリプトのショートカットキーが設定されました" break_end linux_Settings @@ -12500,7 +12541,7 @@ linux_Settings() { 2) clear send_stats "ログインパスワードを設定する" - echo "ログインパスワードを設定します" + echo "ログインパスワードを設定する" passwd ;; 3) @@ -12511,18 +12552,18 @@ linux_Settings() { 4) root_use - send_stats "Pyバージョン管理" + send_stats "pyのバージョン管理" echo "Pythonのバージョン管理" echo "ビデオ紹介: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "この機能は、Pythonが正式にサポートするバージョンをシームレスにインストールします!" + echo "この機能を使用すると、Python で公式にサポートされているバージョンをシームレスにインストールできます。" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推奨バージョン:3.12 3.11 3.10 3.9 3.8 2.7" - echo "クエリの詳細:https://www.python.org/downloads/" + echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" - read -e -p "インストールするpythonバージョン番号を入力します(0を入力して終了します):" py_new_v + read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v if [[ "$py_new_v" == "0" ]]; then @@ -12559,7 +12600,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "不明なパッケージマネージャー!" + echo "不明なパッケージマネージャーです!" return fi @@ -12589,7 +12630,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" - send_stats "スイッチスクリプトPyバージョン" + send_stats "スクリプトPYバージョン切り替え" ;; @@ -12612,14 +12653,14 @@ EOF # 現在の SSH ポート番号を読み取ります local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 現在のSSHポート番号を印刷します + # 現在の SSH ポート番号を出力する echo -e "現在の SSH ポート番号は次のとおりです。${gl_huang}$current_port ${gl_bai}" echo "------------------------" echo "ポート番号の範囲は 1 ~ 65535 です (終了するには 0 を入力します)。" - # ユーザーに新しいSSHポート番号を入力するように促します - read -e -p "新しいSSHポート番号を入力してください:" new_port + # 新しい SSH ポート番号の入力をユーザーに求める + read -e -p "新しい SSH ポート番号を入力してください:" new_port # ポート番号が有効な範囲内であるかどうかを確認します。 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 @@ -12627,11 +12668,11 @@ EOF send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSHポート変更を終了します" + send_stats "SSHポート変更の終了" break else - echo "ポート番号は無効です。1〜65535の数字を入力してください。" - send_stats "無効なSSHポート入力" + echo "ポート番号が無効です。 1 ~ 65535 の数字を入力してください。" + send_stats "無効な SSH ポートが入力されました" break_end fi else @@ -12656,7 +12697,7 @@ EOF 9) root_use send_stats "新規ユーザーの root を無効にする" - read -e -p "新しいユーザー名を入力してください(出口に0を入力してください):" new_username + read -e -p "新しいユーザー名を入力してください (終了するには 0 を入力してください):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -12677,7 +12718,7 @@ EOF 10) root_use - send_stats "V4/V6の優先度を設定します" + send_stats "v4/v6 の優先順位を設定する" while true; do clear echo "v4/v6 の優先順位を設定する" @@ -12687,7 +12728,7 @@ EOF if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "現在のネットワーク優先設定:${gl_huang}IPv4${gl_bai}優先度" else - echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" + echo -e "現在のネットワーク優先設定:${gl_huang}IPv6${gl_bai}優先度" fi echo "" @@ -12707,8 +12748,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -12743,20 +12784,20 @@ EOF echo -e "現在の仮想メモリ:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1。1024Mの割り当て2。2048m3を割り当てます。4096m4。カスタムサイズを割り当てます" + echo "1. 1024M の割り当て 2. 2048M の割り当て 3. 4096M の割り当て 4. カスタム サイズ" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case "$choice" in 1) - send_stats "1G仮想メモリが設定されています" + send_stats "1Gの仮想メモリが設定されています" add_swap 1024 ;; 2) - send_stats "2G仮想メモリが設定されています" + send_stats "2Gの仮想メモリが設定されています" add_swap 2048 ;; @@ -12769,7 +12810,7 @@ EOF 4) read -e -p "仮想メモリ サイズ (単位 M) を入力してください:" new_swap add_swap "$new_swap" - send_stats "カスタム仮想メモリが設定されています" + send_stats "カスタム仮想メモリセット" ;; *) @@ -12796,7 +12837,7 @@ EOF echo "" echo "アカウント操作" echo "------------------------" - echo "1.通常のアカウントを作成する2。プレミアムアカウントを作成します" + echo "1. 通常アカウントを作成する 2. プレミアムアカウントを作成する" echo "------------------------" echo "3. 最高の権限を付与する 4. 最高の権限を削除する" echo "------------------------" @@ -12809,7 +12850,7 @@ EOF case $sub_choice in 1) # ユーザーに新しいユーザー名の入力を求める - read -e -p "新しいユーザー名を入力してください:" new_username + read -e -p "新しいユーザー名を入力してください:" new_username # 新しいユーザーを作成してパスワードを設定する useradd -m -s /bin/bash "$new_username" @@ -12822,21 +12863,21 @@ EOF # ユーザーに新しいユーザー名の入力を求める read -e -p "新しいユーザー名を入力してください:" new_username - # 新しいユーザーを作成し、パスワードを設定します + # 新しいユーザーを作成してパスワードを設定する useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 新規ユーザーのsudo許可を付与します + # 新しいユーザーに sudo 権限を付与します echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo - echo "操作が完了しました。" + echo "操作は完了です。" ;; 3) read -e -p "ユーザー名を入力してください:" username - # 新規ユーザーのsudo許可を付与します + # 新しいユーザーに sudo 権限を付与します echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12862,16 +12903,16 @@ EOF 14) clear - send_stats "ユーザー情報ジェネレーター" + send_stats "ユーザー情報ジェネレータ" echo "ランダムなユーザー名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "ランダムユーザー名$i: $username" + echo "ランダムなユーザー名$i: $username" done echo "" - echo "ランダム名" + echo "ランダムな名前" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") @@ -12885,7 +12926,7 @@ EOF done echo "" - echo "ランダムuuid" + echo "ランダムな UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) @@ -12901,7 +12942,7 @@ EOF done echo "" - echo "32ビットランダムパスワード" + echo "32ビットのランダムなパスワード" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) @@ -12918,30 +12959,30 @@ EOF clear echo "システム時刻情報" - # 現在のシステムタイムゾーンを取得します + # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時間を取得します + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # タイムゾーンと時間を表示します + # タイムゾーンと時間を表示する echo "現在のシステムのタイムゾーン:$timezone" echo "現在のシステム時間:$current_time" echo "" - echo "タイムゾーンの切り替え" + echo "タイムゾーンスイッチ" echo "------------------------" echo "アジア" echo "1. 中国上海時間 2. 中国香港時間" - echo "3。日本の東京時間4。韓国のソウル時間" + echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" - echo "7。アラブ首長国連邦のドバイ時間8。オーストラリアのシドニー時間" - echo "9。タイのバンコクでの時間" + echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" - echo "13。ベルリン・タイム、ドイツ14。モスクワ・タイム、ロシア" - echo "15。オランダのユトレヒト時間16。スペインでのマドリード時間" + echo "13. ベルリン、ドイツ時間 14. モスクワ、ロシア時間" + echo "15. ユトラハト時間、オランダ 16. マドリッド時間、スペイン" echo "------------------------" echo "アメリカ" echo "21. 米国西部時間 22. 米国東部時間" @@ -12950,7 +12991,7 @@ EOF echo "------------------------" echo "31. UTC 世界標準時" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice @@ -12995,7 +13036,7 @@ EOF 18) root_use - send_stats "ホスト名を変更します" + send_stats "ホスト名の変更" while true; do clear @@ -13009,7 +13050,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian、Ubuntu、Centosなどの他のシステム。 + # Debian、Ubuntu、CentOS などのその他のシステム hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13027,11 +13068,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "ホスト名は次のように変更されています。$new_hostname" + echo "ホスト名は次のように変更されました。$new_hostname" send_stats "ホスト名が変更されました" sleep 1 else - echo "終了すると、ホスト名は変更されていません。" + echo "ホスト名を変更せずに終了しました。" break fi done @@ -13041,14 +13082,14 @@ EOF root_use send_stats "システムアップデートソースを変更する" clear - echo "更新ソース領域を選択します" + echo "更新元リージョンの選択" echo "LinuxMirror にアクセスしてシステム アップデート ソースを切り替える" echo "------------------------" echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "あなたの選択を入力してください:" choice + read -e -p "選択内容を入力してください:" choice case $choice in 1) @@ -13060,7 +13101,7 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外起源" + send_stats "海外情報源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; *) @@ -13072,7 +13113,7 @@ EOF ;; 20) - send_stats "タイミングタスク管理" + send_stats "スケジュールされたタスクの管理" while true; do clear check_crontab_installed @@ -13080,26 +13121,26 @@ EOF echo "スケジュールされたタスクのリスト" crontab -l echo "" - echo "動作します" + echo "操作する" echo "------------------------" echo "1. スケジュールされたタスクを追加します。 2. スケジュールされたタスクを削除します。 3. スケジュールされたタスクを編集します。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" sub_choice + read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in 1) read -e -p "新しいタスクの実行コマンドを入力してください:" newquest echo "------------------------" echo "1. 月次タスク 2. 週次タスク" - echo "3。毎日のタスク4。時間ごとのタスク" + echo "3. 毎日のタスク 4. 時間ごとのタスク" echo "------------------------" - read -e -p "選択を入力してください:" dingshi + read -e -p "選択肢を入力してください:" dingshi case $dingshi in 1) - read -e -p "毎月何日を選択してタスクを実行しますか? (1-30):" day + read -e -p "タスクを実行する日は月の何日ですか? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -13111,19 +13152,19 @@ EOF (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "タスクを実行するために時間の何時間を入力しますか? (分、0-60):" minute + read -e -p "タスクを実行する時間を入力してください。 (分、0 ~ 60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "タイムされたタスクを追加します" + send_stats "スケジュールされたタスクを追加する" ;; 2) - read -e -p "削除する必要があるキーワードを入力してください。" kquest + read -e -p "削除するタスクのキーワードを入力してください:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "タイミングタスクを削除します" + send_stats "スケジュールされたタスクを削除する" ;; 3) crontab -e @@ -13142,15 +13183,15 @@ EOF send_stats "ローカルホストの解決" while true; do clear - echo "ネイティブホストのペルシングリスト" + echo "ネイティブホスト解決リスト" echo "ここに解析一致を追加すると、動的解析は使用されなくなります" cat /etc/hosts echo "" echo "操作する" echo "------------------------" - echo "1.新しい解析2を追加します。解析アドレスを削除します" + echo "1. 新しい解決策を追加 2. 解決策アドレスを削除" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" host_dns @@ -13158,7 +13199,7 @@ EOF 1) read -e -p "新しい解析レコード形式を入力してください: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホストの解析が追加されました" + send_stats "ローカルホスト解像度が追加されました" ;; 2) @@ -13180,15 +13221,15 @@ EOF check_f2b_status echo -e "SSH防御プログラム$check_f2b_status" - echo "Fail2banは、ブルートフォースを防ぐためのSSHツールです" - echo "公式ウェブサイトの紹介:${gh_proxy}github.com/fail2ban/fail2ban" + echo "failed2ban はブルート フォース クラッキングを防ぐ SSH ツールです" + echo "公式サイト紹介:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" echo "1. 防御プログラムをインストールする" echo "------------------------" - echo "2。SSH傍受記録を表示します" - echo "3。リアルタイムログ監視" + echo "2. SSH インターセプト記録の表示" + echo "3. リアルタイムログ監視" echo "------------------------" - echo "9.防衛プログラムをアンインストールします" + echo "9. 防御プログラムをアンインストールする" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -13214,7 +13255,7 @@ EOF 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2Ban防衛プログラムがアンインストールされています" + echo "Fail2Ban 防御プログラムがアンインストールされました" break ;; *) @@ -13233,36 +13274,36 @@ EOF echo "電流制限シャットダウン機能" echo "ビデオ紹介: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "現在のトラフィックの使用、サーバートラフィックの計算の再起動がクリアされます!" + echo "現在のトラフィック使用量は、サーバーが再起動されるとクリアされます。" output_status - echo -e "${gl_kjlan}合計受信:${gl_bai}$rx" - echo -e "${gl_kjlan}合計送信:${gl_bai}$tx" + echo -e "${gl_kjlan}受け取った合計:${gl_bai}$rx" + echo -e "${gl_kjlan}送信合計:${gl_bai}$tx" - # limiting_shut_down.shファイルが存在するかどうかを確認してください + # Limiting_Shut_down.sh ファイルが存在するかどうかを確認します if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gbの値を取得します + # しきい値_gbの値を取得する local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}現在のセットエントリステーション電流制限しきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}現在のアウトバウンド電流制限しきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo echo "------------------------------------------------" - echo "システムは、実際のトラフィックが毎分でしきい値に達するかどうかを検出し、サーバーが到着した後にサーバーが自動的にシャットダウンされます!" + echo "システムは実際のトラフィックがしきい値に達したかどうかを毎分検出し、しきい値に達するとサーバーを自動的にシャットダウンします。" echo "------------------------" echo "1. 電流制限シャットダウン機能を有効にする 2. 電流制限シャットダウン機能を無効にする" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" Limiting + read -e -p "選択肢を入力してください:" Limiting case "$Limiting" in 1) - # 新しい仮想メモリサイズを入力します - echo "実際のサーバーに100gのトラフィックがある場合、しきい値を95gに設定し、事前に電源をシャットダウンして、トラフィックエラーやオーバーフローを回避できます。" + # 新しい仮想メモリ サイズを入力してください + echo "実際のサーバーのトラフィックが 100G しかない場合は、しきい値を 95G に設定し、事前にシャットダウンして、トラフィック エラーやオーバーフローを回避できます。" read -e -p "受信トラフィックのしきい値を入力してください (単位は G、デフォルトは 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "送信トラフィックのしきい値を入力してください (単位は G、デフォルトは 100G):" tx_threshold_gb @@ -13280,8 +13321,8 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "現在の制限シャットダウンが設定されています" - send_stats "現在の制限シャットダウンが設定されています" + echo "電流制限シャットダウンが設定されています" + send_stats "電流制限シャットダウンが設定されています" ;; 2) check_crontab_installed @@ -13301,40 +13342,40 @@ EOF 24) root_use - send_stats "秘密キーログイン" + send_stats "秘密キーによるログイン" while true; do clear - echo "ルート秘密キーログインモード" + echo "ROOT秘密鍵ログインモード" echo "ビデオ紹介: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" echo "------------------------" echo "1. 新しいキーを生成します。 2. 既存のキーをインポートします。 3. ローカルキーを表示します。" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" host_dns + read -e -p "選択肢を入力してください:" host_dns case $host_dns in 1) - send_stats "新しいキーを生成します" + send_stats "新しいキーを生成する" add_sshkey break_end ;; 2) - send_stats "既存の公開キーをインポートします" + send_stats "既存の公開キーをインポートする" import_sshkey break_end ;; 3) - send_stats "地元の秘密の鍵を表示します" + send_stats "ローカルキーを表示する" echo "------------------------" echo "公開鍵情報" cat ~/.ssh/authorized_keys echo "------------------------" - echo "秘密のキー情報" + echo "秘密鍵情報" cat ~/.ssh/sshkey echo "------------------------" break_end @@ -13350,14 +13391,14 @@ EOF 25) root_use - send_stats "電報警告" + send_stats "電報警報" echo "TG-bot監視・早期警告機能" echo "動画紹介:https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "ローカル CPU、メモリ、ハードディスク、トラフィック、SSH ログインのリアルタイム監視とアラートを実現するには、tg robot API とアラートを受信するユーザー ID を設定する必要があります。" - echo "しきい値に達した後、ユーザーはユーザーに送信されます" + echo "しきい値に達すると、警告メッセージがユーザーに送信されます。" echo -e "${gl_hui}- 通信量についてはサーバーを再起動すると再計算されます -${gl_bai}" - read -e -p "必ず続けますか? (y/n):" choice + read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in [Yy]) @@ -13395,20 +13436,20 @@ EOF clear echo "TG-bot早期警戒システムが作動しました" - echo -e "${gl_hui}他のマシンのルートディレクトリにTG-Check-notify.sh警告ファイルを配置して、直接使用することもできます。${gl_bai}" + echo -e "${gl_hui}TG-check-notify.sh 警告ファイルを他のマシンのルート ディレクトリに置き、それを直接使用することもできます。${gl_bai}" ;; [Nn]) echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; 26) root_use - send_stats "SSHの高リスクの脆弱性を修正します" + send_stats "高リスクの SSH 脆弱性を修正する" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -13476,9 +13517,9 @@ EOF 41) clear send_stats "掲示板" - echo "公式のメッセージ技術委員会ライオンをご覧ください。スクリプトについて何かアイデアがある場合は、メッセージを残してコミュニケーションをとってください!" + echo "Technology Lion の公式掲示板をご覧ください。脚本についてのアイデアがあれば、メッセージを残して交換してください。" echo "https://board.kejilion.pro" - echo "パスワード:kejilion.sh" + echo "公開パスワード: kejilion.sh" ;; 66) @@ -13487,16 +13528,16 @@ EOF send_stats "ワンストップチューニング" echo "ワンストップのシステムチューニング" echo "------------------------------------------------" - echo "以下が操作され、最適化されます" - echo "1.システムを最新の状態に更新します" - echo "2。システムジャンクファイルをクリーンアップします" + echo "以下のコンテンツを運用・最適化していきます" + echo "1. システムを最新のものにアップデートします" + echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo -e "5.すべてのポートを開きます" - echo -e "6。電源を入れます${gl_huang}BBR${gl_bai}加速する" - echo -e "7.タイムゾーンをに設定します${gl_huang}上海${gl_bai}" - echo -e "8。DNSアドレスを自動的に最適化します${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" - echo -e "9.基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "6.電源を入れます${gl_huang}BBR${gl_bai}加速する" + echo -e "7. タイムゾーンを次のように設定します。${gl_huang}上海${gl_bai}" + echo -e "8. DNS アドレスを自動的に最適化する${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" + echo -e "9. 基本ツールのインストール${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "10. Linux システムのカーネル パラメータの最適化が次のように切り替わります。${gl_huang}バランスのとれた最適化モード${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスを実行してもよろしいですか? (はい/いいえ):" choice @@ -13507,7 +13548,7 @@ EOF send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10。システムを最新の状態に更新します" + echo -e "[${gl_lv}OK${gl_bai}】1/10。システムを最新のものにアップデートする" echo "------------------------------------------------" linux_clean @@ -13515,18 +13556,18 @@ EOF echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10。仮想メモリを設定します${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】3/10。仮想メモリを設定する${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port echo -e "[${gl_lv}OK${gl_bai}】4/10。 SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10。すべてのポートを開きます" + echo -e "[${gl_lv}OK${gl_bai}】5/10。すべてのポートを開く" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10。開ける${gl_huang}BBR${gl_bai}加速する" + echo -e "[${gl_lv}OK${gl_bai}】6/10。開ける${gl_huang}BBR${gl_bai}加速する" echo "------------------------------------------------" set_timedate Asia/Shanghai @@ -13552,13 +13593,13 @@ EOF echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10。基本ツールをインストールします${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】9/10。基本的なツールをインストールする${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced echo -e "[${gl_lv}OK${gl_bai}】10/10。 Linuxシステムのカーネルパラメータの最適化" - echo -e "${gl_lv}ワンストップシステムのチューニングが完了しました${gl_bai}" + echo -e "${gl_lv}ワンストップでのシステムチューニングが完了${gl_bai}" ;; [Nn]) @@ -13595,10 +13636,10 @@ EOF echo "------------------------------------------------" echo -e "現在のステータス:$status_message" echo "--------------------" - echo "1。コレクションをオンにします" + echo "1.収集を開始する" echo "2. コレクションを閉じる" echo "--------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "--------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -13607,13 +13648,13 @@ EOF sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh echo "収集が開始されました" - send_stats "プライバシーとセキュリティコレクションが有効になっています" + send_stats "プライバシーとセキュリティの収集がオンになっています" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "コレクションは閉じた" + echo "コレクションは終了しました" send_stats "プライバシーとセキュリティの収集がオフになっています" ;; *) @@ -13633,7 +13674,7 @@ EOF send_stats "Tech Lion スクリプトをアンインストールする" echo "Tech Lion スクリプトをアンインストールする" echo "------------------------------------------------" - echo "Kejilionスクリプトを完全にアンインストールし、他の機能には影響しません" + echo "kejilion スクリプトは、他の機能に影響を与えることなく完全にアンインストールされます。" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice case "$choice" in @@ -13642,7 +13683,7 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "スクリプトはアンインストールされています、さようなら!" + echo "スクリプトはアンインストールされました、さようなら!" break_end clear exit @@ -13651,7 +13692,7 @@ EOF echo "キャンセル" ;; *) - echo "無効な選択、yまたはnを入力してください。" + echo "選択が無効です。Y または N を入力してください。" ;; esac ;; @@ -13692,125 +13733,125 @@ linux_file() { echo "1. ディレクトリを入力します。 2. ディレクトリを作成します。 3. ディレクトリのアクセス許可を変更します。 4. ディレクトリの名前を変更します。" echo "5. ディレクトリを削除します。 6. 前のメニュー ディレクトリに戻ります。" echo "------------------------" - echo "11。ファイルを作成する12。ファイル13を編集します。ファイル許可を変更14。ファイルの名前を変更します" - echo "15.ファイルを削除します" + echo "11. ファイルの作成 12. ファイルの編集 13. ファイル権限の変更 14. ファイル名の変更" + echo "15. ファイルの削除" echo "------------------------" echo "21. ファイル ディレクトリの圧縮 22. ファイル ディレクトリの解凍 23. ファイル ディレクトリの移動 24. ファイル ディレクトリのコピー" - echo "25。ファイルを別のサーバーに渡します" + echo "25. 他のサーバーにファイルを転送する" echo "------------------------" - echo "0。前のメニューに戻ります" + echo "0. 前のメニューに戻る" echo "------------------------" read -e -p "選択肢を入力してください:" Limiting case "$Limiting" in 1) # 进入目录 read -e -p "ディレクトリ名を入力してください:" dirname - cd "$dirname" 2>/dev/null || echo "ディレクトリを入力できません" + cd "$dirname" 2>/dev/null || echo "ディレクトリに入れません" send_stats "ディレクトリを入力してください" ;; 2) # 创建目录 - read -e -p "作成するにはディレクトリ名を入力してください。" dirname - mkdir -p "$dirname" && echo "作成されたディレクトリ" || echo "作成に失敗しました" - send_stats "ディレクトリを作成します" + read -e -p "作成するディレクトリ名を入力してください:" dirname + mkdir -p "$dirname" && echo "ディレクトリが作成されました" || echo "作成に失敗しました" + send_stats "ディレクトリの作成" ;; 3) # 修改目录权限 - read -e -p "ディレクトリ名を入力してください:" dirname - read -e -p "許可(755など)を入力してください。" perm + read -e -p "ディレクトリ名を入力してください:" dirname + read -e -p "権限を入力してください (例: 755):" perm chmod "$perm" "$dirname" && echo "権限が変更されました" || echo "変更に失敗しました" send_stats "ディレクトリの権限を変更する" ;; 4) # 重命名目录 - read -e -p "現在のディレクトリ名を入力してください:" current_name - read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前変更に失敗しました" - send_stats "ディレクトリの名前を変更します" + read -e -p "現在のディレクトリ名を入力してください:" current_name + read -e -p "新しいディレクトリ名を入力してください:" new_name + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前の変更に失敗しました" + send_stats "ディレクトリの名前を変更する" ;; 5) # 删除目录 - read -e -p "削除するには、ディレクトリ名を入力してください。" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除が失敗しました" + read -e -p "削除するディレクトリ名を入力してください:" dirname + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除に失敗しました" send_stats "ディレクトリを削除する" ;; 6) # 返回上一级选单目录 cd .. - send_stats "前のメニューディレクトリに戻ります" + send_stats "前のメニュー ディレクトリに戻る" ;; 11) # 创建文件 - read -e -p "作成するにはファイル名を入力してください。" filename + read -e -p "作成するファイル名を入力してください:" filename touch "$filename" && echo "ファイルが作成されました" || echo "作成に失敗しました" send_stats "ファイルの作成" ;; 12) # 编辑文件 - read -e -p "編集するにはファイル名を入力してください:" filename + read -e -p "編集するファイル名を入力してください:" filename install nano nano "$filename" - send_stats "ファイルを編集します" + send_stats "ファイルを編集する" ;; 13) # 修改文件权限 - read -e -p "ファイル名を入力してください:" filename + read -e -p "ファイル名を入力してください:" filename read -e -p "権限を入力してください (例: 755):" perm chmod "$perm" "$filename" && echo "権限が変更されました" || echo "変更に失敗しました" - send_stats "ファイル権限を変更します" + send_stats "ファイル権限を変更する" ;; 14) # 重命名文件 - read -e -p "現在のファイル名を入力してください:" current_name + read -e -p "現在のファイル名を入力してください:" current_name read -e -p "新しいファイル名を入力してください:" new_name mv "$current_name" "$new_name" && echo "ファイル名が変更されました" || echo "名前の変更に失敗しました" send_stats "ファイル名の変更" ;; 15) # 删除文件 read -e -p "削除するファイル名を入力してください:" filename - rm -f "$filename" && echo "削除されたファイル" || echo "削除が失敗しました" + rm -f "$filename" && echo "ファイルが削除されました" || echo "削除に失敗しました" send_stats "ファイルの削除" ;; 21) # 压缩文件/目录 - read -e -p "圧縮するには、ファイル/ディレクトリ名を入力してください。" name + read -e -p "圧縮するファイル/ディレクトリ名を入力してください:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "圧縮$name.tar.gz" || echo "圧縮に失敗しました" + tar -czvf "$name.tar.gz" "$name" && echo "に圧縮$name.tar.gz" || echo "圧縮に失敗しました" send_stats "圧縮ファイル/ディレクトリ" ;; 22) # 解压文件/目录 - read -e -p "ファイル名(.tar.gz)を入力してください:" filename + read -e -p "抽出するファイル名 (.tar.gz) を入力してください:" filename install tar tar -xzvf "$filename" && echo "解凍された$filename" || echo "解凍に失敗しました" - send_stats "ファイル/ディレクトリを解凍します" + send_stats "ファイル/ディレクトリを解凍する" ;; 23) # 移动文件或目录 - read -e -p "移動するには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "移動するファイルまたはディレクトリのパスを入力してください:" src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:ファイルまたはディレクトリは存在しません" + echo "エラー: ファイルまたはディレクトリが存在しません。" + send_stats "ファイルまたはディレクトリの移動に失敗しました: ファイルまたはディレクトリが存在しません" continue fi - read -e -p "ターゲットパス(新しいファイル名またはディレクトリ名を含む)を入力してください。" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" - send_stats "ファイルまたはディレクトリの移動に失敗しました:宛先パスが指定されていません" + send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" continue fi - mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリの移動先$dest_path" || echo "ファイルやディレクトリの移動に失敗しました" + mv "$src_path" "$dest_path" && echo "ファイルまたはディレクトリの移動先$dest_path" || echo "ファイルまたはディレクトリの移動に失敗しました" send_stats "ファイルまたはディレクトリを移動する" ;; 24) # 复制文件目录 - read -e -p "コピーするには、ファイルまたはディレクトリパスを入力してください。" src_path + read -e -p "コピーするファイルまたはディレクトリのパスを入力してください:" src_path if [ ! -e "$src_path" ]; then - echo "エラー:ファイルまたはディレクトリは存在しません。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:ファイルまたはディレクトリが存在しません" + echo "エラー: ファイルまたはディレクトリが存在しません。" + send_stats "ファイルまたはディレクトリのコピーに失敗しました: ファイルまたはディレクトリが存在しません" continue fi read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" - send_stats "ファイルまたはディレクトリのコピーに失敗しました:宛先パスが指定されていない" + send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" continue fi - # -Rオプションを使用して、ディレクトリを再帰的にコピーします + # -r オプションを使用してディレクトリを再帰的にコピーします cp -r "$src_path" "$dest_path" && echo "コピー先のファイルまたはディレクトリ$dest_path" || echo "ファイルまたはディレクトリのコピーに失敗しました" send_stats "ファイルまたはディレクトリをコピーする" ;; @@ -13819,15 +13860,15 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "転送するファイル パスを入力してください:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "エラー:ファイルは存在しません。" - send_stats "ファイルの転送に失敗しました:ファイルは存在しません" + echo "エラー: ファイルが存在しません。" + send_stats "ファイルの転送に失敗しました: ファイルが存在しません" continue fi read -e -p "リモートサーバーのIPを入力してください:" remote_ip if [ -z "$remote_ip" ]; then echo "エラー: リモート サーバーの IP を入力してください。" - send_stats "ファイル転送に失敗しました:リモートサーバーIPは入力されませんでした" + send_stats "ファイル転送に失敗しました: リモート サーバー IP が入力されていません" continue fi @@ -13838,14 +13879,14 @@ linux_file() { echo if [ -z "$remote_password" ]; then echo "エラー: リモート サーバーのパスワードを入力してください。" - send_stats "ファイル転送の失敗:リモートサーバーパスワードが入力されていません" + send_stats "ファイル転送に失敗しました: リモートサーバーのパスワードが入力されていません" continue fi read -e -p "ログイン ポートを入力してください (デフォルトは 22):" remote_port remote_port=${remote_port:-22} - # 既知のホストの古いエントリをクリアします + # 既知のホストの古いエントリをクリアする ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 @@ -13855,8 +13896,8 @@ $remote_password EOF if [ $? -eq 0 ]; then - echo "このファイルは、リモートサーバーホームディレクトリに転送されました。" - send_stats "ファイル転送に正常に転送します" + echo "ファイルはリモート サーバーのホーム ディレクトリに転送されました。" + send_stats "ファイル転送が成功しました" else echo "ファイル転送に失敗しました。" send_stats "ファイル転送に失敗しました" @@ -13899,7 +13940,7 @@ run_commands_on_servers() { local SERVERS_FILE="$HOME/cluster/servers.py" local SERVERS=$(grep -oP '{"name": "\K[^"]+|"hostname": "\K[^"]+|"port": \K[^,]+|"username": "\K[^"]+|"password": "\K[^"]+' "$SERVERS_FILE") - # 抽出された情報を配列に変換します + # 抽出した情報を配列に変換する IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" # サーバーを横断してコマンドを実行する @@ -13932,19 +13973,19 @@ fi while true; do clear - send_stats "クラスター制御センター" + send_stats "クラスターコントロールセンター" echo "サーバークラスタ制御" cat ~/cluster/servers.py echo echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" - echo -e "${gl_kjlan}1. ${gl_bai}サーバーを追加します${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーを編集します" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元します" + echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}バッチでタスクを実行します${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定します${gl_kjlan}18. ${gl_bai}すべてのポートを開きます${gl_kjlan}51. ${gl_bai}カスタムコマンド" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -13954,10 +13995,10 @@ while true; do 1) send_stats "クラスターサーバーの追加" read -e -p "サーバー名:" server_name - read -e -p "サーバーIP:" server_ip - read -e -p "サーバーポート(22):" server_port + read -e -p "サーバーIP:" server_ip + read -e -p "サーバーポート (22):" server_port local server_port=${server_port:-22} - read -e -p "サーバーユーザー名(root):" server_username + read -e -p "サーバーのユーザー名 (root):" server_username local server_username=${server_username:-root} read -e -p "サーバーユーザーのパスワード:" server_password @@ -13965,8 +14006,8 @@ while true; do ;; 2) - send_stats "クラスターサーバーを削除します" - read -e -p "削除する必要があるキーワードを入力してください。" rmserver + send_stats "クラスターサーバーの削除" + read -e -p "削除するキーワードを入力してください:" rmserver sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) @@ -13978,15 +14019,15 @@ while true; do 4) clear send_stats "バックアップクラスター" - echo -e "お願いします${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" + echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" - echo -e "アップロードしてください${gl_huang}servers.py${gl_bai}にファイル${gl_huang}/root/cluster/${gl_bai}復元を完了してください!" + echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end ;; @@ -14036,48 +14077,48 @@ done kejilion_Affiliates() { clear -send_stats "広告列" +send_stats "広告コラム" echo "広告コラム" echo "------------------------" -echo "これにより、ユーザーはよりシンプルでエレガントなプロモーションと購入エクスペリエンスを提供します!" +echo "ユーザーには、よりシンプルでエレガントなプロモーションと購入エクスペリエンスが提供されます。" echo "" -echo -e "サーバーオファー" +echo -e "サーバー割引" echo "------------------------" echo -e "${gl_lan}Laika Cloud 香港 CN2 GIA 韓国のデュアル ISP 米国 CN2 GIA プロモーション${gl_bai}" -echo -e "${gl_bai}ウェブサイト:https://www.lcayun.com/aff/zexuqbim${gl_bai}" +echo -e "${gl_bai}ウェブサイト: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd 年間 10.99 ドル、米国、1 コア、1G メモリ、20G ハードドライブ、月あたり 1T トラフィック${gl_bai}" -echo -e "${gl_bai}ウェブサイト:https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" +echo -e "${gl_bai}URL: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 年間 $52.7 米国 1 コア 4G メモリ 50G ハードドライブ 月額 4T トラフィック${gl_bai}" -echo -e "${gl_bai}ウェブサイト:https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=ga1.3.942352702.1711283207${gl_bai}" +echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" echo -e "${gl_huang}Bricklayer 四半期あたり 49 ドル 米国 CN2GIA 日本 ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 1T トラフィック/月${gl_bai}" echo -e "${gl_bai}ウェブサイト: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" -echo -e "${gl_lan}dmit四半期あたり28ドルUS CN2GIA 1コア2Gメモリ20Gハードドライブ800gトラフィック${gl_bai}" +echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" -echo -e "${gl_bai}ウェブサイト:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?faffid=1355 &? affid=1355${gl_bai}" +echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}より人気のあるVPSオファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "ドメイン名の割引" echo "------------------------" echo -e "${gl_lan}GNAME 初年度 8.8 ドル COM ドメイン名 初年度 6.68 ドル CC ドメイン名${gl_bai}" -echo -e "${gl_bai}ウェブサイト:https://www.gname.com/register?tt=86836&ttcode=kejilion86836&ttbj=sh${gl_bai}" +echo -e "${gl_bai}ウェブサイト: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" echo "------------------------" echo "" echo -e "テクノロジーライオン周辺機器" echo "------------------------" echo -e "${gl_kjlan}ステーションB:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}オイルパイプ:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" echo -e "${gl_kjlan}公式ウェブサイト:${gl_bai}https://kejilion.pro/ ${gl_kjlan}ナビゲーション:${gl_bai}https://dh.kejilion.pro/${gl_bai}" -echo -e "${gl_kjlan}ブログ:ブログ${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}ソフトウェアセンター:${gl_bai}https://app.kejilion.pro/${gl_bai}" +echo -e "${gl_kjlan}ブログ:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}ソフトウェアセンター:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}スクリプトの公式ウェブサイト:${gl_bai}https://kejilion.sh ${gl_kjlan}githubアドレス:${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}スクリプト公式サイト:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub アドレス:${gl_bai}https://github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -14092,16 +14133,16 @@ send_stats "スクリプトの更新" cd ~ while true; do clear - echo "ログを更新します" + echo "変更ログ" echo "------------------------" - echo "すべてのログ:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" + echo "すべてのログ:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) if [ "$sh_v" = "$sh_v_new" ]; then - echo -e "${gl_lv}あなたはすでに最新バージョンです!${gl_huang}v$sh_v${gl_bai}" + echo -e "${gl_lv}すでに最新バージョンを使用しています。${gl_huang}v$sh_v${gl_bai}" send_stats "スクリプトはすでに最新であるため、更新する必要はありません" else echo "新しいバージョン発見!" @@ -14120,9 +14161,9 @@ while true; do echo "------------------------" echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" echo "------------------------" - echo "0。メインメニューに戻ります" + echo "0. メインメニューに戻る" echo "------------------------" - read -e -p "選択を入力してください:" choice + read -e -p "選択肢を入力してください:" choice case "$choice" in 1) clear @@ -14188,10 +14229,10 @@ echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" echo -e "テクノロジー ライオン スクリプト ツールボックス v$sh_v" -echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}スクリプトをすばやく開始します${gl_bai}" +echo -e "コマンドライン入力${gl_huang}k${gl_kjlan}クイックスタートスクリプト${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}システム情報の問い合わせ" -echo -e "${gl_kjlan}2. ${gl_bai}システムの更新" +echo -e "${gl_kjlan}2. ${gl_bai}システムアップデート" echo -e "${gl_kjlan}3. ${gl_bai}システムのクリーンアップ" echo -e "${gl_kjlan}4. ${gl_bai}基本的なツール" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" @@ -14203,20 +14244,20 @@ echo -e "${gl_huang}10. ${gl_bai}LDNMP Web サイトの構築" echo -e "${gl_kjlan}11. ${gl_bai}アプリケーション市場" echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" echo -e "${gl_kjlan}13. ${gl_bai}システムツール" -echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスター制御" +echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスタ制御" echo -e "${gl_kjlan}15. ${gl_bai}広告コラム" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Phantom Beast Palu Serverオープニングスクリプト" +echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu サーバー開始スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "選択を入力してください:" choice +read -e -p "選択肢を入力してください:" choice case $choice in 1) linux_info ;; - 2) clear ; send_stats "システムの更新" ; linux_update ;; + 2) clear ; send_stats "システムアップデート" ; linux_update ;; 3) clear ; send_stats "システムのクリーンアップ" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; @@ -14232,13 +14273,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu Serverオープニングスクリプト" ; cd ~ + p) send_stats "Eudemons Parlu サーバー開始スクリプト" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "無効な入力!" ;; + *) echo "無効な入力です!" ;; esac break_end done @@ -14246,50 +14287,50 @@ done k_info() { -send_stats "Kコマンド参照ユースケース" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下は、Kコマンドリファレンスユースケースです。" +echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージのアンインストールk nano wgetを削除| k del nano wget | K UNINSTALLNANOWGET | K UNINSTALLNANO WGET" -echo "システムKアップデートを更新| Kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" -echo "システムパネルk dd |を再インストールしますk再インストール" -echo "BBR3コントロールパネルK BBR3 | K BBRV3" -echo "カーネルチューニングパネルk nhyh | Kカーネル最適化" +echo "システムパネルを再度取り付けます。 k再インストール" +echo "BBR3 コントロール パネル K BBR3 | k bbrv3" +echo "カーネル チューニング パネルk カーネルの最適化" echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "SSHリモート接続ツールK SSH | Kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" echo "イントラネット浸透率 (クライアント) k frpc" echo "ソフトウェア起動 k start sshd | sshdを起動します" -echo "ソフトウェアSTOP K STOP SSHD | k stop sshd" -echo "ソフトウェア再起動k再起動sshd | k再起動sshd" +echo "ソフトウェア停止 k 停止 sshd | k ストップ sshd" +echo "ソフトウェア再起動 k 再起動 sshd | k sshdを再起動します" echo "ソフトウェアのステータスを確認します。 k ステータス sshd | kステータスsshd" echo "k ドッカーを有効にする | k 自動開始ドッカー | k ソフトウェアの起動時に Docker を有効にする" -echo "ドメイン名証明書アプリケーションK SSL" +echo "ドメイン名証明書アプリケーション k ssl" echo "ドメイン名証明書の有効期限のクエリ k ssl ps" echo "docker 管理プレーン k docker" -echo "Docker Environment Installation K Dockerインストール| K Dockerのインストール" -echo "Docker Container Management K Docker PS | K Dockerコンテナ" -echo "Docker Image Management K Docker IMG | K Docker画像" +echo "docker 環境のインストール k docker install |k docker インストール" +echo "docker コンテナ管理 k docker ps |k docker コンテナ" +echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" -echo "WordPress k wp | k wordpress | k wp xxx.comをインストールします" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "ファイアウォール パネル k fhq |k ファイアウォール" echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" -echo "IP K FXIP 127.0.0.0/8 | KリリースIP 127.0.0.0/8をリリースします" -echo "ブロックIP K ZZIP 177.5.25.36 | KブロックIP 177.5.25.36" +echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" +echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" echo "コマンド お気に入り k お気に入り | k コマンドのお気に入り" -echo "アプリ市場管理Kアプリ" +echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "システム情報を表示 k info" } @@ -14297,14 +14338,14 @@ echo "システム情報を表示 k info" if [ "$#" -eq 0 ]; then - # パラメーターがない場合は、インタラクティブロジックを実行します + # 引数なしで対話型ロジックを実行します kejilion_sh else # パラメータがある場合は、対応する関数を実行します case $1 in install|add|安装) shift - send_stats "ソフトウェアをインストールします" + send_stats "ソフトウェアのインストール" install "$@" ;; remove|del|uninstall|卸载) @@ -14343,7 +14384,7 @@ else rsync_run) shift - send_stats "タイム付きRSYNC同期" + send_stats "スケジュールされたrsync同期" run_task "$@" ;; @@ -14362,7 +14403,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+ポートは、サービスへのアクセスをブロックされています" + echo "IP+ポートはサービスへのアクセスをブロックされています" else ip_address block_container_port "$docker_name" "$ipv4_address" @@ -14375,7 +14416,7 @@ else swap) shift - send_stats "仮想メモリをすばやく設定します" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; @@ -14429,7 +14470,7 @@ else status|状态) shift - send_stats "ソフトウェアステータスビュー" + send_stats "ソフトウェアのステータスを確認する" status "$@" ;; start|启动) @@ -14474,7 +14515,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 4bffecd80..88d94db65 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# 전체 텍스트의 경우 Send_Stats 기능 호출 위치, 투명 및 오픈 소스를 검색 할 수 있으며 우려 사항이 있으면 사용을 거부 할 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -111,22 +111,22 @@ CheckFirstRun_false() { fi } -# 사용자에게 이용 약관에 동의하라는 메시지 +# 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" - echo "스크립트를 처음 사용하면 사용자 라이센스 계약을 읽고 동의하십시오." + echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "위의 약관에 동의하십니까? (예/아니요):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "라이센스 동의" + send_stats "라이센스 계약" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "허가 거부" + send_stats "허가가 거부되었습니다" clear exit fi @@ -222,9 +222,9 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}힌트:${gl_bai}디스크 공간이 부족합니다!" echo "현재 사용 가능한 공간: $((available_space_mb/1024))G" - echo "최소 수요 공간 :${required_gb}G" + echo "최소 필요 공간:${required_gb}G" echo "설치를 계속할 수 없습니다. 디스크 공간을 비운 후 다시 시도하십시오." - send_stats "불충분 한 디스크 공간" + send_stats "디스크 공간이 부족합니다." break_end kejilion fi @@ -238,7 +238,7 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "패키지 매개 변수는 제공되지 않습니다!" + echo "패키지 매개변수가 제공되지 않았습니다!" return 1 fi @@ -261,7 +261,7 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "알 수없는 패키지 관리자!" + echo "알 수 없는 패키지 관리자입니다!" return 1 fi done @@ -287,11 +287,11 @@ restart() { if [ $? -eq 0 ]; then echo "$1서비스가 다시 시작되었습니다." else - echo "오류 : 다시 시작합니다$1서비스가 실패했습니다." + echo "오류: 다시 시작$1서비스가 실패했습니다." fi } -# 서비스를 시작하십시오 +# 서비스 시작 start() { systemctl start "$1" if [ $? -eq 0 ]; then @@ -307,7 +307,7 @@ stop() { if [ $? -eq 0 ]; then echo "$1서비스가 중지되었습니다." else - echo "오류 : 중지$1서비스가 실패했습니다." + echo "오류: 중지$1서비스가 실패했습니다." fi } @@ -317,7 +317,7 @@ status() { if [ $? -eq 0 ]; then echo "$1서비스 상태가 표시됩니다." else - echo "오류 : 표시 할 수 없습니다$1서비스 상태." + echo "오류: 표시할 수 없습니다.$1서비스 상태." fi } @@ -330,14 +330,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME전원 켜기로 설정합니다." + echo "$SERVICE_NAME부팅시 자동으로 시작되도록 설정되어 있습니다." } break_end() { - echo -e "${gl_lv}작업이 완료되었습니다${gl_bai}" - echo "계속하려면 키를 누르십시오 ..." + echo -e "${gl_lv}작업 완료${gl_bai}" + echo "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" echo "" clear @@ -427,7 +427,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker 환경 설치 ...${gl_bai}" + echo -e "${gl_huang}도커 환경 설치 중...${gl_bai}" if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then install_add_docker_guanfang elif command -v dnf &>/dev/null; then @@ -508,29 +508,29 @@ while true; do echo "" echo "컨테이너 운영" echo "------------------------" - echo "1. 새 컨테이너를 만듭니다" + echo "1. 새 컨테이너 생성" echo "------------------------" echo "2. 지정된 컨테이너 시작 6. 모든 컨테이너 시작" echo "3. 지정된 컨테이너를 중지합니다. 7. 모든 컨테이너를 중지합니다." echo "4. 지정된 컨테이너 삭제 8. 모든 컨테이너 삭제" - echo "5. 지정된 컨테이너를 다시 시작하십시오. 9. 모든 컨테이너를 다시 시작하십시오" + echo "5. 지정된 컨테이너를 다시 시작합니다. 9. 모든 컨테이너를 다시 시작합니다." echo "------------------------" - echo "11. 지정된 컨테이너를 입력하십시오. 12. 컨테이너 로그보기" + echo "11. 지정된 컨테이너를 입력합니다. 12. 컨테이너 로그를 봅니다." echo "13. 컨테이너 네트워크 확인 14. 컨테이너 점유율 확인" echo "------------------------" - echo "15. 컨테이너 포트 액세스 켜기 16. 컨테이너 포트 액세스를 끄십시오." + echo "15. 컨테이너 포트 액세스 활성화 16. 컨테이너 포트 액세스 닫기" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) send_stats "새 컨테이너 만들기" - read -e -p "창조 명령을 입력하십시오 :" dockername + read -e -p "생성 명령을 입력하십시오:" dockername $dockername ;; 2) - send_stats "지정된 컨테이너를 시작하십시오" + send_stats "지정된 컨테이너 시작" read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; @@ -540,17 +540,17 @@ while true; do docker stop $dockername ;; 4) - send_stats "지정된 컨테이너를 삭제하십시오" - read -e -p "컨테이너 이름 (공백별로 분리 된 여러 컨테이너 이름)을 입력하십시오." dockername + send_stats "지정된 컨테이너 삭제" + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) - send_stats "지정된 컨테이너를 다시 시작하십시오" + send_stats "지정된 컨테이너를 다시 시작합니다." read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) - send_stats "모든 컨테이너를 시작하십시오" + send_stats "모든 컨테이너 시작" docker start $(docker ps -a -q) ;; 7) @@ -572,23 +572,23 @@ while true; do esac ;; 9) - send_stats "모든 컨테이너를 다시 시작하십시오" + send_stats "모든 컨테이너 다시 시작" docker restart $(docker ps -q) ;; 11) - send_stats "컨테이너를 입력하십시오" + send_stats "컨테이너를 입력하세요" read -e -p "컨테이너 이름을 입력하세요:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "컨테이너 로그를 봅니다" + send_stats "컨테이너 로그 보기" read -e -p "컨테이너 이름을 입력하세요:" dockername docker logs $dockername break_end ;; 13) - send_stats "컨테이너 네트워크를 봅니다" + send_stats "컨테이너 네트워크 보기" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" @@ -606,14 +606,14 @@ while true; do break_end ;; 14) - send_stats "컨테이너 점유를 봅니다" + send_stats "컨테이너 점유율 보기" docker stats --no-stream break_end ;; 15) - send_stats "컨테이너 포트 액세스를 허용합니다" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + send_stats "컨테이너 포트 액세스 허용" + read -e -p "컨테이너 이름을 입력하세요:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -623,7 +623,7 @@ while true; do 16) send_stats "컨테이너 포트 접근 차단" - read -e -p "컨테이너 이름을 입력하십시오 :" docker_name + read -e -p "컨테이너 이름을 입력하세요:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -648,31 +648,31 @@ while true; do echo "" echo "미러 작동" echo "------------------------" - echo "1. 지정된 이미지 가져 오기 3. 지정된 이미지 삭제" + echo "1. 지정된 이미지 가져오기 3. 지정된 이미지 삭제" echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) send_stats "이미지 가져오기" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_huang}이미지 얻기 :$name${gl_bai}" + echo -e "${gl_huang}이미지 가져오기:$name${gl_bai}" docker pull $name done ;; 2) send_stats "이미지 업데이트" - read -e -p "거울 이름을 입력하십시오 (공백으로 여러 거울 이름을 별도로 분리하십시오) :" imagenames + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_huang}업데이트 된 이미지 :$name${gl_bai}" + echo -e "${gl_huang}이미지 업데이트 중:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "거울을 삭제하십시오" + send_stats "이미지 삭제" read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do docker rmi -f $name @@ -688,7 +688,7 @@ while true; do [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -756,7 +756,7 @@ install_crontab() { service cron start ;; *) - echo "지원되지 않는 분포 :$ID" + echo "지원되지 않는 배포판:$ID" return ;; esac @@ -777,15 +777,15 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 구성 파일이 존재하는지 확인하고 파일을 작성하고 기본 설정이 존재하지 않는 경우 작성하십시오. + # 구성 파일이 있는지 확인하고, 없으면 파일을 생성하고 기본 설정을 씁니다. if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # jq를 사용하여 구성 파일 업데이트 처리 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 현재 구성에 이미 IPv6 설정이 있는지 확인하십시오 + # 현재 구성에 이미 ipv6 설정이 있는지 확인하십시오. local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') # 구성 업데이트 및 IPv6 활성화 @@ -795,7 +795,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 원래 구성과 새로운 구성을 비교합니다 + # 원래 구성을 새 구성과 비교 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}현재 IPv6 액세스가 활성화되어 있습니다.${gl_bai}" else @@ -812,28 +812,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 구성 파일이 있는지 확인하십시오 + # 구성 파일이 있는지 확인하십시오. if [ ! -f "$CONFIG_FILE" ]; then echo -e "${gl_hong}구성 파일이 존재하지 않습니다.${gl_bai}" return fi - # 현재 구성을 읽으십시오 + # 현재 구성 읽기 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # JQ를 사용하여 구성 파일 업데이트를 처리하십시오 + # jq를 사용하여 구성 파일 업데이트 처리 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') # 현재 ipv6 상태 확인 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 원래 구성과 새로운 구성을 비교합니다 + # 원래 구성을 새 구성과 비교 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6 액세스는 현재 닫힙니다${gl_bai}" + echo -e "${gl_huang}IPv6 액세스는 현재 폐쇄되었습니다.${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6 액세스가 성공적으로 닫혔습니다${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 성공적으로 종료되었습니다.${gl_bai}" fi } @@ -872,7 +872,7 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "포트 번호를 하나 이상 입력하세요." return 1 fi @@ -883,7 +883,7 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 열린 규칙을 추가하십시오 + # 공개 규칙 추가 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi @@ -902,7 +902,7 @@ open_port() { close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "하나 이상의 포트 번호를 제공하십시오" + echo "포트 번호를 하나 이상 입력하세요." return 1 fi @@ -913,18 +913,18 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 가까운 규칙을 추가하십시오 + # 종료 규칙 추가 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "포트 폐쇄$port" + echo "항구 폐쇄$port" fi done - # 기존 규칙 삭제 (있는 경우) + # 기존 규칙 삭제(있는 경우) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null @@ -933,14 +933,14 @@ close_port() { iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "포트 폐쇄" + send_stats "항구 폐쇄" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." return 1 fi @@ -950,7 +950,7 @@ allow_ip() { # 기존 차단 규칙 삭제 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 허용 규칙을 추가하십시오 + # 허용 규칙 추가 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "공개된 IP$ip" @@ -958,13 +958,13 @@ allow_ip() { done save_iptables_rules - send_stats "IP 출시" + send_stats "공개된 IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "하나 이상의 IP 주소 또는 IP 세그먼트를 제공하십시오." + echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." return 1 fi @@ -974,10 +974,10 @@ block_ip() { # 기존 허용 규칙 삭제 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 차단 규칙을 추가하십시오 + # 차단 규칙 추가 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP 차단$ip" + echo "IP가 차단됨$ip" fi done @@ -992,7 +992,7 @@ block_ip() { enable_ddos_defense() { - # 방어 DDO를 켜십시오 + # DDoS 보호 켜기 iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -1007,7 +1007,7 @@ enable_ddos_defense() { # DDoS 방어 끄기 disable_ddos_defense() { - # 방어 DDO를 끄십시오 + # DDoS 보호 끄기 iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1017,7 +1017,7 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDOS 방어를 끕니다" + send_stats "DDoS 방어 끄기" } @@ -1042,7 +1042,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일 실패" + echo "오류: 다운로드$country_codeIP 영역 파일 실패" continue fi @@ -1062,7 +1062,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류 : 다운로드$country_codeIP 영역 파일이 실패했습니다" + echo "오류: 다운로드$country_codeIP 영역 파일 실패" continue fi @@ -1090,7 +1090,7 @@ manage_country_rules() { ;; *) - echo "사용법 : manage_country_rules {블록 | 허용 | unblock} " + echo "사용법: prepare_country_rules {block|allow|unblock} " ;; esac done @@ -1118,11 +1118,11 @@ iptables_panel() { echo "" echo "방화벽 관리" echo "------------------------" - echo "1. 지정된 포트 2를 엽니 다. 지정된 포트를 닫으십시오." - echo "3. 모든 포트를 엽니 다. 4. 모든 포트를 닫으십시오" + echo "1. 지정 포트 열기 2. 지정 포트 닫기" + echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 지우십시오" + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1133,17 +1133,17 @@ iptables_panel() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - read -e -p "열린 포트 번호를 입력하십시오 :" o_port + read -e -p "열려 있는 포트 번호를 입력하세요." o_port open_port $o_port - send_stats "지정된 포트를 엽니 다" + send_stats "지정된 포트 열기" ;; 2) - read -e -p "닫힌 포트 번호를 입력하십시오 :" c_port + read -e -p "닫힌 포트 번호를 입력하세요:" c_port close_port $c_port - send_stats "지정된 포트를 닫습니다" + send_stats "지정된 포트 닫기" ;; 3) # 모든 포트 열기 @@ -1175,12 +1175,12 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 닫습니다" + send_stats "모든 포트를 닫으세요" ;; 5) # IP 화이트리스트 - read -e -p "해제 할 IP 또는 IP 세그먼트를 입력하십시오." o_ip + read -e -p "허용된 IP 또는 IP 세그먼트를 입력하세요." o_ip allow_ip $o_ip ;; 6) @@ -1189,26 +1189,26 @@ iptables_panel() { block_ip $c_ip ;; 7) - # 지정된 IP를 지우십시오 + # 지정된 IP 지우기 read -e -p "삭제된 IP를 입력하세요:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "지정된 IP를 지우십시오" + send_stats "지정된 IP 지우기" ;; 11) - # 핑을 허용하십시오 + # 핑 허용 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 허용하십시오" + send_stats "핑 허용" ;; 12) - # 핑을 비활성화합니다 + # 핑 비활성화 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "핑을 비활성화합니다" + send_stats "핑 비활성화" ;; 13) enable_ddos_defense @@ -1218,20 +1218,20 @@ iptables_panel() { ;; 15) - read -e -p "차단 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code + read -e -p "차단된 국가 코드를 입력하세요(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules block $country_code - send_stats "허용 국가$country_codeIP" + send_stats "국가 허용$country_codeIP" ;; 16) read -e -p "허용되는 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분할 수 있음)." country_code manage_country_rules allow $country_code - send_stats "나라를 차단하십시오$country_codeIP" + send_stats "블록 국가$country_codeIP" ;; 17) - read -e -p "청산 된 국가 코드를 입력하십시오 (여러 국가 코드는 CN US JP와 같은 공간으로 분리 될 수 있습니다) :" country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code - send_stats "나라를 정리하십시오$country_codeIP" + send_stats "명확한 국가$country_codeIP" ;; *) @@ -1250,7 +1250,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 현재 시스템에서 모든 스왑 파티션을 얻으십시오 + # 현재 시스템의 모든 스왑 파티션을 가져옵니다. local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 모든 스왑 파티션을 탐색하고 삭제합니다. @@ -1263,7 +1263,7 @@ add_swap() { # /swapfile이 더 이상 사용되지 않는지 확인하세요. swapoff /swapfile - # 이전 /스왑 파일을 삭제하십시오 + # 이전 /swap 파일 삭제 rm -f /swapfile # 새로운 스왑 파티션 생성 @@ -1307,21 +1307,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginx 버전을 얻으십시오 + # nginx 버전 받기 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # MySQL 버전을 얻으십시오 + # mysql 버전 받기 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHP 버전을 얻으십시오 + # PHP 버전 받기 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전을 얻으십시오 + # Redis 버전 받기 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1343,7 +1343,7 @@ install_ldnmp_conf() { default_server_ssl - # docker-compose.yml 파일을 다운로드하여 교체하십시오 + # docker-compose.yml 파일을 다운로드하여 교체하세요. wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) @@ -1454,7 +1454,7 @@ install_ssltls_text() { echo "" echo -e "${gl_huang}인증서 저장 경로${gl_bai}" echo "공개 키: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "개인 키 :/etc/letsencrypt/live/$yuming/privkey.pem" + echo "개인 키: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1463,7 +1463,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL 인증서를 신속하게 신청하고 만료 전에 서명을 자동으로 갱신하십시오.${gl_bai}" +echo -e "${gl_huang}SSL 인증서를 빠르게 신청하고 만료되기 전에 자동으로 갱신하세요.${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1479,7 +1479,7 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}응용 인증서 만료${gl_bai}" + echo -e "${gl_huang}신청한 인증서의 만료 상태${gl_bai}" echo "사이트 정보 인증서 만료 시간" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do @@ -1521,14 +1521,14 @@ certs_status() { if [ -f "$file_path" ]; then send_stats "도메인 이름 인증서 신청이 성공했습니다." else - send_stats "도메인 이름 인증서 신청에 실패했습니다" + send_stats "도메인 이름 인증서 신청 실패" echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." - echo -e "5. 응용 프로그램 수는 한계를 초과합니다. ➠ 암호화하자는 주간 제한 (5 배/도메인 이름/주)을 갖습니다." - echo -e "6. 국내 등록 제한 ➠ 도메인 이름이 중국 본토에 등록되어 있는지 확인하십시오." + echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." break_end clear echo "다시 배포해 보세요.$webname" @@ -1652,18 +1652,18 @@ cf_purge_cache() { # 구성 파일이 있는지 확인하십시오. if [ -f "$CONFIG_FILE" ]; then - # 구성 파일에서 API_TOKE 및 ZONE_ID를 읽으십시오 + # 구성 파일에서 API_TOKEN 및 zone_id를 읽습니다. read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # Zone_ids를 배열로 변환합니다 + # ZONE_IDS를 어레이로 변환 ZONE_IDS=($ZONE_IDS) else # 캐시를 지울지 여부를 사용자에게 묻습니다. - read -e -p "CloudFlare의 캐시를 청소해야합니까? (Y/N) :" answer + read -e -p "Cloudflare의 캐시를 지워야 합니까? (예/아니요):" answer if [[ "$answer" == "y" ]]; then echo "CF 정보는 다음 위치에 저장됩니다.$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다." read -e -p "API_TOKEN을 입력하세요:" API_TOKEN - read -e -p "CF 사용자 이름을 입력하십시오 :" EMAIL - read -e -p "Zone_ID를 입력하십시오 (공백으로 여러 차례 분리) :" -a ZONE_IDS + read -e -p "CF 사용자 이름을 입력하세요:" EMAIL + read -e -p "zone_id를 입력하십시오(여러 개는 공백으로 구분)." -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" @@ -1706,7 +1706,7 @@ web_del() { fi for yuming in $yuming_list; do - echo "도메인 이름 삭제 :$yuming" + echo "도메인 이름을 삭제하는 중입니다:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 @@ -1716,8 +1716,8 @@ web_del() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 피하기 위해 삭제하기 전에 데이터베이스가 존재하는지 확인하십시오. - echo "데이터베이스 삭제 :$dbname" + # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. + echo "데이터베이스 삭제 중:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1735,12 +1735,12 @@ nginx_waf() { # 모드 매개변수에 따라 WAF를 켤지 끌지 결정합니다. if [ "$mode" == "on" ]; then - # WAF 켜기 : 주석을 제거하십시오 + # WAF 켜기: 댓글 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # waf 닫기 : 댓글을 추가하십시오 + # WAF 끄기: 댓글 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1796,11 +1796,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 오래된 정의를 삭제하십시오 + # 이전 정의 삭제 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # "Happy Publishing"과 함께 새로운 정의를 삽입하십시오. + # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1851,7 +1851,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotli를 켜십시오 : 주석을 제거하십시오 + # Brotli 켜기: 댓글 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1865,7 +1865,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotli를 닫습니다 : 주석을 추가하십시오 + # Brotli 닫기: 댓글 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1881,7 +1881,7 @@ nginx_br() { }' /home/web/nginx.conf else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi @@ -1907,7 +1907,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # ZSTD를 켜십시오 : 주석을 제거하십시오 + # Zstd 켜기: 주석 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1938,11 +1938,11 @@ nginx_zstd() { else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi - # Nginx 이미지를 확인하고 상황에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1969,7 +1969,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "유효하지 않은 매개 변수 : 'ON'또는 'OFF'사용" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi @@ -1991,21 +1991,21 @@ web_security() { clear echo -e "서버 웹사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 방어 프로그램을 설치하십시오" + echo "1. 방어 프로그램 설치" echo "------------------------" echo "5. SSH 차단 기록 보기 6. 웹사이트 차단 기록 보기" - echo "7. 방어 규칙 목록보기 8. 로그의 실시간 모니터링보기" + echo "7. 방어규칙 목록 보기 8. 실시간 모니터링을 위한 로그 보기" echo "------------------------" echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" echo "------------------------" - echo "21. CloudFlare 모드 22. 5 초 방패의 높은 하중" + echo "21. cloudflare 모드 22. 고부하에서 5초 보호 활성화" echo "------------------------" echo "31. WAF 켜기 32. WAF 끄기" echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -2089,9 +2089,9 @@ web_security() { 21) send_stats "클라우드플레어 모드" - echo "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 글로벌 API 키를 얻습니다." + echo "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고 글로벌 API 키를 받으세요." echo "https://dash.cloudflare.com/login" - read -e -p "CF 계정 번호를 입력하십시오." cfuser + read -e -p "CF의 계좌번호를 입력하세요:" cfuser read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf @@ -2111,17 +2111,17 @@ web_security() { ;; 22) - send_stats "5 초 방패의 높은 하중" - echo -e "${gl_huang}웹 사이트는 5 분마다 자동으로 감지됩니다. 높은 하중의 감지에 도달하면 방패가 자동으로 켜지고 낮은 부하가 자동으로 5 초 동안 꺼집니다.${gl_bai}" + send_stats "고부하로 5초 쉴드 가능" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" - echo "CF 매개 변수 가져 오기 :" - echo -e "CF 배경의 오른쪽 상단 모서리로 이동하여 왼쪽의 API 토큰을 선택하고 얻습니다.${gl_huang}Global API Key${gl_bai}" - echo -e "CF 배경 도메인 이름 요약 페이지의 오른쪽 하단으로 이동하려면${gl_huang}지역 ID${gl_bai}" + echo "CF 매개변수 가져오기:" + echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" + echo -e "cf 백엔드 도메인 이름 요약 페이지 오른쪽 하단으로 이동하여 가져오세요.${gl_huang}지역 ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CF의 계좌번호를 입력하세요:" cfuser read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken - read -e -p "CF에 도메인 이름의 영역 ID를 입력하십시오." cfzonID + read -e -p "CF에 도메인 이름의 영역 ID를 입력하세요." cfzonID cd ~ install jq bc @@ -2147,13 +2147,13 @@ web_security() { 31) nginx_waf on - echo "사이트 waf가 활성화되어 있습니다" - send_stats "사이트 waf가 활성화되어 있습니다" + echo "사이트 WAF가 활성화되었습니다" + send_stats "사이트 WAF가 활성화되었습니다" ;; 32) nginx_waf off - echo "사이트 waf가 닫혔습니다" + echo "사이트 WAF가 다운되었습니다" send_stats "사이트 WAF가 다운되었습니다" ;; @@ -2179,7 +2179,7 @@ check_nginx_mode() { CONFIG_FILE="/home/web/nginx.conf" -# 현재 Worker_Processes 설정 값을 얻으십시오 +# 현재 작업자_프로세스 설정 값을 가져옵니다. current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') # 값에 따라 모드 정보 설정 @@ -2212,7 +2212,7 @@ check_nginx_compression() { br_status="" fi - # GZIP가 활성화되어 있고 댓글을 달지 않은지 확인하십시오 + # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status=" gzip压缩已开启" else @@ -2228,16 +2228,16 @@ web_optimization() { check_nginx_mode check_nginx_compression clear - send_stats "LDNMP 환경을 최적화하십시오" + send_stats "LDNMP 환경 최적화" echo -e "LDNMP 환경 최적화${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 표준 모드 2. 고성능 모드 (2H4G 이상 권장)" + echo "1. 표준 모드 2. 고성능 모드(2H4G 이상 권장)" echo "------------------------" - echo "3. GZIP 압축 켜기 4. GZIP 압축 끄기" + echo "3. gzip 압축 켜기 4. gzip 압축 끄기" echo "5. br 압축을 켭니다. 6. br 압축을 끕니다." - echo "7. ZSTD 압축 켜기 8. ZSTD 압축 끄기" + echo "7. zstd 압축을 켭니다. 8. zstd 압축을 끕니다." echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -2278,7 +2278,7 @@ web_optimization() { optimize_balanced - echo "LDNMP 환경은 표준 모드로 설정되었습니다" + echo "LDNMP 환경이 표준 모드로 설정되었습니다." ;; 2) @@ -2376,9 +2376,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker = "$ {gl_lv} $ {gl_bai} 설치" +# check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker = "$ {gl_hui} $ {gl_bai}가 설치되지 않았다" +# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2429,21 +2429,21 @@ check_docker_image_update() { local container_created=$(echo "$container_info" | cut -d',' -f1) local image_name=$(echo "$container_info" | cut -d',' -f2) - # 거울 창고 및 태그 추출 + # 이미지 저장소 및 태그 추출 local image_repo=${image_name%%:*} local image_tag=${image_name##*:} - # 기본 레이블이 최신입니다 + # 기본 태그는 최신입니다. [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - # 공식 이미지에 대한 지원을 추가하십시오 + # 공식 이미지에 대한 지원 추가 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" # Docker Hub API에서 이미지 릴리스 시간 가져오기 local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득한 시간을 확인 + # 획득한 시간을 확인하세요. if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) @@ -2467,7 +2467,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 컨테이너의 IP 주소 가져오기 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2482,12 +2482,12 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 지정된 IP 확인 및 해제 if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 확인하고 해제하십시오 + # 로컬 네트워크 127.0.0.0/8 확인 및 허용 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2499,7 +2499,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 확인하고 해제하십시오 + # 지정된 IP 확인 및 해제 if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2525,7 +2525,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소를 가져옵니다 + # 컨테이너의 IP 주소 가져오기 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2540,12 +2540,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2559,12 +2559,12 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 릴리스 규칙을 지우십시오. 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2575,7 +2575,7 @@ clear_container_rules() { fi - echo "IP+포트는 서비스에 액세스 할 수있었습니다" + echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules } @@ -2590,7 +2590,7 @@ block_host_port() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." - echo "사용법 : block_host_port <포트 번호> <승인 된 ip>" + echo "사용법: block_host_port <포트 번호> <허용 IP>" return 1 fi @@ -2616,7 +2616,7 @@ block_host_port() { - # 다른 모든 IP 액세스를 거부했습니다 + # 다른 모든 IP의 접근을 거부 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi @@ -2626,7 +2626,7 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스를 허용합니다 + # 로컬 액세스 허용 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2636,7 +2636,7 @@ block_host_port() { iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+ 포트는 서비스에 액세스하는 것이 차단되었습니다" + echo "IP+포트가 서비스 접근을 차단했습니다." save_iptables_rules } @@ -2672,17 +2672,17 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 기본 액세스를 허용하는 명확한 규칙 + # 로컬 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP 액세스를 허용하는 명확한 규칙 + # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2759,7 +2759,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2800,13 +2800,13 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." send_stats "제거$docker_name" ;; 5) echo "${docker_name}도메인 이름 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" @@ -2863,16 +2863,16 @@ docker_app_plus() { echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+ 포트 액세스 허용 8. 블록 IP+ 포트 액세스" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택 항목을 입력하세요." choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "응용 프로그램 외부 서비스 포트를 입력하고 기본값을 입력하십시오.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -2895,8 +2895,8 @@ docker_app_plus() { ;; 5) - echo "${docker_name}도메인 액세스 설정" - send_stats "${docker_name}도메인 액세스 설정" + echo "${docker_name}도메인 이름 액세스 설정" + send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" @@ -3121,7 +3121,7 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP 환경을 설치하십시오" +send_stats "LDNMP 환경 설치" root_use clear echo -e "${gl_huang}LDNMP 환경이 설치되지 않았습니다. LDNMP 환경 설치를 시작합니다...${gl_bai}" @@ -3141,7 +3141,7 @@ cd ~ send_stats "nginx 환경 설치" root_use clear -echo -e "${gl_huang}Nginx가 설치되지 않았고 Nginx 환경 설치 시작 ...${gl_bai}" +echo -e "${gl_huang}nginx가 설치되지 않았습니다. nginx 환경 설치를 시작하세요...${gl_bai}" check_disk_space 1 /home check_port install_dependency @@ -3174,7 +3174,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "Nginx 환경을 먼저 설치하십시오" + send_stats "먼저 nginx 환경을 설치해주세요" nginx_install_all fi @@ -3185,10 +3185,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname세워짐!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3248,16 +3248,16 @@ ldnmp_Proxy() { port="${3:-}" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "반세대 IP를 입력하십시오 :" reverseproxy + read -e -p "세대방지 IP를 입력해주세요:" reverseproxy fi if [ -z "$port" ]; then - read -e -p "반세대 포트를 입력하십시오 :" port + read -e -p "안티 세대 포트를 입력하십시오:" port fi nginx_install_status install_ssltls @@ -3281,7 +3281,7 @@ ldnmp_Proxy_backend() { reverseproxy_port="${2:-}" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3372,21 +3372,21 @@ ldnmp_web_status() { echo "" echo "작동하다" echo "------------------------" - echo "1. 도메인 이름 인증서 신청/업데이트 2. 사이트 도메인 이름 변경" - echo "3. 사이트 캐시 정리 4. 관련 사이트 만들기" + echo "1. 도메인 이름 인증서 적용/업데이트 2. 사이트 도메인 이름 복제" + echo "3. 사이트 캐시 지우기 4. 관련 사이트 생성" echo "5. 접속 로그 보기 6. 오류 로그 보기" echo "7. 전역 구성 편집 8. 사이트 구성 편집" echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서 보기" echo "------------------------" echo "20. 특정 사이트 데이터 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "도메인 이름 인증서를 신청하십시오" - read -e -p "도메인 이름을 입력하십시오 :" yuming + send_stats "도메인 이름 인증서 신청" + read -e -p "도메인 이름을 입력하세요:" yuming install_certbot docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3395,10 +3395,9 @@ ldnmp_web_status() { ;; 2) - send_stats "사이트 도메인 이름 변경" - echo -e "${gl_hong}적극 권장:${gl_bai}먼저 전체 사이트 데이터를 백업 한 다음 사이트 도메인 이름을 변경하십시오!" - read -e -p "이전 도메인 이름을 입력하십시오 :" oddyuming - read -e -p "새 도메인 이름을 입력하십시오 :" yuming + send_stats "복제 사이트 도메인 이름" + read -e -p "이전 도메인 이름을 입력하세요:" oddyuming + read -e -p "새 도메인 이름을 입력하세요:" yuming install_certbot install_ssltls certs_status @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3422,18 +3421,18 @@ ldnmp_web_status() { done # 웹사이트 디렉토리 교체 - mv /home/web/html/$oddyuming /home/web/html/$yuming + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; @@ -3442,9 +3441,9 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "관련 사이트를 만듭니다" + send_stats "연결된 사이트 만들기" echo -e "액세스하려면 새 도메인 이름을 기존 사이트에 연결하세요." - read -e -p "기존 도메인 이름을 입력하십시오 :" oddyuming + read -e -p "기존 도메인 이름을 입력하세요:" oddyuming read -e -p "새 도메인 이름을 입력하세요:" yuming install_certbot install_ssltls @@ -3459,12 +3458,12 @@ ldnmp_web_status() { ;; 5) - send_stats "액세스 로그를 봅니다" + send_stats "접속 로그 보기" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "오류 로그를 봅니다" + send_stats "오류 로그 보기" tail -n 200 /home/web/log/nginx/error.log break_end ;; @@ -3477,7 +3476,7 @@ ldnmp_web_status() { 8) send_stats "사이트 구성 편집" - read -e -p "사이트 구성을 편집하려면 편집 할 도메인 이름을 입력하십시오." yuming + read -e -p "사이트 구성을 편집하려면 편집하려는 도메인 이름을 입력하십시오:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3524,15 +3523,15 @@ while true; do check_panel_app echo -e "$panelname $check_panel" echo "${panelname}대중적이고 강력한 운영 및 유지 관리 관리 패널입니다." - echo "공식 웹 사이트 소개 :$panelurl " + echo "공식 웹사이트 소개:$panelurl " echo "" echo "------------------------" echo "1. 설치 2. 관리 3. 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) check_disk_space 1 @@ -3554,7 +3553,7 @@ while true; do panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}제거하십시오" + send_stats "${panelname}제거" ;; *) break @@ -3620,7 +3619,7 @@ EOF donlond_frp frps - # 출력 생성 정보 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -3629,8 +3628,8 @@ EOF echo echo "FRP 패널 정보" echo "FRP 패널 주소: http://$ipv4_address:$dashboard_port" - echo "FRP 패널 사용자 이름 :$dashboard_user" - echo "FRP 패널 비밀번호 :$dashboard_pwd" + echo "FRP 패널 사용자 이름:$dashboard_user" + echo "FRP 패널 비밀번호:$dashboard_pwd" echo open_port 8055 8056 @@ -3640,7 +3639,7 @@ EOF configure_frpc() { - send_stats "FRP 클라이언트를 설치하십시오" + send_stats "FRP 클라이언트 설치" read -e -p "외부 네트워크 도킹 IP를 입력하세요." server_addr read -e -p "외부 네트워크 도킹 토큰을 입력하세요." token echo @@ -3663,11 +3662,11 @@ EOF add_forwarding_service() { send_stats "FRP 인트라넷 서비스 추가" - # 사용자에게 서비스 이름 및 전달 정보를 입력하라는 메시지 + # 사용자에게 서비스 이름 및 전달 정보를 묻는 메시지를 표시합니다. read -e -p "서비스 이름을 입력하세요:" service_name read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오 [기본값 127.0.0.1 입력] : :" local_ip + read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "인트라넷 포트를 입력하십시오:" local_port read -e -p "외부 네트워크 포트를 입력하세요:" remote_port @@ -3682,7 +3681,7 @@ remote_port = ${remote_port} EOF - # 출력 생성 정보 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -3694,7 +3693,7 @@ EOF delete_forwarding_service() { - send_stats "FRP 인트라넷 서비스를 삭제하십시오" + send_stats "FRP 인트라넷 서비스 삭제" # 삭제해야 하는 서비스 이름을 입력하라는 메시지를 사용자에게 표시합니다. read -e -p "삭제할 서비스 이름을 입력하세요:" service_name # sed를 사용하여 서비스 및 관련 구성 삭제 @@ -3709,7 +3708,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 헤더를 인쇄하십시오 + # 헤더 인쇄 printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' @@ -3772,7 +3771,7 @@ list_forwarding_services() { } END { - # 마지막 서비스에 대한 정보를 인쇄하십시오 + # 마지막 서비스에 대한 정보 인쇄 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -3790,7 +3789,7 @@ get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 액세스 주소를 생성합니다 +# 액세스 주소 생성 generate_access_urls() { # 먼저 모든 포트를 확보하십시오. get_frp_ports @@ -3806,16 +3805,16 @@ generate_access_urls() { # 유효한 포트가 있는 경우에만 제목과 내용 표시 if [ "$has_valid_ports" = true ]; then - echo "FRP 서비스 외부 액세스 주소 :" + echo "FRP 서비스 외부 액세스 주소:" - # 프로세스 IPv4 주소 + # IPv4 주소 처리 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # Process IPv6 주소 (현재 경우) + # IPv6 주소가 있는 경우 처리 if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -3906,10 +3905,10 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." ;; 5) - echo "리버스 인트라넷 침투 서비스를 도메인 이름 액세스로 향합니다" + echo "도메인 이름 액세스에 대한 역인트라넷 침투 서비스" send_stats "FRP 외부 도메인 이름 액세스" add_yuming read -e -p "인트라넷 침투 서비스 포트를 입력하십시오:" frps_port @@ -3917,26 +3916,26 @@ frps_panel() { block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "도메인 이름 형식 example.com은 https : //와 함께 제공되지 않습니다." + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; 7) send_stats "IP 액세스 허용" - read -e -p "해제 할 포트를 입력하십시오." frps_port + read -e -p "해제해야 하는 포트를 입력하세요." frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IP 액세스를 차단하십시오" - echo "반세기 도메인 이름에 액세스 한 경우이 기능을 사용하여 IP+ 포트 액세스를 차단하십시오." - read -e -p "차단 해야하는 포트를 입력하십시오." frps_port + send_stats "IP 접근 차단" + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) send_stats "FRP 서비스 상태 새로 고침" - echo "FRP 서비스 상태가 새로 고쳐졌습니다" + echo "FRP 서비스 상태가 새로 고쳐졌습니다." ;; *) @@ -3959,7 +3958,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." - echo "공식 웹 사이트 소개 : https://github.com/fatedier/frp/" + echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -3970,9 +3969,9 @@ frpc_panel() { echo "------------------------" echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 구성 수동으로 서비스 구성" + echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 수동 구성" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택 항목을 입력하세요." choice case $choice in @@ -4052,7 +4051,7 @@ yt_menu_pro() { send_stats "yt-dlp 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp는 YouTube, Bilibili, Twitter 등과 같은 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." - echo -e "공식 웹 사이트 주소 : https://github.com/yt-dlp/yt-dlp" + echo -e "공식 홈페이지 주소: https://github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "다운로드한 동영상 목록:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" @@ -4062,23 +4061,23 @@ yt_menu_pro() { echo "5. 단일 비디오 다운로드 6. 일괄 비디오 다운로드 7. 사용자 정의 매개변수 다운로드" echo "8. MP3 오디오로 다운로드 9. 비디오 디렉터리 삭제 10. 쿠키 관리(개발 중)" echo "-------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "-------------------------" read -e -p "옵션 번호를 입력하세요:" choice case $choice in 1) - send_stats "yt-dlp 설치 ..." - echo "yt-dlp 설치 ..." + send_stats "yt-dlp 설치 중..." + echo "yt-dlp 설치 중..." install ffmpeg curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id - echo "설치가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "설치가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 2) - send_stats "yt-dlp 업데이트 ..." + send_stats "yt-dlp 업데이트 중..." echo "yt-dlp 업데이트 중..." yt-dlp -U @@ -4091,7 +4090,7 @@ yt_menu_pro() { rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "제거가 완료되었습니다. 계속하려면 키를 누르십시오 ..." + echo "제거가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 5) send_stats "단일 비디오 다운로드" @@ -4102,12 +4101,12 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "다운로드가 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 6) - send_stats "배치 비디오 다운로드" + send_stats "일괄 비디오 다운로드" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 여러 비디오 링크 주소를 입력하십시오 \ n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 여러 개의 동영상 링크 주소를 입력하세요\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE echo "지금 일괄 다운로드를 시작하세요..." @@ -4128,7 +4127,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "실행이 완료되면 키를 눌러 계속하십시오 ..." ;; + read -e -p "실행이 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 8) send_stats "MP3 다운로드" read -e -p "동영상 링크를 입력하세요:" url @@ -4141,7 +4140,7 @@ yt_menu_pro() { read -e -p "오디오 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 9) - send_stats "비디오 삭제" + send_stats "동영상 삭제" read -e -p "삭제된 동영상의 이름을 입력하세요:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; @@ -4178,7 +4177,7 @@ set_timedate() { -# DPKG 인터럽트 문제를 수정하십시오 +# dpkg 중단 문제 수정 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4187,7 +4186,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 ...${gl_bai}" + echo -e "${gl_huang}시스템 업데이트 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4206,7 +4205,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "알 수없는 패키지 관리자!" + echo "알 수 없는 패키지 관리자입니다!" return fi } @@ -4214,7 +4213,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}시스템 정리 ...${gl_bai}" + echo -e "${gl_huang}시스템 청소 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4245,9 +4244,9 @@ linux_clean() { elif command -v apk &>/dev/null; then echo "패키지 관리자 캐시 정리..." apk cache clean - echo "시스템 로그 삭제 ..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "APK 캐시 삭제 ..." + echo "APK 캐시 삭제..." rm -rf /var/cache/apk/* echo "임시 파일 삭제..." rm -rf /tmp/* @@ -4273,9 +4272,9 @@ linux_clean() { rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "사용하지 않는 의존성 정리 ..." + echo "사용하지 않는 종속성을 정리합니다..." pkg autoremove -y - echo "패키지 관리자 캐시 청소 ..." + echo "패키지 관리자 캐시 정리..." pkg clean -y echo "시스템 로그 삭제..." rm -rf /var/log/* @@ -4346,7 +4345,7 @@ while true; do echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4369,7 +4368,7 @@ while true; do chattr -i /etc/resolv.conf nano /etc/resolv.conf chattr +i /etc/resolv.conf - send_stats "DNS 구성을 수동으로 편집합니다" + send_stats "DNS 구성을 수동으로 편집" ;; *) break @@ -4398,7 +4397,7 @@ correct_ssh_config() { sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" fi - # 발견 된 경우 PubKeyAuthentication이 예로 설정됩니다 + # 발견된 경우 PubkeyAuthentication이 yes로 설정되어 있습니다. if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4406,7 +4405,7 @@ correct_ssh_config() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" fi - # PasswordAuthentication 또는 PubKeyAuthentication이 일치하지 않는 경우 기본값을 설정하십시오. + # PasswordAuthentication과 PubkeyAuthentication이 모두 일치하지 않는 경우 기본값을 설정합니다. if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4460,7 +4459,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}루트 프라이빗 키 로그인이 활성화되고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" } @@ -4488,7 +4487,7 @@ import_sshkey() { rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}공개 키가 성공적으로 가져 왔고 루트 개인 키 로그인이 활성화되었고 루트 비밀번호 로그인이 닫히고 재 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}공개 키를 성공적으로 가져왔고 ROOT 개인 키 로그인이 활성화되었으며 ROOT 비밀번호 로그인이 종료되었습니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -4497,7 +4496,7 @@ import_sshkey() { add_sshpasswd() { -echo "루트 비밀번호를 설정하십시오" +echo "루트 비밀번호를 설정하세요" passwd sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; @@ -4516,7 +4515,7 @@ clear dd_xitong() { - send_stats "시스템을 다시 설치하십시오" + send_stats "시스템 재설치" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -4527,7 +4526,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}LeitboGi0ro${gl_bai}초기 포트 :${gl_huang}22${gl_bai}" + echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트:${gl_huang}22${gl_bai}" echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget @@ -4535,7 +4534,7 @@ dd_xitong() { } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget @@ -4543,24 +4542,24 @@ dd_xitong() { } dd_xitong_3() { - echo -e "재설치 후 초기 사용자 이름 :${gl_huang}root${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}22${gl_bai}" + echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}22${gl_bai}" echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호 :${gl_huang}123@@@${gl_bai}초기 포트 :${gl_huang}3389${gl_bai}" - echo -e "계속하려면 키를 누르십시오 ..." + echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "시스템을 다시 설치하십시오" + echo "시스템 재설치" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." + echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." echo -e "${gl_hui}스크립트를 지원해주신 leitbogioro 보스와 bin456789 보스에게 감사드립니다!${gl_bai} " echo "------------------------" echo "1. Debian 13 2. Debian 12" @@ -4586,12 +4585,12 @@ dd_xitong() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "다시 설치할 시스템을 선택하십시오." sys_choice + read -e -p "다시 설치하려는 시스템을 선택하십시오:" sys_choice case "$sys_choice" in 1) - send_stats "데비안 13을 다시 설치하십시오" + send_stats "데비안 13 재설치" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -4613,21 +4612,21 @@ dd_xitong() { exit ;; 4) - send_stats "데비안 10을 다시 설치하십시오" + send_stats "데비안 10 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "우분투 24.04를 다시 설치하십시오" + send_stats "우분투 24.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "우분투 22.04를 다시 설치하십시오" + send_stats "우분투 22.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot @@ -4641,7 +4640,7 @@ dd_xitong() { exit ;; 14) - send_stats "우분투 18.04를 다시 설치하십시오" + send_stats "우분투 18.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -4658,7 +4657,7 @@ dd_xitong() { ;; 22) - send_stats "Rockylinux9를 다시 설치하십시오" + send_stats "rockylinux9 재설치" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -4666,7 +4665,7 @@ dd_xitong() { ;; 23) - send_stats "Alma10을 다시 설치하십시오" + send_stats "alma10 재설치" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -4682,7 +4681,7 @@ dd_xitong() { ;; 25) - send_stats "Oracle10을 다시 설치하십시오" + send_stats "oracle10 재설치" dd_xitong_3 bash reinstall.sh oracle reboot @@ -4698,7 +4697,7 @@ dd_xitong() { ;; 27) - send_stats "Fedora42를 다시 설치하십시오" + send_stats "fedora42 재설치" dd_xitong_3 bash reinstall.sh fedora reboot @@ -4714,7 +4713,7 @@ dd_xitong() { ;; 29) - send_stats "CentOS10을 다시 설치하십시오" + send_stats "centos10 재설치" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -4730,7 +4729,7 @@ dd_xitong() { ;; 31) - send_stats "알파인을 다시 설치하십시오" + send_stats "알파인 재설치" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -4738,7 +4737,7 @@ dd_xitong() { ;; 32) - send_stats "아치를 다시 설치하십시오" + send_stats "아치 재설치" dd_xitong_3 bash reinstall.sh arch reboot @@ -4754,7 +4753,7 @@ dd_xitong() { ;; 34) - send_stats "Openeuler를 다시 설치하십시오" + send_stats "openeuler 다시 설치" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -4770,7 +4769,7 @@ dd_xitong() { ;; 36) - send_stats "비행 소부소" + send_stats "Feiniu 재설치" dd_xitong_3 bash reinstall.sh fnos reboot @@ -4778,7 +4777,7 @@ dd_xitong() { ;; 41) - send_stats "Windows 11을 다시 설치하십시오" + send_stats "윈도우 11 재설치" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -4787,7 +4786,7 @@ dd_xitong() { 42) dd_xitong_2 - send_stats "Windows 10을 다시 설치하십시오" + send_stats "윈도우 10 재설치" bash InstallNET.sh -windows 10 -lang "cn" reboot exit @@ -4843,7 +4842,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "BBRV3 관리" + send_stats "bbrv3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -4864,7 +4863,7 @@ bbrv3() { echo "------------------------" echo "1. BBRv3 커널 업데이트 2. BBRv3 커널 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice @@ -4911,10 +4910,10 @@ bbrv3() { echo "BBR3 가속 설정" echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "데비안/우분투 만 지원합니다" - echo "데이터를 백업하고 BBR3에서 Linux 커널을 업그레이드 할 수 있습니다." + echo "데비안/우분투만 지원" + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -4922,7 +4921,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경은이를 지원하지 않으며 데비안 및 우분투 시스템 만 지원합니다." + echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." break_end linux_Settings fi @@ -4949,7 +4948,7 @@ bbrv3() { bbr_on - echo "Xanmod 커널이 설치되고 BBR3이 성공적으로 활성화됩니다. 다시 시작한 후에도 적용됩니다" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -4959,7 +4958,7 @@ bbrv3() { echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac fi @@ -4968,37 +4967,37 @@ bbrv3() { elrepo_install() { - # Elrepo GPG 공개 키를 가져 오십시오 - echo "Elrepo GPG 공개 키를 가져 오십시오 ..." + # ELRepo GPG 공개 키 가져오기 + echo "ELRepo GPG 공개 키 가져오기..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 시스템 버전을 감지하십시오 + # 시스템 버전 확인 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 지원되는 운영 체제에서 실행하십시오 + # 지원되는 운영 체제에서 실행되고 있는지 확인하세요. if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "지원되지 않는 운영 체제:$os_name" break_end linux_Settings fi # 감지된 운영 체제 정보 인쇄 - echo "감지 된 운영 체제 :$os_name $os_version" - # 시스템 버전에 따라 해당 Elrepo 창고 구성을 설치하십시오. + echo "감지된 운영 체제:$os_name $os_version" + # 시스템 버전에 따라 해당 ELRepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then - echo "Elrepo 저장소 구성 (버전 8)을 설치하십시오 ..." + echo "ELRepo 저장소 구성(버전 8) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then echo "ELRepo 저장소 구성(버전 9) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Elrepo 저장소 구성 (버전 10)을 설치하십시오 ..." + echo "ELRepo 저장소 구성(버전 10) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "지원되지 않는 시스템 버전 :$os_version" + echo "지원되지 않는 시스템 버전:$os_version" break_end linux_Settings fi # ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치합니다. - echo "Elrepo 커널 저장소를 활성화하고 최신 메인 라인 커널을 설치하십시오 ..." + echo "ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치하세요..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml echo "ELRepo 저장소 구성을 설치하고 최신 메인라인 커널로 업데이트했습니다." @@ -5009,37 +5008,37 @@ elrepo_install() { elrepo() { root_use - send_stats "레드 모자 커널 관리" + send_stats "Red Hat 커널 관리" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "Elrepo 커널을 설치했습니다" - echo "현재 커널 버전 :$kernel_version" + echo "elrepo 커널을 설치했습니다" + echo "현재 커널 버전:$kernel_version" echo "" echo "커널 관리" echo "------------------------" - echo "1. Elrepo 커널 업데이트 2. Elrepo 커널 제거" + echo "1. elrepo 커널 업데이트 2. elrepo 커널 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hat 커널을 업데이트하십시오" + send_stats "Red Hat 커널 업데이트" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "Elrepo 커널은 제거되었습니다. 다시 시작한 후에도 적용됩니다" - send_stats "빨간 모자 커널을 제거하십시오" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + send_stats "Red Hat 커널 제거" server_reboot ;; @@ -5052,10 +5051,10 @@ elrepo() { else clear - echo "데이터를 백업하고 Linux 커널을 업그레이드합니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mh4y1w7qa?t=529.2" + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드해 드리겠습니다." + echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Red Hat 시리즈 배포 Centos/Redhat/Alma/Rocky/Oracle 만 지원합니다" + echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5064,7 +5063,7 @@ elrepo() { [Yy]) check_swap elrepo_install - send_stats "Red Hat 커널을 업그레이드하십시오" + send_stats "Red Hat 커널 업그레이드" server_reboot ;; [Nn]) @@ -5082,7 +5081,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}바이러스 데이터베이스 업데이트 ...${gl_bai}" + echo -e "${gl_huang}바이러스 데이터베이스 업데이트 중...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5092,19 +5091,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi echo -e "${gl_huang}$@ 디렉터리를 검색하는 중...${gl_bai}" - # 마운트 매개 변수를 빌드하십시오 + # 마운트 매개변수 빌드 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # Clamscan 명령 매개 변수를 작성하십시오 + # clamscan 명령 매개변수 빌드 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5113,7 +5112,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # Docker 명령을 실행하십시오 + # 도커 명령 실행 docker run -it --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5122,8 +5121,8 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ scan이 완료되고 바이러스 보고서가 저장됩니다${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}바이러스가 있다면 제발${gl_huang}scan.log${gl_lv}파일에서 찾은 키워드를 검색하여 바이러스의 위치를 ​​확인하십시오.${gl_bai}" + echo -e "${gl_lv}$@ 검사가 완료되고 바이러스 보고서가 다음 위치에 저장됩니다.${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}바이러스 있으면 제발${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" } @@ -5135,16 +5134,16 @@ clamav_scan() { clamav() { root_use - send_stats "바이러스 스캔 관리" + send_stats "바이러스 검사 관리" while true; do clear echo "clamav 바이러스 검사 도구" echo "영상 소개: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "다양한 유형의 악성 코드를 탐지하고 제거하는 데 주로 사용되는 오픈 소스 바이러스 백신 소프트웨어 도구입니다." - echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어를 포함합니다." + echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어가 포함됩니다." echo "------------------------" - echo -e "${gl_lv}1. 전체 디스크 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리 스캔${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉토리 스캔${gl_bai}" + echo -e "${gl_lv}1. 전체 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리 스캔${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉터리 검색${gl_bai}" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -5188,9 +5187,9 @@ clamav() { # 고성능 모드 최적화 기능 optimize_high_performance() { - echo -e "${gl_lv}전환하십시오${tiaoyou_moshi}...${gl_bai}" + echo -e "${gl_lv}로 전환하다${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" ulimit -n 65535 echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" @@ -5215,11 +5214,11 @@ optimize_high_performance() { echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}기타 최적화...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. echo never > /sys/kernel/mm/transparent_hugepage/enabled # NUMA 밸런싱 비활성화 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5227,21 +5226,21 @@ optimize_high_performance() { } -# 이퀄라이제이션 모드 최적화 기능 +# 균형 모드 최적화 기능 optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환 ...${gl_bai}" + echo -e "${gl_lv}이퀄라이제이션 모드로 전환...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}가상 메모리 최적화 ...${gl_bai}" + echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5253,14 +5252,14 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 투명 페이지를 복원하십시오 + echo -e "${gl_lv}기타 최적화...${gl_bai}" + # 투명한 대용량 페이지 복원 echo always > /sys/kernel/mm/transparent_hugepage/enabled # NUMA 밸런싱 복원 sysctl -w kernel.numa_balancing=1 2>/dev/null @@ -5268,21 +5267,21 @@ optimize_balanced() { } -# 기본 설정 기능을 복원하십시오 +# 기본 설정 복원 기능 restore_defaults() { echo -e "${gl_lv}기본 설정으로 되돌리기...${gl_bai}" echo -e "${gl_lv}파일 설명자를 복원합니다...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}가상 메모리 복원 ...${gl_bai}" + echo -e "${gl_lv}가상 메모리 복원...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}네트워크 설정 복원 ...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 재설정...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5314,7 +5313,7 @@ restore_defaults() { optimize_web_server() { echo -e "${gl_lv}웹사이트 구축 최적화 모드로 전환...${gl_bai}" - echo -e "${gl_lv}파일 설명자 최적화 ...${gl_bai}" + echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" ulimit -n 65535 echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" @@ -5324,7 +5323,7 @@ optimize_web_server() { sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}네트워크 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -5336,14 +5335,14 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}캐시 관리 최적화 ...${gl_bai}" + echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}CPU 설정 최적화 ...${gl_bai}" + echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - echo -e "${gl_lv}기타 최적화 ...${gl_bai}" - # 대형 투명 페이지를 비활성화하여 대기 시간을 줄입니다 + echo -e "${gl_lv}기타 최적화...${gl_bai}" + # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. echo never > /sys/kernel/mm/transparent_hugepage/enabled # NUMA 밸런싱 비활성화 sysctl -w kernel.numa_balancing=0 2>/dev/null @@ -5357,20 +5356,20 @@ Kernel_optimize() { while true; do clear send_stats "Linux 커널 튜닝 관리" - echo "Linux 시스템에서 커널 매개 변수의 최적화" + echo "Linux 시스템 커널 매개변수 최적화" echo "영상 소개: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개 변수 튜닝 모드가 제공되며 사용자는 자체 사용 시나리오에 따라 선택하고 전환 할 수 있습니다." + echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." echo -e "${gl_huang}힌트:${gl_bai}프로덕션 환경에서는 주의해서 사용해주세요!" echo "--------------------" echo "1. 고성능 최적화 모드: 시스템 성능을 최대화하고 파일 설명자, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." echo "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." echo "3. 웹사이트 최적화 모드: 웹사이트 서버를 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." - echo "4. 라이브 브로드 캐스트 최적화 모드 : 라이브 방송 스트리밍의 특별한 요구를 최적화하여 대기 시간을 줄이고 전송 성능을 향상시킵니다." - echo "5. 게임 서버 최적화 모드 : 게임 서버를 위해 동시 처리 기능 및 응답 속도를 향상시킬 최적화." + echo "4. 라이브 방송 최적화 모드: 라이브 스트리밍의 특별한 요구 사항을 최적화하여 지연을 줄이고 전송 성능을 향상시킵니다." + echo "5. 게임 서버 최적화 모드: 게임 서버를 최적화하여 동시 처리 기능과 응답 속도를 향상시킵니다." echo "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." echo "--------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -5391,7 +5390,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹 사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -5411,7 +5410,7 @@ Kernel_optimize() { cd ~ clear restore_defaults - send_stats "기본 설정을 복원하십시오" + send_stats "기본 설정 복원" ;; *) break @@ -5438,7 +5437,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" hash -r break_end @@ -5447,7 +5446,7 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$langSSH를 다시 ​​연결하면 적용됩니다.${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" hash -r break_end ;; @@ -5467,25 +5466,25 @@ update_locale() { linux_language() { root_use -send_stats "스위치 시스템 언어" +send_stats "시스템 언어 전환" while true; do clear echo "현재 시스템 언어:$LANG" echo "------------------------" - echo "1. 영어 2. 중국어 3. 전통 중국어" + echo "1. 영어 2. 중국어 간체 3. 중국어 번체" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "영어로 전환하십시오" + send_stats "영어로 전환" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "단순화 된 중국어로 전환하십시오" + send_stats "중국어 간체로 전환" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" @@ -5511,7 +5510,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 볼 수 있도록 SSH를 다시 ​​연결하십시오!${gl_bai}" +echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 보려면 SSH에 다시 연결하세요!${gl_bai}" hash -r break_end @@ -5535,9 +5534,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -5598,12 +5597,12 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화 후 RM이 삭제 한 파일은 먼저 재활용 빈에 입력하여 중요한 파일의 잘못된 삭제를 방지합니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" echo "1. 휴지통 활성화 2. 휴지통 닫기" - echo "3. 컨텐츠를 복원 4. 재활용 쓰레기통을 지 웁니다" + echo "3. 콘텐츠 복원 4. 휴지통 비우기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -5623,7 +5622,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "재활용 빈이 닫히고 파일이 직접 삭제됩니다." + echo "휴지통이 닫히고 파일이 직접 삭제됩니다." sleep 2 ;; 3) @@ -5639,7 +5638,7 @@ linux_trash() { read -e -p "휴지통을 비우시겠습니까? [예/아니요]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "재활용 쓰레기통이 지워졌습니다." + echo "휴지통이 비워졌습니다." fi ;; *) @@ -5654,17 +5653,17 @@ send_stats "명령 즐겨찾기" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 백업을 만듭니다 +# 백업 만들기 create_backup() { send_stats "백업 만들기" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # 사용자에게 백업 디렉터리를 묻는 메시지 표시 - echo "백업 예제 :" + echo "백업 생성 예:" echo "- 단일 디렉터리 백업: /var/www" echo "- 여러 디렉터리 백업: /etc /home /var/log" echo "- Enter를 눌러 기본 디렉터리(/etc/usr/home)를 사용합니다." - read -r -p "백업 디렉토리를 입력하십시오 (여러 디렉토리가 공간별로 구분되며 직접 입력하면 기본 디렉토리를 사용하십시오)." input + read -r -p "백업할 디렉터리를 입력하십시오(여러 디렉터리를 공백으로 구분하고 Enter를 눌러 기본 디렉터리를 사용하십시오)." input # 사용자가 디렉터리를 입력하지 않으면 기본 디렉터리가 사용됩니다. if [ -z "$input" ]; then @@ -5686,13 +5685,13 @@ create_backup() { PREFIX+="${dir_name}_" done - # 마지막 밑줄을 제거하십시오 + # 마지막 밑줄 제거 local PREFIX=${PREFIX%_} # 백업 파일 이름 생성 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 사용자가 선택한 디렉토리를 인쇄하십시오 + # 사용자가 선택한 디렉토리 인쇄 echo "선택한 백업 디렉터리는 다음과 같습니다." for path in "${BACKUP_PATHS[@]}"; do echo "- $path" @@ -5714,11 +5713,11 @@ create_backup() { # 백업 복원 restore_backup() { - send_stats "백업을 복원하십시오" - # 복원하려는 백업을 선택하십시오 + send_stats "백업 복원" + # 복원할 백업을 선택하세요 read -e -p "복원할 백업 파일 이름을 입력하십시오:" BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 백업 파일이 있는지 확인 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then echo "백업 파일이 존재하지 않습니다!" exit 1 @@ -5730,34 +5729,34 @@ restore_backup() { if [ $? -eq 0 ]; then echo "백업 및 복원 성공!" else - echo "백업 복구 실패!" + echo "백업 복원에 실패했습니다!" exit 1 fi } -# 백업을 나열합니다 +# 백업 나열 list_backups() { - echo "사용 가능한 백업 :" + echo "사용 가능한 백업:" ls -1 "$BACKUP_DIR" } -# 백업을 삭제하십시오 +# 백업 삭제 delete_backup() { send_stats "백업 삭제" read -e -p "삭제할 백업 파일 이름을 입력하십시오:" BACKUP_NAME - # 백업 파일이 있는지 확인하십시오 + # 백업 파일이 있는지 확인 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then echo "백업 파일이 존재하지 않습니다!" exit 1 fi - # 백업을 삭제하십시오 + # 백업 삭제 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "백업이 성공적으로 삭제되었습니다!" + echo "백업이 삭제되었습니다!" else echo "백업 삭제에 실패했습니다!" exit 1 @@ -5777,7 +5776,7 @@ linux_backup() { echo "------------------------" echo "1. 백업 생성 2. 백업 복원 3. 백업 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" choice case $choice in @@ -5786,7 +5785,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "계속하려면 Enter를 누르세요..." done } @@ -5800,7 +5799,7 @@ linux_backup() { # 연결 목록 표시 list_connections() { - echo "저장된 연결 :" + echo "저장된 연결:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" @@ -5809,39 +5808,39 @@ list_connections() { # 새 연결 추가 add_connection() { - send_stats "새 연결을 추가하십시오" + send_stats "새 연결 추가" echo "새 연결 생성의 예:" echo "- 연결 이름: my_server" echo "- IP 주소: 192.168.1.100" echo "- 사용자 이름: 루트" echo "- 포트: 22" echo "------------------------" - read -e -p "연결 이름을 입력하십시오 :" name - read -e -p "IP 주소를 입력하십시오 :" ip + read -e -p "연결 이름을 입력하세요:" name + read -e -p "IP 주소를 입력하세요:" ip read -e -p "사용자 이름을 입력하십시오(기본값: 루트):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "포트 번호를 입력하십시오 (기본값 : 22) :" port + read -e -p "포트 번호를 입력하십시오(기본값: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 - echo "인증 방법을 선택하십시오 :" + echo "인증 방법을 선택하세요:" echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택 (1/2)을 입력하십시오 :" auth_choice + echo "2. 열쇠" + read -e -p "원하는 항목(1/2)을 입력하세요." auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하십시오 :" password_or_key + read -s -p "비밀번호를 입력하세요:" password_or_key echo # 换行 ;; 2) echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 비어 있고 키 컨텐츠에 이미 시작이 포함되어 있으면 입력이 끝납니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -5870,7 +5869,7 @@ add_connection() { # 연결 삭제 delete_connection() { send_stats "연결 삭제" - read -e -p "삭제하려면 연결 번호를 입력하십시오." num + read -e -p "삭제할 연결 번호를 입력하세요:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -5880,7 +5879,7 @@ delete_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하세요. if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -5889,14 +5888,14 @@ delete_connection() { echo "연결이 삭제되었습니다!" } -# 연결을 사용하십시오 +# 연결 사용 use_connection() { send_stats "연결 사용" - read -e -p "사용할 연결 번호를 입력하십시오." num + read -e -p "사용할 연결 번호를 입력하세요:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류 : 해당 연결을 찾을 수 없었습니다." + echo "오류: 해당 연결을 찾을 수 없습니다." return fi @@ -5904,18 +5903,18 @@ use_connection() { echo "연결 중$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 키와 연결하십시오 + # 키를 사용하여 연결 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 키 파일 경로가 정확합니까?$password_or_key" + echo "연결에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 키파일 경로가 맞나요?$password_or_key" echo "2. 키 파일 권한이 올바른가요(600이어야 함)." echo "3. 대상 서버에서 키를 이용한 로그인을 허용하는지 여부." fi else - # 비밀번호로 연결하십시오 + # 비밀번호를 사용하여 연결 if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -5923,10 +5922,10 @@ use_connection() { fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결 실패! 다음을 확인하십시오." - echo "1. 사용자 이름과 비밀번호가 올바른지 여부." - echo "2. 대상 서버가 암호 로그인을 허용하는지 여부." - echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되는지 여부." + echo "연결에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 사용자 이름과 비밀번호가 정확합니까?" + echo "2. 대상 서버에서 비밀번호 로그인을 허용하는지 여부." + echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되고 있는지 여부." fi fi } @@ -5938,7 +5937,7 @@ ssh_manager() { CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 구성 파일과 키 디렉토리가 존재하는지 확인하고 존재하지 않으면 작성하십시오. + # 구성 파일과 키 디렉터리가 있는지 확인하고 없으면 만듭니다. if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -5958,7 +5957,7 @@ ssh_manager() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) add_connection ;; 2) use_connection ;; @@ -5986,10 +5985,10 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 파티션을 장착하십시오 +# 마운트 파티션 mount_partition() { - send_stats "파티션을 장착하십시오" - read -e -p "장착 할 파티션 이름을 입력하십시오 (예 : SDA1) :" PARTITION + send_stats "마운트 파티션" + read -e -p "마운트할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then @@ -6003,17 +6002,17 @@ mount_partition() { return fi - # 마운트 포인트를 만듭니다 + # 마운트 지점 생성 MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 파티션을 장착하십시오 + # 마운트 파티션 mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then echo "파티션이 성공적으로 마운트되었습니다:$MOUNT_POINT" else - echo "파티션 마운트 실패!" + echo "파티션 마운트에 실패했습니다!" rmdir "$MOUNT_POINT" fi } @@ -6021,38 +6020,38 @@ mount_partition() { # 파티션 마운트 해제 unmount_partition() { send_stats "파티션 마운트 해제" - read -e -p "파티션 이름 (예 : SDA1)을 입력하십시오." PARTITION + read -e -p "마운트 해제할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION - # 파티션이 이미 장착되어 있는지 확인하십시오 + # 파티션이 마운트되었는지 확인 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then echo "파티션이 마운트되지 않았습니다!" return fi - # 파티션을 제거하십시오 + # 파티션 마운트 해제 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then echo "파티션이 성공적으로 제거되었습니다:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "파티션 제거 실패!" + echo "파티션 제거에 실패했습니다!" fi } -# 목록 장착 파티션 +# 마운트된 파티션 나열 list_mounted_partitions() { echo "마운트된 파티션:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 형식 파티션 +# 파티션 포맷 format_partition() { send_stats "파티션 포맷" read -e -p "포맷할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION - # 파티션이 있는지 확인하십시오 + # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "파티션이 존재하지 않습니다!" return @@ -6065,12 +6064,12 @@ format_partition() { fi # 파일 시스템 유형 선택 - echo "파일 시스템 유형을 선택하십시오 :" + echo "파일 시스템 유형을 선택하십시오:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "선택을 입력하십시오 :" FS_CHOICE + read -e -p "선택사항을 입력하세요:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; @@ -6080,30 +6079,30 @@ format_partition() { *) echo "잘못된 선택입니다!"; return ;; esac - # 형식을 확인하십시오 + # 포맷 확인 read -e -p "포맷된 파티션 /dev/ 확인$PARTITION~을 위한$FS_TYPE? (예/아니요):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "작업이 취소되었습니다." return fi - # 형식 파티션 - echo "파티션 서식 /dev /$PARTITION~을 위한$FS_TYPE ..." + # 파티션 포맷 + echo "파티션 /dev/ 포맷 중$PARTITION~을 위한$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then echo "파티션이 성공적으로 포맷되었습니다!" else - echo "파티션 형식이 실패했습니다!" + echo "파티션 포맷에 실패했습니다!" fi } -# 파티션 상태를 확인하십시오 +# 파티션 상태 확인 check_partition() { - send_stats "파티션 상태를 확인하십시오" - read -e -p "파티션 이름을 입력하여 확인하십시오 (예 : SDA1) :" PARTITION + send_stats "파티션 상태 확인" + read -e -p "확인할 파티션 이름을 입력하세요(예: sda1):" PARTITION - # 파티션이 있는지 확인하십시오 + # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "파티션이 존재하지 않습니다!" return @@ -6116,18 +6115,18 @@ check_partition() { # 메인 메뉴 disk_manager() { - send_stats "하드 디스크 관리 기능" + send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 파티션 마운트 2. 파티션 3. 마운트 파티션보기" + echo "1. 파티션 마운트 2. 파티션 마운트 해제 3. 마운트된 파티션 보기" echo "4. 파티션 포맷 5. 파티션 상태 확인" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" choice case $choice in @@ -6147,33 +6146,33 @@ disk_manager() { # 작업 목록 표시 list_tasks() { - echo "저장된 동기화 작업 :" + echo "저장된 동기화 작업:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 새로운 작업을 추가하십시오 +# 새 작업 추가 add_task() { - send_stats "새 동기화 작업을 추가하십시오" - echo "새 동기화 작업 작성 예 :" + send_stats "새 동기화 작업 추가" + echo "새 동기화 작업 생성의 예:" echo "- 작업 이름: backup_www" - echo "- 로컬 디렉토리 : /var /www" - echo "- 원격 주소 : user@192.168.1.100" - echo "- 원격 디렉토리 : /백업 /www" + echo "- 로컬 디렉터리: /var/www" + echo "- 원격 주소: user@192.168.1.100" + echo "- 원격 디렉터리: /backup/www" echo "- 포트 번호(기본값 22)" echo "---------------------------------" - read -e -p "작업 이름을 입력하십시오 :" name + read -e -p "작업 이름을 입력하세요:" name read -e -p "로컬 디렉토리를 입력하십시오:" local_path - read -e -p "원격 디렉토리를 입력하십시오 :" remote_path - read -e -p "원격 사용자 @IP를 입력하십시오 :" remote - read -e -p "SSH 포트 (기본값 22)를 입력하십시오 :" port + read -e -p "원격 디렉토리를 입력하십시오:" remote_path + read -e -p "원격 user@IP를 입력하십시오:" remote + read -e -p "SSH 포트(기본값 22)를 입력하세요." port port=${port:-22} - echo "인증 방법을 선택하십시오 :" + echo "인증 방법을 선택하세요:" echo "1. 비밀번호" - echo "2. 키" - read -e -p "선택하십시오 (1/2) :" auth_choice + echo "2. 열쇠" + read -e -p "(1/2)을 선택하세요:" auth_choice case $auth_choice in 1) @@ -6182,14 +6181,14 @@ add_task() { auth_method="password" ;; 2) - echo "키 내용을 붙여 넣으십시오 (붙여 넣기 후 Enter Enter를 두 번 누릅니다) :" + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 키 컨텐츠가 입력 된 경우 계속 추가하십시오. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6203,7 +6202,7 @@ add_task() { password_or_key="$key_file" auth_method="key" else - echo "잘못된 키 컨텐츠!" + echo "잘못된 키 콘텐츠입니다!" return fi ;; @@ -6213,9 +6212,9 @@ add_task() { ;; esac - echo "동기화 모드를 선택하십시오 :" - echo "1. 표준 모드 (-avz)" - echo "2. 대상 파일 삭제 (-avz-delete)" + echo "동기화 모드를 선택하십시오:" + echo "1. 표준 모드(-avz)" + echo "2. 대상 파일 삭제(-avz --delete)" read -e -p "(1/2)을 선택하세요:" mode case $mode in 1) options="-avz" ;; @@ -6230,20 +6229,20 @@ add_task() { echo "임무가 저장되었습니다!" } -# 작업을 삭제하십시오 +# 할 일 삭제 delete_task() { - send_stats "동기화 작업을 삭제합니다" - read -e -p "삭제하려면 작업 번호를 입력하십시오." num + send_stats "동기화 작업 삭제" + read -e -p "삭제할 작업 번호를 입력하세요:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 해당 작업을 찾을 수 없었습니다." + echo "오류: 해당 작업을 찾을 수 없습니다." return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하십시오. + # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하세요. if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -6254,12 +6253,12 @@ delete_task() { run_task() { - send_stats "동기화 작업을 수행하십시오" + send_stats "동기화 작업 수행" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 매개 변수를 분석하십시오 + # 매개변수 구문 분석 local direction="push" # 默认是推送到远端 local num @@ -6270,14 +6269,14 @@ run_task() { num="$1" fi - # 들어오는 작업 번호가없는 경우 사용자에게 입력하라는 메시지를 표시하십시오. + # 작업 번호가 전달되지 않으면 사용자에게 입력하라는 메시지가 표시됩니다. if [[ -z "$num" ]]; then - read -e -p "실행할 작업 번호를 입력하십시오." num + read -e -p "실행할 작업 번호를 입력하세요:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류 : 작업이 찾을 수 없었습니다!" + echo "오류: 작업을 찾을 수 없습니다!" return fi @@ -6285,11 +6284,11 @@ run_task() { # 동기화 방향에 따라 소스 및 대상 경로 조정 if [[ "$direction" == "pull" ]]; then - echo "로컬로 동기화를 당기기 :$remote:$local_path -> $remote_path" + echo "로컬로 가져오기 및 동기화:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "동기화를 원격 끝으로 푸시합니다.$local_path -> $remote:$remote_path" + echo "원격 끝에 푸시 및 동기화:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi @@ -6299,7 +6298,7 @@ run_task() { if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류 : Sshpass가 설치되지 않았습니다. 먼저 Sshpass를 설치하십시오." + echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -6307,14 +6306,14 @@ run_task() { fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 키 파일이 존재하는지 여부와 권한이 올바른지 확인 + # 키 파일이 존재하는지, 권한이 올바른지 확인하세요. if [[ ! -f "$password_or_key" ]]; then - echo "오류 : 키 파일이 존재하지 않습니다.$password_or_key" + echo "오류: 키 파일이 존재하지 않습니다:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "경고 : 키 파일 권한이 잘못되었고 수리 중입니다 ..." + echo "경고: 잘못된 키 파일 권한, 수정 중..." chmod 600 "$password_or_key" fi @@ -6324,10 +6323,10 @@ run_task() { if [[ $? -eq 0 ]]; then echo "동기화가 완료되었습니다!" else - echo "동기화 실패! 다음을 확인하십시오." - echo "1. 네트워크 연결이 정상입니까?" + echo "동기화에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 네트워크 연결이 정상인가요?" echo "2. 원격 호스트에 접근 가능한지 여부" - echo "3. 인증 정보가 정확합니까?" + echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi } @@ -6339,13 +6338,13 @@ schedule_task() { read -e -p "정기적으로 동기화할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류 : 유효한 작업 번호를 입력하십시오!" + echo "오류: 유효한 작업 번호를 입력하십시오!" return fi echo "예약된 실행 간격을 선택하십시오." echo "1) 매 시간마다 한 번씩 실행" - echo "2) 하루에 한 번 수행하십시오" + echo "2) 하루에 한 번 실행" echo "3) 일주일에 한 번 실행" read -e -p "옵션을 입력하세요(1/2/3):" interval @@ -6361,7 +6360,7 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 동일한 작업이 이미 존재하는지 확인하십시오 + # 동일한 작업이 이미 존재하는지 확인하세요. if crontab -l | grep -q "k rsync_run $num"; then echo "오류: 이 작업에 대해 예약된 동기화가 이미 존재합니다!" return @@ -6372,7 +6371,7 @@ schedule_task() { echo "예약된 작업이 생성되었습니다:$cron_job" } -# 예정된 작업을 봅니다 +# 예약된 작업 보기 view_tasks() { echo "현재 예약된 작업:" echo "---------------------------------" @@ -6380,9 +6379,9 @@ view_tasks() { echo "---------------------------------" } -# 타이밍 작업을 삭제하십시오 +# 예약된 작업 삭제 delete_task_schedule() { - send_stats "동기화 타이밍 작업을 삭제합니다" + send_stats "동기화 예약 작업 삭제" read -e -p "삭제할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then echo "오류: 유효한 작업 번호를 입력하십시오!" @@ -6402,19 +6401,19 @@ rsync_manager() { while true; do clear echo "Rsync 원격 동기화 도구" - echo "원격 디렉토리 간의 동기화는 증분 동기화, 효율적이고 안정적인 지원을 지원합니다." + echo "원격 디렉터리 간의 동기화는 효율적이고 안정적인 증분 동기화를 지원합니다." echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 새 작업 생성 2. 작업을 삭제하십시오" + echo "1. 새 작업 생성 2. 작업 삭제" echo "3. 원격 사이트에 대한 로컬 동기화 수행 4. 로컬 사이트에 대한 원격 동기화 수행" - echo "5. 타이밍 작업 만들기 6. 타이밍 작업 삭제" + echo "5. 예약된 작업 생성 6. 예약된 작업 삭제" echo "---------------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "---------------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -6425,7 +6424,7 @@ rsync_manager() { 0) break ;; *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; esac - read -e -p "계속하려면 Enter를 누르십시오 ..." + read -e -p "계속하려면 Enter를 누르세요..." done } @@ -6494,18 +6493,18 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}호스트 이름:${gl_bai}$hostname" echo -e "${gl_kjlan}시스템 버전:${gl_bai}$os_info" - echo -e "${gl_kjlan}리눅스 버전 :${gl_bai}$kernel_version" + echo -e "${gl_kjlan}리눅스 버전:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 아키텍처 :${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU 아키텍처:${gl_bai}$cpu_arch" echo -e "${gl_kjlan}CPU 모델:${gl_bai}$cpu_info" echo -e "${gl_kjlan}CPU 코어 수:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU 주파수 :${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU 주파수:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 점유 :${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}CPU 사용량:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" echo -e "${gl_kjlan}가상 메모리:${gl_bai}$swap_info" - echo -e "${gl_kjlan}하드 디스크 직업 :${gl_bai}$disk_info" + echo -e "${gl_kjlan}하드 드라이브 사용량:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" @@ -6518,11 +6517,11 @@ linux_info() { fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6 주소 :${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6 주소:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS 주소 :${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}지리적 위치 :${gl_bai}$country $city" - echo -e "${gl_kjlan}시스템 시간 :${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS 주소:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}위치:${gl_bai}$country $city" + echo -e "${gl_kjlan}시스템 시간:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" echo @@ -6540,54 +6539,54 @@ linux_tools() { # send_stats "기본 도구" echo -e "기본 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}WGET 다운로드 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}Sudo Super Management 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" + echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 다운로드 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 최고 관리 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" echo -e "${gl_kjlan}5. ${gl_bai}htop 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}iftop 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}압축 지퍼 압축 압축 압축 도구${gl_kjlan}8. ${gl_bai}TAR GZ 압축 감압 도구" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP 압축 및 압축 풀기 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}범위 파일 관리 도구" - echo -e "${gl_kjlan}13. ${gl_bai}NCDU 디스크 직업 관찰 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" + echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}레인저 파일 관리 도구" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 디스크 사용량 보기 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}GIT 버전 제어 시스템" + echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 화면 보증${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 게임${gl_kjlan}27. ${gl_bai}뱀 먹는 게임" + echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 스크린세이버${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 미니게임" echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 미니 게임" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}모두 설치하십시오${gl_kjlan}32. ${gl_bai}모든 설치 (스크린 세이버 및 게임 제외)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}모든 것을 제거하십시오" + echo -e "${gl_kjlan}31. ${gl_bai}모두 설치${gl_kjlan}32. ${gl_bai}모두 설치(화면 보호기 및 게임 제외)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}모두 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구를 설치하십시오${gl_kjlan}42. ${gl_bai}지정된 도구 제거" + echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구 설치${gl_kjlan}42. ${gl_bai}지정된 도구 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear install curl clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." curl --help - send_stats "컬을 설치하십시오" + send_stats "컬 설치" ;; 2) clear install wget clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." wget --help - send_stats "wget을 설치하십시오" + send_stats "wget 설치" ;; 3) clear install sudo clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." sudo --help - send_stats "Sudo를 설치하십시오" + send_stats "sudo 설치" ;; 4) clear @@ -6602,14 +6601,14 @@ linux_tools() { install htop clear htop - send_stats "HTOP를 설치하십시오" + send_stats "htop 설치" ;; 6) clear install iftop clear iftop - send_stats "iftop을 설치하십시오" + send_stats "iftop 설치" ;; 7) clear @@ -6617,7 +6616,7 @@ linux_tools() { clear echo "도구가 설치되었으며 다음과 같이 사용됩니다." unzip - send_stats "압축을 설치하십시오" + send_stats "설치압축 해제" ;; 8) clear @@ -6631,9 +6630,9 @@ linux_tools() { clear install tmux clear - echo "도구가 설치되었으며 사용법은 다음과 같습니다." + echo "도구가 설치되었으며 다음과 같이 사용됩니다." tmux --help - send_stats "tmux를 설치하십시오" + send_stats "tmux 설치" ;; 10) clear @@ -6641,7 +6640,7 @@ linux_tools() { clear echo "도구가 설치되었으며 다음과 같이 사용됩니다." ffmpeg --help - send_stats "FFMPEG를 설치하십시오" + send_stats "ffmpeg 설치" ;; 11) @@ -6649,7 +6648,7 @@ linux_tools() { install btop clear btop - send_stats "Btop을 설치하십시오" + send_stats "btop 설치" ;; 12) clear @@ -6658,7 +6657,7 @@ linux_tools() { clear ranger cd ~ - send_stats "레인저를 설치하십시오" + send_stats "레인저 설치" ;; 13) clear @@ -6694,7 +6693,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "나노를 설치하십시오" + send_stats "나노 설치" ;; @@ -6713,7 +6712,7 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix를 설치하십시오" + send_stats "cmatrix 설치" ;; 22) clear @@ -6741,25 +6740,25 @@ linux_tools() { install ninvaders clear ninvaders - send_stats "Ninvaders를 설치하십시오" + send_stats "닌베이더 설치" ;; 31) clear - send_stats "모두 설치하십시오" + send_stats "모두 설치" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "모든 설치 (게임 및 화면 보호기 제외)" + send_stats "모두 설치(게임 및 화면 보호기 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "모든 것을 제거하십시오" + send_stats "모두 제거" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; @@ -6767,13 +6766,13 @@ linux_tools() { clear read -e -p "설치된 도구 이름을 입력하십시오(wget 컬 sudo htop):" installname install $installname - send_stats "지정된 소프트웨어를 설치하십시오" + send_stats "지정된 소프트웨어 설치" ;; 42) clear read -e -p "제거된 도구 이름(htop ufw tmux cmatrix)을 입력하십시오." removename remove $removename - send_stats "지정된 소프트웨어를 제거하십시오" + send_stats "지정된 소프트웨어 제거" ;; 0) @@ -6801,16 +6800,16 @@ linux_bbr() { clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "현재 TCP 차단 알고리즘 :$congestion_algorithm $queue_algorithm" + echo "현재 TCP 차단 알고리즘:$congestion_algorithm $queue_algorithm" echo "" echo "BBR 관리" echo "------------------------" echo "1. BBRv3를 켭니다. 2. BBRv3을 끕니다(다시 시작됩니다)." echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -6857,7 +6856,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}현재 백업 목록 :${NC}" + echo -e "${BLUE}현재 백업 목록:${NC}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" } @@ -6869,9 +6868,9 @@ docker_ssh_migration() { backup_docker() { send_stats "도커 백업" - echo -e "${YELLOW}Docker 컨테이너 백업 ...${NC}" + echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -6898,17 +6897,17 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}백업 컨테이너 :$c${NC}" + echo -e "${GREEN}백업 컨테이너:$c${NC}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}감지$c도커 작성 컨테이너입니다${NC}" + echo -e "${BLUE}감지됨$c도커 작성 컨테이너입니다${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "Compose 디렉토리가 감지되지 않으므로 수동으로 경로를 입력하십시오." project_dir + read -e -p "작성 디렉터리가 감지되지 않습니다. 경로를 수동으로 입력하세요." project_dir fi # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. @@ -6924,9 +6923,9 @@ docker_ssh_migration() { echo "# docker-compose 복원:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}프로젝트 작성 [$project_name] 포장 :${project_dir}${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name] 포장:${project_dir}${NC}" else - echo -e "${RED}docker-compose.yml을 찾을 수 없고이 컨테이너를 건너 뛰십시오 ...${NC}" + echo -e "${RED}docker-compose.yml을 찾을 수 없습니다. 이 컨테이너를 건너뛰는 중입니다...${NC}" fi else # 일반 컨테이너 백업 볼륨 @@ -6963,14 +6962,14 @@ docker_ssh_migration() { # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home /docker 아래 파일을 백업 ...${NC}" + echo -e "${BLUE}/home/docker 아래의 파일을 백업합니다...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi chmod +x "$RESTORE_SCRIPT" echo -e "${GREEN}백업 완료:${BACKUP_DIR}${NC}" - echo -e "${GREEN}사용 가능한 복원 스크립트 :${RESTORE_SCRIPT}${NC}" + echo -e "${GREEN}사용 가능한 복원 스크립트:${RESTORE_SCRIPT}${NC}" } @@ -6981,52 +6980,52 @@ docker_ssh_migration() { restore_docker() { send_stats "도커 복원" - read -e -p "복원하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + read -e -p "복원할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } - echo -e "${BLUE}복원 작업 시작 ...${NC}" + echo -e "${BLUE}복원 작업을 시작하는 중...${NC}" install tar jq gzip install_docker - # ----------------------------- + # --------- Compose 프로젝트 복원 우선순위 지정 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -e -p "원래 경로는 찾을 수 없었습니다. 복원 디렉토리 경로를 입력하십시오." original_path + [[ -z "$original_path" ]] && read -e -p "원래 경로를 찾을 수 없습니다. 복원 디렉터리 경로를 입력하십시오:" original_path # Compose 프로젝트의 컨테이너가 이미 실행 중인지 확인하세요. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 컨테이너가 실행 중입니다. 스킵 복원 ...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 컨테이너가 이미 실행 중입니다. 복원을 건너뛰세요...${NC}" continue fi read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -e -p "새로운 복원 경로를 입력하십시오 :" original_path + [[ "$confirm" != "y" ]] && read -e -p "새 복원 경로를 입력하십시오." original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name] 압축 압축 : :$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}작곡 프로젝트 [$project_name] 복원 완료!${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name] 복원 완료!${NC}" fi done # --------- 일반 컨테이너를 계속 복원합니다 --------- - echo -e "${BLUE}일반적인 도커 컨테이너를 확인하고 복원하십시오 ...${NC}" + echo -e "${BLUE}일반 Docker 컨테이너 확인 및 복원...${NC}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 컨테이너 :$container${NC}" + echo -e "${GREEN}처리 용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7067,20 +7066,20 @@ docker_ssh_migration() { fi done - # 기존이지만 실행되지 않은 컨테이너를 삭제하십시오 + # 기존이지만 실행되지 않는 컨테이너 삭제 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then echo -e "${YELLOW}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${NC}" docker rm -f "$container" fi - # 컨테이너를 시작하십시오 + # 컨테이너 시작 echo "복원 명령을 실행합니다: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done [[ "$has_container" == false ]] && echo -e "${YELLOW}공통 컨테이너에 대한 백업 정보가 없습니다.${NC}" - # /home /docker에서 파일을 복원하십시오 + # /home/docker 아래의 파일 복원 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker 아래의 파일을 복원하는 중...${NC}" mkdir -p /home/docker @@ -7095,24 +7094,24 @@ docker_ssh_migration() { # ---------------------------- - # 마이그레이션 + # 이주하다 # ---------------------------- migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션하려면 백업 디렉토리를 입력하십시오." BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } - read -e -p "대상 서버 IP :" TARGET_IP + read -e -p "대상 서버 IP:" TARGET_IP read -e -p "대상 서버 SSH 사용자 이름:" TARGET_USER - read -e -p "대상 서버 SSH 포트 [기본값 22] :" TARGET_PORT + read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}백업 전송 ...${NC}" + echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7124,9 +7123,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker 백업 파일 삭제" read -e -p "삭제할 백업 디렉터리를 입력하십시오:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉토리가 존재하지 않습니다${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}삭제 된 백업 :${BACKUP_DIR}${NC}" + echo -e "${GREEN}삭제된 백업:${BACKUP_DIR}${NC}" } # ---------------------------- @@ -7137,15 +7136,15 @@ docker_ssh_migration() { while true; do clear echo "------------------------" - echo -e "도커 백업/마이그레이션/복원 도구" + echo -e "Docker 백업/마이그레이션/복원 도구" echo "------------------------" list_backups echo -e "" echo "------------------------" echo -e "1. 도커 프로젝트 백업" - echo -e "2. Docker 프로젝트를 마이그레이션합니다" + echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제하십시오" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -7173,13 +7172,13 @@ linux_docker() { while true; do clear - # Send_stats "Docker Management" + # send_stats "도커 관리" echo -e "도커 관리" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경을 설치하고 업데이트하십시오${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경 설치 및 업데이트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Docker Global Status를 봅니다${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Docker 전역 상태 보기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" @@ -7191,7 +7190,7 @@ linux_docker() { echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스 변경" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Docker-IPV6 액세스를 활성화하십시오" + echo -e "${gl_kjlan}11. ${gl_bai}Docker-ipv6 액세스 활성화" echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 액세스 끄기" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}19. ${gl_bai}Docker 환경 백업/마이그레이션/복원" @@ -7204,7 +7203,7 @@ linux_docker() { case $sub_choice in 1) clear - send_stats "Docker 환경을 설치하십시오" + send_stats "도커 환경 설치" install_add_docker ;; @@ -7215,7 +7214,7 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "도커 글로벌 상태" + send_stats "도커 전역 상태" echo "도커 버전" docker -v docker compose version @@ -7224,10 +7223,10 @@ linux_docker() { echo -e "도커 이미지:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "도커 컨테이너 :${gl_lv}$container_count${gl_bai}" + echo -e "도커 컨테이너:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "도커 볼륨 :${gl_lv}$volume_count${gl_bai}" + echo -e "Docker 볼륨:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" echo -e "도커 네트워크:${gl_lv}$network_count${gl_bai}" @@ -7273,33 +7272,33 @@ linux_docker() { echo "네트워크 운영" echo "------------------------" echo "1. 네트워크 생성" - echo "2. 인터넷에 가입하십시오" + echo "2. 네트워크에 가입하세요" echo "3. 네트워크 종료" - echo "4. 네트워크를 삭제합니다" + echo "4. 네트워크 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) send_stats "네트워크 생성" - read -e -p "새 네트워크 이름 설정 :" dockernetwork + read -e -p "새 네트워크 이름 설정:" dockernetwork docker network create $dockernetwork ;; 2) send_stats "네트워크에 가입하세요" read -e -p "네트워크 이름 추가:" dockernetwork - read -e -p "해당 컨테이너는 네트워크에 추가됩니다 (여러 컨테이너 이름은 공간으로 분리됩니다)." dockernames + read -e -p "네트워크에 참여하는 컨테이너(여러 컨테이너 이름을 공백으로 구분하세요):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "인터넷에 가입하십시오" - read -e -p "종료 네트워크 이름 :" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + send_stats "네트워크에 가입하세요" + read -e -p "종료 네트워크 이름:" dockernetwork + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7309,7 +7308,7 @@ linux_docker() { 4) send_stats "네트워크 삭제" - read -e -p "삭제하려면 네트워크 이름을 입력하십시오." dockernetwork + read -e -p "삭제할 네트워크 이름을 입력하세요:" dockernetwork docker network rm $dockernetwork ;; @@ -7327,11 +7326,11 @@ linux_docker() { echo "도커 볼륨 목록" docker volume ls echo "" - echo "볼륨 작동" + echo "볼륨 작업" echo "------------------------" echo "1. 새 볼륨 생성" - echo "2. 지정된 볼륨을 삭제합니다" - echo "3. 모든 볼륨을 삭제하십시오" + echo "2. 지정된 볼륨 삭제" + echo "3. 모든 볼륨 삭제" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -7339,8 +7338,8 @@ linux_docker() { case $sub_choice in 1) - send_stats "새 볼륨을 만듭니다" - read -e -p "새 볼륨 이름 설정 :" dockerjuan + send_stats "새 볼륨 생성" + read -e -p "새 볼륨 이름 설정:" dockerjuan docker volume create $dockerjuan ;; @@ -7363,7 +7362,7 @@ linux_docker() { [Nn]) ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -7376,7 +7375,7 @@ linux_docker() { ;; 7) clear - send_stats "도커 청소" + send_stats "도커 정리" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7407,7 +7406,7 @@ linux_docker() { 11) clear - send_stats "Docker V6 열기" + send_stats "도커 v6 켜짐" docker_ipv6_on ;; @@ -7424,7 +7423,7 @@ linux_docker() { 20) clear - send_stats "Docker는 제거합니다" + send_stats "도커 제거" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -7445,7 +7444,7 @@ linux_docker() { kejilion ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -7462,44 +7461,44 @@ linux_test() { while true; do clear - # Send_stats "테스트 스크립트 컬렉션" + # send_stats "테스트 스크립트 수집" echo -e "테스트 스크립트 수집" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 잠금 해제 상태 감지" echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" - echo -e "${gl_kjlan}3. ${gl_bai}YEAHWU 스트리밍 미디어 잠금 해제 탐지" + echo -e "${gl_kjlan}3. ${gl_bai}예우 스트리밍 미디어 잠금 해제 감지" echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 품질 확인 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}네트워크 회선 속도 테스트" echo -e "${gl_kjlan}11. ${gl_bai}besttrace 3 네트워크 백홀 지연 라우팅 테스트" - echo -e "${gl_kjlan}12. ${gl_bai}MTR_TRACE 3- 네트워크 백홀 라인 테스트" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 3 Net 속도 측정" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 삼중 네트워크 백홀 회선 테스트" + echo -e "${gl_kjlan}13. ${gl_bai}초고속 트리플 네트워크 속도 테스트" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo -e "${gl_kjlan}16. ${gl_bai}Ludashi2020 3 네트워크 라인 테스트" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 세 개의 네트워크 라인 테스트" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" - echo -e "${gl_kjlan}18. ${gl_bai}Netquality Network 품질 신체 검사 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 네트워크 품질 확인 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}하드웨어 성능 테스트" echo -e "${gl_kjlan}21. ${gl_bai}Yabs 성능 테스트" - echo -e "${gl_kjlan}22. ${gl_bai}IICU/GB5 CPU 성능 테스트 스크립트" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU 성능 테스트 스크립트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}포괄적 인 테스트" + echo -e "${gl_kjlan}종합적인 테스트" echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" - echo -e "${gl_kjlan}32. ${gl_bai}SpiritySDX 퓨전 몬스터 검토${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 퓨전 몬스터 평가${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGpt는 상태 감지를 잠금 해제합니다" + send_stats "ChatGPT 잠금 해제 상태 감지" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) @@ -7515,14 +7514,14 @@ linux_test() { ;; 4) clear - send_stats "xykt_ip 품질 신체 검사 스크립트" + send_stats "xykt_IP 품질 확인 스크립트" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "Besttrace 3 개의 네트워크 백홀 지연 라우팅 테스트" + send_stats "besttrace 삼중 네트워크 백홀 지연 라우팅 테스트" install wget wget -qO- git.io/besttrace | bash ;; @@ -7544,27 +7543,27 @@ linux_test() { ;; 15) clear - send_stats "nxtrace는 ip backhaul 테스트 스크립트를 지정합니다" - echo "참조 할 수있는 IP 목록" + send_stats "nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." + echo "참조 IP 목록" echo "------------------------" echo "베이징 통신: 219.141.136.12" - echo "베이징 유니폼 : 202.106.50.1" + echo "베이징 유니콤: 202.106.50.1" echo "베이징 모바일: 221.179.155.161" echo "상하이 통신: 202.96.209.133" - echo "상하이 유니폼 : 210.22.97.1" + echo "상하이 유니콤: 210.22.97.1" echo "상하이 모바일: 211.136.112.200" echo "광저우 통신: 58.60.188.222" echo "광저우 차이나 유니콤: 210.21.196.6" echo "광저우 모바일: 120.196.165.24" echo "청두통신: 61.139.2.69" - echo "청두 유니폼 : 119.6.6.6" - echo "청두 모바일 : 211.137.96.205" - echo "Hunan Telecom : 36.111.200.100" + echo "청두 차이나 유니콤: 119.6.6.6" + echo "청두 모바일: 211.137.96.205" + echo "후난 통신: 36.111.200.100" echo "후난 유니콤: 42.48.16.100" - echo "후난 모바일 : 39.134.254.6" + echo "후난 모바일: 39.134.254.6" echo "------------------------" - read -e -p "지정된 IP를 입력하십시오." testip + read -e -p "특정 IP를 입력하세요:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; @@ -7577,7 +7576,7 @@ linux_test() { 17) clear - send_stats "I-ABC 다기능 속도 테스트 스크립트" + send_stats "i-abc 다기능 속도 테스트 스크립트" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; @@ -7635,48 +7634,48 @@ linux_Oracle() { send_stats "Oracle Cloud 스크립트 컬렉션" echo -e "Oracle Cloud 스크립트 컬렉션" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}유휴 기계 활성 스크립트를 설치하십시오" - echo -e "${gl_kjlan}2. ${gl_bai}유휴 기계 활성 스크립트를 제거하십시오" + echo -e "${gl_kjlan}1. ${gl_bai}유휴 머신 활성 스크립트 설치" + echo -e "${gl_kjlan}2. ${gl_bai}유휴 컴퓨터에서 활성 스크립트 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD 다시 설치 시스템 스크립트" + echo -e "${gl_kjlan}3. ${gl_bai}DD 재설치 시스템 스크립트" echo -e "${gl_kjlan}4. ${gl_bai}R 형사 시작 스크립트" echo -e "${gl_kjlan}5. ${gl_bai}ROOT 비밀번호 로그인 모드 활성화" echo -e "${gl_kjlan}6. ${gl_bai}IPV6 복구 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear - echo "활성 스크립트 : CPU는 10-20% 메모리를 점유합니다." - read -e -p "설치 하시겠습니까? (Y/N) :" choice + echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) install_docker - # 기본값을 설정합니다 + # 기본값 설정 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율 백분율을 입력하라는 메시지를 표시하고 입력 한 경우 기본값을 사용하십시오. - read -e -p "CPU 코어 수를 입력하십시오 [기본값 :$DEFAULT_CPU_CORE]: " cpu_core + # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter 키를 누르면 기본값이 사용됩니다. + read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용 백분율 범위 (예 : 10-20) [기본값 :$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 사용량 백분율 범위(예: 10-20)를 입력하십시오. [기본값:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "메모리 사용 백분율을 입력하십시오 [기본값 :$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "메모리 사용량 비율을 입력하십시오.[기본값:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "스피드 테스트 간격 시간 (초)을 입력하십시오 [기본값 :$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "속도 테스트 간격 시간(초)을 입력하십시오. [기본값:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 도커 컨테이너를 실행하십시오 + # Docker 컨테이너 실행 docker run -itd --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -7691,7 +7690,7 @@ linux_Oracle() { ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -7699,20 +7698,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud는 활성 스크립트를 제거합니다" + send_stats "Oracle Cloud 제거 활성 스크립트" ;; 3) clear - echo "시스템을 다시 설치하십시오" + echo "시스템 재설치" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}다시 설치는 접촉을 잃을 위험이 있으며 걱정하는 사람들은 그것을주의해서 사용해야합니다. 재설치는 15 분이 걸릴 것으로 예상됩니다. 데이터를 미리 백업하십시오." - read -e -p "계속할거야? (Y/N) :" choice + echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) while true; do - read -e -p "다시 설치할 시스템을 선택하십시오 : 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "다시 설치하려는 시스템을 선택하십시오: 1. Debian12 | 2. 우분투20.04:" sys_choice case "$sys_choice" in 1) @@ -7745,7 +7744,7 @@ linux_Oracle() { 4) clear - send_stats "형사 R 스크립트 시작" + send_stats "R 형사 시작 스크립트" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -7764,7 +7763,7 @@ linux_Oracle() { ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -7785,7 +7784,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}환경이 설치되었습니다.${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" fi } @@ -7838,25 +7837,25 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP 웹사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경을 설치하십시오${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" + echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경 설치${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼 설치${gl_huang}4. ${gl_bai}Kedao 클라우드 데스크탑 설치" - echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 텔레비전 방송국을 설치하십시오${gl_huang}6. ${gl_bai}유니콘 디지털 카드 네트워크를 설치하십시오" - echo -e "${gl_huang}7. ${gl_bai}Flarum Forum 웹 사이트를 설치하십시오${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}동적 사이트를 사용자 정의합니다" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 TV 스테이션 설치${gl_huang}6. ${gl_bai}Unicorn 디지털 카드 네트워크 설치" + echo -e "${gl_huang}7. ${gl_bai}flarum 포럼 웹사이트 설치${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}맞춤 동적 사이트" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" - echo -e "${gl_huang}23. ${gl_bai}사이트 리버스 프록시 -IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" + echo -e "${gl_huang}23. ${gl_bai}사이트 역방향 프록시-IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" echo -e "${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" - echo -e "${gl_huang}33. ${gl_bai}시간이 지정된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터를 복원하십시오" + echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터 복원" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경을 보호하십시오${gl_huang}36. ${gl_bai}LDNMP 환경을 최적화하십시오" - echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경을 업데이트하십시오${gl_huang}38. ${gl_bai}LDNMP 환경 제거" + echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경 보호${gl_huang}36. ${gl_bai}LDNMP 환경 최적화" + echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경 업데이트${gl_huang}38. ${gl_bai}LDNMP 환경 제거" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_huang}------------------------${gl_bai}" read -e -p "선택사항을 입력하세요:" sub_choice @@ -7872,7 +7871,7 @@ linux_ldnmp() { 3) clear - # Discuz 포럼 + # 토론 포럼 webname="Discuz论坛" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -7900,7 +7899,7 @@ linux_ldnmp() { ldnmp_web_on echo "데이터베이스 주소: mysql" echo "데이터베이스 이름:$dbname" - echo "사용자 이름 :$dbuse" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "테이블 접두사: discuz_" @@ -7912,7 +7911,7 @@ linux_ldnmp() { # Kedao 클라우드 데스크탑 webname="可道云桌面" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -7935,10 +7934,10 @@ linux_ldnmp() { ldnmp_web_on echo "데이터베이스 주소: mysql" - echo "사용자 이름 :$dbuse" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "데이터베이스 이름:$dbname" - echo "Redis 호스트 : Redis" + echo "레디스 호스트: 레디스" ;; @@ -7974,13 +7973,13 @@ linux_ldnmp() { ldnmp_web_on echo "데이터베이스 주소: mysql" - echo "데이터베이스 포트 : 3306" + echo "데이터베이스 포트: 3306" echo "데이터베이스 이름:$dbname" echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사 : MAC_" + echo "데이터베이스 접두사: mac_" echo "------------------------" - echo "설치가 성공한 후 배경 주소에 로그인하십시오." + echo "설치가 성공적으로 완료되면 백엔드 주소로 로그인하세요." echo "https://$yuming/vip.php" ;; @@ -7990,7 +7989,7 @@ linux_ldnmp() { # 한쪽다리 숫자카드 webname="独脚数卡" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8011,21 +8010,21 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 포트: 3306" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "" - echo "Redis 주소 : Redis" - echo "Redis Password : 기본적으로 채워지지 않습니다" + echo "레디스 주소 : 레디스" + echo "redis 비밀번호: 기본적으로 입력되지 않음" echo "레디스 포트: 6379" echo "" echo "웹사이트 URL: https://$yuming" - echo "백그라운드 로그인 경로 : /admin" + echo "백엔드 로그인 경로: /admin" echo "------------------------" echo "사용자 이름: 관리자" - echo "비밀번호 : 관리자" + echo "비밀번호: 관리자" echo "------------------------" echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" @@ -8075,12 +8074,12 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소 : MySQL" - echo "데이터베이스 이름 :$dbname" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 이름:$dbname" echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "테이블 접두사: flarum_" - echo "관리자 정보는 직접 설정됩니다" + echo "관리자 정보는 직접 설정 가능" ;; @@ -8127,7 +8126,7 @@ linux_ldnmp() { # LinkStack webname="LinkStack" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8153,9 +8152,9 @@ linux_ldnmp() { clear ldnmp_web_on echo "데이터베이스 주소: mysql" - echo "데이터베이스 포트 : 3306" - echo "데이터베이스 이름 :$dbname" - echo "사용자 이름 :$dbuse" + echo "데이터베이스 포트: 3306" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" ;; @@ -8163,7 +8162,7 @@ linux_ldnmp() { clear webname="PHP动态站点" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -8182,7 +8181,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드 업로드" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리 아래" + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then @@ -8193,7 +8192,7 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php가있는 경로" + echo -e "[${gl_huang}2/6${gl_bai}] index.php가 위치한 경로" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} @@ -8204,9 +8203,9 @@ linux_ldnmp() { sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택하십시오" + echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택해주세요." echo "-------------" - read -e -p "1. PHP의 최신 버전 | 2. PHP7.4 :" pho_v + read -e -p "1. PHP 최신 버전 | 2.php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -8223,9 +8222,9 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장자를 설치하십시오" + echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장 설치" echo "-------------" - echo "설치된 확장" + echo "설치된 확장 프로그램" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -8237,7 +8236,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" echo "-------------" - echo "계속하려면 모든 키를 누르면 의사 정적 내용 등과 같은 사이트 구성을 자세히 설정할 수 있습니다." + echo "계속하려면 아무 키나 누르세요. 의사정적 콘텐츠 등 사이트 구성을 세부적으로 설정할 수 있습니다." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf @@ -8246,14 +8245,14 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 작성하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db case $use_db in 1) echo ;; 2) echo "데이터베이스 백업은 .gz로 끝나는 압축 패키지여야 합니다. Pagoda/1panel 백업 데이터 가져오기를 지원하려면 /home/ 디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 백업 데이터를 원격으로 다운로드 할 수도 있습니다. Enter가 직접 누르면 원격 다운로드를 건너 뜁니다." url_download_db + read -e -p "다운로드 링크를 입력하여 원격으로 백업 데이터를 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -8278,12 +8277,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "데이터베이스 주소 : MySQL" + echo "데이터베이스 주소: mysql" echo "데이터베이스 이름:$dbname" echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "테이블 접두사:$prefix" - echo "관리자 로그인 정보는 직접 설정됩니다" + echo "관리자 로그인 정보는 직접 설정합니다." ;; @@ -8299,7 +8298,7 @@ linux_ldnmp() { send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming - read -e -p "점프 도메인 이름을 입력하십시오 :" reverseproxy + read -e -p "리디렉션 도메인 이름을 입력하세요." reverseproxy nginx_install_status install_ssltls certs_status @@ -8333,10 +8332,10 @@ linux_ldnmp() { clear webname="反向代理-域名" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "반세기 도메인 이름을 입력하십시오 :" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls certs_status @@ -8357,7 +8356,7 @@ linux_ldnmp() { clear webname="Bitwarden" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming nginx_install_status install_ssltls @@ -8380,7 +8379,7 @@ linux_ldnmp() { clear webname="halo" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming nginx_install_status install_ssltls @@ -8432,7 +8431,7 @@ linux_ldnmp() { clear webname="静态站点" send_stats "설치하다$webname" - echo "배포를 시작하십시오$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming nginx_install_status @@ -8451,7 +8450,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드 업로드" echo "-------------" - echo "현재 Zip-Format 소스 코드 패키지 만 허용됩니다. 소스 코드 패키지를/home/web/html에 넣으십시오.${yuming}디렉토리에서" + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then @@ -8462,7 +8461,7 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이있는 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이 위치한 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} @@ -8500,11 +8499,11 @@ linux_ldnmp() { while true; do clear - echo "백업 파일이 작성되었습니다 : /home /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + echo "생성된 백업 파일: /home/$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "원격 서버 IP를 입력하세요:" remote_ip read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -8516,7 +8515,7 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "파일은 원격 서버 홈 디렉토리로 전송되었습니다." + echo "파일이 원격 서버 홈 디렉터리로 전송되었습니다." else echo "전송할 파일을 찾을 수 없습니다." fi @@ -8526,7 +8525,7 @@ linux_ldnmp() { break ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac done @@ -8534,7 +8533,7 @@ linux_ldnmp() { 33) clear - send_stats "시간이 지정된 원격 백업" + send_stats "예약된 원격 백업" read -e -p "원격 서버 IP를 입력하세요." useip read -e -p "원격 서버 비밀번호를 입력하세요:" usepasswd @@ -8546,18 +8545,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 주간 백업 2. 매일 백업" + echo "1. 주간 백업 2. 일일 백업" read -e -p "선택사항을 입력하세요:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "주간 백업의 요일을 선택하십시오 (0-6, 0은 일요일을 나타냅니다) :" weekday + read -e -p "주간 백업 요일을 선택합니다(0-6, 0은 일요일을 나타냄)." weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "매일 백업 시간을 선택하십시오 (시간, 0-23) :" hour + read -e -p "일일 백업 시간 선택(시간, 0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -8576,14 +8575,14 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 입력하고 백업 파일 이름을 입력하여 지정된 백업을 복원하고 0을 입력하려면 다음을 종료하십시오." filename + read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -8620,11 +8619,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP 환경을 업데이트하십시오" + send_stats "LDNMP 환경 업데이트" echo "LDNMP 환경 업데이트" echo "------------------------" ldnmp_v - echo "구성 요소의 새 버전을 발견하십시오" + echo "새 버전의 구성 요소가 발견되었습니다." echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -8644,13 +8643,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. Nginx 업데이트 2. MySQL 업데이트 3. PHP 업데이트 4. Redis 업데이트" + echo "1. nginx 업데이트 2. mysql 업데이트 3. PHP 업데이트 4. redis 업데이트" echo "------------------------" echo "5. 전체 환경 업데이트" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -8676,7 +8675,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "입력하십시오${ldnmp_pods}버전 번호(예: 7.4 8.0 8.1 8.2 8.3)(최신 버전을 얻으려면 Enter 키를 누르세요):" version + read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 7.4 8.0 8.1 8.2 8.3)(최신 버전을 얻으려면 Enter 키를 누르세요):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -8755,7 +8754,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP 환경을 제거하십시오" + send_stats "LDNMP 환경 제거" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8769,7 +8768,7 @@ linux_ldnmp() { ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -8813,73 +8812,74 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}Baota 패널의 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" - echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}nginxproxymanager 시각적 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 멀티 스토어 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" - echo -e "${gl_kjlan}7. ${color7}Nezha 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" + echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" + echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 시간 작업 관리 플랫폼" - echo -e "${gl_kjlan}13. ${color13}CloudReve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}스피드 테스트 속도 테스트 패널" - echo -e "${gl_kjlan}17. ${color17}Adguardhome Adware${gl_kjlan}18. ${color18}Office Office Online Office Office" - echo -e "${gl_kjlan}19. ${color19}썬더 풀 WAF 방화벽 패널${gl_kjlan}20. ${color20}Portainer 컨테이너 관리 패널" + echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 예정된 작업 관리 플랫폼" + echo -e "${gl_kjlan}13. ${color13}Cloudreve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" + echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}Speedtest 속도 테스트 패널" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome은 애드웨어를 제거합니다${gl_kjlan}18. ${color18}onlyoffice온라인 오피스 OFFICE" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF 방화벽 패널${gl_kjlan}20. ${color20}포테이너 컨테이너 관리 패널" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${color21}VSCODE 웹 버전${gl_kjlan}22. ${color22}Uptimekuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}WebTop 원격 데스크탑 웹 에디션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}NextCloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 사이트${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" - echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatai 채팅 집계 웹 사이트" - echo -e "${gl_kjlan}37. ${color37}MYIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya Alist 가족 버킷" - echo -e "${gl_kjlan}39. ${color39}Bilililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatAI 채팅 집계 웹사이트" + echo -e "${gl_kjlan}37. ${color37}MyIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist 가족 버킷" + echo -e "${gl_kjlan}39. ${color39}Bililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexte 원격 연결 도구" + echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexterm 원격 연결 도구" echo -e "${gl_kjlan}43. ${color43}RustDesk 원격 데스크톱(서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}GitHub 가속 스테이션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로 메테우스 (호스트 모니터링)" - echo -e "${gl_kjlan}49. ${color49}Prometheus (컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" + echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로메테우스(호스트 모니터링)" + echo -e "${gl_kjlan}49. ${color49}프로메테우스(컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPANEL 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${color53}llama3 채팅 AI 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" - echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투 (클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}DeepSeek 채팅 AI 큰 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}Newapi 큰 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" + echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPanel 컨테이너 관리 패널" + echo -e "${gl_kjlan}53. ${color53}라마3 채팅 AI 대형 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투(클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek 채팅 AI 대형 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI 대형 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" - echo -e "${gl_kjlan}63. ${color63}OpenWebui 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}N8N 자동화 워크 플로 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}YT-DLP 비디오 다운로드 도구" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" + echo -e "${gl_kjlan}65. ${color65}n8n 자동화된 워크플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp 비디오 다운로드 도구" echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}Astrbot 채팅 로봇 프레임 워크" + echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" - echo -e "${gl_kjlan}75. ${color75}멜로디 음악 엘프${gl_kjlan}76. ${color76}온라인 dos 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}천둥 오프라인 다운로드 도구${gl_kjlan}78. ${color78}Pandawiki 지능형 문서 관리 시스템" - echo -e "${gl_kjlan}79. ${color79}Beszel 서버 모니터링${gl_kjlan}80. ${color80}Linkwarden 북마크 관리" + echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" + echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}79. ${color79}베젤 서버 모니터링${gl_kjlan}80. ${color80}링크워든 북마크 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}GPT-로드 고성능 AI 투명 프록시" - echo -e "${gl_kjlan}83. ${color83}Komari 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}gpt-load 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}91. ${color91}Gitea 개인 코드 저장소${gl_kjlan}92. ${color92}파일 브라우저 파일 관리자" - echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}고속 다운로드 도구" + echo -e "${gl_kjlan}91. ${color91}gitea 비공개 코드 저장소${gl_kjlan}92. ${color92}FileBrowser 파일 관리자" + echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}Gopeed 고속 다운로드 도구" echo -e "${gl_kjlan}95. ${color95}종이 없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAuth 자체 호스팅 2단계 인증자" echo -e "${gl_kjlan}97. ${color97}WireGuard 네트워킹(서버)${gl_kjlan}98. ${color98}WireGuard 네트워킹(클라이언트)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}동기화 지점 간 파일 동기화 도구" + echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}P2P 파일 동기화 도구 동기화" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}101. ${color101}AI 비디오 생성 도구${gl_kjlan}102. ${color102}vecechat 멀티 플레이어 온라인 채팅 시스템" + echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" + echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}모든 응용 프로그램 데이터를 백업합니다${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" + echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice fi case $sub_choice in @@ -9032,8 +9032,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정 :" admin - read -e -p "로그인 사용자 비밀번호 설정 :" admin_password + read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 비밀번호 설정:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -9066,7 +9066,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9075,7 +9075,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "Nezha 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9088,7 +9088,7 @@ while true; do echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -9145,7 +9145,7 @@ while true; do ;; 9|mail) - send_stats "우체국을 건설하십시오" + send_stats "우체국을 짓다" clear install telnet local app_id="9" @@ -9155,16 +9155,16 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우체국 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1wv421c71t?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" echo "포트 감지" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}포트$port현재 사용 가능합니다${gl_bai}" + echo -e "${gl_lv}포트$port현재 사용 가능${gl_bai}" else echo -e "${gl_hong}포트$port현재는 이용할 수 없습니다${gl_bai}" fi @@ -9181,13 +9181,13 @@ while true; do echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름 (예 : Mail.yuming.com)을 설정하십시오." yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -9223,7 +9223,7 @@ while true; do clear echo "poste.io가 설치되었습니다" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." echo "https://$yuming" echo "" @@ -9246,9 +9246,9 @@ while true; do add_app_id clear - echo "Poste.io가 설치되었습니다" + echo "poste.io가 설치되었습니다" echo "------------------------" - echo "다음 주소를 사용하여 Poste.io에 액세스 할 수 있습니다." + echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." echo "https://$yuming" echo "" ;; @@ -9259,7 +9259,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." ;; *) @@ -9313,7 +9313,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -9397,7 +9397,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -9556,7 +9556,7 @@ while true; do ;; 19|safeline) - send_stats "천둥 수영장을 건설하십시오" + send_stats "천둥 웅덩이를 만들어라" local app_id="19" local docker_name=safeline-mgt @@ -9566,7 +9566,7 @@ while true; do clear echo -e "썬더 풀 서비스$check_docker" echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." - echo "비디오 소개 : https://www.bilibili.com/video/bv1mz421t74c?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi @@ -9600,7 +9600,7 @@ while true; do add_app_id clear - echo "Thunder Pool WAF 패널이 업데이트되었습니다" + echo "Leichi WAF 패널이 업데이트되었습니다." check_docker_app_ip ;; 3) @@ -9611,7 +9611,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "기본 설치 디렉토리 인 경우 프로젝트가 제거되었습니다. 설치 디렉토리를 사용자 정의하는 경우 직접 실행하려면 설치 디렉토리로 이동해야합니다." + echo "기본 설치 디렉터리에 있다면 이제 프로젝트가 제거된 것입니다. 설치 디렉터리를 사용자 정의하는 경우 설치 디렉터리로 이동하여 직접 실행해야 합니다." echo "docker compose down && docker compose down --rmi all" ;; *) @@ -10019,7 +10019,7 @@ while true; do local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="공식 웹 사이트 소개 :${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" @@ -10276,9 +10276,9 @@ while true; do prometheus_install clear ip_address - echo "설치" + echo "설치 완료" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 다음과 같습니다" + echo "초기 사용자 이름과 비밀번호는 admin입니다." } docker_app_update() { @@ -10296,7 +10296,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -10518,7 +10518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -10593,7 +10593,7 @@ while true; do echo "설치 완료" check_docker_app_ip echo "초기 사용자 이름: admin" - echo "초기 비밀번호 : changeme" + echo "초기 비밀번호: ChangeMe" } @@ -10935,7 +10935,7 @@ while true; do docker_rum() { - read -e -p "libretv 로그인 비밀번호 설정 :" app_passwd + read -e -p "LibreTV 로그인 비밀번호 설정:" app_passwd docker run -d \ --name libretv \ @@ -10969,9 +10969,9 @@ while true; do local app_size="2" docker_app_install() { - read -e -p "로그인 사용자 이름 설정 :" admin + read -e -p "로그인 사용자 이름 설정:" admin read -e -p "로그인 사용자 비밀번호 설정:" admin_password - read -e -p "인증 코드를 입력하십시오." shouquanma + read -e -p "인증 코드 입력:" shouquanma mkdir -p /home/docker/moontv @@ -11075,7 +11075,7 @@ while true; do docker_rum() { read -e -p "로그인 사용자 이름 설정:" app_use - read -e -p "로그인 비밀번호 설정 :" app_passwd + read -e -p "로그인 비밀번호 설정:" app_passwd docker run -d \ --name xunlei \ @@ -11172,11 +11172,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 공식 Docker-Compose 및 ENV 파일을 다운로드하십시오 + # 공식 docker-compose 및 env 파일 다운로드 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 암호를 생성합니다 + # 임의의 키와 비밀번호 생성 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -11185,17 +11185,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 관리자 계정 정보를 추가하십시오 + # 관리자 계정 정보 추가 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 컨테이너를 시작하십시오 + # 컨테이너 시작 docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11205,7 +11205,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 원래 변수를 유지하십시오 + # 원래 변수 유지 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -11290,7 +11290,7 @@ while true; do docker_rum() { - read -e -p "설정${docker_name}SK-159KEJILIONYYDS163 :와 같은 로그인 키 (SK 별 문자 및 숫자 조합) :" app_passwd + read -e -p "설정${docker_name}로그인 키(sk-다음과 같이 시작하는 문자와 숫자의 조합): sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -11394,7 +11394,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11407,7 +11407,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11568,7 +11568,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "초기 사용자 또는 관리자를 만듭니다. 다음 사용자 이름과 비밀번호와 관리자 여부를 설정하십시오." + echo "초기 사용자 또는 관리자를 생성합니다. 다음 사용자 이름과 비밀번호를 설정하고 관리자인지 여부를 설정하세요." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -11634,7 +11634,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "앱이 제거되었습니다" + echo "앱이 제거되었습니다." } docker_app_plus @@ -11812,7 +11812,7 @@ while true; do block_container_port "$docker_name" "$ipv4_address" clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -11844,7 +11844,7 @@ while true; do docker_rum() { - read -e -p "네트워크를 구성하려면 클라이언트 수를 입력하십시오 (기본값 5)." COUNT + read -e -p "네트워크의 클라이언트 수를 입력하십시오(기본값 5):" COUNT COUNT=${COUNT:-5} read -e -p "WireGuard 네트워크 세그먼트(기본값 10.13.13.0)를 입력하세요." NETWORK NETWORK=${NETWORK:-10.13.13.0} @@ -11916,18 +11916,18 @@ while true; do sleep 2 echo - echo -e "${gl_huang}모든 클라이언트 QR 코드 구성 :${gl_bai}" + echo -e "${gl_huang}모든 클라이언트 QR 코드 구성:${gl_bai}" docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo - echo -e "${gl_huang}모든 클라이언트 구성 코드 :${gl_bai}" + echo -e "${gl_huang}모든 클라이언트 구성 코드:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}모든 출력은 모두 각 클라이언트에 의해 구성되며 사용 방법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}${COUNT}각 클라이언트에 대한 모든 출력을 구성합니다. 사용방법은 다음과 같습니다.${gl_bai}" echo -e "${gl_lv}1. 휴대폰에 wg APP을 다운로드하고 위의 QR 코드를 스캔하면 빠르게 인터넷에 연결됩니다.${gl_bai}" - echo -e "${gl_lv}2. Windows 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결하십시오.${gl_bai}" + echo -e "${gl_lv}2. Windows용 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" echo -e "${gl_lv}3. 스크립트를 사용하여 Linux에 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" - echo -e "${gl_lv}공식 클라이언트 다운로드 방법 : https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}공식 클라이언트 다운로드 방법: https://www.wireguard.com/install/${gl_bai}" break_end } @@ -11955,16 +11955,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 디렉토리 생성 (존재하지 않는 경우) + # 디렉터리가 없으면 생성 mkdir -p "$(dirname "$CONFIG_FILE")" - echo "클라이언트 구성을 붙여 넣고 다음을 저장하려면 Enter Enter를 두 번 누릅니다." + echo "클라이언트 구성을 붙여넣고 Enter를 두 번 눌러 저장하세요." # 변수 초기화 input="" empty_line_count=0 - # 사용자 입력 라인별로 읽으십시오 + # 사용자 입력을 한 줄씩 읽습니다. while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -12045,7 +12045,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -12114,7 +12114,7 @@ while true; do docker compose up -d clear - echo "설치" + echo "설치 완료" check_docker_app_ip } @@ -12165,6 +12165,47 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "설치 완료" + check_docker_app_ip + echo "초기 사용자 이름: admin" + echo "초기 비밀번호 : umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "앱이 제거되었습니다." + } + + docker_app_plus + + ;; + + b) clear @@ -12177,7 +12218,7 @@ while true; do while true; do clear echo "생성된 백업 파일: /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송 하시겠습니까? (Y/N) :" choice + read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) read -e -p "원격 서버 IP를 입력하세요:" remote_ip @@ -12195,12 +12236,12 @@ while true; do scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" echo "원격 서버/루트 디렉터리로 파일이 전송되었습니다." else - echo "전송할 파일은 찾을 수 없었습니다." + echo "전송할 파일을 찾을 수 없습니다." fi break ;; *) - echo "참고 : 현재 백업에는 Docker 프로젝트 만 포함되어 있으며 Pagoda 및 1Panel과 같은 웹 사이트 구축 패널의 데이터 백업은 포함되지 않습니다." + echo "참고: 현재 백업에는 docker 프로젝트만 포함되며, Pagoda, 1panel 등 웹사이트 구축 패널의 데이터 백업은 포함되지 않습니다." break ;; esac @@ -12211,7 +12252,7 @@ while true; do r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12222,15 +12263,15 @@ while true; do linux_panel fi - # 사용자가 파일 이름을 입력하지 않으면 최신 압축 패키지를 사용하십시오. + # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_huang}감압이 수행되고 있습니다$filename ...${gl_bai}" + echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "응용 프로그램 데이터가 복원되었습니다. 지정된 응용 프로그램 메뉴를 수동으로 입력하고 응용 프로그램을 업데이트하여 응용 프로그램을 복원하십시오." + echo "애플리케이션 데이터가 복원되었습니다. 현재 해당 애플리케이션을 복원하려면 지정된 애플리케이션 메뉴에 수동으로 진입한 후 애플리케이션을 업데이트하시기 바랍니다." else echo "압축된 패키지를 찾을 수 없습니다." fi @@ -12256,32 +12297,32 @@ linux_work() { while true; do clear send_stats "백엔드 작업공간" - echo -e "백엔드 작업 공간" - echo -e "이 시스템은 백엔드에서 실행할 수있는 작업 공간을 제공하며 장기 작업을 수행하는 데 사용할 수 있습니다." + echo -e "백엔드 작업공간" + echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." - echo -e "${gl_huang}힌트:${gl_bai}작업 공간에 입력 한 후 Ctrl+B를 사용하고 D 만 눌러 작업 공간을 종료하십시오!" + echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}작업 공간 번호 1" + echo -e "${gl_kjlan}1. ${gl_bai}작업 영역 1" echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 공간 No. 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 번호 5" + echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 번호 7" + echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" - echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}작업 공간 번호 10" + echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH 거주 모드${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}작업 공간을 작성/입력하십시오" + echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" echo -e "${gl_kjlan}23. ${gl_bai}백그라운드 작업 공간에 명령 삽입" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업 공간을 삭제하십시오" + echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업공간 삭제" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아갑니다" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택사항을 입력하세요:" sub_choice @@ -12291,7 +12332,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; @@ -12313,7 +12354,7 @@ linux_work() { clear install tmux local SESSION_NAME="work4" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 5) @@ -12327,35 +12368,35 @@ linux_work() { clear install tmux local SESSION_NAME="work6" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "작업 공간을 시작하십시오$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; @@ -12371,7 +12412,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 2를 켜십시오. 2를 끕니다" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -12397,7 +12438,7 @@ linux_work() { ;; 22) - read -e -p "1001 KJ001 Work1과 같이 생성하거나 입력 한 작업 공간의 이름을 입력하십시오." SESSION_NAME + read -e -p "1001 kj001 work1과 같이 생성하거나 입력한 작업공간의 이름을 입력하세요." SESSION_NAME tmux_run send_stats "맞춤형 작업공간" ;; @@ -12410,7 +12451,7 @@ linux_work() { ;; 24) - read -e -p "삭제하려는 작업 공간의 이름을 입력하십시오." gongzuoqu_name + read -e -p "삭제하려는 작업공간의 이름을 입력하세요:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name send_stats "작업공간 삭제" ;; @@ -12447,37 +12488,37 @@ linux_Settings() { # send_stats "시스템 도구" echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 스타트 업 단축키 키를 설정하십시오${gl_kjlan}2. ${gl_bai}로그인 암호를 수정하십시오" - echo -e "${gl_kjlan}3. ${gl_bai}루트 암호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" - echo -e "${gl_kjlan}5. ${gl_bai}모든 포트를 엽니 다${gl_kjlan}6. ${gl_bai}SSH 연결 포트를 수정하십시오" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}원 클릭 복직 시스템${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}루트 계정을 비활성화하여 새 계정을 생성하십시오${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}항구 직업 상태를 확인하십시오${gl_kjlan}12. ${gl_bai}가상 메모리 크기를 수정합니다" + echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속도를 설정하십시오" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속 설정" echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름 수정" - echo -e "${gl_kjlan}19. ${gl_bai}스위치 시스템 업데이트 소스${gl_kjlan}20. ${gl_bai}예약된 작업 관리" + echo -e "${gl_kjlan}19. ${gl_bai}시스템 업데이트 소스 전환${gl_kjlan}20. ${gl_bai}예약된 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 구문 분석${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}바이러스 스캐닝 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" + echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}스위치 시스템 언어${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 재활용 빈을 설정하십시오${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}31. ${gl_bai}시스템 언어 전환${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}RSYNC 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨 찾기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}rsync 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원 스톱 시스템 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원스톱 시스템 튜닝${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하세요${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" echo -e "${gl_kjlan}101. ${gl_bai}k 명령의 고급 사용법${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 사자 스크립트 제거" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -12490,7 +12531,7 @@ linux_Settings() { fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian - echo "바로 가기 키가 설정되어 있습니다" + echo "단축키가 설정되었습니다" send_stats "스크립트 단축키가 설정되었습니다" break_end linux_Settings @@ -12500,7 +12541,7 @@ linux_Settings() { 2) clear send_stats "로그인 비밀번호를 설정하세요" - echo "로그인 비밀번호를 설정하십시오" + echo "로그인 비밀번호를 설정하세요" passwd ;; 3) @@ -12513,16 +12554,16 @@ linux_Settings() { root_use send_stats "py 버전 관리" echo "파이썬 버전 관리" - echo "비디오 소개 : https://www.bilibili.com/video/bv1pm42157ck?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "현재 파이썬 버전 번호 :${gl_huang}$VERSION${gl_bai}" + echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "권장 버전: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "더 많은 버전 : https://www.python.org/downloads/" + echo "더 많은 버전 확인: https://www.python.org/downloads/" echo "------------" - read -e -p "설치하려는 Python 버전 번호를 입력하십시오 (종료하려면 0을 입력하십시오) :" py_new_v + read -e -p "설치하려는 Python 버전 번호를 입력하세요(종료하려면 0 입력)." py_new_v if [[ "$py_new_v" == "0" ]]; then @@ -12589,7 +12630,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 Py 버전을 스위치하십시오" + send_stats "스크립트 PY 버전 전환" ;; @@ -12598,12 +12639,12 @@ EOF send_stats "열린 포트" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "모든 포트가 열려 있습니다" + echo "모든 포트가 열려 있습니다." ;; 6) root_use - send_stats "SSH 포트를 수정하십시오" + send_stats "SSH 포트 수정" while true; do clear @@ -12616,15 +12657,15 @@ EOF echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "1 ~ 65535 범위의 포트 번호가있는 숫자 (종료하려면 0을 입력하십시오)" + echo "포트 번호 범위는 1~65535입니다. (종료하려면 0을 입력하세요.)" - # 사용자에게 새 SSH 포트 번호를 입력하라는 메시지 + # 사용자에게 새 SSH 포트 번호를 묻는 메시지 표시 read -e -p "새 SSH 포트 번호를 입력하세요." new_port # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH 포트가 수정되었습니다" + send_stats "SSH 포트가 수정되었습니다." new_ssh_port elif [[ $new_port -eq 0 ]]; then send_stats "SSH 포트 수정 종료" @@ -12687,14 +12728,14 @@ EOF if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv4${gl_bai}우선 사항" else - echo -e "현재 네트워크 우선 순위 설정 :${gl_huang}IPv6${gl_bai}우선 사항" + echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" echo "1. IPv4 우선 2. IPv6 우선 3. IPv6 복구 도구" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선호하는 네트워크를 선택하세요:" choice @@ -12702,20 +12743,20 @@ EOF 1) grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "IPv4 우선 순위로 전환되었습니다" - send_stats "IPv4 우선 순위로 전환되었습니다" + echo "IPv4 우선순위로 전환됨" + send_stats "IPv4 우선순위로 전환됨" ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선 순위로 전환되었습니다" - send_stats "IPv6 우선 순위로 전환되었습니다" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) echo "이 기능은 jhb에서 제공합니다. 감사합니다!" - send_stats "IPv6 수정" + send_stats "IPv6 수리" ;; *) @@ -12741,9 +12782,9 @@ EOF local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "현재 가상 메모리 :${gl_huang}$swap_info${gl_bai}" + echo -e "현재 가상 메모리:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 1024m 2. 할당 2048m 3. 4096m 할당 4. 사용자 정의 크기" + echo "1. 1024M 할당 2. 2048M 할당 3. 4096M 할당 4. 사용자 정의 크기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -12767,7 +12808,7 @@ EOF ;; 4) - read -e -p "가상 메모리 크기 (단위 M)를 입력하십시오." new_swap + read -e -p "가상 메모리 크기(단위 M)를 입력하세요." new_swap add_swap "$new_swap" send_stats "사용자 정의 가상 메모리 세트" ;; @@ -12804,11 +12845,11 @@ EOF echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - # 사용자에게 새 사용자 이름을 입력하도록 프롬프트하십시오 + # 사용자에게 새 사용자 이름을 묻는 메시지 표시 read -e -p "새 사용자 이름을 입력하세요:" new_username # 새로운 사용자 생성 및 비밀번호 설정 @@ -12820,13 +12861,13 @@ EOF 2) # 사용자에게 새 사용자 이름을 묻는 메시지 표시 - read -e -p "새 사용자 이름을 입력하십시오 :" new_username + read -e -p "새 사용자 이름을 입력하세요:" new_username - # 새 사용자를 생성하고 비밀번호를 설정하십시오 + # 새로운 사용자 생성 및 비밀번호 설정 useradd -m -s /bin/bash "$new_username" passwd "$new_username" - # 새로운 사용자에게 허가를 부여하십시오 + # 새 사용자에게 sudo 권한 부여 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers install sudo @@ -12848,8 +12889,8 @@ EOF ;; 5) - read -e -p "삭제하려면 사용자 이름을 입력하십시오." username - # 사용자와 홈 디렉토리를 삭제하십시오 + read -e -p "삭제하려는 사용자 이름을 입력하세요:" username + # 사용자 및 해당 홈 디렉터리 삭제 userdel -r "$username" ;; @@ -12871,7 +12912,7 @@ EOF done echo "" - echo "임의 이름" + echo "임의의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") @@ -12893,7 +12934,7 @@ EOF done echo "" - echo "16 비트 랜덤 비밀번호" + echo "16자리 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) @@ -12913,30 +12954,30 @@ EOF 15) root_use - send_stats "시간대를 변경하십시오" + send_stats "시간대 변경" while true; do clear echo "시스템 시간 정보" - # 현재 시스템 시간대를 얻으십시오 + # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간을 얻으십시오 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 시간대와 시간을 보여줍니다 + # 시간대 및 시간 표시 echo "현재 시스템 시간대:$timezone" - echo "현재 시스템 시간 :$current_time" + echo "현재 시스템 시간:$current_time" echo "" - echo "시간대 스위칭" + echo "시간대 스위치" echo "------------------------" echo "아시아" echo "1. 중국 상하이 시간 2. 중국 홍콩 시간" - echo "3. 일본의 도쿄 시간 4. 한국의 서울 시간" + echo "3. 일본 도쿄 시간 4. 한국 서울 시간" echo "5. 싱가포르 시간 6. 콜카타, 인도 시간" echo "7. 아랍에미리트 두바이 시간 8. 호주 시드니 시간" - echo "9. 태국 방콕에서의 시간" + echo "9. 태국 방콕 시간" echo "------------------------" echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" @@ -12948,11 +12989,11 @@ EOF echo "23. 캐나다 시간 24. 멕시코 시간" echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC 글로벌 표준 시간" + echo "31. UTC 세계 표준시" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -12995,14 +13036,14 @@ EOF 18) root_use - send_stats "호스트 이름을 수정하십시오" + send_stats "호스트 이름 수정" while true; do clear local current_hostname=$(uname -n) echo -e "현재 호스트 이름:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "새 호스트 이름을 입력하십시오 (종료하려면 0을 입력하십시오) :" new_hostname + read -e -p "새 호스트 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine @@ -13028,7 +13069,7 @@ EOF fi echo "호스트 이름이 다음으로 변경되었습니다.$new_hostname" - send_stats "호스트 이름이 변경되었습니다" + send_stats "호스트 이름이 변경됨" sleep 1 else echo "호스트 이름을 변경하지 않고 종료되었습니다." @@ -13042,17 +13083,17 @@ EOF send_stats "시스템 업데이트 소스 변경" clear echo "업데이트 소스 지역 선택" - echo "LinuxMirrors에 연결하여 시스템 업데이트 소스를 전환하십시오" + echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) - send_stats "중국 본토의 기본 소스" + send_stats "중국 본토 기본 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -13077,29 +13118,29 @@ EOF clear check_crontab_installed clear - echo "시간이 정한 작업 목록" + echo "예약된 작업 목록" crontab -l echo "" echo "작동하다" echo "------------------------" - echo "1. 타이밍 작업 추가 2. 타이밍 작업 삭제 3. 타이밍 작업 편집" + echo "1. 예약된 작업 추가 2. 예약된 작업 삭제 3. 예약된 작업 편집" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - read -e -p "새 작업에 대한 실행 명령을 입력하십시오." newquest + read -e -p "새 작업의 실행 명령을 입력하십시오:" newquest echo "------------------------" echo "1. 월간 작업 2. 주간 작업" - echo "3. 일일 작업 4. 시간당 작업" + echo "3. 일일 작업 4. 시간별 작업" echo "------------------------" - read -e -p "선택을 입력하십시오 :" dingshi + read -e -p "선택사항을 입력하세요:" dingshi case $dingshi in 1) - read -e -p "작업을 수행하려면 매월 어느 날을 선택합니까? (1-30) :" day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -13107,7 +13148,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 작업을 수행 할 시간을 선택하십시오. (시간, 0-23) :" hour + read -e -p "매일 몇 시에 작업을 수행하기로 선택하시나요? (시간, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -13123,11 +13164,11 @@ EOF 2) read -e -p "삭제할 작업의 키워드를 입력하세요:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "타이밍 작업을 삭제하십시오" + send_stats "예약된 작업 삭제" ;; 3) crontab -e - send_stats "타이밍 작업 편집" + send_stats "예약된 작업 편집" ;; *) break # 跳出循环,退出菜单 @@ -13139,24 +13180,24 @@ EOF 21) root_use - send_stats "지역 호스트 구문 분석" + send_stats "로컬 호스트 확인" while true; do clear echo "기본 호스트 확인 목록" - echo "여기에 구문 분석 일치를 추가하면 더 이상 동적 구문 분석이 사용되지 않습니다." + echo "여기에 파싱 매칭을 추가하면 더 이상 동적 파싱이 사용되지 않습니다." cat /etc/hosts echo "" echo "작동하다" echo "------------------------" echo "1. 새로운 해상도 추가 2. 해상도 주소 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" host_dns case $host_dns in 1) - read -e -p "새 구문 분석 기록 형식을 입력하십시오 : 110.25.5.33 Kejilion.pro :" addhost + read -e -p "새로운 구문 분석 기록 형식을 입력하세요: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts send_stats "로컬 호스트 해상도가 추가되었습니다." @@ -13164,7 +13205,7 @@ EOF 2) read -e -p "삭제해야 하는 구문 분석된 콘텐츠의 키워드를 입력하세요." delhost sed -i "/$delhost/d" /etc/hosts - send_stats "로컬 호스트 구문 분석 및 삭제" + send_stats "로컬 호스트 확인 및 삭제" ;; *) break # 跳出循环,退出菜单 @@ -13180,8 +13221,8 @@ EOF check_f2b_status echo -e "SSH 방어 프로그램$check_f2b_status" - echo "FAIL2BAN은 무자비한 힘을 방지하는 SSH 도구입니다" - echo "공식 웹 사이트 소개 :${gh_proxy}github.com/fail2ban/fail2ban" + echo "fall2ban은 무차별 대입 크래킹을 방지하는 SSH 도구입니다." + echo "공식 웹사이트 소개:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" echo "1. 방어 프로그램 설치" echo "------------------------" @@ -13190,9 +13231,9 @@ EOF echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -13230,44 +13271,44 @@ EOF send_stats "전류 제한 차단 기능" while true; do clear - echo "현재 제한 종료 기능" - echo "비디오 소개 : https://www.bilibili.com/video/bv1mc411j7qd?t=0.1" + echo "전류 제한 차단 기능" + echo "영상 소개: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "서버 트래픽 계산을 다시 시작하는 현재 트래픽 사용이 지워집니다!" + echo "서버가 다시 시작되면 현재 트래픽 사용량이 지워집니다!" output_status echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" - echo -e "${gl_kjlan}총 보내기 :${gl_bai}$tx" + echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" # Limiting_Shut_down.sh 파일이 있는지 확인하세요. if [ -f ~/Limiting_Shut_down.sh ]; then - # threshold_gb의 값을 얻으십시오 + # Threshold_gb 값을 가져옵니다. local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}현재 아웃 바운드 전류 한계 임계 값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo echo "------------------------------------------------" - echo "시스템은 실제 트래픽이 1 분마다 임계 값에 도달하는지 여부를 감지하고 서버가 도착하면 자동으로 종료됩니다!" + echo "시스템은 매분마다 실제 트래픽이 임계값에 도달했는지 여부를 감지하고 임계값에 도달한 후 자동으로 서버를 종료합니다!" echo "------------------------" - echo "1. 현재 한계 셧다운 함수 켜기 2. 현재 한계 종료 함수 비활성화" + echo "1. 전류 제한 종료 기능을 활성화합니다. 2. 전류 제한 종료 기능을 비활성화합니다." echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버에 트래픽이 100g 인 경우 트래픽 오류 나 오버플로를 피하기 위해 임계 값을 95G로 설정하고 전원을 미리 차단할 수 있습니다." - read -e -p "들어오는 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100G) :" rx_threshold_gb + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "아웃 바운드 트래픽 임계 값을 입력하십시오 (단위 G, 기본값은 100g) :" tx_threshold_gb + read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하십시오 (매월 1 일에 기본 재설정) :" cz_day + read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일 재설정)." cz_day cz_day=${cz_day:-1} cd ~ @@ -13281,7 +13322,7 @@ EOF crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 echo "전류 제한 종료가 설정되었습니다." - send_stats "전류 제한 종료가 설정되었습니다" + send_stats "전류 제한 종료가 설정되었습니다." ;; 2) check_crontab_installed @@ -13301,15 +13342,15 @@ EOF 24) root_use - send_stats "개인 키 로그인" + send_stats "개인키 로그인" while true; do clear echo "ROOT 개인 키 로그인 모드" - echo "비디오 소개 : https://www.bilibili.com/video/bv1q4421x78n?t=209.4" + echo "영상 소개: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" - echo "1. 새 키 생성 2. 기존 키 가져 오기 3. 기본 키보기" + echo "1. 새 키 생성 2. 기존 키 가져오기 3. 로컬 키 보기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13317,7 +13358,7 @@ EOF case $host_dns in 1) - send_stats "새로운 키를 생성하십시오" + send_stats "새 키 생성" add_sshkey break_end @@ -13350,18 +13391,18 @@ EOF 25) root_use - send_stats "전보 경고" + send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." - echo "임계 값에 도달하면 사용자가 사용자에게 전송됩니다." - echo -e "${gl_hui}- 트래픽과 관련하여 서버를 다시 시작하면 다시 계산됩니다.${gl_bai}" - read -e -p "계속할거야? (Y/N) :" choice + echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." + echo -e "${gl_hui}- 트래픽에 관해서는 서버를 다시 시작하면 다시 계산됩니다 -${gl_bai}" + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - send_stats "전보 경고가 활성화되었습니다" + send_stats "텔레그램 경고 활성화됨" cd ~ install nano tmux bc jq check_crontab_installed @@ -13383,7 +13424,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # ~/.profile 파일에 추가하십시오 + # ~/.profile 파일에 추가 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -13395,13 +13436,13 @@ EOF clear echo "TG-bot 조기경보 시스템이 활성화되었습니다." - echo -e "${gl_hui}다른 시스템의 루트 디렉토리에 TG-Check-Notify.sh 경고 파일을 배치하고 직접 사용할 수도 있습니다!${gl_bai}" + echo -e "${gl_hui}TG-check-notify.sh 경고 파일을 다른 컴퓨터의 루트 디렉터리에 넣고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -13452,7 +13493,7 @@ EOF ;; 37) clear - send_stats "명령 줄 기록" + send_stats "명령줄 기록" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -13484,27 +13525,27 @@ EOF 66) root_use - send_stats "원 스톱 튜닝" + send_stats "원스톱 튜닝" echo "원스톱 시스템 튜닝" echo "------------------------------------------------" - echo "다음은 작동하고 최적화됩니다" + echo "다음 콘텐츠가 운영 및 최적화됩니다." echo "1. 시스템을 최신으로 업데이트하세요" echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" - echo -e "4. SSH 포트 번호를 설정하십시오${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니 다" + echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" + echo -e "5. 모든 포트를 엽니다." echo -e "6. 켜기${gl_huang}BBR${gl_bai}가속하다" echo -e "7. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" - echo -e "8. DNS 주소를 자동으로 최적화합니다${gl_huang}해외 : 1.1.1.1 8.8.8.8 국내 : 223.5.5.5${gl_bai}" + echo -e "8. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" echo -e "9. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux 시스템에서 커널 매개 변수 최적화로 전환하십시오${gl_huang}균형 최적화 모드${gl_bai}" + echo -e "10. Linux 시스템 커널 매개변수 최적화가 다음으로 전환됩니다.${gl_huang}균형 잡힌 최적화 모드${gl_bai}" echo "------------------------------------------------" read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice case "$choice" in [Yy]) clear - send_stats "원 스톱 튜닝 시작" + send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하세요" @@ -13515,18 +13556,18 @@ EOF echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리를 설정합니다${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트를 엽니 다" + echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트 열기" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속" + echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속하다" echo "------------------------------------------------" set_timedate Asia/Shanghai @@ -13552,20 +13593,20 @@ EOF echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구를 설치하십시오${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템의 커널 매개 변수 최적화" - echo -e "${gl_lv}원 스톱 시스템 튜닝이 완료되었습니다${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템 커널 매개변수 최적화" + echo -e "${gl_lv}원스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; [Nn]) echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac @@ -13591,7 +13632,7 @@ EOF echo "개인 정보 보호 및 보안" echo "스크립트는 사용자의 기능 사용에 대한 데이터를 수집하고 스크립트 경험을 최적화하며 더 재미 있고 유용한 기능을 만듭니다." - echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기계 국가 및 사용 된 기능의 이름을 수집합니다." + echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 사용된 기능 이름이 수집됩니다." echo "------------------------------------------------" echo -e "현재 상태:$status_message" echo "--------------------" @@ -13614,7 +13655,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인 정보 보호 및 보안이 컬렉션을 위해 마감되었습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." ;; *) break @@ -13630,11 +13671,11 @@ EOF 102) clear - send_stats "기술 라이온 스크립트를 제거하십시오" + send_stats "기술 사자 스크립트 제거" echo "기술 사자 스크립트 제거" echo "------------------------------------------------" echo "kejilion 스크립트는 다른 기능에 영향을 주지 않고 완전히 제거됩니다." - read -e -p "계속할거야? (Y/N) :" choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -13651,7 +13692,7 @@ EOF echo "취소" ;; *) - echo "잘못된 선택, y 또는 N을 입력하십시오." + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -13661,7 +13702,7 @@ EOF ;; *) - echo "잘못된 입력!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -13689,41 +13730,41 @@ linux_file() { echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉토리를 입력합니다. 2. 디렉토리 만들기 3. 디렉토리 권한 수정 4. 디렉토리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 돌아갑니다." + echo "1. 디렉터리 입력 2. 디렉터리 생성 3. 디렉터리 권한 수정 4. 디렉터리 이름 바꾸기" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" echo "------------------------" echo "11. 파일 생성 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" - echo "15. 파일을 삭제하십시오" + echo "15. 파일 삭제" echo "------------------------" - echo "21. 파일 디렉토리 압축 22. zip 파일 디렉토리 23. 파일 디렉토리 이동 24. 파일 디렉토리 복사" - echo "25. 파일을 다른 서버로 전달합니다" + echo "21. 파일 디렉터리 압축 22. 파일 디렉터리 압축 풀기 23. 파일 디렉터리 이동 24. 파일 디렉터리 복사" + echo "25. 다른 서버로 파일 전송" echo "------------------------" - echo "0. 이전 메뉴로 돌아갑니다" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택을 입력하십시오 :" Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "디렉토리 이름을 입력하십시오 :" dirname - cd "$dirname" 2>/dev/null || echo "디렉토리에 입력 할 수 없습니다" - send_stats "디렉토리로 이동하십시오" + read -e -p "디렉토리 이름을 입력하십시오:" dirname + cd "$dirname" 2>/dev/null || echo "디렉토리에 들어갈 수 없습니다" + send_stats "디렉토리 입력" ;; 2) # 创建目录 - read -e -p "작성하려면 디렉토리 이름을 입력하십시오." dirname + read -e -p "생성할 디렉터리 이름을 입력하세요." dirname mkdir -p "$dirname" && echo "디렉터리가 생성되었습니다." || echo "생성 실패" - send_stats "디렉토리를 만듭니다" + send_stats "디렉터리 생성" ;; 3) # 修改目录权限 read -e -p "디렉토리 이름을 입력하십시오:" dirname read -e -p "권한을 입력하세요(예: 755):" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다." || echo "수정이 실패했습니다" - send_stats "디렉토리 권한을 수정하십시오" + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다." || echo "수정 실패" + send_stats "디렉터리 권한 수정" ;; 4) # 重命名目录 - read -e -p "현재 디렉토리 이름을 입력하십시오 :" current_name - read -e -p "새 디렉토리 이름을 입력하십시오 :" new_name - mv "$current_name" "$new_name" && echo "디렉터리 이름이 변경되었습니다." || echo "이름 바꾸지 실패했습니다" - send_stats "디렉토리의 이름을 바꿉니다" + read -e -p "현재 디렉터리 이름을 입력하세요." current_name + read -e -p "새 디렉터리 이름을 입력하세요." new_name + mv "$current_name" "$new_name" && echo "디렉터리 이름이 변경되었습니다." || echo "이름 바꾸기 실패" + send_stats "디렉터리 이름 바꾸기" ;; 5) # 删除目录 read -e -p "삭제할 디렉터리 이름을 입력하세요:" dirname @@ -13732,46 +13773,46 @@ linux_file() { ;; 6) # 返回上一级选单目录 cd .. - send_stats "이전 메뉴 디렉토리로 돌아갑니다" + send_stats "이전 메뉴 디렉토리로 돌아가기" ;; 11) # 创建文件 - read -e -p "작성하려면 파일 이름을 입력하십시오." filename - touch "$filename" && echo "생성 된 파일" || echo "생성 실패" + read -e -p "생성할 파일 이름을 입력하세요:" filename + touch "$filename" && echo "파일이 생성되었습니다." || echo "생성 실패" send_stats "파일 생성" ;; 12) # 编辑文件 - read -e -p "편집 할 파일 이름을 입력하십시오." filename + read -e -p "편집할 파일 이름을 입력하십시오:" filename install nano nano "$filename" send_stats "파일 편집" ;; 13) # 修改文件权限 - read -e -p "파일 이름을 입력하십시오 :" filename - read -e -p "권한을 입력하십시오 (예 : 755) :" perm + read -e -p "파일 이름을 입력하세요:" filename + read -e -p "권한을 입력하세요(예: 755):" perm chmod "$perm" "$filename" && echo "권한이 수정되었습니다." || echo "수정 실패" - send_stats "파일 권한을 수정하십시오" + send_stats "파일 권한 수정" ;; 14) # 重命名文件 read -e -p "현재 파일 이름을 입력하십시오:" current_name read -e -p "새 파일 이름을 입력하세요:" new_name - mv "$current_name" "$new_name" && echo "파일 이름이 변경되었습니다." || echo "이름 바꾸지 실패했습니다" - send_stats "파일의 이름을 바꿉니다" + mv "$current_name" "$new_name" && echo "파일 이름이 변경되었습니다." || echo "이름 바꾸기 실패" + send_stats "파일 이름 바꾸기" ;; 15) # 删除文件 - read -e -p "삭제하려면 파일 이름을 입력하십시오." filename - rm -f "$filename" && echo "파일이 삭제되었습니다" || echo "삭제 실패" + read -e -p "삭제할 파일 이름을 입력하세요:" filename + rm -f "$filename" && echo "파일이 삭제되었습니다." || echo "삭제 실패" send_stats "파일 삭제" ;; 21) # 压缩文件/目录 read -e -p "압축할 파일/디렉터리 이름을 입력하십시오:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축이 실패했습니다" - send_stats "압축 파일/디렉토리" + tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축 실패" + send_stats "압축된 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오:" filename + read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오." filename install tar - tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "감압이 실패했습니다" + tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "압축 해제 실패" send_stats "파일/디렉토리 압축 풀기" ;; @@ -13779,14 +13820,14 @@ linux_file() { read -e -p "이동할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉토리를 이동하지 못했습니다 : 파일 또는 디렉토리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 이동 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then echo "오류: 대상 경로를 입력하십시오." - send_stats "움직이는 파일 또는 디렉토리 실패 : 대상 경로가 지정되지 않았습니다." + send_stats "파일 또는 디렉터리 이동 실패: 대상 경로가 지정되지 않았습니다." continue fi @@ -13799,35 +13840,35 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then - echo "오류 : 대상 경로를 입력하십시오." + echo "오류: 대상 경로를 입력하십시오." send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." continue fi # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. - cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일이나 디렉토리를 복사하지 못했습니다" - send_stats "파일 또는 디렉토리를 복사하십시오" + cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." + send_stats "파일 또는 디렉터리 복사" ;; 25) # 传送文件至远端服务器 read -e -p "전송할 파일 경로를 입력하십시오:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "오류 : 파일이 존재하지 않습니다." + echo "오류: 파일이 존재하지 않습니다." send_stats "파일 전송 실패: 파일이 존재하지 않습니다." continue fi - read -e -p "원격 서버 IP를 입력하십시오 :" remote_ip + read -e -p "원격 서버 IP를 입력하세요:" remote_ip if [ -z "$remote_ip" ]; then echo "오류: 원격 서버 IP를 입력하세요." - send_stats "파일 전송 실패 : 원격 서버 IP가 입력되지 않았습니다" + send_stats "파일 전송 실패: 원격 서버 IP가 입력되지 않았습니다." continue fi @@ -13842,23 +13883,23 @@ linux_file() { continue fi - read -e -p "로그인 포트 (기본값 22)를 입력하십시오 :" remote_port + read -e -p "로그인 포트(기본값 22)를 입력하세요." remote_port remote_port=${remote_port:-22} # 알려진 호스트에 대한 이전 항목 지우기 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # SCP를 사용하여 파일을 전송합니다 + # scp를 사용하여 파일 전송 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}스크립트는 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}스크립트가 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" send_stats "스크립트가 최신 상태입니다.$sh_v_new" break_end ~/kejilion.sh @@ -14164,7 +14205,7 @@ while true; do 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}자동 업데이트가 닫힙니다${gl_bai}" + echo -e "${gl_lv}자동 업데이트가 꺼졌습니다${gl_bai}" send_stats "자동 스크립트 업데이트 끄기" break_end ;; @@ -14188,7 +14229,7 @@ echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" echo -e "기술 사자 스크립트 도구 상자 v$sh_v" -echo -e "명령 줄 입력${gl_huang}k${gl_kjlan}빠른 시작 스크립트${gl_bai}" +echo -e "명령줄 입력${gl_huang}k${gl_kjlan}빠른 시작 스크립트${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" @@ -14199,9 +14240,9 @@ echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" echo -e "${gl_kjlan}8. ${gl_bai}테스트 스크립트 수집" echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" -echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹 사이트 구축" +echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹사이트 구축" echo -e "${gl_kjlan}11. ${gl_bai}응용 시장" -echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업 공간" +echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업공간" echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" echo -e "${gl_kjlan}15. ${gl_bai}광고 칼럼" @@ -14212,7 +14253,7 @@ echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "선택을 입력하십시오 :" choice +read -e -p "선택사항을 입력하세요:" choice case $choice in 1) linux_info ;; @@ -14232,13 +14273,13 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Phantom Beast Palu 서버 오프닝 스크립트" ; cd ~ + p) send_stats "Eudemons Parlu 서버 오픈 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "잘못된 입력!" ;; + *) echo "입력이 잘못되었습니다!" ;; esac break_end done @@ -14246,13 +14287,13 @@ done k_info() { -send_stats "K 명령 참조 사용 사례" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." -echo "스크립트 시작 k" -echo "소프트웨어 패키지 설치 K 설치 나노 wget | K 추가 나노 wget | K Nano wget을 설치하십시오" -echo "패키지 k 제거 나노 wget | K del nano wget | k 제거 나노 wget | K를 제거하십시오" +echo "시작 스크립트 k" +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" echo "시스템 패널을 다시 설치하십시오. k dd | k 다시 설치하다" @@ -14263,10 +14304,10 @@ echo "가상 시간대 설정 k 시간 아시아/상하이 | k 시간대 아시 echo "시스템 휴지통 k 쓰레기 | khsz | k 휴지통" echo "시스템 백업 기능 k 백업 | k bf | k 백업" echo "SSH 원격 연결 도구 k SSH | k 원격 연결" -echo "rsync 원격 동기화 도구 K rsync | K 원격 동기화" -echo "하드 디스크 관리 도구 K 디스크 | K 하드 디스크 관리" -echo "인트라넷 침투 (서버 측) K frps" -echo "인트라넷 침투 (클라이언트) K frpc" +echo "rsync 원격 동기화 도구 k rsync | k 원격 동기화" +echo "하드 디스크 관리 도구 k 디스크 | k 하드 디스크 관리" +echo "인트라넷 침투(서버) k frps" +echo "인트라넷 침투(클라이언트) k frpc" echo "소프트웨어 시작 k start sshd | k sshd를 시작하세요" echo "소프트웨어 중지 k 중지 sshd | k sshd 중지" echo "소프트웨어 재시작 k 재시작 sshd | k sshd를 다시 시작하세요" @@ -14274,24 +14315,24 @@ echo "소프트웨어 상태 확인 k status sshd | k 상태 sshd" echo "k 도커 활성화 | k 자동 시작 도커 | k 소프트웨어를 부팅할 때 도커를 활성화합니다." echo "도메인 이름 인증서 신청 k SSL" echo "도메인 이름 인증서 만료 쿼리 k SSL ps" -echo "Docker Management Plane K Docker" -echo "도커 환경 설치 K 도커 설치 | K 도커 설치" +echo "도커 관리 플레인 k 도커" +echo "docker 환경 설치 k docker 설치 |k docker 설치" echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" -echo "Docker Image Management K Docker img | K Docker Image" -echo "LDNMP 사이트 관리 K 웹" +echo "도커 이미지 관리 k docker img |k 도커 이미지" +echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" -echo "리버스 프록시 k fd | k rp | k an-generation | k fd xxx.com을 설치하십시오." +echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" -echo "방화벽 패널 K FHQ | K 방화벽" +echo "방화벽 패널 k fhq |k 방화벽" echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" -echo "포트 K GBDK 7800 | K 닫기 포트 7800" -echo "IP K FXIP 127.0.0.0/8 | K 릴리스 IP 127.0.0.0/8 릴리스" -echo "블록 IP K ZZIP 177.5.25.36 | K 블록 IP 177.5.25.36" -echo "명령 즐겨 찾기 k fav | K 명령 즐겨 찾기" -echo "앱 시장 관리 K 앱" +echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" +echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" +echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" +echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" -echo "디스플레이 시스템 정보 K 정보" +echo "시스템 정보 표시 k 정보" } @@ -14300,11 +14341,11 @@ if [ "$#" -eq 0 ]; then # 인수 없이 대화형 논리를 실행합니다. kejilion_sh else - # 매개 변수가있는 경우 해당 함수를 실행하십시오 + # 매개변수가 있으면 해당 함수를 실행합니다. case $1 in install|add|安装) shift - send_stats "소프트웨어를 설치하십시오" + send_stats "소프트웨어 설치" install "$@" ;; remove|del|uninstall|卸载) @@ -14381,7 +14422,7 @@ else time|时区) shift - send_stats "시간대를 빠르게 설정하십시오" + send_stats "시간대를 빠르게 설정" set_timedate "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 56f7acff1..24eec9078 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.8" +sh_v="4.1.9" gl_hui='\e[37m' @@ -3372,11 +3372,11 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申請/更新域名證書 2. 更換站點域名" + echo "1. 申請/更新域名證書 2. 克隆站點域名" echo "3. 清理站點緩存 4. 創建關聯站點" echo "5. 查看訪問日誌 6. 查看錯誤日誌" echo "7. 編輯全局配置 8. 編輯站點配置" - echo "9. 管理站點數據庫 10. 查看站點分析報告" + echo "9. 管理站點數據庫 10. 查看站點分析報告" echo "------------------------" echo "20. 刪除指定站點數據" echo "------------------------" @@ -3395,8 +3395,7 @@ ldnmp_web_status() { ;; 2) - send_stats "更換站點域名" - echo -e "${gl_hong}強烈建議:${gl_bai}先備份好全站數據再更換站點域名!" + send_stats "克隆站點域名" read -e -p "請輸入舊域名:" oddyuming read -e -p "請輸入新域名:" yuming install_certbot @@ -3410,7 +3409,7 @@ ldnmp_web_status() { local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" + # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') @@ -3422,18 +3421,18 @@ ldnmp_web_status() { done # 網站目錄替換 - mv /home/web/html/$oddyuming /home/web/html/$yuming + cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + find /home/web/html/$yuming -type f -exec sed -i "s/$oddyuming/$yuming/g" {} + - mv /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf + cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - rm /home/web/certs/${oddyuming}_key.pem - rm /home/web/certs/${oddyuming}_cert.pem + # rm /home/web/certs/${oddyuming}_key.pem + # rm /home/web/certs/${oddyuming}_cert.pem - docker exec nginx nginx -s reload + cd /home/web && docker compose restart ;; @@ -8874,6 +8873,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" + echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -12165,6 +12165,47 @@ while true; do ;; + 103|umami) + local app_id="103" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: https://github.com/umami-software/umami" + local docker_name="umami-umami-1" + local docker_port="8103" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml + + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + echo "初始用戶名: admin" + echo "初始密碼: umami" + } + + docker_app_update() { + cd /home/docker/umami/ && docker compose down --rmi all + cd /home/docker/umami/ + git pull origin main + sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml + cd /home/docker/umami/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/umami/ && docker compose down --rmi all + rm -rf /home/docker/umami + echo "應用已卸載" + } + + docker_app_plus + + ;; + + b) clear From 47c95e5bb030878e479def24d2f80c23227d22de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:56:07 +0800 Subject: [PATCH 0275/1285] Update kejilion.sh --- cn/kejilion.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 76e3736cf..8c6b24610 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" - echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}VNC驱动的安卓模拟器(x86_64架构)" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml @@ -12205,6 +12205,53 @@ while true; do ;; + 104|android) + + local app_id="104" + local docker_name="android-container" + local docker_img="budtmo/docker-android:emulator_11.0" + local docker_port=8104 + + docker_rum() { + + read -e -p "设置访问密码: " app_passwd + + docker run -d \ + --name android-container \ + --restart=always \ + -p ${docker_port}:6080 \ + -e EMULATOR_DEVICE="Samsung Galaxy S10" \ + -e WEB_VNC=true \ + -e VNC_PASSWORD="${app_passwd}" \ + -v /home/docker/android:/home/androidusr \ + --device /dev/kvm \ + budtmo/docker-android:emulator_11.0 + + docker volume create android_data + docker run -d \ + --name android-container \ + --restart=always \ + -p 6080:6080 \ + -e EMULATOR_DEVICE="Samsung Galaxy S10" \ + -e WEB_VNC=true \ + -e VNC_PASSWORD="mypassword123" \ + -v android_data:/home/androidusr \ + --device /dev/kvm \ + budtmo/docker-android:emulator_11.0 + + + + + } + + local docker_describe="是一个基于 Docker 容器的 Android 模拟器环境" + local docker_url="官网介绍: https://github.com/budtmo/docker-android" + local docker_use="" + local docker_passwd="" + local app_size="3" + docker_app + + ;; b) From d0b6a2fa69cba88bacca0a2605838e33789da1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:58:12 +0800 Subject: [PATCH 0276/1285] Update kejilion.sh --- cn/kejilion.sh | 51 ++------------------------------------------------ 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8c6b24610..76e3736cf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8873,7 +8873,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" - echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}VNC驱动的安卓模拟器(x86_64架构)" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl wget + install git openssl mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml @@ -12205,53 +12205,6 @@ while true; do ;; - 104|android) - - local app_id="104" - local docker_name="android-container" - local docker_img="budtmo/docker-android:emulator_11.0" - local docker_port=8104 - - docker_rum() { - - read -e -p "设置访问密码: " app_passwd - - docker run -d \ - --name android-container \ - --restart=always \ - -p ${docker_port}:6080 \ - -e EMULATOR_DEVICE="Samsung Galaxy S10" \ - -e WEB_VNC=true \ - -e VNC_PASSWORD="${app_passwd}" \ - -v /home/docker/android:/home/androidusr \ - --device /dev/kvm \ - budtmo/docker-android:emulator_11.0 - - docker volume create android_data - docker run -d \ - --name android-container \ - --restart=always \ - -p 6080:6080 \ - -e EMULATOR_DEVICE="Samsung Galaxy S10" \ - -e WEB_VNC=true \ - -e VNC_PASSWORD="mypassword123" \ - -v android_data:/home/androidusr \ - --device /dev/kvm \ - budtmo/docker-android:emulator_11.0 - - - - - } - - local docker_describe="是一个基于 Docker 容器的 Android 模拟器环境" - local docker_url="官网介绍: https://github.com/budtmo/docker-android" - local docker_use="" - local docker_passwd="" - local app_size="3" - docker_app - - ;; b) From 598a7a89dfe5ac07c95312b6271e71a4d3fae35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:58:59 +0800 Subject: [PATCH 0277/1285] Update kejilion.sh From 98496d17dd3de2dfca69777ca17dc97400da6106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:01:29 +0800 Subject: [PATCH 0278/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 4b835c421..3d4cfb38a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml From 1a36345cea8bdaa675372cfcb0b010ae07270980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:02:04 +0800 Subject: [PATCH 0279/1285] Add wget installation to docker_app_install function --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 76e3736cf..bbeee49ef 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml From 1228e0dce5a358e9c916b21581c9efc17d5d8e9a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 19 Oct 2025 03:57:26 +0000 Subject: [PATCH 0280/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-19=2003:57:26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 14 +++++++------- jp/kejilion.sh | 38 +++++++++++++++++++------------------- kr/kejilion.sh | 28 ++++++++++++++-------------- tw/kejilion.sh | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 305b75111..d1698edd1 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -6118,7 +6118,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -9155,7 +9155,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml @@ -12556,7 +12556,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -14102,7 +14102,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14177,7 +14177,7 @@ while true; do CheckFirstRun_true yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "The script is up to date$sh_v_new" break_end ~/kejilion.sh @@ -14287,7 +14287,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 146f811f2..29fbbd273 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -890,7 +890,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done @@ -1218,7 +1218,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -2114,7 +2114,7 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -4341,7 +4341,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5785,7 +5785,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6006,7 +6006,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6097,7 +6097,7 @@ format_partition() { fi } -# パーティションのステータスを確認する +# 检查分区状态 check_partition() { send_stats "パーティションのステータスを確認する" read -e -p "確認するパーティション名を入力してください (例: sda1):" PARTITION @@ -6109,7 +6109,7 @@ check_partition() { fi # パーティションのステータスを確認する - echo "パーティション /dev/ を確認してください$PARTITION状態:" + echo "检查分区 /dev/$PARTITION状態:" fsck "/dev/$PARTITION" } @@ -6137,7 +6137,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6424,7 +6424,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -8814,7 +8814,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -8822,7 +8822,7 @@ while true; do echo -e "${gl_kjlan}13. ${color13}Cloudreve ネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルなピクチャーベッド画像管理プログラム" echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}Speedtest スピードテストパネル" echo -e "${gl_kjlan}17. ${color17}AdGuardHome はアドウェアを削除します${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" - echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}ポーターコンテナ管理パネル" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode Web バージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" echo -e "${gl_kjlan}23. ${color23}メモウェブメモ${gl_kjlan}24. ${color24}Webtop リモート デスクトップ Web バージョン${gl_huang}★${gl_bai}" @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml @@ -11846,7 +11846,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -12748,8 +12748,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -12977,7 +12977,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13844,7 +13844,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14287,7 +14287,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 88d94db65..36d551dbe 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -2672,7 +2672,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2872,7 +2872,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -6870,7 +6870,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7298,7 +7298,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8814,7 +8814,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9075,7 +9075,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9155,7 +9155,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9187,7 +9187,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml @@ -12412,7 +12412,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -12492,7 +12492,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -12748,8 +12748,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -14287,7 +14287,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 24eec9078..ac3dbbf37 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -11384,7 +11384,7 @@ while true; do local app_size="3" docker_app_install() { - install git openssl + install git openssl wget mkdir -p /home/docker/${docker_name} && cd /home/docker/${docker_name} wget -O docker-compose.yml ${gh_proxy}github.com/immich-app/immich/releases/latest/download/docker-compose.yml From 386e681c5c353374c1a66f7b2eb987dbdd969fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:33:56 +0800 Subject: [PATCH 0281/1285] Update kejilion.sh --- kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3d4cfb38a..f6d2d88ef 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10497,7 +10497,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10536,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10653,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12109,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12176,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d From 66cc110032c1a62adf98b14609df9eeeabb2bfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:34:42 +0800 Subject: [PATCH 0282/1285] Update git clone URLs to use HTTPS --- cn/kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bbeee49ef..8e390fe64 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10497,7 +10497,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10536,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10653,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12109,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12176,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d From 2782176e5816d229226bc9ca950bd47a6fa5870e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:37:47 +0800 Subject: [PATCH 0283/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index d24b25ed2..35443ef0e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1324,5 +1324,6 @@ k快捷命令增加了 k info 系统信息快速查询。 2025-10-09 v4.1.9 LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可以保留老站点,让用户自己处决。 应用市场新增了Umami网站统计工具的安装及使用。 +应用市场优化了部分应用因网络原因无法安装的问题。 ------------------------ From 64108524983f5c74d321d32cbc1128eba51931d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:40:41 +0800 Subject: [PATCH 0284/1285] Update kejilion.sh --- kejilion.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f6d2d88ef..e1f51f22a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1335,11 +1335,9 @@ ldnmp_v() { install_ldnmp_conf() { # 创建必要的目录和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl From 10e290fcc5446eea8d1e987fb0c08ce5632cc20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:41:59 +0800 Subject: [PATCH 0285/1285] Update kejilion.sh --- cn/kejilion.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8e390fe64..e1f51f22a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -1335,11 +1335,9 @@ ldnmp_v() { install_ldnmp_conf() { # 创建必要的目录和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl From cc3b77ac0b10c824020b86a5f14a2e73aa249684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:42:22 +0800 Subject: [PATCH 0286/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e1f51f22a..c8b5d374f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From 0b538d35d70440a17a6edaaa1e65bb45e880e1e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:50:26 +0800 Subject: [PATCH 0287/1285] Update kejilion.sh --- cn/kejilion.sh | 245 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 223 insertions(+), 22 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c8b5d374f..c7e5e46b5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -1353,31 +1353,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -3275,8 +3278,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "安装$webname" echo "开始部署 $webname" @@ -3314,6 +3315,194 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # 服务名取文件名 + service_name=$(basename "$conf" .conf) + + # 获取 upstream 块中的 server 后端 IP:端口 + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # 获取 listen 端口 + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # 默认本地 IP + ip_address + local_ip="$ipv4_address" + + # 获取通信类型,优先从文件名后缀或内容判断 + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # 拼接监听 IP:端口 + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "Stream四层代理" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模块,用于实现高性能的 传输层流量转发和负载均衡。" + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. 安装 2. 更新 3. 卸载" + echo "------------------------" + echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice + case $choice in + 1) + nginx_install_status + add_app_id + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + ;; + 3) + read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + echo "nginx 容器已删除。" + else + echo "操作已取消。" + fi + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + ;; + 5) + send_stats "编辑转发配置" + read -e -p "请输入你要编辑的服务名: " stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + ;; + 6) + send_stats "删除转发配置" + read -e -p "请输入你要删除的服务名: " stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "安装$webname" + echo "开始部署 $webname" + + # 获取代理名称 + read -rp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + if [ -z "$proxy_name" ]; then + echo "名称不能为空"; return 1 + fi + + # 获取监听端口 + read -rp "请输入本机监听端口 (如 3306): " listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "端口必须是数字"; return 1 + fi + + echo "请选择协议类型:" + echo "1. TCP 2. UDP" + read -rp "请输入序号 [1-2]: " proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "无效选择"; return 1 ;; + esac + + read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port + + nginx_install_status + + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "您的 $webname 搭建好了!" + echo "------------------------" + echo "访问地址:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -7845,7 +8034,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" @@ -8425,6 +8614,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8871,7 +9064,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" - echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12203,7 +12396,9 @@ while true; do ;; - + 104|stream) + stream_panel + ;; b) clear @@ -14322,6 +14517,7 @@ echo "LDNMP缓存清理 k web cache" echo "安装WordPress k wp |k wordpress |k wp xxx.com" echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "安装L4负载均衡 k stream |k L4负载均衡" echo "防火墙面板 k fhq |k 防火墙" echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" @@ -14412,6 +14608,11 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift send_stats "快速设置虚拟内存" From b1258bda4dfa313bea6f502c4ccd96041eece633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:50:59 +0800 Subject: [PATCH 0288/1285] Update kejilion.sh --- kejilion.sh | 245 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 223 insertions(+), 22 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e1f51f22a..76cfb8b41 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -1353,31 +1353,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -3275,8 +3278,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "安装$webname" echo "开始部署 $webname" @@ -3314,6 +3315,194 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # 服务名取文件名 + service_name=$(basename "$conf" .conf) + + # 获取 upstream 块中的 server 后端 IP:端口 + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # 获取 listen 端口 + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # 默认本地 IP + ip_address + local_ip="$ipv4_address" + + # 获取通信类型,优先从文件名后缀或内容判断 + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # 拼接监听 IP:端口 + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "Stream四层代理" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模块,用于实现高性能的 传输层流量转发和负载均衡。" + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. 安装 2. 更新 3. 卸载" + echo "------------------------" + echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "输入你的选择: " choice + case $choice in + 1) + nginx_install_status + add_app_id + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + ;; + 3) + read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + echo "nginx 容器已删除。" + else + echo "操作已取消。" + fi + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + ;; + 5) + send_stats "编辑转发配置" + read -e -p "请输入你要编辑的服务名: " stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + ;; + 6) + send_stats "删除转发配置" + read -e -p "请输入你要删除的服务名: " stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "安装$webname" + echo "开始部署 $webname" + + # 获取代理名称 + read -rp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + if [ -z "$proxy_name" ]; then + echo "名称不能为空"; return 1 + fi + + # 获取监听端口 + read -rp "请输入本机监听端口 (如 3306): " listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "端口必须是数字"; return 1 + fi + + echo "请选择协议类型:" + echo "1. TCP 2. UDP" + read -rp "请输入序号 [1-2]: " proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "无效选择"; return 1 ;; + esac + + read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port + + nginx_install_status + + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "您的 $webname 搭建好了!" + echo "------------------------" + echo "访问地址:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -7845,7 +8034,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" @@ -8425,6 +8614,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8871,7 +9064,7 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" - echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12203,7 +12396,9 @@ while true; do ;; - + 104|stream) + stream_panel + ;; b) clear @@ -14322,6 +14517,7 @@ echo "LDNMP缓存清理 k web cache" echo "安装WordPress k wp |k wordpress |k wp xxx.com" echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "安装L4负载均衡 k stream |k L4负载均衡" echo "防火墙面板 k fhq |k 防火墙" echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" @@ -14412,6 +14608,11 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift send_stats "快速设置虚拟内存" From e36b977ed00138356335e279d98b0a23817f712d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:53:34 +0800 Subject: [PATCH 0289/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 35443ef0e..a0373922c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1326,4 +1326,7 @@ LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可 应用市场新增了Umami网站统计工具的安装及使用。 应用市场优化了部分应用因网络原因无法安装的问题。 ------------------------ +2025-10-21 v4.2.0 +LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 +------------------------ From 369b8142f150768bd95f7cd3069796581753b503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:41:25 +0800 Subject: [PATCH 0290/1285] Update kejilion.sh --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c7e5e46b5..20493cf01 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3467,7 +3467,6 @@ ldnmp_Proxy_backend_stream() { read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port nginx_install_status - cd /home && mkdir -p web/stream.d grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf @@ -12396,7 +12395,7 @@ while true; do ;; - 104|stream) + 104|nginx-stream) stream_panel ;; From 6009c87655278d9d8666a9f6793d9bea8b631e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:42:19 +0800 Subject: [PATCH 0291/1285] Update kejilion.sh --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 76cfb8b41..febb040ed 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3467,7 +3467,6 @@ ldnmp_Proxy_backend_stream() { read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port nginx_install_status - cd /home && mkdir -p web/stream.d grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf @@ -12396,7 +12395,7 @@ while true; do ;; - 104|stream) + 104|nginx-stream) stream_panel ;; From 89237d6438cc2f1c95a3d91391e137fdd571a8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:31:17 +0800 Subject: [PATCH 0292/1285] Update kejilion.sh --- cn/kejilion.sh | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 20493cf01..251135024 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9064,6 +9064,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" + echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12399,6 +12400,69 @@ while true; do stream_panel ;; + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="105" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + b) clear send_stats "全部应用备份" From 4d51ace7d5756338c68015f3ca2866422992336a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:31:56 +0800 Subject: [PATCH 0293/1285] Add Siyuan and Drawnix applications to script --- kejilion.sh | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index febb040ed..a7d56f673 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9064,6 +9064,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" + echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12399,6 +12400,69 @@ while true; do stream_panel ;; + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "设置登录密码: " app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="105" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + b) clear send_stats "全部应用备份" From 001a9b6c1e8dd183dce9c1aa1ca46e35bd142229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:34:00 +0800 Subject: [PATCH 0294/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index a0373922c..68d56497d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1328,5 +1328,7 @@ LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可 ------------------------ 2025-10-21 v4.2.0 LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 +应用市场新增了思源笔记的安装及使用。 +应用市场新增了开源Drawnix白板工具的安装及使用。 ------------------------ From 6e03e4cd65a3a573125f5efe457f2f3072e4958d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:50:52 +0800 Subject: [PATCH 0295/1285] Update kejilion.sh --- cn/kejilion.sh | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 251135024..9d260faf6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9065,6 +9065,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12437,7 +12438,7 @@ while true; do 106|drawnix) - local app_id="105" + local app_id="106" local docker_name="drawnix" local docker_img="pubuzhixing/drawnix" local docker_port=8106 @@ -12462,6 +12463,37 @@ while true; do ;; + 106|drawnix) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + b) clear From f6892e1ef1b259df2090737965c76afc004d7011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:51:25 +0800 Subject: [PATCH 0296/1285] Add PanSou cloud storage search tool --- kejilion.sh | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index a7d56f673..d7c5bfab3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9065,6 +9065,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12437,7 +12438,7 @@ while true; do 106|drawnix) - local app_id="105" + local app_id="106" local docker_name="drawnix" local docker_img="pubuzhixing/drawnix" local docker_port=8106 @@ -12462,6 +12463,37 @@ while true; do ;; + 106|drawnix) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + b) clear From 0b0cfab71d99b9ca39c0782a9f361d6a9a2d98ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:52:58 +0800 Subject: [PATCH 0297/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 68d56497d..61e1e6a00 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1330,5 +1330,6 @@ LDNMP建站中将更换站点域名功能调整成克隆站点功能,这样可 LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 应用市场新增了思源笔记的安装及使用。 应用市场新增了开源Drawnix白板工具的安装及使用。 +应用市场新增了PanSou网盘搜索工具的安装及使用。 ------------------------ From 63d7a5d5d7d00df5873d91ea62174cf7bf6dc734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:55:53 +0800 Subject: [PATCH 0298/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d7c5bfab3..1231b02fe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12463,7 +12463,7 @@ while true; do ;; - 106|drawnix) + 107|pansou) local app_id="107" local docker_name="pansou" From 459eefe9c71a8e49a70604bd0109359707d3f424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:56:32 +0800 Subject: [PATCH 0299/1285] Rename drawnix to pansou in kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9d260faf6..d4039a24b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12463,7 +12463,7 @@ while true; do ;; - 106|drawnix) + 107|pansou) local app_id="107" local docker_name="pansou" From 380b39da3acaab57d041345c4c46f847e3c01321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 24 Oct 2025 17:56:59 +0800 Subject: [PATCH 0300/1285] Update kejilion.sh --- cn/kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d4039a24b..111b30b72 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -3391,26 +3393,31 @@ stream_panel() { 1) nginx_install_status add_app_id + send_stats "安装Stream四层代理" ;; 2) update_docker_compose_with_db_creds nginx_upgrade add_app_id + send_stats "更新Stream四层代理" ;; 3) read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "更新Stream四层代理" echo "nginx 容器已删除。" else echo "操作已取消。" fi - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + ;; 4) ldnmp_Proxy_backend_stream add_app_id + send_stats "添加四层代理" ;; 5) send_stats "编辑转发配置" @@ -3418,12 +3425,14 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx + send_stats "修改四层代理" ;; 6) send_stats "删除转发配置" read -e -p "请输入你要删除的服务名: " stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx + send_stats "删除四层代理" ;; *) break From 777d00357f0727540061667c522f47361b6d133d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 24 Oct 2025 17:57:35 +0800 Subject: [PATCH 0301/1285] Add send_stats calls for various operations --- kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1231b02fe..f21db5585 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -3391,26 +3393,31 @@ stream_panel() { 1) nginx_install_status add_app_id + send_stats "安装Stream四层代理" ;; 2) update_docker_compose_with_db_creds nginx_upgrade add_app_id + send_stats "更新Stream四层代理" ;; 3) read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "更新Stream四层代理" echo "nginx 容器已删除。" else echo "操作已取消。" fi - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + ;; 4) ldnmp_Proxy_backend_stream add_app_id + send_stats "添加四层代理" ;; 5) send_stats "编辑转发配置" @@ -3418,12 +3425,14 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx + send_stats "修改四层代理" ;; 6) send_stats "删除转发配置" read -e -p "请输入你要删除的服务名: " stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx + send_stats "删除四层代理" ;; *) break From f0f4247fd61ba7819eb4f6bbeb4b4f36de8bb59a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 24 Oct 2025 11:34:39 +0000 Subject: [PATCH 0302/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-24=2011:34:39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 379 ++++++++++++++++++++++++++++++++++---- jp/kejilion.sh | 485 +++++++++++++++++++++++++++++++++++++++---------- kr/kejilion.sh | 407 +++++++++++++++++++++++++++++++++++------ tw/kejilion.sh | 361 +++++++++++++++++++++++++++++++++--- 4 files changed, 1422 insertions(+), 210 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d1698edd1..767701c6f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -913,7 +915,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1335,11 +1337,9 @@ ldnmp_v() { install_ldnmp_conf() { # Create necessary directories and files - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl @@ -1355,31 +1355,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -3277,8 +3280,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "Install$webname" echo "Start deployment$webname" @@ -3316,6 +3317,200 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # Service name takes file name + service_name=$(basename "$conf" .conf) + + # Get the server backend IP:port in the upstream block + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # Get listen port + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # Default local IP + ip_address + local_ip="$ipv4_address" + + # Get the communication type, first judging from the file name suffix or content + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # Splice listening IP:port + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "Stream four-layer proxy" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "Stream four-layer proxy forwarding tool$check_docker $update_status" + echo "NGINX Stream is the TCP/UDP proxy module of NGINX, which is used to achieve high-performance transport layer traffic forwarding and load balancing." + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. Install 2. Update 3. Uninstall" + echo "------------------------" + echo "4. Add forwarding service 5. Modify forwarding service 6. Delete forwarding service" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Enter your selection:" choice + case $choice in + 1) + nginx_install_status + add_app_id + send_stats "Install Stream four-layer agent" + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + send_stats "Update Stream four-layer proxy" + ;; + 3) + read -e -p "Are you sure you want to delete the nginx container? This may affect website functionality! (y/N):" confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "Update Stream four-layer proxy" + echo "nginx container has been deleted." + else + echo "The operation has been cancelled." + fi + + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + send_stats "Add layer 4 proxy" + ;; + 5) + send_stats "Edit forwarding configuration" + read -e -p "Please enter the service name you want to edit:" stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + send_stats "Modify layer 4 proxy" + ;; + 6) + send_stats "Delete forwarding configuration" + read -e -p "Please enter the service name you want to delete:" stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + send_stats "Delete layer 4 proxy" + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "Install$webname" + echo "Start deployment$webname" + + # Get agent name + read -rp "Please enter a proxy forwarding name (e.g. mysql_proxy):" proxy_name + if [ -z "$proxy_name" ]; then + echo "Name cannot be empty"; return 1 + fi + + # Get listening port + read -rp "Please enter the local listening port (such as 3306):" listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "Port must be numeric"; return 1 + fi + + echo "Please select agreement type:" + echo "1. TCP 2. UDP" + read -rp "Please enter the serial number [1-2]:" proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "Invalid selection"; return 1 ;; + esac + + read -e -p "Please enter one or more of your backend IP+ports separated by spaces (for example, 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + + nginx_install_status + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "your$webnameIt's built!" + echo "------------------------" + echo "Visit address:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -4502,14 +4697,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -6950,7 +7145,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -7847,7 +8042,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy-domain name" echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden Password Management Platform${gl_huang}26. ${gl_bai}Install Halo Blog Site" echo -e "${gl_huang}27. ${gl_bai}Install the AI ​​painting prompt word generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" - echo -e "${gl_huang}30. ${gl_bai}Custom static site" + echo -e "${gl_huang}29. ${gl_bai}Stream four-layer proxy forwarding${gl_huang}30. ${gl_bai}Custom static site" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore whole site data" @@ -8427,6 +8622,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8814,7 +9013,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -8873,7 +9072,9 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing peer-to-peer file synchronization tool" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" - echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool" + echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool${gl_kjlan}104. ${color104}Stream four-layer proxy forwarding tool" + echo -e "${gl_kjlan}105. ${color105}Siyuan Notes${gl_kjlan}106. ${color106}Drawnix open source whiteboard tool" + echo -e "${gl_kjlan}107. ${color107}PanSou network disk search" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" @@ -9155,7 +9356,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10497,7 +10698,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10737,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10854,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12310,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12377,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12205,6 +12406,102 @@ while true; do ;; + 104|nginx-stream) + stream_panel + ;; + + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "Set login password:" app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="106" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 107|pansou) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -12310,7 +12607,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -12556,7 +12853,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -14177,7 +14474,7 @@ while true; do CheckFirstRun_true yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" send_stats "The script is up to date$sh_v_new" break_end ~/kejilion.sh @@ -14324,6 +14621,7 @@ echo "LDNMP cache cleaning k web cache" echo "Install WordPress k wp | k wordpress | k wp xxx.com" echo "Install reverse proxy k fd |k rp |k reverse proxy |k fd xxx.com" echo "Install load balancing k loadbalance |k load balancing" +echo "Install L4 load balancing k stream |k L4 load balancing" echo "firewall panel k fhq |k firewall" echo "open port k dkdk 8080 |k open port 8080" echo "Close port k gbdk 7800 |k Close port 7800" @@ -14414,6 +14712,11 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift send_stats "Quickly set up virtual memory" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 29fbbd273..a9559b67b 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -116,7 +116,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "上記の条件に同意しますか? (y/n):" user_input @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -243,7 +245,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストールする$package...${gl_bai}" + echo -e "${gl_huang}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -895,7 +897,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -953,12 +955,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1218,7 +1220,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1335,11 +1337,9 @@ ldnmp_v() { install_ldnmp_conf() { # 必要なディレクトリとファイルを作成する - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl @@ -1355,31 +1355,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -1523,7 +1526,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -1865,7 +1868,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1996,7 +1999,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2111,11 +2114,11 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2231,7 +2234,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2439,7 +2442,7 @@ check_docker_image_update() { # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIからイメージのリリース時刻を取得する + # Docker Hub APIからイメージのリリース時間を取得する local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) @@ -2487,7 +2490,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2504,7 +2507,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2759,7 +2762,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2872,7 +2875,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3277,8 +3280,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "インストール$webname" echo "導入を開始する$webname" @@ -3316,6 +3317,200 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # サービス名がファイル名になります + service_name=$(basename "$conf" .conf) + + # 上流ブロックでサーバーのバックエンド IP:ポートを取得します。 + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # リッスンポートの取得 + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # デフォルトのローカルIP + ip_address + local_ip="$ipv4_address" + + # ファイル名の接尾辞または内容から最初に判断して通信タイプを取得します + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # スプライス リスニング IP:ポート + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "ストリーム 4 層プロキシ" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "ストリーム 4 層プロキシ転送ツール$check_docker $update_status" + echo "NGINX Stream は NGINX の TCP/UDP プロキシ モジュールであり、高性能のトランスポート層トラフィック転送とロード バランシングを実現するために使用されます。" + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. インストール 2. アップデート 3. アンインストール" + echo "------------------------" + echo "4. 転送サービスの追加 5. 転送サービスの変更 6. 転送サービスの削除" + echo "------------------------" + echo "0. 前のメニューに戻る" + echo "------------------------" + read -e -p "選択内容を入力してください:" choice + case $choice in + 1) + nginx_install_status + add_app_id + send_stats "Stream 4 層エージェントのインストール" + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + send_stats "ストリームの 4 層プロキシを更新します" + ;; + 3) + read -e -p "nginx コンテナを削除してもよろしいですか?これはウェブサイトの機能に影響を与える可能性があります。 (y/N):" confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "ストリームの 4 層プロキシを更新します" + echo "nginxコンテナは削除されました。" + else + echo "操作はキャンセルされました。" + fi + + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + send_stats "レイヤ 4 プロキシを追加する" + ;; + 5) + send_stats "転送設定を編集する" + read -e -p "編集するサービス名を入力してください:" stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + send_stats "レイヤ 4 プロキシを変更する" + ;; + 6) + send_stats "転送設定の削除" + read -e -p "削除するサービス名を入力してください:" stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + send_stats "レイヤ 4 プロキシを削除する" + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "インストール$webname" + echo "導入を開始する$webname" + + # エージェント名を取得する + read -rp "プロキシ転送名を入力してください (例: mysql_proxy):" proxy_name + if [ -z "$proxy_name" ]; then + echo "名前を空にすることはできません"; return 1 + fi + + # リスニングポートの取得 + read -rp "ローカルのリスニング ポート (3306 など) を入力してください。" listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "ポートは数値である必要があります"; return 1 + fi + + echo "契約の種類を選択してください:" + echo "1. TCP 2. UDP" + read -rp "シリアル番号を入力してください [1-2]:" proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "無効な選択"; return 1 ;; + esac + + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + + nginx_install_status + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "あなたの$webname建てられました!" + echo "------------------------" + echo "訪問先住所:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -3476,7 +3671,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3928,7 +4123,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4341,7 +4536,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4502,14 +4697,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには、root ユーザーが必要です。" && break_end && kejilion } @@ -5055,7 +5250,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5785,7 +5980,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -5985,9 +6180,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションのマウント +# パーティションをマウントする mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6097,7 +6292,7 @@ format_partition() { fi } -# 检查分区状态 +# パーティションのステータスを確認する check_partition() { send_stats "パーティションのステータスを確認する" read -e -p "確認するパーティション名を入力してください (例: sda1):" PARTITION @@ -6109,7 +6304,7 @@ check_partition() { fi # パーティションのステータスを確認する - echo "检查分区 /dev/$PARTITION状態:" + echo "パーティション /dev/ を確認してください$PARTITION状態:" fsck "/dev/$PARTITION" } @@ -6137,7 +6332,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6166,7 +6361,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6334,7 +6529,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6424,7 +6619,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6608,7 +6803,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -6912,7 +7107,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -6923,7 +7118,7 @@ docker_ssh_migration() { echo "# docker-compose 復元:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトの作成 [$project_name] パッケージ内容:${project_dir}${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name]パッケージ化:${project_dir}${NC}" else echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" fi @@ -7079,7 +7274,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7185,7 +7380,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7229,7 +7424,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7328,7 +7523,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -7662,7 +7857,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -7847,7 +8042,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" - echo -e "${gl_huang}30. ${gl_bai}カスタム静的サイト" + echo -e "${gl_huang}29. ${gl_bai}ストリーム 4 層プロキシ転送${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイト全体のデータをバックアップする" echo -e "${gl_huang}33. ${gl_bai}スケジュールされたリモートバックアップ${gl_huang}34. ${gl_bai}サイト全体のデータを復元する" @@ -8027,7 +8222,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8427,6 +8622,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8466,7 +8665,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/ のような、index.html へのパスを入力してください)$yuming/index/): " index_lujing + read -e -p "(/home/web/html/ のような)index.html へのパスを入力してください。$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8852,7 +9051,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -8862,7 +9061,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" @@ -8873,7 +9072,9 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM Synology 仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat 複数人オンライン チャット システム" - echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール" + echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" + echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" + echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" @@ -9075,7 +9276,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "ネザ監視$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9084,7 +9285,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -10497,7 +10698,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10737,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10854,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12310,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12377,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12205,6 +12406,102 @@ while true; do ;; + 104|nginx-stream) + stream_panel + ;; + + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "ログインパスワードを設定します:" app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="106" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 107|pansou) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -12310,7 +12607,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -12561,7 +12858,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -12962,7 +13259,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -12977,7 +13274,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13824,7 +14121,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -13844,7 +14141,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -13980,10 +14277,10 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14159,7 +14456,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" + echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -14251,7 +14548,7 @@ echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu サーバー開始スクリプ echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -14294,7 +14591,7 @@ echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -14303,7 +14600,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -14322,10 +14619,11 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" +echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -14414,9 +14712,14 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift - send_stats "仮想メモリをすばやくセットアップする" + send_stats "仮想メモリを素早く設定する" add_swap "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 36d551dbe..aea2c98cd 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -1335,11 +1337,9 @@ ldnmp_v() { install_ldnmp_conf() { # 필요한 디렉토리 및 파일 생성 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl @@ -1355,31 +1355,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -2112,7 +2115,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2443,7 +2446,7 @@ check_docker_image_update() { local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득한 시간을 확인하세요. + # 획득한 시간을 확인 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) @@ -2759,7 +2762,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3185,7 +3188,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3194,7 +3197,7 @@ ldnmp_web_on() { nginx_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" } @@ -3277,8 +3280,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3316,6 +3317,200 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # 서비스 이름은 파일 이름을 사용합니다. + service_name=$(basename "$conf" .conf) + + # 업스트림 블록에서 서버 백엔드 IP:포트 가져오기 + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # 청취 포트 가져오기 + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # 기본 로컬 IP + ip_address + local_ip="$ipv4_address" + + # 먼저 파일 이름 접미사 또는 내용으로 판단하여 통신 유형을 가져옵니다. + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # 스플라이스 청취 IP:포트 + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "4계층 프록시 스트리밍" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "스트림 4계층 프록시 전달 도구$check_docker $update_status" + echo "NGINX 스트림은 고성능 전송 계층 트래픽 전달 및 로드 밸런싱을 달성하는 데 사용되는 NGINX의 TCP/UDP 프록시 모듈입니다." + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. 설치 2. 업데이트 3. 제거" + echo "------------------------" + echo "4. 포워딩 서비스 추가 5. 포워딩 서비스 수정 6. 포워딩 서비스 삭제" + echo "------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "------------------------" + read -e -p "선택 항목을 입력하세요." choice + case $choice in + 1) + nginx_install_status + add_app_id + send_stats "Stream 4계층 에이전트 설치" + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + send_stats "Stream 4계층 프록시 업데이트" + ;; + 3) + read -e -p "nginx 컨테이너를 삭제하시겠습니까? 이는 웹사이트 기능에 영향을 미칠 수 있습니다! (예/아니요):" confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "Stream 4계층 프록시 업데이트" + echo "nginx 컨테이너가 삭제되었습니다." + else + echo "작업이 취소되었습니다." + fi + + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + send_stats "레이어 4 프록시 추가" + ;; + 5) + send_stats "전달 구성 수정" + read -e -p "편집하려는 서비스 이름을 입력하십시오:" stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + send_stats "레이어 4 프록시 수정" + ;; + 6) + send_stats "전달 구성 삭제" + read -e -p "삭제하려는 서비스 이름을 입력하세요." stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + send_stats "레이어 4 프록시 삭제" + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "설치하다$webname" + echo "배포 시작$webname" + + # 에이전트 이름 가져오기 + read -rp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name + if [ -z "$proxy_name" ]; then + echo "이름은 비워둘 수 없습니다."; return 1 + fi + + # 수신 포트 가져오기 + read -rp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "포트는 숫자여야 합니다."; return 1 + fi + + echo "계약 유형을 선택하십시오:" + echo "1. TCP 2. UDP" + read -rp "일련 번호 [1-2]를 입력하십시오:" proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "잘못된 선택"; return 1 ;; + esac + + read -e -p "하나 이상의 백엔드 IP+포트를 공백으로 구분하여 입력하세요(예: 10.13.0.2:3306 10.13.0.3:3306)." reverseproxy_port + + nginx_install_status + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "당신의$webname건설되었습니다!" + echo "------------------------" + echo "방문 주소:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -3619,7 +3814,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -3681,7 +3876,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4884,7 +5079,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -4894,7 +5089,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -4948,7 +5143,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5037,7 +5232,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5091,7 +5286,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -7009,7 +7204,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7025,7 +7220,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 용기:$container${NC}" + echo -e "${GREEN}처리용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7847,7 +8042,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}사이트 역방향 프록시-IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" - echo -e "${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" + echo -e "${gl_huang}29. ${gl_bai}스트림 4계층 프록시 전달${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터 복원" @@ -8026,7 +8221,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8427,6 +8622,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8873,7 +9072,9 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}P2P 파일 동기화 도구 동기화" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" - echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구" + echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" @@ -9066,7 +9267,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9155,7 +9356,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9187,7 +9388,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -10497,7 +10698,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10737,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10854,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12310,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12377,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12205,6 +12406,102 @@ while true; do ;; + 104|nginx-stream) + stream_panel + ;; + + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "로그인 비밀번호 설정:" app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="106" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 107|pansou) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -12310,7 +12607,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -12492,7 +12789,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -12502,7 +12799,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -14321,9 +14618,10 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" +echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" @@ -14414,6 +14712,11 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift send_stats "가상 메모리를 빠르게 설정하세요" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index ac3dbbf37..ded2d8c10 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.1.9" +sh_v="4.2.0" gl_hui='\e[37m' @@ -216,6 +216,8 @@ check_disk_space() { local required_gb=$1 local path=${2:-/} + mkdir -p "$path" + local required_space_mb=$((required_gb * 1024)) local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') @@ -1335,11 +1337,9 @@ ldnmp_v() { install_ldnmp_conf() { # 創建必要的目錄和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf - wget -O /home/web/redis/valkey.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/valkey.conf - default_server_ssl @@ -1355,31 +1355,34 @@ install_ldnmp_conf() { } +update_docker_compose_with_db_creds() { + cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if ! grep -q "stream" /home/web/docker-compose.yml; then + wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml -install_ldnmp() { + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - check_swap + sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml + sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml + fi - cp /home/web/docker-compose.yml /home/web/docker-compose1.yml + if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + fi - if ! grep -q "network_mode" /home/web/docker-compose.yml; then - wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') +} - sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml - sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml - fi +install_ldnmp() { - if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 - fi + check_swap + update_docker_compose_with_db_creds cd /home/web && docker compose up -d sleep 1 @@ -3277,8 +3280,6 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear webname="反向代理-负载均衡" - yuming="${1:-}" - reverseproxy_port="${2:-}" send_stats "安裝$webname" echo "開始部署$webname" @@ -3316,6 +3317,200 @@ ldnmp_Proxy_backend() { + + + +list_stream_services() { + + STREAM_DIR="/home/web/stream.d" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + + if [ -z "$(ls -A "$STREAM_DIR")" ]; then + return + fi + + for conf in "$STREAM_DIR"/*; do + # 服務名取文件名 + service_name=$(basename "$conf" .conf) + + # 獲取 upstream 塊中的 server 後端 IP:端口 + backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) + + # 獲取 listen 端口 + listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) + + # 默認本地 IP + ip_address + local_ip="$ipv4_address" + + # 獲取通信類型,優先從文件名後綴或內容判斷 + if grep -qi 'udp;' "$conf"; then + proto="udp" + else + proto="tcp" + fi + + # 拼接監聽 IP:端口 + local_addr="$local_ip:$listen_port" + + printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" + done +} + + + + + + + + + +stream_panel() { + send_stats "Stream四層代理" + local app_id="104" + local docker_name="nginx" + + while true; do + clear + check_docker_app + check_docker_image_update $docker_name + echo -e "Stream四層代理轉發工具$check_docker $update_status" + echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模塊,用於實現高性能的 傳輸層流量轉發和負載均衡。" + echo "------------------------" + if [ -d "/home/web/stream.d" ]; then + list_stream_services + fi + echo "" + echo "------------------------" + echo "1. 安裝 2. 更新 3. 卸載" + echo "------------------------" + echo "4. 添加轉發服務 5. 修改轉發服務 6. 刪除轉發服務" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "輸入你的選擇:" choice + case $choice in + 1) + nginx_install_status + add_app_id + send_stats "安裝Stream四層代理" + ;; + 2) + update_docker_compose_with_db_creds + nginx_upgrade + add_app_id + send_stats "更新Stream四層代理" + ;; + 3) + read -e -p "確定要刪除 nginx 容器嗎?這可能會影響網站功能! (y/N):" confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + docker rm -f nginx + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "更新Stream四層代理" + echo "nginx 容器已刪除。" + else + echo "操作已取消。" + fi + + ;; + + 4) + ldnmp_Proxy_backend_stream + add_app_id + send_stats "添加四層代理" + ;; + 5) + send_stats "編輯轉發配置" + read -e -p "請輸入你要編輯的服務名:" stream_name + install nano + nano /home/web/stream.d/$stream_name.conf + docker restart nginx + send_stats "修改四層代理" + ;; + 6) + send_stats "刪除轉發配置" + read -e -p "請輸入你要刪除的服務名:" stream_name + rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 + docker restart nginx + send_stats "刪除四層代理" + ;; + *) + break + ;; + esac + break_end + done +} + + + +ldnmp_Proxy_backend_stream() { + clear + webname="Stream四层代理-负载均衡" + + send_stats "安裝$webname" + echo "開始部署$webname" + + # 獲取代理名稱 + read -rp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name + if [ -z "$proxy_name" ]; then + echo "名稱不能為空"; return 1 + fi + + # 獲取監聽端口 + read -rp "請輸入本機監聽端口 (如 3306):" listen_port + if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then + echo "端口必須是數字"; return 1 + fi + + echo "請選擇協議類型:" + echo "1. TCP 2. UDP" + read -rp "請輸入序號 [1-2]:" proto_choice + + case "$proto_choice" in + 1) proto="tcp"; listen_suffix="" ;; + 2) proto="udp"; listen_suffix=" udp" ;; + *) echo "無效選擇"; return 1 ;; + esac + + read -e -p "請輸入你的一個或者多個後端IP+端口用空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + + nginx_install_status + cd /home && mkdir -p web/stream.d + grep -q '^[[:space:]]*stream[[:space:]]*{' /home/web/nginx.conf || echo -e '\nstream {\n include /etc/nginx/stream.d/*.conf;\n}' | tee -a /home/web/nginx.conf + wget -O /home/web/stream.d/$proxy_name.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend-stream.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/${proxy_name}_${backend}/g" /home/web/stream.d/"$proxy_name".conf + sed -i "s|listen 80|listen $listen_port $listen_suffix|g" /home/web/stream.d/$proxy_name.conf + sed -i "s|listen \[::\]:|listen [::]:${listen_port} ${listen_suffix}|g" "/home/web/stream.d/${proxy_name}.conf" + + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + + docker exec nginx nginx -s reload + clear + echo "您的$webname搭建好了!" + echo "------------------------" + echo "訪問地址:" + ip_address + if [ -n "$ipv4_address" ]; then + echo "$ipv4_address:${listen_port}" + fi + if [ -n "$ipv6_address" ]; then + echo "$ipv6_address:${listen_port}" + fi + echo "" +} + + + + + find_container_by_host_port() { port="$1" docker_name=$(docker ps --format '{{.ID}} {{.Names}}' | while read id name; do @@ -7847,7 +8042,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo博客網站" echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞生成器${gl_huang}28. ${gl_bai}站點反向代理-負載均衡" - echo -e "${gl_huang}30. ${gl_bai}自定義靜態站點" + echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自定義靜態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站點數據管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠程備份${gl_huang}34. ${gl_bai}還原全站數據" @@ -8427,6 +8622,10 @@ linux_ldnmp() { ;; + 29) + stream_panel + ;; + 30) clear webname="静态站点" @@ -8873,7 +9072,9 @@ while true; do echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" - echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具" + echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" + echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" + echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -10497,7 +10698,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env @@ -10536,7 +10737,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -10653,7 +10854,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12109,7 +12310,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12176,7 +12377,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12205,6 +12406,102 @@ while true; do ;; + 104|nginx-stream) + stream_panel + ;; + + + 105|siyuan) + + local app_id="105" + local docker_name="siyuan" + local docker_img="b3log/siyuan" + local docker_port=8105 + + docker_rum() { + + read -e -p "設置登錄密碼:" app_passwd + + docker run -d \ + --name siyuan \ + --restart=always \ + -v /home/docker/siyuan/workspace:/siyuan/workspace \ + -p ${docker_port}:6806 \ + -e PUID=1001 \ + -e PGID=1002 \ + b3log/siyuan \ + --workspace=/siyuan/workspace/ \ + --accessAuthCode="${app_passwd}" + + } + + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 106|drawnix) + + local app_id="106" + local docker_name="drawnix" + local docker_img="pubuzhixing/drawnix" + local docker_port=8106 + + docker_rum() { + + docker run -d \ + --restart=always \ + --name drawnix \ + -p ${docker_port}:80 \ + pubuzhixing/drawnix + + } + + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 107|pansou) + + local app_id="107" + local docker_name="pansou" + local docker_img="ghcr.io/fish2018/pansou-web" + local docker_port=8107 + + docker_rum() { + + docker run -d \ + --name pansou \ + --restart=always \ + -p ${docker_port}:80 \ + -v /home/docker/pansou/data:/app/data \ + -v /home/docker/pansou/logs:/app/logs \ + -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + ghcr.io/fish2018/pansou-web + + } + + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -14324,6 +14621,7 @@ echo "LDNMP緩存清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載均衡 k loadbalance |k 負載均衡" +echo "安裝L4負載均衡 k stream |k L4負載均衡" echo "防火牆面板 k fhq |k 防火牆" echo "開放端口 k dkdk 8080 |k 打開端口 8080" echo "關閉端口 k gbdk 7800 |k 關閉端口 7800" @@ -14414,6 +14712,11 @@ else ldnmp_Proxy_backend ;; + + stream|L4负载均衡) + ldnmp_Proxy_backend_stream + ;; + swap) shift send_stats "快速設置虛擬內存" From 7184d257e8616c2af2d61c4c19877284430375cf Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 26 Oct 2025 03:32:11 +0000 Subject: [PATCH 0303/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-10-26=2003:32:11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 98 ++++++++++++++++++++-------------------- jp/kejilion.sh | 118 ++++++++++++++++++++++++------------------------- kr/kejilion.sh | 102 +++++++++++++++++++++--------------------- 3 files changed, 159 insertions(+), 159 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 767701c6f..333c368f2 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -915,7 +915,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2543,7 +2543,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2562,7 +2562,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2803,7 +2803,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3454,7 +3454,7 @@ ldnmp_Proxy_backend_stream() { # Get agent name read -rp "Please enter a proxy forwarding name (e.g. mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then - echo "Name cannot be empty"; return 1 + echo "name cannot be empty"; return 1 fi # Get listening port @@ -4100,7 +4100,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4197,7 +4197,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -4697,14 +4697,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -4972,7 +4972,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5506,7 +5506,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5585,7 +5585,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -5848,9 +5848,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -5892,7 +5892,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6035,7 +6035,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6313,7 +6313,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6383,7 +6383,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7306,7 +7306,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7673,7 +7673,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9460,7 +9460,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -9514,7 +9514,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -9612,7 +9612,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10497,7 +10497,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10719,7 +10719,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10770,7 +10770,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10811,7 +10811,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10874,7 +10874,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11202,7 +11202,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11423,7 +11423,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11473,7 +11473,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11608,7 +11608,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11835,7 +11835,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11973,7 +11973,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12027,7 +12027,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12260,7 +12260,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12330,7 +12330,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12399,7 +12399,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12549,7 +12549,7 @@ while true; do r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12609,7 +12609,7 @@ linux_work() { echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" - echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" + echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" @@ -12782,7 +12782,7 @@ linux_Settings() { while true; do clear - # send_stats "System Tools" + # send_stats "system tools" echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" @@ -12853,7 +12853,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13045,8 +13045,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -13584,7 +13584,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -14137,7 +14137,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Copying file or directory failed: File or directory does not exist" + send_stats "Failed to copy file or directory: File or directory does not exist" continue fi @@ -14248,7 +14248,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14282,7 +14282,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14584,7 +14584,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a9559b67b..f75fad562 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -59,7 +59,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -116,7 +116,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -r -p "上記の条件に同意しますか? (y/n):" user_input @@ -955,12 +955,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1130,7 +1130,7 @@ iptables_panel() { echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" - echo "15. 指定した国の IP をブロックする 16. 指定した国の IP のみを許可する" + echo "15. 指定した国の IP をブロック 16. 指定した国の IP のみを許可" echo "17. 指定国における知的財産制限を解除する" echo "------------------------" echo "0. 前のメニューに戻る" @@ -1526,7 +1526,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -1663,7 +1663,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2114,10 +2114,10 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2442,7 +2442,7 @@ check_docker_image_update() { # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIからイメージのリリース時間を取得する + # Docker Hub APIからイメージのリリース時刻を取得する local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) @@ -3330,13 +3330,13 @@ list_stream_services() { fi for conf in "$STREAM_DIR"/*; do - # サービス名がファイル名になります + # サービス名はファイル名を取得します service_name=$(basename "$conf" .conf) # 上流ブロックでサーバーのバックエンド IP:ポートを取得します。 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) - # リッスンポートの取得 + # リッスンポートを取得する listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) # デフォルトのローカルIP @@ -3420,7 +3420,7 @@ stream_panel() { send_stats "レイヤ 4 プロキシを追加する" ;; 5) - send_stats "転送設定を編集する" + send_stats "転送設定の編集" read -e -p "編集するサービス名を入力してください:" stream_name install nano nano /home/web/stream.d/$stream_name.conf @@ -3671,7 +3671,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4018,7 +4018,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4586,7 +4586,7 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 見つかった場合は、PasswordAuthentication が Yes に設定されます + # 見つかった場合、PasswordAuthentication は Yes に設定されます if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -4697,14 +4697,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには、root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -5298,7 +5298,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5550,7 +5550,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" + send_stats "Linux カーネルのチューニング管理" echo "Linuxシステムのカーネルパラメータの最適化" echo "ビデオ紹介: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -5558,7 +5558,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -5585,7 +5585,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -5675,7 +5675,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -5848,9 +5848,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -5892,7 +5892,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6180,9 +6180,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントする +# パーティションのマウント mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6201,7 +6201,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6313,7 +6313,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7097,7 +7097,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" + echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7192,7 +7192,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" @@ -7299,14 +7299,14 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8222,7 +8222,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8665,7 +8665,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/ のような)index.html へのパスを入力してください。$yuming/index/): " index_lujing + read -e -p "(/home/web/html/ のような、index.html へのパスを入力してください)$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -8703,7 +8703,7 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "エラー: リモート サーバーの IP を入力してください。" @@ -8927,7 +8927,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境の完全アップデート" + send_stats "LDNMP環境の完全なアップデート" cd /home/web/ docker compose down --rmi all @@ -9285,7 +9285,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -12159,7 +12159,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -12519,7 +12519,7 @@ while true; do case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -12549,7 +12549,7 @@ while true; do r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリケーションのバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12597,7 +12597,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -12609,7 +12609,7 @@ linux_work() { echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" - echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" + echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo.7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" @@ -12782,12 +12782,12 @@ linux_Settings() { while true; do clear - # send_stats 「システムツール」 + # send_stats「システムツール」 echo -e "システムツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -13045,8 +13045,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -13584,7 +13584,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -13688,7 +13688,7 @@ EOF 25) root_use - send_stats "電報警報" + send_stats "電報警告" echo "TG-bot監視・早期警告機能" echo "動画紹介:https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" @@ -14248,7 +14248,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14277,12 +14277,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14322,7 +14322,7 @@ while true; do 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14584,13 +14584,13 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" @@ -14600,7 +14600,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -14623,7 +14623,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -14818,7 +14818,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index aea2c98cd..110dc751e 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1124,7 +1124,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1347,7 +1347,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 교체 + # docker-compose.yml 파일에서 바꾸기 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1531,7 +1531,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." break_end clear echo "다시 배포해 보세요.$webname" @@ -2115,7 +2115,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2381,7 +2381,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2543,7 +2543,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2562,7 +2562,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2659,7 +2659,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2675,7 +2675,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3191,7 +3191,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3350,7 +3350,7 @@ list_stream_services() { proto="tcp" fi - # 스플라이스 청취 IP:포트 + # 접속 수신 IP:포트 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -4123,7 +4123,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5250,7 +5250,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5286,7 +5286,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5585,7 +5585,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -5792,7 +5792,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6031,11 +6031,11 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6313,7 +6313,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6379,11 +6379,11 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7065,7 +7065,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -7220,7 +7220,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리용기:$container${NC}" + echo -e "${GREEN}처리 용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7306,7 +7306,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7493,7 +7493,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7539,7 +7539,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8221,7 +8221,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9053,7 +9053,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9766,7 +9766,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -12549,7 +12549,7 @@ while true; do r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12609,7 +12609,7 @@ linux_work() { echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" + echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 7호" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" @@ -12709,7 +12709,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -12786,7 +12786,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -12799,7 +12799,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13045,8 +13045,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -13279,7 +13279,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -13584,7 +13584,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -13830,7 +13830,7 @@ EOF echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니다." + echo -e "5. 모든 포트를 엽니다" echo -e "6. 켜기${gl_huang}BBR${gl_bai}가속하다" echo -e "7. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" echo -e "8. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" @@ -13952,7 +13952,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." + send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" ;; *) break @@ -14137,7 +14137,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -14148,7 +14148,7 @@ linux_file() { continue fi - # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -14248,7 +14248,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14282,7 +14282,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시문" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14324,7 +14324,7 @@ while true; do clear send_stats "클러스터 복원" echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "귀하의${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -14396,7 +14396,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -14584,12 +14584,12 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -14623,12 +14623,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "시스템 정보 표시 k 정보" } From 6e48a45a6f9a8fcf0ced096d8bc48c7ca8efaf9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:52:18 +0800 Subject: [PATCH 0304/1285] Update kejilion.sh --- cn/kejilion.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 111b30b72..acec28ea7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2247,9 +2247,11 @@ web_optimization() { 1) send_stats "站点标准模式" - # nginx调优 - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2290,10 @@ web_optimization() { send_stats "站点高性能模式" # nginx调优 - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini From b57639f8e82edf99a4f9739283cb83de1917e8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:52:56 +0800 Subject: [PATCH 0305/1285] Update kejilion.sh --- kejilion.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f21db5585..bda83096c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2247,9 +2247,11 @@ web_optimization() { 1) send_stats "站点标准模式" - # nginx调优 - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2290,10 @@ web_optimization() { send_stats "站点高性能模式" # nginx调优 - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini From 7fbf4971a978571c5799c9456d1fdba7f02dbf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:54:25 +0800 Subject: [PATCH 0306/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 61e1e6a00..ef551e354 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1331,5 +1331,6 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 应用市场新增了思源笔记的安装及使用。 应用市场新增了开源Drawnix白板工具的安装及使用。 应用市场新增了PanSou网盘搜索工具的安装及使用。 +优化LDNMP环境中nginx将根据核心数优化并发连接数。 ------------------------ From dc533423d68a1d0664a348f26d8b0c084827c228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:26:27 +0800 Subject: [PATCH 0307/1285] Update kejilion.sh --- cn/kejilion.sh | 97 +++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index acec28ea7..cd698506a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -1379,9 +1384,46 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # 获取国家代码(如 CN、US 等) + local country=$(curl -s ipinfo.io/country) + + # 根据国家设置 DNS + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # 调用设置 DNS 的函数(需你定义) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + # 打印结果 + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "已切换为 IPv4 优先" +send_stats "已切换为 IPv4 优先" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -13042,10 +13084,7 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf @@ -13875,21 +13914,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + auto_optimize_dns echo "------------------------------------------------" install_docker From b553a23276c81d0bcad0eca26f45216577458250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:27:40 +0800 Subject: [PATCH 0308/1285] Update kejilion.sh --- kejilion.sh | 97 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index bda83096c..a41c72dfb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -1379,9 +1384,46 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # 获取国家代码(如 CN、US 等) + local country=$(curl -s ipinfo.io/country) + + # 根据国家设置 DNS + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # 调用设置 DNS 的函数(需你定义) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + # 打印结果 + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "已切换为 IPv4 优先" +send_stats "已切换为 IPv4 优先" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -13042,10 +13084,7 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "已切换为 IPv4 优先" - send_stats "已切换为 IPv4 优先" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf @@ -13875,21 +13914,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + auto_optimize_dns echo "------------------------------------------------" install_docker From daca6a54edb99172eff88becedb8c769b717efa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:30:16 +0800 Subject: [PATCH 0309/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ef551e354..af7d3f079 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1333,4 +1333,8 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 应用市场新增了PanSou网盘搜索工具的安装及使用。 优化LDNMP环境中nginx将根据核心数优化并发连接数。 ------------------------ +2025-10-21 v4.2.0 +安装LDNMP/NGINX建站环境是检测网络进行dns优化IP优先调整,解决因网络问题无法安装环境的问题。 +国内安装docker环境时的加速站列表进行更新。 +------------------------ From af6e97ff4032fd5a226578a64db3f99958a44f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:30:46 +0800 Subject: [PATCH 0310/1285] Update version number to v4.2.1 in log file Updated version number from v4.2.0 to v4.2.1 and made minor log adjustments. --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index af7d3f079..f7f72d38b 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1333,7 +1333,7 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 应用市场新增了PanSou网盘搜索工具的安装及使用。 优化LDNMP环境中nginx将根据核心数优化并发连接数。 ------------------------ -2025-10-21 v4.2.0 +2025-10-30 v4.2.1 安装LDNMP/NGINX建站环境是检测网络进行dns优化IP优先调整,解决因网络问题无法安装环境的问题。 国内安装docker环境时的加速站列表进行更新。 ------------------------ From 36aec52deaa11e34d8098c482004d533fb65d64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 13:28:23 +0800 Subject: [PATCH 0311/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cd698506a..adc72b8e0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1407,8 +1407,7 @@ auto_optimize_dns() { # 调用设置 DNS 的函数(需你定义) set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" - # 打印结果 - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + } @@ -13915,6 +13914,7 @@ EOF echo "------------------------------------------------" auto_optimize_dns + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker From bdbef892e58db06b21663b6c92c6e3e63aaba95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Oct 2025 13:29:01 +0800 Subject: [PATCH 0312/1285] Remove duplicate DNS optimization echo statement Removed duplicate echo statement for DNS optimization. --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a41c72dfb..a511facc4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1407,8 +1407,7 @@ auto_optimize_dns() { # 调用设置 DNS 的函数(需你定义) set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" - # 打印结果 - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + } @@ -13915,6 +13914,7 @@ EOF echo "------------------------------------------------" auto_optimize_dns + echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" install_docker From efc6c05f185339500d6ba7597fd44eaa6c5e5ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:04:25 +0800 Subject: [PATCH 0313/1285] Update ENABLED_PLUGINS in kejilion.sh --- cn/kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index adc72b8e0..5f927dc95 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12532,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } From b2ee2b359143915d9696b23cba602c8c416f1036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:05:00 +0800 Subject: [PATCH 0314/1285] Update ENABLED_PLUGINS environment variable --- kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index a511facc4..3389d8b33 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12532,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } From 8f73d224eda5e24cdaefdafe9044d1451874fd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:06:14 +0800 Subject: [PATCH 0315/1285] Update PanSou cloud disk search sources Added more search sources for PanSou cloud disk in the application market. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f7f72d38b..8e140e3a5 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1336,5 +1336,6 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 2025-10-30 v4.2.1 安装LDNMP/NGINX建站环境是检测网络进行dns优化IP优先调整,解决因网络问题无法安装环境的问题。 国内安装docker环境时的加速站列表进行更新。 +应用市场中PanSou网盘搜索增加更多搜索源。 ------------------------ From 954984b56d8c02330f42ea80d77bf4f3e4f5bbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:43:51 +0800 Subject: [PATCH 0316/1285] Add WP_REDIS_MAXTTL to wp-config-sample.php --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5f927dc95..4d821d9d0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3275,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400);" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php From a4da9d25e9decc3a67e64b8e7c54b920488afc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:44:56 +0800 Subject: [PATCH 0317/1285] Add WP_REDIS_MAXTTL to wp-config-sample.php --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 3389d8b33..bb6c7122a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3275,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400);" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php From c01225afff366fa2b2ef5101890d22b34d20f8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:54:31 +0800 Subject: [PATCH 0318/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index bb6c7122a..7bc22f7fe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3275,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400);" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php From 2fe6558a279e4763ea02103d6bdab92cd378ff56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:56:56 +0800 Subject: [PATCH 0319/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4d821d9d0..6e133f36b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3275,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400);" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php From 7a4cfd2437cc980239d22acc1c4003ae8c23948a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 2 Nov 2025 04:09:42 +0000 Subject: [PATCH 0320/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-02=2004:09:42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 210 ++++++++++++++++++++++----------------- jp/kejilion.sh | 262 ++++++++++++++++++++++++++++--------------------- kr/kejilion.sh | 234 ++++++++++++++++++++++++------------------- tw/kejilion.sh | 118 ++++++++++++++-------- 4 files changed, 480 insertions(+), 344 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 333c368f2..672e1795c 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -915,7 +920,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1379,9 +1384,45 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # Get the country code (such as CN, US, etc.) + local country=$(curl -s ipinfo.io/country) + + # Set DNS based on country + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # Call the function that sets DNS (needs to be defined by you) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "Switched to IPv4 priority" +send_stats "Switched to IPv4 priority" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -2247,9 +2288,11 @@ web_optimization() { 1) send_stats "site standards mode" - # nginx tuning - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # php tuning wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2331,10 @@ web_optimization() { send_stats "Site high performance mode" # nginx tuning - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # php tuning wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2543,7 +2588,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2562,7 +2607,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2803,7 +2848,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3230,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3454,7 +3499,7 @@ ldnmp_Proxy_backend_stream() { # Get agent name read -rp "Please enter a proxy forwarding name (e.g. mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then - echo "name cannot be empty"; return 1 + echo "Name cannot be empty"; return 1 fi # Get listening port @@ -4100,7 +4145,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4197,7 +4242,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -4972,7 +5017,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5585,7 +5630,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -5848,9 +5893,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -5892,7 +5937,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6035,7 +6080,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6383,7 +6428,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7145,7 +7190,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -7306,7 +7351,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7673,7 +7718,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9460,7 +9505,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -9514,7 +9559,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -9612,7 +9657,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10497,7 +10542,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10719,7 +10764,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10770,7 +10815,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10811,7 +10856,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10874,7 +10919,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11202,7 +11247,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11423,7 +11468,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11473,7 +11518,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11608,7 +11653,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11835,7 +11880,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11973,7 +12018,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12027,7 +12072,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12260,7 +12305,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12330,7 +12375,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12399,7 +12444,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12487,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } @@ -12549,7 +12599,7 @@ while true; do r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12607,9 +12657,9 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" - echo -e "${gl_kjlan}7. ${gl_bai}Workspace No. 7" + echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" @@ -12782,7 +12832,7 @@ linux_Settings() { while true; do clear - # send_stats "system tools" + # send_stats "System Tools" echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" @@ -13038,15 +13088,12 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "Switched to IPv4 priority" - send_stats "Switched to IPv4 priority" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + send_stats "Switched to IPv6 priority" ;; 3) @@ -13584,7 +13631,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -13871,20 +13918,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set time zone to${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns + auto_optimize_dns echo -e "[${gl_lv}OK${gl_bai}] 8/10. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" @@ -14137,7 +14171,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Failed to copy file or directory: File or directory does not exist" + send_stats "Copying file or directory failed: File or directory does not exist" continue fi @@ -14248,7 +14282,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14282,7 +14316,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14399,7 +14433,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14584,7 +14618,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index f75fad562..46d03be9b 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -245,7 +250,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストール中$package...${gl_bai}" + echo -e "${gl_huang}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -897,7 +902,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -1130,7 +1135,7 @@ iptables_panel() { echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" - echo "15. 指定した国の IP をブロック 16. 指定した国の IP のみを許可" + echo "15. 指定した国の IP をブロックする 16. 指定した国の IP のみを許可する" echo "17. 指定国における知的財産制限を解除する" echo "------------------------" echo "0. 前のメニューに戻る" @@ -1379,9 +1384,45 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # 国コードを取得します (CN、US など)。 + local country=$(curl -s ipinfo.io/country) + + # 国に基づいてDNSを設定する + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # DNS を設定する関数を呼び出します (ユーザーが定義する必要があります) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "IPv4優先に切り替えました" +send_stats "IPv4優先に切り替えました" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -1663,7 +1704,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1868,7 +1909,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1999,7 +2040,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2118,7 +2159,7 @@ web_security() { echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2234,7 +2275,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2247,9 +2288,11 @@ web_optimization() { 1) send_stats "サイト標準モード" - # nginxのチューニング - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # PHPのチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2331,10 @@ web_optimization() { send_stats "サイトハイパフォーマンスモード" # nginxのチューニング - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # PHPのチューニング wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2490,7 +2535,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2507,7 +2552,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2762,7 +2807,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3230,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3336,7 +3381,7 @@ list_stream_services() { # 上流ブロックでサーバーのバックエンド IP:ポートを取得します。 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) - # リッスンポートを取得する + # リッスンポートの取得 listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) # デフォルトのローカルIP @@ -3417,7 +3462,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "レイヤ 4 プロキシを追加する" + send_stats "レイヤー 4 プロキシを追加する" ;; 5) send_stats "転送設定の編集" @@ -4018,7 +4063,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4586,7 +4631,7 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 見つかった場合、PasswordAuthentication は Yes に設定されます + # 見つかった場合は、PasswordAuthentication が Yes に設定されます if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" @@ -5250,7 +5295,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5298,7 +5343,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5550,7 +5595,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" echo "Linuxシステムのカーネルパラメータの最適化" echo "ビデオ紹介: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -5558,7 +5603,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -5585,7 +5630,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -5848,9 +5893,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -5892,7 +5937,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6313,7 +6358,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6361,7 +6406,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -6529,7 +6574,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6731,7 +6776,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -6803,7 +6848,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7097,7 +7142,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7107,7 +7152,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7118,7 +7163,7 @@ docker_ssh_migration() { echo "# docker-compose 復元:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトの作成 [$project_name]パッケージ化:${project_dir}${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name] パッケージ内容:${project_dir}${NC}" else echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" fi @@ -7192,7 +7237,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" @@ -7274,7 +7319,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7299,14 +7344,14 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7424,7 +7469,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -7523,7 +7568,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -7857,7 +7902,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8703,7 +8748,7 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "エラー: リモート サーバーの IP を入力してください。" @@ -8927,7 +8972,7 @@ linux_ldnmp() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP環境の完全なアップデート" + send_stats "LDNMP環境の完全アップデート" cd /home/web/ docker compose down --rmi all @@ -9013,7 +9058,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9051,7 +9096,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -9061,7 +9106,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" @@ -9276,7 +9321,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザ監視$check_docker $update_status" + echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -12159,7 +12204,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -12487,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } @@ -12519,7 +12569,7 @@ while true; do case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -12549,7 +12599,7 @@ while true; do r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリのバックアップ" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12597,7 +12647,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -12607,9 +12657,9 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" - echo -e "${gl_kjlan}7. ${gl_bai}ワークスペースNo.7" + echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" @@ -12782,12 +12832,12 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 + # send_stats 「システムツール」 echo -e "システムツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -12858,7 +12908,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -13038,10 +13088,7 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "IPv4優先に切り替えました" - send_stats "IPv4優先に切り替えました" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf @@ -13259,7 +13306,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13584,7 +13631,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -13688,7 +13735,7 @@ EOF 25) root_use - send_stats "電報警告" + send_stats "電報警報" echo "TG-bot監視・早期警告機能" echo "動画紹介:https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" @@ -13871,20 +13918,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}】7/10。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns + auto_optimize_dns echo -e "[${gl_lv}OK${gl_bai}】8/10。 DNSアドレスを自動的に最適化する${gl_huang}${gl_bai}" echo "------------------------------------------------" @@ -13928,7 +13962,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14121,7 +14155,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14248,7 +14282,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14277,12 +14311,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14322,7 +14356,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14399,7 +14433,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14456,7 +14490,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" + echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -14548,7 +14582,7 @@ echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu サーバー開始スクリプ echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -14590,8 +14624,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -14619,7 +14653,7 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" @@ -14719,7 +14753,7 @@ else swap) shift - send_stats "仮想メモリを素早く設定する" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; @@ -14818,7 +14852,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 110dc751e..ae41b45fb 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -1124,7 +1129,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1347,7 +1352,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 바꾸기 + # docker-compose.yml 파일에서 교체 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1379,9 +1384,45 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # 국가 코드(예: CN, US 등)를 가져옵니다. + local country=$(curl -s ipinfo.io/country) + + # 국가에 따라 DNS 설정 + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # DNS를 설정하는 함수 호출(사용자가 정의해야 함) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "IPv4 우선순위로 전환됨" +send_stats "IPv4 우선순위로 전환됨" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -1531,7 +1572,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." break_end clear echo "다시 배포해 보세요.$webname" @@ -2247,9 +2288,11 @@ web_optimization() { 1) send_stats "사이트 표준 모드" - # nginx 튜닝 - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2331,10 @@ web_optimization() { send_stats "사이트 고성능 모드" # nginx 튜닝 - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2381,7 +2426,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2446,7 +2491,7 @@ check_docker_image_update() { local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득한 시간을 확인 + # 획득한 시간을 확인하세요. if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) @@ -2543,7 +2588,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2562,7 +2607,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2659,7 +2704,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2762,7 +2807,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2875,7 +2920,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3188,16 +3233,16 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } nginx_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" } @@ -3230,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -3350,7 +3395,7 @@ list_stream_services() { proto="tcp" fi - # 접속 수신 IP:포트 + # 스플라이스 청취 IP:포트 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -3494,7 +3539,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -3814,7 +3859,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -3876,7 +3921,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4123,7 +4168,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5079,7 +5124,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5089,7 +5134,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5143,7 +5188,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5232,7 +5277,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5250,7 +5295,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5585,7 +5630,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6031,11 +6076,11 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6313,7 +6358,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6379,11 +6424,11 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7065,7 +7110,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7204,7 +7249,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7306,7 +7351,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7493,7 +7538,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7539,7 +7584,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9013,7 +9058,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9276,7 +9321,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9388,7 +9433,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -9766,7 +9811,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -12487,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } @@ -12549,7 +12599,7 @@ while true; do r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -12607,9 +12657,9 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 공간 7호" + echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" @@ -12709,7 +12759,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -12786,10 +12836,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13038,10 +13088,7 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "IPv4 우선순위로 전환됨" - send_stats "IPv4 우선순위로 전환됨" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf @@ -13279,7 +13326,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -13584,7 +13631,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -13830,7 +13877,7 @@ EOF echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니다" + echo -e "5. 모든 포트를 엽니다." echo -e "6. 켜기${gl_huang}BBR${gl_bai}가속하다" echo -e "7. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" echo -e "8. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" @@ -13871,20 +13918,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns + auto_optimize_dns echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소 자동 최적화${gl_huang}${gl_bai}" echo "------------------------------------------------" @@ -13952,7 +13986,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." ;; *) break @@ -14137,7 +14171,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -14148,7 +14182,7 @@ linux_file() { continue fi - # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -14248,7 +14282,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14282,7 +14316,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시문" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14324,7 +14358,7 @@ while true; do clear send_stats "클러스터 복원" echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" - echo -e "귀하의${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -14396,10 +14430,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14589,7 +14623,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -14618,12 +14652,12 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index ded2d8c10..1e86fa2ba 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.0" +sh_v="4.2.1" gl_hui='\e[37m' @@ -236,6 +236,11 @@ check_disk_space() { install_dependency() { install wget unzip tar jq grep + + check_swap + auto_optimize_dns + prefer_ipv4 + } remove() { @@ -381,23 +386,23 @@ if [ "$country" = "CN" ]; then cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ - "https://docker-0.unsee.tech", - "https://docker.1panel.live", - "https://registry.dockermirror.com", - "https://docker.imgdb.de", - "https://docker.m.daocloud.io", - "https://hub.firefly.store", - "https://hub.littlediary.cn", + "https://docker.1ms.run", + "https://docker.m.ixdev.cn", "https://hub.rat.dev", - "https://dhub.kubesre.xyz", - "https://cjie.eu.org", - "https://docker.1panelproxy.com", + "https://dockerproxy.net", + "https://docker-registry.nmqu.com", + "https://docker.amingg.com", "https://docker.hlmirror.com", - "https://hub.fast360.xyz", - "https://dockerpull.cn", - "https://cr.laoyou.ip-ddns.com", - "https://docker.melikeme.cn", - "https://docker.kejilion.pro" + "https://hub1.nat.tf", + "https://hub2.nat.tf", + "https://hub3.nat.tf", + "https://docker.m.daocloud.io", + "https://docker.kejilion.pro", + "https://docker.367231.xyz", + "https://hub.1panel.dev", + "https://dockerproxy.cool", + "https://docker.apiba.cn", + "https://proxy.vvvv.ee" ] } EOF @@ -1379,9 +1384,45 @@ update_docker_compose_with_db_creds() { } + + + +auto_optimize_dns() { + # 獲取國家代碼(如 CN、US 等) + local country=$(curl -s ipinfo.io/country) + + # 根據國家設置 DNS + if [ "$country" = "CN" ]; then + local dns1_ipv4="223.5.5.5" + local dns2_ipv4="183.60.83.19" + local dns1_ipv6="2400:3200::1" + local dns2_ipv6="2400:da00::6666" + else + local dns1_ipv4="1.1.1.1" + local dns2_ipv4="8.8.8.8" + local dns1_ipv6="2606:4700:4700::1111" + local dns2_ipv6="2001:4860:4860::8888" + fi + + # 調用設置 DNS 的函數(需你定義) + set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + + +} + + +prefer_ipv4() { +grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ + || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf +echo "已切換為 IPv4 優先" +send_stats "已切換為 IPv4 優先" +} + + + + install_ldnmp() { - check_swap update_docker_compose_with_db_creds cd /home/web && docker compose up -d @@ -2247,9 +2288,11 @@ web_optimization() { 1) send_stats "站點標準模式" - # nginx調優 - sed -i 's/worker_connections.*/worker_connections 10240;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 4;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((1024 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + # php調優 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -2288,8 +2331,10 @@ web_optimization() { send_stats "站點高性能模式" # nginx調優 - sed -i 's/worker_connections.*/worker_connections 20480;/' /home/web/nginx.conf - sed -i 's/worker_processes.*/worker_processes 8;/' /home/web/nginx.conf + local cpu_cores=$(nproc) + local connections=$((2048 * ${cpu_cores})) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf # php調優 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini @@ -3230,7 +3275,7 @@ ldnmp_wp() { wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip rm latest.zip - echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php + echo "define('FS_METHOD', 'direct'); define('WP_REDIS_HOST', 'redis'); define('WP_REDIS_PORT', '6379'); define('WP_REDIS_MAXTTL', 86400); define('WP_CACHE_KEY_SALT', '${yuming}_');" >> /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|database_name_here|$dbname|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php @@ -12487,7 +12532,12 @@ while true; do -p ${docker_port}:80 \ -v /home/docker/pansou/data:/app/data \ -v /home/docker/pansou/logs:/app/logs \ - -e ENABLED_PLUGINS="labi,zhizhen,shandian,duoduo,muou,wanou" \ + -e ENABLED_PLUGINS="hunhepan,jikepan,panwiki,pansearch,panta,qupansou, +susu,thepiratebay,wanou,xuexizhinan,panyq,zhizhen,labi,muou,ouge,shandian, +duoduo,huban,cyg,erxiao,miaoso,fox4k,pianku,clmao,wuji,cldi,xiaozhang, +libvio,leijing,xb6v,xys,ddys,hdmoli,yuhuage,u3c3,javdb,clxiong,jutoushe, +sdso,xiaoji,xdyh,haisou,bixin,djgou,nyaa,xinjuc,aikanzy,qupanshe,xdpan, +discourse,yunsou,ahhhhfs,nsgame,gying" \ ghcr.io/fish2018/pansou-web } @@ -13038,10 +13088,7 @@ EOF case $choice in 1) - grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ - || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf - echo "已切換為 IPv4 優先" - send_stats "已切換為 IPv4 優先" + prefer_ipv4 ;; 2) rm -f /etc/gai.conf @@ -13871,20 +13918,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 7/10. 設置時區到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - local country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then - local dns1_ipv4="223.5.5.5" - local dns2_ipv4="183.60.83.19" - local dns1_ipv6="2400:3200::1" - local dns2_ipv6="2400:da00::6666" - else - local dns1_ipv4="1.1.1.1" - local dns2_ipv4="8.8.8.8" - local dns1_ipv6="2606:4700:4700::1111" - local dns2_ipv6="2001:4860:4860::8888" - fi - - set_dns + auto_optimize_dns echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自動優化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" From 15b3b95be2e62bc504393b179ed0776782e11296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:34:57 +0800 Subject: [PATCH 0321/1285] Update optimized_php.ini --- optimized_php.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/optimized_php.ini b/optimized_php.ini index e1a3531da..2fe0d64bb 100644 --- a/optimized_php.ini +++ b/optimized_php.ini @@ -13,6 +13,7 @@ session.cookie_secure = 1 session.use_strict_mode = 1 session.use_only_cookies = 1 + ; Opcache配置 opcache.enable=1 opcache.enable_cli=1 @@ -25,9 +26,11 @@ opcache.fast_shutdown=1 opcache.save_comments=1 opcache.file_update_protection=0 opcache.max_wasted_percentage=5 -opcache.jit=tracing +# opcache.jit=tracing +opcache.jit = 0 opcache.jit_buffer_size=64M + ; Realpath Cache配置 realpath_cache_size=4096k realpath_cache_ttl=3600 From 945967b6ac2aa7b82b13e45f16d3e71d65fbcc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:35:26 +0800 Subject: [PATCH 0322/1285] Comment out opcache.jit setting in optimized_php.ini --- optimized_php.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optimized_php.ini b/optimized_php.ini index 2fe0d64bb..547435a45 100644 --- a/optimized_php.ini +++ b/optimized_php.ini @@ -26,7 +26,7 @@ opcache.fast_shutdown=1 opcache.save_comments=1 opcache.file_update_protection=0 opcache.max_wasted_percentage=5 -# opcache.jit=tracing +; opcache.jit=tracing opcache.jit = 0 opcache.jit_buffer_size=64M From f7ad2ac89af987ec6c28075d7c188ff0b42f4072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:36:01 +0800 Subject: [PATCH 0323/1285] Update optimized_php.ini --- optimized_php.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/optimized_php.ini b/optimized_php.ini index 547435a45..5b0f525fd 100644 --- a/optimized_php.ini +++ b/optimized_php.ini @@ -27,8 +27,9 @@ opcache.save_comments=1 opcache.file_update_protection=0 opcache.max_wasted_percentage=5 ; opcache.jit=tracing +; opcache.jit_buffer_size=64M opcache.jit = 0 -opcache.jit_buffer_size=64M + ; Realpath Cache配置 From 11c90d804ac56889297535947813be430611dedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:42:23 +0800 Subject: [PATCH 0324/1285] Update optimized_php.ini --- optimized_php.ini | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/optimized_php.ini b/optimized_php.ini index 5b0f525fd..0f25b5b89 100644 --- a/optimized_php.ini +++ b/optimized_php.ini @@ -26,10 +26,8 @@ opcache.fast_shutdown=1 opcache.save_comments=1 opcache.file_update_protection=0 opcache.max_wasted_percentage=5 -; opcache.jit=tracing -; opcache.jit_buffer_size=64M -opcache.jit = 0 - +opcache.jit=tracing +opcache.jit_buffer_size=64M ; Realpath Cache配置 From ac439a9a343a3b53310bb32c3f0af9d590667aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:51:53 +0800 Subject: [PATCH 0325/1285] Update www.conf --- www.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www.conf b/www.conf index bd04bc093..06cea267f 100644 --- a/www.conf +++ b/www.conf @@ -484,7 +484,7 @@ request_terminate_timeout = 1600 ; Default Value: nothing is defined by default except the values in php.ini and ; specified at startup with the -d argument ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com -php_flag[display_errors] = off +php_flag[display_errors] = on php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on ;php_admin_value[memory_limit] = 32M From 8c87e97bd451d2c0fe0a6947a962eb5c7d41ae02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:58:13 +0800 Subject: [PATCH 0326/1285] Update www.conf --- www.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www.conf b/www.conf index 06cea267f..bd04bc093 100644 --- a/www.conf +++ b/www.conf @@ -484,7 +484,7 @@ request_terminate_timeout = 1600 ; Default Value: nothing is defined by default except the values in php.ini and ; specified at startup with the -d argument ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com -php_flag[display_errors] = on +php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on ;php_admin_value[memory_limit] = 32M From 6556f180781415c673933e720ec0226ffd88e6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:09:27 +0800 Subject: [PATCH 0327/1285] Update version and reorder maintenance steps --- cn/kejilion.sh | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6e133f36b..f1a310854 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -13581,7 +13581,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13876,14 @@ EOF echo "2. 清理系统垃圾文件" echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo -e "5. 启动fail2ban防御SSH暴力破解" + echo -e "6. 开放所有端口" + echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" + echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" read -e -p "确定一键保养吗?(Y/N): " choice @@ -13892,44 +13893,52 @@ EOF send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo "------------------------------------------------" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" + echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; From 7aa96dfb7933350cfc4838539edc700215bbafe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:10:01 +0800 Subject: [PATCH 0328/1285] Update version and modify maintenance steps --- kejilion.sh | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7bc22f7fe..6fd626fa0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -13581,7 +13581,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13876,14 @@ EOF echo "2. 清理系统垃圾文件" echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 开放所有端口" - echo -e "6. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "7. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "8. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "9. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo -e "5. 启动fail2ban防御SSH暴力破解" + echo -e "6. 开放所有端口" + echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" + echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" read -e -p "确定一键保养吗?(Y/N): " choice @@ -13892,44 +13893,52 @@ EOF send_stats "一条龙调优启动" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo "------------------------------------------------" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" + echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系统内核参数优化" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; From 2c312d1fec6e71da3e496b2a955ad393f3fedb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:12:58 +0800 Subject: [PATCH 0329/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8e140e3a5..4d65ae7d2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1338,4 +1338,8 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 国内安装docker环境时的加速站列表进行更新。 应用市场中PanSou网盘搜索增加更多搜索源。 ------------------------ +2025-11-06 v4.2.2 +系统工具中一条龙优化功能新增自动ipv4优先, +系统工具中一条龙优化功能新增自动开启fail2ban防御SSH暴力破解。 +------------------------ From 6d5bd98242115895bd4699188d3dc8cd23e38938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:17:52 +0800 Subject: [PATCH 0330/1285] Add LangBot chatbot installation and management scripts --- cn/kejilion.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f1a310854..45bcf2353 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9119,7 +9119,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" - echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12554,6 +12554,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + b) clear send_stats "全部应用备份" From b58dae38b089f34ce4f2d30db5256d0855554110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:18:30 +0800 Subject: [PATCH 0331/1285] Update kejilion.sh --- kejilion.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 6fd626fa0..c91913f45 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9119,7 +9119,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" - echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12554,6 +12554,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + b) clear send_stats "全部应用备份" From 38aecab3fa82d4f10dd2f91859ebf53512609732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:19:56 +0800 Subject: [PATCH 0332/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4d65ae7d2..f3821b5fb 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1341,5 +1341,7 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 2025-11-06 v4.2.2 系统工具中一条龙优化功能新增自动ipv4优先, 系统工具中一条龙优化功能新增自动开启fail2ban防御SSH暴力破解。 +应用市场新增了LangBot开源聊天机器人的安装及使用。 ------------------------ + From 51b0a33966da698519d5639cc5856f8ef3103a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:40:05 +0800 Subject: [PATCH 0333/1285] Update custom_mysql_config-1.cnf --- custom_mysql_config-1.cnf | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/custom_mysql_config-1.cnf b/custom_mysql_config-1.cnf index d3f5a12fa..5261b859f 100644 --- a/custom_mysql_config-1.cnf +++ b/custom_mysql_config-1.cnf @@ -1 +1,44 @@ +[mysqld] + +# 连接和线程管理 +max_connections = 200 # 小机型避免连接风暴 +thread_cache_size = 64 +interactive_timeout = 20 +wait_timeout = 20 + +# InnoDB设置 +innodb_buffer_pool_size = 512M # 2G RAM 中最重要的分配,留足系统空间 +innodb_buffer_pool_instances = 1 # 小内存不需要分片 +innodb_log_buffer_size = 8M +innodb_redo_log_capacity = 64M +innodb_lock_wait_timeout = 30 +innodb_file_per_table = 1 +innodb_flush_log_at_trx_commit = 1 +innodb_io_capacity = 400 # 普通SSD预期值 +innodb_io_capacity_max = 800 + +# 缓存和表限制 +table_open_cache = 512 +open_files_limit = 20000 +tmp_table_size = 32M +max_heap_table_size = 32M +max_allowed_packet = 32M + +# 缓冲区大小 +sort_buffer_size = 2M +read_buffer_size = 512K +join_buffer_size = 1M + +# 日志管理 +log_error_verbosity = 3 +slow_query_log = 1 +slow_query_log_file = /var/log/mysql/slow.log +long_query_time = 1 +log_queries_not_using_indexes = 1 + +# 其他 +sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION +performance_schema=ON +disable-log-bin + From 1d6514e638dffb8cfe44142380f78c645c1448a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:47:42 +0800 Subject: [PATCH 0334/1285] Update kejilion.sh --- cn/kejilion.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 45bcf2353..88fbf68af 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # mysql调优 + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear From c6007c4341695b4372f2423c76905ee0016ff628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:48:43 +0800 Subject: [PATCH 0335/1285] Update kejilion.sh --- kejilion.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index c91913f45..4bb3e9ea6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # mysql调优 + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear From 8dc5bebb0f9f738bdb221ce54966e875651856af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:49:39 +0800 Subject: [PATCH 0336/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f3821b5fb..e734c9510 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1342,6 +1342,7 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 系统工具中一条龙优化功能新增自动ipv4优先, 系统工具中一条龙优化功能新增自动开启fail2ban防御SSH暴力破解。 应用市场新增了LangBot开源聊天机器人的安装及使用。 +LDNMP安装环境时对mysql进行优化。 ------------------------ From 86d98697662ac0813f4181de86311edf98502113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 8 Nov 2025 21:09:06 +0800 Subject: [PATCH 0337/1285] Update optimized_php.ini --- optimized_php.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optimized_php.ini b/optimized_php.ini index 0f25b5b89..dfb2e0a75 100644 --- a/optimized_php.ini +++ b/optimized_php.ini @@ -5,7 +5,7 @@ error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED expose_php = Off allow_url_fopen = Off allow_url_include = Off -disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source +disable_functions = passthru,system,proc_open,popen,parse_ini_file,show_source default_charset = "UTF-8" session.cookie_httponly = 1 From 487e16b948cb2da53840dd448e04890961e8f180 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 9 Nov 2025 03:52:30 +0000 Subject: [PATCH 0338/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-09=2003:52:30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 111 +++++++++++++++++++++++++++++++---------- jp/kejilion.sh | 133 +++++++++++++++++++++++++++++++++++-------------- kr/kejilion.sh | 125 ++++++++++++++++++++++++++++++++++------------ tw/kejilion.sh | 99 ++++++++++++++++++++++++++++-------- 4 files changed, 352 insertions(+), 116 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 672e1795c..d38c47639 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # mysql tuning + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear @@ -4742,7 +4751,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } @@ -5551,7 +5560,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -9058,7 +9067,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -9119,7 +9128,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool${gl_kjlan}104. ${color104}Stream four-layer proxy forwarding tool" echo -e "${gl_kjlan}105. ${color105}Siyuan Notes${gl_kjlan}106. ${color106}Drawnix open source whiteboard tool" - echo -e "${gl_kjlan}107. ${color107}PanSou network disk search" + echo -e "${gl_kjlan}107. ${color107}PanSou network disk search${gl_kjlan}108. ${color108}LangBot chatbot" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" @@ -12554,6 +12563,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "Installation completed" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "App has been uninstalled" + } + + docker_app_plus + + ;; + + + + b) clear send_stats "All application backup" @@ -12903,7 +12953,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13092,7 +13142,7 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" + echo "Switched to IPv6 priority" send_stats "Switched to IPv6 priority" ;; @@ -13581,7 +13631,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13926,14 @@ EOF echo "2. Clean up system junk files" echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" - echo -e "5. Open all ports" - echo -e "6. Turn on${gl_huang}BBR${gl_bai}accelerate" - echo -e "7. Set time zone to${gl_huang}Shanghai${gl_bai}" - echo -e "8. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "9. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" + echo -e "5. Start fail2ban to defend against SSH brute force cracking" + echo -e "6. Open all ports" + echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" + echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" read -e -p "Are you sure you want one-click maintenance? (Y/N):" choice @@ -13892,44 +13943,52 @@ EOF send_stats "One-stop tuning starts" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. Update the system to the latest" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. Update the system to the latest" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. Clean up system junk files" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. Clean up system junk files" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. Set up virtual memory${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. Set up virtual memory${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. Set the SSH port number to${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. Set the SSH port number to${gl_huang}5522${gl_bai}" + echo "------------------------------------------------" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}] 5/12. Start fail2ban to defend against SSH brute force cracking" + echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. Open all ports" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. Open all ports" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. Open${gl_huang}BBR${gl_bai}accelerate" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. Open${gl_huang}BBR${gl_bai}accelerate" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. Set time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. Set time zone to${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. Automatically optimize DNS address${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux system kernel parameter optimization" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux system kernel parameter optimization" echo -e "${gl_lv}One-stop system tuning has been completed${gl_bai}" ;; @@ -14433,7 +14492,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 46d03be9b..4de4a5ef3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -897,7 +897,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done @@ -1225,7 +1225,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # mysqlのチューニング + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear @@ -4742,7 +4751,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } @@ -5343,7 +5352,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5408,7 +5417,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -5720,7 +5729,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6358,7 +6367,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6776,7 +6785,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -7142,7 +7151,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" + echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7425,7 +7434,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -9119,7 +9128,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" - echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索" + echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" @@ -9330,7 +9339,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -12554,6 +12563,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "インストール完了" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "アプリがアンインストールされました" + } + + docker_app_plus + + ;; + + + + b) clear send_stats "すべてのアプリケーションのバックアップ" @@ -13092,8 +13142,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -13581,7 +13631,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13926,14 @@ EOF echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" - echo -e "5.すべてのポートを開きます" - echo -e "6.電源を入れます${gl_huang}BBR${gl_bai}加速する" - echo -e "7. タイムゾーンを次のように設定します。${gl_huang}上海${gl_bai}" - echo -e "8. DNS アドレスを自動的に最適化する${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" - echo -e "9. 基本ツールのインストール${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux システムのカーネル パラメータの最適化が次のように切り替わります。${gl_huang}バランスのとれた最適化モード${gl_bai}" + echo -e "5. SSH ブルート フォース クラッキングを防ぐために、fail2ban を開始します。" + echo -e "6.すべてのポートを開きます" + echo -e "7.電源を入れます${gl_huang}BBR${gl_bai}加速する" + echo -e "8. タイムゾーンを次のように設定します。${gl_huang}上海${gl_bai}" + echo -e "9. DNS アドレスを自動的に最適化する${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" + echo -e "10. ネットワークを次のように設定します。${gl_huang}IPv4優先度${gl_bai}" + echo -e "11. 基本ツールのインストール${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux システムのカーネル パラメータの最適化は、${gl_huang}バランスのとれた最適化モード${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスを実行してもよろしいですか? (はい/いいえ):" choice @@ -13892,44 +13943,52 @@ EOF send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}】1/10。システムを最新のものにアップデートする" + echo -e "[${gl_lv}OK${gl_bai}】1/12。システムを最新のものにアップデートする" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}】2/10。システムのジャンクファイルをクリーンアップする" + echo -e "[${gl_lv}OK${gl_bai}】2/12。システムのジャンクファイルをクリーンアップする" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}】3/10。仮想メモリを設定する${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】3/12。仮想メモリを設定する${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}】4/10。 SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】4/12。 SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}】5/10。すべてのポートを開く" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}】5/12。 SSH ブルート フォース クラッキングを防ぐために、fail2ban を開始します。" + + echo "------------------------------------------------" + echo -e "[${gl_lv}OK${gl_bai}】6/12。すべてのポートを開く" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}】6/10。開ける${gl_huang}BBR${gl_bai}加速する" + echo -e "[${gl_lv}OK${gl_bai}】7/12。開ける${gl_huang}BBR${gl_bai}加速する" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}】7/10。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】8/12。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}】8/10。 DNSアドレスを自動的に最適化する${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】9/12。 DNSアドレスを自動的に最適化する${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}】10/12。ネットワークを次のように設定します${gl_huang}IPv4優先度${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}】9/10。基本的なツールをインストールする${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】11/12。基本的なツールをインストールする${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}】10/10。 Linuxシステムのカーネルパラメータの最適化" + echo -e "[${gl_lv}OK${gl_bai}】12/12。 Linuxシステムのカーネルパラメータの最適化" echo -e "${gl_lv}ワンストップでのシステムチューニングが完了${gl_bai}" ;; @@ -13962,7 +14021,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14175,7 +14234,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14349,7 +14408,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14618,7 +14677,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index ae41b45fb..c2533424d 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # MySQL 튜닝 + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear @@ -2920,7 +2929,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -5331,7 +5340,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -5837,7 +5846,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6358,7 +6367,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -9098,7 +9107,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9119,7 +9128,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" - echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색" + echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" @@ -9321,7 +9330,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9433,7 +9442,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -12554,6 +12563,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "설치 완료" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "앱이 제거되었습니다." + } + + docker_app_plus + + ;; + + + + b) clear send_stats "모든 애플리케이션 백업" @@ -12759,7 +12809,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13092,8 +13142,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -13581,7 +13631,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13926,14 @@ EOF echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" - echo -e "5. 모든 포트를 엽니다." - echo -e "6. 켜기${gl_huang}BBR${gl_bai}가속하다" - echo -e "7. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" - echo -e "8. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" - echo -e "9. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux 시스템 커널 매개변수 최적화가 다음으로 전환됩니다.${gl_huang}균형 잡힌 최적화 모드${gl_bai}" + echo -e "5. SSH 무차별 대입 크래킹을 방어하기 위해 fall2ban을 시작하세요." + echo -e "6. 모든 포트를 엽니다" + echo -e "7. 켜다${gl_huang}BBR${gl_bai}가속하다" + echo -e "8. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" + echo -e "9. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" + echo -e "10. 네트워크를 다음으로 설정합니다.${gl_huang}IPv4 우선순위${gl_bai}" + echo -e "11. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux 시스템 커널 매개변수 최적화가 다음으로 전환됩니다.${gl_huang}균형 잡힌 최적화 모드${gl_bai}" echo "------------------------------------------------" read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice @@ -13892,44 +13943,52 @@ EOF send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 시스템을 최신으로 업데이트하세요" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 시스템을 최신으로 업데이트하세요" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 시스템 정크 파일 정리" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 시스템 정크 파일 정리" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 가상 메모리 설정${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" + echo "------------------------------------------------" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}] 5/12. SSH 무차별 대입 크래킹을 방어하려면 Fail2ban을 시작하세요." + echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 모든 포트 열기" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 모든 포트 열기" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 열려 있는${gl_huang}BBR${gl_bai}가속하다" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 열려 있는${gl_huang}BBR${gl_bai}가속하다" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. DNS 주소 자동 최적화${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. DNS 주소 자동 최적화${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 네트워크를 다음으로 설정하세요.${gl_huang}IPv4 우선순위${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux 시스템 커널 매개변수 최적화" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux 시스템 커널 매개변수 최적화" echo -e "${gl_lv}원스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; @@ -14618,7 +14677,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -14662,7 +14721,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "시스템 정보 표시 k 정보" } diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 1e86fa2ba..0f95ecbed 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.1" +sh_v="4.2.2" gl_hui='\e[37m' @@ -1432,7 +1432,16 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 + + # mysql調優 + wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -rf /home/custom_mysql_config.cnf + + + restart_ldnmp + clear @@ -9119,7 +9128,7 @@ while true; do echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" - echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索" + echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -12554,6 +12563,47 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 108|langbot) + local app_id="108" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: https://github.com/langbot-app/LangBot" + local docker_name="langbot_plugin_runtime" + local docker_port="8108" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/LangBot/docker && docker compose down --rmi all + cd /home/docker/LangBot/ + git pull origin main + sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml + cd /home/docker/LangBot/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/LangBot/docker/ && docker compose down --rmi all + rm -rf /home/docker/LangBot + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + b) clear send_stats "全部應用備份" @@ -13581,7 +13631,6 @@ EOF case $sub_choice in 1) f2b_install_sshd - cd ~ f2b_status break_end @@ -13877,12 +13926,14 @@ EOF echo "2. 清理系統垃圾文件" echo -e "3. 設置虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設置SSH端口號為${gl_huang}5522${gl_bai}" - echo -e "5. 開放所有端口" - echo -e "6. 開啟${gl_huang}BBR${gl_bai}加速" - echo -e "7. 設置時區到${gl_huang}上海${gl_bai}" - echo -e "8. 自動優化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "9. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "10. Linux系統內核參數優化切換到${gl_huang}均衡優化模式${gl_bai}" + echo -e "5. 啟動fail2ban防禦SSH暴力破解" + echo -e "6. 開放所有端口" + echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "8. 設置時區到${gl_huang}上海${gl_bai}" + echo -e "9. 自動優化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" + echo -e "10. 設置網絡為${gl_huang}ipv4優先${gl_bai}" + echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux系統內核參數優化切換到${gl_huang}均衡優化模式${gl_bai}" echo "------------------------------------------------" read -e -p "確定一鍵保養嗎? (Y/N):" choice @@ -13892,44 +13943,52 @@ EOF send_stats "一條龍調優啟動" echo "------------------------------------------------" linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/10. 更新系統到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/10. 清理系統垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系統垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/10. 設置虛擬內存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設置虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" local new_port=5522 new_ssh_port - echo -e "[${gl_lv}OK${gl_bai}] 4/10. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo "------------------------------------------------" + f2b_install_sshd + cd ~ + f2b_status + echo -e "[${gl_lv}OK${gl_bai}] 5/12. 啟動fail2ban防禦SSH暴力破解" + echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 5/10. 開放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 開放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 6/10. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 開啟${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 7/10. 設置時區到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 設置時區到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 8/10. 自動優化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自動優化DNS地址${gl_huang}${gl_bai}" + echo "------------------------------------------------" + prefer_ipv4 + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 設置網絡為${gl_huang}ipv4優先${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 9/10. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 10/10. Linux系統內核參數優化" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系統內核參數優化" echo -e "${gl_lv}一條龍系統調優已完成${gl_bai}" ;; From 7a134bf7459af1f2d16606d5a622cbe5c45a7791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:47:47 +0800 Subject: [PATCH 0339/1285] Update version and add new test options --- cn/kejilion.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 88fbf68af..5402d1126 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.3" gl_hui='\e[37m' @@ -1439,9 +1439,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -7739,6 +7739,7 @@ linux_test() { echo -e "${gl_kjlan}综合性测试" echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7857,17 @@ linux_test() { 32) send_stats "spiritysdx融合怪测评" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + ;; + + 33) + send_stats "nodequality融合怪测评" + clear + bash <(curl -sL https://run.NodeQuality.com) ;; + + 0) kejilion From b1641397818ac71b503b56b85859cb1700f3a7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:48:19 +0800 Subject: [PATCH 0340/1285] Update kejilion.sh --- kejilion.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 4bb3e9ea6..bc87cdbb1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.3" gl_hui='\e[37m' @@ -1439,9 +1439,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -7739,6 +7739,7 @@ linux_test() { echo -e "${gl_kjlan}综合性测试" echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7857,17 @@ linux_test() { 32) send_stats "spiritysdx融合怪测评" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + ;; + + 33) + send_stats "nodequality融合怪测评" + clear + bash <(curl -sL https://run.NodeQuality.com) ;; + + 0) kejilion From 7d8209629501cb604cd1b5f80eb2237eb28ed1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:50:10 +0800 Subject: [PATCH 0341/1285] Update changelog for version 4.2.3 --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e734c9510..ac7bd55f2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1344,5 +1344,9 @@ LDNMP建站和应用市场新增nginx的stream四层代理转发工具。 应用市场新增了LangBot开源聊天机器人的安装及使用。 LDNMP安装环境时对mysql进行优化。 ------------------------ +2025-11-10 v4.2.3 +测试脚本合集中添加nodequality融合测试脚本。 +------------------------ + From bf06fc836dabb55c9f52c69a59bd255c1f26b7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:30:22 +0800 Subject: [PATCH 0342/1285] Clean up blank lines in kejilion_sh_log.txt Removed unnecessary blank lines in log file. --- kejilion_sh_log.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ac7bd55f2..e73f04939 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1348,5 +1348,3 @@ LDNMP安装环境时对mysql进行优化。 测试脚本合集中添加nodequality融合测试脚本。 ------------------------ - - From 0ee70692f72f9bd678c479ed9a4dcbec3dcb7074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:50:30 +0800 Subject: [PATCH 0343/1285] Add ZFile online storage option to script --- cn/kejilion.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5402d1126..6954ea537 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9138,6 +9138,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" + echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12611,6 +12612,37 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -12885,6 +12917,43 @@ linux_work() { +# 智能切换镜像源函数 +switch_mirror() { + # 可选参数,默认为 false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 获取用户国家 + local country + country=$(curl -s ipinfo.io/country) + + echo "检测到国家:$country" + + if [ "$country" = "CN" ]; then + echo "使用国内镜像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "使用官方镜像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13488,7 +13557,7 @@ EOF echo "选择更新源区域" echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -13507,6 +13576,11 @@ EOF send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "智能切换更新源" + switch_mirror true true + ;; + *) echo "已取消" ;; From 3a3e6a9a9ca67ddd608ed9edd175657d43afad0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:51:16 +0800 Subject: [PATCH 0344/1285] Add ZFile online storage option to kejilion.sh --- kejilion.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index bc87cdbb1..6f543414c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9138,6 +9138,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" + echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12611,6 +12612,37 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) @@ -12885,6 +12917,43 @@ linux_work() { +# 智能切换镜像源函数 +switch_mirror() { + # 可选参数,默认为 false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 获取用户国家 + local country + country=$(curl -s ipinfo.io/country) + + echo "检测到国家:$country" + + if [ "$country" = "CN" ]; then + echo "使用国内镜像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "使用官方镜像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13488,7 +13557,7 @@ EOF echo "选择更新源区域" echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -13507,6 +13576,11 @@ EOF send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "智能切换更新源" + switch_mirror true true + ;; + *) echo "已取消" ;; From 3d17fa4a8a34c686f0d873a08f4e7b9afd208048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:53:00 +0800 Subject: [PATCH 0345/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e73f04939..dbbfd81fd 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1346,5 +1346,6 @@ LDNMP安装环境时对mysql进行优化。 ------------------------ 2025-11-10 v4.2.3 测试脚本合集中添加nodequality融合测试脚本。 +系统工具更换系统更新源新增智能切换更新源功能,识别国内自动切换华为源。 ------------------------ From 63c8b277b34dd8c2cb9a2774a7cdc92473a527af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:54:27 +0800 Subject: [PATCH 0346/1285] Update version and add Karakeep app installation --- cn/kejilion.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6954ea537..521fba625 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.3" +sh_v="4.2.4" gl_hui='\e[37m' @@ -9138,7 +9138,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" - echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘" + echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -10763,7 +10763,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12643,6 +12642,51 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + + + + b) From a7bfbacc6a9bb3365241de08f4c73675fb5378ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:55:04 +0800 Subject: [PATCH 0347/1285] Update kejilion.sh --- kejilion.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6f543414c..95bca0ede 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.3" +sh_v="4.2.4" gl_hui='\e[37m' @@ -9138,7 +9138,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" - echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘" + echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -10763,7 +10763,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12643,6 +12642,51 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "应用已卸载" + } + + docker_app_plus + + ;; + + + + + + + + b) From d5fd4868fa1ed7609e61fc806fdfb25962ab86a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:57:00 +0800 Subject: [PATCH 0348/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index dbbfd81fd..2c45dcb87 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1348,4 +1348,8 @@ LDNMP安装环境时对mysql进行优化。 测试脚本合集中添加nodequality融合测试脚本。 系统工具更换系统更新源新增智能切换更新源功能,识别国内自动切换华为源。 ------------------------ +2025-11-13 v4.2.4 +应用市场新增了karakeep书签管理的安装及使用。 +应用市场新增了zfile网盘的安装及使用。 +------------------------ From a8f89d1c1e4b156a13463124927c24239d844059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:21:00 +0800 Subject: [PATCH 0349/1285] Update kejilion.sh --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 521fba625..ab3ca4cf9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # 调用设置 DNS 的函数(需你定义) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } From 50ab6f0af392485c51a318aaf2260413b0908dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:21:31 +0800 Subject: [PATCH 0350/1285] Update kejilion.sh --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 95bca0ede..39d096ebb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # 调用设置 DNS 的函数(需你定义) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } From ea84e87ae761c1d21892a89188f646ccf3a12de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:22:41 +0800 Subject: [PATCH 0351/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2c45dcb87..9bc9932c8 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1351,5 +1351,6 @@ LDNMP安装环境时对mysql进行优化。 2025-11-13 v4.2.4 应用市场新增了karakeep书签管理的安装及使用。 应用市场新增了zfile网盘的安装及使用。 +自动优化dns地址修复部分机型写入为空的问题。 ------------------------ From cd8c5b93942ffa6a10b06a8a44efb484b2c64882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:13:41 +0800 Subject: [PATCH 0352/1285] Update kejilion.sh --- cn/kejilion.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ab3ca4cf9..bb1bcac75 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3099,6 +3099,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { From 7a6df4ebf786055008124904038662689d3b5823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:14:21 +0800 Subject: [PATCH 0353/1285] Install and enable rsyslog for apt systems Add installation and enablement of rsyslog for apt-based systems. --- kejilion.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 39d096ebb..eafe76103 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3099,6 +3099,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { From 0f95f80791ad5c4c3ddab45acffb287820a00d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:15:29 +0800 Subject: [PATCH 0354/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 9bc9932c8..33e6dc2dd 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1352,5 +1352,6 @@ LDNMP安装环境时对mysql进行优化。 应用市场新增了karakeep书签管理的安装及使用。 应用市场新增了zfile网盘的安装及使用。 自动优化dns地址修复部分机型写入为空的问题。 +系统工具ssh防御修复个别系统安装后启动失败的问题。 ------------------------ From 4d6f802bb33c3ecd6732a1d70acdc46fa4261567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:20:49 +0800 Subject: [PATCH 0355/1285] Update kejilion.sh --- kejilion.sh | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index eafe76103..879678899 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1629,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1741,7 +1732,6 @@ web_cache() { send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2328,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2369,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP环境已设置成 高性能模式" @@ -8986,7 +8974,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新$ldnmp_pods" echo "更新${ldnmp_pods}完成" From caa41ed516d0cbd99f2cd777a0266e9da3c700c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:21:24 +0800 Subject: [PATCH 0356/1285] Remove restart_redis function and its invocations Removed the restart_redis function and its calls from various parts of the script. --- cn/kejilion.sh | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bb1bcac75..40adf8ef3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1629,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1741,7 +1732,6 @@ web_cache() { send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2328,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2369,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP环境已设置成 高性能模式" @@ -8986,7 +8974,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新$ldnmp_pods" echo "更新${ldnmp_pods}完成" From 0bc6b170f86254651d8bcd00bb76004b7d218119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:41:17 +0800 Subject: [PATCH 0357/1285] Update kejilion.sh --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 40adf8ef3..075f574f1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4547,9 +4547,8 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +# rm /etc/resolv.conf +# touch /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf From 189bbd4889ce288c9391f95c9a1e2c6cd13fc7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:42:01 +0800 Subject: [PATCH 0358/1285] Update kejilion.sh --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 879678899..9325b87d8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4547,9 +4547,8 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +# rm /etc/resolv.conf +# touch /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf From 790fa22f215ec9c99a4a567bb8d9eefccac009ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:53:59 +0800 Subject: [PATCH 0359/1285] Update resolv.conf management in kejilion.sh Modify resolv.conf handling to ensure nameservers are added if the file is empty. --- cn/kejilion.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 075f574f1..6d8be57d3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4547,8 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -# rm /etc/resolv.conf -# touch /etc/resolv.conf +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4560,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } From d4e92528578f424eb64b91cdbf0408ffd3cf7dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:55:15 +0800 Subject: [PATCH 0360/1285] Update resolv.conf management in kejilion.sh Modify resolv.conf handling to ensure nameservers are added if the file is empty. --- kejilion.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9325b87d8..5bcbf0676 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4547,8 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -# rm /etc/resolv.conf -# touch /etc/resolv.conf +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4560,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } From 96911679fca12d284a0bee3cbe1cab75061429e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:07:51 +0800 Subject: [PATCH 0361/1285] Remove unnecessary optimization from redis in LDNMP --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 33e6dc2dd..92809390a 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1353,5 +1353,6 @@ LDNMP安装环境时对mysql进行优化。 应用市场新增了zfile网盘的安装及使用。 自动优化dns地址修复部分机型写入为空的问题。 系统工具ssh防御修复个别系统安装后启动失败的问题。 +LDNMP环境中redis去除了不必要的优化机制。 ------------------------ From 2861201340d1e038d65e958e4236396bcfd1ecc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:08:39 +0800 Subject: [PATCH 0362/1285] Update redis optimization description in log --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 92809390a..153ab569f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1353,6 +1353,6 @@ LDNMP安装环境时对mysql进行优化。 应用市场新增了zfile网盘的安装及使用。 自动优化dns地址修复部分机型写入为空的问题。 系统工具ssh防御修复个别系统安装后启动失败的问题。 -LDNMP环境中redis去除了不必要的优化机制。 +LDNMP环境中redis去除了不必要的清理机制。 ------------------------ From ec19062dbe51f166dc99c3841c61aa590eecc963 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 16 Nov 2025 04:06:41 +0000 Subject: [PATCH 0363/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-16=2004:06:41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 188 +++++++++++++++++++++++++++++++++++++-------- jp/kejilion.sh | 202 +++++++++++++++++++++++++++++++++++++++---------- kr/kejilion.sh | 190 +++++++++++++++++++++++++++++++++++++--------- tw/kejilion.sh | 170 +++++++++++++++++++++++++++++++++++------ 4 files changed, 619 insertions(+), 131 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d38c47639..9221ad3b3 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # Call the function that sets DNS (needs to be defined by you) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "Clear site cache" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "The LDNMP environment has been set to high performance mode" @@ -2597,7 +2584,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2616,7 +2603,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -4751,7 +4747,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } @@ -6367,7 +6363,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}Comprehensive testing" echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx fusion monster evaluation${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality fusion monster evaluation${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx fusion monster review" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "nodequality fusion monster evaluation" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "renew$ldnmp_pods" echo "renew${ldnmp_pods}Finish" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool${gl_kjlan}104. ${color104}Stream four-layer proxy forwarding tool" echo -e "${gl_kjlan}105. ${color105}Siyuan Notes${gl_kjlan}106. ${color106}Drawnix open source whiteboard tool" echo -e "${gl_kjlan}107. ${color107}PanSou network disk search${gl_kjlan}108. ${color108}LangBot chatbot" + echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" @@ -9410,7 +9415,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "Installation completed" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "App has been uninstalled" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# Intelligent switching mirror source function +switch_mirror() { + # Optional parameter, default is false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # Get user country + local country + country=$(curl -s ipinfo.io/country) + + echo "Countries detected:$country" + + if [ "$country" = "CN" ]; then + echo "Use domestic mirror sources..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "Use official mirror source..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13142,7 +13259,7 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" + echo "Switched to IPv6 first" send_stats "Switched to IPv6 priority" ;; @@ -13479,7 +13596,7 @@ EOF echo "Select update source region" echo "Access LinuxMirrors to switch system update sources" echo "------------------------" - echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions" + echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions 4. Intelligent switching of update sources" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "Overseas sources" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "Intelligent switching of update sources" + switch_mirror true true + ;; + *) echo "Canceled" ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4de4a5ef3..527ff1dc4 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -897,12 +897,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1225,7 +1225,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # DNS を設定する関数を呼び出します (ユーザーが定義する必要があります) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "サイトキャッシュをクリアする" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP 環境が高パフォーマンス モードに設定されている" @@ -2929,7 +2916,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -3527,7 +3520,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4177,7 +4170,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -4751,7 +4747,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } @@ -5352,7 +5348,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5417,7 +5413,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -7151,7 +7147,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}総合的なテスト" echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}ノードクオリティ融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "Spiritysdx フュージョンモンスター レビュー" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "ノードクオリティ融合モンスターの評価" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新する$ldnmp_pods" echo "更新する${ldnmp_pods}仕上げる" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" + echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" @@ -9339,7 +9344,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "インストール完了" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "アプリがアンインストールされました" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# インテリジェントスイッチングミラーソース機能 +switch_mirror() { + # オプションのパラメータ、デフォルトは false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # ユーザーの国を取得する + local country + country=$(curl -s ipinfo.io/country) + + echo "検出された国:$country" + + if [ "$country" = "CN" ]; then + echo "国内のミラーソースを使用..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "公式ミラーソースを使用してください..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13371,7 +13488,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13479,7 +13596,7 @@ EOF echo "更新元リージョンの選択" echo "LinuxMirror にアクセスしてシステム アップデート ソースを切り替える" echo "------------------------" - echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域" + echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域 4. 更新ソースのインテリジェントな切り替え" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "海外情報源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "アップデートソースのインテリジェントな切り替え" + switch_mirror true true + ;; + *) echo "キャンセル" ;; @@ -14408,7 +14530,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index c2533424d..056abd24f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # DNS를 설정하는 함수 호출(사용자가 정의해야 함) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "사이트 캐시 지우기" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP 환경이 고성능 모드로 설정되었습니다." @@ -2597,7 +2584,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2616,7 +2603,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2729,7 +2716,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -5340,7 +5336,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}종합적인 테스트" echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 퓨전 몬스터 평가${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}Nodequality 융합 몬스터 평가${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx 퓨전 몬스터 리뷰" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + ;; + + 33) + send_stats "Nodequality 융합 몬스터 평가" + clear + bash <(curl -sL https://run.NodeQuality.com) ;; + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "고쳐 쓰다$ldnmp_pods" echo "고쳐 쓰다${ldnmp_pods}마치다" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" + echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" @@ -9410,7 +9415,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "설치 완료" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "앱이 제거되었습니다." + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# 지능형 스위칭 미러 소스 기능 +switch_mirror() { + # 선택적 매개변수, 기본값은 false입니다. + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 사용자 국가 가져오기 + local country + country=$(curl -s ipinfo.io/country) + + echo "감지된 국가:$country" + + if [ "$country" = "CN" ]; then + echo "국내 미러 소스를 사용하세요..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "공식 미러 소스를 사용하세요..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13444,7 +13561,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13479,7 +13596,7 @@ EOF echo "업데이트 소스 지역 선택" echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "해외 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "업데이트 소스의 지능적인 전환" + switch_mirror true true + ;; + *) echo "취소" ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 0f95ecbed..5687c0c6e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # 調用設置 DNS 的函數(需你定義) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "清理站點緩存" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP環境已設置成 高性能模式" @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}綜合性測試" echo -e "${gl_kjlan}31. ${gl_bai}bench 性能測試" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪測評${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪測評${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx融合怪測評" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "nodequality融合怪測評" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新$ldnmp_pods" echo "更新${ldnmp_pods}完成" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" + echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# 智能切換鏡像源函數 +switch_mirror() { + # 可選參數,默認為 false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 獲取用戶國家 + local country + country=$(curl -s ipinfo.io/country) + + echo "檢測到國家:$country" + + if [ "$country" = "CN" ]; then + echo "使用國內鏡像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "使用官方鏡像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13479,7 +13596,7 @@ EOF echo "選擇更新源區域" echo "接入LinuxMirrors切換系統更新源" echo "------------------------" - echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區" + echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區 4. 智能切換更新源" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "智能切換更新源" + switch_mirror true true + ;; + *) echo "已取消" ;; From abe9dab50efe678869248b04ccfdf4659f67b9c6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 16 Nov 2025 04:06:41 +0000 Subject: [PATCH 0364/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-16=2004:06:41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 184 +++++++++++++++++++++++++++++++++++++-------- jp/kejilion.sh | 200 +++++++++++++++++++++++++++++++++++++++---------- kr/kejilion.sh | 190 +++++++++++++++++++++++++++++++++++++--------- tw/kejilion.sh | 170 +++++++++++++++++++++++++++++++++++------ 4 files changed, 616 insertions(+), 128 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d38c47639..8e4ece6ab 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # Call the function that sets DNS (needs to be defined by you) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "Clear site cache" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "The LDNMP environment has been set to high performance mode" @@ -2597,7 +2584,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2616,7 +2603,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -4751,7 +4747,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}Comprehensive testing" echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx fusion monster evaluation${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality fusion monster evaluation${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx fusion monster review" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "nodequality fusion monster evaluation" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "renew$ldnmp_pods" echo "renew${ldnmp_pods}Finish" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool${gl_kjlan}104. ${color104}Stream four-layer proxy forwarding tool" echo -e "${gl_kjlan}105. ${color105}Siyuan Notes${gl_kjlan}106. ${color106}Drawnix open source whiteboard tool" echo -e "${gl_kjlan}107. ${color107}PanSou network disk search${gl_kjlan}108. ${color108}LangBot chatbot" + echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" @@ -9410,7 +9415,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "Installation completed" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "App has been uninstalled" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# Intelligent switching mirror source function +switch_mirror() { + # Optional parameter, default is false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # Get user country + local country + country=$(curl -s ipinfo.io/country) + + echo "Countries detected:$country" + + if [ "$country" = "CN" ]; then + echo "Use domestic mirror sources..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "Use official mirror source..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13479,7 +13596,7 @@ EOF echo "Select update source region" echo "Access LinuxMirrors to switch system update sources" echo "------------------------" - echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions" + echo "1. Mainland China [Default] 2. Mainland China [Education Network] 3. Overseas regions 4. Intelligent switching of update sources" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "Overseas sources" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "Intelligent switching of update sources" + switch_mirror true true + ;; + *) echo "Canceled" ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4de4a5ef3..28aec41f5 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -897,12 +897,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # DNS を設定する関数を呼び出します (ユーザーが定義する必要があります) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "サイトキャッシュをクリアする" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP 環境が高パフォーマンス モードに設定されている" @@ -2929,7 +2916,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -3527,7 +3520,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4177,7 +4170,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -4751,7 +4747,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } @@ -5352,7 +5348,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5417,7 +5413,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -7151,7 +7147,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}総合的なテスト" echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}ノードクオリティ融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "Spiritysdx フュージョンモンスター レビュー" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "ノードクオリティ融合モンスターの評価" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新する$ldnmp_pods" echo "更新する${ldnmp_pods}仕上げる" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" + echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" @@ -9339,7 +9344,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "インストール完了" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "アプリがアンインストールされました" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# インテリジェントスイッチングミラーソース機能 +switch_mirror() { + # オプションのパラメータ、デフォルトは false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # ユーザーの国を取得する + local country + country=$(curl -s ipinfo.io/country) + + echo "検出された国:$country" + + if [ "$country" = "CN" ]; then + echo "国内のミラーソースを使用..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "公式ミラーソースを使用してください..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13371,7 +13488,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13479,7 +13596,7 @@ EOF echo "更新元リージョンの選択" echo "LinuxMirror にアクセスしてシステム アップデート ソースを切り替える" echo "------------------------" - echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域" + echo "1. 中国本土 [デフォルト] 2. 中国本土 [教育ネットワーク] 3. 海外地域 4. 更新ソースのインテリジェントな切り替え" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "海外情報源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "アップデートソースのインテリジェントな切り替え" + switch_mirror true true + ;; + *) echo "キャンセル" ;; @@ -14408,7 +14530,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index c2533424d..056abd24f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # DNS를 설정하는 함수 호출(사용자가 정의해야 함) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "사이트 캐시 지우기" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP 환경이 고성능 모드로 설정되었습니다." @@ -2597,7 +2584,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2616,7 +2603,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2729,7 +2716,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -5340,7 +5336,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -7360,7 +7356,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}종합적인 테스트" echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 퓨전 몬스터 평가${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}Nodequality 융합 몬스터 평가${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx 퓨전 몬스터 리뷰" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + ;; + + 33) + send_stats "Nodequality 융합 몬스터 평가" + clear + bash <(curl -sL https://run.NodeQuality.com) ;; + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "고쳐 쓰다$ldnmp_pods" echo "고쳐 쓰다${ldnmp_pods}마치다" @@ -9067,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" + echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" @@ -9410,7 +9415,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "설치 완료" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "앱이 제거되었습니다." + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# 지능형 스위칭 미러 소스 기능 +switch_mirror() { + # 선택적 매개변수, 기본값은 false입니다. + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 사용자 국가 가져오기 + local country + country=$(curl -s ipinfo.io/country) + + echo "감지된 국가:$country" + + if [ "$country" = "CN" ]; then + echo "국내 미러 소스를 사용하세요..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "공식 미러 소스를 사용하세요..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13444,7 +13561,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13479,7 +13596,7 @@ EOF echo "업데이트 소스 지역 선택" echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "해외 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "업데이트 소스의 지능적인 전환" + switch_mirror true true + ;; + *) echo "취소" ;; @@ -14492,7 +14614,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 0f95ecbed..5687c0c6e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.2" +sh_v="4.2.4" gl_hui='\e[37m' @@ -1404,8 +1404,7 @@ auto_optimize_dns() { local dns2_ipv6="2001:4860:4860::8888" fi - # 調用設置 DNS 的函數(需你定義) - set_dns "$dns1_ipv4" "$dns2_ipv4" "$dns1_ipv6" "$dns2_ipv6" + set_dns } @@ -1439,9 +1438,9 @@ install_ldnmp() { rm -rf /home/custom_mysql_config.cnf - + restart_ldnmp - + clear @@ -1630,17 +1629,8 @@ reverse_proxy() { } -restart_redis() { - rm -rf /home/web/redis/* - docker exec redis redis-cli FLUSHALL > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory 1gb > /dev/null 2>&1 - # docker exec -it redis redis-cli CONFIG SET maxmemory-policy allkeys-lru > /dev/null 2>&1 -} - - restart_ldnmp() { - restart_redis docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/fastcgi > /dev/null 2>&1 @@ -1742,7 +1732,6 @@ web_cache() { send_stats "清理站點緩存" cf_purge_cache cd /home/web && docker compose restart - restart_redis } @@ -2329,7 +2318,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_balanced @@ -2370,7 +2358,6 @@ web_optimization() { cd /home/web && docker compose restart - restart_redis optimize_web_server echo "LDNMP環境已設置成 高性能模式" @@ -3100,6 +3087,12 @@ f2b_install_sshd() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf fi + if command -v apt &>/dev/null; then + install rsyslog + systemctl start rsyslog + systemctl enable rsyslog + fi + } f2b_sshd() { @@ -4554,9 +4547,7 @@ set_dns() { ip_address chattr -i /etc/resolv.conf -rm /etc/resolv.conf -touch /etc/resolv.conf - +> /etc/resolv.conf if [ -n "$ipv4_address" ]; then echo "nameserver $dns1_ipv4" >> /etc/resolv.conf @@ -4568,6 +4559,11 @@ if [ -n "$ipv6_address" ]; then echo "nameserver $dns2_ipv6" >> /etc/resolv.conf fi +if [ ! -s /etc/resolv.conf ]; then + echo "nameserver 223.5.5.5" >> /etc/resolv.conf + echo "nameserver 8.8.8.8" >> /etc/resolv.conf +fi + chattr +i /etc/resolv.conf } @@ -7739,6 +7735,7 @@ linux_test() { echo -e "${gl_kjlan}綜合性測試" echo -e "${gl_kjlan}31. ${gl_bai}bench 性能測試" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪測評${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪測評${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -7856,9 +7853,17 @@ linux_test() { 32) send_stats "spiritysdx融合怪測評" clear - curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; + 33) + send_stats "nodequality融合怪測評" + clear + bash <(curl -sL https://run.NodeQuality.com) + ;; + + + 0) kejilion @@ -8972,7 +8977,6 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - restart_redis send_stats "更新$ldnmp_pods" echo "更新${ldnmp_pods}完成" @@ -9129,6 +9133,7 @@ while true; do echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" + echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -10753,7 +10758,6 @@ while true; do docker_app_install() { install git mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env - # sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -12602,6 +12606,82 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 109|zfile) + + local app_id="109" + local docker_name="zfile" + local docker_img="zhaojun1998/zfile:latest" + local docker_port=8109 + + docker_rum() { + + + docker run -d --name=zfile --restart=always \ + -p ${docker_port}:8080 \ + -v /home/docker/zfile/db:/root/.zfile-v4/db \ + -v /home/docker/zfile/logs:/root/.zfile-v4/logs \ + -v /home/docker/zfile/file:/data/file \ + -v /home/docker/zfile/application.properties:/root/.zfile-v4/application.properties \ + zhaojun1998/zfile:latest + + + } + + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 110|karakeep) + local app_id="110" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local docker_name="docker-web-1" + local docker_port="8110" + local app_size="1" + + docker_app_install() { + install git + mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + + docker compose up -d + clear + echo "已經安裝完成" + check_docker_app_ip + } + + docker_app_update() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + cd /home/docker/karakeep/ + git pull origin main + sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml + cd /home/docker/karakeep/docker/ && docker compose up -d + } + + docker_app_uninstall() { + cd /home/docker/karakeep/docker/ && docker compose down --rmi all + rm -rf /home/docker/karakeep + echo "應用已卸載" + } + + docker_app_plus + + ;; + + + + + + + + b) @@ -12876,6 +12956,43 @@ linux_work() { +# 智能切換鏡像源函數 +switch_mirror() { + # 可選參數,默認為 false + local upgrade_software=${1:-false} + local clean_cache=${2:-false} + + # 獲取用戶國家 + local country + country=$(curl -s ipinfo.io/country) + + echo "檢測到國家:$country" + + if [ "$country" = "CN" ]; then + echo "使用國內鏡像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.huaweicloud.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + else + echo "使用官方鏡像源..." + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --pure-mode + fi +} + linux_Settings() { @@ -13479,7 +13596,7 @@ EOF echo "選擇更新源區域" echo "接入LinuxMirrors切換系統更新源" echo "------------------------" - echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區" + echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區 4. 智能切換更新源" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -13498,6 +13615,11 @@ EOF send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; + 4) + send_stats "智能切換更新源" + switch_mirror true true + ;; + *) echo "已取消" ;; From b6e352c3b8c7467f569aadc73f75230f4230faa7 Mon Sep 17 00:00:00 2001 From: AkarinLiu Date: Sun, 16 Nov 2025 13:59:00 +0800 Subject: [PATCH 0365/1285] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Minecraft=20?= =?UTF-8?q?=E5=BC=80=E6=9C=8D=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mc.sh | 445 +++++++++++++++++++++++++++++++++++++++++++++++++++ mc_backup.sh | 7 + 2 files changed, 452 insertions(+) create mode 100644 mc.sh create mode 100644 mc_backup.sh diff --git a/mc.sh b/mc.sh new file mode 100644 index 000000000..fd79f9c4c --- /dev/null +++ b/mc.sh @@ -0,0 +1,445 @@ +#!/bin/bash +ln -sf ~/minecraft_server.sh /usr/local/bin/mcs + +ip_address() { +ipv4_address=$(curl -s ipv4.ip.sb) +ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) +} + + +install() { + if [ $# -eq 0 ]; then + echo "未提供软件包参数!" + return 1 + fi + + for package in "$@"; do + if ! command -v "$package" &>/dev/null; then + if command -v apt &>/dev/null; then + apt update -y && apt install -y "$package" + elif command -v yum &>/dev/null; then + yum -y update && yum -y install "$package" + elif command -v apk &>/dev/null; then + apk update && apk add "$package" + else + echo "未知的包管理器!" + return 1 + fi + fi + done + + return 0 +} + + +remove() { + if [ $# -eq 0 ]; then + echo "未提供软件包参数!" + return 1 + fi + + for package in "$@"; do + if command -v apt &>/dev/null; then + apt purge -y "$package" + elif command -v yum &>/dev/null; then + yum remove -y "$package" + elif command -v apk &>/dev/null; then + apk del "$package" + else + echo "未知的包管理器!" + return 1 + fi + done + + return 0 +} + + +break_end() { + echo -e "\033[0;32m操作完成\033[0m" + echo "按任意键继续..." + read -n 1 -s -r -p "" + echo "" + clear +} + +mc() { + p + exit +} + + +install_add_docker() { + if [ -f "/etc/alpine-release" ]; then + apk update + apk add docker docker-compose + rc-update add docker default + service docker start + else + curl -fsSL https://get.docker.com | sh && ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin + systemctl start docker + systemctl enable docker + fi +} + +install_docker() { + if ! command -v docker &>/dev/null; then + install_add_docker + else + echo "Docker 已经安装" + fi +} + +mc_start() { + ip_address + tmux new -d -s mc1 "docker start mcserver -it" + echo -e "\033[0;32mMinecraft服务启动啦!\033[0m" + echo -e "\033[0;32m游戏下载地址: https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj\033[0m" + echo -e "\033[0;32m进入游戏连接:\033[93m $ipv4_address:25565 $ipv6_address:25565 \033[0;32m开始冒险吧!\033[0m" + +} + +mc_backup() { + cd ~ + curl -sS -O https://kejilion.pro/mc_backup.sh && chmod +x mc_backup.sh +} + +mc_install_status() { + CONTAINER_NAME="mcserver" + + # 检查容器是否已安装 + if [ "$(docker ps -a -q -f name=$CONTAINER_NAME 2>/dev/null)" ]; then + container_status="\e[32mMinecraft服务已安装\e[0m" # 绿色 + else + container_status="\e[90mMinecraft服务未安装\e[0m" # 灰色 + fi + + SESSION_NAME="mc1" + + ip_address + # 检查 tmux 中是否存在指定的工作区 + if tmux has-session -t $SESSION_NAME 2>/dev/null; then + tmux_status="\e[32m已开服:\033[93m $ipv4_address:25565 $ipv6_address:25565 \e[0m" # 绿色 + else + tmux_status="\e[90m未开服\e[0m" # 灰色 + fi + +} + +while true; do +clear +mc_install_status +echo -e "\033[93m . . ." +echo "███╗ ███╗██╗███╗ ██╗███████╗ ██████╗██████╗ █████╗ ███████╗████████╗" +echo "████╗ ████║██║████╗ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝" +echo "██╔████╔██║██║██╔██╗ ██║█████╗ ██║ ██████╔╝███████║█████╗ ██║ " +echo "██║╚██╔╝██║██║██║╚██╗██║██╔══╝ ██║ ██╔══██╗██╔══██║██╔══╝ ██║ " +echo "██║ ╚═╝ ██║██║██║ ╚████║███████╗╚██████╗██║ ██║██║ ██║██║ ██║ " +echo "╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ " +echo -e "\033[96mMinecraft开服一键脚本工具v1.0.0 by AkarinLiu\033[0m" +echo -e "\033[96m-输入\033[93mp\033[96m可快速启动此脚本-\033[0m" +echo -e "$container_status $tmux_status" +echo "------------------------" +echo "1. 安装Minecraft服务" +echo "2. 开启Minecraft服务" +echo "3. 关闭Minecraft服务" +echo "4. 重启Minecraft服务" +echo "------------------------" +echo "5. 查看服务器状态" +echo "6. 设置虚拟内存" +echo "------------------------" +echo "7. 导出游戏存档" +echo "8. 导入游戏存档" +echo "9. 定时备份游戏存档" +echo "------------------------" +echo "10. 修改游戏配置" +echo "------------------------" +echo "11. 更新Minecraft服务" +echo "12. 卸载Minecraft服务" +echo "------------------------" +echo "k. 科技lion脚本工具箱" +echo "------------------------" +echo "00. 脚本更新" +echo "------------------------" +echo "0. 退出脚本" +echo "------------------------" +read -p "请输入你的选择: " choice + +case $choice in + 1) + clear + install_docker + install tmux + docker create -d --name $CONTAINER_NAME -p 25565:25565/tcp --restart=always -e EULA=true -v mcserver:/data:rw itzg/minecraft-server + clear + mc_start + ;; + + 2) + clear + docker start $CONTAINER_NAME > /dev/null 2>&1 + mc_start + ;; + + 3) + clear + tmux kill-session -t mc1 + docker stop $CONTAINER_NAME > /dev/null 2>&1 + echo -e "\033[0;32mMinecraft服务已关闭\033[0m" + ;; + + 4) + clear + tmux kill-session -t mc1 + docker restart $CONTAINER_NAME > /dev/null 2>&1 + mc_start + ;; + + 5) + clear + install btop + clear + btop + ;; + + 6) + clear + swap_used=$(free -m | awk 'NR==3{print $3}') + swap_total=$(free -m | awk 'NR==3{print $2}') + + if [ "$swap_total" -eq 0 ]; then + swap_percentage=0 + else + swap_percentage=$((swap_used * 100 / swap_total)) + fi + + swap_info="${swap_used}MB/${swap_total}MB (${swap_percentage}%)" + + echo "当前虚拟内存: $swap_info" + + read -p "是否调整大小?(Y/N): " choice + + case "$choice" in + [Yy]) + # 输入新的虚拟内存大小 + read -p "请输入虚拟内存大小MB: " new_swap + + # 获取当前系统中所有的 swap 分区 + swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') + + # 遍历并删除所有的 swap 分区 + for partition in $swap_partitions; do + swapoff "$partition" + wipefs -a "$partition" # 清除文件系统标识符 + mkswap -f "$partition" + echo "已删除并重新创建 swap 分区: $partition" + done + + # 确保 /swapfile 不再被使用 + swapoff /swapfile + + # 删除旧的 /swapfile + rm -f /swapfile + + # 创建新的 swap 分区 + dd if=/dev/zero of=/swapfile bs=1M count=$new_swap + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + + if [ -f /etc/alpine-release ]; then + echo "/swapfile swap swap defaults 0 0" >> /etc/fstab + echo "nohup swapon /swapfile" >> /etc/local.d/swap.start + chmod +x /etc/local.d/swap.start + rc-update add local + else + echo "/swapfile swap swap defaults 0 0" >> /etc/fstab + fi + + echo "虚拟内存大小已调整为${new_swap}MB" + ;; + [Nn]) + echo "已取消" + ;; + *) + echo "无效的选择,请输入 Y 或 N。" + ;; + esac + ;; + + 7) + clear + mkdir -p /home/game + docker cp $CONTAINER_NAME:/data/world /home/game/mc/ > /dev/null 2>&1 + cd /home/game && tar czvf mcsave_$(date +"%Y%m%d%H%M%S").tar.gz mc > /dev/null 2>&1 + rm -rf /home/game/mc/ + echo -e "\033[0;32m游戏存档已导出存放在: /home/game/\033[0m" + ;; + 8) + clear + tmux kill-session -t mc1 + docker exec -it mcserver bash -c "rm -rf /data/world/*" + cd /home/game/ && ls -t /home/game/mc/mcsave_*.tar.gz | head -1 | xargs -I {} tar -xzf {} + docker cp /home/game/mc/world/* mcserver: + docker exec -it -u root $CONTAINER_NAME bash -c "chmod -R 777 /home/steam/Steam/steamapps/common/mcServer/mc/Saved/" + rm -rf /home/game/mc/ + echo -e "\033[0;32m游戏存档已导入\033[0m" + docker restart mcserver > /dev/null 2>&1 + mc_start + ;; + + 9) + clear + echo "Minecraft游戏存档定时备份" + echo "------------------------" + echo "1. 每周备份 2. 每天备份 3. 每小时备份" + echo "------------------------" + read -p "请输入你的选择: " dingshi + case $dingshi in + 1) + mc_backup + (crontab -l ; echo "0 0 * * 1 ./mc_backup.sh") | crontab - > /dev/null 2>&1 + echo "每周一备份,已设置" + + ;; + 2) + mc_backup + (crontab -l ; echo "0 3 * * * ./mc_backup.sh") | crontab - > /dev/null 2>&1 + echo "每天凌晨3点备份,已设置" + + ;; + 3) + mc_backup + (crontab -l ; echo "0 * * * * ./mc_backup.sh") | crontab - > /dev/null 2>&1 + echo "每小时整点备份,已设置" + + ;; + *) + echo "已取消" + ;; + esac + ;; + + 10) + clear + tmux kill-session -t mc1 + cd ~ && curl -sS -O https://kejilion.pro/mcSettings.ini + + echo "配置游戏参数" + echo "------------------------" + read -p "设置加入的密码(回车默认无密码): " server_password + read -p "设置游戏难度: (1. 简单 2. 普通 3. 困难):" Difficulty + case $Difficulty in + 1) + Difficulty=1 + ;; + + 2) + Difficulty=2 + ;; + 3) + Difficulty=3 + ;; + *) + echo "-默认设置为普通难度" + Difficulty=2 + ;; + esac + + read -p "经验值倍率: (回车默认1倍):" exp_rate + ExpRate=${exp_rate:-1} + read -p "死亡后掉落设置: (1. 掉落 2. 不掉落):" DeathPenalty + case $DeathPenalty in + 1) + DeathPenalty=All + ;; + + 2) + DeathPenalty=None + ;; + *) + DeathPenalty=All + echo "-默认设置为掉落" + ;; + esac + + read -p "设置pvp模式: (1. 开启 2. 关闭):" mc_pvp + + case $mc_pvp in + 1) + mc_pvp=True + ;; + 2) + mc_pvp=False + ;; + *) + mc_pvp=False + echo "-默认关闭pvp模式" + ;; + esac + + # 更新配置文件 + sed -i "s/ServerPassword=\"\"/ServerPassword=\"$server_password\"/" ~/mcSettings.ini + sed -i "s/Difficulty=2/Difficulty=$Difficulty/" ~/mcSettings.ini + sed -i "s/ExpRate=1.000000/ExpRate=$ExpRate/" ~/mcSettings.ini + sed -i "s/DeathPenalty=All/DeathPenalty=$DeathPenalty/" ~/mcSettings.ini + sed -i "s/bEnablePlayerToPlayerDamage=False/bEnablePlayerToPlayerDamage=$mc_pvp/" ~/mcSettings.ini + sed -i "s/bIsPvP=False/bIsPvP=$mc_pvp/" ~/mcSettings.ini + echo "------------------------" + echo "配置文件已更新" + + docker exec -it mcserver bash -c "rm -f /home/steam/Steam/steamapps/common/mcServer/mc/Saved/Config/LinuxServer/mcSettings.ini" + docker cp ~/mcSettings.ini mcserver:/home/steam/Steam/steamapps/common/mcServer/mc/Saved/Config/LinuxServer/ > /dev/null 2>&1 + docker exec -it -u root $CONTAINER_NAME bash -c "chmod -R 777 /home/steam/Steam/steamapps/common/mcServer/mc/Saved/" + rm -f ~/mcSettings.ini + echo -e "\033[0;32m游戏配置已导入\033[0m" + docker restart mcserver > /dev/null 2>&1 + mc_start + ;; + + + 11) + clear + tmux kill-session -t mc1 + docker restart mcserver > /dev/null 2>&1 + docker exec -it mcserver bash -c "/home/steam/mcserver/mcserver.sh +login anonymous +app_update 2394010 validate +quit" + clear + echo -e "\033[0;32mMinecraft已更新\033[0m" + mc_start + ;; + + 12) + clear + docker rm -f mcserver + docker rmi -f cm2network/mcserver + ;; + + k) + cd ~ + curl -sS -O https://kejilion.pro/kejilion.sh && chmod +x kejilion.sh && ./kejilion.sh + exit + ;; + + 00) + cd ~ + curl -sS -O https://kejilion.pro/mc_log.sh && chmod +x mc_log.sh && ./mc_log.sh + rm mc_log.sh + echo "" + curl -sS -O https://kejilion.pro/mc.sh && chmod +x mc.sh + echo "脚本已更新到最新版本!" + break_end + mc + ;; + + + 0) + clear + exit + ;; + + *) + echo "无效的输入!" + ;; +esac + break_end +done diff --git a/mc_backup.sh b/mc_backup.sh new file mode 100644 index 000000000..2f0515202 --- /dev/null +++ b/mc_backup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +clear +mkdir -p /home/game +docker cp mcserver:/data /home/game/mc +cd /home/game && tar czvf mc_$(date +"%Y%m%d%H%M%S").tar.gz mc +rm -rf /home/game/mc/ +echo -e "\033[0;32m游戏存档已导出存放在: /home/game/\033[0m" \ No newline at end of file From c01330aa19ca4b843de3f12d0abe66d70e769259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:43:15 +0800 Subject: [PATCH 0366/1285] Update kejilion.sh --- cn/kejilion.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6d8be57d3..039797fae 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror true true + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -1638,7 +1639,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -3176,7 +3178,6 @@ root_use clear echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3194,6 @@ root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -8853,7 +8853,6 @@ linux_ldnmp() { echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8988,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot From 4f88b479f365a2408c866fe133d13144ebac9c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:43:54 +0800 Subject: [PATCH 0367/1285] Refactor install_dependency function and remove check_port --- kejilion.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 5bcbf0676..0abd6f75e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror true true + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -1638,7 +1639,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -3176,7 +3178,6 @@ root_use clear echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3194,6 @@ root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -8853,7 +8853,6 @@ linux_ldnmp() { echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8988,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot From 2110e9e734386fc887dda7eb35e4d670bdceadee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:46:27 +0800 Subject: [PATCH 0368/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 153ab569f..c94a568e6 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1354,5 +1354,6 @@ LDNMP安装环境时对mysql进行优化。 自动优化dns地址修复部分机型写入为空的问题。 系统工具ssh防御修复个别系统安装后启动失败的问题。 LDNMP环境中redis去除了不必要的清理机制。 +LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 ------------------------ From 04cf6e42f5907cb223920674bc759b77ea8fd8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:27:04 +0800 Subject: [PATCH 0369/1285] Fix docker stop command indentation in install_ssltls --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 039797fae..b1041c15a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1467,8 +1467,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From 45a5a67861712126d9c8792825e2575b21e404eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:27:55 +0800 Subject: [PATCH 0370/1285] Fix docker stop command indentation in install_ssltls --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 0abd6f75e..bc9b4413c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1467,8 +1467,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From d3bdcdbeb39996ae39845e1c7c1a14edff2eca1b Mon Sep 17 00:00:00 2001 From: AkarinLiu Date: Mon, 17 Nov 2025 13:51:27 +0800 Subject: [PATCH 0371/1285] =?UTF-8?q?=E5=AF=B9=20Minecraft=20=E7=9A=84?= =?UTF-8?q?=E9=9A=BE=E5=BA=A6=E7=AD=89=E7=BB=86=E8=8A=82=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=BA=86=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mc.sh | 104 ++++++++++++++++++++++----------------------------- mc_backup.sh | 4 +- mc_log.sh | 7 ++++ 3 files changed, 53 insertions(+), 62 deletions(-) create mode 100644 mc_log.sh diff --git a/mc.sh b/mc.sh index fd79f9c4c..f79a7b3ca 100644 --- a/mc.sh +++ b/mc.sh @@ -92,7 +92,7 @@ install_docker() { mc_start() { ip_address - tmux new -d -s mc1 "docker start mcserver -it" + docker start mcserver > /dev/null 2>&1 echo -e "\033[0;32mMinecraft服务启动啦!\033[0m" echo -e "\033[0;32m游戏下载地址: https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj\033[0m" echo -e "\033[0;32m进入游戏连接:\033[93m $ipv4_address:25565 $ipv6_address:25565 \033[0;32m开始冒险吧!\033[0m" @@ -114,11 +114,9 @@ mc_install_status() { container_status="\e[90mMinecraft服务未安装\e[0m" # 灰色 fi - SESSION_NAME="mc1" - ip_address - # 检查 tmux 中是否存在指定的工作区 - if tmux has-session -t $SESSION_NAME 2>/dev/null; then + # 检查 Docker 容器是否正在运行 + if docker ps --format "table {{.Names}}" | grep -q "^$CONTAINER_NAME$"; then tmux_status="\e[32m已开服:\033[93m $ipv4_address:25565 $ipv6_address:25565 \e[0m" # 绿色 else tmux_status="\e[90m未开服\e[0m" # 灰色 @@ -129,15 +127,14 @@ mc_install_status() { while true; do clear mc_install_status -echo -e "\033[93m . . ." -echo "███╗ ███╗██╗███╗ ██╗███████╗ ██████╗██████╗ █████╗ ███████╗████████╗" -echo "████╗ ████║██║████╗ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝" -echo "██╔████╔██║██║██╔██╗ ██║█████╗ ██║ ██████╔╝███████║█████╗ ██║ " -echo "██║╚██╔╝██║██║██║╚██╗██║██╔══╝ ██║ ██╔══██╗██╔══██║██╔══╝ ██║ " -echo "██║ ╚═╝ ██║██║██║ ╚████║███████╗╚██████╗██║ ██║██║ ██║██║ ██║ " -echo "╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ " -echo -e "\033[96mMinecraft开服一键脚本工具v1.0.0 by AkarinLiu\033[0m" -echo -e "\033[96m-输入\033[93mp\033[96m可快速启动此脚本-\033[0m" +echo -e "\033[92m███╗ ███╗██╗███╗ ██╗███████╗ ██████╗██████╗ █████╗ ███████╗████████╗\033[0m" +echo -e "\033[92m████╗ ████║██║████╗ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝\033[0m" +echo -e "\033[92m██╔████╔██║██║██╔██╗ ██║█████╗ ██║ ██████╔╝███████║█████╗ ██║ \033[0m" +echo -e "\033[92m██║╚██╔╝██║██║██║╚██╗██║██╔══╝ ██║ ██╔══██╗██╔══██║██╔══╝ ██║ \033[0m" +echo -e "\033[92m██║ ╚═╝ ██║██║██║ ╚████║███████╗╚██████╗██║ ██║██║ ██║██║ ██║ \033[0m" +echo -e "\033[92m╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ \033[0m" +echo -e "\033[92mMinecraft开服一键脚本工具v1.0.1 by AkarinLiu\033[0m" +echo -e "\033[92m-输入\033[92mp\033[92m可快速启动此脚本-\033[0m" echo -e "$container_status $tmux_status" echo "------------------------" echo "1. 安装Minecraft服务" @@ -153,6 +150,8 @@ echo "8. 导入游戏存档" echo "9. 定时备份游戏存档" echo "------------------------" echo "10. 修改游戏配置" +echo "o. 添加管理员权限" +echo "p. 删除管理员权限" echo "------------------------" echo "11. 更新Minecraft服务" echo "12. 卸载Minecraft服务" @@ -169,8 +168,7 @@ case $choice in 1) clear install_docker - install tmux - docker create -d --name $CONTAINER_NAME -p 25565:25565/tcp --restart=always -e EULA=true -v mcserver:/data:rw itzg/minecraft-server + docker run -d --name mcserver -p 25565:25565/tcp --restart=always -e EULA=true -e CREATE_CONSOLE_IN_PIPE=true -v mcserver:/data:rw itzg/minecraft-server clear mc_start ;; @@ -183,14 +181,12 @@ case $choice in 3) clear - tmux kill-session -t mc1 docker stop $CONTAINER_NAME > /dev/null 2>&1 echo -e "\033[0;32mMinecraft服务已关闭\033[0m" ;; 4) clear - tmux kill-session -t mc1 docker restart $CONTAINER_NAME > /dev/null 2>&1 mc_start ;; @@ -273,15 +269,14 @@ case $choice in docker cp $CONTAINER_NAME:/data/world /home/game/mc/ > /dev/null 2>&1 cd /home/game && tar czvf mcsave_$(date +"%Y%m%d%H%M%S").tar.gz mc > /dev/null 2>&1 rm -rf /home/game/mc/ - echo -e "\033[0;32m游戏存档已导出存放在: /home/game/\033[0m" + echo -e "\033[0;32m游戏存档已导出存放在: /home/game/mc/\033[0m" ;; 8) clear - tmux kill-session -t mc1 + docker stop mcserver > /dev/null 2>&1 docker exec -it mcserver bash -c "rm -rf /data/world/*" - cd /home/game/ && ls -t /home/game/mc/mcsave_*.tar.gz | head -1 | xargs -I {} tar -xzf {} - docker cp /home/game/mc/world/* mcserver: - docker exec -it -u root $CONTAINER_NAME bash -c "chmod -R 777 /home/steam/Steam/steamapps/common/mcServer/mc/Saved/" + cd /home/game/ && ls -t /home/game/mc/*.tar.gz | head -1 | xargs -I {} tar -xzf {} + docker cp /home/game/mc/world/* mcserver:/data/world rm -rf /home/game/mc/ echo -e "\033[0;32m游戏存档已导入\033[0m" docker restart mcserver > /dev/null 2>&1 @@ -322,43 +317,40 @@ case $choice in 10) clear - tmux kill-session -t mc1 - cd ~ && curl -sS -O https://kejilion.pro/mcSettings.ini - echo "配置游戏参数" echo "------------------------" - read -p "设置加入的密码(回车默认无密码): " server_password - read -p "设置游戏难度: (1. 简单 2. 普通 3. 困难):" Difficulty + read -p "设置游戏难度: (0.和平 1. 简单 2. 普通 3. 困难):" Difficulty case $Difficulty in + 0) + docker exec --user 1000 mcserver mc-send-to-console difficulty peaceful + ;; 1) - Difficulty=1 + docker exec --user 1000 mcserver mc-send-to-console difficulty easy ;; 2) - Difficulty=2 + docker exec --user 1000 mcserver mc-send-to-console difficulty normal ;; 3) - Difficulty=3 + docker exec --user 1000 mcserver mc-send-to-console difficulty hard ;; *) echo "-默认设置为普通难度" - Difficulty=2 + docker exec --user 1000 mcserver mc-send-to-console difficulty normal ;; esac - read -p "经验值倍率: (回车默认1倍):" exp_rate - ExpRate=${exp_rate:-1} read -p "死亡后掉落设置: (1. 掉落 2. 不掉落):" DeathPenalty case $DeathPenalty in 1) - DeathPenalty=All + docker exec --user 1000 mcserver mc-send-to-console gamerule KeepInventoy false ;; 2) - DeathPenalty=None + docker exec --user 1000 mcserver mc-send-to-console gamerule KeepInventoy true ;; *) - DeathPenalty=All + docker exec --user 1000 mcserver mc-send-to-console gamerule KeepInventoy false echo "-默认设置为掉落" ;; esac @@ -367,40 +359,25 @@ case $choice in case $mc_pvp in 1) - mc_pvp=True + docker exec --user 1000 mcserver mc-send-to-console gamerule pvp true ;; 2) - mc_pvp=False + docker exec --user 1000 mcserver mc-send-to-console gamerule pvp false ;; *) - mc_pvp=False + docker exec --user 1000 mcserver mc-send-to-console gamerule pvp false echo "-默认关闭pvp模式" ;; esac - # 更新配置文件 - sed -i "s/ServerPassword=\"\"/ServerPassword=\"$server_password\"/" ~/mcSettings.ini - sed -i "s/Difficulty=2/Difficulty=$Difficulty/" ~/mcSettings.ini - sed -i "s/ExpRate=1.000000/ExpRate=$ExpRate/" ~/mcSettings.ini - sed -i "s/DeathPenalty=All/DeathPenalty=$DeathPenalty/" ~/mcSettings.ini - sed -i "s/bEnablePlayerToPlayerDamage=False/bEnablePlayerToPlayerDamage=$mc_pvp/" ~/mcSettings.ini - sed -i "s/bIsPvP=False/bIsPvP=$mc_pvp/" ~/mcSettings.ini - echo "------------------------" - echo "配置文件已更新" - - docker exec -it mcserver bash -c "rm -f /home/steam/Steam/steamapps/common/mcServer/mc/Saved/Config/LinuxServer/mcSettings.ini" - docker cp ~/mcSettings.ini mcserver:/home/steam/Steam/steamapps/common/mcServer/mc/Saved/Config/LinuxServer/ > /dev/null 2>&1 - docker exec -it -u root $CONTAINER_NAME bash -c "chmod -R 777 /home/steam/Steam/steamapps/common/mcServer/mc/Saved/" - rm -f ~/mcSettings.ini - echo -e "\033[0;32m游戏配置已导入\033[0m" - docker restart mcserver > /dev/null 2>&1 - mc_start + # 更新配置 + echo -e "\033[0;32m游戏配置已更改\033[0m" ;; 11) clear - tmux kill-session -t mc1 + docker stop mcserver > /dev/null 2>&1 docker restart mcserver > /dev/null 2>&1 docker exec -it mcserver bash -c "/home/steam/mcserver/mcserver.sh +login anonymous +app_update 2394010 validate +quit" clear @@ -411,9 +388,16 @@ case $choice in 12) clear docker rm -f mcserver - docker rmi -f cm2network/mcserver + docker rmi -f itzg/minecraft-server ;; - + o) + read -p "请输入 Minecraft Java 版档案名称:" mc_op + docker exec --user 1000 mcserver mc-send-to-console op $mc_op + ;; + p) + read -p "请输入 Minecraft Java 版档案名称:" mc_deop + docker exec --user 1000 mcserver mc-send-to-console deop $mc_deop + ;; k) cd ~ curl -sS -O https://kejilion.pro/kejilion.sh && chmod +x kejilion.sh && ./kejilion.sh diff --git a/mc_backup.sh b/mc_backup.sh index 2f0515202..a996cc18d 100644 --- a/mc_backup.sh +++ b/mc_backup.sh @@ -2,6 +2,6 @@ clear mkdir -p /home/game docker cp mcserver:/data /home/game/mc -cd /home/game && tar czvf mc_$(date +"%Y%m%d%H%M%S").tar.gz mc +cd /home/game/mc && tar czvf mc_$(date +"%Y%m%d%H%M%S").tar.gz mc rm -rf /home/game/mc/ -echo -e "\033[0;32m游戏存档已导出存放在: /home/game/\033[0m" \ No newline at end of file +echo -e "\033[0;32m游戏存档已导出存放在: /home/game/mc/\033[0m" diff --git a/mc_log.sh b/mc_log.sh new file mode 100644 index 000000000..0023e118d --- /dev/null +++ b/mc_log.sh @@ -0,0 +1,7 @@ + clear + echo "脚本更新日志" + echo "------------------------" + echo "2025-11-16 v1.0.1" + echo "Minecraft 开服脚本魔改自 幻兽帕鲁开服脚本" + echo "2025-11-17 v1.0.1" + ech "对 Minecraft 的难度等细节进行了适配" From 1217abeeee41474da06b3c3b6f03d98f1a4ea4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:32:08 +0800 Subject: [PATCH 0372/1285] Update kejilion.sh --- cn/kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b1041c15a..54987310e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.5" gl_hui='\e[37m' @@ -14758,6 +14758,7 @@ echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}m. ${gl_bai}我的世界开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14787,6 +14788,10 @@ case $choice in curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; + m) send_stats "我的世界开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "无效的输入!" ;; From e039dadd6b3eb27f0e29a1d9f7c5b882f16dbdb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:32:54 +0800 Subject: [PATCH 0373/1285] Update kejilion.sh --- kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index bc9b4413c..24f114eb3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.5" gl_hui='\e[37m' @@ -14758,6 +14758,7 @@ echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" +echo -e "${gl_kjlan}m. ${gl_bai}我的世界开服脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14787,6 +14788,10 @@ case $choice in curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; + m) send_stats "我的世界开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "无效的输入!" ;; From 9401aa1d1f2aa63f99d4469d5e89630d53200d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:36:42 +0800 Subject: [PATCH 0374/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c94a568e6..ea621a9f7 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1356,4 +1356,7 @@ LDNMP安装环境时对mysql进行优化。 LDNMP环境中redis去除了不必要的清理机制。 LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 ------------------------ +2025-11-17 v4.2.5 +新增我的世界开服脚本工具,感谢阿卡林刘大佬进行适配,有我的世界开服需求的可以试试。 +------------------------ From 058d85ac2f1209ed853eeec6159cca3585da0c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:49:48 +0800 Subject: [PATCH 0375/1285] Add game server tools function and update menu Added a new function for game server scripts and updated the main menu to include it. --- cn/kejilion.sh | 74 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 54987310e..b16109b88 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8029,6 +8029,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -14636,6 +14639,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "游戏开服脚本合集" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}幻兽帕鲁开服脚本" + echo -e "${gl_kjlan}2. ${gl_bai}我的世界开服脚本" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "请输入你的选择: " sub_choice + + case $sub_choice in + + 1) send_stats "幻兽帕鲁开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "我的世界开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "无效的输入!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14756,9 +14817,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" echo -e "${gl_kjlan}13. ${gl_bai}系统工具" echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" -echo -e "${gl_kjlan}m. ${gl_bai}我的世界开服脚本" +echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14784,14 +14843,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; - m) send_stats "我的世界开服脚本" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "无效的输入!" ;; From 1b773cb2dc8a4f402d23d69deffc4bf9f2bc8337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:50:26 +0800 Subject: [PATCH 0376/1285] Add game server tools function and menu option Added a new function for game server tools and updated the main menu to include it. --- kejilion.sh | 74 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 24f114eb3..57765bb65 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8029,6 +8029,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -14636,6 +14639,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "游戏开服脚本合集" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}幻兽帕鲁开服脚本" + echo -e "${gl_kjlan}2. ${gl_bai}我的世界开服脚本" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "请输入你的选择: " sub_choice + + case $sub_choice in + + 1) send_stats "幻兽帕鲁开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "我的世界开服脚本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "无效的输入!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14756,9 +14817,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" echo -e "${gl_kjlan}13. ${gl_bai}系统工具" echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻兽帕鲁开服脚本" -echo -e "${gl_kjlan}m. ${gl_bai}我的世界开服脚本" +echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14784,14 +14843,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻兽帕鲁开服脚本" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; - m) send_stats "我的世界开服脚本" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "无效的输入!" ;; From 60796e84b88f646b54fdef818cd9db8afef722a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:29:06 +0800 Subject: [PATCH 0377/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ea621a9f7..1eea5bbde 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1358,5 +1358,6 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 ------------------------ 2025-11-17 v4.2.5 新增我的世界开服脚本工具,感谢阿卡林刘大佬进行适配,有我的世界开服需求的可以试试。 +主菜单新增游戏开服脚本合集,将幻兽帕鲁和我的世界的开服脚本加入合集。 ------------------------ From 98764cd0cff5ba802647d0fea8d0338dc58a0588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:43:33 +0800 Subject: [PATCH 0378/1285] Add TCP and UDP connection counts to output --- cn/kejilion.sh | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b16109b88..6ba3a2cca 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6732,43 +6732,47 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo From c5f457371ef2d41661e7fad6b9d6ebd833c823f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:44:02 +0800 Subject: [PATCH 0379/1285] Update kejilion.sh --- kejilion.sh | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 57765bb65..4aa57657c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6732,43 +6732,47 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo From ba973d03f6851f4b9f34fdec9a5895ca5ebccaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:45:29 +0800 Subject: [PATCH 0380/1285] Update kejilion_sh_log with new features Added TCP/UDP current connection count display to system query. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1eea5bbde..4f34eced9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1359,5 +1359,6 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 2025-11-17 v4.2.5 新增我的世界开服脚本工具,感谢阿卡林刘大佬进行适配,有我的世界开服需求的可以试试。 主菜单新增游戏开服脚本合集,将幻兽帕鲁和我的世界的开服脚本加入合集。 +系统查询中添加TCP|UDP当前连接数显示。 ------------------------ From 476f31919777706f13a5baf8f8a2f50f8becba4e Mon Sep 17 00:00:00 2001 From: AkarinLiu Date: Mon, 17 Nov 2025 17:26:31 +0800 Subject: [PATCH 0381/1285] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20IP=20=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=99=BA=E8=83=BD=E6=A3=80=E6=B5=8B=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E7=94=B1=20DeepSeek=20=E6=8F=90=E4=BE=9B=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mc.sh | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/mc.sh b/mc.sh index f79a7b3ca..839aad603 100644 --- a/mc.sh +++ b/mc.sh @@ -2,8 +2,21 @@ ln -sf ~/minecraft_server.sh /usr/local/bin/mcs ip_address() { -ipv4_address=$(curl -s ipv4.ip.sb) -ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + # 检测 IPv4 地址 + ipv4_address=$(curl -s --connect-timeout 5 ipv4.ip.sb 2>/dev/null || echo "") + # 检测 IPv6 地址 + ipv6_address=$(curl -s --connect-timeout 5 ipv6.ip.sb 2>/dev/null || echo "") + + # 设置显示变量 + if [ -n "$ipv4_address" ] && [ -n "$ipv6_address" ]; then + ip_display="\033[93m IPv4: $ipv4_address:25565 IPv6: $ipv6_address:25565 \033[0m" + elif [ -n "$ipv4_address" ]; then + ip_display="\033[93m IPv4: $ipv4_address:25565 \033[0m" + elif [ -n "$ipv6_address" ]; then + ip_display="\033[93m IPv6: $ipv6_address:25565 \033[0m" + else + ip_display="\033[93m 无法获取IP地址 \033[0m" + fi } @@ -95,7 +108,7 @@ mc_start() { docker start mcserver > /dev/null 2>&1 echo -e "\033[0;32mMinecraft服务启动啦!\033[0m" echo -e "\033[0;32m游戏下载地址: https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj\033[0m" - echo -e "\033[0;32m进入游戏连接:\033[93m $ipv4_address:25565 $ipv6_address:25565 \033[0;32m开始冒险吧!\033[0m" + echo -e "\033[0;32m进入游戏连接:$ip_display\033[0;32m开始冒险吧!\033[0m" } @@ -117,7 +130,7 @@ mc_install_status() { ip_address # 检查 Docker 容器是否正在运行 if docker ps --format "table {{.Names}}" | grep -q "^$CONTAINER_NAME$"; then - tmux_status="\e[32m已开服:\033[93m $ipv4_address:25565 $ipv6_address:25565 \e[0m" # 绿色 + tmux_status="\e[32m已开服:$ip_display\e[0m" # 绿色 else tmux_status="\e[90m未开服\e[0m" # 灰色 fi @@ -134,7 +147,7 @@ echo -e "\033[92m██║╚██╔╝██║██║██║╚██╗ echo -e "\033[92m██║ ╚═╝ ██║██║██║ ╚████║███████╗╚██████╗██║ ██║██║ ██║██║ ██║ \033[0m" echo -e "\033[92m╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ \033[0m" echo -e "\033[92mMinecraft开服一键脚本工具v1.0.1 by AkarinLiu\033[0m" -echo -e "\033[92m-输入\033[92mp\033[92m可快速启动此脚本-\033[0m" +echo -e "\033[92m-输入\033[92mmcs\033[92m可快速启动此脚本-\033[0m" echo -e "$container_status $tmux_status" echo "------------------------" echo "1. 安装Minecraft服务" From aff1bdd4a005f4fe0ff7460043afeefc648b58ba Mon Sep 17 00:00:00 2001 From: AkarinLiu Date: Mon, 17 Nov 2025 17:31:00 +0800 Subject: [PATCH 0382/1285] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mc.sh b/mc.sh index 839aad603..b622b4b6f 100644 --- a/mc.sh +++ b/mc.sh @@ -1,5 +1,5 @@ #!/bin/bash -ln -sf ~/minecraft_server.sh /usr/local/bin/mcs +ln -sf ~/mc.sh /usr/local/bin/mcs ip_address() { # 检测 IPv4 地址 From 40642e8903c7caca7241e86ce41d3724b3595dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 18 Nov 2025 20:09:07 +0800 Subject: [PATCH 0383/1285] Fix make command in OpenSSH upgrade script --- upgrade_openssh9.8p1.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upgrade_openssh9.8p1.sh b/upgrade_openssh9.8p1.sh index 8bd19bd14..78b5d7138 100644 --- a/upgrade_openssh9.8p1.sh +++ b/upgrade_openssh9.8p1.sh @@ -64,13 +64,13 @@ install_openssh() { ./configure - make -j${nproc} + make make install } # 重启SSH服务 restart_ssh() { - case $OS 在 + case $OS in ubuntu|debian) systemctl restart ssh ;; From 5b90987e50bb31c64e684a50a882c6f4ca90d19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:04:31 +0800 Subject: [PATCH 0384/1285] Update kejilion.sh --- cn/kejilion.sh | 86 ++++++++++++++------------------------------------ 1 file changed, 23 insertions(+), 63 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6ba3a2cca..0ef67e646 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.5" +sh_v="4.2.6" gl_hui='\e[37m' @@ -417,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -436,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}正在安装docker环境...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn From 8a26e3e0073cbfeab94c50f095c6ea4a505c48ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:05:50 +0800 Subject: [PATCH 0385/1285] Update kejilion.sh --- kejilion.sh | 86 ++++++++++++++--------------------------------------- 1 file changed, 23 insertions(+), 63 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 4aa57657c..8db81133c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.5" +sh_v="4.2.6" gl_hui='\e[37m' @@ -417,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -436,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}正在安装docker环境...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn From 67b53265a1e84957de406ab833fa33af6d848718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:09:44 +0800 Subject: [PATCH 0386/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4f34eced9..f846ff5a6 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1361,4 +1361,8 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 主菜单新增游戏开服脚本合集,将幻兽帕鲁和我的世界的开服脚本加入合集。 系统查询中添加TCP|UDP当前连接数显示。 ------------------------ +2025-11-19 v4.2.6 +安装docker环境采用更加成熟的linuxmirrors解决方案。提升安装兼容性和稳定性。 +------------------------ + From 1183005cd1acda0a97caff3ca330697844364ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:17:28 +0800 Subject: [PATCH 0387/1285] Update kejilion.sh --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0ef67e646..f0b2b016e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14009,7 +14009,7 @@ EOF echo "一条龙系统调优" echo "------------------------------------------------" echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" + echo "1. 优化系统更新源,更新系统到最新" echo "2. 清理系统垃圾文件" echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" @@ -14029,6 +14029,7 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" From 28f5ffc4d8b0326be26020feb0ea8bf597488167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:18:59 +0800 Subject: [PATCH 0388/1285] Enhance system update message in kejilion.sh --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 8db81133c..97c4709e2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14009,7 +14009,7 @@ EOF echo "一条龙系统调优" echo "------------------------------------------------" echo "将对以下内容进行操作与优化" - echo "1. 更新系统到最新" + echo "1. 优化系统更新源,更新系统到最新" echo "2. 清理系统垃圾文件" echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" @@ -14029,6 +14029,7 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" From 25c6669660bb8de1edf3d577f0741c66a16b12d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:20:18 +0800 Subject: [PATCH 0389/1285] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=B9=B6=E6=9B=B4=E6=96=B0=E8=87=B3=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化系统工具并更新系统源至最新版本。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f846ff5a6..9d2ebca2d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1363,6 +1363,7 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 ------------------------ 2025-11-19 v4.2.6 安装docker环境采用更加成熟的linuxmirrors解决方案。提升安装兼容性和稳定性。 +系统工具一条龙优化增加了对系统源的优化,并将系统更新到最新。 ------------------------ From bafdf790e395c455662dc114d56808eab56a7969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:56:48 +0800 Subject: [PATCH 0390/1285] Rename function and update MySQL configuration checks --- cn/kejilion.sh | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f0b2b016e..e9fd323b2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2179,19 +2179,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + MYSQL_CONTAINER="mysql" + MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# 获取当前的 worker_processes 设置值 -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# 根据值设置模式信息 -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # 检查 MySQL 配置文件中是否包含 4096M + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2200,7 +2198,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2229,7 +2227,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "优化LDNMP环境" From 5bc4c04860ab9b43287ab926910865d72b7832b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:58:42 +0800 Subject: [PATCH 0391/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e9fd323b2..3036c80d8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2181,8 +2181,8 @@ web_security() { check_ldnmp_mode() { - MYSQL_CONTAINER="mysql" - MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" # 检查 MySQL 配置文件中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then From 4eec1e28cb41e91833315d9d3cc90f8912b09cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:59:16 +0800 Subject: [PATCH 0392/1285] Rename check_nginx_mode to check_ldnmp_mode --- kejilion.sh | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 97c4709e2..12f382ca1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2179,19 +2179,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# 获取当前的 worker_processes 设置值 -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# 根据值设置模式信息 -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # 检查 MySQL 配置文件中是否包含 4096M + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2200,7 +2198,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2229,7 +2227,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "优化LDNMP环境" From 2fff7c1a0c7f0e276b1f2aabd360501a5b5ac786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:00:21 +0800 Subject: [PATCH 0393/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 9d2ebca2d..8bc0af1a1 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1364,6 +1364,7 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 2025-11-19 v4.2.6 安装docker环境采用更加成熟的linuxmirrors解决方案。提升安装兼容性和稳定性。 系统工具一条龙优化增加了对系统源的优化,并将系统更新到最新。 +优化LDNMP环境中高性能模式无法切换的问题进行修复。 ------------------------ From 7b23303483b8acc3fae54890c47db31859555848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:49:10 +0800 Subject: [PATCH 0394/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3036c80d8..87e939835 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -235,7 +235,7 @@ check_disk_space() { install_dependency() { - switch_mirror true true + switch_mirror false false check_port check_swap prefer_ipv4 From 84ad393a109a09984b71b69a22ec2e8d3bc12597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:49:42 +0800 Subject: [PATCH 0395/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 12f382ca1..42c1037dd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -235,7 +235,7 @@ check_disk_space() { install_dependency() { - switch_mirror true true + switch_mirror false false check_port check_swap prefer_ipv4 From 3f16fc8dc6724df4a3b5935e57a498454a6037c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:56:15 +0800 Subject: [PATCH 0396/1285] Implement patch_wp_url function for WordPress config Add patch_wp_url function to update WP_HOME and WP_SITEURL in wp-config.php files. --- cn/kejilion.sh | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 87e939835..3b8757ec2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1846,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # 删除旧定义 + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # 生成插入内容 + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # 插入到 “Happy publishing” 之前 + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -3241,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3602,15 +3640,12 @@ ldnmp_web_status() { install_ssltls certs_status - # mysql替换 - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3629,9 +3664,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; From 9b1910b13ee7552c573f8048f7f671b2a33d9896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:56:51 +0800 Subject: [PATCH 0397/1285] Implement patch_wp_url function for WordPress config Add patch_wp_url function to update WP_HOME and WP_SITEURL in wp-config.php files. --- kejilion.sh | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 42c1037dd..17786c06c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1846,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # 删除旧定义 + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # 生成插入内容 + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # 插入到 “Happy publishing” 之前 + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -3241,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3602,15 +3640,12 @@ ldnmp_web_status() { install_ssltls certs_status - # mysql替换 - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3629,9 +3664,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; From 59dfc14d808af3a4d38e85ef7f25f0f3eadbac9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 20 Nov 2025 21:03:35 +0800 Subject: [PATCH 0398/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8bc0af1a1..9aa252599 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1365,6 +1365,7 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 安装docker环境采用更加成熟的linuxmirrors解决方案。提升安装兼容性和稳定性。 系统工具一条龙优化增加了对系统源的优化,并将系统更新到最新。 优化LDNMP环境中高性能模式无法切换的问题进行修复。 +LDNMP初始化时新增URL绑定,提升wordpress安装向导的稳定性。 ------------------------ From f51045c2bf431b886aea844743d6dc530c2c682c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:52:18 +0800 Subject: [PATCH 0399/1285] Update prompt for reverse proxy IP input --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3b8757ec2..ba1cb2023 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3299,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then From 916194716f2540549efa115af41f12bc03ff0287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:53:21 +0800 Subject: [PATCH 0400/1285] Update kejilion.sh --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 17786c06c..dc3ab3660 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3299,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP: " reverseproxy + read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then From bcb2933287827e8a89896066b8354780f4e74e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:55:46 +0800 Subject: [PATCH 0401/1285] Enhance reverse proxy IP input functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化反向代理IP端口功能,简化用户输入。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 9aa252599..402b72ee2 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1366,6 +1366,7 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 系统工具一条龙优化增加了对系统源的优化,并将系统更新到最新。 优化LDNMP环境中高性能模式无法切换的问题进行修复。 LDNMP初始化时新增URL绑定,提升wordpress安装向导的稳定性。 +反向代理IP+端口功能优化,输入反代IP时回车可默认选择本机IP 127.0.0.1省去额外输入的麻烦。 ------------------------ From c41924add1ca5f82da1d7b23de42cc29f3a557b1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 23 Nov 2025 04:48:53 +0000 Subject: [PATCH 0402/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-23=2004:48:53?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 281 +++++++++++++++++++++++++++------------------- jp/kejilion.sh | 299 +++++++++++++++++++++++++++++-------------------- kr/kejilion.sh | 287 ++++++++++++++++++++++++++++------------------- tw/kejilion.sh | 251 ++++++++++++++++++++++++----------------- 4 files changed, 661 insertions(+), 457 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 9221ad3b3..27b2e33c9 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.6" gl_hui='\e[37m' @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror false false + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -416,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -435,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}Installing docker environment...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn @@ -920,7 +881,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1466,8 +1427,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" @@ -1638,7 +1599,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -1884,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # Delete old definition + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # Generate insert content + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # Insert before “Happy publishing” + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -2217,19 +2216,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# Get the current worker_processes setting value -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# Set mode information based on value -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # Check if MySQL configuration file contains 4096M + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2238,7 +2235,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2267,7 +2264,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "Optimize LDNMP environment" @@ -3176,7 +3173,6 @@ root_use clear echo -e "${gl_huang}The LDNMP environment is not installed. Start installing the LDNMP environment...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3189,6 @@ root_use clear echo -e "${gl_huang}nginx is not installed, start installing nginx environment...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -3283,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3303,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "Please enter your anti-generation IP:" reverseproxy + read -e -p "Please enter your anti-generation IP (press Enter to default to the local IP 127.0.0.1):" reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then @@ -3644,15 +3641,12 @@ ldnmp_web_status() { install_ssltls certs_status - # mysql replacement - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3671,9 +3665,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; @@ -4704,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" } @@ -4747,14 +4738,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -5022,7 +5013,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5556,7 +5547,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -6732,6 +6723,9 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "System information query" @@ -6747,6 +6741,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU usage:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}System load:${gl_bai}$load" + echo -e "${gl_kjlan}Number of TCP|UDP connections:${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" echo -e "${gl_kjlan}Hard drive usage:${gl_bai}$disk_info" @@ -6781,7 +6776,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" @@ -7356,7 +7351,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8029,6 +8024,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -8853,7 +8851,6 @@ linux_ldnmp() { echo -e "${gl_huang}Unzipping$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8986,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot @@ -9415,7 +9411,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -12776,7 +12772,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -12787,7 +12783,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -13260,7 +13256,7 @@ EOF 2) rm -f /etc/gai.conf echo "Switched to IPv6 first" - send_stats "Switched to IPv6 priority" + send_stats "Switched to IPv6 first" ;; 3) @@ -13802,7 +13798,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -14044,7 +14040,7 @@ EOF echo "One-stop system tuning" echo "------------------------------------------------" echo "The following content will be operated and optimized" - echo "1. Update the system to the latest" + echo "1. Optimize the system update source and update the system to the latest" echo "2. Clean up system junk files" echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" @@ -14064,6 +14060,7 @@ EOF clear send_stats "One-stop tuning starts" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. Update the system to the latest" @@ -14497,7 +14494,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14614,7 +14611,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14638,6 +14635,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "Collection of game server opening scripts" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}Eudemons Parlu server opening script" + echo -e "${gl_kjlan}2. ${gl_bai}Minecraft server opening script" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "Please enter your choice:" sub_choice + + case $sub_choice in + + 1) send_stats "Eudemons Parlu server opening script" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "Minecraft server opening script" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "Invalid input!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14758,8 +14813,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}Backend workspace" echo -e "${gl_kjlan}13. ${gl_bai}system tools" echo -e "${gl_kjlan}14. ${gl_bai}Server cluster control" echo -e "${gl_kjlan}15. ${gl_bai}Advertising column" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu server opening script" +echo -e "${gl_kjlan}16. ${gl_bai}Collection of game server opening scripts" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14785,10 +14839,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Eudemons Parlu server opening script" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "Invalid input!" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 527ff1dc4..890c94315 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.6" gl_hui='\e[37m' @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror false false + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -416,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -435,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}Docker 環境をインストールしています...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn @@ -897,12 +858,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -1466,8 +1427,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" @@ -1638,7 +1599,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -1884,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # 古い定義を削除する + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # 挿入コンテンツの生成 + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # 「出版おめでとうございます」の前に挿入 + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -2153,7 +2152,7 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -2217,19 +2216,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# 現在のworker_processes設定値を取得します -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# 値に基づいてモード情報を設定します -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # MySQL 設定ファイルに 4096M が含まれているかどうかを確認する + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2238,7 +2235,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2267,7 +2264,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "LDNMP環境の最適化" @@ -3176,7 +3173,6 @@ root_use clear echo -e "${gl_huang}LDNMP環境がインストールされていません。 LDNMP 環境のインストールを開始します...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3189,6 @@ root_use clear echo -e "${gl_huang}nginx がインストールされていません。nginx 環境のインストールを開始してください...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -3283,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3303,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "アンチジェネレーション IP を入力してください:" reverseproxy + read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すと、デフォルトのローカル IP 127.0.0.1 になります)。" reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then @@ -3520,7 +3517,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3644,15 +3641,12 @@ ldnmp_web_status() { install_ssltls certs_status - # mysqlの置換 - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3671,9 +3665,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; @@ -4586,7 +4577,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4704,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" } @@ -4747,14 +4738,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion } @@ -5383,7 +5374,7 @@ clamav() { while true; do clear echo "Clamav ウイルス スキャン ツール" - echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "これは、主にさまざまな種類のマルウェアを検出して削除するために使用されるオープンソースのウイルス対策ソフトウェア ツールです。" echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアが含まれます。" @@ -6363,7 +6354,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6732,6 +6723,9 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "システム情報の問い合わせ" @@ -6747,6 +6741,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU使用率:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}システム負荷:${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP 接続の数:${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}物理メモリ:${gl_bai}$mem_info" echo -e "${gl_kjlan}仮想メモリ:${gl_bai}$swap_info" echo -e "${gl_kjlan}ハードドライブの使用状況:${gl_bai}$disk_info" @@ -6781,7 +6776,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -7157,7 +7152,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7356,7 +7351,7 @@ docker_ssh_migration() { echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7430,7 +7425,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7573,7 +7568,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8029,6 +8024,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -8853,7 +8851,6 @@ linux_ldnmp() { echo -e "${gl_huang}解凍中$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8986,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot @@ -12776,7 +12772,7 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" @@ -12787,7 +12783,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -13259,8 +13255,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -13802,7 +13798,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -14044,7 +14040,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムを最新のものにアップデートします" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14064,6 +14060,7 @@ EOF clear send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}】1/12。システムを最新のものにアップデートする" @@ -14492,12 +14489,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14530,7 +14527,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14638,6 +14635,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "ゲームサーバー起動スクリプト集" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}Eudemons Parlu サーバー開始スクリプト" + echo -e "${gl_kjlan}2. ${gl_bai}Minecraft サーバーを開くスクリプト" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "選択肢を入力してください:" sub_choice + + case $sub_choice in + + 1) send_stats "Eudemons Parlu サーバー開始スクリプト" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "Minecraft サーバーを開くスクリプト" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "無効な入力です!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14758,8 +14813,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}バックエンドワークスペース" echo -e "${gl_kjlan}13. ${gl_bai}システムツール" echo -e "${gl_kjlan}14. ${gl_bai}サーバークラスタ制御" echo -e "${gl_kjlan}15. ${gl_bai}広告コラム" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu サーバー開始スクリプト" +echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14785,10 +14839,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Eudemons Parlu サーバー開始スクリプト" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "無効な入力です!" ;; @@ -14806,7 +14857,7 @@ echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 056abd24f..702be9f86 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.6" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror false false + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -416,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -435,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}도커 환경 설치 중...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn @@ -1129,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1466,8 +1427,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" @@ -1638,7 +1599,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -1884,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # 이전 정의 삭제 + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # 삽입 콘텐츠 생성 + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # '행복한 출판' 앞에 삽입 + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -2217,19 +2216,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# 현재 작업자_프로세스 설정 값을 가져옵니다. -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# 값에 따라 모드 정보 설정 -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # MySQL 구성 파일에 4096M이 포함되어 있는지 확인하세요. + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2238,7 +2235,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2267,7 +2264,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "LDNMP 환경 최적화" @@ -2803,7 +2800,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3176,7 +3173,6 @@ root_use clear echo -e "${gl_huang}LDNMP 환경이 설치되지 않았습니다. LDNMP 환경 설치를 시작합니다...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3189,6 @@ root_use clear echo -e "${gl_huang}nginx가 설치되지 않았습니다. nginx 환경 설치를 시작하세요...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -3283,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3303,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "세대방지 IP를 입력해주세요:" reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then @@ -3644,15 +3641,12 @@ ldnmp_web_status() { install_ssltls certs_status - # MySQL 교체 - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3671,9 +3665,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; @@ -4704,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -6363,7 +6354,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6732,6 +6723,9 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "시스템 정보 쿼리" @@ -6747,6 +6741,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 사용량:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP 연결 수:${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" echo -e "${gl_kjlan}가상 메모리:${gl_bai}$swap_info" echo -e "${gl_kjlan}하드 드라이브 사용량:${gl_bai}$disk_info" @@ -7356,7 +7351,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7543,7 +7538,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8029,6 +8024,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -8853,7 +8851,6 @@ linux_ldnmp() { echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8986,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot @@ -9131,7 +9127,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" @@ -9335,7 +9331,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9415,7 +9411,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -12776,7 +12772,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -12787,7 +12783,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -13006,7 +13002,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13259,8 +13255,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -13561,7 +13557,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13802,7 +13798,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -14044,7 +14040,7 @@ EOF echo "원스톱 시스템 튜닝" echo "------------------------------------------------" echo "다음 콘텐츠가 운영 및 최적화됩니다." - echo "1. 시스템을 최신으로 업데이트하세요" + echo "1. 시스템 업데이트 소스를 최적화하고 시스템을 최신 버전으로 업데이트하세요." echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" @@ -14064,6 +14060,7 @@ EOF clear send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 시스템을 최신으로 업데이트하세요" @@ -14497,7 +14494,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14638,6 +14635,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "게임 서버 오프닝 스크립트 모음" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}Eudemons Parlu 서버 오픈 스크립트" + echo -e "${gl_kjlan}2. ${gl_bai}Minecraft 서버 열기 스크립트" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "선택사항을 입력하세요:" sub_choice + + case $sub_choice in + + 1) send_stats "Eudemons Parlu 서버 오픈 스크립트" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "Minecraft 서버 열기 스크립트" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "입력이 잘못되었습니다!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14758,8 +14813,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업공간" echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" echo -e "${gl_kjlan}15. ${gl_bai}광고 칼럼" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}Eudemons Parlu 서버 오픈 스크립트" +echo -e "${gl_kjlan}16. ${gl_bai}게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14785,10 +14839,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "Eudemons Parlu 서버 오픈 스크립트" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "입력이 잘못되었습니다!" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 5687c0c6e..f3e3243c5 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.4" +sh_v="4.2.6" gl_hui='\e[37m' @@ -235,11 +235,12 @@ check_disk_space() { install_dependency() { - install wget unzip tar jq grep - + switch_mirror false false + check_port check_swap - auto_optimize_dns prefer_ipv4 + auto_optimize_dns + install wget unzip tar jq grep } @@ -416,18 +417,31 @@ restart docker } -install_add_docker_guanfang() { + +linuxmirrors_install_docker() { + local country=$(curl -s ipinfo.io/country) if [ "$country" = "CN" ]; then - cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/install && chmod +x install - sh install --mirror Aliyun - rm -f install + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source mirrors.huaweicloud.com/docker-ce \ + --source-registry docker.1ms.run \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips else - curl -fsSL https://get.docker.com | sh + bash <(curl -sSL https://linuxmirrors.cn/docker.sh) \ + --source download.docker.com \ + --source-registry registry.hub.docker.com \ + --protocol https \ + --use-intranet-source false \ + --install-latest true \ + --close-firewall false \ + --ignore-backup-tips fi -install_add_docker_cn +install_add_docker_cn } @@ -435,61 +449,8 @@ install_add_docker_cn install_add_docker() { echo -e "${gl_huang}正在安裝docker環境...${gl_bai}" - if [ -f /etc/os-release ] && grep -q "Fedora" /etc/os-release; then - install_add_docker_guanfang - elif command -v dnf &>/dev/null; then - dnf update -y - dnf install -y yum-utils device-mapper-persistent-data lvm2 - rm -f /etc/yum.repos.d/docker*.repo > /dev/null - country=$(curl -s ipinfo.io/country) - arch=$(uname -m) - if [ "$country" = "CN" ]; then - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | tee /etc/yum.repos.d/docker-ce.repo > /dev/null - else - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo > /dev/null - fi - dnf install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - elif [ -f /etc/os-release ] && grep -q "Kali" /etc/os-release; then - apt update - apt upgrade -y - apt install -y apt-transport-https ca-certificates curl gnupg lsb-release - rm -f /usr/share/keyrings/docker-archive-keyring.gpg - local country=$(curl -s ipinfo.io/country) - local arch=$(uname -m) - if [ "$country" = "CN" ]; then - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/etc\/apt\/keyrings\/docker-archive-keyring.gpg\] https:\/\/mirrors.aliyun.com\/docker-ce\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - else - if [ "$arch" = "x86_64" ]; then - sed -i '/^deb \[arch=amd64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - elif [ "$arch" = "aarch64" ]; then - sed -i '/^deb \[arch=arm64 signed-by=\/usr\/share\/keyrings\/docker-archive-keyring.gpg\] https:\/\/download.docker.com\/linux\/debian bullseye stable/d' /etc/apt/sources.list.d/docker.list > /dev/null - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg > /dev/null - echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - fi - fi - apt update - apt install -y docker-ce docker-ce-cli containerd.io - install_add_docker_cn - - - elif command -v apt &>/dev/null || command -v yum &>/dev/null; then - install_add_docker_guanfang + if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then + linuxmirrors_install_docker else install docker docker-compose install_add_docker_cn @@ -1466,8 +1427,8 @@ install_certbot() { install_ssltls() { - docker stop nginx > /dev/null 2>&1 check_port > /dev/null 2>&1 + docker stop nginx > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" @@ -1638,7 +1599,8 @@ restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi > /dev/null 2>&1 docker exec php chown -R www-data:www-data /var/www/html > /dev/null 2>&1 docker exec php74 chown -R www-data:www-data /var/www/html > /dev/null 2>&1 - cd /home/web && docker compose restart nginx php php74 + cd /home/web && docker compose restart + } @@ -1884,6 +1846,43 @@ patch_wp_debug() { } + + +patch_wp_url() { + local HOME_URL="$1" + local SITE_URL="$2" + local TARGET_DIR="/home/web/html" + + find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + # 刪除舊定義 + sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" + sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" + + # 生成插入內容 + INSERT=" +define('WP_HOME', '$HOME_URL'); +define('WP_SITEURL', '$SITE_URL'); +" + + # 插入到 “Happy publishing” 之前 + awk -v insert="$INSERT" ' + /Happy publishing/ { + print insert + } + { print } + ' "$FILE" > "$FILE.tmp" && mv -f "$FILE.tmp" "$FILE" + + echo "[+] Updated WP_HOME and WP_SITEURL in $FILE" + done +} + + + + + + + + nginx_br() { local mode=$1 @@ -2217,19 +2216,17 @@ web_security() { -check_nginx_mode() { +check_ldnmp_mode() { -CONFIG_FILE="/home/web/nginx.conf" + local MYSQL_CONTAINER="mysql" + local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" -# 獲取當前的 worker_processes 設置值 -current_value=$(grep -E '^\s*worker_processes\s+[0-9]+;' "$CONFIG_FILE" | awk '{print $2}' | tr -d ';') - -# 根據值設置模式信息 -if [ "$current_value" = "8" ]; then - mode_info=" 高性能模式" -else - mode_info=" 标准模式" -fi + # 檢查 MySQL 配置文件中是否包含 4096M + if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then + mode_info=" 高性能模式" + else + mode_info=" 标准模式" + fi @@ -2238,7 +2235,7 @@ fi check_nginx_compression() { - CONFIG_FILE="/home/web/nginx.conf" + local CONFIG_FILE="/home/web/nginx.conf" # 檢查 zstd 是否開啟且未被註釋(整行以 zstd on; 開頭) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then @@ -2267,7 +2264,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_nginx_mode + check_ldnmp_mode check_nginx_compression clear send_stats "優化LDNMP環境" @@ -3176,7 +3173,6 @@ root_use clear echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" check_disk_space 3 /home -check_port install_dependency install_docker install_certbot @@ -3193,7 +3189,6 @@ root_use clear echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" check_disk_space 1 /home -check_port install_dependency install_docker install_certbot @@ -3283,6 +3278,7 @@ ldnmp_wp() { sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + patch_wp_url "https://$yuming" "https://$yuming" restart_ldnmp nginx_web_on @@ -3303,7 +3299,8 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "請輸入你的反代IP:" reverseproxy + read -e -p "請輸入你的反代IP (回車默認本機IP 127.0.0.1):" reverseproxy + reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then @@ -3644,15 +3641,12 @@ ldnmp_web_status() { install_ssltls certs_status - # mysql替換 - add_db + add_db local odd_dbname=$(echo "$oddyuming" | sed -e 's/[^A-Za-z0-9]/_/g') local odd_dbname="${odd_dbname}" docker exec mysql mysqldump -u root -p"$dbrootpasswd" $odd_dbname | docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname - # docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE $odd_dbname;" - local tables=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -D $dbname -e "SHOW TABLES;" | awk '{ if (NR>1) print $1 }') for table in $tables; do @@ -3671,9 +3665,6 @@ ldnmp_web_status() { cp /home/web/conf.d/$oddyuming.conf /home/web/conf.d/$yuming.conf sed -i "s/$oddyuming/$yuming/g" /home/web/conf.d/$yuming.conf - # rm /home/web/certs/${oddyuming}_key.pem - # rm /home/web/certs/${oddyuming}_cert.pem - cd /home/web && docker compose restart ;; @@ -6732,6 +6723,9 @@ linux_info() { local timezone=$(current_timezone) + local tcp_count=$(ss -t | wc -l) + local udp_count=$(ss -u | wc -l) + echo "" echo -e "系統信息查詢" @@ -6747,6 +6741,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}系統負載:${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP連接數:${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}物理內存:${gl_bai}$mem_info" echo -e "${gl_kjlan}虛擬內存:${gl_bai}$swap_info" echo -e "${gl_kjlan}硬盤佔用:${gl_bai}$disk_info" @@ -8029,6 +8024,9 @@ linux_Oracle() { } + + + docker_tato() { local container_count=$(docker ps -a -q 2>/dev/null | wc -l) @@ -8853,7 +8851,6 @@ linux_ldnmp() { echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" - check_port install_dependency install_docker install_certbot @@ -8989,7 +8986,6 @@ linux_ldnmp() { cd /home/web/ docker compose down --rmi all - check_port install_dependency install_docker install_certbot @@ -14044,7 +14040,7 @@ EOF echo "一條龍系統調優" echo "------------------------------------------------" echo "將對以下內容進行操作與優化" - echo "1. 更新系統到最新" + echo "1. 優化系統更新源,更新系統到最新" echo "2. 清理系統垃圾文件" echo -e "3. 設置虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設置SSH端口號為${gl_huang}5522${gl_bai}" @@ -14064,6 +14060,7 @@ EOF clear send_stats "一條龍調優啟動" echo "------------------------------------------------" + switch_mirror true true linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" @@ -14638,6 +14635,64 @@ echo "" +games_server_tools() { + + while true; do + clear + echo -e "遊戲開服腳本合集" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}1. ${gl_bai}幻獸帕魯開服腳本" + echo -e "${gl_kjlan}2. ${gl_bai}我的世界開服腳本" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}------------------------${gl_bai}" + read -e -p "請輸入你的選擇:" sub_choice + + case $sub_choice in + + 1) send_stats "幻獸帕魯開服腳本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh + exit + ;; + 2) send_stats "我的世界開服腳本" ; cd ~ + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh + exit + ;; + + 0) + kejilion + ;; + + *) + echo "無效的輸入!" + ;; + esac + break_end + + done + + +} + + + + + + + + + + + + + + + + + + + + kejilion_update() { @@ -14758,8 +14813,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}後台工作區" echo -e "${gl_kjlan}13. ${gl_bai}系統工具" echo -e "${gl_kjlan}14. ${gl_bai}服務器集群控制" echo -e "${gl_kjlan}15. ${gl_bai}廣告專欄" -echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}p. ${gl_bai}幻獸帕魯開服腳本" +echo -e "${gl_kjlan}16. ${gl_bai}遊戲開服腳本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}腳本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14785,10 +14839,7 @@ case $choice in 13) linux_Settings ;; 14) linux_cluster ;; 15) kejilion_Affiliates ;; - p) send_stats "幻獸帕魯開服腳本" ; cd ~ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh - exit - ;; + 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; *) echo "無效的輸入!" ;; From 1e5e9dcf4349422a5eb996d2b695a3d0093a980a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 23 Nov 2025 13:07:39 +0800 Subject: [PATCH 0403/1285] Add timezone environment variable to Docker run command --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ba1cb2023..75479bfc9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest From 52f522d6bce430a509887377900827c288f58a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 23 Nov 2025 13:08:24 +0800 Subject: [PATCH 0404/1285] Add timezone environment variable to Docker command --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index dc3ab3660..a36dfe7db 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest From ff39d1e84ee155589a9c66fcc9b2863c772283b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 23 Nov 2025 13:09:53 +0800 Subject: [PATCH 0405/1285] Fix time display issue in Komari monitoring Added timezone definition for Komari monitoring in the app market and fixed the time display issue. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 402b72ee2..5e51f6a81 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1367,6 +1367,7 @@ LDNMP环境NGINX环境优化安装流程,提升环境安装稳定性。 优化LDNMP环境中高性能模式无法切换的问题进行修复。 LDNMP初始化时新增URL绑定,提升wordpress安装向导的稳定性。 反向代理IP+端口功能优化,输入反代IP时回车可默认选择本机IP 127.0.0.1省去额外输入的麻烦。 +应用市场komari监控定义时区为上海,修复时间显示问题。 ------------------------ From 7c2e2798ec5864e09c3380d8b79eab555d3f8612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 25 Nov 2025 14:16:42 +0800 Subject: [PATCH 0406/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 75479bfc9..885357deb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13614,7 +13614,7 @@ EOF ;; 4) send_stats "智能切换更新源" - switch_mirror true true + switch_mirror false false ;; *) @@ -14061,7 +14061,7 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" From f3bd3eabfdd588dfc3a1f758d7f35ecd6098da27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 25 Nov 2025 14:17:19 +0800 Subject: [PATCH 0407/1285] Change switch_mirror parameters to false --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a36dfe7db..c52319d5f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13614,7 +13614,7 @@ EOF ;; 4) send_stats "智能切换更新源" - switch_mirror true true + switch_mirror false false ;; *) @@ -14061,7 +14061,7 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" From 9efe1237c1cd7c056939955f41481949bfda5aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 27 Nov 2025 09:45:30 +0800 Subject: [PATCH 0408/1285] Refactor BBR configuration in kejilion.sh --- cn/kejilion.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 885357deb..f7ac1a32d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4525,9 +4525,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -7057,7 +7056,7 @@ linux_bbr() { send_stats "alpine开启bbr3" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; From 0414e986967b535777e816cbf8880c9ec74b5efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 27 Nov 2025 09:45:56 +0800 Subject: [PATCH 0409/1285] Refactor BBR configuration in kejilion.sh --- kejilion.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c52319d5f..e4e42085c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4525,9 +4525,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -7057,7 +7056,7 @@ linux_bbr() { send_stats "alpine开启bbr3" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; From ad2146e58c1f59c9c309b0bbcf7f96b262d81ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:24:43 +0800 Subject: [PATCH 0410/1285] Change wp-config.php to wp-config-sample.php --- cn/kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f7ac1a32d..6d99bb0c9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # 删除旧定义 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on From ffb2b81dce27ea573ed9c8a057f3648b20205717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:25:14 +0800 Subject: [PATCH 0411/1285] Change wp-config.php to wp-config-sample.php --- kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e4e42085c..d46c2cd6e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # 删除旧定义 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on From 19d444f76630a322bbc8d9174a39ff76cb134147 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 30 Nov 2025 04:09:05 +0000 Subject: [PATCH 0412/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-11-30=2004:09:05?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 47 +++++++++++++++++---------------- jp/kejilion.sh | 71 +++++++++++++++++++++++++------------------------- kr/kejilion.sh | 51 ++++++++++++++++++------------------ tw/kejilion.sh | 17 ++++++------ 4 files changed, 95 insertions(+), 91 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 27b2e33c9..592e40c24 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # Delete old definition sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -2581,7 +2581,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2600,7 +2600,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on @@ -4525,9 +4526,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -4695,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" } @@ -4745,7 +4745,7 @@ echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -5013,7 +5013,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5547,7 +5547,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -6776,7 +6776,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" @@ -7057,7 +7057,7 @@ linux_bbr() { send_stats "alpine opens bbr3" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; @@ -7190,7 +7190,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -9067,7 +9067,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -12772,7 +12773,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -12783,7 +12784,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -13066,7 +13067,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13613,7 +13614,7 @@ EOF ;; 4) send_stats "Intelligent switching of update sources" - switch_mirror true true + switch_mirror false false ;; *) @@ -13798,7 +13799,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -14060,7 +14061,7 @@ EOF clear send_stats "One-stop tuning starts" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. Update the system to the latest" @@ -14494,7 +14495,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14611,7 +14612,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 890c94315..1f230406c 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # 古い定義を削除する sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -2037,7 +2037,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2152,7 +2152,7 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on @@ -3299,7 +3300,7 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すと、デフォルトのローカル IP 127.0.0.1 になります)。" reverseproxy + read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すとデフォルトでローカル IP 127.0.0.1 になります):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3709,7 +3710,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4525,9 +4526,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -4577,7 +4577,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4695,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" } @@ -4745,7 +4745,7 @@ echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -5374,7 +5374,7 @@ clamav() { while true; do clear echo "Clamav ウイルス スキャン ツール" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "これは、主にさまざまな種類のマルウェアを検出して削除するために使用されるオープンソースのウイルス対策ソフトウェア ツールです。" echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアが含まれます。" @@ -6242,7 +6242,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6402,7 +6402,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6776,7 +6776,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -7057,7 +7057,7 @@ linux_bbr() { send_stats "アルパインがBBR3をオープン" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; @@ -7152,7 +7152,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7425,7 +7425,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7568,7 +7568,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9067,7 +9067,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9340,7 +9340,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -12772,7 +12773,7 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" @@ -12783,7 +12784,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -13484,7 +13485,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13613,7 +13614,7 @@ EOF ;; 4) send_stats "アップデートソースのインテリジェントな切り替え" - switch_mirror true true + switch_mirror false false ;; *) @@ -13798,7 +13799,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -14040,7 +14041,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14060,7 +14061,7 @@ EOF clear send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}】1/12。システムを最新のものにアップデートする" @@ -14140,7 +14141,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14333,7 +14334,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14353,7 +14354,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14494,7 +14495,7 @@ while true; do echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14527,7 +14528,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14857,7 +14858,7 @@ echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 702be9f86..484b56417 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # 이전 정의 삭제 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -2581,7 +2581,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2600,7 +2600,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2800,7 +2800,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2913,7 +2913,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on @@ -3299,7 +3300,7 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4525,9 +4526,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -4695,7 +4695,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" } @@ -7057,7 +7057,7 @@ linux_bbr() { send_stats "알파인이 열립니다 bbr3" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; @@ -7538,7 +7538,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -9067,7 +9067,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9127,7 +9127,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" @@ -9331,7 +9331,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9443,7 +9443,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -12772,7 +12773,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -12783,7 +12784,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -12885,7 +12886,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13613,7 +13614,7 @@ EOF ;; 4) send_stats "업데이트 소스의 지능적인 전환" - switch_mirror true true + switch_mirror false false ;; *) @@ -13798,7 +13799,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -14060,7 +14061,7 @@ EOF clear send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 시스템을 최신으로 업데이트하세요" @@ -14494,7 +14495,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index f3e3243c5..42bd4e45d 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1853,7 +1853,7 @@ patch_wp_url() { local SITE_URL="$2" local TARGET_DIR="/home/web/html" - find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do + find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do # 刪除舊定義 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" @@ -3277,8 +3277,9 @@ ldnmp_wp() { sed -i "s|username_here|$dbuse|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|password_here|$dbusepasswd|g" /home/web/html/$yuming/wordpress/wp-config-sample.php sed -i "s|localhost|mysql|g" /home/web/html/$yuming/wordpress/wp-config-sample.php - cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php patch_wp_url "https://$yuming" "https://$yuming" + cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + restart_ldnmp nginx_web_on @@ -4525,9 +4526,8 @@ linux_clean() { bbr_on() { -cat > /etc/sysctl.conf << EOF -net.ipv4.tcp_congestion_control=bbr -EOF +sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p } @@ -7057,7 +7057,7 @@ linux_bbr() { send_stats "alpine開啟bbr3" ;; 2) - sed -i '/net.ipv4.tcp_congestion_control=bbr/d' /etc/sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf sysctl -p server_reboot ;; @@ -11583,6 +11583,7 @@ while true; do -v /home/docker/komari:/app/data \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=1212156 \ + -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -13613,7 +13614,7 @@ EOF ;; 4) send_stats "智能切換更新源" - switch_mirror true true + switch_mirror false false ;; *) @@ -14060,7 +14061,7 @@ EOF clear send_stats "一條龍調優啟動" echo "------------------------------------------------" - switch_mirror true true + switch_mirror false false linux_update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" From 0be21cfde4aa93504fae9865fde78aa0ba7bcf76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:39:36 +0800 Subject: [PATCH 0413/1285] Add sleep before clearing screen in kejilion.sh Added a sleep command before clearing the screen after installation. --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6d99bb0c9..fe1309a92 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "LDNMP环境安装完毕" From a44d1b255e8486f266f6261311969ee9eb42c551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:40:33 +0800 Subject: [PATCH 0414/1285] Update kejilion.sh --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d46c2cd6e..657172347 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "LDNMP环境安装完毕" From 093f1643103afcb7ab21b5d87e12dcfffbc5fbd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:51:05 +0800 Subject: [PATCH 0415/1285] Update auto_cert_renewal.sh --- auto_cert_renewal.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 4d574d6dc..97cd09087 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -31,15 +31,19 @@ for cert_file in $certs_directory*_cert.pem; do docker stop nginx > /dev/null 2>&1 - iptables -P INPUT ACCEPT - iptables -P FORWARD ACCEPT - iptables -P OUTPUT ACCEPT - iptables -F - - ip6tables -P INPUT ACCEPT - ip6tables -P FORWARD ACCEPT - ip6tables -P OUTPUT ACCEPT - ip6tables -F + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi + + # iptables -P INPUT ACCEPT + # iptables -P FORWARD ACCEPT + # iptables -P OUTPUT ACCEPT + # iptables -F + + # ip6tables -P INPUT ACCEPT + # ip6tables -P FORWARD ACCEPT + # ip6tables -P OUTPUT ACCEPT + # ip6tables -F docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d $yuming --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa From 96e2eaea713884c0cc72e0e6b23ace9a2dd75187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:15:02 +0800 Subject: [PATCH 0416/1285] Update version and add new composer requirements --- cn/kejilion.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fe1309a92..459a02c39 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -8318,9 +8318,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -10756,6 +10760,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "已经安装完成" check_docker_app_ip From 8fc06fa0bd8b717f75caf03a13b016b37a87ba34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:15:46 +0800 Subject: [PATCH 0417/1285] Update shell script for version and dependencies --- kejilion.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 657172347..3599f925c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -8318,9 +8318,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -10756,6 +10760,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "已经安装完成" check_docker_app_ip From 08423c94c208697585bf950932601461b573722c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:18:41 +0800 Subject: [PATCH 0418/1285] Update kejilion_sh_log.txt with version 4.2.7 changes --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5e51f6a81..8443077a0 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1369,5 +1369,9 @@ LDNMP初始化时新增URL绑定,提升wordpress安装向导的稳定性。 反向代理IP+端口功能优化,输入反代IP时回车可默认选择本机IP 127.0.0.1省去额外输入的麻烦。 应用市场komari监控定义时区为上海,修复时间显示问题。 ------------------------ +2025-12-03 v4.2.7 +LDNMP建站为flarum论坛安装时增加了更多实用插件扩展。 +应用市场Dify知识库修复创建管理员出错的问题。官方API权限问题已擦屁股。 +------------------------ From 30efeadb3ce81e8fbdf63e19e72d7a550680b68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 5 Dec 2025 21:33:45 +0800 Subject: [PATCH 0419/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 459a02c39..77275d675 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1634,7 +1634,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address From 821ee648671c89f59b2e045d69b94c3855097b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 5 Dec 2025 21:34:40 +0800 Subject: [PATCH 0420/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 3599f925c..c09cdd22f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1634,7 +1634,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address From cd839def044925cda130955a8e3516b230d2be49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:14:43 +0800 Subject: [PATCH 0421/1285] Update kejilion.sh --- cn/kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 77275d675..6422c68ab 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1434,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1445,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From cff7a0f3f958eaa286cac1281d2546d0b38e1fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:15:49 +0800 Subject: [PATCH 0422/1285] Allow traffic on port 80 for certbot Add iptables rule to allow traffic on port 80 for certbot. --- kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c09cdd22f..a9885f850 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1434,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1445,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From 6c0558e1071102f2683bc77168bacfb73c7ea780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:17:32 +0800 Subject: [PATCH 0423/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8443077a0..e19355d8c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1372,6 +1372,7 @@ LDNMP初始化时新增URL绑定,提升wordpress安装向导的稳定性。 2025-12-03 v4.2.7 LDNMP建站为flarum论坛安装时增加了更多实用插件扩展。 应用市场Dify知识库修复创建管理员出错的问题。官方API权限问题已擦屁股。 +对申请证书时80端口防火墙规则进行优化,提升申请证书成功率。 ------------------------ From 518bc0d2f7f09cb258189e0cb649acec7015b384 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 7 Dec 2025 04:30:07 +0000 Subject: [PATCH 0424/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-07=2004:30:07?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 30 ++++++++++++++++++---------- jp/kejilion.sh | 54 ++++++++++++++++++++++++++++++-------------------- kr/kejilion.sh | 44 ++++++++++++++++++++++++---------------- tw/kejilion.sh | 22 ++++++++++++++------ 4 files changed, 95 insertions(+), 55 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 592e40c24..af13a099d 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "The LDNMP environment is installed" @@ -1435,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1446,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1635,7 +1635,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -8319,9 +8319,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -10757,6 +10761,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "Installation completed" check_docker_app_ip @@ -12784,7 +12794,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -13256,8 +13266,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 1f230406c..8fed2772b 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -863,7 +863,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1186,7 +1186,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "LDNMP環境がインストールされている" @@ -1435,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1446,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1635,7 +1635,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address @@ -2037,7 +2037,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -5716,7 +5716,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6242,7 +6242,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6402,7 +6402,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -7425,7 +7425,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8319,9 +8319,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -10757,6 +10761,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "インストール完了" check_docker_app_ip @@ -12784,7 +12794,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -13256,8 +13266,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -14141,7 +14151,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14334,7 +14344,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14354,7 +14364,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14490,7 +14500,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -14818,7 +14828,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 484b56417..018b44482 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "LDNMP 환경이 설치되었습니다" @@ -1435,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1446,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1635,7 +1635,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address @@ -3233,7 +3233,7 @@ ldnmp_web_on() { echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8319,9 +8319,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -9443,7 +9447,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -10757,6 +10761,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "설치 완료" check_docker_app_ip @@ -12784,7 +12794,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -12886,7 +12896,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13003,7 +13013,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13256,8 +13266,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -13558,7 +13568,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 42bd4e45d..c8f9f2a9e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.6" +sh_v="4.2.7" gl_hui='\e[37m' @@ -1401,8 +1401,7 @@ install_ldnmp() { restart_ldnmp - - + sleep 2 clear echo "LDNMP環境安裝完畢" @@ -1435,8 +1434,6 @@ install_ssltls() { if [ ! -f "$file_path" ]; then local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - # local ipv6_pattern='^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$' - # local ipv6_pattern='^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4][0-9]|[01]?[0-9][0-9]?))))$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -1446,6 +1443,9 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1635,7 +1635,7 @@ phpmyadmin_upgrade() { cd /home/web/ docker rm -f $ldnmp_pods > /dev/null 2>&1 docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - curl -sS -O https://raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml + curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/docker/refs/heads/main/docker-compose.phpmyadmin.yml docker compose -f docker-compose.phpmyadmin.yml up -d clear ip_address @@ -8319,9 +8319,13 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/sitemap" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/oauth" docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/best-answer:*" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/upload" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/gamification" + docker exec php sh -c "cd /var/www/html/$yuming && composer require fof/byobu:*" docker exec php sh -c "cd /var/www/html/$yuming && composer require v17development/flarum-seo" docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + restart_ldnmp @@ -10757,6 +10761,12 @@ while true; do sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d + + chown -R 1001:1001 /home/docker/dify/docker/volumes/app/storage + chmod -R 755 /home/docker/dify/docker/volumes/app/storage + docker compose down + docker compose up -d + clear echo "已經安裝完成" check_docker_app_ip From 3ad21f01243cf0af80f9451d48b746128533c82f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 14 Dec 2025 04:44:15 +0000 Subject: [PATCH 0425/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-14=2004:44:15?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 18 +++++++++--------- jp/kejilion.sh | 34 +++++++++++++++++----------------- kr/kejilion.sh | 30 +++++++++++++++--------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index af13a099d..f271d8a02 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -4738,7 +4738,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } @@ -5013,7 +5013,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7190,7 +7190,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -9071,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -13266,8 +13266,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -14060,7 +14060,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14109,7 +14109,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 8fed2772b..eb2dcf90a 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -858,12 +858,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -921,7 +921,7 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done @@ -1186,7 +1186,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -2913,7 +2913,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3710,7 +3710,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4738,7 +4738,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } @@ -5716,7 +5716,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6242,7 +6242,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7425,7 +7425,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -9071,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9344,7 +9344,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -12784,7 +12784,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13480,7 +13480,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -14622,7 +14622,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14828,7 +14828,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 018b44482..2fcfc8e66 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -2800,7 +2800,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2913,7 +2913,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3239,7 +3239,7 @@ ldnmp_web_on() { nginx_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" } @@ -3300,7 +3300,7 @@ ldnmp_Proxy() { add_yuming fi if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3539,7 +3539,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -6354,7 +6354,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -9071,7 +9071,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9131,7 +9131,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" @@ -9326,7 +9326,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9335,7 +9335,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9447,7 +9447,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -12896,7 +12896,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13568,7 +13568,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14622,7 +14622,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" From 1c7b7b6acaf06952bff12247feabf9ccf68bba4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:10:29 +0800 Subject: [PATCH 0426/1285] Upgrade sh_v to 4.2.8 and adjust nginx config handling Updated version from 4.2.7 to 4.2.8 and modified configuration file handling. --- cn/kejilion.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6422c68ab..237d8f6dd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.8" gl_hui='\e[37m' @@ -3310,11 +3310,25 @@ ldnmp_Proxy() { nginx_install_status install_ssltls certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload nginx_web_on From eb4afcf5100e3355c676ac63b7b2d9c4eadb4a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:11:10 +0800 Subject: [PATCH 0427/1285] Update version and enhance reverse proxy configuration Updated the script to use a new version and modified the configuration file paths. Added dynamic backend server generation and updated reverse proxy settings. --- kejilion.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a9885f850..e78846210 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.8" gl_hui='\e[37m' @@ -3310,11 +3310,25 @@ ldnmp_Proxy() { nginx_install_status install_ssltls certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload nginx_web_on From 862d317e31aed4d21f09aeaf760d6ff767c623ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:14:28 +0800 Subject: [PATCH 0428/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e19355d8c..2ccb6e9ba 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1374,5 +1374,8 @@ LDNMP建站为flarum论坛安装时增加了更多实用插件扩展。 应用市场Dify知识库修复创建管理员出错的问题。官方API权限问题已擦屁股。 对申请证书时80端口防火墙规则进行优化,提升申请证书成功率。 ------------------------ +2025-12-15 v4.2.8 +nginx反向代理优化,定义upstream和keepalive提升后端连接性能和稳定性。 +------------------------ From b8704a930186ae87f8441725b2431ab4a2da0114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:54:42 +0800 Subject: [PATCH 0429/1285] Remove '-it' option from docker exec and run commands --- cn/kejilion.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 237d8f6dd..4d88c90c2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -546,7 +546,7 @@ while true; do 11) send_stats "进入容器" read -e -p "请输入容器名: " dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -1446,7 +1446,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1483,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -3642,7 +3642,7 @@ ldnmp_web_status() { send_stats "申请域名证书" read -e -p "请输入你的域名: " yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3741,7 +3741,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -5363,7 +5363,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # 执行 Docker 命令 - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -7939,7 +7939,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 运行Docker容器 - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -9290,7 +9290,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9561,7 +9561,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10671,7 +10671,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11070,7 +11070,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11833,7 +11833,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12183,7 +12183,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12197,7 +12197,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" From 8aa6c56c9f78ae030007e750b1b410c4f3cba547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:55:22 +0800 Subject: [PATCH 0430/1285] Remove interactive flag from docker run commands --- kejilion.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e78846210..09bd7f5e3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -546,7 +546,7 @@ while true; do 11) send_stats "进入容器" read -e -p "请输入容器名: " dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -1446,7 +1446,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1483,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -3642,7 +3642,7 @@ ldnmp_web_status() { send_stats "申请域名证书" read -e -p "请输入你的域名: " yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3741,7 +3741,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -5363,7 +5363,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # 执行 Docker 命令 - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -7939,7 +7939,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 运行Docker容器 - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -9290,7 +9290,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9561,7 +9561,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10671,7 +10671,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11070,7 +11070,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11833,7 +11833,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12183,7 +12183,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12197,7 +12197,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" From cca8b3ec794ec5f54f7c8a6b2993e08eececac6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:56:45 +0800 Subject: [PATCH 0431/1285] Optimize Docker automation by removing -it parameter Removed unnecessary -it parameter from Docker automation to enhance stability and follow best practices. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2ccb6e9ba..db9f8ca54 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1376,6 +1376,7 @@ LDNMP建站为flarum论坛安装时增加了更多实用插件扩展。 ------------------------ 2025-12-15 v4.2.8 nginx反向代理优化,定义upstream和keepalive提升后端连接性能和稳定性。 +去掉docker自动化中无用的-it参数,提升运行稳定性,遵行最佳实践。 ------------------------ From b303d20515842fd962b25b41c64537746526fe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:26:58 +0800 Subject: [PATCH 0432/1285] Add fail2ban management panel function --- cn/kejilion.sh | 111 ++++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4d88c90c2..de7880337 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13015,6 +13015,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "ssh防御" + while true; do + + check_f2b_status + echo -e "SSH防御程序 $check_f2b_status" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. 安装防御程序" + echo "------------------------" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" + echo "------------------------" + echo "9. 卸载防御程序" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "请输入你的选择: " sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban防御程序已卸载" + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13752,53 +13808,7 @@ EOF ;; 22) - root_use - send_stats "ssh防御" - while true; do - - check_f2b_status - echo -e "SSH防御程序 $check_f2b_status" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. 安装防御程序" - echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" - echo "------------------------" - echo "9. 卸载防御程序" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "请输入你的选择: " sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban防御程序已卸载" - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14921,6 +14931,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" } @@ -15153,8 +15164,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + From 2f6345e5bf47acb4afc2417dd1568ea3bc9e4a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:27:30 +0800 Subject: [PATCH 0433/1285] Update kejilion.sh --- kejilion.sh | 111 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 09bd7f5e3..29567b34b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13015,6 +13015,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "ssh防御" + while true; do + + check_f2b_status + echo -e "SSH防御程序 $check_f2b_status" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. 安装防御程序" + echo "------------------------" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" + echo "------------------------" + echo "9. 卸载防御程序" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "请输入你的选择: " sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban防御程序已卸载" + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13752,53 +13808,7 @@ EOF ;; 22) - root_use - send_stats "ssh防御" - while true; do - - check_f2b_status - echo -e "SSH防御程序 $check_f2b_status" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. 安装防御程序" - echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" - echo "------------------------" - echo "9. 卸载防御程序" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "请输入你的选择: " sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban防御程序已卸载" - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14921,6 +14931,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" } @@ -15153,8 +15164,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + From 0264f78e7f48aa5d5ffe36c0dbbf3a36ddb85cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:29:04 +0800 Subject: [PATCH 0434/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index db9f8ca54..bb2172376 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1377,6 +1377,7 @@ LDNMP建站为flarum论坛安装时增加了更多实用插件扩展。 2025-12-15 v4.2.8 nginx反向代理优化,定义upstream和keepalive提升后端连接性能和稳定性。 去掉docker自动化中无用的-it参数,提升运行稳定性,遵行最佳实践。 +添加kl快捷命令 k f2b 可以快速启动fail2ban管理工具。 ------------------------ From 5a7064e46bb9803aafa72dfb86647b08c273448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:43:47 +0800 Subject: [PATCH 0435/1285] Update kejilion.sh --- cn/kejilion.sh | 118 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 23 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index de7880337..19ce322e6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.8" +sh_v="4.2.9" gl_hui='\e[37m' @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1542,12 +1549,28 @@ certs_status() { echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" - break_end - clear - echo "请再次尝试部署 $webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. 重新申请 2. 不带证书改用HTTP访问 0. 退出" + echo "------------------------" + read -e -p "请输入你的选择: " sub_choice + case $sub_choice in + 1) + send_stats "重新申请" + echo "请再次尝试部署 $webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "不带证书改用HTTP访问" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # 如果 access_port 为空,则跳过 + [ -z "$access_port" ] && return 0 + + # 删除所有 listen 行 + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # 在 server { 后插入新的 listen + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "您的 $webname 搭建好了!" - echo "https://$yuming" + clear + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + echo "您的 $webname 搭建好了!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3287,6 +3344,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3357,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3329,6 +3390,8 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3346,6 +3409,8 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi @@ -3369,6 +3434,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3610,6 +3677,11 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + echo "------------------------" echo "" echo -e "数据库: ${db_output}" @@ -8639,7 +8711,7 @@ linux_ldnmp() { -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server duankou=3280 - reverse_proxy + ldnmp_Proxy 127.0.0.1 $duankou nginx_web_on @@ -8657,7 +8729,7 @@ linux_ldnmp() { docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 - reverse_proxy + ldnmp_Proxy 127.0.0.1 $duankou nginx_web_on From 38e7200fbc87c6c140639fe2f4c8abee92d9795d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:44:29 +0800 Subject: [PATCH 0436/1285] Update version and refactor reverse proxy handling Updated version from 4.2.8 to 4.2.9 and refactored the reverse proxy function. Added user prompts for deployment options and improved nginx configuration handling. --- kejilion.sh | 118 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 23 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 29567b34b..de08356a1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.8" +sh_v="4.2.9" gl_hui='\e[37m' @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1542,12 +1549,28 @@ certs_status() { echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" - break_end - clear - echo "请再次尝试部署 $webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. 重新申请 2. 不带证书改用HTTP访问 0. 退出" + echo "------------------------" + read -e -p "请输入你的选择: " sub_choice + case $sub_choice in + 1) + send_stats "重新申请" + echo "请再次尝试部署 $webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "不带证书改用HTTP访问" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # 如果 access_port 为空,则跳过 + [ -z "$access_port" ] && return 0 + + # 删除所有 listen 行 + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # 在 server { 后插入新的 listen + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "您的 $webname 搭建好了!" - echo "https://$yuming" + clear + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + echo "您的 $webname 搭建好了!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3287,6 +3344,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3357,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3329,6 +3390,8 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3346,6 +3409,8 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi @@ -3369,6 +3434,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3610,6 +3677,11 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + echo "------------------------" echo "" echo -e "数据库: ${db_output}" @@ -8639,7 +8711,7 @@ linux_ldnmp() { -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server duankou=3280 - reverse_proxy + ldnmp_Proxy 127.0.0.1 $duankou nginx_web_on @@ -8657,7 +8729,7 @@ linux_ldnmp() { docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 duankou=8010 - reverse_proxy + ldnmp_Proxy 127.0.0.1 $duankou nginx_web_on From e0c67a2d3006a4fac928c45793ff9c4c8a53f493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:49:04 +0800 Subject: [PATCH 0437/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index bb2172376..de8ca8a1e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1379,5 +1379,9 @@ nginx反向代理优化,定义upstream和keepalive提升后端连接性能和 去掉docker自动化中无用的-it参数,提升运行稳定性,遵行最佳实践。 添加kl快捷命令 k f2b 可以快速启动fail2ban管理工具。 ------------------------ +2025-12-19 v4.2.9 +nginx反向代理和负载均衡支持IP自定义监听端口功能,可实现反代内部IP加端口到网关的效果, +SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问或者中断申请。 +------------------------ From d0e5a4b6dd2a43a64d1ef75838daee897eac7f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 19 Dec 2025 16:07:23 +0800 Subject: [PATCH 0438/1285] Rearrange installation functions in kejilion.sh --- cn/kejilion.sh | 152 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 50 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 19ce322e6..8105a0cb3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3315,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3369,12 +3371,14 @@ ldnmp_Proxy() { read -e -p "请输入你的反代端口: " port fi nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls + certs_status + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3416,11 +3420,14 @@ ldnmp_Proxy_backend() { fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3682,6 +3689,20 @@ ldnmp_web_status() { basename "$conf_file" .conf done + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "数据库: ${db_output}" @@ -8216,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8253,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8288,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8331,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8379,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8434,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8472,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8508,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8642,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "请输入跳转域名: " reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8679,12 +8732,14 @@ linux_ldnmp() { echo -e "域名格式: ${gl_huang}google.com${gl_bai}" read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8700,9 +8755,6 @@ linux_ldnmp() { send_stats "安装$webname" echo "开始部署 $webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8710,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - ldnmp_Proxy 127.0.0.1 $duankou + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8723,15 +8775,11 @@ linux_ldnmp() { send_stats "安装$webname" echo "开始部署 $webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - ldnmp_Proxy 127.0.0.1 $duankou - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8742,11 +8790,13 @@ linux_ldnmp() { echo "开始部署 $webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8781,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html From 6efa4abc0f81de18dd3ce54ed1841b27de76f37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 19 Dec 2025 16:08:00 +0800 Subject: [PATCH 0439/1285] Rearrange installation steps for clarity Reorder installation steps to ensure SSL/TLS and database setup occur after configuration downloads. --- kejilion.sh | 152 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 50 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index de08356a1..ee7500831 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3315,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3369,12 +3371,14 @@ ldnmp_Proxy() { read -e -p "请输入你的反代端口: " port fi nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls + certs_status + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3416,11 +3420,14 @@ ldnmp_Proxy_backend() { fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3682,6 +3689,20 @@ ldnmp_web_status() { basename "$conf_file" .conf done + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "数据库: ${db_output}" @@ -8216,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8253,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8288,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8331,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8379,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8434,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8472,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8508,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8642,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "请输入跳转域名: " reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8679,12 +8732,14 @@ linux_ldnmp() { echo -e "域名格式: ${gl_huang}google.com${gl_bai}" read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8700,9 +8755,6 @@ linux_ldnmp() { send_stats "安装$webname" echo "开始部署 $webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8710,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - ldnmp_Proxy 127.0.0.1 $duankou + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8723,15 +8775,11 @@ linux_ldnmp() { send_stats "安装$webname" echo "开始部署 $webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - ldnmp_Proxy 127.0.0.1 $duankou - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8742,11 +8790,13 @@ linux_ldnmp() { echo "开始部署 $webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8781,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html From 9b2b0bfcdfee8bd44b39cc96b66664eb6301d5bd Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 21 Dec 2025 04:12:25 +0000 Subject: [PATCH 0440/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-21=2004:12:25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 445 ++++++++++++++++++++++++++++++--------------- jp/kejilion.sh | 463 +++++++++++++++++++++++++++++++---------------- kr/kejilion.sh | 477 ++++++++++++++++++++++++++++++++----------------- tw/kejilion.sh | 423 +++++++++++++++++++++++++++++-------------- 4 files changed, 1214 insertions(+), 594 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index f271d8a02..807db858c 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.9" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "Enter the container" read -e -p "Please enter the container name:" dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -881,7 +881,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1446,7 +1453,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1490,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -1542,12 +1549,28 @@ certs_status() { echo -e "4. Firewall restrictions ➠ Check whether port 80/443 is open and ensure that it is accessible" echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" echo -e "6. Domestic registration restrictions ➠ For mainland China environment, please confirm whether the domain name is registered" - break_end - clear - echo "Please try deploying again$webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. Reapply 2. Switch to HTTP access without certificate 0. Exit" + echo "------------------------" + read -e -p "Please enter your choice:" sub_choice + case $sub_choice in + 1) + send_stats "Reapply" + echo "Please try deploying again$webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "Switch to HTTP access without a certificate" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "Please enter the access/listening port, and press Enter to use 80 by default:" access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # Skip if access_port is empty + [ -z "$access_port" ] && return 0 + + # Remove all listen lines + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # Insert new listen after server { + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "your$webnameIt's built!" - echo "https://$yuming" + clear + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + echo "your$webnameIt's built!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3258,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3287,6 +3346,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3359,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "Please enter your anti-generation IP (press Enter to default to the local IP 127.0.0.1):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3308,13 +3371,31 @@ ldnmp_Proxy() { read -e -p "Please enter your anti-generation port:" port fi nginx_install_status + + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls certs_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3332,16 +3413,21 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "Please enter your multiple anti-generation IP+ports separated by spaces (for example, 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3355,6 +3441,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3596,6 +3684,25 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "database:${db_output}" @@ -3628,7 +3735,7 @@ ldnmp_web_status() { send_stats "Apply for a domain name certificate" read -e -p "Please enter your domain name:" yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3727,7 +3834,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -4738,7 +4845,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } @@ -5013,7 +5120,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5349,7 +5456,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # Execute Docker command - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -6354,7 +6461,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7190,7 +7297,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -7925,7 +8032,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # Run Docker container - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -8130,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8167,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8202,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8245,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8293,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8348,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8386,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8422,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8556,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "Please enter the redirect domain name:" reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8593,12 +8732,14 @@ linux_ldnmp() { echo -e "Domain name format:${gl_huang}google.com${gl_bai}" read -e -p "Please enter your reverse proxy domain name:" fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8614,9 +8755,6 @@ linux_ldnmp() { send_stats "Install$webname" echo "Start deployment$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8624,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - reverse_proxy + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8637,15 +8775,11 @@ linux_ldnmp() { send_stats "Install$webname" echo "Start deployment$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - reverse_proxy - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8656,11 +8790,13 @@ linux_ldnmp() { echo "Start deployment$webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8695,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -9071,7 +9209,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -9276,7 +9414,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9415,7 +9553,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9547,7 +9685,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10657,7 +10795,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11056,7 +11194,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11819,7 +11957,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12169,7 +12307,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12183,7 +12321,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}All client QR code configurations:${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}All client configuration codes:${gl_bai}" @@ -12794,7 +12932,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -13001,6 +13139,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "ssh defense" + while true; do + + check_f2b_status + echo -e "SSH defense program$check_f2b_status" + echo "fail2ban is an SSH tool to prevent brute force cracking" + echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. Install a defense program" + echo "------------------------" + echo "2. View SSH interception records" + echo "3. Real-time log monitoring" + echo "------------------------" + echo "9. Uninstall the defense program" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Please enter your choice:" sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban defense program has been uninstalled" + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13738,53 +13932,7 @@ EOF ;; 22) - root_use - send_stats "ssh defense" - while true; do - - check_f2b_status - echo -e "SSH defense program$check_f2b_status" - echo "fail2ban is an SSH tool to prevent brute force cracking" - echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. Install a defense program" - echo "------------------------" - echo "2. View SSH interception records" - echo "3. Real-time log monitoring" - echo "------------------------" - echo "9. Uninstall the defense program" - echo "------------------------" - echo "0. Return to the previous menu" - echo "------------------------" - read -e -p "Please enter your choice:" sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban defense program has been uninstalled" - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14060,7 +14208,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14109,7 +14257,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14622,7 +14770,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14907,6 +15055,7 @@ echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" echo "command favorites k fav | k command favorites" echo "Application market management k app" echo "Quick management of application numbers k app 26 | k app 1panel | k app npm" +echo "fail2ban management k fail2ban | k f2b" echo "Display system information k info" } @@ -15139,8 +15288,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + diff --git a/jp/kejilion.sh b/jp/kejilion.sh index eb2dcf90a..4628b2dc2 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.9" gl_hui='\e[37m' @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストールする$package...${gl_bai}" + echo -e "${gl_huang}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -546,7 +546,7 @@ while true; do 11) send_stats "コンテナに入る" read -e -p "コンテナ名を入力してください:" dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -858,7 +858,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done @@ -921,7 +921,7 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1446,7 +1453,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1490,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -1542,12 +1549,28 @@ certs_status() { echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" - break_end - clear - echo "もう一度デプロイしてみてください$webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. 再適用 2. 証明書なしの HTTP アクセスに切り替える 0. 終了" + echo "------------------------" + read -e -p "選択肢を入力してください:" sub_choice + case $sub_choice in + 1) + send_stats "再申請" + echo "もう一度デプロイしてみてください$webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "証明書なしの HTTP アクセスに切り替える" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "デフォルトで 80 を使用するには、アクセス/リスニング ポートを入力し、Enter キーを押してください。" access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # access_port が空の場合はスキップします + [ -z "$access_port" ] && return 0 + + # すべてのリッスン行を削除します + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # サーバー { の後に新しいリッスンを挿入します + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -2037,7 +2083,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2528,7 +2574,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2545,7 +2591,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2913,7 +2959,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "あなたの$webname建てられました!" - echo "https://$yuming" + clear + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + echo "あなたの$webname建てられました!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3258,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3287,6 +3346,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3359,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すとデフォルトでローカル IP 127.0.0.1 になります):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3308,13 +3371,31 @@ ldnmp_Proxy() { read -e -p "アンチジェネレーションポートを入力してください:" port fi nginx_install_status + + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls certs_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3332,16 +3413,21 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "複数のアンチジェネレーション IP + ポートをスペースで区切って入力してください (例: 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3355,6 +3441,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3596,6 +3684,25 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "データベース:${db_output}" @@ -3628,7 +3735,7 @@ ldnmp_web_status() { send_stats "ドメイン名証明書を申請する" read -e -p "ドメイン名を入力してください:" yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3727,7 +3834,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -4162,7 +4269,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4738,7 +4845,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } @@ -5349,7 +5456,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # Dockerコマンドを実行する - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -6242,7 +6349,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6354,7 +6461,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7152,7 +7259,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7925,7 +8032,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # Dockerコンテナを実行する - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -8130,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8167,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8202,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8245,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8293,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8348,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8386,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8422,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8556,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "リダイレクト ドメイン名を入力してください:" reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8593,12 +8732,14 @@ linux_ldnmp() { echo -e "ドメイン名の形式:${gl_huang}google.com${gl_bai}" read -e -p "リバース プロキシ ドメイン名を入力してください:" fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8614,9 +8755,6 @@ linux_ldnmp() { send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8624,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - reverse_proxy + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8637,15 +8775,11 @@ linux_ldnmp() { send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - reverse_proxy - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8656,11 +8790,13 @@ linux_ldnmp() { echo "導入を開始する$webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8695,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -9071,7 +9209,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9276,7 +9414,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9547,7 +9685,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10657,7 +10795,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11056,7 +11194,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11819,7 +11957,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12169,7 +12307,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12183,7 +12321,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}すべてのクライアント QR コード構成:${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" @@ -12784,7 +12922,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -12794,7 +12932,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -13001,6 +13139,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "SSH防御" + while true; do + + check_f2b_status + echo -e "SSH防御プログラム$check_f2b_status" + echo "failed2ban はブルート フォース クラッキングを防ぐ SSH ツールです" + echo "公式サイト紹介:${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. 防御プログラムをインストールする" + echo "------------------------" + echo "2. SSH インターセプト記録の表示" + echo "3. リアルタイムログ監視" + echo "------------------------" + echo "9. 防御プログラムをアンインストールする" + echo "------------------------" + echo "0. 前のメニューに戻る" + echo "------------------------" + read -e -p "選択肢を入力してください:" sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban 防御プログラムがアンインストールされました" + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13266,8 +13460,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -13480,7 +13674,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13495,7 +13689,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -13738,53 +13932,7 @@ EOF ;; 22) - root_use - send_stats "SSH防御" - while true; do - - check_f2b_status - echo -e "SSH防御プログラム$check_f2b_status" - echo "failed2ban はブルート フォース クラッキングを防ぐ SSH ツールです" - echo "公式サイト紹介:${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. 防御プログラムをインストールする" - echo "------------------------" - echo "2. SSH インターセプト記録の表示" - echo "3. リアルタイムログ監視" - echo "------------------------" - echo "9. 防御プログラムをアンインストールする" - echo "------------------------" - echo "0. 前のメニューに戻る" - echo "------------------------" - read -e -p "選択肢を入力してください:" sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban 防御プログラムがアンインストールされました" - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14622,7 +14770,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14907,6 +15055,7 @@ echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" echo "コマンド お気に入り k お気に入り | k コマンドのお気に入り" echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" +echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" echo "システム情報を表示 k info" } @@ -15139,8 +15288,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 2fcfc8e66..b6ae7276f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.9" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "컨테이너를 입력하세요" read -e -p "컨테이너 이름을 입력하세요:" dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1446,7 +1453,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1490,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -1538,16 +1545,32 @@ certs_status() { echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." - break_end - clear - echo "다시 배포해 보세요.$webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. 재적용 2. 인증서 없이 HTTP 접속으로 전환 0. 종료" + echo "------------------------" + read -e -p "선택사항을 입력하세요:" sub_choice + case $sub_choice in + 1) + send_stats "재신청" + echo "다시 배포해 보세요.$webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "인증서 없이 HTTP 액세스로 전환" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "액세스/수신 포트를 입력하고 Enter를 눌러 기본적으로 80을 사용하십시오." access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # access_port가 비어 있으면 건너뛰세요. + [ -z "$access_port" ] && return 0 + + # 모든 청취 라인 제거 + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # 서버 { 뒤에 새 수신 대기 삽입 + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -2153,7 +2199,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -3230,7 +3276,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치 정보는 다음과 같습니다." @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "당신의$webname건설되었습니다!" - echo "https://$yuming" + clear + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + echo "당신의$webname건설되었습니다!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3258,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3287,6 +3346,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3359,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3308,13 +3371,31 @@ ldnmp_Proxy() { read -e -p "안티 세대 포트를 입력하십시오:" port fi nginx_install_status + + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls certs_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3332,16 +3413,21 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "여러 개의 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3355,6 +3441,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3596,6 +3684,25 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "데이터 베이스:${db_output}" @@ -3628,7 +3735,7 @@ ldnmp_web_status() { send_stats "도메인 이름 인증서 신청" read -e -p "도메인 이름을 입력하세요:" yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3727,7 +3834,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -5120,7 +5227,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5130,7 +5237,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -5184,7 +5291,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5273,7 +5380,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5291,7 +5398,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5327,7 +5434,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -5349,7 +5456,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # 도커 명령 실행 - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -6354,7 +6461,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -7202,7 +7309,7 @@ docker_ssh_migration() { # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home/docker 아래의 파일을 백업합니다...${NC}" + echo -e "${BLUE}/home/docker 아래의 파일을 백업하세요...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi @@ -7249,7 +7356,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7265,7 +7372,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 용기:$container${NC}" + echo -e "${GREEN}처리용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7584,7 +7691,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -7925,7 +8032,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # Docker 컨테이너 실행 - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -8130,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8167,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8202,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8245,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8293,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8348,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8386,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8422,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8556,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "리디렉션 도메인 이름을 입력하세요." reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8591,14 +8730,16 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8614,9 +8755,6 @@ linux_ldnmp() { send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8624,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - reverse_proxy + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8637,15 +8775,11 @@ linux_ldnmp() { send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - reverse_proxy - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8656,11 +8790,13 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8695,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -9071,7 +9209,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9131,7 +9269,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" @@ -9276,7 +9414,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9335,7 +9473,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9415,7 +9553,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9547,7 +9685,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10657,7 +10795,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11056,7 +11194,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11819,7 +11957,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12169,7 +12307,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12183,7 +12321,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}모든 클라이언트 QR 코드 구성:${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}모든 클라이언트 구성 코드:${gl_bai}" @@ -12794,7 +12932,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -13001,6 +13139,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "SSH 방어" + while true; do + + check_f2b_status + echo -e "SSH 방어 프로그램$check_f2b_status" + echo "fall2ban은 무차별 대입 크래킹을 방지하는 SSH 도구입니다." + echo "공식 웹사이트 소개:${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. 방어 프로그램 설치" + echo "------------------------" + echo "2. SSH 차단 기록 보기" + echo "3. 실시간 로그 모니터링" + echo "------------------------" + echo "9. 방어 프로그램 제거" + echo "------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "------------------------" + read -e -p "선택사항을 입력하세요:" sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban 방어 프로그램이 제거되었습니다." + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13013,7 +13207,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13266,8 +13460,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -13310,7 +13504,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -13568,7 +13762,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13738,53 +13932,7 @@ EOF ;; 22) - root_use - send_stats "SSH 방어" - while true; do - - check_f2b_status - echo -e "SSH 방어 프로그램$check_f2b_status" - echo "fall2ban은 무차별 대입 크래킹을 방지하는 SSH 도구입니다." - echo "공식 웹사이트 소개:${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. 방어 프로그램 설치" - echo "------------------------" - echo "2. SSH 차단 기록 보기" - echo "3. 실시간 로그 모니터링" - echo "------------------------" - echo "9. 방어 프로그램 제거" - echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" - echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban 방어 프로그램이 제거되었습니다." - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14622,7 +14770,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14907,6 +15055,7 @@ echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" +echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" } @@ -15139,8 +15288,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + diff --git a/tw/kejilion.sh b/tw/kejilion.sh index c8f9f2a9e..de76654f6 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.7" +sh_v="4.2.9" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "進入容器" read -e -p "請輸入容器名:" dockername - docker exec -it $dockername /bin/sh + docker exec $dockername /bin/sh break_end ;; 12) @@ -1425,6 +1425,13 @@ install_certbot() { } + + + + + + + install_ssltls() { check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 @@ -1446,7 +1453,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi - docker run -it --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi mkdir -p /home/web/certs/ @@ -1483,7 +1490,7 @@ if [ -z "$yuming" ]; then fi install_docker install_certbot -docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null +docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status install_ssltls_text @@ -1542,12 +1549,28 @@ certs_status() { echo -e "4. 防火牆限制 ➠ 檢查80/443端口是否開放,確保驗證可訪問" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" - break_end - clear - echo "請再次嘗試部署$webname" - add_yuming - install_ssltls - certs_status + echo "------------------------" + echo "1. 重新申請 2. 不帶證書改用HTTP訪問 0. 退出" + echo "------------------------" + read -e -p "請輸入你的選擇:" sub_choice + case $sub_choice in + 1) + send_stats "重新申請" + echo "請再次嘗試部署$webname" + add_yuming + install_ssltls + certs_status + ;; + 2) + send_stats "不帶證書改用HTTP訪問" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf + sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + ;; + *) + exit + ;; + esac fi } @@ -1569,6 +1592,40 @@ add_yuming() { } +check_ip_and_get_access_port() { + local yuming="$1" + + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + read -e -p "請輸入訪問/監聽端口,回車默認使用 80:" access_port + access_port=${access_port:-80} + fi +} + + + +update_nginx_listen_port() { + local yuming="$1" + local access_port="$2" + local conf="/home/web/conf.d/${yuming}.conf" + + # 如果 access_port 為空,則跳過 + [ -z "$access_port" ] && return 0 + + # 刪除所有 listen 行 + sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" + + # 在 server { 後插入新的 l​​isten + sed -i "/server {/a\\ + listen ${access_port};\\ + listen [::]:${access_port}; +" "$conf" +} + + + add_db() { dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbname="${dbname}" @@ -1579,17 +1636,6 @@ add_db() { docker exec mysql mysql -u root -p"$dbrootpasswd" -e "CREATE DATABASE $dbname; GRANT ALL PRIVILEGES ON $dbname.* TO \"$dbuse\"@\"%\";" } -reverse_proxy() { - ip_address - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$ipv4_address/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$duankou|g" /home/web/conf.d/$yuming.conf - nginx_http_on - docker exec nginx nginx -s reload -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 @@ -3238,10 +3284,21 @@ ldnmp_web_on() { } nginx_web_on() { - clear - echo "您的$webname搭建好了!" - echo "https://$yuming" + clear + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' + + echo "您的$webname搭建好了!" + + if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then + mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf + echo "http://$yuming:$access_port" + elif grep -q '^[[:space:]]*#.*if (\$scheme = http)' "/home/web/conf.d/"$yuming".conf"; then + echo "http://$yuming" + else + echo "https://$yuming" + fi } @@ -3258,14 +3315,16 @@ ldnmp_wp() { fi repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + install_ssltls + certs_status + add_db + cd /home/web/html mkdir $yuming cd $yuming @@ -3287,6 +3346,7 @@ ldnmp_wp() { } + ldnmp_Proxy() { clear webname="反向代理-IP+端口" @@ -3299,6 +3359,9 @@ ldnmp_Proxy() { if [ -z "$yuming" ]; then add_yuming fi + + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy" ]; then read -e -p "請輸入你的反代IP (回車默認本機IP 127.0.0.1):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} @@ -3308,13 +3371,31 @@ ldnmp_Proxy() { read -e -p "請輸入你的反代端口:" port fi nginx_install_status + + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + install_ssltls certs_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy.conf + + + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) + sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf + + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/0.0.0.0/$reverseproxy/g" /home/web/conf.d/$yuming.conf - sed -i "s|0000|$port|g" /home/web/conf.d/$yuming.conf + + reverseproxy_port="$reverseproxy:$port" + upstream_servers="" + for server in $reverseproxy_port; do + upstream_servers="$upstream_servers server $server;\n" + done + + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3332,16 +3413,21 @@ ldnmp_Proxy_backend() { add_yuming fi + check_ip_and_get_access_port "$yuming" + if [ -z "$reverseproxy_port" ]; then read -e -p "請輸入你的多個反代IP+端口用空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + + install_ssltls + certs_status + backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3355,6 +3441,8 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + update_nginx_listen_port "$yuming" "$access_port" + nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3596,6 +3684,25 @@ ldnmp_web_status() { fi done + for conf_file in /home/web/conf.d/*_*.conf; do + [ -e "$conf_file" ] || continue + basename "$conf_file" .conf + done + + for conf_file in /home/web/conf.d/*.conf; do + [ -e "$conf_file" ] || continue + + filename=$(basename "$conf_file") + + if [ "$filename" = "map.conf" ] || [ "$filename" = "default.conf" ]; then + continue + fi + + if ! grep -q "ssl_certificate" "$conf_file"; then + basename "$conf_file" .conf + fi + done + echo "------------------------" echo "" echo -e "資料庫:${db_output}" @@ -3628,7 +3735,7 @@ ldnmp_web_status() { send_stats "申請域名證書" read -e -p "請輸入你的域名:" yuming install_certbot - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls certs_status @@ -3727,7 +3834,7 @@ ldnmp_web_status() { 20) web_del - docker run -it --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null ;; *) @@ -5349,7 +5456,7 @@ clamav_scan() { > /home/docker/clamav/log/scan.log > /dev/null 2>&1 # 執行 Docker 命令 - docker run -it --rm \ + docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ $MOUNT_PARAMS \ @@ -7925,7 +8032,7 @@ linux_Oracle() { local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 運行Docker容器 - docker run -itd --name=lookbusy --restart=always \ + docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ -e CPU_CORE="$cpu_core" \ @@ -8130,12 +8237,17 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8167,12 +8279,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8202,12 +8317,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8245,12 +8364,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + + nginx_http_on cd /home/web/html @@ -8293,12 +8416,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8348,12 +8474,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8386,13 +8516,16 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8422,12 +8555,15 @@ linux_ldnmp() { add_yuming repeat_add_yuming ldnmp_install_status - install_ssltls - certs_status - add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + add_db + nginx_http_on cd /home/web/html @@ -8556,12 +8692,15 @@ linux_ldnmp() { add_yuming read -e -p "請輸入跳轉域名:" reverseproxy nginx_install_status - install_ssltls - certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8593,12 +8732,14 @@ linux_ldnmp() { echo -e "域名格式:${gl_huang}google.com${gl_bai}" read -e -p "請輸入你的反代域名:" fandai_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on docker exec nginx nginx -s reload @@ -8614,9 +8755,6 @@ linux_ldnmp() { send_stats "安裝$webname" echo "開始部署$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d \ --name bitwarden \ @@ -8624,10 +8762,10 @@ linux_ldnmp() { -p 3280:80 \ -v /home/web/html/$yuming/bitwarden/data:/data \ vaultwarden/server + duankou=3280 - reverse_proxy + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou - nginx_web_on ;; @@ -8637,15 +8775,11 @@ linux_ldnmp() { send_stats "安裝$webname" echo "開始部署$webname" add_yuming - nginx_install_status - install_ssltls - certs_status docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 - duankou=8010 - reverse_proxy - nginx_web_on + duankou=8010 + ldnmp_Proxy ${yuming} 127.0.0.1 $duankou ;; @@ -8656,11 +8790,13 @@ linux_ldnmp() { echo "開始部署$webname" add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -8695,11 +8831,13 @@ linux_ldnmp() { add_yuming repeat_add_yuming nginx_install_status - install_ssltls - certs_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + install_ssltls + certs_status + nginx_http_on cd /home/web/html @@ -9276,7 +9414,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" - local docker_use="docker exec -it openlist ./openlist admin random" + local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" docker_app @@ -9547,7 +9685,7 @@ while true; do -v /home/docker/mongo/dump:/dump \ mongo:latest --replSet rs5 --oplogSize 256 sleep 1 - docker exec -it db mongosh --eval "printjson(rs.initiate())" + docker exec db mongosh --eval "printjson(rs.initiate())" sleep 5 docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat @@ -10657,7 +10795,7 @@ while true; do docker_rum() { - docker run -it -d --name dpanel --restart=always \ + docker run -d --name dpanel --restart=always \ -p ${docker_port}:8080 -e APP_NAME=dpanel \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /home/docker/dpanel:/dpanel \ @@ -11056,7 +11194,7 @@ while true; do local docker_port=8068 docker_rum() { - docker run -itd --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest + docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } local docker_describe="开源免费的 SSL 证书自动化管理平台" @@ -11819,7 +11957,7 @@ while true; do add_yuming if [ ! -d /home/docker/matrix/data ]; then - docker run -it --rm \ + docker run --rm \ -v /home/docker/matrix/data:/data \ -e SYNAPSE_SERVER_NAME=${yuming} \ -e SYNAPSE_REPORT_STATS=yes \ @@ -12169,7 +12307,7 @@ while true; do done ' - docker exec -it wireguard bash -c ' + docker exec wireguard bash -c ' for d in /config/peer_*; do cd "$d" || continue conf_file=$(ls *.conf) @@ -12183,7 +12321,7 @@ while true; do sleep 2 echo echo -e "${gl_huang}所有客戶端二維碼配置:${gl_bai}" - docker exec -it wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' + docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo echo -e "${gl_huang}所有客戶端配置代碼:${gl_bai}" @@ -13001,6 +13139,62 @@ switch_mirror() { } +fail2ban_panel() { + root_use + send_stats "ssh防禦" + while true; do + + check_f2b_status + echo -e "SSH防禦程序$check_f2b_status" + echo "fail2ban是一個SSH防止暴力破解工具" + echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" + echo "------------------------" + echo "1. 安裝防禦程序" + echo "------------------------" + echo "2. 查看SSH攔截記錄" + echo "3. 日誌實時監控" + echo "------------------------" + echo "9. 卸載防禦程序" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "請輸入你的選擇:" sub_choice + case $sub_choice in + 1) + f2b_install_sshd + cd ~ + f2b_status + break_end + ;; + 2) + echo "------------------------" + f2b_sshd + echo "------------------------" + break_end + ;; + 3) + tail -f /var/log/fail2ban.log + break + ;; + 9) + remove fail2ban + rm -rf /etc/fail2ban + echo "Fail2Ban防禦程序已卸載" + break + ;; + *) + break + ;; + esac + done + +} + + + + + + linux_Settings() { @@ -13738,53 +13932,7 @@ EOF ;; 22) - root_use - send_stats "ssh防禦" - while true; do - - check_f2b_status - echo -e "SSH防禦程序$check_f2b_status" - echo "fail2ban是一個SSH防止暴力破解工具" - echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" - echo "------------------------" - echo "1. 安裝防禦程序" - echo "------------------------" - echo "2. 查看SSH攔截記錄" - echo "3. 日誌實時監控" - echo "------------------------" - echo "9. 卸載防禦程序" - echo "------------------------" - echo "0. 返回上一級選單" - echo "------------------------" - read -e -p "請輸入你的選擇:" sub_choice - case $sub_choice in - 1) - f2b_install_sshd - cd ~ - f2b_status - break_end - ;; - 2) - echo "------------------------" - f2b_sshd - echo "------------------------" - break_end - ;; - 3) - tail -f /var/log/fail2ban.log - break - ;; - 9) - remove fail2ban - rm -rf /etc/fail2ban - echo "Fail2Ban防禦程序已卸載" - break - ;; - *) - break - ;; - esac - done + fail2ban_panel ;; @@ -14907,6 +15055,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夾 k fav | k 命令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" +echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統信息 k info" } @@ -15139,8 +15288,14 @@ else linux_info ;; + fail2ban|f2b) + fail2ban_panel + ;; + *) k_info ;; esac fi + + From ac9eef3f2076e3c18e722d760b3a293f83bde8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:14:23 +0800 Subject: [PATCH 0441/1285] Add ConvertX multi-format conversion tool --- cn/kejilion.sh | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8105a0cb3..0b5785cb4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1568,7 +1568,8 @@ certs_status() { sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "退出申请" + exit ;; esac fi @@ -9273,6 +9274,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -12822,8 +12825,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + + } + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; From f38259d620489e4701fa21ffe3bf472941908438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:15:16 +0800 Subject: [PATCH 0442/1285] Add ConvertX multi-format conversion tool --- kejilion.sh | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index ee7500831..11ebad49b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1568,7 +1568,8 @@ certs_status() { sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "退出申请" + exit ;; esac fi @@ -9273,6 +9274,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -12822,8 +12825,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + + } + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + ;; From 33b0df8e62947661b8329247b5a3cd60f2d511b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:17:19 +0800 Subject: [PATCH 0443/1285] Update changelog with ConvertX tool details Added information about ConvertX file conversion tool. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index de8ca8a1e..810ac1c41 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1382,6 +1382,7 @@ nginx反向代理优化,定义upstream和keepalive提升后端连接性能和 2025-12-19 v4.2.9 nginx反向代理和负载均衡支持IP自定义监听端口功能,可实现反代内部IP加端口到网关的效果, SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问或者中断申请。 +应用市场新增了ConvertX全能文件转换工具的安装及使用。 ------------------------ From 0148da2cba7cf8386d48eb6e0929925ef2a25ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:17:40 +0800 Subject: [PATCH 0444/1285] Update version and add certificate import option --- cn/kejilion.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0b5785cb4..2f77f95b8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -1550,7 +1550,7 @@ certs_status() { echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" - echo "1. 重新申请 2. 不带证书改用HTTP访问 0. 退出" + echo "1. 重新申请 2. 导入已有证书 3. 不带证书改用HTTP访问 0. 退出" echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -1560,8 +1560,56 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "导入已有证书" + + # 定义文件路径 + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. 输入证书 (ECC 和 RSA 证书开头都是 BEGIN CERTIFICATE) + echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. 智能校验 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # 识别当前证书类型并显示 + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "检测到 ECC 证书已成功保存。" + else + echo "检测到 RSA 证书已成功保存。" + fi + auth_method="ssl_imported" + else + echo "错误:无效的证书或私钥格式!" + return 1 + fi + + ;; + 3) send_stats "不带证书改用HTTP访问" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf From 8477fb1e1f3f0b1cc0ce711b1fd7adcff172f493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:21:28 +0800 Subject: [PATCH 0445/1285] Update error handling in kejilion.sh Replace return statement with certs_status call on error. --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2f77f95b8..2411ba2fa 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1605,7 +1605,7 @@ certs_status() { auth_method="ssl_imported" else echo "错误:无效的证书或私钥格式!" - return 1 + certs_status fi ;; From df836fbaaf024a6013b7472e759fab15eec8e2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:22:05 +0800 Subject: [PATCH 0446/1285] Enhance SSL handling with certificate import option Added option to import existing SSL certificates and keys. --- kejilion.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 11ebad49b..e3c83a5ae 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -1550,7 +1550,7 @@ certs_status() { echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" - echo "1. 重新申请 2. 不带证书改用HTTP访问 0. 退出" + echo "1. 重新申请 2. 导入已有证书 3. 不带证书改用HTTP访问 0. 退出" echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -1560,8 +1560,56 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "导入已有证书" + + # 定义文件路径 + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. 输入证书 (ECC 和 RSA 证书开头都是 BEGIN CERTIFICATE) + echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. 智能校验 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # 识别当前证书类型并显示 + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "检测到 ECC 证书已成功保存。" + else + echo "检测到 RSA 证书已成功保存。" + fi + auth_method="ssl_imported" + else + echo "错误:无效的证书或私钥格式!" + certs_status + fi + + ;; + 3) send_stats "不带证书改用HTTP访问" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf From b12afa09d3b61211def5eb48a514598d9ba7d455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:24:25 +0800 Subject: [PATCH 0447/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 810ac1c41..c02015e99 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1384,5 +1384,8 @@ nginx反向代理和负载均衡支持IP自定义监听端口功能,可实现 SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问或者中断申请。 应用市场新增了ConvertX全能文件转换工具的安装及使用。 ------------------------ +2025-12-24 v4.2.10 +SSL申请失败后追加已有证书导入选项,你可以导入域名有效证书如CF15年证书使用。 +------------------------ From e96eaf1302654edfadfeea392837c8bc729be902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:33:48 +0800 Subject: [PATCH 0448/1285] Update SSL certificate import option description --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c02015e99..2d2473b91 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1385,7 +1385,7 @@ SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问 应用市场新增了ConvertX全能文件转换工具的安装及使用。 ------------------------ 2025-12-24 v4.2.10 -SSL申请失败后追加已有证书导入选项,你可以导入域名有效证书如CF15年证书使用。 +SSL申请失败后追加导入已有证书选项,你可以导入域名有效证书使用了(如CF15年证书)。 ------------------------ From d579da10df52f735c06fbf4fb72b857c8cfed041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:59:33 +0800 Subject: [PATCH 0449/1285] Update kejilion.sh --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2411ba2fa..2edb9a057 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13196,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "使用官方镜像源..." @@ -13207,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } From fcaa50edf4578ca6338f388a1b286fd1300af2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:00:17 +0800 Subject: [PATCH 0450/1285] Add --install-epel option to installation commands --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index e3c83a5ae..33f670e46 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13196,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "使用官方镜像源..." @@ -13207,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } From 80c4ba3017809e71e143ca936541028eb8fa1757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:12:54 +0800 Subject: [PATCH 0451/1285] Update translate.yml --- .github/workflows/translate.yml | 103 +++++++++++++++----------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/.github/workflows/translate.yml b/.github/workflows/translate.yml index a8f525880..6e2d6b7de 100644 --- a/.github/workflows/translate.yml +++ b/.github/workflows/translate.yml @@ -1,4 +1,3 @@ - name: Weekly Translation Workflow on: @@ -7,11 +6,9 @@ on: - cron: '0 2 * * 0' workflow_dispatch: # 允许手动触发 - permissions: contents: write - jobs: translate: runs-on: ubuntu-latest @@ -50,6 +47,8 @@ jobs: return bool(re.search(r'[\u4e00-\u9fff]', text)) def translate_text(text, target_lang): + if not text.strip() or not is_chinese(text): + return text try: return GoogleTranslator(source='zh-CN', target=target_lang).translate(text) except Exception as e: @@ -58,14 +57,13 @@ jobs: def translate_line_preserving_variables(line, target_lang): """ - Translate only Chinese parts in echo/read/send_stats commands, excluding shell variables + 处理 echo/read/send_stats 等命令中的中文,同时保护其中的 ${var} """ - # Match double or single quoted strings def repl(match): full_string = match.group(0) quote = full_string[0] content = full_string[1:-1] - # Split by variable expressions + # 分割出变量,只翻译非变量部分 parts = re.split(r'(\$\{?\w+\}?)', content) translated_parts = [ translate_text(p, target_lang) if is_chinese(p) else p @@ -74,6 +72,24 @@ jobs: return quote + ''.join(translated_parts) + quote return re.sub(r'(?:\'[^\']*\'|"[^"]*")', repl, line) + + def translate_assignment_value(line, target_lang): + """ + 专门处理变量赋值语句:VAR="中文内容" -> VAR="Translated Content" + """ + # 匹配 key="value" 或 key='value' 格式,且 value 包含中文 + match = re.match(r'^(\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)([\'"])(.*)([\'"])(.*)$', line) + if match: + prefix, quote_open, value, quote_close, suffix = match.groups() + if is_chinese(value): + # 同样要保护赋值内容里的 ${var} + parts = re.split(r'(\$\{?\w+\}?)', value) + translated_value = "".join([ + translate_text(p, target_lang) if is_chinese(p) else p + for p in parts + ]) + return f"{prefix}{quote_open}{translated_value}{quote_close}{suffix}\n" + return line def translate_file(input_file, output_file, target_lang): print(f"Translating to {target_lang}...") @@ -82,70 +98,60 @@ jobs: print(f"Error: Input file {input_file} not found") return False - total_lines = sum(1 for _ in open(input_file, 'r', encoding='utf-8')) - processed_lines = 0 + with open(input_file, 'r', encoding='utf-8') as f: + lines = f.readlines() + + total_lines = len(lines) - with open(input_file, 'r', encoding='utf-8') as f_in, \ - open(output_file, 'w', encoding='utf-8') as f_out: - - for line in f_in: - processed_lines += 1 - progress = processed_lines / total_lines * 100 - print(f"\rProcessing: {progress:.1f}% ({processed_lines}/{total_lines})", end='') + with open(output_file, 'w', encoding='utf-8') as f_out: + for i, line in enumerate(lines): + progress = (i + 1) / total_lines * 100 + print(f"\rProcessing: {progress:.1f}% ({i+1}/{total_lines})", end='') leading_space = re.match(r'^(\s*)', line).group(1) stripped = line.strip() + # 1. 处理注释 if stripped.startswith('#') and is_chinese(stripped): - comment_mark = '#' comment_text = stripped[1:].strip() if comment_text: translated = translate_text(comment_text, target_lang) - f_out.write(f"{leading_space}{comment_mark} {translated}\n") + f_out.write(f"{leading_space}# {translated}\n") else: f_out.write(line) + + # 2. 处理常用交互命令 elif any(cmd in stripped for cmd in ['echo', 'read', 'send_stats']) and is_chinese(stripped): - translated_line = translate_line_preserving_variables(line, target_lang) - f_out.write(translated_line) + f_out.write(translate_line_preserving_variables(line, target_lang)) + + # 3. 处理变量赋值中的中文 (新增强化) + elif '=' in stripped and is_chinese(stripped): + f_out.write(translate_assignment_value(line, target_lang)) + + # 4. 其他行原样保留 else: f_out.write(line) print(f"\nTranslation to {target_lang} completed.") - print(f"Original file size: {os.path.getsize(input_file)} bytes") - print(f"Translated file size: {os.path.getsize(output_file)} bytes") return True if __name__ == "__main__": input_file = 'kejilion.sh' - - # 语言映射:目录名 -> Google翻译语言代码 - languages = { - 'en': 'en', # 英语 - 'tw': 'zh-TW', # 繁体中文 - 'kr': 'ko', # 韩语 - 'jp': 'ja' # 日语 - } + languages = {'en': 'en', 'tw': 'zh-TW', 'kr': 'ko', 'jp': 'ja'} success_count = 0 - for dir_name, lang_code in languages.items(): output_file = f'{dir_name}/kejilion.sh' if translate_file(input_file, output_file, lang_code): success_count += 1 - print(f"✓ Successfully translated to {dir_name}") - else: - print(f"✗ Failed to translate to {dir_name}") - print("-" * 50) - - print(f"\nTranslation summary: {success_count}/{len(languages)} languages completed") + print(f"✓ {dir_name} done") + print("-" * 30) - if success_count == 0: - sys.exit(1) + if success_count == 0: sys.exit(1) EOF - name: Run translation - run: | - python translate.py + run: python translate.py - name: Check for changes id: check_changes @@ -162,7 +168,6 @@ jobs: run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - git add . git commit -m "🌐 Weekly translation update - $(date +'%Y-%m-%d %H:%M:%S')" git push env: @@ -172,26 +177,12 @@ jobs: if: always() run: | echo "## Translation Summary 📊" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY echo "| Language | Directory | Status |" >> $GITHUB_STEP_SUMMARY echo "|----------|-----------|--------|" >> $GITHUB_STEP_SUMMARY - for dir in en tw kr jp; do if [ -f "$dir/kejilion.sh" ]; then - size=$(stat -c%s "$dir/kejilion.sh") - echo "| $dir | /$dir/ | ✅ Success (${size} bytes) |" >> $GITHUB_STEP_SUMMARY + echo "| $dir | /$dir/ | ✅ Success |" >> $GITHUB_STEP_SUMMARY else echo "| $dir | /$dir/ | ❌ Failed |" >> $GITHUB_STEP_SUMMARY fi done - - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Execution time:** $(date)" >> $GITHUB_STEP_SUMMARY - - if [ "${{ steps.check_changes.outputs.has_changes }}" == "true" ]; then - echo "**Changes:** New translations committed and pushed" >> $GITHUB_STEP_SUMMARY - else - echo "**Changes:** No changes detected" >> $GITHUB_STEP_SUMMARY - fi - - From 20c390fb2bec962bd25a16b2c4061c9fbb0c15b1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 24 Dec 2025 04:53:06 +0000 Subject: [PATCH 0452/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-24=2004:53:06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 157 ++++++++++++++++++++-------- jp/kejilion.sh | 275 +++++++++++++++++++++++++++++++------------------ kr/kejilion.sh | 199 ++++++++++++++++++++++++----------- translate.py | 80 +++++++------- tw/kejilion.sh | 135 ++++++++++++++++++------ 5 files changed, 578 insertions(+), 268 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 807db858c..a6159b887 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -881,7 +881,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1550,7 +1550,7 @@ certs_status() { echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" echo -e "6. Domestic registration restrictions ➠ For mainland China environment, please confirm whether the domain name is registered" echo "------------------------" - echo "1. Reapply 2. Switch to HTTP access without certificate 0. Exit" + echo "1. Apply again 2. Import the existing certificate 3. Use HTTP access without certificate 0. Exit" echo "------------------------" read -e -p "Please enter your choice:" sub_choice case $sub_choice in @@ -1560,15 +1560,64 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "Import existing certificate" + + # Define file path + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. Enter the certificate (both ECC and RSA certificates start with BEGIN CERTIFICATE) + echo "Please paste the certificate (CRT/PEM) content (press Enter twice to end):" + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. Enter the private key (compatible with RSA, ECC, PKCS#8) + echo "Please paste the certificate private key (Private Key) content (press Enter twice to end):" + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. Intelligent verification + # Just include "BEGIN CERTIFICATE" and "PRIVATE KEY" to pass + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # Identify the current certificate type and display it + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "Detected that the ECC certificate was saved successfully." + else + echo "Detected that the RSA certificate was saved successfully." + fi + auth_method="ssl_imported" + else + echo "Error: Invalid certificate or private key format!" + certs_status + fi + + ;; + 3) send_stats "Switch to HTTP access without a certificate" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "Withdraw application" + exit ;; esac fi @@ -1813,7 +1862,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status=" WAF已开启" + waf_status="WAF is turned on" else waf_status="" fi @@ -1822,7 +1871,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage=" cf模式已开启" + CFmessage="cf mode is on" else CFmessage="" fi @@ -2269,9 +2318,9 @@ check_ldnmp_mode() { # Check if MySQL configuration file contains 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info=" 高性能模式" + mode_info="High performance mode" else - mode_info=" 标准模式" + mode_info="Standard mode" fi @@ -2285,21 +2334,21 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status=" zstd压缩已开启" + zstd_status="zstd compression is on" else zstd_status="" fi # Check if brotli is enabled and uncommented if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="brCompression is on" else br_status="" fi # Check if gzip is enabled and uncommented if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status=" gzip压缩已开启" + gzip_status="gzip compression is on" else gzip_status="" fi @@ -2452,9 +2501,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}已安装${gl_bai}" + check_docker="${gl_lv}Installed${gl_bai}" else - check_docker="${gl_hui}未安装${gl_bai}" + check_docker="${gl_hui}Not installed${gl_bai}" fi } @@ -2537,7 +2586,7 @@ check_docker_image_update() { # Compare timestamps if [[ $container_created_ts -lt $last_updated_ts ]]; then - update_status="${gl_huang}发现新版本!${gl_bai}" + update_status="${gl_huang}New version found!${gl_bai}" else update_status="" fi @@ -3112,9 +3161,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}已安装${gl_bai}" + check_f2b_status="${gl_lv}Installed${gl_bai}" else - check_f2b_status="${gl_hui}未安装${gl_bai}" + check_f2b_status="${gl_hui}Not installed${gl_bai}" fi } @@ -3349,7 +3398,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="Reverse proxy-IP+port" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3405,7 +3454,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="Reverse proxy-load balancing" send_stats "Install$webname" echo "Start deployment$webname" @@ -3579,7 +3628,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四层代理-负载均衡" + webname="Stream four-layer proxy-load balancing" send_stats "Install$webname" echo "Start deployment$webname" @@ -3849,7 +3898,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安装${gl_bai}" + check_panel="${gl_lv}Installed${gl_bai}" else check_panel="" fi @@ -3910,9 +3959,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}已安装${gl_bai}" + check_frp="${gl_lv}Installed${gl_bai}" else - check_frp="${gl_hui}未安装${gl_bai}" + check_frp="${gl_hui}Not installed${gl_bai}" fi } @@ -4845,7 +4894,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } @@ -5933,9 +5982,9 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}未启用${gl_bai}" + trash_status="${gl_hui}Not enabled${gl_bai}" else - trash_status="${gl_lv}已启用${gl_bai}" + trash_status="${gl_lv}Enabled${gl_bai}" fi clear @@ -7297,7 +7346,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8211,8 +8260,8 @@ linux_ldnmp() { echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore whole site data" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environments${gl_huang}36. ${gl_bai}Optimize LDNMP environment" - echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall the LDNMP environment" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}Optimize LDNMP environment" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}Uninstall the LDNMP environment" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}Return to main menu" echo -e "${gl_huang}------------------------${gl_bai}" @@ -8231,7 +8280,7 @@ linux_ldnmp() { 3) clear # Discuz Forum - webname="Discuz论坛" + webname="Discuz Forum" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8273,7 +8322,7 @@ linux_ldnmp() { 4) clear # Kedao cloud desktop - webname="可道云桌面" + webname="Kedao cloud desktop" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8311,7 +8360,7 @@ linux_ldnmp() { 5) clear # AppleCMS - webname="苹果CMS" + webname="AppleCMS" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8358,7 +8407,7 @@ linux_ldnmp() { 6) clear # One-legged number card - webname="独脚数卡" + webname="One-legged number card" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8410,7 +8459,7 @@ linux_ldnmp() { 7) clear # flarum forum - webname="flarum论坛" + webname="flarum forum" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8549,7 +8598,7 @@ linux_ldnmp() { 20) clear - webname="PHP动态站点" + webname="PHP dynamic site" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8686,7 +8735,7 @@ linux_ldnmp() { 22) clear - webname="站点重定向" + webname="site redirect" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8725,7 +8774,7 @@ linux_ldnmp() { 24) clear - webname="反向代理-域名" + webname="Reverse proxy-domain name" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8785,7 +8834,7 @@ linux_ldnmp() { 27) clear - webname="AI绘画提示词生成器" + webname="AI painting prompt word generator" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -8825,7 +8874,7 @@ linux_ldnmp() { 30) clear - webname="静态站点" + webname="static site" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -9273,6 +9322,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou network disk search${gl_kjlan}108. ${color108}LangBot chatbot" echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -9553,7 +9604,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -12822,8 +12873,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + } + + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + + ;; @@ -13123,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "Use official mirror source..." @@ -13134,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } @@ -13271,7 +13346,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -14619,7 +14694,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4628b2dc2..12cc6266f 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストール中$package...${gl_bai}" + echo -e "${gl_huang}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -858,7 +858,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done @@ -921,12 +921,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1186,7 +1186,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1543,14 +1543,14 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" echo "------------------------" - echo "1. 再適用 2. 証明書なしの HTTP アクセスに切り替える 0. 終了" + echo "1. 再度適用します。 2. 既存の証明書をインポートします。 3. 証明書なしで HTTP アクセスを使用します。 0. 終了します。" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -1560,15 +1560,64 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "既存の証明書をインポートする" + + # ファイルパスを定義する + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. 証明書を入力します (ECC 証明書と RSA 証明書はどちらも BEGIN CERTIFICATE で始まります) + echo "証明書 (CRT/PEM) の内容を貼り付けてください (Enter を 2 回押して終了します)。" + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. 秘密キーを入力します (RSA、ECC、PKCS#8 と互換性があります) + echo "証明書の秘密キー (Private Key) の内容を貼り付けてください (Enter を 2 回押して終了します)。" + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. インテリジェントな検証 + # 「BEGIN CERTIFICATE」と「PRIVATE KEY」を含めるだけで渡されます + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # 現在の証明書の種類を特定して表示します。 + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "ECC証明書が正常に保存されたことが検出されました。" + else + echo "RSA証明書が正常に保存されたことが検出されました。" + fi + auth_method="ssl_imported" + else + echo "エラー: 証明書または秘密キーの形式が無効です。" + certs_status + fi + + ;; + 3) send_stats "証明書なしの HTTP アクセスに切り替える" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "申請を取り下げる" + exit ;; esac fi @@ -1711,7 +1760,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1813,7 +1862,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status=" WAF已开启" + waf_status="WAFがオンになっている" else waf_status="" fi @@ -1822,7 +1871,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage=" cf模式已开启" + CFmessage="cfモードがオンになっています" else CFmessage="" fi @@ -1952,7 +2001,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2201,8 +2250,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2269,9 +2318,9 @@ check_ldnmp_mode() { # MySQL 設定ファイルに 4096M が含まれているかどうかを確認する if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info=" 高性能模式" + mode_info="ハイパフォーマンスモード" else - mode_info=" 标准模式" + mode_info="標準モード" fi @@ -2285,21 +2334,21 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status=" zstd压缩已开启" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi # Brotli が有効になっていてコメントが解除されているかどうかを確認します if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="br圧縮がオンになっています" else br_status="" fi # gzip が有効になっていてコメントが解除されているかどうかを確認します if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status=" gzip压缩已开启" + gzip_status="gzip圧縮がオンになっています" else gzip_status="" fi @@ -2316,7 +2365,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2452,9 +2501,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}已安装${gl_bai}" + check_docker="${gl_lv}インストール済み${gl_bai}" else - check_docker="${gl_hui}未安装${gl_bai}" + check_docker="${gl_hui}インストールされていません${gl_bai}" fi } @@ -2537,7 +2586,7 @@ check_docker_image_update() { # タイムスタンプを比較する if [[ $container_created_ts -lt $last_updated_ts ]]; then - update_status="${gl_huang}发现新版本!${gl_bai}" + update_status="${gl_huang}新しいバージョンが見つかりました!${gl_bai}" else update_status="" fi @@ -2574,7 +2623,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2591,7 +2640,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2846,7 +2895,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -2959,7 +3008,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3112,9 +3161,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}已安装${gl_bai}" + check_f2b_status="${gl_lv}インストール済み${gl_bai}" else - check_f2b_status="${gl_hui}未安装${gl_bai}" + check_f2b_status="${gl_hui}インストールされていません${gl_bai}" fi } @@ -3349,7 +3398,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="リバースプロキシ IP+ポート" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3405,7 +3454,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="リバースプロキシ負荷分散" send_stats "インストール$webname" echo "導入を開始する$webname" @@ -3535,7 +3584,7 @@ stream_panel() { send_stats "ストリームの 4 層プロキシを更新します" ;; 3) - read -e -p "nginx コンテナを削除してもよろしいですか?これはウェブサイトの機能に影響を与える可能性があります。 (y/N):" confirm + read -e -p "Are you sure you want to delete the nginx container?これはウェブサイトの機能に影響を与える可能性があります。 (y/N):" confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx sed -i "/\b${app_id}\b/d" /home/docker/appno.txt @@ -3579,7 +3628,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四层代理-负载均衡" + webname="ストリーム 4 層プロキシ負荷分散" send_stats "インストール$webname" echo "導入を開始する$webname" @@ -3783,7 +3832,7 @@ ldnmp_web_status() { ;; 4) send_stats "関連サイトの作成" - echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスする" + echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスします" read -e -p "既存のドメイン名を入力してください:" oddyuming read -e -p "新しいドメイン名を入力してください:" yuming install_certbot @@ -3817,7 +3866,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3849,7 +3898,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安装${gl_bai}" + check_panel="${gl_lv}インストール済み${gl_bai}" else check_panel="" fi @@ -3910,9 +3959,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}已安装${gl_bai}" + check_frp="${gl_lv}インストール済み${gl_bai}" else - check_frp="${gl_hui}未安装${gl_bai}" + check_frp="${gl_hui}インストールされていません${gl_bai}" fi } @@ -4007,7 +4056,7 @@ add_forwarding_service() { read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -4164,7 +4213,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4684,7 +4733,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4845,7 +4894,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } @@ -5064,7 +5113,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5398,7 +5447,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5446,7 +5495,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5823,7 +5872,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -5933,9 +5982,9 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}未启用${gl_bai}" + trash_status="${gl_hui}有効になっていません${gl_bai}" else - trash_status="${gl_lv}已启用${gl_bai}" + trash_status="${gl_lv}有効${gl_bai}" fi clear @@ -6328,9 +6377,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションのマウント +# パーティションをマウントする mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6349,7 +6398,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6509,7 +6558,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6677,7 +6726,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6955,7 +7004,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7249,7 +7298,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" + echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7344,7 +7393,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" @@ -7426,7 +7475,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7451,7 +7500,7 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" @@ -7675,7 +7724,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8018,7 +8067,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8231,7 +8280,7 @@ linux_ldnmp() { 3) clear # ディスカスフォーラム - webname="Discuz论坛" + webname="ディスカスフォーラム" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8273,7 +8322,7 @@ linux_ldnmp() { 4) clear # Kedao クラウド デスクトップ - webname="可道云桌面" + webname="Kedao クラウド デスクトップ" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8311,7 +8360,7 @@ linux_ldnmp() { 5) clear # AppleCMS - webname="苹果CMS" + webname="AppleCMS" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8358,7 +8407,7 @@ linux_ldnmp() { 6) clear # 一本足のナンバーカード - webname="独脚数卡" + webname="一本足のナンバーカード" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8402,7 +8451,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8410,7 +8459,7 @@ linux_ldnmp() { 7) clear # フララムフォーラム - webname="flarum论坛" + webname="フララムフォーラム" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8549,7 +8598,7 @@ linux_ldnmp() { 20) clear - webname="PHP动态站点" + webname="PHP動的サイト" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8686,7 +8735,7 @@ linux_ldnmp() { 22) clear - webname="站点重定向" + webname="サイトリダイレクト" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8725,7 +8774,7 @@ linux_ldnmp() { 24) clear - webname="反向代理-域名" + webname="リバースプロキシドメイン名" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8785,7 +8834,7 @@ linux_ldnmp() { 27) clear - webname="AI绘画提示词生成器" + webname="AI絵画プロンプトワードジェネレーター" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8825,7 +8874,7 @@ linux_ldnmp() { 30) clear - webname="静态站点" + webname="静的サイト" send_stats "インストール$webname" echo "導入を開始する$webname" add_yuming @@ -8902,7 +8951,7 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "エラー: リモート サーバーの IP を入力してください。" @@ -9231,7 +9280,7 @@ while true; do echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nexterm リモート接続ツール" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nextermリモート接続ツール" echo -e "${gl_kjlan}43. ${color43}RustDesk リモート デスクトップ (サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker アクセラレーション ステーション${gl_kjlan}46. ${color46}GitHub アクセラレーション ステーション${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}プロメテウスの監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" @@ -9257,7 +9306,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}------------------------" @@ -9273,6 +9322,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" @@ -12822,8 +12873,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + } + + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + + ;; @@ -12844,7 +12917,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -12922,7 +12995,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13123,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "公式ミラーソースを使用してください..." @@ -13134,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } @@ -13205,7 +13280,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -13276,7 +13351,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -13383,7 +13458,7 @@ EOF send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSHポート変更の終了" + send_stats "SSH ポート変更の終了" break else echo "ポート番号が無効です。 1 ~ 65535 の数字を入力してください。" @@ -13674,7 +13749,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13689,7 +13764,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14431,7 +14506,7 @@ linux_file() { 4) # 重命名目录 read -e -p "現在のディレクトリ名を入力してください:" current_name read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前の変更に失敗しました" + mv "$current_name" "$new_name" && echo "ディレクトリ名が変更されました" || echo "名前の変更に失敗しました" send_stats "ディレクトリの名前を変更する" ;; 5) # 删除目录 @@ -14492,7 +14567,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14512,7 +14587,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14619,7 +14694,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14648,10 +14723,10 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14693,7 +14768,7 @@ while true; do 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14767,7 +14842,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" @@ -14976,7 +15051,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -15015,8 +15090,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -15025,10 +15100,10 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" -echo "イントラネット普及率 (サーバー) k frps" +echo "イントラネットの普及率 (サーバー) k frps" echo "イントラネット浸透率 (クライアント) k frpc" echo "ソフトウェア起動 k start sshd | sshdを起動します" echo "ソフトウェア停止 k 停止 sshd | k ストップ sshd" @@ -15044,11 +15119,11 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" -echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" +echo "L4 ロード バランシングのインストール k ストリーム |k L4 ロード バランシング" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -15145,7 +15220,7 @@ else swap) shift - send_stats "仮想メモリをすばやくセットアップする" + send_stats "仮想メモリを素早く設定する" add_swap "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b6ae7276f..d63ce1259 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1545,12 +1545,12 @@ certs_status() { echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" - echo "1. 재적용 2. 인증서 없이 HTTP 접속으로 전환 0. 종료" + echo "1. 다시 적용 2. 기존 인증서 가져오기 3. 인증서 없이 HTTP 액세스 사용 0. 종료" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -1560,15 +1560,64 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "기존 인증서 가져오기" + + # 파일 경로 정의 + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. 인증서를 입력합니다(ECC 및 RSA 인증서 모두 BEGIN CERTIFICATE로 시작함). + echo "인증서(CRT/PEM) 콘텐츠를 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. 개인 키를 입력하세요. (RSA, ECC, PKCS#8과 호환 가능) + echo "인증서 개인 키(개인 키) 내용을 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. 지능형 검증 + # 통과하려면 "BEGIN CERTIFICATE" 및 "PRIVATE KEY"만 포함하면 됩니다. + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # 현재 인증서 유형을 식별하고 표시합니다. + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "ECC 인증서가 성공적으로 저장되었음을 감지했습니다." + else + echo "RSA 인증서가 성공적으로 저장되었음을 감지했습니다." + fi + auth_method="ssl_imported" + else + echo "오류: 잘못된 인증서 또는 개인 키 형식입니다!" + certs_status + fi + + ;; + 3) send_stats "인증서 없이 HTTP 액세스로 전환" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "신청철회" + exit ;; esac fi @@ -1813,7 +1862,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status=" WAF已开启" + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -1822,7 +1871,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage=" cf模式已开启" + CFmessage="cf 모드가 켜져 있습니다" else CFmessage="" fi @@ -2199,7 +2248,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2269,9 +2318,9 @@ check_ldnmp_mode() { # MySQL 구성 파일에 4096M이 포함되어 있는지 확인하세요. if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info=" 高性能模式" + mode_info="고성능 모드" else - mode_info=" 标准模式" + mode_info="표준 모드" fi @@ -2285,21 +2334,21 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status=" zstd压缩已开启" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi # brotli가 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="br압축이 켜져 있습니다" else br_status="" fi # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status=" gzip压缩已开启" + gzip_status="gzip 압축이 켜져 있습니다" else gzip_status="" fi @@ -2452,9 +2501,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}已安装${gl_bai}" + check_docker="${gl_lv}설치됨${gl_bai}" else - check_docker="${gl_hui}未安装${gl_bai}" + check_docker="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -2537,7 +2586,7 @@ check_docker_image_update() { # 타임스탬프 비교 if [[ $container_created_ts -lt $last_updated_ts ]]; then - update_status="${gl_huang}发现新版本!${gl_bai}" + update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" else update_status="" fi @@ -3112,9 +3161,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}已安装${gl_bai}" + check_f2b_status="${gl_lv}설치됨${gl_bai}" else - check_f2b_status="${gl_hui}未安装${gl_bai}" + check_f2b_status="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -3276,10 +3325,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3289,7 +3338,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3349,7 +3398,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="역방향 프록시-IP+포트" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3363,7 +3412,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3405,7 +3454,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="역방향 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3579,7 +3628,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四层代理-负载均衡" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3627,7 +3676,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -3849,7 +3898,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安装${gl_bai}" + check_panel="${gl_lv}설치됨${gl_bai}" else check_panel="" fi @@ -3910,9 +3959,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}已安装${gl_bai}" + check_frp="${gl_lv}설치됨${gl_bai}" else - check_frp="${gl_hui}未安装${gl_bai}" + check_frp="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -3960,7 +4009,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4022,7 +4071,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -5933,9 +5982,9 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}未启用${gl_bai}" + trash_status="${gl_hui}활성화되지 않음${gl_bai}" else - trash_status="${gl_lv}已启用${gl_bai}" + trash_status="${gl_lv}활성화됨${gl_bai}" fi clear @@ -7309,7 +7358,7 @@ docker_ssh_migration() { # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home/docker 아래의 파일을 백업하세요...${NC}" + echo -e "${BLUE}/home/docker 아래의 파일을 백업합니다...${NC}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - echo -e "${GREEN}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" fi @@ -7356,7 +7405,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7491,7 +7540,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8006,7 +8055,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8231,7 +8280,7 @@ linux_ldnmp() { 3) clear # 토론 포럼 - webname="Discuz论坛" + webname="토론 포럼" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8273,7 +8322,7 @@ linux_ldnmp() { 4) clear # Kedao 클라우드 데스크탑 - webname="可道云桌面" + webname="Kedao 클라우드 데스크탑" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8311,7 +8360,7 @@ linux_ldnmp() { 5) clear # AppleCMS - webname="苹果CMS" + webname="AppleCMS" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8358,7 +8407,7 @@ linux_ldnmp() { 6) clear # 한쪽다리 숫자카드 - webname="独脚数卡" + webname="한쪽다리 숫자카드" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8410,7 +8459,7 @@ linux_ldnmp() { 7) clear # 플라럼 포럼 - webname="flarum论坛" + webname="플라럼 포럼" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8549,7 +8598,7 @@ linux_ldnmp() { 20) clear - webname="PHP动态站点" + webname="PHP 동적 사이트" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8686,7 +8735,7 @@ linux_ldnmp() { 22) clear - webname="站点重定向" + webname="사이트 리디렉션" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8725,12 +8774,12 @@ linux_ldnmp() { 24) clear - webname="反向代理-域名" + webname="역방향 프록시 도메인 이름" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf @@ -8785,7 +8834,7 @@ linux_ldnmp() { 27) clear - webname="AI绘画提示词生成器" + webname="AI 그림 프롬프트 단어 생성기" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -8825,7 +8874,7 @@ linux_ldnmp() { 30) clear - webname="静态站点" + webname="정적 사이트" send_stats "설치하다$webname" echo "배포 시작$webname" add_yuming @@ -9221,7 +9270,7 @@ while true; do echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}------------------------" @@ -9249,7 +9298,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9273,6 +9322,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" @@ -9473,7 +9524,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9553,7 +9604,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -12822,8 +12873,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + } + + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + + ;; @@ -13034,7 +13107,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13123,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "공식 미러 소스를 사용하세요..." @@ -13134,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } @@ -13504,7 +13579,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -13694,7 +13769,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -13762,7 +13837,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -13857,7 +13932,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -14619,7 +14694,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15014,7 +15089,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -15043,7 +15118,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" @@ -15053,7 +15128,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/translate.py b/translate.py index 08fa7e575..496df5347 100644 --- a/translate.py +++ b/translate.py @@ -9,6 +9,8 @@ def is_chinese(text): return bool(re.search(r'[\u4e00-\u9fff]', text)) def translate_text(text, target_lang): + if not text.strip() or not is_chinese(text): + return text try: return GoogleTranslator(source='zh-CN', target=target_lang).translate(text) except Exception as e: @@ -17,14 +19,13 @@ def translate_text(text, target_lang): def translate_line_preserving_variables(line, target_lang): """ - Translate only Chinese parts in echo/read/send_stats commands, excluding shell variables + 处理 echo/read/send_stats 等命令中的中文,同时保护其中的 ${var} """ - # Match double or single quoted strings def repl(match): full_string = match.group(0) quote = full_string[0] content = full_string[1:-1] - # Split by variable expressions + # 分割出变量,只翻译非变量部分 parts = re.split(r'(\$\{?\w+\}?)', content) translated_parts = [ translate_text(p, target_lang) if is_chinese(p) else p @@ -34,6 +35,24 @@ def repl(match): return re.sub(r'(?:\'[^\']*\'|"[^"]*")', repl, line) +def translate_assignment_value(line, target_lang): + """ + 专门处理变量赋值语句:VAR="中文内容" -> VAR="Translated Content" + """ + # 匹配 key="value" 或 key='value' 格式,且 value 包含中文 + match = re.match(r'^(\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)([\'"])(.*)([\'"])(.*)$', line) + if match: + prefix, quote_open, value, quote_close, suffix = match.groups() + if is_chinese(value): + # 同样要保护赋值内容里的 ${var} + parts = re.split(r'(\$\{?\w+\}?)', value) + translated_value = "".join([ + translate_text(p, target_lang) if is_chinese(p) else p + for p in parts + ]) + return f"{prefix}{quote_open}{translated_value}{quote_close}{suffix}\n" + return line + def translate_file(input_file, output_file, target_lang): print(f"Translating to {target_lang}...") @@ -41,62 +60,53 @@ def translate_file(input_file, output_file, target_lang): print(f"Error: Input file {input_file} not found") return False - total_lines = sum(1 for _ in open(input_file, 'r', encoding='utf-8')) - processed_lines = 0 + with open(input_file, 'r', encoding='utf-8') as f: + lines = f.readlines() + + total_lines = len(lines) - with open(input_file, 'r', encoding='utf-8') as f_in, \ - open(output_file, 'w', encoding='utf-8') as f_out: - - for line in f_in: - processed_lines += 1 - progress = processed_lines / total_lines * 100 - print(f"\rProcessing: {progress:.1f}% ({processed_lines}/{total_lines})", end='') + with open(output_file, 'w', encoding='utf-8') as f_out: + for i, line in enumerate(lines): + progress = (i + 1) / total_lines * 100 + print(f"\rProcessing: {progress:.1f}% ({i+1}/{total_lines})", end='') leading_space = re.match(r'^(\s*)', line).group(1) stripped = line.strip() + # 1. 处理注释 if stripped.startswith('#') and is_chinese(stripped): - comment_mark = '#' comment_text = stripped[1:].strip() if comment_text: translated = translate_text(comment_text, target_lang) - f_out.write(f"{leading_space}{comment_mark} {translated}\n") + f_out.write(f"{leading_space}# {translated}\n") else: f_out.write(line) + + # 2. 处理常用交互命令 elif any(cmd in stripped for cmd in ['echo', 'read', 'send_stats']) and is_chinese(stripped): - translated_line = translate_line_preserving_variables(line, target_lang) - f_out.write(translated_line) + f_out.write(translate_line_preserving_variables(line, target_lang)) + + # 3. 处理变量赋值中的中文 (新增强化) + elif '=' in stripped and is_chinese(stripped): + f_out.write(translate_assignment_value(line, target_lang)) + + # 4. 其他行原样保留 else: f_out.write(line) print(f"\nTranslation to {target_lang} completed.") - print(f"Original file size: {os.path.getsize(input_file)} bytes") - print(f"Translated file size: {os.path.getsize(output_file)} bytes") return True if __name__ == "__main__": input_file = 'kejilion.sh' - - # 语言映射:目录名 -> Google翻译语言代码 - languages = { - 'en': 'en', # 英语 - 'tw': 'zh-TW', # 繁体中文 - 'kr': 'ko', # 韩语 - 'jp': 'ja' # 日语 - } + languages = {'en': 'en', 'tw': 'zh-TW', 'kr': 'ko', 'jp': 'ja'} success_count = 0 - for dir_name, lang_code in languages.items(): output_file = f'{dir_name}/kejilion.sh' if translate_file(input_file, output_file, lang_code): success_count += 1 - print(f"✓ Successfully translated to {dir_name}") - else: - print(f"✗ Failed to translate to {dir_name}") - print("-" * 50) - - print(f"\nTranslation summary: {success_count}/{len(languages)} languages completed") + print(f"✓ {dir_name} done") + print("-" * 30) - if success_count == 0: - sys.exit(1) + if success_count == 0: sys.exit(1) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index de76654f6..e9fc50a50 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.9" +sh_v="4.2.10" gl_hui='\e[37m' @@ -1550,7 +1550,7 @@ certs_status() { echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" echo "------------------------" - echo "1. 重新申請 2. 不帶證書改用HTTP訪問 0. 退出" + echo "1. 重新申請 2. 導入已有證書 3. 不帶證書改用HTTP訪問 0. 退出" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -1560,15 +1560,64 @@ certs_status() { add_yuming install_ssltls certs_status + ;; 2) + send_stats "導入已有證書" + + # 定義文件路徑 + local cert_file="/home/web/certs/${yuming}_cert.pem" + local key_file="/home/web/certs/${yuming}_key.pem" + + mkdir -p /home/web/certs + + # 1. 輸入證書 (ECC 和 RSA 證書開頭都是 BEGIN CERTIFICATE) + echo "請粘貼 證書 (CRT/PEM) 內容 (按兩次回車結束):" + local cert_content="" + while IFS= read -r line; do + [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break + cert_content+="${line}"$'\n' + done + + # 2. 輸入私鑰 (兼容 RSA, ECC, PKCS#8) + echo "請粘貼 證書私鑰 (Private Key) 內容 (按兩次回車結束):" + local key_content="" + while IFS= read -r line; do + [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break + key_content+="${line}"$'\n' + done + + # 3. 智能校驗 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通過 + if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then + echo -n "$cert_content" > "$cert_file" + echo -n "$key_content" > "$key_file" + + chmod 644 "$cert_file" + chmod 600 "$key_file" + + # 識別當前證書類型並顯示 + if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then + echo "檢測到 ECC 證書已成功保存。" + else + echo "檢測到 RSA 證書已成功保存。" + fi + auth_method="ssl_imported" + else + echo "錯誤:無效的證書或私鑰格式!" + certs_status + fi + + ;; + 3) send_stats "不帶證書改用HTTP訪問" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - exit + send_stats "退出申請" + exit ;; esac fi @@ -1813,7 +1862,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status=" WAF已开启" + waf_status="WAF已開啟" else waf_status="" fi @@ -1822,7 +1871,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage=" cf模式已开启" + CFmessage="cf模式已開啟" else CFmessage="" fi @@ -2269,9 +2318,9 @@ check_ldnmp_mode() { # 檢查 MySQL 配置文件中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info=" 高性能模式" + mode_info="高性能模式" else - mode_info=" 标准模式" + mode_info="標準模式" fi @@ -2285,21 +2334,21 @@ check_nginx_compression() { # 檢查 zstd 是否開啟且未被註釋(整行以 zstd on; 開頭) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status=" zstd压缩已开启" + zstd_status="zstd壓縮已開啟" else zstd_status="" fi # 檢查 brotli 是否開啟且未被註釋 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="br壓縮已開啟" else br_status="" fi # 檢查 gzip 是否開啟且未被註釋 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status=" gzip压缩已开启" + gzip_status="gzip壓縮已開啟" else gzip_status="" fi @@ -2452,9 +2501,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}已安装${gl_bai}" + check_docker="${gl_lv}已安裝${gl_bai}" else - check_docker="${gl_hui}未安装${gl_bai}" + check_docker="${gl_hui}未安裝${gl_bai}" fi } @@ -2537,7 +2586,7 @@ check_docker_image_update() { # 比較時間戳 if [[ $container_created_ts -lt $last_updated_ts ]]; then - update_status="${gl_huang}发现新版本!${gl_bai}" + update_status="${gl_huang}發現新版本!${gl_bai}" else update_status="" fi @@ -3112,9 +3161,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}已安装${gl_bai}" + check_f2b_status="${gl_lv}已安裝${gl_bai}" else - check_f2b_status="${gl_hui}未安装${gl_bai}" + check_f2b_status="${gl_hui}未安裝${gl_bai}" fi } @@ -3405,7 +3454,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="反向代理-負載均衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3579,7 +3628,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四层代理-负载均衡" + webname="Stream四層代理-負載均衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3849,7 +3898,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安装${gl_bai}" + check_panel="${gl_lv}已安裝${gl_bai}" else check_panel="" fi @@ -3910,9 +3959,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}已安装${gl_bai}" + check_frp="${gl_lv}已安裝${gl_bai}" else - check_frp="${gl_hui}未安装${gl_bai}" + check_frp="${gl_hui}未安裝${gl_bai}" fi } @@ -5933,9 +5982,9 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}未启用${gl_bai}" + trash_status="${gl_hui}未啟用${gl_bai}" else - trash_status="${gl_lv}已启用${gl_bai}" + trash_status="${gl_lv}已啟用${gl_bai}" fi clear @@ -8231,7 +8280,7 @@ linux_ldnmp() { 3) clear # Discuz論壇 - webname="Discuz论坛" + webname="Discuz論壇" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8311,7 +8360,7 @@ linux_ldnmp() { 5) clear # 蘋果CMS - webname="苹果CMS" + webname="蘋果CMS" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8358,7 +8407,7 @@ linux_ldnmp() { 6) clear # 獨腳數卡 - webname="独脚数卡" + webname="獨腳數卡" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8410,7 +8459,7 @@ linux_ldnmp() { 7) clear # flarum論壇 - webname="flarum论坛" + webname="flarum論壇" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8549,7 +8598,7 @@ linux_ldnmp() { 20) clear - webname="PHP动态站点" + webname="PHP動態站點" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8686,7 +8735,7 @@ linux_ldnmp() { 22) clear - webname="站点重定向" + webname="站點重定向" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8785,7 +8834,7 @@ linux_ldnmp() { 27) clear - webname="AI绘画提示词生成器" + webname="AI繪畫提示詞生成器" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8825,7 +8874,7 @@ linux_ldnmp() { 30) clear - webname="静态站点" + webname="靜態站點" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -9273,6 +9322,8 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}111. ${color111}多格式文件轉換工具" + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" @@ -12822,8 +12873,30 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ + 111|convertx) + local app_id="111" + local docker_name="convertx" + local docker_img="ghcr.io/c4illin/convertx:latest" + local docker_port=8111 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:3000 \ + -v /home/docker/convertx:/app/data \ + ${docker_img} + } + + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_use="" + local docker_passwd="" + local app_size="2" + docker_app + + ;; @@ -13123,6 +13196,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode else echo "使用官方鏡像源..." @@ -13134,6 +13208,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ + --install-epel true \ --pure-mode fi } From 83863e4887880d39d88e25846eb7116bcfc7af99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 13:21:57 +0800 Subject: [PATCH 0453/1285] Update translate.yml --- .github/workflows/translate.yml | 126 +++++++++++--------------------- 1 file changed, 44 insertions(+), 82 deletions(-) diff --git a/.github/workflows/translate.yml b/.github/workflows/translate.yml index 6e2d6b7de..215b3fef9 100644 --- a/.github/workflows/translate.yml +++ b/.github/workflows/translate.yml @@ -2,9 +2,8 @@ name: Weekly Translation Workflow on: schedule: - # 每周日 UTC 02:00 执行 (北京时间周日 10:00) - cron: '0 2 * * 0' - workflow_dispatch: # 允许手动触发 + workflow_dispatch: permissions: contents: write @@ -47,106 +46,72 @@ jobs: return bool(re.search(r'[\u4e00-\u9fff]', text)) def translate_text(text, target_lang): - if not text.strip() or not is_chinese(text): + if not text or not text.strip() or not is_chinese(text): return text try: + # 过滤掉仅由符号组成的文本 + if not re.search(r'[a-zA-Z\u4e00-\u9fff]', text): + return text return GoogleTranslator(source='zh-CN', target=target_lang).translate(text) except Exception as e: print(f"\nTranslation error: {e}") return text - def translate_line_preserving_variables(line, target_lang): + def process_content_with_vars(content, target_lang): """ - 处理 echo/read/send_stats 等命令中的中文,同时保护其中的 ${var} + 保护 ${var} 和 $var 不被翻译 """ - def repl(match): - full_string = match.group(0) - quote = full_string[0] - content = full_string[1:-1] - # 分割出变量,只翻译非变量部分 - parts = re.split(r'(\$\{?\w+\}?)', content) - translated_parts = [ - translate_text(p, target_lang) if is_chinese(p) else p - for p in parts - ] - return quote + ''.join(translated_parts) + quote - - return re.sub(r'(?:\'[^\']*\'|"[^"]*")', repl, line) + # 匹配 ${var} 或 $var (简单变量名) + parts = re.split(r'(\$\{?\w+\}?)', content) + translated_parts = [ + translate_text(p, target_lang) if is_chinese(p) else p + for p in parts + ] + return ''.join(translated_parts) - def translate_assignment_value(line, target_lang): - """ - 专门处理变量赋值语句:VAR="中文内容" -> VAR="Translated Content" - """ - # 匹配 key="value" 或 key='value' 格式,且 value 包含中文 - match = re.match(r'^(\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)([\'"])(.*)([\'"])(.*)$', line) - if match: - prefix, quote_open, value, quote_close, suffix = match.groups() - if is_chinese(value): - # 同样要保护赋值内容里的 ${var} - parts = re.split(r'(\$\{?\w+\}?)', value) - translated_value = "".join([ - translate_text(p, target_lang) if is_chinese(p) else p - for p in parts - ]) - return f"{prefix}{quote_open}{translated_value}{quote_close}{suffix}\n" - return line + def translate_line(line, target_lang): + stripped = line.strip() + if not is_chinese(stripped): + return line + + # 1. 处理注释 (# 开头) + if stripped.startswith('#'): + comment_part = line.split('#', 1) + return comment_part[0] + '#' + translate_text(comment_part[1], target_lang) + '\n' + + # 2. 处理包含引号的内容 (适用于变量赋值 local var="..." 或 echo "...") + # 这个正则会寻找所有被单引号或双引号包裹的部分 + def quote_replacer(match): + quote = match.group(1) # ' 或 " + content = match.group(2) + return f"{quote}{process_content_with_vars(content, target_lang)}{quote}" + + # 匹配 '...' 或 "..." + new_line = re.sub(r'([\'"])(.*?)\1', quote_replacer, line) + return new_line def translate_file(input_file, output_file, target_lang): print(f"Translating to {target_lang}...") - - if not os.path.exists(input_file): - print(f"Error: Input file {input_file} not found") - return False + if not os.path.exists(input_file): return False with open(input_file, 'r', encoding='utf-8') as f: lines = f.readlines() - total_lines = len(lines) - with open(output_file, 'w', encoding='utf-8') as f_out: for i, line in enumerate(lines): - progress = (i + 1) / total_lines * 100 - print(f"\rProcessing: {progress:.1f}% ({i+1}/{total_lines})", end='') - - leading_space = re.match(r'^(\s*)', line).group(1) - stripped = line.strip() - - # 1. 处理注释 - if stripped.startswith('#') and is_chinese(stripped): - comment_text = stripped[1:].strip() - if comment_text: - translated = translate_text(comment_text, target_lang) - f_out.write(f"{leading_space}# {translated}\n") - else: - f_out.write(line) - - # 2. 处理常用交互命令 - elif any(cmd in stripped for cmd in ['echo', 'read', 'send_stats']) and is_chinese(stripped): - f_out.write(translate_line_preserving_variables(line, target_lang)) - - # 3. 处理变量赋值中的中文 (新增强化) - elif '=' in stripped and is_chinese(stripped): - f_out.write(translate_assignment_value(line, target_lang)) - - # 4. 其他行原样保留 - else: - f_out.write(line) + # 直接处理每一行,translate_line 内部会判断是否有中文 + f_out.write(translate_line(line, target_lang)) - print(f"\nTranslation to {target_lang} completed.") + print(f"Done: {target_lang}") return True if __name__ == "__main__": input_file = 'kejilion.sh' languages = {'en': 'en', 'tw': 'zh-TW', 'kr': 'ko', 'jp': 'ja'} - success_count = 0 for dir_name, lang_code in languages.items(): - output_file = f'{dir_name}/kejilion.sh' - if translate_file(input_file, output_file, lang_code): + if translate_file(input_file, f'{dir_name}/kejilion.sh', lang_code): success_count += 1 - print(f"✓ {dir_name} done") - print("-" * 30) - if success_count == 0: sys.exit(1) EOF @@ -172,17 +137,14 @@ jobs: git push env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + - name: Create summary if: always() run: | echo "## Translation Summary 📊" >> $GITHUB_STEP_SUMMARY - echo "| Language | Directory | Status |" >> $GITHUB_STEP_SUMMARY - echo "|----------|-----------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Language | Status |" >> $GITHUB_STEP_SUMMARY + echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY for dir in en tw kr jp; do - if [ -f "$dir/kejilion.sh" ]; then - echo "| $dir | /$dir/ | ✅ Success |" >> $GITHUB_STEP_SUMMARY - else - echo "| $dir | /$dir/ | ❌ Failed |" >> $GITHUB_STEP_SUMMARY - fi + [ -f "$dir/kejilion.sh" ] && status="✅ Success" || status="❌ Failed" + echo "| $dir | $status |" >> $GITHUB_STEP_SUMMARY done From 7c20ff0d2e7836f65a25e67e7b76f45e65140264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 13:26:27 +0800 Subject: [PATCH 0454/1285] Update translate.yml --- .github/workflows/translate.yml | 100 ++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/.github/workflows/translate.yml b/.github/workflows/translate.yml index 215b3fef9..01c152fc9 100644 --- a/.github/workflows/translate.yml +++ b/.github/workflows/translate.yml @@ -46,48 +46,59 @@ jobs: return bool(re.search(r'[\u4e00-\u9fff]', text)) def translate_text(text, target_lang): - if not text or not text.strip() or not is_chinese(text): + if not text.strip() or not is_chinese(text): return text try: - # 过滤掉仅由符号组成的文本 - if not re.search(r'[a-zA-Z\u4e00-\u9fff]', text): - return text - return GoogleTranslator(source='zh-CN', target=target_lang).translate(text) + # 过滤掉一些不该翻译的特殊符号 + clean_text = text.strip() + result = GoogleTranslator(source='zh-CN', target=target_lang).translate(clean_text) + return result except Exception as e: - print(f"\nTranslation error: {e}") + print(f"\n[Error] {e}") return text - + def process_content_with_vars(content, target_lang): """ - 保护 ${var} 和 $var 不被翻译 + 核心逻辑:保护 ${var} 和 $var,翻译其中的中文部分 """ - # 匹配 ${var} 或 $var (简单变量名) - parts = re.split(r'(\$\{?\w+\}?)', content) - translated_parts = [ - translate_text(p, target_lang) if is_chinese(p) else p - for p in parts - ] - return ''.join(translated_parts) + # 匹配 ${var} 或 $var (字母数字下划线) + parts = re.split(r'(\$\{\w+\}|\$\w+)', content) + translated_parts = [] + for p in parts: + if p.startswith('$'): # 变量部分,保持原样 + translated_parts.append(p) + elif is_chinese(p): # 中文部分,翻译 + translated_parts.append(translate_text(p, target_lang)) + else: # 其他英文/符号,保持原样 + translated_parts.append(p) + return "".join(translated_parts) - def translate_line(line, target_lang): + def universal_translator(line, target_lang): + """ + 通用翻译引擎:识别行内所有引号内容并翻译 + """ + # 1. 保护注释行 + leading_space = re.match(r'^(\s*)', line).group(1) stripped = line.strip() - if not is_chinese(stripped): - return line - - # 1. 处理注释 (# 开头) if stripped.startswith('#'): - comment_part = line.split('#', 1) - return comment_part[0] + '#' + translate_text(comment_part[1], target_lang) + '\n' + comment_content = stripped[1:].strip() + if is_chinese(comment_content): + return f"{leading_space}# {translate_text(comment_content, target_lang)}\n" + return line - # 2. 处理包含引号的内容 (适用于变量赋值 local var="..." 或 echo "...") - # 这个正则会寻找所有被单引号或双引号包裹的部分 - def quote_replacer(match): - quote = match.group(1) # ' 或 " - content = match.group(2) - return f"{quote}{process_content_with_vars(content, target_lang)}{quote}" + # 2. 识别所有引号内的内容 (双引号或单引号) + # 使用正则匹配引号对,同时处理转义引号 \" + def replacer(match): + quote_type = match.group(1) # ' 或 " + content = match.group(2) # 引号内的文本内容 + if is_chinese(content): + # 翻译内容,但保护里面的变量 + translated = process_content_with_vars(content, target_lang) + return f"{quote_type}{translated}{quote_type}" + return match.group(0) - # 匹配 '...' 或 "..." - new_line = re.sub(r'([\'"])(.*?)\1', quote_replacer, line) + # 匹配 "content" 或 'content' + new_line = re.sub(r'([\'"])(.*?)(?> $GITHUB_OUTPUT - else - echo "has_changes=true" >> $GITHUB_OUTPUT - fi + git diff --staged --quiet || echo "has_changes=true" >> $GITHUB_OUTPUT - name: Commit and push changes if: steps.check_changes.outputs.has_changes == 'true' From 96f21b8a2118318f24fee60966eba7ee3860739b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 24 Dec 2025 07:43:31 +0000 Subject: [PATCH 0455/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-24=2007:43:31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 608 +++++++++++++++++++++++----------------------- jp/kejilion.sh | 648 ++++++++++++++++++++++++------------------------- kr/kejilion.sh | 618 +++++++++++++++++++++++----------------------- translate.py | 128 +++++----- tw/kejilion.sh | 506 +++++++++++++++++++------------------- 5 files changed, 1244 insertions(+), 1264 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index a6159b887..916de7124 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -560,7 +560,7 @@ while true; do echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "Container name" "network name" "IP address" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -2248,10 +2248,10 @@ web_security() { 22) send_stats "High load enables 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield. If the load is low, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and obtain${gl_huang}Global API Key${gl_bai}" echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2334,7 +2334,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3440,7 +3440,7 @@ ldnmp_Proxy() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3488,7 +3488,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3505,7 +3505,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3672,7 +3672,7 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# dynamically add/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear @@ -4099,7 +4099,7 @@ list_forwarding_services() { local config_file="$1" # Print header - printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" + printf "%-20s %-25s %-30s %-10s\n" "Service name" "Intranet address" "External network address" "protocol" awk ' BEGIN { @@ -4295,7 +4295,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4392,7 +4392,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -4432,9 +4432,9 @@ yt_menu_pro() { while true; do if [ -x "/usr/local/bin/yt-dlp" ]; then - local YTDLP_STATUS="${gl_lv}已安装${gl_bai}" + local YTDLP_STATUS="${gl_lv}Installed${gl_bai}" else - local YTDLP_STATUS="${gl_hui}未安装${gl_bai}" + local YTDLP_STATUS="${gl_hui}Not installed${gl_bai}" fi clear @@ -5513,7 +5513,7 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ The scan is completed and the virus report is stored in${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" echo -e "${gl_lv}If there is a virus please${gl_huang}scan.log${gl_lv}Search the file for the FOUND keyword to confirm the location of the virus${gl_bai}" } @@ -5703,7 +5703,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5768,7 +5768,7 @@ Kernel_optimize() { 1) cd ~ clear - local tiaoyou_moshi="高性能优化模式" + local tiaoyou_moshi="High performance optimization mode" optimize_high_performance send_stats "High performance mode optimization" ;; @@ -5782,19 +5782,19 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ clear - local tiaoyou_moshi="直播优化模式" + local tiaoyou_moshi="Live broadcast optimization mode" optimize_high_performance send_stats "Live streaming optimization" ;; 5) cd ~ clear - local tiaoyou_moshi="游戏服优化模式" + local tiaoyou_moshi="Game server optimization mode" optimize_high_performance send_stats "Game server optimization" ;; @@ -6232,7 +6232,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6580,7 +6580,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6717,7 +6717,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -6875,7 +6875,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d hour ", run_hours); printf("%d minute\n", run_minutes)}') local timezone=$(current_timezone) @@ -6932,7 +6932,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" @@ -7342,7 +7342,7 @@ docker_ssh_migration() { mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # volume mapping + # Volume mapping local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done @@ -7507,7 +7507,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7648,7 +7648,7 @@ linux_docker() { echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "Container name" "network name" "IP address" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -7734,7 +7734,7 @@ linux_docker() { case $sub_choice in 1) - send_stats "Create new volume" + send_stats "Create a new volume" read -e -p "Set new volume name:" dockerjuan docker volume create $dockerjuan @@ -7874,7 +7874,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8260,8 +8260,8 @@ linux_ldnmp() { echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore whole site data" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}Optimize LDNMP environment" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}Uninstall the LDNMP environment" + echo -e "${gl_huang}35. ${gl_bai}Protect LDNMP environments${gl_huang}36. ${gl_bai}Optimize LDNMP environment" + echo -e "${gl_huang}37. ${gl_bai}Update LDNMP environment${gl_huang}38. ${gl_bai}Uninstall the LDNMP environment" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}Return to main menu" echo -e "${gl_huang}------------------------${gl_bai}" @@ -9258,7 +9258,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}------------------------" @@ -9335,7 +9335,7 @@ while true; do 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" + local panelname="pagoda panel" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -9428,10 +9428,10 @@ while true; do } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_describe="An Nginx reverse proxy tool panel that does not support adding domain name access." + local docker_url="Official website introduction: https://nginxproxymanager.com/" + local docker_use="echo \"Initial username: admin@example.com\"" + local docker_passwd="echo \"Initial password: changeme\"" local app_size="1" docker_app @@ -9463,8 +9463,8 @@ while true; do } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_describe="A file listing program that supports multiple storages, web browsing and WebDAV, powered by gin and Solidjs" + local docker_url="Official website introduction: https://github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9504,8 +9504,8 @@ while true; do } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop is an Ubuntu-based container. If the IP cannot be accessed, please add a domain name for access." + local docker_url="Official website introduction: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -9584,8 +9584,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent offline BT magnetic download service" + local docker_url="Official website introduction: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -9708,7 +9708,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -9724,9 +9724,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" + local app_name="Rocket.Chat chat system" + local app_text="Rocket.Chat is an open source team communication platform that supports real-time chat, audio and video calls, file sharing and other functions." + local app_url="Official introduction: https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -9762,7 +9762,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -9792,10 +9792,10 @@ while true; do } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_describe="ZenTao is a universal project management software" + local docker_url="Official website introduction: https://www.zentao.net/" + local docker_use="echo \"Initial username: admin\"" + local docker_passwd="echo \"Initial password: 123456\"" local app_size="2" docker_app @@ -9821,8 +9821,8 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_describe="Qinglong Panel is a scheduled task management platform" + local docker_url="Official website introduction:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -9832,9 +9832,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="cloudreve network disk" + local app_text="cloudreve is a network disk system that supports multiple cloud storages" + local app_url="Video introduction: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -9860,7 +9860,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -9886,8 +9886,8 @@ while true; do } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="Simple drawing bed is a simple drawing bed program" + local docker_url="Official website introduction:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -9914,8 +9914,8 @@ while true; do } - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" + local docker_describe="emby is a master-slave architecture media server software that can be used to organize video and audio on the server and stream audio and video to client devices" + local docker_url="Official website introduction: https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -9935,8 +9935,8 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -9966,8 +9966,8 @@ while true; do } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome is a network-wide ad blocking and anti-tracking software that will be more than just a DNS server in the future." + local docker_url="Official website introduction: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -9995,8 +9995,8 @@ while true; do } - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_describe="onlyoffice is an open source online office tool, so powerful!" + local docker_url="Official website introduction: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10092,8 +10092,8 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" + local docker_describe="portainer is a lightweight docker container management panel" + local docker_url="Official website introduction: https://www.portainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10115,8 +10115,8 @@ while true; do } - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode is a powerful online code writing tool" + local docker_url="Official website introduction:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -10143,8 +10143,8 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="Uptime Kuma Easy-to-use self-hosted monitoring tool" + local docker_url="Official website introduction:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -10163,8 +10163,8 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos is a lightweight, self-hosted memo center" + local docker_url="Official website introduction:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -10204,8 +10204,8 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop is based on the Chinese version of Alpine container. If the IP cannot be accessed, please add a domain name for access." + local docker_url="Official website introduction: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10225,9 +10225,9 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_describe="With over 400,000 deployments, Nextcloud is the most popular local content collaboration platform you can download" + local docker_url="Official website introduction: https://nextcloud.com/" + local docker_use="echo \"Account: nextcloud Password:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -10245,8 +10245,8 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today is an HTTP request scheduled task automatic execution framework" + local docker_url="Official website introduction: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10265,8 +10265,8 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_describe="dockge is a visual docker-compose container management panel" + local docker_url="Official website introduction:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -10285,8 +10285,8 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed is a lightweight speed testing tool implemented in Javascript that can be used out of the box" + local docker_url="Official website introduction:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -10310,8 +10310,8 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng is a private and private search engine site" + local docker_url="Official website introduction: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -10342,9 +10342,9 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_describe="Photoprism is a very powerful private photo album system" + local docker_url="Official website introduction: https://www.photoprism.app/" + local docker_use="echo \"Account: admin Password:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -10370,8 +10370,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="This is a powerful locally hosted web-based PDF manipulation tool using docker that allows you to perform various operations on PDF files such as split merge, convert, reorganize, add images, rotate, compress, etc." + local docker_url="Official website introduction:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -10391,8 +10391,8 @@ while true; do } - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" + local docker_describe="This is a powerful charting software. You can draw mind maps, topology diagrams, and flow charts." + local docker_url="Official website introduction: https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10416,9 +10416,9 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_describe="Sun-Panel server, NAS navigation panel, Homepage, browser homepage" + local docker_url="Official website introduction: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"Account: admin@sun.cc Password: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -10440,8 +10440,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share is a self-buildable file sharing platform and an alternative to WeTransfer" + local docker_url="Official website introduction:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -10467,9 +10467,9 @@ while true; do } - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_describe="Minimalist Moments, high imitation WeChat Moments, record your wonderful life" local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_use="echo \"Account: admin Password: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10491,8 +10491,8 @@ while true; do lobehub/lobe-chat } - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_describe="LobeChat aggregates the mainstream AI large models on the market, ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="Official website introduction:${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -10512,8 +10512,8 @@ while true; do } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="It is a multifunctional IP toolbox that allows you to view your own IP information and connectivity, and displays it using a web panel." + local docker_url="Official website introduction:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -10546,8 +10546,8 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go is a live broadcast recording tool that supports multiple live broadcast platforms" + local docker_url="Official website introduction:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -10563,8 +10563,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="Simple online ssh connection tool and sftp tool" + local docker_url="Official website introduction:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -10575,8 +10575,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="mouse panel" + local panelurl="Official address:${gh_proxy}github.com/TheTNB/panel" panel_app_install() { mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh @@ -10616,8 +10616,8 @@ while true; do } - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm is a powerful online SSH/VNC/RDP connection tool." + local docker_url="Official website introduction:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -10637,10 +10637,10 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_describe="Rustdesk's open source remote desktop (server) is similar to its own Sunflower private server." + local docker_url="Official website introduction: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local docker_passwd="echo \"Record your IP and key, which will be used in the remote desktop client. Go to option 44 to install the relay!\"" local app_size="1" docker_app ;; @@ -10657,9 +10657,9 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_describe="Rustdesk's open source remote desktop (relay) is similar to its own Sunflower private server." + local docker_url="Official website introduction: https://rustdesk.com/zh-cn/" + local docker_use="echo \"Go to the official website to download the remote desktop client: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -10683,8 +10683,8 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry is a service for storing and distributing Docker images." + local docker_url="Official website introduction: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -10703,8 +10703,8 @@ while true; do } - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="GHProxy implemented using Go is used to accelerate the pulling of Github repositories in some areas." + local docker_url="Official website introduction: https://github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -10714,9 +10714,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" + local app_name="Prometheus monitoring" + local app_text="Prometheus+Grafana enterprise-level monitoring system" + local app_url="Official website introduction: https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -10745,7 +10745,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10768,8 +10768,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_describe="This is a Prometheus host data collection component, please deploy it on the monitored host." + local docker_url="Official website introduction: https://github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -10798,8 +10798,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_describe="This is a Prometheus container data collection component, please deploy it on the monitored host." + local docker_url="Official website introduction: https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -10821,8 +10821,8 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_describe="This is a small tool for website change detection, replenishment monitoring and notification" + local docker_url="Official website introduction: https://github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -10854,8 +10854,8 @@ while true; do } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_describe="Docker visual panel system provides complete docker management functions." + local docker_url="Official website introduction: https://github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -10874,8 +10874,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI is a large language model web page framework that is connected to the new llama3 large language model." + local docker_url="Official website introduction: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -10886,8 +10886,8 @@ while true; do local app_id="54" local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" + local panelname="AMH panel" + local panelurl="Official address: https://amh.sh/index.htm?amh" panel_app_install() { cd ~ @@ -10926,8 +10926,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI is a large language model web page framework that is connected to the new DeepSeek R1 large language model." + local docker_url="Official website introduction: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -10937,9 +10937,9 @@ while true; do 58|dify) local app_id="58" - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" + local app_name="DifyKnowledge Base" + local app_text="It is an open source large language model (LLM) application development platform. Self-hosted training data for AI generation" + local app_url="Official website: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -10972,7 +10972,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10982,8 +10982,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_text="New generation of large model gateway and AI asset management system" + local app_url="Official website: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11023,7 +11023,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11034,9 +11034,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_name="JumpServer open source bastion machine" + local app_text="It is an open source privileged access management (PAM) tool. This program occupies port 80 and does not support adding domain names for access." + local app_url="Official introduction: https://github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11064,7 +11064,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11086,8 +11086,8 @@ while true; do } - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_describe="Free open source machine translation API, fully self-hosted, and its translation engine is powered by the open source Argos Translate library." + local docker_url="Official website introduction: https://github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11098,9 +11098,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_name="RAGFlow knowledge base" + local app_text="Open source RAG (Retrieval Augmented Generation) engine based on deep document understanding" + local app_url="Official website: https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11127,7 +11127,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11147,8 +11147,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI is a large language model web page framework, the official simplified version supports API access to all major models." + local docker_url="Official website introduction: https://github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11165,8 +11165,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_describe="Very useful tool for developers and IT workers" + local docker_url="Official website introduction: https://github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11201,8 +11201,8 @@ while true; do } - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_describe="It is a powerful automated workflow platform" + local docker_url="Official website introduction: https://github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11230,8 +11230,8 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_describe="Automatically update your public IP (IPv4/IPv6) to major DNS service providers in real time to achieve dynamic domain name resolution." + local docker_url="Official website introduction: https://github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11248,10 +11248,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local docker_describe="Open source free SSL certificate automation management platform" + local docker_url="Official website introduction: https://allinssl.com" + local docker_use="echo \"Security entrance: /allinssl\"" + local docker_passwd="echo \"Username: allinssl Password: allinssldocker\"" local app_size="1" docker_app ;; @@ -11280,8 +11280,8 @@ while true; do } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" + local docker_describe="Open source free anytime, anywhere SFTP FTP WebDAV file transfer tool" + local docker_url="Official website introduction: https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11312,9 +11312,9 @@ while true; do } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" + local docker_url="Official website introduction: https://astrbot.app/" + local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -11341,8 +11341,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11368,8 +11368,8 @@ while true; do } - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" + local docker_describe="A password manager that puts you in control of your data" + local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11400,8 +11400,8 @@ while true; do } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_describe="Free online video search and viewing platform" + local docker_url="Official website introduction: https://github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11415,9 +11415,9 @@ while true; do local app_id="74" - local app_name="moontv私有影视" - local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_name="moontv private film and television" + local app_text="Free online video search and viewing platform" + local app_url="Video introduction: https://github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11455,7 +11455,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11482,8 +11482,8 @@ while true; do } - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_describe="Your music wizard, designed to help you better manage your music." + local docker_url="Official website introduction: https://github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11509,8 +11509,8 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_describe="It is a Chinese DOS game collection website" + local docker_url="Official website introduction: https://github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11544,9 +11544,9 @@ while true; do } - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_describe="Xunlei, your offline high-speed BT magnetic download tool" + local docker_url="Official website introduction: https://github.com/cnk3x/xunlei" + local docker_use="echo \"Log in to Xunlei with your mobile phone, and then enter the invitation code. Invitation code: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -11559,8 +11559,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_text="PandaWiki is an open source intelligent document management system driven by AI large models. It is strongly recommended not to customize port deployment." + local app_url="Official introduction: https://github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -11602,8 +11602,8 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_describe="Beszel is lightweight and easy-to-use server monitoring" + local docker_url="Official website introduction: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11615,9 +11615,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" + local app_name="linkwarden bookmark management" + local app_text="An open source, self-hosted bookmark management platform that supports tagging, search, and team collaboration." + local app_url="Official website: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -11676,7 +11676,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11687,9 +11687,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" + local app_name="JitsiMeet video conference" + local app_text="An open source secure video conferencing solution that supports multi-person online conferencing, screen sharing and encrypted communication." + local app_url="Official website: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -11726,7 +11726,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11755,8 +11755,8 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_describe="High-performance AI interface transparent proxy service" + local docker_url="Official website introduction: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11788,9 +11788,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_describe="Lightweight self-hosted server monitoring tool" + local docker_url="Official website introduction: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"Default account: admin Default password: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -11819,8 +11819,8 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_describe="Open source personal subscription tracker for financial management" + local docker_url="Official website introduction: https://github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -11831,9 +11831,9 @@ while true; do 85|immich) local app_id="85" - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_name="immich picture video manager" + local app_text="High-performance self-hosted photo and video management solution." + local app_url="Official website introduction: https://github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -11862,7 +11862,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11897,8 +11897,8 @@ while true; do } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" + local docker_describe="Is an open source media server software" + local docker_url="Official website introduction: https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11925,9 +11925,9 @@ while true; do } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_url="Official website introduction: https://github.com/synctv-org/synctv" + local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" local app_size="1" docker_app @@ -11955,10 +11955,10 @@ while true; do } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_describe="Open source, free self-built live broadcast platform" + local docker_url="Official website introduction: https://owncast.online" + local docker_use="echo \"The access address is followed by /admin to access the administrator page\"" + local docker_passwd="echo \"Initial account: admin Initial password: abc123 Please change the login password in time after logging in\"" local app_size="1" docker_app @@ -11984,10 +11984,10 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" - local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" + local docker_describe="Share texts and files with anonymous passwords, and pick up files like express delivery" + local docker_url="Official website introduction: https://github.com/vastsa/FileCodeBox" + local docker_use="echo \"The access address is followed by /#/admin to access the administrator page\"" + local docker_passwd="echo \"Administrator password: FileCodeBox2023\"" local app_size="1" docker_app @@ -12040,8 +12040,8 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" - local docker_url="官网介绍: https://matrix.org/" + local docker_describe="Matrix is ​​a decentralized chat protocol" + local docker_url="Official website introduction: https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12055,9 +12055,9 @@ while true; do local app_id="91" - local app_name="gitea私有代码仓库" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_name="gitea private code repository" + local app_text="A free new generation code hosting platform that provides an experience close to GitHub." + local app_url="Video introduction: https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12089,7 +12089,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12119,8 +12119,8 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_describe="Is a web-based file manager" + local docker_url="Official website introduction: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -12146,8 +12146,8 @@ while true; do } - local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_describe="Minimalist static file server, supports upload and download" + local docker_url="Official website introduction: https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12177,8 +12177,8 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_describe="Distributed high-speed download tool, supporting multiple protocols" + local docker_url="Official website introduction: https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12192,9 +12192,9 @@ while true; do local app_id="95" - local app_name="paperless文档管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_name="paperless document management platform" + local app_text="An open source electronic document management system, its main purpose is to digitize and manage your paper documents." + local app_url="Video introduction: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -12227,7 +12227,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12240,9 +12240,9 @@ while true; do local app_id="96" - local app_name="2FAuth自托管二步验证器" - local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_name="2FAuth self-hosted two-step authenticator" + local app_text="Self-hosted two-factor authentication (2FA) account management and verification code generation tool." + local app_url="Official website: https://github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12281,7 +12281,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12387,8 +12387,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="Modern, high-performance virtual private network tools" + local docker_url="Official website introduction: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12457,8 +12457,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="Modern, high-performance virtual private network tools" + local docker_url="Official website introduction: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12471,9 +12471,9 @@ while true; do local app_id="99" - local app_name="dsm群晖虚拟机" - local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_name="dsm Synology virtual machine" + local app_text="Virtual DSM in Docker container" + local app_url="Official website: https://github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12514,7 +12514,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12543,8 +12543,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_describe="An open source peer-to-peer file synchronization tool, similar to Dropbox and Resilio Sync, but completely decentralized." + local docker_url="Official website introduction: https://github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12555,9 +12555,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI视频生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI video generation tool" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_url="Official website: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12584,7 +12584,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12610,8 +12610,8 @@ while true; do } - local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_describe="It is a personal cloud social media chat service that supports independent deployment." + local docker_url="Official website introduction: https://github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12622,9 +12622,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami网站统计工具" - local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_name="Umami website statistics tool" + local app_text="Open source, lightweight, privacy-friendly website analysis tool, similar to Google Analytics." + local app_url="Official website: https://github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12653,7 +12653,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12689,8 +12689,8 @@ while true; do } - local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_describe="Siyuan Notes is a privacy-first knowledge management system" + local docker_url="Official website introduction: https://github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -12716,8 +12716,8 @@ while true; do } - local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_describe="It is a powerful open source whiteboard tool that integrates mind maps, flow charts, etc." + local docker_url="Official website introduction: https://github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -12751,8 +12751,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_describe="PanSou is a high-performance network disk resource search API service." + local docker_url="Official website introduction: https://github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -12765,9 +12765,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot聊天机器人" - local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_name="LangBot chatbot" + local app_text="It is an open source large language model native instant messaging robot development platform." + local app_url="Official website: https://github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -12794,7 +12794,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12823,8 +12823,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_describe="It is an online network disk program suitable for individuals or small teams." + local docker_url="Official website introduction: https://github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -12835,9 +12835,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep书签管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_name="karakeep bookmark management" + local app_text="is a self-hosted bookmarking app with artificial intelligence capabilities designed for data hoarders." + local app_url="Official website: https://github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -12864,7 +12864,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12889,8 +12889,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_describe="It is a powerful multi-format file conversion tool (supports documents, images, audio and video, etc.) It is strongly recommended to add domain name access" + local docker_url="Project address: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -12947,7 +12947,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13005,12 +13005,12 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" @@ -13099,9 +13099,9 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}开启${gl_bai}" + local tmux_sshd_status="${gl_lv}turn on${gl_bai}" else - local tmux_sshd_status="${gl_hui}关闭${gl_bai}" + local tmux_sshd_status="${gl_hui}closure${gl_bai}" fi send_stats "SSH resident mode" echo -e "SSH resident mode${tmux_sshd_status}" @@ -13122,7 +13122,7 @@ linux_work() { tmux_run ;; 2) - sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc + sed -i '/# Automatically enter tmux session/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -13282,7 +13282,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" + echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority to ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" echo -e "${gl_kjlan}13. ${gl_bai}User management${gl_kjlan}14. ${gl_bai}User/password generator" @@ -13346,7 +13346,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13613,7 +13613,7 @@ EOF send_stats "User management" echo "User list" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" + printf "%-24s %-34s %-20s %-10s\n" "username" "User permissions" "User group" "sudo permissions" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") @@ -14283,7 +14283,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14332,7 +14332,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14366,11 +14366,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}Collecting data${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}Collection is closed${gl_bai}" else - local status_message="无法确定的状态" + local status_message="Uncertain status" fi echo "Privacy and security" @@ -15084,7 +15084,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 12cc6266f..06129920e 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストールする$package...${gl_bai}" + echo -e "${gl_huang}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -560,7 +560,7 @@ while true; do echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "コンテナ名" "ネットワーク名" "IPアドレス" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -797,7 +797,7 @@ docker_ipv6_off() { # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在停止中です${gl_bai}" + echo -e "${gl_huang}現在IPv6アクセスは停止中です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -858,7 +858,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done @@ -921,12 +921,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1548,7 +1548,7 @@ certs_status() { echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" - echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" + echo -e "6. 国内の登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかどうかを確認してください" echo "------------------------" echo "1. 再度適用します。 2. 既存の証明書をインポートします。 3. 証明書なしで HTTP アクセスを使用します。 0. 終了します。" echo "------------------------" @@ -2001,7 +2001,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2132,7 +2132,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2248,10 +2248,10 @@ web_security() { 22) send_stats "高負荷により5秒シールドが可能" - echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" + echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検知すると自動的にシールドが開きます。負荷が低い場合は、シールドが 5 秒間自動的に閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2334,7 +2334,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2575,7 +2575,7 @@ check_docker_image_update() { # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIからイメージのリリース時刻を取得する + # Docker Hub APIからイメージのリリース時間を取得する local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) @@ -2623,7 +2623,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2640,7 +2640,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2681,7 +2681,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2700,7 +2700,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2895,7 +2895,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3008,7 +3008,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3440,7 +3440,7 @@ ldnmp_Proxy() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3488,7 +3488,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3505,7 +3505,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + printf "%-25s %-18s %-25s %-20s\n" "サービス名" "通信タイプ" "ローカルアドレス" "バックエンドアドレス" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3584,7 +3584,7 @@ stream_panel() { send_stats "ストリームの 4 層プロキシを更新します" ;; 3) - read -e -p "Are you sure you want to delete the nginx container?これはウェブサイトの機能に影響を与える可能性があります。 (y/N):" confirm + read -e -p "nginx コンテナを削除してもよろしいですか?これはウェブサイトの機能に影響を与える可能性があります。 (y/N):" confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx sed -i "/\b${app_id}\b/d" /home/docker/appno.txt @@ -3639,7 +3639,7 @@ ldnmp_Proxy_backend_stream() { echo "名前を空にすることはできません"; return 1 fi - # リスニングポートの取得 + # リスニングポートを取得する read -rp "ローカルのリスニング ポート (3306 など) を入力してください。" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "ポートは数値である必要があります"; return 1 @@ -3672,7 +3672,7 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear @@ -3768,7 +3768,7 @@ ldnmp_web_status() { echo "" echo "操作する" echo "------------------------" - echo "1. ドメイン名証明書の適用/更新 2. サイトのドメイン名の複製" + echo "1. ドメイン名証明書の適用/更新 2. サイトドメイン名の複製" echo "3. サイトのキャッシュをクリアします。 4. 関連するサイトを作成します。" echo "5. アクセスログの表示 6. エラーログの表示" echo "7. グローバル構成の編集 8. サイト構成の編集" @@ -3866,7 +3866,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4098,8 +4098,8 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーを印刷します - printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" + # ヘッダーの印刷 + printf "%-20s %-25s %-30s %-10s\n" "サービス名" "イントラネットアドレス" "外部ネットワークアドレス" "プロトコル" awk ' BEGIN { @@ -4213,7 +4213,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4318,7 +4318,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4432,9 +4432,9 @@ yt_menu_pro() { while true; do if [ -x "/usr/local/bin/yt-dlp" ]; then - local YTDLP_STATUS="${gl_lv}已安装${gl_bai}" + local YTDLP_STATUS="${gl_lv}インストール済み${gl_bai}" else - local YTDLP_STATUS="${gl_hui}未安装${gl_bai}" + local YTDLP_STATUS="${gl_hui}インストールされていません${gl_bai}" fi clear @@ -5513,7 +5513,7 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ スキャンが完了し、ウイルス レポートが保存されます。${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" echo -e "${gl_lv}ウイルスがある場合はお願いします${gl_huang}scan.log${gl_lv}ファイル内で FOUND キーワードを検索して、ウイルスの場所を確認します。${gl_bai}" } @@ -5768,7 +5768,7 @@ Kernel_optimize() { 1) cd ~ clear - local tiaoyou_moshi="高性能优化模式" + local tiaoyou_moshi="高性能最適化モード" optimize_high_performance send_stats "ハイパフォーマンスモードの最適化" ;; @@ -5782,19 +5782,19 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ clear - local tiaoyou_moshi="直播优化模式" + local tiaoyou_moshi="ライブブロードキャスト最適化モード" optimize_high_performance send_stats "ライブストリーミングの最適化" ;; 5) cd ~ clear - local tiaoyou_moshi="游戏服优化模式" + local tiaoyou_moshi="ゲームサーバー最適化モード" optimize_high_performance send_stats "ゲームサーバーの最適化" ;; @@ -5872,7 +5872,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6177,7 +6177,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -6529,7 +6529,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -6717,7 +6717,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモート ホストにアクセスできますか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6816,7 +6816,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -6875,7 +6875,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -6932,7 +6932,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -7298,7 +7298,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7393,7 +7393,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" @@ -7500,14 +7500,14 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7581,7 +7581,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7648,7 +7648,7 @@ linux_docker() { echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "コンテナ名" "ネットワーク名" "IPアドレス" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -8067,7 +8067,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8451,7 +8451,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -8938,10 +8938,10 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境のバックアップ" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -8951,7 +8951,7 @@ linux_ldnmp() { case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then echo "エラー: リモート サーバーの IP を入力してください。" @@ -9258,7 +9258,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}------------------------" @@ -9280,7 +9280,7 @@ while true; do echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nextermリモート接続ツール" + echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nexterm リモート接続ツール" echo -e "${gl_kjlan}43. ${color43}RustDesk リモート デスクトップ (サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker アクセラレーション ステーション${gl_kjlan}46. ${color46}GitHub アクセラレーション ステーション${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}プロメテウスの監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" @@ -9296,7 +9296,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -9335,7 +9335,7 @@ while true; do 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" + local panelname="パゴダパネル" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -9428,10 +9428,10 @@ while true; do } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_describe="ドメイン名アクセスの追加をサポートしていない Nginx リバース プロキシ ツール パネル。" + local docker_url="公式サイト紹介:https://nginxproxymanager.com/" + local docker_use="echo \"初期ユーザー名: admin@example.com\"" + local docker_passwd="echo \"初期パスワード:changeme\"" local app_size="1" docker_app @@ -9463,8 +9463,8 @@ while true; do } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_describe="gin と Solidjs を利用した、複数のストレージ、Web ブラウジング、WebDAV をサポートするファイル一覧プログラム" + local docker_url="公式サイト紹介:https://github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9504,8 +9504,8 @@ while true; do } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop は Ubuntu ベースのコンテナです。 IP にアクセスできない場合は、アクセス用のドメイン名を追加してください。" + local docker_url="公式Webサイトの紹介:https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -9584,8 +9584,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent オフライン BT 磁気ダウンロード サービス" + local docker_url="公式サイト紹介:https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -9724,9 +9724,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" + local app_name="Rocket.Chat チャット システム" + local app_text="Rocket.Chat は、リアルタイム チャット、音声およびビデオ通話、ファイル共有、その他の機能をサポートするオープンソースのチーム コミュニケーション プラットフォームです。" + local app_url="公式紹介:https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -9792,10 +9792,10 @@ while true; do } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_describe="ZenTao はユニバーサルなプロジェクト管理ソフトウェアです" + local docker_url="公式サイト紹介:https://www.zentao.net/" + local docker_use="echo \"初期ユーザー名: admin\"" + local docker_passwd="echo 「初期パスワード: 123456」" local app_size="2" docker_app @@ -9821,8 +9821,8 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_describe="Qinglong Panel はスケジュールされたタスク管理プラットフォームです" + local docker_url="公式サイト紹介:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -9832,9 +9832,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="クラウドリーブネットワークディスク" + local app_text="Cloudreve は、複数のクラウド ストレージをサポートするネットワーク ディスク システムです。" + local app_url="ビデオ紹介: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -9886,8 +9886,8 @@ while true; do } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="シンプルドローイングベッドはシンプルなドローイングベッドプログラムです" + local docker_url="公式サイト紹介:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -9914,8 +9914,8 @@ while true; do } - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" + local docker_describe="emby は、サーバー上でビデオとオーディオを整理し、クライアント デバイスにオーディオとビデオをストリーミングするために使用できるマスター/スレーブ アーキテクチャのメディア サーバー ソフトウェアです。" + local docker_url="公式サイト紹介:https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -9935,8 +9935,8 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -9966,8 +9966,8 @@ while true; do } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome は、将来的には単なる DNS サーバー以上のネットワーク全体の広告ブロックおよび追跡防止ソフトウェアです。" + local docker_url="公式サイト紹介:https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -9995,8 +9995,8 @@ while true; do } - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" + local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10092,8 +10092,8 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" + local docker_describe="portainer は軽量の Docker コンテナ管理パネルです" + local docker_url="公式サイト紹介:https://www.porttainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10115,8 +10115,8 @@ while true; do } - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode は強力なオンライン コード作成ツールです" + local docker_url="公式サイト紹介:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -10143,8 +10143,8 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="Uptime Kuma 使いやすいセルフホスト型監視ツール" + local docker_url="公式サイト紹介:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -10163,8 +10163,8 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos は軽量の自己ホスト型メモ センターです" + local docker_url="公式サイト紹介:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -10204,8 +10204,8 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="Webtop は、Alpine コンテナの中国語版に基づいています。 IP にアクセスできない場合は、アクセス用のドメイン名を追加してください。" + local docker_url="公式Webサイトの紹介:https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10225,9 +10225,9 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_describe="400,000 を超える導入実績を持つ Nextcloud は、ダウンロードできる最も人気のあるローカル コンテンツ コラボレーション プラットフォームです。" + local docker_url="公式サイト紹介:https://nextcloud.com/" + local docker_use="echo \"アカウント: nextcloud パスワード:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -10245,8 +10245,8 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today は、HTTP リクエストのスケジュールされたタスク自動実行フレームワークです。" + local docker_url="公式サイト紹介:https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10265,8 +10265,8 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_describe="dockge は、視覚的な docker-compose コンテナー管理パネルです。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -10285,8 +10285,8 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed は、JavaScript で実装され、すぐに使用できる軽量の速度テスト ツールです。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -10310,8 +10310,8 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng は非公開の検索エンジン サイトです。" + local docker_url="公式サイト紹介:https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -10342,9 +10342,9 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_describe="Photoprism は非常に強力なプライベート フォト アルバム システムです" + local docker_url="公式サイト紹介:https://www.photoprism.app/" + local docker_use="echo \"アカウント: admin パスワード:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -10370,8 +10370,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、分割マージ、変換、再編成、画像の追加、回転、圧縮など、PDF ファイルに対してさまざまな操作を実行できます。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -10391,8 +10391,8 @@ while true; do } - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" + local docker_describe="これは強力なグラフ作成ソフトウェアです。マインド マップ、トポロジ図、フローチャートを描画できます。" + local docker_url="公式サイト紹介:https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10416,9 +10416,9 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_describe="Sun-Panel サーバー、NAS ナビゲーション パネル、ホームページ、ブラウザー ホームページ" + local docker_url="公式サイト紹介:https://doc.sun-panel.top/zh_cn/" + local docker_use="echo 「アカウント: admin@sun.cc パスワード: 12345678」" local docker_passwd="" local app_size="1" docker_app @@ -10440,8 +10440,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share は自己構築可能なファイル共有プラットフォームであり、WeTransfer の代替品です" + local docker_url="公式サイト紹介:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -10467,9 +10467,9 @@ while true; do } - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -10491,8 +10491,8 @@ while true; do lobehub/lobe-chat } - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_describe="LobeChat は、市場で主流の AI 大型モデル、ChatGPT/Claude/Gemini/Groq/Ollama を集約しています。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -10512,8 +10512,8 @@ while true; do } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="独自の IP 情報と接続性を表示し、Web パネルを使用して表示できる多機能 IP ツールボックスです。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -10546,8 +10546,8 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go は、複数のライブ ブロードキャスト プラットフォームをサポートするライブ ブロードキャスト録画ツールです" + local docker_url="公式サイト紹介:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -10563,8 +10563,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="シンプルなオンライン SSH 接続ツールと SFTP ツール" + local docker_url="公式サイト紹介:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -10575,8 +10575,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="マウスパネル" + local panelurl="正式な住所:${gh_proxy}github.com/TheTNB/panel" panel_app_install() { mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh @@ -10616,8 +10616,8 @@ while true; do } - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm は、強力なオンライン SSH/VNC/RDP 接続ツールです。" + local docker_url="公式サイト紹介:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -10637,10 +10637,10 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_describe="Rustdesk のオープンソース リモート デスクトップ (サーバー) は、自社の Sunflower プライベート サーバーに似ています。" + local docker_url="公式サイト紹介:https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local docker_passwd="echo \"リモート デスクトップ クライアントで使用される IP とキーを記録します。オプション 44 に進んでリレーをインストールしてください!\"" local app_size="1" docker_app ;; @@ -10657,9 +10657,9 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_describe="Rustdesk のオープンソース リモート デスクトップ (リレー) は、独自の Sunflower プライベート サーバーに似ています。" + local docker_url="公式サイト紹介:https://rustdesk.com/zh-cn/" + local docker_use="echo \"公式 Web サイトにアクセスして、リモート デスクトップ クライアントをダウンロードします: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -10683,8 +10683,8 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry は、Docker イメージを保存および配布するためのサービスです。" + local docker_url="公式サイト紹介:https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -10703,8 +10703,8 @@ while true; do } - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="Go を使用して実装された GHProxy は、一部の領域で Github リポジトリのプルを高速化するために使用されます。" + local docker_url="公式サイト紹介:https://github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -10714,9 +10714,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" + local app_name="プロメテウスの監視" + local app_text="Prometheus+Grafana エンタープライズレベルの監視システム" + local app_url="公式サイト紹介:https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -10768,8 +10768,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_describe="これは Prometheus ホスト データ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_url="公式サイト紹介:https://github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -10798,8 +10798,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_url="公式サイト紹介:https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -10821,8 +10821,8 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_describe="これは、Web サイトの変更の検出、補充の監視、通知を行うための小さなツールです。" + local docker_url="公式サイト紹介:https://github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -10854,8 +10854,8 @@ while true; do } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_describe="Docker ビジュアル パネル システムは、完全な Docker 管理機能を提供します。" + local docker_url="公式サイト紹介:https://github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -10874,8 +10874,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI は、新しい llama3 ラージ言語モデルに接続されているラージ言語モデル Web ページ フレームワークです。" + local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -10886,8 +10886,8 @@ while true; do local app_id="54" local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" + local panelname="AMHパネル" + local panelurl="公式アドレス:https://amh.sh/index.htm?amh" panel_app_install() { cd ~ @@ -10926,8 +10926,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI は、新しい DeepSeek R1 大規模言語モデルに接続されている大規模言語モデル Web ページ フレームワークです。" + local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -10937,9 +10937,9 @@ while true; do 58|dify) local app_id="58" - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" + local app_name="Difyナレッジベース" + local app_text="これは、オープンソースの大規模言語モデル (LLM) アプリケーション開発プラットフォームです。 AI生成用の自己ホスト型トレーニングデータ" + local app_url="公式ウェブサイト:https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -10982,8 +10982,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_text="新世代の大型モデルゲートウェイとAI資産管理システム" + local app_url="公式サイト:https://github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11034,9 +11034,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_name="JumpServer オープンソース要塞マシン" + local app_text="これは、オープンソースの特権アクセス管理 (PAM) ツールです。このプログラムはポート 80 を占有しているため、アクセス用のドメイン名の追加はサポートされていません。" + local app_url="公式紹介: https://github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11086,8 +11086,8 @@ while true; do } - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_describe="無料のオープンソース機械翻訳 API は完全に自己ホストされており、その翻訳エンジンはオープンソースの Argos Translate ライブラリを利用しています。" + local docker_url="公式サイト紹介:https://github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11098,9 +11098,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_name="RAGFlow ナレッジベース" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_url="公式サイト:https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11147,8 +11147,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI は大規模な言語モデルの Web ページ フレームワークであり、公式の簡易バージョンではすべての主要モデルへの API アクセスがサポートされています。" + local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11165,8 +11165,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_describe="開発者と IT ワーカーにとって非常に便利なツール" + local docker_url="公式サイト紹介:https://github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11201,8 +11201,8 @@ while true; do } - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_describe="強力な自動ワークフロー プラットフォームです" + local docker_url="公式サイト紹介:https://github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11230,8 +11230,8 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_describe="パブリック IP (IPv4/IPv6) を主要な DNS サービス プロバイダーにリアルタイムで自動的に更新し、動的なドメイン名解決を実現します。" + local docker_url="公式サイト紹介:https://github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11248,10 +11248,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local docker_describe="オープンソースの無料 SSL 証明書自動化管理プラットフォーム" + local docker_url="公式サイト紹介:https://allinssl.com" + local docker_use="echo \"セキュリティの入り口: /allinssl\"" + local docker_passwd="echo \"ユーザー名: allinssl パスワード: allinssldocker\"" local app_size="1" docker_app ;; @@ -11280,8 +11280,8 @@ while true; do } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" + local docker_describe="オープンソースでいつでもどこでも無料の SFTP FTP WebDAV ファイル転送ツール" + local docker_url="公式サイト紹介:https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11312,9 +11312,9 @@ while true; do } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" + local docker_url="公式サイト紹介:https://astrbot.app/" + local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -11341,8 +11341,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="軽量で高性能な音楽ストリーミングサーバーです" + local docker_url="公式サイト紹介:https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11368,8 +11368,8 @@ while true; do } - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" + local docker_describe="データを管理できるパスワード マネージャー" + local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11400,8 +11400,8 @@ while true; do } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_describe="無料のオンラインビデオ検索および視聴プラットフォーム" + local docker_url="公式サイト紹介:https://github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11415,9 +11415,9 @@ while true; do local app_id="74" - local app_name="moontv私有影视" - local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_name="MoonTV プライベート映画とテレビ" + local app_text="無料のオンラインビデオ検索および視聴プラットフォーム" + local app_url="ビデオ紹介: https://github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11482,8 +11482,8 @@ while true; do } - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_describe="音楽をより適切に管理できるように設計された音楽ウィザード。" + local docker_url="公式サイト紹介:https://github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11509,8 +11509,8 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_describe="中華DOSゲームまとめサイトです" + local docker_url="公式サイト紹介:https://github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11544,9 +11544,9 @@ while true; do } - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_describe="Xunlei、オフライン高速 BT 磁気ダウンロード ツール" + local docker_url="公式サイト紹介:https://github.com/cnk3x/xunlei" + local docker_use="echo \"携帯電話で Xunlei にログインし、招待コードを入力します。招待コード: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -11559,8 +11559,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_text="PandaWiki は、AI 大型モデルによって駆動されるオープンソースのインテリジェントな文書管理システムです。ポートの展開をカスタマイズしないことを強くお勧めします。" + local app_url="公式紹介: https://github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -11602,8 +11602,8 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_describe="Beszel は軽量で使いやすいサーバー監視です" + local docker_url="公式サイト紹介:https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11615,9 +11615,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" + local app_name="リンクワーデンのブックマーク管理" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -11687,9 +11687,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" + local app_name="JitsiMeet ビデオ会議" + local app_text="複数人でのオンライン会議、画面共有、暗号化通信をサポートするオープンソースの安全なビデオ会議ソリューション。" + local app_url="公式サイト:https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -11755,8 +11755,8 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_describe="高性能AIインターフェース透過プロキシサービス" + local docker_url="公式サイト紹介:https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11788,9 +11788,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_describe="軽量のセルフホスト型サーバー監視ツール" + local docker_url="公式サイト紹介:https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"デフォルトのアカウント: admin デフォルトのパスワード: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -11819,8 +11819,8 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_describe="財務管理用のオープンソースの個人サブスクリプション トラッカー" + local docker_url="公式サイト紹介:https://github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -11831,9 +11831,9 @@ while true; do 85|immich) local app_id="85" - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" + local app_url="公式サイト紹介:https://github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -11897,8 +11897,8 @@ while true; do } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" + local docker_describe="オープンソースのメディアサーバーソフトウェアです" + local docker_url="公式サイト紹介:https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11925,9 +11925,9 @@ while true; do } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_url="公式サイト紹介:https://github.com/synctv-org/synctv" + local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" local app_size="1" docker_app @@ -11955,10 +11955,10 @@ while true; do } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_url="公式サイト紹介:https://owncast.online" + local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" + local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" local app_size="1" docker_app @@ -11984,10 +11984,10 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" - local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" + local docker_describe="匿名のパスワードでテキストやファイルを共有し、速達のようにファイルを受け取ります" + local docker_url="公式サイト紹介:https://github.com/vastsa/FileCodeBox" + local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /#/admin を続けます\"" + local docker_passwd="echo \"管理者パスワード: FileCodeBox2023\"" local app_size="1" docker_app @@ -12040,8 +12040,8 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" - local docker_url="官网介绍: https://matrix.org/" + local docker_describe="Matrix は分散型チャット プロトコルです" + local docker_url="公式サイト紹介:https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12055,9 +12055,9 @@ while true; do local app_id="91" - local app_name="gitea私有代码仓库" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_name="gitea プライベート コード リポジトリ" + local app_text="GitHub に近いエクスペリエンスを提供する、無料の新世代コード ホスティング プラットフォーム。" + local app_url="ビデオ紹介: https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12119,8 +12119,8 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_describe="Webベースのファイルマネージャーです" + local docker_url="公式サイト紹介:https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -12146,8 +12146,8 @@ while true; do } - local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_describe="シンプルな静的ファイル サーバー、アップロードとダウンロードをサポート" + local docker_url="公式サイト紹介:https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12177,8 +12177,8 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_describe="複数のプロトコルをサポートする分散型高速ダウンロード ツール" + local docker_url="公式サイト紹介:https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12192,9 +12192,9 @@ while true; do local app_id="95" - local app_name="paperless文档管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_name="ペーパーレス文書管理プラットフォーム" + local app_text="オープンソースの電子文書管理システムであり、その主な目的は紙文書をデジタル化して管理することです。" + local app_url="ビデオ紹介: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -12240,9 +12240,9 @@ while true; do local app_id="96" - local app_name="2FAuth自托管二步验证器" - local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_name="2FAuth セルフホスト型 2 段階認証システム" + local app_text="セルフホスト型の 2 要素認証 (2FA) アカウント管理および検証コード生成ツール。" + local app_url="公式サイト:https://github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12387,8 +12387,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="最新の高性能仮想プライベート ネットワーク ツール" + local docker_url="公式サイト紹介:https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12457,8 +12457,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="最新の高性能仮想プライベート ネットワーク ツール" + local docker_url="公式サイト紹介:https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12471,9 +12471,9 @@ while true; do local app_id="99" - local app_name="dsm群晖虚拟机" - local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_name="dsm Synology 仮想マシン" + local app_text="Dockerコンテナ内の仮想DSM" + local app_url="公式ウェブサイト:https://github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12543,8 +12543,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_describe="オープンソースのピアツーピア ファイル同期ツール。Dropbox や Resilio Sync に似ていますが、完全に分散化されています。" + local docker_url="公式サイト紹介:https://github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12555,9 +12555,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI视频生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI動画生成ツール" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_url="公式ウェブサイト:https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12610,8 +12610,8 @@ while true; do } - local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_describe="独自導入をサポートするパーソナルクラウドソーシャルメディアチャットサービスです。" + local docker_url="公式サイト紹介:https://github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12622,9 +12622,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami网站统计工具" - local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_name="Umami ウェブサイト統計ツール" + local app_text="Google Analytics に似た、オープンソースの軽量でプライバシーに配慮した Web サイト分析ツール。" + local app_url="公式サイト:https://github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12689,8 +12689,8 @@ while true; do } - local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_describe="Siyuan Notes はプライバシーを最優先したナレッジ管理システムです" + local docker_url="公式サイト紹介:https://github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -12716,8 +12716,8 @@ while true; do } - local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_describe="これは、マインド マップ、フローチャートなどを統合する強力なオープンソース ホワイトボード ツールです。" + local docker_url="公式サイト紹介:https://github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -12751,8 +12751,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_describe="PanSou は、高パフォーマンスのネットワーク ディスク リソース検索 API サービスです。" + local docker_url="公式サイト紹介:https://github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -12765,9 +12765,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot聊天机器人" - local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_name="LangBot チャットボット" + local app_text="これは、オープンソースの大規模言語モデルのネイティブ インスタント メッセージング ロボット開発プラットフォームです。" + local app_url="公式ウェブサイト:https://github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -12823,8 +12823,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_describe="これは、個人または小規模チームに適したオンライン ネットワーク ディスク プログラムです。" + local docker_url="公式サイト紹介:https://github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -12835,9 +12835,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep书签管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_name="karakeepのブックマーク管理" + local app_text="は、データ蓄積者向けに設計された人工知能機能を備えた自己ホスト型ブックマーク アプリです。" + local app_url="公式サイト:https://github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -12889,8 +12889,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_url="プロジェクトアドレス: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -12917,7 +12917,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ case "$choice" in [Yy]) read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then @@ -12947,7 +12947,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリケーションのバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13005,12 +13005,12 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo.10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" @@ -13099,9 +13099,9 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}开启${gl_bai}" + local tmux_sshd_status="${gl_lv}オンにする${gl_bai}" else - local tmux_sshd_status="${gl_hui}关闭${gl_bai}" + local tmux_sshd_status="${gl_hui}閉鎖${gl_bai}" fi send_stats "SSH常駐モード" echo -e "SSH常駐モード${tmux_sshd_status}" @@ -13122,7 +13122,7 @@ linux_work() { tmux_run ;; 2) - sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc + sed -i '/# 自動的に tmux セッションに入ります/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -13140,7 +13140,7 @@ linux_work() { 23) - read -e -p "バックグラウンドで実行するコマンドを入力してください。たとえば、curl -fsSL https://get.docker.com |し:" tmuxd + read -e -p "バックグラウンドで実行するコマンドを入力してください (例:curl -fsSL https://get.docker.com | )し:" tmuxd tmux_run_d send_stats "バックグラウンドワークスペースにコマンドを挿入する" ;; @@ -13282,7 +13282,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" + echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}優先順位をipv4/ipv6に切り替える" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}ポートの占有状況を確認する${gl_kjlan}12. ${gl_bai}仮想メモリのサイズを変更する" echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワード生成器" @@ -13351,7 +13351,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -13458,7 +13458,7 @@ EOF send_stats "SSHポートが変更されました" new_ssh_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH ポート変更の終了" + send_stats "SSHポート変更の終了" break else echo "ポート番号が無効です。 1 ~ 65535 の数字を入力してください。" @@ -13613,7 +13613,7 @@ EOF send_stats "ユーザー管理" echo "ユーザーリスト" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" + printf "%-24s %-34s %-20s %-10s\n" "ユーザー名" "ユーザー権限" "ユーザーグループ" "sudo 権限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") @@ -13749,7 +13749,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13764,7 +13764,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14274,7 +14274,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14366,11 +14366,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}データの収集${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}コレクションは終了しました${gl_bai}" else - local status_message="无法确定的状态" + local status_message="不確実なステータス" fi echo "プライバシーとセキュリティ" @@ -14506,7 +14506,7 @@ linux_file() { 4) # 重命名目录 read -e -p "現在のディレクトリ名を入力してください:" current_name read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリ名が変更されました" || echo "名前の変更に失敗しました" + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前の変更に失敗しました" send_stats "ディレクトリの名前を変更する" ;; 5) # 删除目录 @@ -14723,7 +14723,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -14768,7 +14768,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14830,7 +14830,7 @@ echo "------------------------" echo -e "${gl_lan}Laika Cloud 香港 CN2 GIA 韓国のデュアル ISP 米国 CN2 GIA プロモーション${gl_bai}" echo -e "${gl_bai}ウェブサイト: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" -echo -e "${gl_lan}RackNerd 年間 10.99 ドル、米国、1 コア、1G メモリ、20G ハードドライブ、月あたり 1T トラフィック${gl_bai}" +echo -e "${gl_lan}RackNerd 年間 10.99 ドル、米国、1 コア、1G メモリ、20G ハード ドライブ、月あたり 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 年間 $52.7 米国 1 コア 4G メモリ 50G ハードドライブ 月額 4T トラフィック${gl_bai}" @@ -14960,7 +14960,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" + echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -15051,7 +15051,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -15084,7 +15084,7 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -15103,7 +15103,7 @@ echo "システムバックアップ機能 kバックアップ | k bf | k バッ echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" -echo "イントラネットの普及率 (サーバー) k frps" +echo "イントラネット普及率 (サーバー) k frps" echo "イントラネット浸透率 (クライアント) k frpc" echo "ソフトウェア起動 k start sshd | sshdを起動します" echo "ソフトウェア停止 k 停止 sshd | k ストップ sshd" @@ -15123,7 +15123,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシングのインストール k ストリーム |k L4 ロード バランシング" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -15220,7 +15220,7 @@ else swap) shift - send_stats "仮想メモリを素早く設定する" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; @@ -15319,7 +15319,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d63ce1259..3801168a4 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -560,7 +560,7 @@ while true; do echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1259,7 +1259,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1544,8 +1544,8 @@ certs_status() { send_stats "도메인 이름 인증서 신청 실패" echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." - echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." + echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인하세요." + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." @@ -1862,7 +1862,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2248,7 +2248,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 실드가 열립니다. 부하가 낮으면 자동으로 5초 동안 쉴드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2334,7 +2334,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -2514,7 +2514,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2579,7 +2579,7 @@ check_docker_image_update() { local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) - # 획득한 시간을 확인하세요. + # 획득한 시간을 확인 if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) @@ -3325,7 +3325,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3338,7 +3338,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3412,7 +3412,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3440,7 +3440,7 @@ ldnmp_Proxy() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3488,7 +3488,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3505,7 +3505,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + printf "%-25s %-18s %-25s %-20s\n" "서비스 이름" "통신 유형" "현지 주소" "백엔드 주소" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3628,7 +3628,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3672,11 +3672,11 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4099,7 +4099,7 @@ list_forwarding_services() { local config_file="$1" # 헤더 인쇄 - printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" + printf "%-20s %-25s %-30s %-10s\n" "서비스 이름" "인트라넷 주소" "외부 네트워크 주소" "규약" awk ' BEGIN { @@ -4318,7 +4318,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4432,9 +4432,9 @@ yt_menu_pro() { while true; do if [ -x "/usr/local/bin/yt-dlp" ]; then - local YTDLP_STATUS="${gl_lv}已安装${gl_bai}" + local YTDLP_STATUS="${gl_lv}설치됨${gl_bai}" else - local YTDLP_STATUS="${gl_hui}未安装${gl_bai}" + local YTDLP_STATUS="${gl_hui}설치되지 않음${gl_bai}" fi clear @@ -5303,7 +5303,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5483,7 +5483,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5513,7 +5513,7 @@ clamav_scan() { clamav/clamav-debian:latest \ clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS - echo -e "${gl_lv}$@ 검사가 완료되고 바이러스 보고서가 다음 위치에 저장됩니다.${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" + echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" echo -e "${gl_lv}바이러스 있으면 제발${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" } @@ -5768,7 +5768,7 @@ Kernel_optimize() { 1) cd ~ clear - local tiaoyou_moshi="高性能优化模式" + local tiaoyou_moshi="고성능 최적화 모드" optimize_high_performance send_stats "고성능 모드 최적화" ;; @@ -5782,19 +5782,19 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ clear - local tiaoyou_moshi="直播优化模式" + local tiaoyou_moshi="라이브 방송 최적화 모드" optimize_high_performance send_stats "라이브 스트리밍 최적화" ;; 5) cd ~ clear - local tiaoyou_moshi="游戏服优化模式" + local tiaoyou_moshi="게임 서버 최적화 모드" optimize_high_performance send_stats "게임 서버 최적화" ;; @@ -6225,14 +6225,14 @@ add_connection() { echo # 换行 ;; 2) - echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6573,14 +6573,14 @@ add_task() { auth_method="password" ;; 2) - echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6717,7 +6717,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -6875,7 +6875,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d시간 ", run_hours); printf("%d분\n", run_mins)}') local timezone=$(current_timezone) @@ -7266,7 +7266,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -7405,7 +7405,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7495,7 +7495,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -7507,7 +7507,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7540,7 +7540,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -7648,7 +7648,7 @@ linux_docker() { echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -7740,7 +7740,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8055,7 +8055,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8686,7 +8686,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db case $use_db in 1) echo @@ -9258,7 +9258,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}------------------------" @@ -9335,7 +9335,7 @@ while true; do 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" + local panelname="탑 패널" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -9428,10 +9428,10 @@ while true; do } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_describe="도메인 이름 액세스 추가를 지원하지 않는 Nginx 역방향 프록시 도구 패널." + local docker_url="공식 홈페이지 소개: https://nginxproxymanager.com/" + local docker_use="echo \"초기 사용자 이름: admin@example.com\"" + local docker_passwd="echo \"초기 비밀번호:changeme\"" local app_size="1" docker_app @@ -9463,8 +9463,8 @@ while true; do } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_describe="gin 및 Solidjs로 구동되는 다중 저장소, 웹 브라우징 및 WebDAV를 지원하는 파일 목록 프로그램" + local docker_url="공식 홈페이지 소개: https://github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9504,8 +9504,8 @@ while true; do } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -9515,7 +9515,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9584,8 +9584,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent 오프라인 BT 자기 다운로드 서비스" + local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -9636,7 +9636,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -9724,9 +9724,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" + local app_name="Rocket.Chat 채팅 시스템" + local app_text="Rocket.Chat은 실시간 채팅, 음성 및 영상 통화, 파일 공유 및 기타 기능을 지원하는 오픈 소스 팀 커뮤니케이션 플랫폼입니다." + local app_url="공식소개 : https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -9792,10 +9792,10 @@ while true; do } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_describe="ZenTao는 범용 프로젝트 관리 소프트웨어입니다" + local docker_url="공식 홈페이지 소개 : https://www.zentao.net/" + local docker_use="echo \"초기 사용자 이름: admin\"" + local docker_passwd="echo \"초기 비밀번호: 123456\"" local app_size="2" docker_app @@ -9821,8 +9821,8 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_describe="Qinglong Panel은 예약된 작업 관리 플랫폼입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -9832,9 +9832,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="클라우드리브 네트워크 디스크" + local app_text="cloudreve는 여러 클라우드 스토리지를 지원하는 네트워크 디스크 시스템입니다." + local app_url="영상 소개: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -9886,8 +9886,8 @@ while true; do } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="심플드로잉베드는 심플드로잉베드 프로그램입니다" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -9914,8 +9914,8 @@ while true; do } - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" + local docker_describe="emby는 서버의 비디오 및 오디오를 구성하고 오디오 및 비디오를 클라이언트 장치로 스트리밍하는 데 사용할 수 있는 마스터-슬레이브 아키텍처 미디어 서버 소프트웨어입니다." + local docker_url="공식 홈페이지 소개 : https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -9935,8 +9935,8 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -9966,8 +9966,8 @@ while true; do } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome은 미래에 단순한 DNS 서버 이상의 역할을 할 네트워크 전체의 광고 차단 및 추적 방지 소프트웨어입니다." + local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -9995,8 +9995,8 @@ while true; do } - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_describe="onlyoffice는 오픈 소스 온라인 오피스 도구로 매우 강력합니다!" + local docker_url="공식 홈페이지 소개 : https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10092,8 +10092,8 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" + local docker_describe="portainer는 경량 도커 컨테이너 관리 패널입니다." + local docker_url="공식 홈페이지 소개 : https://www.portainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10115,8 +10115,8 @@ while true; do } - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode는 강력한 온라인 코드 작성 도구입니다" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -10143,8 +10143,8 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="가동 시간 Kuma 사용하기 쉬운 자체 호스팅 모니터링 도구" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -10163,8 +10163,8 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos는 경량의 자체 호스팅 메모 센터입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -10204,8 +10204,8 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10225,9 +10225,9 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_describe="400,000개 이상 배포된 Nextcloud는 다운로드할 수 있는 가장 인기 있는 로컬 콘텐츠 협업 플랫폼입니다." + local docker_url="공식 홈페이지 소개 : https://nextcloud.com/" + local docker_use="echo \"계정: nextcloud 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -10245,8 +10245,8 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today는 HTTP 요청 예약 작업 자동 실행 프레임워크입니다." + local docker_url="공식 홈페이지 소개: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10265,8 +10265,8 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_describe="Dockge는 시각적 Docker 작성 컨테이너 관리 패널입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -10285,8 +10285,8 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed는 즉시 사용할 수 있는 Javascript로 구현된 경량 속도 테스트 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -10310,8 +10310,8 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng는 비공개 및 비공개 검색 엔진 사이트입니다." + local docker_url="공식 홈페이지 소개 : https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -10342,9 +10342,9 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." + local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -10370,8 +10370,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -10391,8 +10391,8 @@ while true; do } - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" + local docker_describe="이것은 강력한 차트 작성 소프트웨어입니다. 마인드맵, 토폴로지 다이어그램, 흐름도를 그릴 수 있습니다." + local docker_url="공식 홈페이지 소개 : https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10416,9 +10416,9 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_describe="Sun-Panel 서버, NAS 탐색 패널, 홈페이지, 브라우저 홈페이지" + local docker_url="공식 홈페이지 소개: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"계정: admin@sun.cc 비밀번호: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -10440,8 +10440,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share는 자체 구축 가능한 파일 공유 플랫폼이자 WeTransfer의 대안입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -10467,9 +10467,9 @@ while true; do } - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_describe="미니멀리스트 순간, 높은 모방 WeChat 순간, 멋진 삶을 기록하세요" local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_use="echo \"계정: admin 비밀번호: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10491,8 +10491,8 @@ while true; do lobehub/lobe-chat } - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_describe="LobeChat은 시장의 주류 AI 대형 모델인 ChatGPT/Claude/Gemini/Groq/Ollama를 통합합니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -10512,8 +10512,8 @@ while true; do } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="자신의 IP 정보와 연결성을 확인하고 웹 패널을 통해 표시할 수 있는 다기능 IP 도구 상자입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -10546,8 +10546,8 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹음 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -10563,8 +10563,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="간단한 온라인 SSH 연결 도구 및 SFTP 도구" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -10575,8 +10575,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="마우스 패널" + local panelurl="공식 주소:${gh_proxy}github.com/TheTNB/panel" panel_app_install() { mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh @@ -10616,8 +10616,8 @@ while true; do } - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm은 강력한 온라인 SSH/VNC/RDP 연결 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -10637,10 +10637,10 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(서버)은 자체 Sunflower 개인 서버와 유사합니다." + local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local docker_passwd="echo \"원격 데스크톱 클라이언트에서 사용될 IP와 키를 기록하세요. 릴레이를 설치하려면 옵션 44로 이동하세요!\"" local app_size="1" docker_app ;; @@ -10657,9 +10657,9 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(릴레이)은 자체 Sunflower 개인 서버와 유사합니다." + local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" + local docker_use="echo \"원격 데스크톱 클라이언트를 다운로드하려면 공식 웹사이트로 이동하세요: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -10683,8 +10683,8 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry는 Docker 이미지를 저장하고 배포하는 서비스입니다." + local docker_url="공식 홈페이지 소개: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -10703,8 +10703,8 @@ while true; do } - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="Go를 사용하여 구현된 GHProxy는 일부 영역에서 Github 저장소 가져오기를 가속화하는 데 사용됩니다." + local docker_url="공식 홈페이지 소개: https://github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -10714,9 +10714,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" + local app_name="프로메테우스 모니터링" + local app_text="Prometheus+Grafana 전사적 모니터링 시스템" + local app_url="공식 홈페이지 소개 : https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -10768,8 +10768,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_describe="이는 Prometheus 호스트 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." + local docker_url="공식 홈페이지 소개: https://github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -10798,8 +10798,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_describe="이는 Prometheus 컨테이너 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." + local docker_url="공식 홈페이지 소개: https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -10821,8 +10821,8 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_describe="이는 웹사이트 변경 감지, 보충 모니터링 및 알림을 위한 작은 도구입니다." + local docker_url="공식 홈페이지 소개: https://github.com/dgtlmoon/changeDetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -10854,8 +10854,8 @@ while true; do } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_describe="Docker 시각적 패널 시스템은 완전한 Docker 관리 기능을 제공합니다." + local docker_url="공식 홈페이지 소개: https://github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -10874,8 +10874,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -10886,8 +10886,8 @@ while true; do local app_id="54" local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" + local panelname="AMH 패널" + local panelurl="공식 주소 : https://amh.sh/index.htm?amh" panel_app_install() { cd ~ @@ -10926,8 +10926,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 새로운 DeepSeek R1 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -10937,9 +10937,9 @@ while true; do 58|dify) local app_id="58" - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" + local app_name="DifyKnowledge Base" + local app_text="오픈 소스 LLM(대형 언어 모델) 애플리케이션 개발 플랫폼입니다. AI 생성을 위한 자체 호스팅 학습 데이터" + local app_url="공식 홈페이지: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -10982,8 +10982,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_text="차세대 대형 모델 게이트웨이 및 AI 자산 관리 시스템" + local app_url="공식 홈페이지: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11034,9 +11034,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_name="JumpServer 오픈 소스 요새 머신" + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_url="공식 소개: https://github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11086,8 +11086,8 @@ while true; do } - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_describe="무료 오픈 소스 기계 번역 API, 완전 자체 호스팅 및 번역 엔진은 오픈 소스 Argos Translate 라이브러리에 의해 구동됩니다." + local docker_url="공식 홈페이지 소개: https://github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11098,9 +11098,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_name="RAGFlow 지식 기반" + local app_text="깊은 문서 이해를 기반으로 한 오픈소스 RAG(Retrieval Augmented Generation) 엔진" + local app_url="공식 홈페이지: https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11147,8 +11147,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 단순화 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." + local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11165,8 +11165,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_describe="개발자와 IT 작업자에게 매우 유용한 도구" + local docker_url="공식 홈페이지 소개: https://github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11201,8 +11201,8 @@ while true; do } - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_describe="강력한 자동화된 워크플로우 플랫폼입니다." + local docker_url="공식 홈페이지 소개: https://github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11230,8 +11230,8 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_describe="동적 도메인 이름 확인을 위해 공용 IP(IPv4/IPv6)를 주요 DNS 서비스 제공업체에 실시간으로 자동 업데이트합니다." + local docker_url="공식 홈페이지 소개: https://github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11248,10 +11248,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local docker_describe="오픈 소스 무료 SSL 인증서 자동화 관리 플랫폼" + local docker_url="공식 홈페이지 소개: https://allinssl.com" + local docker_use="echo \"보안 입구: /allinssl\"" + local docker_passwd="echo \"사용자 이름: allinssl 비밀번호: allinssldocker\"" local app_size="1" docker_app ;; @@ -11280,8 +11280,8 @@ while true; do } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" + local docker_describe="언제 어디서나 무료 오픈 소스 SFTP FTP WebDAV 파일 전송 도구" + local docker_url="공식 홈페이지 소개 : https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11312,9 +11312,9 @@ while true; do } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_url="공식 홈페이지 소개: https://astrbot.app/" + local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -11341,8 +11341,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="경량, 고성능 음악 스트리밍 서버입니다." + local docker_url="공식 홈페이지 소개 : https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11368,8 +11368,8 @@ while true; do } - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11400,8 +11400,8 @@ while true; do } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_describe="무료 온라인 비디오 검색 및 시청 플랫폼" + local docker_url="공식 홈페이지 소개: https://github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11415,9 +11415,9 @@ while true; do local app_id="74" - local app_name="moontv私有影视" - local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_name="Moontv 개인 영화 및 TV" + local app_text="무료 온라인 비디오 검색 및 시청 플랫폼" + local app_url="영상소개 : https://github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11482,8 +11482,8 @@ while true; do } - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_describe="음악을 더 잘 관리할 수 있도록 설계된 음악 마법사입니다." + local docker_url="공식 홈페이지 소개: https://github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11509,8 +11509,8 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_describe="중국의 DOS 게임 컬렉션 웹사이트입니다." + local docker_url="공식 홈페이지 소개: https://github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11544,9 +11544,9 @@ while true; do } - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_describe="오프라인 고속 BT 자기 다운로드 도구인 Xunlei" + local docker_url="공식 홈페이지 소개: https://github.com/cnk3x/xunlei" + local docker_use="echo \"휴대폰으로 Xunlei에 로그인한 후 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -11559,8 +11559,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_text="PandaWiki는 AI 대형 모델을 기반으로 하는 오픈 소스 지능형 문서 관리 시스템입니다. 포트 배포를 사용자 정의하지 않는 것이 좋습니다." + local app_url="공식 소개: https://github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -11602,8 +11602,8 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_describe="Beszel은 가볍고 사용하기 쉬운 서버 모니터링입니다." + local docker_url="공식 홈페이지 소개: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11615,9 +11615,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" + local app_name="링크워든 북마크 관리" + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -11687,9 +11687,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" + local app_name="JitsiMeet 화상 회의" + local app_text="다자간 온라인 회의, 화면 공유, 암호화된 통신을 지원하는 오픈 소스 보안 화상 회의 솔루션입니다." + local app_url="공식 홈페이지: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -11755,8 +11755,8 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_describe="고성능 AI 인터페이스 투명 프록시 서비스" + local docker_url="공식 홈페이지 소개: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11788,9 +11788,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_describe="경량 자체 호스팅 서버 모니터링 도구" + local docker_url="공식 홈페이지 소개: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"기본 계정: admin 기본 비밀번호: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -11819,8 +11819,8 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_describe="재무 관리를 위한 오픈 소스 개인 구독 추적기" + local docker_url="공식 홈페이지 소개: https://github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -11831,9 +11831,9 @@ while true; do 85|immich) local app_id="85" - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_name="이미치 픽처 비디오 매니저" + local app_text="고성능 자체 호스팅 사진 및 비디오 관리 솔루션입니다." + local app_url="공식 홈페이지 소개: https://github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -11897,8 +11897,8 @@ while true; do } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" + local docker_describe="오픈 소스 미디어 서버 소프트웨어입니다" + local docker_url="공식 홈페이지 소개 : https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11925,9 +11925,9 @@ while true; do } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_url="공식 홈페이지 소개: https://github.com/synctv-org/synctv" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -11955,10 +11955,10 @@ while true; do } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" + local docker_url="공식 홈페이지 소개 : https://owncast.online" + local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -11984,10 +11984,10 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" - local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_url="공식 홈페이지 소개: https://github.com/vastsa/FileCodeBox" + local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" + local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" local app_size="1" docker_app @@ -12040,8 +12040,8 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" - local docker_url="官网介绍: https://matrix.org/" + local docker_describe="Matrix는 분산형 채팅 프로토콜입니다." + local docker_url="공식 홈페이지 소개 : https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12055,9 +12055,9 @@ while true; do local app_id="91" - local app_name="gitea私有代码仓库" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_name="gitea 비공개 코드 저장소" + local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." + local app_url="영상 소개: https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12119,8 +12119,8 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_describe="웹 기반 파일 관리자입니다" + local docker_url="공식 홈페이지 소개 : https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -12146,8 +12146,8 @@ while true; do } - local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_describe="미니멀리스트 정적 파일 서버, 업로드 및 다운로드 지원" + local docker_url="공식 홈페이지 소개: https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12177,8 +12177,8 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" + local docker_url="공식 홈페이지 소개: https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12192,9 +12192,9 @@ while true; do local app_id="95" - local app_name="paperless文档管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_name="종이 없는 문서 관리 플랫폼" + local app_text="오픈 소스 전자 문서 관리 시스템으로, 주요 목적은 종이 문서를 디지털화하고 관리하는 것입니다." + local app_url="영상 소개: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -12240,9 +12240,9 @@ while true; do local app_id="96" - local app_name="2FAuth自托管二步验证器" - local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_name="2FAuth 자체 호스팅 2단계 인증자" + local app_text="자체 호스팅 2단계 인증(2FA) 계정 관리 및 확인 코드 생성 도구입니다." + local app_url="공식 홈페이지: https://github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12387,8 +12387,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="최신 고성능 가상 사설망 도구" + local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12457,8 +12457,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="최신 고성능 가상 사설망 도구" + local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12471,9 +12471,9 @@ while true; do local app_id="99" - local app_name="dsm群晖虚拟机" - local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_name="dsm Synology 가상 머신" + local app_text="Docker 컨테이너의 가상 DSM" + local app_url="공식 웹사이트: https://github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12543,8 +12543,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_describe="Dropbox 및 Resilio Sync와 유사하지만 완전히 분산된 오픈 소스 P2P 파일 동기화 도구입니다." + local docker_url="공식 홈페이지 소개: https://github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12555,9 +12555,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI视频生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI 영상 생성 도구" + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12610,8 +12610,8 @@ while true; do } - local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_describe="독립적인 배포를 지원하는 개인용 클라우드 소셜 미디어 채팅 서비스입니다." + local docker_url="공식 홈페이지 소개: https://github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12622,9 +12622,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami网站统计工具" - local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_name="Umami 웹사이트 통계 도구" + local app_text="Google Analytics와 유사한 오픈 소스, 가볍고 개인정보 보호 친화적인 웹사이트 분석 도구입니다." + local app_url="공식 웹사이트: https://github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12689,8 +12689,8 @@ while true; do } - local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_describe="Siyuan Notes는 개인 정보 보호를 최우선으로 하는 지식 관리 시스템입니다." + local docker_url="공식 홈페이지 소개: https://github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -12716,8 +12716,8 @@ while true; do } - local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_describe="마인드맵, 플로우차트 등을 통합한 강력한 오픈소스 화이트보드 도구입니다." + local docker_url="공식 홈페이지 소개: https://github.com/plait-board/ drawix" local docker_use="" local docker_passwd="" local app_size="1" @@ -12751,8 +12751,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_describe="PanSou는 고성능 네트워크 디스크 리소스 검색 API 서비스입니다." + local docker_url="공식 홈페이지 소개: https://github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -12765,9 +12765,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot聊天机器人" - local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_name="LangBot 챗봇" + local app_text="오픈 소스 대형 언어 모델 기반 인스턴트 메시징 로봇 개발 플랫폼입니다." + local app_url="공식 홈페이지: https://github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -12823,8 +12823,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_describe="개인이나 소규모 팀에 적합한 온라인 네트워크 디스크 프로그램입니다." + local docker_url="공식 홈페이지 소개: https://github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -12835,9 +12835,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep书签管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_name="karakeep 북마크 관리" + local app_text="데이터 수집가를 위해 설계된 인공 지능 기능을 갖춘 자체 호스팅 북마크 앱입니다." + local app_url="공식 홈페이지: https://github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -12889,8 +12889,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_describe="강력한 다중 형식 파일 변환 도구입니다(문서, 이미지, 오디오 및 비디오 등 지원). 도메인 이름 액세스를 추가하는 것이 좋습니다." + local docker_url="프로젝트 주소: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -12947,7 +12947,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13005,12 +13005,12 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10호" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" @@ -13099,9 +13099,9 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}开启${gl_bai}" + local tmux_sshd_status="${gl_lv}켜다${gl_bai}" else - local tmux_sshd_status="${gl_hui}关闭${gl_bai}" + local tmux_sshd_status="${gl_hui}폐쇄${gl_bai}" fi send_stats "SSH 상주 모드" echo -e "SSH 상주 모드${tmux_sshd_status}" @@ -13122,7 +13122,7 @@ linux_work() { tmux_run ;; 2) - sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc + sed -i '/# 자동으로 tmux 세션을 입력합니다/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -13282,7 +13282,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위를 ipv4/ipv6으로 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13292,7 +13292,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13346,7 +13346,7 @@ linux_Settings() { echo "파이썬 버전 관리" echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" + echo "이 기능은 Python에서 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13579,7 +13579,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -13613,7 +13613,7 @@ EOF send_stats "사용자 관리" echo "사용자 목록" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" + printf "%-24s %-34s %-20s %-10s\n" "사용자 이름" "사용자 권한" "사용자 그룹" "sudo 권한" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") @@ -13749,7 +13749,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간을 가져옵니다 + # 현재 시스템 시간 가져오기 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -13837,7 +13837,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14032,7 +14032,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}전류 제한 종료 기능은 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -14048,12 +14048,12 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일 재설정)." cz_day + read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일에 재설정됨)." cz_day cz_day=${cz_day:-1} cd ~ @@ -14366,11 +14366,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}데이터 수집${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}컬렉션이 닫혔습니다.${gl_bai}" else - local status_message="无法确定的状态" + local status_message="불확실한 상태" fi echo "개인 정보 보호 및 보안" @@ -14842,7 +14842,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 Tokyo Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -15084,7 +15084,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -15123,12 +15123,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/translate.py b/translate.py index 496df5347..96c5ae508 100644 --- a/translate.py +++ b/translate.py @@ -12,101 +12,81 @@ def translate_text(text, target_lang): if not text.strip() or not is_chinese(text): return text try: - return GoogleTranslator(source='zh-CN', target=target_lang).translate(text) + # 过滤掉一些不该翻译的特殊符号 + clean_text = text.strip() + result = GoogleTranslator(source='zh-CN', target=target_lang).translate(clean_text) + return result except Exception as e: - print(f"\nTranslation error: {e}") + print(f"\n[Error] {e}") return text -def translate_line_preserving_variables(line, target_lang): +def process_content_with_vars(content, target_lang): """ - 处理 echo/read/send_stats 等命令中的中文,同时保护其中的 ${var} + 核心逻辑:保护 ${var} 和 $var,翻译其中的中文部分 """ - def repl(match): - full_string = match.group(0) - quote = full_string[0] - content = full_string[1:-1] - # 分割出变量,只翻译非变量部分 - parts = re.split(r'(\$\{?\w+\}?)', content) - translated_parts = [ - translate_text(p, target_lang) if is_chinese(p) else p - for p in parts - ] - return quote + ''.join(translated_parts) + quote - - return re.sub(r'(?:\'[^\']*\'|"[^"]*")', repl, line) + # 匹配 ${var} 或 $var (字母数字下划线) + parts = re.split(r'(\$\{\w+\}|\$\w+)', content) + translated_parts = [] + for p in parts: + if p.startswith('$'): # 变量部分,保持原样 + translated_parts.append(p) + elif is_chinese(p): # 中文部分,翻译 + translated_parts.append(translate_text(p, target_lang)) + else: # 其他英文/符号,保持原样 + translated_parts.append(p) + return "".join(translated_parts) -def translate_assignment_value(line, target_lang): +def universal_translator(line, target_lang): """ - 专门处理变量赋值语句:VAR="中文内容" -> VAR="Translated Content" + 通用翻译引擎:识别行内所有引号内容并翻译 """ - # 匹配 key="value" 或 key='value' 格式,且 value 包含中文 - match = re.match(r'^(\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)([\'"])(.*)([\'"])(.*)$', line) - if match: - prefix, quote_open, value, quote_close, suffix = match.groups() - if is_chinese(value): - # 同样要保护赋值内容里的 ${var} - parts = re.split(r'(\$\{?\w+\}?)', value) - translated_value = "".join([ - translate_text(p, target_lang) if is_chinese(p) else p - for p in parts - ]) - return f"{prefix}{quote_open}{translated_value}{quote_close}{suffix}\n" - return line + # 1. 保护注释行 + leading_space = re.match(r'^(\s*)', line).group(1) + stripped = line.strip() + if stripped.startswith('#'): + comment_content = stripped[1:].strip() + if is_chinese(comment_content): + return f"{leading_space}# {translate_text(comment_content, target_lang)}\n" + return line + + # 2. 识别所有引号内的内容 (双引号或单引号) + # 使用正则匹配引号对,同时处理转义引号 \" + def replacer(match): + quote_type = match.group(1) # ' 或 " + content = match.group(2) # 引号内的文本内容 + if is_chinese(content): + # 翻译内容,但保护里面的变量 + translated = process_content_with_vars(content, target_lang) + return f"{quote_type}{translated}{quote_type}" + return match.group(0) + + # 匹配 "content" 或 'content' + new_line = re.sub(r'([\'"])(.*?)(? 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d時 ", run_hours); printf("%d分\n", run_minutes)}') local timezone=$(current_timezone) @@ -7648,7 +7648,7 @@ linux_docker() { echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "容器名稱" "網絡名稱" "IP地址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -9335,7 +9335,7 @@ while true; do 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" + local panelname="寶塔面板" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -9428,10 +9428,10 @@ while true; do } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_describe="一個Nginx反向代理工具面板,不支持添加域名訪問。" + local docker_url="官網介紹: https://nginxproxymanager.com/" + local docker_use="echo \"初始用戶名: admin@example.com\"" + local docker_passwd="echo \"初始密碼: changeme\"" local app_size="1" docker_app @@ -9463,8 +9463,8 @@ while true; do } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_describe="一個支持多種存儲,支持網頁瀏覽和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驅動" + local docker_url="官網介紹: https://github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9504,8 +9504,8 @@ while true; do } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop基於Ubuntu的容器。若IP無法訪問,請添加域名訪問。" + local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -9584,8 +9584,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent離線BT磁力下載服務" + local docker_url="官網介紹: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -9724,9 +9724,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" + local app_name="Rocket.Chat聊天系統" + local app_text="Rocket.Chat 是一個開源的團隊通訊平台,支持實時聊天、音視頻通話、文件共享等多種功能," + local app_url="官方介紹: https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -9792,10 +9792,10 @@ while true; do } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_describe="禪道是通用的項目管理軟件" + local docker_url="官網介紹: https://www.zentao.net/" + local docker_use="echo \"初始用戶名: admin\"" + local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -9821,8 +9821,8 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_describe="青龍面板是一個定時任務管理平台" + local docker_url="官網介紹:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -9832,9 +9832,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="cloudreve網盤" + local app_text="cloudreve是一個支持多家云存儲的網盤系統" + local app_url="視頻介紹: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -9886,8 +9886,8 @@ while true; do } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="簡單圖床是一個簡單的圖床程序" + local docker_url="官網介紹:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -9914,8 +9914,8 @@ while true; do } - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" + local docker_describe="emby是一個主從式架構的媒體服務器軟件,可以用來整理服務器上的視頻和音頻,並將音頻和視頻流式傳輸到客戶端設備" + local docker_url="官網介紹: https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -9935,8 +9935,8 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest測速面板是一個VPS網速測試工具,多項測試功能,還可以實時監控VPS進出站流量" + local docker_url="官網介紹:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -9966,8 +9966,8 @@ while true; do } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome是一款全網廣告攔截與反跟踪軟件,未來將不止是一個DNS服務器。" + local docker_url="官網介紹: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -9995,8 +9995,8 @@ while true; do } - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_describe="onlyoffice是一款開源的在線office工具,太強大了!" + local docker_url="官網介紹: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10092,8 +10092,8 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" + local docker_describe="portainer是一個輕量級的docker容器管理面板" + local docker_url="官網介紹: https://www.portainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10115,8 +10115,8 @@ while true; do } - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode是一款強大的在線代碼編寫工具" + local docker_url="官網介紹:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -10143,8 +10143,8 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="Uptime Kuma 易於使用的自託管監控工具" + local docker_url="官網介紹:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -10163,8 +10163,8 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos是一款輕量級、自託管的備忘錄中心" + local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -10204,8 +10204,8 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請添加域名訪問。" + local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -10225,9 +10225,9 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" + local docker_url="官網介紹: https://nextcloud.com/" + local docker_use="echo \"賬號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -10245,8 +10245,8 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today是一個HTTP請求定時任務自動執行框架" + local docker_url="官網介紹: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10265,8 +10265,8 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_describe="dockge是一個可視化的docker-compose容器管理面板" + local docker_url="官網介紹:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -10285,8 +10285,8 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed是用Javascript實現的輕量級速度測試工具,即開即用" + local docker_url="官網介紹:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -10310,8 +10310,8 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng是一個私有且隱私的搜索引擎站點" + local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -10342,9 +10342,9 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_describe="photoprism非常強大的私有相冊系統" + local docker_url="官網介紹: https://www.photoprism.app/" + local docker_use="echo \"賬號: admin 密碼:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -10370,8 +10370,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="這是一個強大的本地託管基於 Web 的 PDF 操作工具,使用 docker,允許您對 PDF 文件執行各種操作,例如拆分合併、轉換、重新組織、添加圖像、旋轉、壓縮等。" + local docker_url="官網介紹:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -10391,8 +10391,8 @@ while true; do } - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" + local docker_describe="這是一個強大圖表繪製軟件。思維導圖,拓撲圖,流程圖,都能畫" + local docker_url="官網介紹: https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -10416,9 +10416,9 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_describe="Sun-Panel服務器、NAS導航面板、Homepage、瀏覽器首頁" + local docker_url="官網介紹: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"賬號: admin@sun.cc 密碼: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -10440,8 +10440,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share 是一個可自建的文件分享平台,是 WeTransfer 的一個替代品" + local docker_url="官網介紹:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -10467,9 +10467,9 @@ while true; do } - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_describe="極簡朋友圈,高仿微信朋友圈,記錄你的美好生活" local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_use="echo \"賬號: admin 密碼: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10492,7 +10492,7 @@ while true; do } local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_url="官網介紹:${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -10512,8 +10512,8 @@ while true; do } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="是一個多功能IP工具箱,可以查看自己IP信息及連通性,用網頁面板呈現" + local docker_url="官網介紹:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -10546,8 +10546,8 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go是一個支持多種直播平台的直播錄製工具" + local docker_url="官網介紹:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -10563,8 +10563,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="簡易在線ssh連接工具和sftp工具" + local docker_url="官網介紹:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -10575,8 +10575,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="耗子麵板" + local panelurl="官方地址:${gh_proxy}github.com/TheTNB/panel" panel_app_install() { mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh @@ -10616,8 +10616,8 @@ while true; do } - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm是一款強大的在線SSH/VNC/RDP連接工具。" + local docker_url="官網介紹:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -10637,10 +10637,10 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_describe="rustdesk開源的遠程桌面(服務端),類似自己的向日葵私服。" + local docker_url="官網介紹: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local docker_passwd="echo \"把你的IP和key記錄下,會在遠程桌面客戶端中用到。去44選項裝中繼端吧!\"" local app_size="1" docker_app ;; @@ -10657,9 +10657,9 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_describe="rustdesk開源的遠程桌面(中繼端),類似自己的向日葵私服。" + local docker_url="官網介紹: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官網下載遠程桌面的客戶端: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -10683,8 +10683,8 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry 是一個用於存儲和分發 Docker 鏡像的服務。" + local docker_url="官網介紹: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -10703,8 +10703,8 @@ while true; do } - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="使用Go實現的GHProxy,用於加速部分地區Github倉庫的拉取。" + local docker_url="官網介紹: https://github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -10714,9 +10714,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" + local app_name="普羅米修斯監控" + local app_text="Prometheus+Grafana企業級監控系統" + local app_url="官網介紹: https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -10768,8 +10768,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_describe="這是一個普羅米修斯的主機數據採集組件,請部署在被監控主機上。" + local docker_url="官網介紹: https://github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -10798,8 +10798,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_describe="這是一個普羅米修斯的容器數據採集組件,請部署在被監控主機上。" + local docker_url="官網介紹: https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -10821,8 +10821,8 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_describe="這是一款網站變化檢測、補貨監控和通知的小工具" + local docker_url="官網介紹: https://github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -10854,8 +10854,8 @@ while true; do } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_describe="Docker可視化面板系統,提供完善的docker管理功能。" + local docker_url="官網介紹: https://github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -10874,8 +10874,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的llama3大語言模型" + local docker_url="官網介紹: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -10926,8 +10926,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的DeepSeek R1大語言模型" + local docker_url="官網介紹: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -10937,9 +10937,9 @@ while true; do 58|dify) local app_id="58" - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" + local app_name="Dify知識庫" + local app_text="是一款開源的大語言模型(LLM) 應用開發平台。自託管訓練數據用於AI生成" + local app_url="官方網站: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -10982,8 +10982,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_text="新一代大模型網關與AI資產管理系統" + local app_url="官方網站: https://github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11034,9 +11034,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_name="JumpServer開源堡壘機" + local app_text="是一個開源的特權訪問管理 (PAM) 工具,該程序佔用80端口不支持添加域名訪問了" + local app_url="官方介紹: https://github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11086,8 +11086,8 @@ while true; do } - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_describe="免費開源機器翻譯 API,完全自託管,它的翻譯引擎由開源Argos Translate庫提供支持。" + local docker_url="官網介紹: https://github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11098,9 +11098,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_name="RAGFlow知識庫" + local app_text="基於深度文檔理解的開源 RAG(檢索增強生成)引擎" + local app_url="官方網站: https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11147,8 +11147,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大語言模型網頁框架,官方精簡版本,支持各大模型API接入" + local docker_url="官網介紹: https://github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11165,8 +11165,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_describe="對開發人員和 IT 工作者來說非常有用的工具" + local docker_url="官網介紹: https://github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11201,8 +11201,8 @@ while true; do } - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_describe="是一款功能強大的自動化工作流平台" + local docker_url="官網介紹: https://github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11230,8 +11230,8 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_describe="自動將你的公網 IP(IPv4/IPv6)實時更新到各大 DNS 服務商,實現動態域名解析。" + local docker_url="官網介紹: https://github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11248,10 +11248,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" + local docker_describe="開源免費的 SSL 證書自動化管理平台" + local docker_url="官網介紹: https://allinssl.com" local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local docker_passwd="echo \"用戶名: allinssl 密碼: allinssldocker\"" local app_size="1" docker_app ;; @@ -11280,8 +11280,8 @@ while true; do } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" + local docker_describe="開源免費隨時隨地SFTP FTP WebDAV 文件傳輸工具" + local docker_url="官網介紹: https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11312,9 +11312,9 @@ while true; do } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_describe="開源AI聊天機器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官網介紹: https://astrbot.app/" + local docker_use="echo \"用戶名: astrbot 密碼: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -11341,8 +11341,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="是一個輕量、高性能的音樂流媒體服務器" + local docker_url="官網介紹: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11368,8 +11368,8 @@ while true; do } - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" + local docker_describe="一個你可以控制數據的密碼管理器" + local docker_url="官網介紹: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11400,8 +11400,8 @@ while true; do } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_describe="免費在線視頻搜索與觀看平台" + local docker_url="官網介紹: https://github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11415,9 +11415,9 @@ while true; do local app_id="74" - local app_name="moontv私有影视" - local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_name="moontv私有影視" + local app_text="免費在線視頻搜索與觀看平台" + local app_url="視頻介紹: https://github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11482,8 +11482,8 @@ while true; do } - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_describe="你的音樂精靈,旨在幫助你更好地管理音樂。" + local docker_url="官網介紹: https://github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11509,8 +11509,8 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_describe="是一個中文DOS遊戲合集網站" + local docker_url="官網介紹: https://github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11544,9 +11544,9 @@ while true; do } - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_describe="迅雷你的離線高速BT磁力下載工具" + local docker_url="官網介紹: https://github.com/cnk3x/xunlei" + local docker_use="echo \"手機登錄迅雷,再輸入邀請碼,邀請碼: 迅雷牛通\"" local docker_passwd="" local app_size="1" docker_app @@ -11559,8 +11559,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_text="PandaWiki是一款AI大模型驅動的開源智能文檔管理系統,強烈建議不要自定義端口部署。" + local app_url="官方介紹: https://github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -11602,8 +11602,8 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_describe="Beszel輕量易用的服務器監控" + local docker_url="官網介紹: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11615,9 +11615,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" + local app_name="linkwarden書籤管理" + local app_text="一個開源的自託管書籤管理平台,支持標籤、搜索和團隊協作。" + local app_url="官方網站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -11687,9 +11687,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" + local app_name="JitsiMeet視頻會議" + local app_text="一個開源的安全視頻會議解決方案,支持多人在線會議、屏幕共享與加密通信。" + local app_url="官方網站: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -11755,8 +11755,8 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_describe="高性能AI接口透明代理服務" + local docker_url="官網介紹: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11788,9 +11788,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_describe="輕量級的自託管服務器監控工具" + local docker_url="官網介紹: https://github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默認賬號: admin 默認密碼: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -11819,8 +11819,8 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_describe="開源個人訂閱追踪器,可用於財務管理" + local docker_url="官網介紹: https://github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -11831,9 +11831,9 @@ while true; do 85|immich) local app_id="85" - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_name="immich圖片視頻管理器" + local app_text="高性能自託管照片和視頻管理解決方案。" + local app_url="官網介紹: https://github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -11897,8 +11897,8 @@ while true; do } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" + local docker_describe="是一款開源媒體服務器軟件" + local docker_url="官網介紹: https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -11925,9 +11925,9 @@ while true; do } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_describe="遠程一起觀看電影和直播的程序。它提供了同步觀影、直播、聊天等功能" + local docker_url="官網介紹: https://github.com/synctv-org/synctv" + local docker_use="echo \"初始賬號和密碼: root 登陸後請及時修改登錄密碼\"" local docker_passwd="" local app_size="1" docker_app @@ -11955,10 +11955,10 @@ while true; do } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_describe="開源、免費的自建直播平台" + local docker_url="官網介紹: https://owncast.online" + local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" + local docker_passwd="echo \"初始賬號: admin 初始密碼: abc123 登陸後請及時修改登錄密碼\"" local app_size="1" docker_app @@ -11984,10 +11984,10 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" - local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" - local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" + local docker_describe="匿名口令分享文本和文件,像拿快遞一樣取文件" + local docker_url="官網介紹: https://github.com/vastsa/FileCodeBox" + local docker_use="echo \"訪問地址後面帶 /#/admin 訪問管理員頁面\"" + local docker_passwd="echo \"管理員密碼: FileCodeBox2023\"" local app_size="1" docker_app @@ -12040,8 +12040,8 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" - local docker_url="官网介绍: https://matrix.org/" + local docker_describe="Matrix是一個去中心化的聊天協議" + local docker_url="官網介紹: https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12055,9 +12055,9 @@ while true; do local app_id="91" - local app_name="gitea私有代码仓库" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_name="gitea私有代碼倉庫" + local app_text="免費新一代的代碼託管平台,提供接近 GitHub 的使用體驗。" + local app_url="視頻介紹: https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12119,8 +12119,8 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_describe="是一個基於Web的文件管理器" + local docker_url="官網介紹: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -12146,8 +12146,8 @@ while true; do } - local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_describe="極簡靜態文件服務器,支持上傳下載" + local docker_url="官網介紹: https://github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12177,8 +12177,8 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_describe="分佈式高速下載工具,支持多種協議" + local docker_url="官網介紹: https://github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12192,9 +12192,9 @@ while true; do local app_id="95" - local app_name="paperless文档管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_name="paperless文檔管理平台" + local app_text="開源的電子文檔管理系統,它的主要用途是把你的紙質文件數字化並管理起來。" + local app_url="視頻介紹: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -12240,9 +12240,9 @@ while true; do local app_id="96" - local app_name="2FAuth自托管二步验证器" - local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_name="2FAuth自託管二步驗證器" + local app_text="自託管的雙重身份驗證 (2FA) 賬戶管理和驗證碼生成工具。" + local app_url="官網: https://github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12387,8 +12387,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="現代化、高性能的虛擬專用網絡工具" + local docker_url="官網介紹: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12457,8 +12457,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="現代化、高性能的虛擬專用網絡工具" + local docker_url="官網介紹: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12471,9 +12471,9 @@ while true; do local app_id="99" - local app_name="dsm群晖虚拟机" - local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_name="dsm群暉虛擬機" + local app_text="Docker容器中的虛擬DSM" + local app_url="官網: https://github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12543,8 +12543,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_describe="開源的點對點文件同步工具,類似於 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官網介紹: https://github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12555,9 +12555,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI视频生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI視頻生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短視頻的工具" + local app_url="官方網站: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12610,8 +12610,8 @@ while true; do } - local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_describe="是一款支持獨立部署的個人云社交媒體聊天服務" + local docker_url="官網介紹: https://github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12622,9 +12622,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami网站统计工具" - local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_name="Umami網站統計工具" + local app_text="開源、輕量、隱私友好的網站分析工具,類似於GoogleAnalytics。" + local app_url="官方網站: https://github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12689,8 +12689,8 @@ while true; do } - local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_describe="思源筆記是一款隱私優先的知識管理系統" + local docker_url="官網介紹: https://github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -12716,8 +12716,8 @@ while true; do } - local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_describe="是一款強大的開源白板工具,集成思維導圖、流程圖等。" + local docker_url="官網介紹: https://github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -12751,8 +12751,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_describe="PanSou是一個高性能的網盤資源搜索API服務。" + local docker_url="官網介紹: https://github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -12765,9 +12765,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot聊天机器人" - local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_name="LangBot聊天機器人" + local app_text="是一個開源的大語言模型原生即時通信機器人開發平台" + local app_url="官方網站: https://github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -12823,8 +12823,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_describe="是一個適用於個人或小團隊的在線網盤程序。" + local docker_url="官網介紹: https://github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -12835,9 +12835,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep书签管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_name="karakeep書籤管理" + local app_text="是一款可自行託管的書籤應用,帶有人工智能功能,專為數據囤積者而設計。" + local app_url="官方網站: https://github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -12889,8 +12889,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_describe="是一個功能強大的多格式文件轉換工具(支持文檔、圖像、音頻視頻等)強烈建議添加域名訪問" + local docker_url="項目地址: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13099,9 +13099,9 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}开启${gl_bai}" + local tmux_sshd_status="${gl_lv}開啟${gl_bai}" else - local tmux_sshd_status="${gl_hui}关闭${gl_bai}" + local tmux_sshd_status="${gl_hui}關閉${gl_bai}" fi send_stats "SSH常駐模式" echo -e "SSH常駐模式${tmux_sshd_status}" @@ -13122,7 +13122,7 @@ linux_work() { tmux_run ;; 2) - sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc + sed -i '/# 自動進入 tmux 會話/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -13613,7 +13613,7 @@ EOF send_stats "用戶管理" echo "用戶列表" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" + printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "用戶權限" "用戶組" "sudo權限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") @@ -14366,11 +14366,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}正在採集數據${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}採集已關閉${gl_bai}" else - local status_message="无法确定的状态" + local status_message="無法確定的狀態" fi echo "隱私與安全" From 0dbb031666ebb84e8ee78e3abf9c4167ce466d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 21:40:07 +0800 Subject: [PATCH 0456/1285] Add Lucky tool and update menu options --- cn/kejilion.sh | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2edb9a057..15a65cf5c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9322,7 +9322,7 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12899,7 +12899,32 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + local docker_port=16601 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + } + + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。host模式请不要使用自定义端口。" + local docker_url="项目地址: https://github.com/gdy666/lucky" + local docker_use="echo \"默认账号密码: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) From 140d5f33de0cd5acadd4e30489f4731a01d8eda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 21:41:09 +0800 Subject: [PATCH 0457/1285] Add Lucky app for internal network penetration tool --- kejilion.sh | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 33f670e46..035a82082 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9322,7 +9322,7 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12899,7 +12899,32 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + local docker_port=16601 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + } + + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。host模式请不要使用自定义端口。" + local docker_url="项目地址: https://github.com/gdy666/lucky" + local docker_use="echo \"默认账号密码: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) From 9bc11254322eb16ffdc72481621da0acfdc0009f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 21:42:23 +0800 Subject: [PATCH 0458/1285] Update kejilion_sh_log.txt with new tool info Added installation and usage information for lucky reverse proxy tool. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2d2473b91..57975f7af 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1386,6 +1386,7 @@ SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问 ------------------------ 2025-12-24 v4.2.10 SSL申请失败后追加导入已有证书选项,你可以导入域名有效证书使用了(如CF15年证书)。 +应用市场新增了lucky大内网反向代理工具的安装及使用。 ------------------------ From b584b0fcaad14ca826e7a099eb5ce9af0bdcf983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 21:56:07 +0800 Subject: [PATCH 0459/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 15a65cf5c..3d37fdb86 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12917,7 +12917,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。host模式请不要使用自定义端口。" + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" local docker_url="项目地址: https://github.com/gdy666/lucky" local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" From a57c47999c6ea7e6d455a9079072292c95c71adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 21:56:39 +0800 Subject: [PATCH 0460/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 035a82082..ca02b519d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12917,7 +12917,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。host模式请不要使用自定义端口。" + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" local docker_url="项目地址: https://github.com/gdy666/lucky" local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" From 217cbeef66fbaf315f6ffd6b08c721757fd7556c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:38:47 +0800 Subject: [PATCH 0461/1285] Add command to set HTTP admin port in kejilion.sh --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3d37fdb86..9cdf9e5b4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12914,6 +12914,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /home/docker/lucky/conf:/app/conf \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} + docker exec -it ${docker_name} /app/lucky -rSetHttpAdminPort ${docker_port} } From f9e031ee4684875a479b243320c51276bf7fd5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:39:15 +0800 Subject: [PATCH 0462/1285] Add command to set HTTP admin port in kejilion.sh --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index ca02b519d..973d0a10f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12914,6 +12914,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /home/docker/lucky/conf:/app/conf \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} + docker exec -it ${docker_name} /app/lucky -rSetHttpAdminPort ${docker_port} } From d73fb7ccb83eafeffd20e748472f7bab3127ff1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:43:57 +0800 Subject: [PATCH 0463/1285] Update kejilion.sh --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 973d0a10f..7b69dfc10 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12914,7 +12914,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /home/docker/lucky/conf:/app/conf \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - docker exec -it ${docker_name} /app/lucky -rSetHttpAdminPort ${docker_port} + + sleep 3 + docker exec -it lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From f98671e68cbaf0b8be8ac321ab3a3f72965af525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:44:45 +0800 Subject: [PATCH 0464/1285] Add sleep before executing lucky command Added a sleep command before executing the lucky command. --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9cdf9e5b4..de7a59049 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12914,7 +12914,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /home/docker/lucky/conf:/app/conf \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - docker exec -it ${docker_name} /app/lucky -rSetHttpAdminPort ${docker_port} + + sleep 3 + docker exec -it lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From 04624077f64737ccadbe90bc93802dc06fb8b5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:49:17 +0800 Subject: [PATCH 0465/1285] Remove '-it' option from docker exec command --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index de7a59049..2a385c222 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12916,7 +12916,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} sleep 3 - docker exec -it lucky /app/lucky -rSetHttpAdminPort ${docker_port} + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From 0250cc5d746bda60153a5a4ede850b71e0b020bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:50:53 +0800 Subject: [PATCH 0466/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7b69dfc10..0cf019d0d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12916,7 +12916,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} sleep 3 - docker exec -it lucky /app/lucky -rSetHttpAdminPort ${docker_port} + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From 5b972a6906bf230063797caef40287e2b2e4e63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:57:57 +0800 Subject: [PATCH 0467/1285] Adjust sleep duration and restart lucky container Reduced sleep duration before restarting the lucky container. --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2a385c222..a7079c092 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12915,7 +12915,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - sleep 3 + sleep 2 + docker restart lucky + sleep 2 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From c1daa3e609d254d2d689191132e636d405f605d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:58:35 +0800 Subject: [PATCH 0468/1285] Update kejilion.sh --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 0cf019d0d..246cbe04a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12915,7 +12915,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - sleep 3 + sleep 2 + docker restart lucky + sleep 2 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From dc86b710360368842fc7fb22e08cec8fffe599bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 23:05:05 +0800 Subject: [PATCH 0469/1285] Modify Lucky initialization process Replaced sleep and restart commands with a wait message. --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 246cbe04a..70f96d19b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12915,9 +12915,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - sleep 2 - docker restart lucky - sleep 2 + echo "正在等待 Lucky 初始化..." + sleep 10 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From cb2b59aeb23b957db7eece05f42c583a29ed9f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 24 Dec 2025 23:05:52 +0800 Subject: [PATCH 0470/1285] Modify Lucky initialization process Replaced docker restart with a wait message and extended sleep duration. --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a7079c092..d5c85d3f7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12915,9 +12915,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - sleep 2 - docker restart lucky - sleep 2 + echo "正在等待 Lucky 初始化..." + sleep 10 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } From b094c5bcbed079b8e4fca314e8c82a4053f6a446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 11:00:14 +0800 Subject: [PATCH 0471/1285] Update messages and add Firefox Docker configuration --- cn/kejilion.sh | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d5c85d3f7..9c87076d2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令行输入passwd修改密码${gl_bai}" echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "重装系统" echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}bin456789项目地址: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -9323,6 +9326,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12905,7 +12909,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local docker_name="lucky" local docker_img="gdy666/lucky:v2" # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) - local docker_port=16601 + local docker_port=8112 docker_rum() { @@ -12931,6 +12935,36 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "设置登录密码: " admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" + local docker_url="项目地址: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear send_stats "全部应用备份" From 2a17aaf4ac569a0c538744139b284ca81ed874f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 11:00:52 +0800 Subject: [PATCH 0472/1285] Update messages and add Firefox Docker setup --- kejilion.sh | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 70f96d19b..fc7b09bd8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令行输入passwd修改密码${gl_bai}" echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "重装系统" echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢leitbogioro大佬和bin456789大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}bin456789项目地址: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -9323,6 +9326,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -12905,7 +12909,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local docker_name="lucky" local docker_img="gdy666/lucky:v2" # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) - local docker_port=16601 + local docker_port=8112 docker_rum() { @@ -12931,6 +12935,36 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "设置登录密码: " admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" + local docker_url="项目地址: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + b) clear send_stats "全部应用备份" From 475c41d294670a825ea466f62fea2f064253a151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 11:02:25 +0800 Subject: [PATCH 0473/1285] Add Firefox browser installation to changelog --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 57975f7af..afe13e09e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1387,6 +1387,8 @@ SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问 2025-12-24 v4.2.10 SSL申请失败后追加导入已有证书选项,你可以导入域名有效证书使用了(如CF15年证书)。 应用市场新增了lucky大内网反向代理工具的安装及使用。 +应用市场新增了Firefox浏览器的安装及使用。 + ------------------------ From 0bfc2e55655db451d581a2aa6d4f9f3282fc0e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:12:40 +0800 Subject: [PATCH 0474/1285] Add files via upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 第三方应用市场 范例 --- apps/201.conf | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/201.conf diff --git a/apps/201.conf b/apps/201.conf new file mode 100644 index 000000000..ebc5fd875 --- /dev/null +++ b/apps/201.conf @@ -0,0 +1,27 @@ +local app_id="201" +local app_name="cloudreve网盘" +local app_text="cloudreve是一个支持多家云存储的网盘系统" +local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" +local docker_name="cloudreve" +local docker_port="8201" +local app_size="2" +docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip +} +docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d +} +docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "应用已卸载" +} +docker_app_plus From cbd43a2d5ca7888f8a1e8307853adb257b9a6735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:22:20 +0800 Subject: [PATCH 0475/1285] Update and rename 201.conf to cloudreve2.conf --- apps/{201.conf => cloudreve2.conf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/{201.conf => cloudreve2.conf} (100%) diff --git a/apps/201.conf b/apps/cloudreve2.conf similarity index 100% rename from apps/201.conf rename to apps/cloudreve2.conf From 379c0ac052e9d161d0ed9f44ee25ca129c61aa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:03:32 +0800 Subject: [PATCH 0476/1285] Add configuration for cloudreve application --- apps/cd.conf | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/cd.conf diff --git a/apps/cd.conf b/apps/cd.conf new file mode 100644 index 000000000..01b1f9b31 --- /dev/null +++ b/apps/cd.conf @@ -0,0 +1,27 @@ +local app_id="201" +local app_name="cloudreve网盘" +local app_text="cloudreve是一个支持多家云存储的网盘系统" +local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" +local docker_name="cloudreve" +local docker_port="8201" +local app_size="2" +docker_app_install() { + cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 + curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml + sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml + cd /home/docker/cloud/ + docker compose up -d + clear + echo "已经安装完成" + check_docker_app_ip +} +docker_app_update() { + cd /home/docker/cloud/ && docker compose down --rmi all + cd /home/docker/cloud/ && docker compose up -d +} +docker_app_uninstall() { + cd /home/docker/cloud/ && docker compose down --rmi all + rm -rf /home/docker/cloud + echo "应用已卸载" +} +docker_app_plus From 8b20bf35e21c34f0b6eb53d4cadbb461e4372f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:03:53 +0800 Subject: [PATCH 0477/1285] Delete apps/cloudreve2.conf --- apps/cloudreve2.conf | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 apps/cloudreve2.conf diff --git a/apps/cloudreve2.conf b/apps/cloudreve2.conf deleted file mode 100644 index ebc5fd875..000000000 --- a/apps/cloudreve2.conf +++ /dev/null @@ -1,27 +0,0 @@ -local app_id="201" -local app_name="cloudreve网盘" -local app_text="cloudreve是一个支持多家云存储的网盘系统" -local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" -local docker_name="cloudreve" -local docker_port="8201" -local app_size="2" -docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip -} -docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d -} -docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "应用已卸载" -} -docker_app_plus From 3d3185b785b1d4f4c0ffd9542acf6c186cc7d88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:11:01 +0800 Subject: [PATCH 0478/1285] Enhance README with deployment and usage guidelines Added guidelines for directory structure, container lifecycle, variable usage, and network optimization. --- apps/README.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 apps/README.md diff --git a/apps/README.md b/apps/README.md new file mode 100644 index 000000000..83f564d82 --- /dev/null +++ b/apps/README.md @@ -0,0 +1,93 @@ +# 🚀 开发者应用入驻指南 (kejilion.sh) + +欢迎为 `kejilion.sh` 贡献应用!通过在 `sh/apps/` 目录下创建 `.conf` 配置文件,您的应用将自动集成到脚本的应用市场中。 + +--- + +## 1. 快速开始 +在 `sh/apps/` 目录下创建一个以应用名命名的配置文件,例如:`myapp.conf`。 + +## 2. 配置文件模板 +每个配置文件应严格遵循以下结构,确保变量和函数命名规范: + +```bash +# --- 基础信息 --- +local app_name="应用显示名称" +local app_text="一句话简介,说明应用用途" +local app_url="相关链接(如视频教程或项目官网)" +local docker_name="容器识别名" +local docker_port="默认映射端口" +local app_size="占用空间评分 (1-5)" + +# --- 核心逻辑 --- + +# 1. 安装函数 +docker_app_install() { + # 必须在 /home/docker/ 下创建应用目录 + mkdir -p /home/docker/myapp && cd /home/docker/myapp + + # 下载并配置 compose 文件 + curl -L -o docker-compose.yml "${gh_proxy}[raw.githubusercontent.com/](https://raw.githubusercontent.com/)..." + + # 端口处理(使用变量以便用户自定义) + sed -i "s/8080:8080/${docker_port}:8080/g" docker-compose.yml + + # 启动容器 + docker compose up -d + + echo "安装完成" +} + +# 2. 更新函数 +docker_app_update() { + cd /home/docker/myapp + docker compose pull + docker compose up -d + echo "更新完成" +} + +# 3. 卸载函数 +docker_app_uninstall() { + cd /home/docker/myapp + docker compose down --rmi all + rm -rf /home/docker/myapp + echo "卸载完成" +} + +# --- 结尾必须包含此行以完成注册 --- +docker_app_plus + + +``` + +## 3. 强制规范与原则 + +### 📁 目录路径规范 +> **核心原则:数据不入系统盘,统一归档。** + +* **【必须】**:所有持久化数据(Volume/Bind Mount)必须存储在 `/home/docker/[应用名]` 目录下。 +* **【禁止】**:严禁将数据存放在 `/root`、`/etc`、`/var/lib` 或其他非指定根目录。 +* **【理由】**:统一路径方便用户进行一键备份、整机迁移以及权限的统一管理。 + +### 🔄 容器生命周期 +* **开机自启**:生成的 `docker-compose.yml` 中必须包含 `restart: always` 或 `restart: unless-stopped`。 +* **干净卸载**:`docker_app_uninstall` 函数必须执行闭环操作,包含: + * 停止并删除容器 (`docker compose down`) + * 删除对应的镜像 (`--rmi all`) + * **彻底物理删除** `/home/docker/[应用名]` 目录。 + +### 🆔 变量与语法说明 +* **App ID**:当前版本已弱化 ID 概念,您可以省略或填入任意数值,系统目前主要以 `.conf` 文件名作为唯一识别依据。 +* **Local 关键字**:由于配置文件是在函数内部被 `source` 加载的,请务必保留 `local` 声明,这能有效防止变量污染脚本的全局环境。 + +### 🌐 网络优化 +* **镜像加速**:下载 GitHub 资源(如 `.yml` 或 `脚本`)时,请务必在 URL 前加上 `${gh_proxy}` 变量,以确保国内服务器的访问成功率。 + +--- + +## 4. 入驻流程 + +1. **本地自测**:在自己的 VPS 上完整运行安装、更新、卸载流程,确保无报错。 +2. **路径审计**:检查 `/home/docker/` 目录下是否正确生成了应用文件夹,且没有文件“溢出”到其他地方。 +3. **提交申请**:将您的 `[应用名].conf` 文件通过 **Pull Request** 提交至本仓库的 `sh/apps/` 目录。 +4. **审核发布**:维护者审核逻辑安全后,您的应用将正式上线 `kejilion.sh` 菜单。 From 30850586a2f2815f0264b0effef64ce9af9fafd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:22:21 +0800 Subject: [PATCH 0479/1285] Update README.md --- apps/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/README.md b/apps/README.md index 83f564d82..2b3b06751 100644 --- a/apps/README.md +++ b/apps/README.md @@ -83,9 +83,25 @@ docker_app_plus ### 🌐 网络优化 * **镜像加速**:下载 GitHub 资源(如 `.yml` 或 `脚本`)时,请务必在 URL 前加上 `${gh_proxy}` 变量,以确保国内服务器的访问成功率。 + --- -## 4. 入驻流程 + +## 4. 快捷启动与调用 + +一旦您的 `.conf` 文件被合入仓库,该应用将自动进入 **“第三方应用入驻”** 模块。此外,开发者可以向用户提供专属的极简安装指令: + +#### 🚀 快捷安装指令模板: +```bash +bash <(curl -sL kejilion.sh) app [文件名] +``` +示例:如果您的配置文件名为 myapp.conf,则调用指令为: bash <(curl -sL kejilion.sh) app myapp + + +--- + + +## 5. 入驻流程 1. **本地自测**:在自己的 VPS 上完整运行安装、更新、卸载流程,确保无报错。 2. **路径审计**:检查 `/home/docker/` 目录下是否正确生成了应用文件夹,且没有文件“溢出”到其他地方。 From 515fcd7cd7653e4875d3c99352838cbffdbef0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:30:32 +0800 Subject: [PATCH 0480/1285] Update README.md --- apps/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/README.md b/apps/README.md index 2b3b06751..6f2520be1 100644 --- a/apps/README.md +++ b/apps/README.md @@ -14,10 +14,10 @@ # --- 基础信息 --- local app_name="应用显示名称" local app_text="一句话简介,说明应用用途" -local app_url="相关链接(如视频教程或项目官网)" -local docker_name="容器识别名" -local docker_port="默认映射端口" -local app_size="占用空间评分 (1-5)" +local app_url="示例官网: https://github.com/kejilion/sh/edit/main/apps" +local docker_name="容器名称" +local docker_port="暴露端口" +local app_size="占用空间大小 (1-10)设置10代表要求10G空间才能装" # --- 核心逻辑 --- From 386c50aa724700c224ce9ec62c2b8f15df104eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:33:34 +0800 Subject: [PATCH 0481/1285] Update README.md --- apps/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/README.md b/apps/README.md index 6f2520be1..041c5bc2c 100644 --- a/apps/README.md +++ b/apps/README.md @@ -12,11 +12,12 @@ ```bash # --- 基础信息 --- +local app_id="1000以上" local app_name="应用显示名称" local app_text="一句话简介,说明应用用途" local app_url="示例官网: https://github.com/kejilion/sh/edit/main/apps" -local docker_name="容器名称" -local docker_port="暴露端口" +local docker_name="容器启动后的名称" +local docker_port="默认访问端口" local app_size="占用空间大小 (1-10)设置10代表要求10G空间才能装" # --- 核心逻辑 --- From 786ed210e8b149c7a0a9872146cf0b818724c340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:58:41 +0800 Subject: [PATCH 0482/1285] Update sh version and modify application list formatting --- cn/kejilion.sh | 70 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9c87076d2..d0c74d386 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -9246,7 +9246,7 @@ while true; do if [ -z "$sub_choice" ]; then clear echo -e "应用市场" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9264,69 +9264,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" + for f in "$HOME"/sh/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" + done + echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -13037,10 +13047,43 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + s) + send_stats "搜索第三方应用" + cd ~ + install git + if [ ! -d sh/.git ]; then + git clone https://github.com/kejilion/sh.git + else + cd sh + git pull origin main + fi + ;; + + + d) + send_stats "删除第三方应用" + cd ~ + rm -rf $HOME/sh + ;; + 0) kejilion ;; *) + cd ~ + install git + if [ ! -d sh/.git ]; then + git clone https://github.com/kejilion/sh.git + else + cd sh + git pull origin main + fi + local custom_app="$HOME/sh/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}错误: 未找到编号为 ${sub_choice} 的应用配置${gl_bai}" + fi ;; esac break_end @@ -13050,6 +13093,7 @@ done } + linux_work() { while true; do From 4d735fc49e5f5f2e7b6955142f0f14d7a68c31ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:59:22 +0800 Subject: [PATCH 0483/1285] Update version and adjust echo formatting --- kejilion.sh | 70 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fc7b09bd8..0cb3f48df 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -9246,7 +9246,7 @@ while true; do if [ -z "$sub_choice" ]; then clear echo -e "应用市场" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9264,69 +9264,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" + for f in "$HOME"/sh/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" + done + echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -13037,10 +13047,43 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + s) + send_stats "搜索第三方应用" + cd ~ + install git + if [ ! -d sh/.git ]; then + git clone https://github.com/kejilion/sh.git + else + cd sh + git pull origin main + fi + ;; + + + d) + send_stats "删除第三方应用" + cd ~ + rm -rf $HOME/sh + ;; + 0) kejilion ;; *) + cd ~ + install git + if [ ! -d sh/.git ]; then + git clone https://github.com/kejilion/sh.git + else + cd sh + git pull origin main + fi + local custom_app="$HOME/sh/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}错误: 未找到编号为 ${sub_choice} 的应用配置${gl_bai}" + fi ;; esac break_end @@ -13050,6 +13093,7 @@ done } + linux_work() { while true; do From 97beaa3dc5b018e79c8c03d63b5a9b672a4a1453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 00:02:03 +0800 Subject: [PATCH 0484/1285] Update kejilion_sh_log.txt with new version info Added new version details and third-party support information. --- kejilion_sh_log.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index afe13e09e..4729ce6d6 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1388,7 +1388,9 @@ SSL申请失败后追加选项菜单,你可以继续申请,使用HTTP访问 SSL申请失败后追加导入已有证书选项,你可以导入域名有效证书使用了(如CF15年证书)。 应用市场新增了lucky大内网反向代理工具的安装及使用。 应用市场新增了Firefox浏览器的安装及使用。 - ------------------------ - +2025-12-25 v4.3.0 +应用市场支持第三方入驻功能,开发者可以将自己的项目加入到脚本中让大家使用。 +入驻指南: https://github.com/kejilion/sh/tree/main/apps +------------------------ From d627a2bf378c36ed9aa262851a1b75684b7bb449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 09:49:59 +0800 Subject: [PATCH 0485/1285] Update README.md --- apps/README.md | 108 +------------------------------------------------ 1 file changed, 1 insertion(+), 107 deletions(-) diff --git a/apps/README.md b/apps/README.md index 041c5bc2c..e238e5132 100644 --- a/apps/README.md +++ b/apps/README.md @@ -1,110 +1,4 @@ # 🚀 开发者应用入驻指南 (kejilion.sh) -欢迎为 `kejilion.sh` 贡献应用!通过在 `sh/apps/` 目录下创建 `.conf` 配置文件,您的应用将自动集成到脚本的应用市场中。 +https://github.com/kejilion/apps ---- - -## 1. 快速开始 -在 `sh/apps/` 目录下创建一个以应用名命名的配置文件,例如:`myapp.conf`。 - -## 2. 配置文件模板 -每个配置文件应严格遵循以下结构,确保变量和函数命名规范: - -```bash -# --- 基础信息 --- -local app_id="1000以上" -local app_name="应用显示名称" -local app_text="一句话简介,说明应用用途" -local app_url="示例官网: https://github.com/kejilion/sh/edit/main/apps" -local docker_name="容器启动后的名称" -local docker_port="默认访问端口" -local app_size="占用空间大小 (1-10)设置10代表要求10G空间才能装" - -# --- 核心逻辑 --- - -# 1. 安装函数 -docker_app_install() { - # 必须在 /home/docker/ 下创建应用目录 - mkdir -p /home/docker/myapp && cd /home/docker/myapp - - # 下载并配置 compose 文件 - curl -L -o docker-compose.yml "${gh_proxy}[raw.githubusercontent.com/](https://raw.githubusercontent.com/)..." - - # 端口处理(使用变量以便用户自定义) - sed -i "s/8080:8080/${docker_port}:8080/g" docker-compose.yml - - # 启动容器 - docker compose up -d - - echo "安装完成" -} - -# 2. 更新函数 -docker_app_update() { - cd /home/docker/myapp - docker compose pull - docker compose up -d - echo "更新完成" -} - -# 3. 卸载函数 -docker_app_uninstall() { - cd /home/docker/myapp - docker compose down --rmi all - rm -rf /home/docker/myapp - echo "卸载完成" -} - -# --- 结尾必须包含此行以完成注册 --- -docker_app_plus - - -``` - -## 3. 强制规范与原则 - -### 📁 目录路径规范 -> **核心原则:数据不入系统盘,统一归档。** - -* **【必须】**:所有持久化数据(Volume/Bind Mount)必须存储在 `/home/docker/[应用名]` 目录下。 -* **【禁止】**:严禁将数据存放在 `/root`、`/etc`、`/var/lib` 或其他非指定根目录。 -* **【理由】**:统一路径方便用户进行一键备份、整机迁移以及权限的统一管理。 - -### 🔄 容器生命周期 -* **开机自启**:生成的 `docker-compose.yml` 中必须包含 `restart: always` 或 `restart: unless-stopped`。 -* **干净卸载**:`docker_app_uninstall` 函数必须执行闭环操作,包含: - * 停止并删除容器 (`docker compose down`) - * 删除对应的镜像 (`--rmi all`) - * **彻底物理删除** `/home/docker/[应用名]` 目录。 - -### 🆔 变量与语法说明 -* **App ID**:当前版本已弱化 ID 概念,您可以省略或填入任意数值,系统目前主要以 `.conf` 文件名作为唯一识别依据。 -* **Local 关键字**:由于配置文件是在函数内部被 `source` 加载的,请务必保留 `local` 声明,这能有效防止变量污染脚本的全局环境。 - -### 🌐 网络优化 -* **镜像加速**:下载 GitHub 资源(如 `.yml` 或 `脚本`)时,请务必在 URL 前加上 `${gh_proxy}` 变量,以确保国内服务器的访问成功率。 - - ---- - - -## 4. 快捷启动与调用 - -一旦您的 `.conf` 文件被合入仓库,该应用将自动进入 **“第三方应用入驻”** 模块。此外,开发者可以向用户提供专属的极简安装指令: - -#### 🚀 快捷安装指令模板: -```bash -bash <(curl -sL kejilion.sh) app [文件名] -``` -示例:如果您的配置文件名为 myapp.conf,则调用指令为: bash <(curl -sL kejilion.sh) app myapp - - ---- - - -## 5. 入驻流程 - -1. **本地自测**:在自己的 VPS 上完整运行安装、更新、卸载流程,确保无报错。 -2. **路径审计**:检查 `/home/docker/` 目录下是否正确生成了应用文件夹,且没有文件“溢出”到其他地方。 -3. **提交申请**:将您的 `[应用名].conf` 文件通过 **Pull Request** 提交至本仓库的 `sh/apps/` 目录。 -4. **审核发布**:维护者审核逻辑安全后,您的应用将正式上线 `kejilion.sh` 菜单。 From 046e4f10198037f01e8609d7d3e20e522a9dc809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 09:56:42 +0800 Subject: [PATCH 0486/1285] Update paths for application configuration and git repo --- cn/kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d0c74d386..dcb63df1c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9329,14 +9329,14 @@ while true; do echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" - for f in "$HOME"/sh/apps/*.conf; do + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" done - echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" + echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -13052,7 +13052,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d sh/.git ]; then - git clone https://github.com/kejilion/sh.git + git clone https://github.com/kejilion/apps.git else cd sh git pull origin main @@ -13063,7 +13063,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ d) send_stats "删除第三方应用" cd ~ - rm -rf $HOME/sh + rm -rf $HOME/apps ;; 0) @@ -13073,12 +13073,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d sh/.git ]; then - git clone https://github.com/kejilion/sh.git + git clone https://github.com/kejilion/apps.git else - cd sh + cd apps git pull origin main fi - local custom_app="$HOME/sh/apps/${sub_choice}.conf" + local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" else From 4c4dc4b2d83aa7dff3829707765c6fb78dcc4eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 09:58:11 +0800 Subject: [PATCH 0487/1285] Update kejilion.sh --- kejilion.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0cb3f48df..958ca2b53 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9329,14 +9329,14 @@ while true; do echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" - for f in "$HOME"/sh/apps/*.conf; do + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" done - echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" + echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" @@ -13052,7 +13052,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d sh/.git ]; then - git clone https://github.com/kejilion/sh.git + git clone https://github.com/kejilion/apps.git else cd sh git pull origin main @@ -13063,7 +13063,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ d) send_stats "删除第三方应用" cd ~ - rm -rf $HOME/sh + rm -rf $HOME/apps ;; 0) @@ -13073,12 +13073,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d sh/.git ]; then - git clone https://github.com/kejilion/sh.git + git clone https://github.com/kejilion/apps.git else - cd sh + cd apps git pull origin main fi - local custom_app="$HOME/sh/apps/${sub_choice}.conf" + local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" else From 4dc5a65845af649d86d99f3c794e5dba90212b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:23:33 +0800 Subject: [PATCH 0488/1285] Refactor grep and sed commands for clarity --- cn/kejilion.sh | 152 ++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dcb63df1c..3ce6dc59a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1328,9 +1328,9 @@ update_docker_compose_with_db_creds() { if ! grep -q "stream" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml @@ -1338,7 +1338,7 @@ update_docker_compose_with_db_creds() { fi if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 fi @@ -1387,8 +1387,8 @@ install_ldnmp() { cd /home/web && docker compose up -d sleep 1 - crontab -l 2>/dev/null | grep -v 'logrotate' | crontab - - (crontab -l 2>/dev/null; echo '0 2 * * * docker exec nginx apk add logrotate && docker exec nginx logrotate -f /etc/logrotate.conf') | crontab - + crontab -l 2>/dev/null | grep -v 'logrotate' | crontab - + (crontab -l 2>/dev/null; echo '0 2 * * * docker exec nginx apk add logrotate && docker exec nginx logrotate -f /etc/logrotate.conf') | crontab - fix_phpfpm_conf php fix_phpfpm_conf php74 @@ -1439,7 +1439,7 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then - local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ @@ -1554,16 +1554,16 @@ certs_status() { echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in - 1) - send_stats "重新申请" - echo "请再次尝试部署 $webname" - add_yuming - install_ssltls - certs_status + 1) + send_stats "重新申请" + echo "请再次尝试部署 $webname" + add_yuming + install_ssltls + certs_status - ;; - 2) - send_stats "导入已有证书" + ;; + 2) + send_stats "导入已有证书" # 定义文件路径 local cert_file="/home/web/certs/${yuming}_cert.pem" @@ -1608,17 +1608,17 @@ certs_status() { certs_status fi - ;; - 3) - send_stats "不带证书改用HTTP访问" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + ;; + 3) + send_stats "不带证书改用HTTP访问" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf - ;; - *) - send_stats "退出申请" + ;; + *) + send_stats "退出申请" exit - ;; + ;; esac fi @@ -2288,7 +2288,7 @@ web_security() { ;; 32) - nginx_waf off + nginx_waf off echo "站点WAF已关闭" send_stats "站点WAF已关闭" ;; @@ -2359,7 +2359,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_ldnmp_mode + check_ldnmp_mode check_nginx_compression clear send_stats "优化LDNMP环境" @@ -8769,7 +8769,7 @@ linux_ldnmp() { close_port "$port" echo "已阻止IP+端口访问该服务" else - ip_address + ip_address block_container_port "$docker_name" "$ipv4_address" fi @@ -9132,7 +9132,7 @@ linux_ldnmp() { sed -i "s/image: php:fpm-alpine/image: php:${version}-fpm-alpine/" /home/web/docker-compose.yml docker rm -f $ldnmp_pods docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - docker images --filter=reference="kjlion/${ldnmp_pods}*" -q | xargs docker rmi > /dev/null 2>&1 + docker images --filter=reference="kjlion/${ldnmp_pods}*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker exec php chown -R www-data:www-data /var/www/html @@ -11664,7 +11664,7 @@ while true; do clear echo "已经安装完成" - check_docker_app_ip + check_docker_app_ip } @@ -11864,7 +11864,7 @@ while true; do clear echo "已经安装完成" - check_docker_app_ip + check_docker_app_ip } @@ -12976,14 +12976,14 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ b) - clear - send_stats "全部应用备份" + clear + send_stats "全部应用备份" - local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" - cd / && tar czvf "$backup_filename" home + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home - while true; do + while true; do clear echo "备份文件已创建: /$backup_filename" read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice @@ -13013,36 +13013,36 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ break ;; esac - done + done ;; r) - root_use - send_stats "全部应用还原" - echo "可用的应用备份" - echo "-------------------------" - ls -lt /app*.gz | awk '{print $NF}' - echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename - - if [ "$filename" == "0" ]; then + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then break_end linux_panel - fi + fi - # 如果用户没有输入文件名,使用最新的压缩包 - if [ -z "$filename" ]; then + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) - fi + fi - if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" - cd / && tar -xzf "$filename" + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" - else + else echo "没有找到压缩包。" - fi + fi ;; @@ -13054,7 +13054,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ ! -d sh/.git ]; then git clone https://github.com/kejilion/apps.git else - cd sh + cd apps git pull origin main fi ;; @@ -13221,12 +13221,12 @@ linux_work() { read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) - install tmux - local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" + install tmux + local SESSION_NAME="sshd" + send_stats "启动工作区$SESSION_NAME" grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc - tmux_run + tmux_run ;; 2) sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc @@ -14197,10 +14197,10 @@ EOF send_stats "私钥登录" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" @@ -14210,8 +14210,8 @@ EOF case $host_dns in 1) - send_stats "生成新密钥" - add_sshkey + send_stats "生成新密钥" + add_sshkey break_end ;; @@ -14390,7 +14390,7 @@ EOF echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" @@ -14473,11 +14473,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}正在采集数据${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}采集已关闭${gl_bai}" else - local status_message="无法确定的状态" + local status_message="无法确定的状态" fi echo "隐私与安全" @@ -15306,14 +15306,14 @@ else fd|rp|反代) shift ldnmp_Proxy "$@" - find_container_by_host_port "$port" - if [ -z "$docker_name" ]; then - close_port "$port" + find_container_by_host_port "$port" + if [ -z "$docker_name" ]; then + close_port "$port" echo "已阻止IP+端口访问该服务" - else + else ip_address - block_container_port "$docker_name" "$ipv4_address" - fi + block_container_port "$docker_name" "$ipv4_address" + fi ;; loadbalance|负载均衡) From 886118cf7a6d5fd3c293e3879b2c2a92227b402c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:25:51 +0800 Subject: [PATCH 0489/1285] Fix directory navigation for git operations --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 958ca2b53..9634bb863 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13054,7 +13054,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ ! -d sh/.git ]; then git clone https://github.com/kejilion/apps.git else - cd sh + cd apps git pull origin main fi ;; From 571c96eac2ccd068c188f2e9a0409445e930c339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:27:09 +0800 Subject: [PATCH 0490/1285] Refactor script for improved readability and consistency --- cn/kejilion.sh | 150 ++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3ce6dc59a..63820bb18 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1328,9 +1328,9 @@ update_docker_compose_with_db_creds() { if ! grep -q "stream" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') - dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbuse=$(grep -oP 'MYSQL_USER:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') + dbusepasswd=$(grep -oP 'MYSQL_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml @@ -1338,7 +1338,7 @@ update_docker_compose_with_db_creds() { fi if grep -q "kjlion/nginx:alpine" /home/web/docker-compose1.yml; then - sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 + sed -i 's|kjlion/nginx:alpine|nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 sed -i 's|nginx:alpine|kjlion/nginx:alpine|g' /home/web/docker-compose.yml > /dev/null 2>&1 fi @@ -1387,8 +1387,8 @@ install_ldnmp() { cd /home/web && docker compose up -d sleep 1 - crontab -l 2>/dev/null | grep -v 'logrotate' | crontab - - (crontab -l 2>/dev/null; echo '0 2 * * * docker exec nginx apk add logrotate && docker exec nginx logrotate -f /etc/logrotate.conf') | crontab - + crontab -l 2>/dev/null | grep -v 'logrotate' | crontab - + (crontab -l 2>/dev/null; echo '0 2 * * * docker exec nginx apk add logrotate && docker exec nginx logrotate -f /etc/logrotate.conf') | crontab - fix_phpfpm_conf php fix_phpfpm_conf php74 @@ -1439,7 +1439,7 @@ install_ssltls() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ ! -f "$file_path" ]; then - local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ ($yuming =~ $ipv4_pattern || $yuming =~ $ipv6_pattern) ]]; then mkdir -p /etc/letsencrypt/live/$yuming/ @@ -1554,16 +1554,16 @@ certs_status() { echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in - 1) - send_stats "重新申请" - echo "请再次尝试部署 $webname" - add_yuming - install_ssltls - certs_status + 1) + send_stats "重新申请" + echo "请再次尝试部署 $webname" + add_yuming + install_ssltls + certs_status - ;; - 2) - send_stats "导入已有证书" + ;; + 2) + send_stats "导入已有证书" # 定义文件路径 local cert_file="/home/web/certs/${yuming}_cert.pem" @@ -1608,17 +1608,17 @@ certs_status() { certs_status fi - ;; - 3) - send_stats "不带证书改用HTTP访问" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf + ;; + 3) + send_stats "不带证书改用HTTP访问" + sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf - ;; - *) - send_stats "退出申请" + ;; + *) + send_stats "退出申请" exit - ;; + ;; esac fi @@ -2288,7 +2288,7 @@ web_security() { ;; 32) - nginx_waf off + nginx_waf off echo "站点WAF已关闭" send_stats "站点WAF已关闭" ;; @@ -2359,7 +2359,7 @@ check_nginx_compression() { web_optimization() { while true; do - check_ldnmp_mode + check_ldnmp_mode check_nginx_compression clear send_stats "优化LDNMP环境" @@ -8769,7 +8769,7 @@ linux_ldnmp() { close_port "$port" echo "已阻止IP+端口访问该服务" else - ip_address + ip_address block_container_port "$docker_name" "$ipv4_address" fi @@ -9132,7 +9132,7 @@ linux_ldnmp() { sed -i "s/image: php:fpm-alpine/image: php:${version}-fpm-alpine/" /home/web/docker-compose.yml docker rm -f $ldnmp_pods docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 - docker images --filter=reference="kjlion/${ldnmp_pods}*" -q | xargs docker rmi > /dev/null 2>&1 + docker images --filter=reference="kjlion/${ldnmp_pods}*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker exec php chown -R www-data:www-data /var/www/html @@ -11664,7 +11664,7 @@ while true; do clear echo "已经安装完成" - check_docker_app_ip + check_docker_app_ip } @@ -11864,7 +11864,7 @@ while true; do clear echo "已经安装完成" - check_docker_app_ip + check_docker_app_ip } @@ -12976,14 +12976,14 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ b) - clear - send_stats "全部应用备份" + clear + send_stats "全部应用备份" - local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" - cd / && tar czvf "$backup_filename" home + local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" + echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + cd / && tar czvf "$backup_filename" home - while true; do + while true; do clear echo "备份文件已创建: /$backup_filename" read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice @@ -13013,36 +13013,36 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ break ;; esac - done + done ;; r) - root_use - send_stats "全部应用还原" - echo "可用的应用备份" - echo "-------------------------" - ls -lt /app*.gz | awk '{print $NF}' - echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename - - if [ "$filename" == "0" ]; then + root_use + send_stats "全部应用还原" + echo "可用的应用备份" + echo "-------------------------" + ls -lt /app*.gz | awk '{print $NF}' + echo "" + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + + if [ "$filename" == "0" ]; then break_end linux_panel - fi + fi - # 如果用户没有输入文件名,使用最新的压缩包 - if [ -z "$filename" ]; then + # 如果用户没有输入文件名,使用最新的压缩包 + if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) - fi + fi - if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" - cd / && tar -xzf "$filename" + if [ -n "$filename" ]; then + echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + cd / && tar -xzf "$filename" echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" - else + else echo "没有找到压缩包。" - fi + fi ;; @@ -13221,12 +13221,12 @@ linux_work() { read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) - install tmux - local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" + install tmux + local SESSION_NAME="sshd" + send_stats "启动工作区$SESSION_NAME" grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc - tmux_run + tmux_run ;; 2) sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc @@ -14197,10 +14197,10 @@ EOF send_stats "私钥登录" while true; do clear - echo "ROOT私钥登录模式" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "ROOT私钥登录模式" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" echo "------------------------" @@ -14210,8 +14210,8 @@ EOF case $host_dns in 1) - send_stats "生成新密钥" - add_sshkey + send_stats "生成新密钥" + add_sshkey break_end ;; @@ -14390,7 +14390,7 @@ EOF echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" echo "------------------------------------------------" @@ -14473,11 +14473,11 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}正在采集数据${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}采集已关闭${gl_bai}" else - local status_message="无法确定的状态" + local status_message="无法确定的状态" fi echo "隐私与安全" @@ -15306,14 +15306,14 @@ else fd|rp|反代) shift ldnmp_Proxy "$@" - find_container_by_host_port "$port" - if [ -z "$docker_name" ]; then - close_port "$port" + find_container_by_host_port "$port" + if [ -z "$docker_name" ]; then + close_port "$port" echo "已阻止IP+端口访问该服务" - else + else ip_address - block_container_port "$docker_name" "$ipv4_address" - fi + block_container_port "$docker_name" "$ipv4_address" + fi ;; loadbalance|负载均衡) From 05a4f28a06cdc5fa25f2ed4db048afbacb6127a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:31:45 +0800 Subject: [PATCH 0491/1285] Fix directory check for git repository --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9634bb863..236679977 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13051,7 +13051,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ send_stats "搜索第三方应用" cd ~ install git - if [ ! -d sh/.git ]; then + if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps @@ -13072,7 +13072,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ *) cd ~ install git - if [ ! -d sh/.git ]; then + if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps From 15d5790865b18501038299a648fd1e671e830dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:32:33 +0800 Subject: [PATCH 0492/1285] Fix directory check for git repository --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 63820bb18..689d7a43a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13051,7 +13051,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ send_stats "搜索第三方应用" cd ~ install git - if [ ! -d sh/.git ]; then + if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps @@ -13072,7 +13072,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ *) cd ~ install git - if [ ! -d sh/.git ]; then + if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps From 5011dda0979c0d4f83208da2864f1833d6fe880c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:28:31 +0800 Subject: [PATCH 0493/1285] =?UTF-8?q?Change=20'=E7=AC=AC=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=85=A5=E9=A9=BB'=20to=20'=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E5=BA=94=E7=94=A8=E5=88=97=E8=A1=A8'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 689d7a43a..e893221fe 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9328,7 +9328,7 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) @@ -9336,6 +9336,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" @@ -15479,5 +15480,3 @@ else ;; esac fi - - From c9f34440b7a43b0352b05cff353f51eea49b6c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:29:07 +0800 Subject: [PATCH 0494/1285] Update kejilion.sh --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 236679977..d7a843280 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9328,7 +9328,7 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用入驻${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) @@ -9336,6 +9336,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" @@ -15479,5 +15480,3 @@ else ;; esac fi - - From 840bd4e98b4d273f081d5c58b041f9f94c7760c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:49:34 +0800 Subject: [PATCH 0495/1285] Enhance third-party applications list message Updated the third-party applications list message to include a link to the developer guide. --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e893221fe..0bca2f279 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9328,7 +9328,8 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_kjlan}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) From 9e121a525a65d5ef3f0b503fe14eac002638b57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:50:42 +0800 Subject: [PATCH 0496/1285] Enhance third-party application list message Updated the third-party application list message to include a link to the developer guide. --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d7a843280..d5bdc49c7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9328,7 +9328,8 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_kjlan}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) From df7eab88669972ee56cec68a7b838c03d55a4e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:51:27 +0800 Subject: [PATCH 0497/1285] Update URL color in third-party application list --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d5bdc49c7..cc66df001 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9328,7 +9328,7 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_kjlan}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue From 80b8f0282ea60121e28d1f469bf0c4140fb85023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:52:10 +0800 Subject: [PATCH 0498/1285] Update link color in third-party applications list --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0bca2f279..c584586d0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9328,7 +9328,7 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_kjlan}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue From 9c6d24be387506d887c0b16719f80fcc2e662656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:57:46 +0800 Subject: [PATCH 0499/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c584586d0..227758be6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9328,8 +9328,8 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" - + echo -e "${gl_kjlan}第三方应用列表" + echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) From a0815e49dc9371cef78012f2f95933d11ceb6cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:58:36 +0800 Subject: [PATCH 0500/1285] Refactor third-party applications message output --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index cc66df001..613fecc41 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9328,8 +9328,8 @@ while true; do echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表 - 想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" - + echo -e "${gl_kjlan}第三方应用列表" + echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) From 6936941606234b7d3440ad9f419229a4e00a8e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 17:40:51 +0800 Subject: [PATCH 0501/1285] Simplify application listing output Removed app_name from output in the application listing. --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 227758be6..39defd0f6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9333,9 +9333,8 @@ while true; do for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) - local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" done echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" From 53e69cdccc2f69940dc48cb81ca77cd552eea93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 17:41:36 +0800 Subject: [PATCH 0502/1285] Simplify app listing output by removing app_name Remove app_name from output in app listing. --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 613fecc41..c14c64659 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9333,9 +9333,8 @@ while true; do for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) - local app_name=$(grep "app_name=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_name - $app_text" + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" done echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" From a40a00238ab3c0064f357199d20f9844d46bb257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 17:42:12 +0800 Subject: [PATCH 0503/1285] Delete apps/cd.conf --- apps/cd.conf | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 apps/cd.conf diff --git a/apps/cd.conf b/apps/cd.conf deleted file mode 100644 index 01b1f9b31..000000000 --- a/apps/cd.conf +++ /dev/null @@ -1,27 +0,0 @@ -local app_id="201" -local app_name="cloudreve网盘" -local app_text="cloudreve是一个支持多家云存储的网盘系统" -local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" -local docker_name="cloudreve" -local docker_port="8201" -local app_size="2" -docker_app_install() { - cd /home/ && mkdir -p docker/cloud && cd docker/cloud && mkdir temp_data && mkdir -vp cloudreve/{uploads,avatar} && touch cloudreve/conf.ini && touch cloudreve/cloudreve.db && mkdir -p aria2/config && mkdir -p data/aria2 && chmod -R 777 data/aria2 - curl -o /home/docker/cloud/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/cloudreve-docker-compose.yml - sed -i "s/5212:5212/${docker_port}:5212/g" /home/docker/cloud/docker-compose.yml - cd /home/docker/cloud/ - docker compose up -d - clear - echo "已经安装完成" - check_docker_app_ip -} -docker_app_update() { - cd /home/docker/cloud/ && docker compose down --rmi all - cd /home/docker/cloud/ && docker compose up -d -} -docker_app_uninstall() { - cd /home/docker/cloud/ && docker compose down --rmi all - rm -rf /home/docker/cloud - echo "应用已卸载" -} -docker_app_plus From 637d34d4d4ff4b739819cd42745851056dcfa356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 18:02:39 +0800 Subject: [PATCH 0504/1285] Refactor git installation and app management logic --- cn/kejilion.sh | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 39defd0f6..2755329d5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9237,9 +9237,16 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main +fi while true; do @@ -9337,8 +9344,6 @@ while true; do echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" done echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" - echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -13047,26 +13052,6 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - - s) - send_stats "搜索第三方应用" - cd ~ - install git - if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git - else - cd apps - git pull origin main - fi - ;; - - - d) - send_stats "删除第三方应用" - cd ~ - rm -rf $HOME/apps - ;; - 0) kejilion ;; From a35abb2a97c182a6ab8f019a3be94529f6903c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 18:03:52 +0800 Subject: [PATCH 0505/1285] Fix git clone command and add missing fi --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2755329d5..e3c2b2034 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9239,6 +9239,7 @@ linux_panel() { local sub_choice="$1" +clear cd ~ install git if [ ! -d apps/.git ]; then From b5ee4c977b0c7b3e22461bfa960d39148ca72cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 26 Dec 2025 18:05:04 +0800 Subject: [PATCH 0506/1285] Refactor linux_panel function for git operations --- kejilion.sh | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c14c64659..8f439bce5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9237,9 +9237,17 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +clear +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main +fi while true; do @@ -9337,8 +9345,6 @@ while true; do echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" done echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}s. ${gl_bai}搜索三方应用 ${gl_kjlan}d. ${gl_bai}删除三方应用" - echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" @@ -13047,26 +13053,6 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - - s) - send_stats "搜索第三方应用" - cd ~ - install git - if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git - else - cd apps - git pull origin main - fi - ;; - - - d) - send_stats "删除第三方应用" - cd ~ - rm -rf $HOME/apps - ;; - 0) kejilion ;; From 70704f176e0d668f4223d3d04afb0948290c9210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:28:34 +0800 Subject: [PATCH 0507/1285] Update kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e3c2b2034..cc30e0143 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9246,7 +9246,7 @@ if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps - git pull origin main + git pull origin main > /dev/null 2>&1 fi while true; do @@ -13063,7 +13063,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone https://github.com/kejilion/apps.git else cd apps - git pull origin main + git pull origin main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then From 680d033465edd132ef556319197fa35656949367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:29:19 +0800 Subject: [PATCH 0508/1285] Silence git pull output in kejilion.sh Suppress output of git pull command in kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8f439bce5..62f7ef5ab 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9246,7 +9246,7 @@ if [ ! -d apps/.git ]; then git clone https://github.com/kejilion/apps.git else cd apps - git pull origin main + git pull origin main > /dev/null 2>&1 fi while true; do @@ -13063,7 +13063,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone https://github.com/kejilion/apps.git else cd apps - git pull origin main + git pull origin main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then From 8163cf0e16a163f920bd867c11e728832eee4b64 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 28 Dec 2025 04:27:20 +0000 Subject: [PATCH 0509/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202025-12-28=2004:27:20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 202 +++++++++++++++++++++++--------- jp/kejilion.sh | 308 ++++++++++++++++++++++++++++++++----------------- kr/kejilion.sh | 284 ++++++++++++++++++++++++++++++--------------- tw/kejilion.sh | 132 +++++++++++++++++---- 4 files changed, 647 insertions(+), 279 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 916de7124..921dc0eb6 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# This function collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! +# A function that collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! # Why is this function designed? The purpose is to better understand the functions that users like to use, and to further optimize the functions and launch more functions that meet user needs. # The full text can be searched for the send_stats function call location. It is transparent and open source. If you have any concerns, you can refuse to use it. @@ -733,7 +733,7 @@ install_crontab() { return fi - echo -e "${gl_lv}crontab is installed and cron service is running.${gl_bai}" + echo -e "${gl_lv}crontab is installed and the cron service is running.${gl_bai}" } @@ -921,12 +921,12 @@ allow_ip() { # Add allow rule if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "Released IP$ip" + echo "IP released$ip" fi done save_iptables_rules - send_stats "Released IP" + send_stats "IP released" } block_ip() { @@ -2248,10 +2248,10 @@ web_security() { 22) send_stats "High load enables 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield. If the load is low, it will automatically close the shield for 5 seconds.${gl_bai}" + echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and obtain${gl_huang}Global API Key${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2676,7 +2676,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2695,7 +2695,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -4054,7 +4054,7 @@ add_forwarding_service() { send_stats "Add frp intranet service" # Prompts user for service name and forwarding information read -e -p "Please enter service name:" service_name - read -e -p "Please enter the forwarding type (tcp/udp) [Enter to default to tcp]:" service_type + read -e -p "Please enter the forwarding type (tcp/udp) [Press enter to default to tcp]:" service_type local service_type=${service_type:-tcp} read -e -p "Please enter the intranet IP [default is 127.0.0.1 when pressing Enter]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -4894,14 +4894,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "Initial username after reinstallation:${gl_huang}root${gl_bai}Initial password:${gl_huang}LeitboGi0ro${gl_bai}Initial port:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}After reinstallation, please change the initial password in time to prevent violent intrusion. Enter passwd on the command line to change the password.${gl_bai}" echo -e "Press any key to continue..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "Reinstall the system" echo "--------------------------------" echo -e "${gl_hong}Notice:${gl_bai}Reinstalling may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." - echo -e "${gl_hui}Thanks to boss leitbogioro and boss bin456789 for their script support!${gl_bai} " + echo -e "${gl_hui}Thanks to boss bin456789 and boss leitbogioro for their script support!${gl_bai} " + echo -e "${gl_hui}bin456789 project address: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro project address: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -6045,9 +6048,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6089,7 +6092,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6232,7 +6235,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6510,7 +6513,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6580,7 +6583,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6717,7 +6720,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -7342,7 +7345,7 @@ docker_ssh_migration() { mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # Volume mapping + # volume mapping local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done @@ -7734,7 +7737,7 @@ linux_docker() { case $sub_choice in 1) - send_stats "Create a new volume" + send_stats "Create new volume" read -e -p "Set new volume name:" dockerjuan docker volume create $dockerjuan @@ -9234,16 +9237,24 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +clear +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main > /dev/null 2>&1 +fi while true; do if [ -z "$sub_choice" ]; then clear echo -e "application market" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9261,69 +9272,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}ZenTao project management software${gl_kjlan}12. ${color12}Qinglong panel scheduled task management platform" echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" echo -e "${gl_kjlan}17. ${color17}AdGuardHome removes adware${gl_kjlan}18. ${color18}onlyofficeOnline office OFFICE" echo -e "${gl_kjlan}19. ${color19}Leichi WAF firewall panel${gl_kjlan}20. ${color20}portainer container management panel" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode web version${gl_kjlan}22. ${color22}UptimeKuma monitoring tool" echo -e "${gl_kjlan}23. ${color23}Memos web memo${gl_kjlan}24. ${color24}Webtop remote desktop web version${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud network disk${gl_kjlan}26. ${color26}QD-Today scheduled task management framework" echo -e "${gl_kjlan}27. ${color27}Dockge container stack management panel${gl_kjlan}28. ${color28}LibreSpeed ​​speed test tool" echo -e "${gl_kjlan}29. ${color29}searxng aggregated search station${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF Tools Collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI chat aggregation website" echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}Mouse management panel${gl_kjlan}42. ${color42}Nexterm remote connection tool" echo -e "${gl_kjlan}43. ${color43}RustDesk remote desktop (server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk remote desktop (relay)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub acceleration station${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}Prometheus monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" echo -e "${gl_kjlan}49. ${color49}Prometheus (container monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tools" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE open chick panel${gl_kjlan}52. ${color52}DPanel container management panel" echo -e "${gl_kjlan}53. ${color53}llama3 chat AI large model${gl_kjlan}54. ${color54}AMH host website building management panel" echo -e "${gl_kjlan}55. ${color55}FRP intranet penetration (server)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP intranet penetration (client)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek chat AI large model${gl_kjlan}58. ${color58}Dify large model knowledge base${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI large model asset management${gl_kjlan}60. ${color60}JumpServer open source bastion machine" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}Online translation server${gl_kjlan}62. ${color62}RAGFlow large model knowledge base" echo -e "${gl_kjlan}63. ${color63}OpenWebUI self-hosted AI platform${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools toolbox" echo -e "${gl_kjlan}65. ${color65}n8n automated workflow platform${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp video download tool" echo -e "${gl_kjlan}67. ${color67}ddns-go dynamic DNS management tool${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL certificate management platform" echo -e "${gl_kjlan}69. ${color69}SFTPGo file transfer tool${gl_kjlan}70. ${color70}AstrBot chatbot framework" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome private music server${gl_kjlan}72. ${color72}bitwarden password manager${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV Private Movies${gl_kjlan}74. ${color74}MoonTV private movies" echo -e "${gl_kjlan}75. ${color75}Melody music wizard${gl_kjlan}76. ${color76}Online DOS old games" echo -e "${gl_kjlan}77. ${color77}Thunder offline download tool${gl_kjlan}78. ${color78}PandaWiki intelligent document management system" echo -e "${gl_kjlan}79. ${color79}Beszel server monitoring${gl_kjlan}80. ${color80}linkwarden bookmark management" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet video conference${gl_kjlan}82. ${color82}gpt-load high-performance AI transparent proxy" echo -e "${gl_kjlan}83. ${color83}komari server monitoring tool${gl_kjlan}84. ${color84}Wallos personal financial management tool" echo -e "${gl_kjlan}85. ${color85}immich picture video manager${gl_kjlan}86. ${color86}jellyfin media management system" echo -e "${gl_kjlan}87. ${color87}SyncTV is a great tool for watching movies together${gl_kjlan}88. ${color88}Owncast self-hosted live streaming platform" echo -e "${gl_kjlan}89. ${color89}FileCodeBox file express${gl_kjlan}90. ${color90}matrix decentralized chat protocol" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea private code repository${gl_kjlan}92. ${color92}FileBrowser file manager" echo -e "${gl_kjlan}93. ${color93}Dufs minimalist static file server${gl_kjlan}94. ${color94}Gopeed high-speed download tool" echo -e "${gl_kjlan}95. ${color95}paperless document management platform${gl_kjlan}96. ${color96}2FAuth self-hosted two-step authenticator" echo -e "${gl_kjlan}97. ${color97}WireGuard networking (server)${gl_kjlan}98. ${color98}WireGuard networking (client)" echo -e "${gl_kjlan}99. ${color99}DSM Synology Virtual Machine${gl_kjlan}100. ${color100}Syncthing peer-to-peer file synchronization tool" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI video generation tool${gl_kjlan}102. ${color102}VoceChat multi-person online chat system" echo -e "${gl_kjlan}103. ${color103}Umami website statistics tool${gl_kjlan}104. ${color104}Stream four-layer proxy forwarding tool" echo -e "${gl_kjlan}105. ${color105}Siyuan Notes${gl_kjlan}106. ${color106}Drawnix open source whiteboard tool" echo -e "${gl_kjlan}107. ${color107}PanSou network disk search${gl_kjlan}108. ${color108}LangBot chatbot" echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" - echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool${gl_kjlan}112. ${color112}Lucky large intranet penetration tool" + echo -e "${gl_kjlan}113. ${color113}Firefox browser" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}Third-party application list" + echo -e "${gl_kjlan}Want your app to appear here? Check out the developer guide:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" @@ -9935,7 +9956,7 @@ while true; do } - local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -11312,7 +11333,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -11368,7 +11389,7 @@ while true; do } - local docker_describe="A password manager that puts you in control of your data" + local docker_describe="A password manager where you can control your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11546,7 +11567,7 @@ while true; do local docker_describe="Xunlei, your offline high-speed BT magnetic download tool" local docker_url="Official website introduction: https://github.com/cnk3x/xunlei" - local docker_use="echo \"Log in to Xunlei with your mobile phone, and then enter the invitation code. Invitation code: Xunlei Niutong\"" + local docker_use="echo \"Log in to Xunlei with your mobile phone and enter the invitation code. Invitation code: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -12471,7 +12492,7 @@ while true; do local app_id="99" - local app_name="dsm Synology virtual machine" + local app_name="dsm synology virtual machine" local app_text="Virtual DSM in Docker container" local app_url="Official website: https://github.com/vdsm/virtual-dsm" local docker_name="dsm" @@ -12556,7 +12577,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." local app_url="Official website: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12899,7 +12920,66 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # Since Lucky uses the host network mode, the port here is only for record/explanation reference, and is actually controlled by the application itself (default 16601) + local docker_port=8112 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + echo "Waiting for Lucky to initialize..." + sleep 10 + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} + + } + + local docker_describe="Lucky is a large intranet penetration and port forwarding management tool that supports DDNS, reverse proxy, WOL and other functions." + local docker_url="Project address: https://github.com/gdy666/lucky" + local docker_use="echo \"Default account password: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "Set login password:" admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through web pages." + local docker_url="Project address: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) @@ -12973,11 +13053,24 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 0) kejilion ;; *) + cd ~ + install git + if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git + else + cd apps + git pull origin main > /dev/null 2>&1 + fi + local custom_app="$HOME/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}Error: Not found with number${sub_choice}application configuration${gl_bai}" + fi ;; esac break_end @@ -12987,6 +13080,7 @@ done } + linux_work() { while true; do @@ -13010,7 +13104,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" @@ -13282,7 +13376,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority to ipv4/ipv6" + echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" echo -e "${gl_kjlan}13. ${gl_bai}User management${gl_kjlan}14. ${gl_bai}User/password generator" @@ -13744,7 +13838,7 @@ EOF send_stats "Change time zone" while true; do clear - echo "System time information" + echo "系统时间信息" # Get the current system time zone local timezone=$(current_timezone) @@ -13774,7 +13868,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil time 26. Argentina time" + echo "25. Brazil Time 26. Argentina Time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -14032,7 +14126,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -14283,7 +14377,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14292,7 +14386,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "One-stop tuning starts" + send_stats "One-stop tuning started" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14332,7 +14426,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14845,7 +14939,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15372,5 +15466,3 @@ else ;; esac fi - - diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 06129920e..7b233ad85 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -57,9 +57,9 @@ CheckFirstRun_true() { -# この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! +# 関数の埋もれた情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、ユーザーが使用した関数名を記録する機能。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストール中$package...${gl_bai}" + echo -e "${gl_huang}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -797,7 +797,7 @@ docker_ipv6_off() { # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}現在IPv6アクセスは停止中です${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在停止中です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -863,7 +863,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -921,12 +921,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "IP公開$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "IP公開" } block_ip() { @@ -1186,7 +1186,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1543,12 +1543,12 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" - echo -e "6. 国内の登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかどうかを確認してください" + echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" echo "------------------------" echo "1. 再度適用します。 2. 既存の証明書をインポートします。 3. 証明書なしで HTTP アクセスを使用します。 0. 終了します。" echo "------------------------" @@ -1760,7 +1760,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2248,9 +2248,9 @@ web_security() { 22) send_stats "高負荷により5秒シールドが可能" - echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検知すると自動的にシールドが開きます。負荷が低い場合は、シールドが 5 秒間自動的に閉じます。${gl_bai}" + echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2365,7 +2365,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2575,7 +2575,7 @@ check_docker_image_update() { # 公式画像のサポートを追加 [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Docker Hub APIからイメージのリリース時間を取得する + # Docker Hub APIからイメージのリリース時刻を取得する local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) @@ -2623,7 +2623,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2640,7 +2640,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2681,7 +2681,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2700,7 +2700,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3008,7 +3008,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3639,7 +3639,7 @@ ldnmp_Proxy_backend_stream() { echo "名前を空にすることはできません"; return 1 fi - # リスニングポートを取得する + # リスニングポートの取得 read -rp "ローカルのリスニング ポート (3306 など) を入力してください。" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "ポートは数値である必要があります"; return 1 @@ -3768,7 +3768,7 @@ ldnmp_web_status() { echo "" echo "操作する" echo "------------------------" - echo "1. ドメイン名証明書の適用/更新 2. サイトドメイン名の複製" + echo "1. ドメイン名証明書の適用/更新 2. サイトのドメイン名の複製" echo "3. サイトのキャッシュをクリアします。 4. 関連するサイトを作成します。" echo "5. アクセスログの表示 6. エラーログの表示" echo "7. グローバル構成の編集 8. サイト構成の編集" @@ -3832,7 +3832,7 @@ ldnmp_web_status() { ;; 4) send_stats "関連サイトの作成" - echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスします" + echo -e "新しいドメイン名を既存のサイトに関連付けてアクセスする" read -e -p "既存のドメイン名を入力してください:" oddyuming read -e -p "新しいドメイン名を入力してください:" yuming install_certbot @@ -4054,9 +4054,9 @@ add_forwarding_service() { send_stats "FRPイントラネットサービスを追加" # ユーザーにサービス名と転送情報の入力を求めるプロンプトを表示します read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type + read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp にするには Enter キーを押してください]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -4098,7 +4098,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーの印刷 + # ヘッダーを印刷します printf "%-20s %-25s %-30s %-10s\n" "サービス名" "イントラネットアドレス" "外部ネットワークアドレス" "プロトコル" awk ' @@ -4733,7 +4733,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4894,14 +4894,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion } @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "再インストール後の初期ユーザー名:${gl_huang}root${gl_bai}初期パスワード:${gl_huang}LeitboGi0ro${gl_bai}初期ポート:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}再インストール後は、暴力的な侵入を防ぐため、初期パスワードを適時に変更してください。パスワードを変更するには、コマンドラインに passwd と入力します。${gl_bai}" echo -e "続行するには任意のキーを押してください..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "システムを再インストールする" echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" - echo -e "${gl_hui}スクリプトをサポートしてくれたボス leitbogioro とボス bin456789 に感謝します。${gl_bai} " + echo -e "${gl_hui}スクリプトをサポートしてくれたボス bin456789 とボス leitbogioro に感謝します。${gl_bai} " + echo -e "${gl_hui}bin456789 プロジェクトのアドレス: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro プロジェクトのアドレス: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5113,7 +5116,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5447,7 +5450,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5495,7 +5498,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6045,9 +6048,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6089,7 +6092,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6177,7 +6180,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6377,9 +6380,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントする +# パーティションのマウント mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6398,7 +6401,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6510,7 +6513,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6529,7 +6532,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "Enter を押して続行します..." done } @@ -6558,7 +6561,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -6717,7 +6720,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモート ホストにアクセスできますか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6726,7 +6729,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6816,7 +6819,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "Enter を押して続行します..." done } @@ -6875,7 +6878,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7004,7 +7007,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7308,7 +7311,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7475,7 +7478,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7581,7 +7584,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8938,10 +8941,10 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境のバックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9234,16 +9237,24 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +clear +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main > /dev/null 2>&1 +fi while true; do if [ -z "$sub_choice" ]; then clear echo -e "アプリケーション市場" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9261,69 +9272,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}ZenTao プロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglong パネルのスケジュールされたタスク管理プラットフォーム" echo -e "${gl_kjlan}13. ${color13}Cloudreve ネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルなピクチャーベッド画像管理プログラム" echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}Speedtest スピードテストパネル" echo -e "${gl_kjlan}17. ${color17}AdGuardHome はアドウェアを削除します${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}ポーターコンテナ管理パネル" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode Web バージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" echo -e "${gl_kjlan}23. ${color23}メモウェブメモ${gl_kjlan}24. ${color24}Webtop リモート デスクトップ Web バージョン${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud ネットワーク ディスク${gl_kjlan}26. ${color26}QD-Today スケジュールされたタスク管理フレームワーク" echo -e "${gl_kjlan}27. ${color27}Dockge コンテナ スタック管理パネル${gl_kjlan}28. ${color28}LibreSpeed 速度テストツール" echo -e "${gl_kjlan}29. ${color29}searxng 集約検索ステーション${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrismプライベートアルバムシステム" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF ツール コレクション${gl_kjlan}32. ${color32}無料のオンライングラフ作成ソフトウェアdrawio${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel ナビゲーション パネル${gl_kjlan}34. ${color34}Pingvin-Share ファイル共有プラットフォーム" echo -e "${gl_kjlan}35. ${color35}ミニマリストの友達の輪${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nexterm リモート接続ツール" echo -e "${gl_kjlan}43. ${color43}RustDesk リモート デスクトップ (サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker アクセラレーション ステーション${gl_kjlan}46. ${color46}GitHub アクセラレーション ステーション${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}プロメテウスの監視${gl_kjlan}48. ${color48}Prometheus (ホスト監視)" echo -e "${gl_kjlan}49. ${color49}Prometheus (コンテナ監視)${gl_kjlan}50. ${color50}補充監視ツール" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" echo -e "${gl_kjlan}75. ${color75}メロディー音楽の魔法使い${gl_kjlan}76. ${color76}オンライン DOS 古いゲーム" echo -e "${gl_kjlan}77. ${color77}Thunder オフライン ダウンロード ツール${gl_kjlan}78. ${color78}PandaWiki インテリジェント文書管理システム" echo -e "${gl_kjlan}79. ${color79}Beszel サーバーの監視${gl_kjlan}80. ${color80}リンクワーデンのブックマーク管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea プライベート コード リポジトリ${gl_kjlan}92. ${color92}FileBrowser ファイルマネージャー" echo -e "${gl_kjlan}93. ${color93}Dufs のミニマリスト静的ファイル サーバー${gl_kjlan}94. ${color94}Gopeed高速ダウンロードツール" echo -e "${gl_kjlan}95. ${color95}ペーパーレス文書管理プラットフォーム${gl_kjlan}96. ${color96}2FAuth セルフホスト型 2 段階認証システム" echo -e "${gl_kjlan}97. ${color97}WireGuard ネットワーキング (サーバー)${gl_kjlan}98. ${color98}WireGuard ネットワーキング (クライアント)" echo -e "${gl_kjlan}99. ${color99}DSM Synology 仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" - echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール${gl_kjlan}112. ${color112}Lucky 大規模イントラネット侵入ツール" + echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" + echo -e "${gl_kjlan}あなたのアプリをここに表示したいですか?開発者ガイドを確認してください。${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" @@ -9935,7 +9956,7 @@ while true; do } - local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -11099,8 +11120,8 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" - local app_url="公式サイト:https://github.com/infiniflow/ragflow" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_url="公式ウェブサイト:https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11312,7 +11333,7 @@ while true; do } - local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" + local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -11368,7 +11389,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11546,7 +11567,7 @@ while true; do local docker_describe="Xunlei、オフライン高速 BT 磁気ダウンロード ツール" local docker_url="公式サイト紹介:https://github.com/cnk3x/xunlei" - local docker_use="echo \"携帯電話で Xunlei にログインし、招待コードを入力します。招待コード: Xunlei Niutong\"" + local docker_use="echo \"携帯電話で Xunlei にログインし、招待コードを入力してください。招待コード: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -11616,7 +11637,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -11831,7 +11852,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:https://github.com/immich-app/immich" local docker_name="immich_server" @@ -11955,7 +11976,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -12471,7 +12492,7 @@ while true; do local app_id="99" - local app_name="dsm Synology 仮想マシン" + local app_name="DSM Synology 仮想マシン" local app_text="Dockerコンテナ内の仮想DSM" local app_url="公式ウェブサイト:https://github.com/vdsm/virtual-dsm" local docker_name="dsm" @@ -12556,7 +12577,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" local app_url="公式ウェブサイト:https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12889,7 +12910,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -12899,7 +12920,66 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # Lucky はホスト ネットワーク モードを使用するため、ここでのポートは記録と説明の参照のみを目的としており、実際にはアプリケーション自体によって制御されます (デフォルトは 16601)。 + local docker_port=8112 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + echo "Lucky が初期化されるのを待っています..." + sleep 10 + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} + + } + + local docker_describe="Lucky は、DDNS、リバース プロキシ、WOL、その他の機能をサポートする大規模なイントラネット ペネトレーションおよびポート フォワーディング管理ツールです。" + local docker_url="プロジェクトアドレス: https://github.com/gdy666/lucky" + local docker_use="echo \"デフォルトのアカウントパスワード: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "ログインパスワードを設定します:" admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="これは、Web ページを介したデスクトップ ブラウザ インターフェイスへの直接アクセスをサポートする、Docker で実行される Firefox ブラウザです。" + local docker_url="プロジェクトアドレス: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) @@ -12973,11 +13053,24 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 0) kejilion ;; *) + cd ~ + install git + if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git + else + cd apps + git pull origin main > /dev/null 2>&1 + fi + local custom_app="$HOME/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}エラー: 番号が見つかりません${sub_choice}アプリケーション構成${gl_bai}" + fi ;; esac break_end @@ -12987,6 +13080,7 @@ done } + linux_work() { while true; do @@ -12995,7 +13089,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13010,7 +13104,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo.10" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" @@ -13140,7 +13234,7 @@ linux_work() { 23) - read -e -p "バックグラウンドで実行するコマンドを入力してください (例:curl -fsSL https://get.docker.com | )し:" tmuxd + read -e -p "バックグラウンドで実行するコマンドを入力してください。たとえば、curl -fsSL https://get.docker.com |し:" tmuxd tmux_run_d send_stats "バックグラウンドワークスペースにコマンドを挿入する" ;; @@ -13280,9 +13374,9 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}優先順位をipv4/ipv6に切り替える" + echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}ポートの占有状況を確認する${gl_kjlan}12. ${gl_bai}仮想メモリのサイズを変更する" echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワード生成器" @@ -14032,7 +14126,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -14274,7 +14368,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14292,7 +14386,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングが始まります" + send_stats "ワンストップチューニングスタート" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14567,7 +14661,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14587,7 +14681,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14726,7 +14820,7 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14830,7 +14924,7 @@ echo "------------------------" echo -e "${gl_lan}Laika Cloud 香港 CN2 GIA 韓国のデュアル ISP 米国 CN2 GIA プロモーション${gl_bai}" echo -e "${gl_bai}ウェブサイト: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" -echo -e "${gl_lan}RackNerd 年間 10.99 ドル、米国、1 コア、1G メモリ、20G ハード ドライブ、月あたり 1T トラフィック${gl_bai}" +echo -e "${gl_lan}RackNerd 年間 10.99 ドル、米国、1 コア、1G メモリ、20G ハードドライブ、月あたり 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 年間 $52.7 米国 1 コア 4G メモリ 50G ハードドライブ 月額 4T トラフィック${gl_bai}" @@ -14842,10 +14936,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -14960,7 +15054,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" + echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -15090,8 +15184,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -15100,7 +15194,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -15119,9 +15213,9 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" -echo "L4 ロード バランシングのインストール k ストリーム |k L4 ロード バランシング" +echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" @@ -15220,7 +15314,7 @@ else swap) shift - send_stats "仮想メモリをすばやくセットアップする" + send_stats "仮想メモリを素早く設定する" add_swap "$@" ;; @@ -15319,7 +15413,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) @@ -15372,5 +15466,3 @@ else ;; esac fi - - diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 3801168a4..93e99c13b 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! +# 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기기 국가 및 기능 이름을 기록하는 기능입니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. # send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -921,12 +921,12 @@ allow_ip() { # 허용 규칙 추가 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "공개된 IP$ip" + echo "IP 공개$ip" fi done save_iptables_rules - send_stats "공개된 IP" + send_stats "IP 공개" } block_ip() { @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1259,7 +1259,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1313,7 +1313,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 교체 + # docker-compose.yml 파일에서 바꾸기 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1545,7 +1545,7 @@ certs_status() { echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인하세요." - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." @@ -2134,7 +2134,7 @@ web_security() { echo "------------------------" echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" echo "------------------------" - echo "21. cloudflare 모드 22. 고부하에서 5초 보호 활성화" + echo "21. cloudflare 모드 22. 고부하에서 5초 쉴드 활성화" echo "------------------------" echo "31. WAF 켜기 32. WAF 끄기" echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" @@ -2248,7 +2248,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 실드가 열립니다. 부하가 낮으면 자동으로 5초 동안 쉴드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2514,7 +2514,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2676,7 +2676,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2695,7 +2695,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2792,7 +2792,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2808,7 +2808,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3325,7 +3325,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3338,7 +3338,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3412,7 +3412,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3676,7 +3676,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4054,7 +4054,7 @@ add_forwarding_service() { send_stats "FRP 인트라넷 서비스 추가" # 사용자에게 서비스 이름 및 전달 정보를 묻는 메시지를 표시합니다. read -e -p "서비스 이름을 입력하세요:" service_name - read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type + read -e -p "전달 유형(tcp/udp)을 입력하십시오. [tcp를 기본값으로 설정하려면 Enter를 누르십시오]:" service_type local service_type=${service_type:-tcp} read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}재설치 후에는 초기 비밀번호를 적시에 변경하여 폭력적인 침입을 방지하시기 바랍니다. 비밀번호를 변경하려면 명령줄에 passwd를 입력하세요.${gl_bai}" echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "시스템 재설치" echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." - echo -e "${gl_hui}스크립트를 지원해주신 leitbogioro 보스와 bin456789 보스에게 감사드립니다!${gl_bai} " + echo -e "${gl_hui}스크립트 지원을 해주신 bin456789 보스와 leitbogioro 보스에게 감사드립니다!${gl_bai} " + echo -e "${gl_hui}bin456789 프로젝트 주소: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro 프로젝트 주소: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5276,7 +5279,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5286,7 +5289,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5303,7 +5306,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5340,7 +5343,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5429,7 +5432,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5447,7 +5450,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5483,7 +5486,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -5989,7 +5992,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6225,14 +6228,14 @@ add_connection() { echo # 换行 ;; 2) - echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6510,7 +6513,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6573,14 +6576,14 @@ add_task() { auth_method="password" ;; 2) - echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -6717,7 +6720,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -7266,7 +7269,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7308,7 +7311,7 @@ docker_ssh_migration() { # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 건너뛰세요...${NC}" continue fi @@ -7421,7 +7424,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리용기:$container${NC}" + echo -e "${GREEN}처리 용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7495,7 +7498,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -7694,7 +7697,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8055,7 +8058,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8440,7 +8443,7 @@ linux_ldnmp() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "" - echo "레디스 주소 : 레디스" + echo "레디스 주소: 레디스" echo "redis 비밀번호: 기본적으로 입력되지 않음" echo "레디스 포트: 6379" echo "" @@ -8450,7 +8453,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8779,7 +8782,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf @@ -9234,16 +9237,24 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +clear +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main > /dev/null 2>&1 +fi while true; do if [ -z "$sub_choice" ]; then clear echo -e "응용 시장" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9261,69 +9272,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 예정된 작업 관리 플랫폼" echo -e "${gl_kjlan}13. ${color13}Cloudreve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}Speedtest 속도 테스트 패널" echo -e "${gl_kjlan}17. ${color17}AdGuardHome은 애드웨어를 제거합니다${gl_kjlan}18. ${color18}onlyoffice온라인 오피스 OFFICE" echo -e "${gl_kjlan}19. ${color19}Leichi WAF 방화벽 패널${gl_kjlan}20. ${color20}포테이너 컨테이너 관리 패널" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatAI 채팅 집계 웹사이트" echo -e "${gl_kjlan}37. ${color37}MyIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist 가족 버킷" echo -e "${gl_kjlan}39. ${color39}Bililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexterm 원격 연결 도구" echo -e "${gl_kjlan}43. ${color43}RustDesk 원격 데스크톱(서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}GitHub 가속 스테이션${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로메테우스(호스트 모니터링)" echo -e "${gl_kjlan}49. ${color49}프로메테우스(컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPanel 컨테이너 관리 패널" echo -e "${gl_kjlan}53. ${color53}라마3 채팅 AI 대형 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투(클라이언트)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek 채팅 AI 대형 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 대형 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" echo -e "${gl_kjlan}63. ${color63}OpenWebUI 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" echo -e "${gl_kjlan}65. ${color65}n8n 자동화된 워크플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp 비디오 다운로드 도구" echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" echo -e "${gl_kjlan}79. ${color79}베젤 서버 모니터링${gl_kjlan}80. ${color80}링크워든 북마크 관리" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}gpt-load 고성능 AI 투명 프록시" echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea 비공개 코드 저장소${gl_kjlan}92. ${color92}FileBrowser 파일 관리자" echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}Gopeed 고속 다운로드 도구" echo -e "${gl_kjlan}95. ${color95}종이 없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAuth 자체 호스팅 2단계 인증자" echo -e "${gl_kjlan}97. ${color97}WireGuard 네트워킹(서버)${gl_kjlan}98. ${color98}WireGuard 네트워킹(클라이언트)" echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}P2P 파일 동기화 도구 동기화" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" - echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}타사 애플리케이션 목록" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" @@ -9515,7 +9536,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9524,7 +9545,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9935,7 +9956,7 @@ while true; do } - local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -10370,7 +10391,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10546,7 +10567,7 @@ while true; do } - local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹음 도구입니다." + local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹화 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" @@ -10874,7 +10895,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -11312,7 +11333,7 @@ while true; do } - local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -11368,7 +11389,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11546,7 +11567,7 @@ while true; do local docker_describe="오프라인 고속 BT 자기 다운로드 도구인 Xunlei" local docker_url="공식 홈페이지 소개: https://github.com/cnk3x/xunlei" - local docker_use="echo \"휴대폰으로 Xunlei에 로그인한 후 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" + local docker_use="echo \"휴대폰으로 Xunlei에 로그인하고 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -11927,7 +11948,7 @@ while true; do local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 홈페이지 소개: https://github.com/synctv-org/synctv" - local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 적시에 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -11984,7 +12005,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 홈페이지 소개: https://github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -12057,7 +12078,7 @@ while true; do local app_name="gitea 비공개 코드 저장소" local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." - local app_url="영상 소개: https://github.com/go-gitea/gitea" + local app_url="영상소개 : https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12241,7 +12262,7 @@ while true; do local app_id="96" local app_name="2FAuth 자체 호스팅 2단계 인증자" - local app_text="자체 호스팅 2단계 인증(2FA) 계정 관리 및 확인 코드 생성 도구입니다." + local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." local app_url="공식 홈페이지: https://github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" @@ -12471,7 +12492,7 @@ while true; do local app_id="99" - local app_name="dsm Synology 가상 머신" + local app_name="dsm 시놀로지 가상 머신" local app_text="Docker 컨테이너의 가상 DSM" local app_url="공식 웹사이트: https://github.com/vdsm/virtual-dsm" local docker_name="dsm" @@ -12556,7 +12577,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12899,7 +12920,66 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + local docker_port=8112 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + echo "Lucky가 초기화되기를 기다리는 중..." + sleep 10 + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} + + } + + local docker_describe="Lucky는 DDNS, 역방향 프록시, WOL 및 기타 기능을 지원하는 대규모 인트라넷 침투 및 포트 전달 관리 도구입니다." + local docker_url="프로젝트 주소: https://github.com/gdy666/lucky" + local docker_use="echo \"기본 계정 비밀번호: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "로그인 비밀번호 설정:" admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="웹 페이지를 통해 데스크톱 브라우저 인터페이스에 대한 직접 액세스를 지원하는 Docker에서 실행되는 Firefox 브라우저입니다." + local docker_url="프로젝트 주소: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) @@ -12973,11 +13053,24 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 0) kejilion ;; *) + cd ~ + install git + if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git + else + cd apps + git pull origin main > /dev/null 2>&1 + fi + local custom_app="$HOME/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}오류: 번호가 없습니다.${sub_choice}애플리케이션 구성${gl_bai}" + fi ;; esac break_end @@ -12987,6 +13080,7 @@ done } + linux_work() { while true; do @@ -13010,7 +13104,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10호" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" @@ -13279,10 +13373,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위를 ipv4/ipv6으로 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -13292,7 +13386,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13346,7 +13440,7 @@ linux_Settings() { echo "파이썬 버전 관리" echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" + echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13579,7 +13673,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -14032,7 +14126,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}전류 제한 종료 기능은 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -14053,7 +14147,7 @@ EOF rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일에 재설정됨)." cz_day + read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일 재설정)." cz_day cz_day=${cz_day:-1} cd ~ @@ -14138,7 +14232,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -14292,7 +14386,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "원스톱 튜닝 시작" + send_stats "원스톱 튜닝이 시작되었습니다" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14842,10 +14936,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 Tokyo Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15089,7 +15183,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -15118,17 +15212,17 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" @@ -15372,5 +15466,3 @@ else ;; esac fi - - diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 116a47b13..fee310e9d 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.2.10" +sh_v="4.3.0" gl_hui='\e[37m' @@ -4919,6 +4919,7 @@ dd_xitong() { dd_xitong_1() { echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始端口:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}重裝後請及時修改初始密碼,防止暴力入侵。命令行輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -4952,7 +4953,9 @@ dd_xitong() { echo "重裝系統" echo "--------------------------------" echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" - echo -e "${gl_hui}感謝leitbogioro大佬和bin456789大佬的腳本支持!${gl_bai} " + echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " + echo -e "${gl_hui}bin456789項目地址: https://github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro項目地址: https://github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -9234,16 +9237,24 @@ linux_ldnmp() { linux_panel() { - local sub_choice="$1" +clear +cd ~ +install git +if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git +else + cd apps + git pull origin main > /dev/null 2>&1 +fi while true; do if [ -z "$sub_choice" ]; then clear echo -e "應用市場" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") @@ -9261,69 +9272,79 @@ while true; do echo -e "${gl_kjlan}5. ${color5}OpenList多存儲文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠程桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" echo -e "${gl_kjlan}9. ${color9}Poste.io郵件服務器程序${gl_kjlan}10. ${color10}RocketChat多人在線聊天系統" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道項目管理軟件${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速面板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟件${gl_kjlan}18. ${color18}onlyoffice在線辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網盤${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆棧管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相冊系統" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄製工具${gl_kjlan}40. ${color40}webssh網頁版SSH連接工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠程連接工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}在線翻譯服務器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp視頻下載工具" echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL證書管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo文件傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂服務器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}在線DOS老遊戲" echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台${gl_kjlan}96. ${color96}2FAuth自託管二步驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" - echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件轉換工具" - echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}111. ${color111}多格式文件轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" + echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器" + echo -e "${gl_kjlan}-------------------------" + echo -e "${gl_kjlan}第三方應用列表" + echo -e "${gl_kjlan}想要讓你的應用出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do + [ -e "$f" ] || continue + local base_name=$(basename "$f" .conf) + local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + done + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" @@ -12899,7 +12920,66 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 112|lucky) + local app_id="112" + local docker_name="lucky" + local docker_img="gdy666/lucky:v2" + # 由於 Lucky 使用 host 網絡模式,這裡的端口僅作記錄/說明參考,實際由應用自身控制(默認16601) + local docker_port=8112 + + docker_rum() { + + docker run -d --name=${docker_name} --restart=always \ + --network host \ + -v /home/docker/lucky/conf:/app/conf \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${docker_img} + + echo "正在等待 Lucky 初始化..." + sleep 10 + docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} + + } + + local docker_describe="Lucky 是一個大內網穿透及端口轉發管理工具,支持 DDNS、反向代理、WOL 等功能。" + local docker_url="項目地址: https://github.com/gdy666/lucky" + local docker_use="echo \"默認賬號密碼: 666\"" + local docker_passwd="" + local app_size="1" + docker_app + + ;; + + + 113|firefox) + + local app_id="113" + local docker_name="firefox" + local docker_img="jlesage/firefox:latest" + local docker_port=8113 + + docker_rum() { + + read -e -p "設置登錄密碼:" admin_password + + docker run -d --name=${docker_name} --restart=always \ + -p ${docker_port}:5800 \ + -v /home/docker/firefox:/config:rw \ + -e ENABLE_CJK_FONT=1 \ + -e WEB_AUDIO=1 \ + -e VNC_PASSWORD="${admin_password}" \ + ${docker_img} + } + + local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支持通過網頁直接訪問桌面版瀏覽器界面。" + local docker_url="項目地址: https://github.com/jlesage/docker-firefox" + local docker_use="" + local docker_passwd="" + local app_size="1" + docker_app + + ;; b) @@ -12973,11 +13053,24 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 0) kejilion ;; *) + cd ~ + install git + if [ ! -d apps/.git ]; then + git clone https://github.com/kejilion/apps.git + else + cd apps + git pull origin main > /dev/null 2>&1 + fi + local custom_app="$HOME/apps/${sub_choice}.conf" + if [ -f "$custom_app" ]; then + . "$custom_app" + else + echo -e "${gl_hong}錯誤: 未找到編號為${sub_choice}的應用配置${gl_bai}" + fi ;; esac break_end @@ -12987,6 +13080,7 @@ done } + linux_work() { while true; do @@ -15372,5 +15466,3 @@ else ;; esac fi - - From 5dce492311f602b117c67ba7dbf87d0212b7e808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Dec 2025 17:44:46 +0800 Subject: [PATCH 0510/1285] Update git clone URLs to use gh_proxy --- cn/kejilion.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cc30e0143..1ae4148b2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -10967,7 +10967,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11011,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11128,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12585,7 +12585,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12652,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12795,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12865,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -13060,7 +13060,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 From 33e38e63da76a1335eeb7af6376147a3d3bc4b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 28 Dec 2025 17:45:16 +0800 Subject: [PATCH 0511/1285] Replace direct GitHub URLs with gh_proxy variable --- kejilion.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 62f7ef5ab..cfb9bf128 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -10967,7 +10967,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11011,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11128,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12585,7 +12585,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12652,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12795,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12865,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -13060,7 +13060,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 From 104219a842d6ab494d9281577f42caa9cb861dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:03:59 +0800 Subject: [PATCH 0512/1285] Enhance application listing with installation status --- kejilion.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index cfb9bf128..1deb190a0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # 获取应用描述 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # 检查安装状态 (匹配 appno.txt 中的 ID) + # 这里假设 appno.txt 中记录的是 base_name (即文件名) + if echo "$app_numbers" | grep -q "^$base_name$"; then + # 如果已安装:显示 base_name - 描述 [已安装] (绿色) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" + else + # 如果未安装:正常显示 + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" From 856ac9c906ea2410a40f948bd3e68a9087359385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:06:35 +0800 Subject: [PATCH 0513/1285] Enhance application listing with installation status --- cn/kejilion.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1ae4148b2..ca6d12873 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # 获取应用描述 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # 检查安装状态 (匹配 appno.txt 中的 ID) + # 这里假设 appno.txt 中记录的是 base_name (即文件名) + if echo "$app_numbers" | grep -q "^$base_name$"; then + # 如果已安装:显示 base_name - 描述 [已安装] (绿色) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" + else + # 如果未安装:正常显示 + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" From 8fafecc266a5675680c7b21a0fa2f53d66e60510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 31 Dec 2025 16:07:52 +0800 Subject: [PATCH 0514/1285] Update upgrade_openssh9.8p1.sh --- upgrade_openssh9.8p1.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/upgrade_openssh9.8p1.sh b/upgrade_openssh9.8p1.sh index 78b5d7138..f56dc3d5a 100644 --- a/upgrade_openssh9.8p1.sh +++ b/upgrade_openssh9.8p1.sh @@ -70,6 +70,8 @@ install_openssh() { # 重启SSH服务 restart_ssh() { + mv /usr/bin/ssh /usr/bin/ssh.bak + ln -s /usr/local/bin/ssh /usr/bin/ssh case $OS in ubuntu|debian) systemctl restart ssh From 8fe0bb743842d1e2ae5a286cc6f04cb7cc10f610 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 4 Jan 2026 04:27:44 +0000 Subject: [PATCH 0515/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-01-04=2004:27:44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 92 +++++++++++++++++------------- jp/kejilion.sh | 112 ++++++++++++++++++++---------------- kr/kejilion.sh | 150 +++++++++++++++++++++++++++---------------------- tw/kejilion.sh | 34 +++++++---- 4 files changed, 222 insertions(+), 166 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 921dc0eb6..73a923fc4 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# A function that collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! +# This function collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! # Why is this function designed? The purpose is to better understand the functions that users like to use, and to further optimize the functions and launch more functions that meet user needs. # The full text can be searched for the send_stats function call location. It is transparent and open source. If you have any concerns, you can refuse to use it. @@ -733,7 +733,7 @@ install_crontab() { return fi - echo -e "${gl_lv}crontab is installed and the cron service is running.${gl_bai}" + echo -e "${gl_lv}crontab is installed and cron service is running.${gl_bai}" } @@ -921,12 +921,12 @@ allow_ip() { # Add allow rule if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP released$ip" + echo "Released IP$ip" fi done save_iptables_rules - send_stats "IP released" + send_stats "Released IP" } block_ip() { @@ -3505,7 +3505,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4054,7 +4054,7 @@ add_forwarding_service() { send_stats "Add frp intranet service" # Prompts user for service name and forwarding information read -e -p "Please enter service name:" service_name - read -e -p "Please enter the forwarding type (tcp/udp) [Press enter to default to tcp]:" service_type + read -e -p "Please enter the forwarding type (tcp/udp) [Enter to default to tcp]:" service_type local service_type=${service_type:-tcp} read -e -p "Please enter the intranet IP [default is 127.0.0.1 when pressing Enter]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -4851,7 +4851,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" } @@ -4894,7 +4894,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" } @@ -5172,7 +5172,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5563,7 +5563,7 @@ clamav() { ;; 3) send_stats "Custom directory scan" - read -e -p "Please enter the directories to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories + read -e -p "Please enter the directories to be scanned, separated by spaces (for example: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6048,9 +6048,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6092,7 +6092,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6720,7 +6720,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}Third-party application list" echo -e "${gl_kjlan}Want your app to appear here? Check out the developer guide:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # Get app description local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # Check installation status (match ID in appno.txt) + # It is assumed here that what is recorded in appno.txt is base_name (i.e. file name) + if echo "$app_numbers" | grep -q "^$base_name$"; then + # If installed: show base_name - description [Installed] (green) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[Installed]${gl_bai}" + else + # If not installed: display normally + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}Back up all application data${gl_kjlan}r. ${gl_bai}Restore all app data" echo -e "${gl_kjlan}------------------------" @@ -10967,7 +10981,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11025,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11142,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -11946,7 +11960,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction: https://github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -12577,7 +12591,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" local app_url="Official website: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12585,7 +12599,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12666,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12809,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12879,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -12925,7 +12939,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Since Lucky uses the host network mode, the port here is only for record/explanation reference, and is actually controlled by the application itself (default 16601) + # Since Lucky uses the host network mode, the port here is only for record/explanation reference and is actually controlled by the application itself (default 16601) local docker_port=8112 docker_rum() { @@ -12972,7 +12986,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through web pages." + local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through the web page." local docker_url="Project address: https://github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -13027,7 +13041,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13060,7 +13074,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -13629,8 +13643,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -13838,7 +13852,7 @@ EOF send_stats "Change time zone" while true; do clear - echo "系统时间信息" + echo "System time information" # Get the current system time zone local timezone=$(current_timezone) @@ -14126,7 +14140,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -14377,7 +14391,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14386,7 +14400,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "One-stop tuning started" + send_stats "One-stop tuning starts" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14426,7 +14440,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14674,7 +14688,7 @@ linux_file() { 24) # 复制文件目录 - read -e -p "Please enter the file or directory path to copy:" src_path + read -e -p "Please enter the file or directory path to be copied:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." send_stats "Copying file or directory failed: File or directory does not exist" @@ -14788,7 +14802,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14939,7 +14953,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 7b233ad85..62add0daa 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 関数の埋もれた情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、ユーザーが使用した関数名を記録する機能。機密情報は含まれませんので、ご安心ください。信じてください! +# この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 # send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -863,7 +863,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -921,12 +921,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP公開$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "IP公開" + send_stats "リリース済みIP" } block_ip() { @@ -3008,7 +3008,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -4054,7 +4054,7 @@ add_forwarding_service() { send_stats "FRPイントラネットサービスを追加" # ユーザーにサービス名と転送情報の入力を求めるプロンプトを表示します read -e -p "サービス名を入力してください:" service_name - read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp にするには Enter キーを押してください]:" service_type + read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -4851,7 +4851,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" } @@ -4894,7 +4894,7 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" } @@ -5563,7 +5563,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6048,9 +6048,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6092,7 +6092,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6401,7 +6401,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6532,7 +6532,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6720,7 +6720,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモート ホストにアクセスできますか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6819,7 +6819,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7584,7 +7584,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7727,7 +7727,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" echo -e "${gl_kjlan}あなたのアプリをここに表示したいですか?開発者ガイドを確認してください。${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # アプリの説明を取得する local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # インストールステータスを確認します (appno.txt の ID と一致します)。 + # ここでは、appno.txtに記録されているのはbase_name(つまりファイル名)であると仮定します。 + if echo "$app_numbers" | grep -q "^$base_name$"; then + # インストールされている場合: showbase_name - description [インストール済み] (緑色) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[インストール済み]${gl_bai}" + else + # インストールされていない場合:通常通り表示 + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}すべてのアプリケーション データをバックアップする${gl_kjlan}r. ${gl_bai}すべてのアプリデータを復元する" echo -e "${gl_kjlan}------------------------" @@ -9554,7 +9568,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -10490,7 +10504,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10967,7 +10981,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11025,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11142,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -11623,7 +11637,7 @@ while true; do } - local docker_describe="Beszel は軽量で使いやすいサーバー監視です" + local docker_describe="Beszel轻量易用的服务器监控" local docker_url="公式サイト紹介:https://beszel.dev/zh/" local docker_use="" local docker_passwd="" @@ -11637,7 +11651,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -11946,7 +11960,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:https://github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -12434,7 +12448,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -12577,7 +12591,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" local app_url="公式ウェブサイト:https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12585,7 +12599,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12666,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12809,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12879,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -13027,7 +13041,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリのバックアップ" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13060,7 +13074,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -13089,7 +13103,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13629,8 +13643,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -14126,7 +14140,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -14368,7 +14382,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14386,7 +14400,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "ワンストップチューニングスタート" + send_stats "ワンストップチューニングが始まります" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14661,7 +14675,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14681,7 +14695,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14788,7 +14802,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14817,7 +14831,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -14855,7 +14869,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -14939,7 +14953,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15314,7 +15328,7 @@ else swap) shift - send_stats "仮想メモリを素早く設定する" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 93e99c13b..80b3e79f3 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -57,7 +57,7 @@ CheckFirstRun_true() { -# 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기기 국가 및 기능 이름을 기록하는 기능입니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! +# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. # send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -921,12 +921,12 @@ allow_ip() { # 허용 규칙 추가 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "IP 공개$ip" + echo "공개된 IP$ip" fi done save_iptables_rules - send_stats "IP 공개" + send_stats "공개된 IP" } block_ip() { @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP 삭제" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1313,7 +1313,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 바꾸기 + # docker-compose.yml 파일에서 교체 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1544,11 +1544,11 @@ certs_status() { send_stats "도메인 이름 인증서 신청 실패" echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." - echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인하세요." + echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." echo "------------------------" echo "1. 다시 적용 2. 기존 인증서 가져오기 3. 인증서 없이 HTTP 액세스 사용 0. 종료" echo "------------------------" @@ -2134,7 +2134,7 @@ web_security() { echo "------------------------" echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" echo "------------------------" - echo "21. cloudflare 모드 22. 고부하에서 5초 쉴드 활성화" + echo "21. cloudflare 모드 22. 고부하에서 5초 보호 활성화" echo "------------------------" echo "31. WAF 켜기 32. WAF 끄기" echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" @@ -2248,7 +2248,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2514,7 +2514,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -3325,7 +3325,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3338,7 +3338,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3412,7 +3412,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3532,7 +3532,7 @@ list_stream_services() { proto="tcp" fi - # 스플라이스 청취 IP:포트 + # 접속 수신 IP:포트 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -3676,7 +3676,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4009,7 +4009,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4054,7 +4054,7 @@ add_forwarding_service() { send_stats "FRP 인트라넷 서비스 추가" # 사용자에게 서비스 이름 및 전달 정보를 묻는 메시지를 표시합니다. read -e -p "서비스 이름을 입력하세요:" service_name - read -e -p "전달 유형(tcp/udp)을 입력하십시오. [tcp를 기본값으로 설정하려면 Enter를 누르십시오]:" service_type + read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} @@ -4071,7 +4071,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4318,7 +4318,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4851,7 +4851,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -5279,7 +5279,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5289,7 +5289,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -5306,7 +5306,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5343,7 +5343,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5432,7 +5432,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -6720,7 +6720,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -7311,7 +7311,7 @@ docker_ssh_migration() { # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 건너뛰세요...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" continue fi @@ -7424,7 +7424,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 용기:$container${NC}" + echo -e "${GREEN}처리용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7498,7 +7498,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -7543,7 +7543,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8443,7 +8443,7 @@ linux_ldnmp() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "" - echo "레디스 주소: 레디스" + echo "레디스 주소 : 레디스" echo "redis 비밀번호: 기본적으로 입력되지 않음" echo "레디스 포트: 6379" echo "" @@ -8689,7 +8689,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db case $use_db in 1) echo @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -9329,7 +9329,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # 앱 설명 가져오기 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # 설치 상태 확인(appno.txt의 ID 일치) + # 여기서는 appno.txt에 기록되는 내용이 base_name(즉, 파일 이름)이라고 가정합니다. + if echo "$app_numbers" | grep -q "^$base_name$"; then + # 설치된 경우: show base_name - 설명 [설치됨](녹색) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[설치됨]${gl_bai}" + else + # 설치되지 않은 경우: 정상적으로 표시됩니다. + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" @@ -9525,7 +9539,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -9545,7 +9559,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -10225,7 +10239,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -10391,7 +10405,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10567,7 +10581,7 @@ while true; do } - local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹화 도구입니다." + local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹음 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" @@ -10967,7 +10981,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11025,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11142,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -11946,9 +11960,9 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 홈페이지 소개: https://github.com/synctv-org/synctv" - local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 적시에 로그인 비밀번호를 변경하세요\"" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -12005,7 +12019,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" local docker_url="공식 홈페이지 소개: https://github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -12078,7 +12092,7 @@ while true; do local app_name="gitea 비공개 코드 저장소" local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." - local app_url="영상소개 : https://github.com/go-gitea/gitea" + local app_url="영상 소개: https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12577,7 +12591,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12585,7 +12599,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12666,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12809,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12879,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -12925,7 +12939,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -13027,7 +13041,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13060,7 +13074,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -13629,8 +13643,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -13673,7 +13687,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -13863,7 +13877,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -13931,7 +13945,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14026,7 +14040,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -14126,7 +14140,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -14142,7 +14156,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -14232,7 +14246,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -14386,7 +14400,7 @@ EOF case "$choice" in [Yy]) clear - send_stats "원스톱 튜닝이 시작되었습니다" + send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" switch_mirror false false linux_update @@ -14788,7 +14802,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14939,7 +14953,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15222,7 +15236,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index fee310e9d..aa78f0041 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -9243,7 +9243,7 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 @@ -9338,12 +9338,26 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用列表" echo -e "${gl_kjlan}想要讓你的應用出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) + # 獲取應用描述 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + + # 檢查安裝狀態 (匹配 appno.txt 中的 ID) + # 這裡假設 appno.txt 中記錄的是 base_name (即文件名) + if echo "$app_numbers" | grep -q "^$base_name$"; then + # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" + else + # 如果未安裝:正常顯示 + echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" + fi done + + + echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" @@ -10967,7 +10981,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langgenius/dify.git && cd dify/docker && cp .env.example .env sed -i "s/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=${docker_port}/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/" /home/docker/dify/docker/.env docker compose up -d @@ -11011,7 +11025,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/Calcium-Ion/new-api.git && cd new-api + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/Calcium-Ion/new-api.git && cd new-api sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ @@ -11128,7 +11142,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/infiniflow/ragflow.git && cd ragflow/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/infiniflow/ragflow.git && cd ragflow/docker sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear @@ -12585,7 +12599,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git && cd MoneyPrinterTurbo/ sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml docker compose up -d @@ -12652,7 +12666,7 @@ while true; do docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/umami-software/umami.git && cd umami + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/umami-software/umami.git && cd umami sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/umami/docker-compose.yml docker compose up -d @@ -12795,7 +12809,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/langbot-app/LangBot && cd LangBot/docker + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/langbot-app/LangBot && cd LangBot/docker sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml docker compose up -d @@ -12865,7 +12879,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_install() { install git - mkdir -p /home/docker/ && cd /home/docker/ && git clone https://github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env + mkdir -p /home/docker/ && cd /home/docker/ && git clone ${gh_proxy}github.com/karakeep-app/karakeep.git && cd karakeep/docker && cp .env.sample .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml docker compose up -d @@ -13060,7 +13074,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone https://github.com/kejilion/apps.git + git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps git pull origin main > /dev/null 2>&1 From 0089136518dfc04b73ee41c35f135f50ee3323db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 6 Jan 2026 11:26:49 +0800 Subject: [PATCH 0516/1285] Refactor Docker image update checks and logic --- cn/kejilion.sh | 75 +++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ca6d12873..520c44bc9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. 区域检查 + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # 获取容器的创建时间和镜像名称 + # 2. 获取本地镜像信息 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # 提取镜像仓库和标签 - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # 默认标签为 latest - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # 添加对官方镜像的支持 - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. 智能路由判断 + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- 场景 A: 镜像在 GitHub (ghcr.io) --- + # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # 注意:ghcr.io 的 API 比较复杂,通常最快的方法是查 GitHub Repo 的 Release + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # 从 Docker Hub API 获取镜像发布时间 - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- 场景 C: 标准 Docker Hub --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 验证获取的时间 - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # 比较时间戳 - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. 时间戳对比 + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -10189,12 +10196,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } From 167f05b514d4a9758e87173d63c99442a4f02cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 6 Jan 2026 11:27:19 +0800 Subject: [PATCH 0517/1285] Update sh_v version from 4.3.0 to 4.3.1 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 520c44bc9..cf3b0b390 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' From a56cd967101c86b4119d99f714c07d7d30da0f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 6 Jan 2026 11:29:02 +0800 Subject: [PATCH 0518/1285] Update version and Docker image references in kejilion.sh Updated version from 4.3.0 to 4.3.1 and modified Docker image references for memos. --- kejilion.sh | 77 +++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1deb190a0..e2667fefa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. 区域检查 + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # 获取容器的创建时间和镜像名称 + # 2. 获取本地镜像信息 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # 提取镜像仓库和标签 - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # 默认标签为 latest - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # 添加对官方镜像的支持 - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. 智能路由判断 + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- 场景 A: 镜像在 GitHub (ghcr.io) --- + # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # 注意:ghcr.io 的 API 比较复杂,通常最快的方法是查 GitHub Repo 的 Release + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # 从 Docker Hub API 获取镜像发布时间 - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- 场景 C: 标准 Docker Hub --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 验证获取的时间 - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # 比较时间戳 - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. 时间戳对比 + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -10189,12 +10196,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } From 7a953f470c62596f3bda8ba4fa255c5c16634587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 6 Jan 2026 11:33:53 +0800 Subject: [PATCH 0519/1285] Update changelog for v4.3.1 enhancements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化应用市场新版本逻辑以兼容github.io,并调整memos镜像源。 --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4729ce6d6..ba2c5258e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1393,4 +1393,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场支持第三方入驻功能,开发者可以将自己的项目加入到脚本中让大家使用。 入驻指南: https://github.com/kejilion/sh/tree/main/apps ------------------------ +2026-01-06 v4.3.1 +应用市场应用发现新版本逻辑进行优化可以兼容github.io的新版本发现。 +应用市场memos拉取镜像源进行调整,采用官方更推荐的做法。 +------------------------ From a694aac8f3ca178ee5ce41d21d182821fbb81337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:02:37 +0800 Subject: [PATCH 0520/1285] Update git pull commands to use proxy URLs --- cn/kejilion.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cf3b0b390..698968cdc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9253,7 +9253,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -11006,7 +11007,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11049,7 +11050,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11160,7 +11162,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -12618,7 +12620,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12687,7 +12690,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12828,7 +12831,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12898,7 +12901,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -13084,7 +13087,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then From 6cc93a69fee4cad7f24a3e0113675d8657d0941b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:03:12 +0800 Subject: [PATCH 0521/1285] Update git pull commands to use gh_proxy --- kejilion.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e2667fefa..5c65f43da 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9253,7 +9253,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -11006,7 +11007,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11049,7 +11050,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11160,7 +11162,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -12618,7 +12620,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12687,7 +12690,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12828,7 +12831,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12898,7 +12901,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -13084,7 +13087,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then From c68270befd5f771f137b753b9d6d1c634b65b118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:04:45 +0800 Subject: [PATCH 0522/1285] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=B8=82=E5=9C=BAgit=E6=9B=B4=E6=96=B0=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化应用市场的git更新机制以解决拉取卡顿问题。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ba2c5258e..bc1df54bb 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1396,5 +1396,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-01-06 v4.3.1 应用市场应用发现新版本逻辑进行优化可以兼容github.io的新版本发现。 应用市场memos拉取镜像源进行调整,采用官方更推荐的做法。 +应用市场优化部分项目的git更新机制,解决国内拉取卡顿的问题。 ------------------------ From afa8d86bbcd1d05d5e54d983eb066a3b81dadbe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:34:28 +0800 Subject: [PATCH 0523/1285] Enhance send_stats for app management actions Added send_stats calls for app installation, update, uninstallation, and domain access settings. Updated the git installation section to include opencode installation. --- cn/kejilion.sh | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 698968cdc..b253f6f8d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3024,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_name 安装" ;; + 2) docker_app_update - add_app_id + send_stats "$app_name 更新" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_name 卸载" ;; + 5) echo "${docker_name}域名访问设置" send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "域名格式 example.com 不带https://" @@ -6954,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统 ${gl_kjlan}18. ${gl_bai}opencode AI编程助手 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" @@ -7113,6 +7118,15 @@ linux_tools() { send_stats "安装git" ;; + 18) + clear + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + opencode + send_stats "安装opencode" + ;; + + 21) clear install cmatrix @@ -7141,6 +7155,7 @@ linux_tools() { nsnake send_stats "安装nsnake" ;; + 28) clear install ninvaders @@ -12620,7 +12635,7 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d From 0753822c170595cfd07393331a333cae56f6b2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:35:43 +0800 Subject: [PATCH 0524/1285] Add send_stats calls for app installation and updates --- kejilion.sh | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 5c65f43da..a57b8bd4a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3024,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_name 安装" ;; + 2) docker_app_update - add_app_id + send_stats "$app_name 更新" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_name 卸载" ;; + 5) echo "${docker_name}域名访问设置" send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "域名格式 example.com 不带https://" @@ -6954,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统 ${gl_kjlan}18. ${gl_bai}opencode AI编程助手 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" @@ -7113,6 +7118,15 @@ linux_tools() { send_stats "安装git" ;; + 18) + clear + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + opencode + send_stats "安装opencode" + ;; + + 21) clear install cmatrix @@ -7141,6 +7155,7 @@ linux_tools() { nsnake send_stats "安装nsnake" ;; + 28) clear install ninvaders @@ -12620,7 +12635,7 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d From 27eff918134938ee60ba936c42af2d5cd3affb95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:37:41 +0800 Subject: [PATCH 0525/1285] Add opencode AI assistant for server-side development Added a new AI programming assistant to the basic tools. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index bc1df54bb..231f3143e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1397,5 +1397,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场应用发现新版本逻辑进行优化可以兼容github.io的新版本发现。 应用市场memos拉取镜像源进行调整,采用官方更推荐的做法。 应用市场优化部分项目的git更新机制,解决国内拉取卡顿的问题。 +基础工具中添加了目前流行的opencode编程AI助手可以在服务器上直接AI可视化开发编程。 ------------------------ From 768a48f0cc4ee4ecd588d8bcb1ec0affab46f39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:57:40 +0800 Subject: [PATCH 0526/1285] Add installation and uninstallation for opencode --- cn/kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b253f6f8d..1aa1500c3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7120,8 +7120,10 @@ linux_tools() { 18) clear + cd ~ curl -fsSL https://opencode.ai/install | bash source ~/.bashrc + source ~/.profile opencode send_stats "安装opencode" ;; @@ -7181,6 +7183,8 @@ linux_tools() { clear send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) From 4e449931f357e60a87952bf4e1f7ec253f2681a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:58:23 +0800 Subject: [PATCH 0527/1285] Add opencode installation and uninstallation commands --- kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index a57b8bd4a..e25c7b01a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7120,8 +7120,10 @@ linux_tools() { 18) clear + cd ~ curl -fsSL https://opencode.ai/install | bash source ~/.bashrc + source ~/.profile opencode send_stats "安装opencode" ;; @@ -7181,6 +7183,8 @@ linux_tools() { clear send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) From ee62662fd2485fd719d3cbed80c0aec0e264f16e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 11 Jan 2026 04:25:39 +0000 Subject: [PATCH 0528/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-01-11=2004:25:39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 232 +++++++++++++++++++++++++------------------- jp/kejilion.sh | 258 +++++++++++++++++++++++++++---------------------- kr/kejilion.sh | 254 +++++++++++++++++++++++++++--------------------- tw/kejilion.sh | 124 +++++++++++++++--------- 4 files changed, 494 insertions(+), 374 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 73a923fc4..c2f4a0387 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' @@ -2334,7 +2334,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. Regional inspection + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # Get the creation time and image name of the container + # 2. Get local mirror information local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # Extract image repository and tags - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # The default tag is latest - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # Add support for official images - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. Intelligent routing judgment + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- Scenario A: Mirror on GitHub (ghcr.io) --- + # Extract the warehouse path, for example ghcr.io/onexru/oneimg -> onexru/oneimg + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # Note: The API of ghcr.io is relatively complex. Usually the fastest way is to check the Release of GitHub Repo + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- Scenario B: Special designation (even in Docker Hub, I want to judge by GitHub Release) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # Get image release time from Docker Hub API - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- Scenario C: Standard Docker Hub --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # Verify the time obtained - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # Compare timestamps - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. Timestamp comparison + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}New version found!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -2676,7 +2683,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2695,7 +2702,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2936,7 +2943,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3017,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_nameInstall" ;; + 2) docker_app_update - add_app_id + send_stats "$app_namerenew" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_nameuninstall" ;; + 5) echo "${docker_name}Domain name access settings" send_stats "${docker_name}Domain name access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "Domain name format example.com without https://" @@ -4295,7 +4307,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4392,7 +4404,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -4851,7 +4863,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" } @@ -4894,14 +4906,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOT login setup is complete!${gl_bai}" +echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -5172,7 +5184,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5563,7 +5575,7 @@ clamav() { ;; 3) send_stats "Custom directory scan" - read -e -p "Please enter the directories to be scanned, separated by spaces (for example: /etc /var /usr /home /root):" directories + read -e -p "Please enter the directories to scan, separated by spaces (for example: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5706,7 +5718,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -5785,7 +5797,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6720,7 +6732,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -6935,7 +6947,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" @@ -6947,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop modern monitoring tool${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger file management tool" echo -e "${gl_kjlan}13. ${gl_bai}ncdu disk usage viewing tool${gl_kjlan}14. ${gl_bai}fzf global search tool" echo -e "${gl_kjlan}15. ${gl_bai}vim text editor${gl_kjlan}16. ${gl_bai}nano text editor${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git version control system" + echo -e "${gl_kjlan}17. ${gl_bai}git version control system${gl_kjlan}18. ${gl_bai}opencode AI programming assistant${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Running train screensaver" echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake mini game" @@ -7106,6 +7118,17 @@ linux_tools() { send_stats "Install git" ;; + 18) + clear + cd ~ + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + source ~/.profile + opencode + send_stats "Install opencode" + ;; + + 21) clear install cmatrix @@ -7134,6 +7157,7 @@ linux_tools() { nsnake send_stats "Install nsnake" ;; + 28) clear install ninvaders @@ -7159,6 +7183,8 @@ linux_tools() { clear send_stats "Uninstall all" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) @@ -7510,7 +7536,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Transferring backup...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7877,7 +7903,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9246,7 +9272,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9269,7 +9296,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -9639,7 +9666,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9743,7 +9770,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -9797,7 +9824,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -9895,7 +9922,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -9970,7 +9997,7 @@ while true; do } - local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -10189,12 +10216,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } @@ -10780,7 +10807,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -10999,7 +11026,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11007,7 +11034,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11042,7 +11069,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11058,7 +11086,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11099,7 +11127,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11153,7 +11181,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -11162,7 +11190,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11347,7 +11375,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -11403,7 +11431,7 @@ while true; do } - local docker_describe="A password manager where you can control your data" + local docker_describe="A password manager that puts you in control of your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11490,7 +11518,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11761,7 +11789,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11897,7 +11925,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11960,7 +11988,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction: https://github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -12124,7 +12152,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12262,7 +12290,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12316,7 +12344,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12549,7 +12577,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12611,7 +12639,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12619,7 +12648,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12680,7 +12709,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12688,7 +12717,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12821,7 +12850,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12829,7 +12858,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12891,7 +12920,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -12899,7 +12928,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13077,7 +13106,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13113,7 +13143,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -13454,7 +13484,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13643,8 +13673,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -13882,7 +13912,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil Time 26. Argentina Time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -14391,7 +14421,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14440,7 +14470,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14688,7 +14718,7 @@ linux_file() { 24) # 复制文件目录 - read -e -p "Please enter the file or directory path to be copied:" src_path + read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." send_stats "Copying file or directory failed: File or directory does not exist" @@ -14836,7 +14866,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14953,7 +14983,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15192,7 +15222,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" @@ -15226,7 +15256,7 @@ echo "docker container management k docker ps |k docker container" echo "docker image management k docker img |k docker image" echo "LDNMP site management k web" echo "LDNMP cache cleaning k web cache" -echo "Install WordPress k wp | k wordpress | k wp xxx.com" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" echo "Install reverse proxy k fd |k rp |k reverse proxy |k fd xxx.com" echo "Install load balancing k loadbalance |k load balancing" echo "Install L4 load balancing k stream |k L4 load balancing" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 62add0daa..634379b25 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' @@ -858,12 +858,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -2334,7 +2334,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. 地域検査 + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # コンテナの作成時刻とイメージ名を取得します。 + # 2. ローカルミラー情報の取得 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # 画像リポジトリとタグを抽出する - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # デフォルトのタグはlatestです - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # 公式画像のサポートを追加 - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. インテリジェントな配線判断 + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- + # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- シナリオB:特別指定(Docker HubでもGitHub Releaseで判断したい) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # Docker Hub APIからイメージのリリース時刻を取得する - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- シナリオ C: 標準 Docker ハブ --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 取得した時間を確認する - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # タイムスタンプを比較する - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. タイムスタンプの比較 + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}新しいバージョンが見つかりました!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -2895,7 +2902,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3008,7 +3015,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3017,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_nameインストール" ;; + 2) docker_app_update - add_app_id + send_stats "$app_name更新する" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_nameアンインストールする" ;; + 5) echo "${docker_name}ドメイン名アクセス設定" send_stats "${docker_name}ドメイン名アクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "ドメイン名の形式 example.com (https:// なし)" @@ -4733,7 +4745,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4851,7 +4863,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" } @@ -4894,14 +4906,14 @@ sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_confi sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh -echo -e "${gl_lv}ROOTログインの設定は完了です!${gl_bai}" +echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" } root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -5563,7 +5575,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -5758,7 +5770,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -5785,7 +5797,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -5875,7 +5887,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6180,7 +6192,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6380,9 +6392,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションのマウント +# パーティションをマウントする mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6532,7 +6544,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6561,7 +6573,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6720,7 +6732,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモート ホストにアクセスできますか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6729,7 +6741,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -6819,7 +6831,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6935,7 +6947,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" @@ -6947,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7007,7 +7019,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7106,6 +7118,17 @@ linux_tools() { send_stats "gitをインストールする" ;; + 18) + clear + cd ~ + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + source ~/.profile + opencode + send_stats "オープンコードをインストールする" + ;; + + 21) clear install cmatrix @@ -7134,6 +7157,7 @@ linux_tools() { nsnake send_stats "nsnakeをインストールする" ;; + 28) clear install ninvaders @@ -7159,6 +7183,8 @@ linux_tools() { clear send_stats "すべてアンインストールする" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) @@ -7301,7 +7327,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" + echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7311,7 +7337,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7478,7 +7504,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7503,14 +7529,14 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" echo -e "${YELLOW}バックアップを転送中...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8070,7 +8096,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8454,7 +8480,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9246,7 +9272,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9269,7 +9296,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -9307,7 +9334,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -9317,7 +9344,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -9970,7 +9997,7 @@ while true; do } - local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -10030,7 +10057,7 @@ while true; do } - local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" + local docker_describe="Onlyoffice は、非常に強力なオープンソースのオンライン オフィス ツールです。" local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -10189,12 +10216,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } @@ -10405,7 +10432,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、分割マージ、変換、再編成、画像の追加、回転、圧縮など、PDF ファイルに対してさまざまな操作を実行できます。" + local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、PDF ファイルに対して分割マージ、変換、再編成、画像の追加、回転、圧縮などのさまざまな操作を実行できます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10451,7 +10478,7 @@ while true; do } - local docker_describe="Sun-Panel サーバー、NAS ナビゲーション パネル、ホームページ、ブラウザー ホームページ" + local docker_describe="Sun-Panel サーバー、NAS ナビゲーション パネル、ホームページ、ブラウザーのホームページ" local docker_url="公式サイト紹介:https://doc.sun-panel.top/zh_cn/" local docker_use="echo 「アカウント: admin@sun.cc パスワード: 12345678」" local docker_passwd="" @@ -10504,7 +10531,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -10833,7 +10860,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -10999,7 +11026,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11042,7 +11069,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11153,7 +11181,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -11347,7 +11375,7 @@ while true; do } - local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" + local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -11403,7 +11431,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11637,7 +11665,7 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" + local docker_describe="Beszel は軽量で使いやすいサーバー監視です" local docker_url="公式サイト紹介:https://beszel.dev/zh/" local docker_use="" local docker_passwd="" @@ -11651,7 +11679,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -11866,7 +11894,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチピクチャービデオマネージャー" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:https://github.com/immich-app/immich" local docker_name="immich_server" @@ -11960,7 +11988,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:https://github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -11990,7 +12018,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -12336,7 +12364,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -12611,7 +12639,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12680,7 +12709,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12821,7 +12850,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12891,7 +12920,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -12924,7 +12953,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -13077,7 +13106,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13103,7 +13133,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13113,7 +13143,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -13388,7 +13418,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -13643,8 +13673,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -13857,7 +13887,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13872,7 +13902,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14099,7 +14129,7 @@ EOF 1) read -e -p "新しい解析レコード形式を入力してください: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホスト解像度が追加されました" + send_stats "ローカルホストの解像度が追加されました" ;; 2) @@ -14382,7 +14412,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -14482,7 +14512,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14675,7 +14705,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -14695,7 +14725,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -14831,12 +14861,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14869,14 +14899,14 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14953,7 +14983,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15159,7 +15189,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -15192,7 +15222,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 80b3e79f3..eecc5ec6f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' @@ -59,7 +59,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1090,7 +1090,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 삭제" + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1259,7 +1259,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1548,7 +1548,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" echo "1. 다시 적용 2. 기존 인증서 가져오기 3. 인증서 없이 HTTP 액세스 사용 0. 종료" echo "------------------------" @@ -1848,7 +1848,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2021,7 +2021,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2078,7 +2078,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2334,7 +2334,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2514,7 +2514,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. 지역점검 + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # 컨테이너의 생성 시간과 이미지 이름을 가져옵니다. + # 2. 로컬 미러 정보 얻기 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # 이미지 저장소 및 태그 추출 - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # 기본 태그는 최신입니다. - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # 공식 이미지에 대한 지원 추가 - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. 지능형 라우팅 판단 + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- 시나리오 A: GitHub(ghcr.io)의 미러링 --- + # 웨어하우스 경로를 추출합니다(예: ghcr.io/onexru/oneimg -> onexru/oneimg). + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # 참고: ghcr.io의 API는 비교적 복잡합니다. 일반적으로 가장 빠른 방법은 GitHub Repo 릴리스를 확인하는 것입니다. + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- 시나리오 B: 특별 지정(Docker Hub에서도 GitHub 릴리스로 판단하고 싶습니다) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # Docker Hub API에서 이미지 릴리스 시간 가져오기 - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- 시나리오 C: 표준 Docker 허브 --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 획득한 시간을 확인 - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # 타임스탬프 비교 - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. 타임스탬프 비교 + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -2676,7 +2683,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2695,7 +2702,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2792,7 +2799,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2808,7 +2815,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2895,7 +2902,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port @@ -3008,7 +3015,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} local docker_port=$app_port install jq @@ -3017,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_name설치하다" ;; + 2) docker_app_update - add_app_id + send_stats "$app_name고쳐 쓰다" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_name제거" ;; + 5) echo "${docker_name}도메인 이름 액세스 설정" send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "https://가 없는 도메인 이름 형식 example.com" @@ -3412,7 +3424,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3532,7 +3544,7 @@ list_stream_services() { proto="tcp" fi - # 접속 수신 IP:포트 + # 스플라이스 청취 IP:포트 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -3628,7 +3640,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4851,7 +4863,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" } @@ -5279,7 +5291,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5289,7 +5301,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5306,7 +5318,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5343,7 +5355,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5432,7 +5444,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5785,7 +5797,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -5992,7 +6004,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6231,7 +6243,7 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6579,7 +6591,7 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6720,7 +6732,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -6947,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}레인저 파일 관리 도구" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 디스크 사용량 보기 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템" + echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템${gl_kjlan}18. ${gl_bai}오픈코드 AI 프로그래밍 도우미${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 스크린세이버${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 미니게임" @@ -7106,6 +7118,17 @@ linux_tools() { send_stats "자식 설치" ;; + 18) + clear + cd ~ + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + source ~/.profile + opencode + send_stats "오픈코드 설치" + ;; + + 21) clear install cmatrix @@ -7134,6 +7157,7 @@ linux_tools() { nsnake send_stats "nsnake 설치" ;; + 28) clear install ninvaders @@ -7159,6 +7183,8 @@ linux_tools() { clear send_stats "모두 제거" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) @@ -7311,7 +7337,7 @@ docker_ssh_migration() { # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 건너뛰세요...${NC}" continue fi @@ -7408,7 +7434,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7498,7 +7524,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -7510,7 +7536,7 @@ docker_ssh_migration() { echo -e "${YELLOW}백업 전송 중...${NC}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7697,7 +7723,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7743,7 +7769,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8453,7 +8479,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8782,7 +8808,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf @@ -9246,7 +9272,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9269,7 +9296,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9309,7 +9336,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9329,7 +9356,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -9337,7 +9364,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -9559,7 +9586,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -9639,7 +9666,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -9671,7 +9698,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -9970,7 +9997,7 @@ while true; do } - local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -10189,12 +10216,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } @@ -10405,7 +10432,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10999,7 +11026,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11042,7 +11069,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11070,7 +11098,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개: https://github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -11153,7 +11181,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -11347,7 +11375,7 @@ while true; do } - local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -11403,7 +11431,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -11651,7 +11679,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -11960,7 +11988,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 홈페이지 소개: https://github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -11993,7 +12021,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" - local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" + local docker_passwd="echo \"초기 계정 : admin 초기 비밀번호 : abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -12591,7 +12619,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12611,7 +12639,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12680,7 +12709,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12821,7 +12850,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12891,7 +12920,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -12939,7 +12968,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -13077,7 +13106,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13113,7 +13143,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -13215,7 +13245,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13387,7 +13417,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -13643,8 +13673,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -13687,7 +13717,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -13857,7 +13887,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간 가져오기 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -13877,7 +13907,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -14836,7 +14866,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14953,7 +14983,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15192,7 +15222,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index aa78f0041..8f711cf7e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.0" +sh_v="4.3.1" gl_hui='\e[37m' @@ -2551,54 +2551,61 @@ done check_docker_image_update() { - local container_name=$1 + update_status="" - local country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" ]]; then - update_status="" - return - fi + # 1. 區域檢查 + local country=$(curl -s --max-time 2 ipinfo.io/country) + [[ "$country" == "CN" ]] && return - # 獲取容器的創建時間和鏡像名稱 + # 2. 獲取本地鏡像信息 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) - local container_created=$(echo "$container_info" | cut -d',' -f1) - local image_name=$(echo "$container_info" | cut -d',' -f2) - - # 提取鏡像倉庫和標籤 - local image_repo=${image_name%%:*} - local image_tag=${image_name##*:} + [[ -z "$container_info" ]] && return - # 默認標籤為 latest - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" - - # 添加對官方鏡像的支持 - [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" + local container_created=$(echo "$container_info" | cut -d',' -f1) + local full_image_name=$(echo "$container_info" | cut -d',' -f2) + local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + + # 3. 智能路由判斷 + if [[ "$full_image_name" == ghcr.io* ]]; then + # --- 場景 A: 鏡像在 GitHub (ghcr.io) --- + # 提取倉庫路徑,例如 ghcr.io/onexru/oneimg -> onexru/oneimg + local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) + # 注意:ghcr.io 的 API 比較複雜,通常最快的方法是查 GitHub Repo 的 Release + local api_url="https://api.github.com/repos/$repo_path/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) + + elif [[ "$full_image_name" == *"oneimg"* ]]; then + # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想通過 GitHub Release 判斷) --- + local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" + local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) - # 從 Docker Hub API 獲取鏡像發佈時間 - local hub_info=$(curl -s "https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag") - local last_updated=$(echo "$hub_info" | jq -r '.last_updated' 2>/dev/null) + else + # --- 場景 C: 標準 Docker Hub --- + local image_repo=${full_image_name%%:*} + local image_tag=${full_image_name##*:} + [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" - # 驗證獲取的時間 - if [[ -n "$last_updated" && "$last_updated" != "null" ]]; then - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - local last_updated_ts=$(date -d "$last_updated" +%s 2>/dev/null) + local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" + local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + fi - # 比較時間戳 - if [[ $container_created_ts -lt $last_updated_ts ]]; then + # 4. 時間戳對比 + if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then + local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) + if [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}發現新版本!${gl_bai}" - else - update_status="" fi - else - update_status="" fi - } + + + block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 @@ -3017,25 +3024,30 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + send_stats "$app_name安裝" ;; + 2) docker_app_update - add_app_id + send_stats "$app_name更新" ;; + 3) docker_app_uninstall rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - + send_stats "$app_name解除安裝" ;; + 5) echo "${docker_name}域名訪問設置" send_stats "${docker_name}域名訪問設置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + ;; 6) echo "域名格式 example.com 不帶https://" @@ -6947,7 +6959,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盤佔用查看工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" echo -e "${gl_kjlan}15. ${gl_bai}vim 文本編輯器${gl_kjlan}16. ${gl_bai}nano 文本編輯器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI編程助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}黑客帝國屏保${gl_kjlan}22. ${gl_bai}跑火車屏保" echo -e "${gl_kjlan}26. ${gl_bai}俄羅斯方塊小遊戲${gl_kjlan}27. ${gl_bai}貪吃蛇小遊戲" @@ -7106,6 +7118,17 @@ linux_tools() { send_stats "安裝git" ;; + 18) + clear + cd ~ + curl -fsSL https://opencode.ai/install | bash + source ~/.bashrc + source ~/.profile + opencode + send_stats "安裝opencode" + ;; + + 21) clear install cmatrix @@ -7134,6 +7157,7 @@ linux_tools() { nsnake send_stats "安裝nsnake" ;; + 28) clear install ninvaders @@ -7159,6 +7183,8 @@ linux_tools() { clear send_stats "全部卸載" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git + opencode uninstall + rm -rf ~/.opencode ;; 41) @@ -9246,7 +9272,8 @@ if [ ! -d apps/.git ]; then git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -10189,12 +10216,12 @@ while true; do 23|memos) local app_id="23" local docker_name="memos" - local docker_img="ghcr.io/usememos/memos:latest" + local docker_img="neosmemo/memos:stable" local docker_port=8023 docker_rum() { - docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always ghcr.io/usememos/memos:latest + docker run -d --name memos -p ${docker_port}:5230 -v /home/docker/memos:/var/opt/memos --restart=always neosmemo/memos:stable } @@ -10999,7 +11026,7 @@ while true; do docker_app_update() { cd /home/docker/dify/docker/ && docker compose down --rmi all cd /home/docker/dify/ - git pull origin main + git pull ${gh_proxy}github.com/langgenius/dify.git main > /dev/null 2>&1 sed -i 's/^EXPOSE_NGINX_PORT=.*/EXPOSE_NGINX_PORT=8058/; s/^EXPOSE_NGINX_SSL_PORT=.*/EXPOSE_NGINX_SSL_PORT=8858/' /home/docker/dify/docker/.env cd /home/docker/dify/docker/ && docker compose up -d } @@ -11042,7 +11069,8 @@ while true; do docker_app_update() { cd /home/docker/new-api/ && docker compose down --rmi all cd /home/docker/new-api/ - git pull origin main + + git pull ${gh_proxy}github.com/Calcium-Ion/new-api.git main > /dev/null 2>&1 sed -i -e "s/- \"3000:3000\"/- \"${docker_port}:3000\"/g" \ -e 's/container_name: redis/container_name: redis-new-api/g' \ -e 's/container_name: mysql/container_name: mysql-new-api/g' \ @@ -11153,7 +11181,7 @@ while true; do docker_app_update() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all cd /home/docker/ragflow/ - git pull origin main + git pull ${gh_proxy}github.com/infiniflow/ragflow.git main > /dev/null 2>&1 cd /home/docker/ragflow/docker/ sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d @@ -12611,7 +12639,8 @@ while true; do docker_app_update() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all cd /home/docker/MoneyPrinterTurbo/ - git pull origin main + + git pull ${gh_proxy}github.com/harry0703/MoneyPrinterTurbo.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/MoneyPrinterTurbo/docker-compose.yml cd /home/docker/MoneyPrinterTurbo/ && docker compose up -d } @@ -12680,7 +12709,7 @@ while true; do docker_app_update() { cd /home/docker/umami/ && docker compose down --rmi all cd /home/docker/umami/ - git pull origin main + git pull ${gh_proxy}github.com/umami-software/umami.git main > /dev/null 2>&1 sed -i "s/8501:8501/${docker_port}:8501/g" /home/docker/umami/docker-compose.yml cd /home/docker/umami/ && docker compose up -d } @@ -12821,7 +12850,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/LangBot/docker && docker compose down --rmi all cd /home/docker/LangBot/ - git pull origin main + git pull ${gh_proxy}github.com/langbot-app/LangBot main > /dev/null 2>&1 sed -i "s/5300:5300/${docker_port}:5300/g" /home/docker/LangBot/docker/docker-compose.yaml cd /home/docker/LangBot/docker/ && docker compose up -d } @@ -12891,7 +12920,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_update() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all cd /home/docker/karakeep/ - git pull origin main + git pull ${gh_proxy}github.com/karakeep-app/karakeep.git main > /dev/null 2>&1 sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/karakeep/docker/docker-compose.yml cd /home/docker/karakeep/docker/ && docker compose up -d } @@ -13077,7 +13106,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps - git pull origin main > /dev/null 2>&1 + # git pull origin main > /dev/null 2>&1 + git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then From 62c53d2b66a11c0ba5393468c0337f6bfd8595d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:08:11 +0800 Subject: [PATCH 0529/1285] Add sleep after starting Docker and update commands Added sleep command after starting Docker and made minor adjustments to Docker commands. --- cn/kejilion.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1aa1500c3..13859500f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -413,7 +413,7 @@ fi enable docker start docker restart docker - +sleep 5 } @@ -3436,6 +3436,9 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf + docker exec nginx mkdir -p /var/cache/nginx/proxy/$yuming > /dev/null 2>&1 + docker exec nginx chown -R nginx:nginx /var/cache/nginx/proxy/$yuming > /dev/null 2>&1 + install_ssltls certs_status From c139e5a9e56a040d9bda2dbf080042ad36095c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:10:52 +0800 Subject: [PATCH 0530/1285] Remove redundant docker exec commands Removed unnecessary docker commands for cache directory creation and ownership. --- cn/kejilion.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 13859500f..839c385a3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3436,9 +3436,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - docker exec nginx mkdir -p /var/cache/nginx/proxy/$yuming > /dev/null 2>&1 - docker exec nginx chown -R nginx:nginx /var/cache/nginx/proxy/$yuming > /dev/null 2>&1 - install_ssltls certs_status From 2d5696079e44e5fb9edf5866af6667532153012c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:11:50 +0800 Subject: [PATCH 0531/1285] Add sleep before Docker restart and fix if statement Added a sleep command before restarting Docker and fixed an if statement. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index e25c7b01a..1bbaaaed2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -413,7 +413,7 @@ fi enable docker start docker restart docker - +sleep 5 } From 43c7c141c6a727f2ce6823aa1a78fabc4271dff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:46:11 +0800 Subject: [PATCH 0532/1285] Adjust sleep timing in kejilion.sh --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 839c385a3..8c98f1650 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -413,7 +413,7 @@ fi enable docker start docker restart docker -sleep 5 + } @@ -1433,6 +1433,7 @@ install_certbot() { install_ssltls() { + sleep 5 check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ From 1f312775695c5b0bf16683134b57801478ace382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:47:39 +0800 Subject: [PATCH 0533/1285] Add sleep command before SSL/TLS installation --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1bbaaaed2..60fc9660d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -413,7 +413,7 @@ fi enable docker start docker restart docker -sleep 5 + } @@ -1433,6 +1433,7 @@ install_certbot() { install_ssltls() { + sleep 5 check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ From 8ae9f3dc283ce46a40499ee04930de79b3bd5496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 12:00:58 +0800 Subject: [PATCH 0534/1285] Refactor install_ssltls function for efficiency Removed sleep and check_port commands before stopping nginx. Adjusted iptables rule handling and ensured proper execution of certbot command. --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8c98f1650..2940f2ad6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1433,8 +1433,6 @@ install_certbot() { install_ssltls() { - sleep 5 - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1454,6 +1452,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From cbd361daa43254404d25ca9617315c29032186d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 12:02:42 +0800 Subject: [PATCH 0535/1285] Refactor install_ssltls function for efficiency Removed sleep and check_port commands from install_ssltls function. Adjusted iptables command and ensured proper execution of docker run for certbot. --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 60fc9660d..a09b98ecd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1433,8 +1433,6 @@ install_certbot() { install_ssltls() { - sleep 5 - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1454,6 +1452,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From 07a529b7a2be3c5d7cf88329640f8f4ff85443d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:57:47 +0800 Subject: [PATCH 0536/1285] Create letsencrypt directory in install_ldnmp_conf Added 'web/letsencrypt' directory to the installation script. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index a09b98ecd..7934100da 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # 创建必要的目录和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf From 4d431780c65adec1e6d3dda22b3914641dd8c2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:58:28 +0800 Subject: [PATCH 0537/1285] Add letsencrypt directory in install_ldnmp_conf function --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2940f2ad6..cb604269e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # 创建必要的目录和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf From 0b2d3ccbbc0e997f34c91eb70a8d054368c2bf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:04:40 +0800 Subject: [PATCH 0538/1285] Change condition in update_docker_compose_with_db_creds --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cb604269e..8af1295ad 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') From d9985f2e9970cb2a2fafe7cddfc5905cb1e27a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:05:40 +0800 Subject: [PATCH 0539/1285] Change grep condition to check for 'letsencrypt' --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7934100da..ea4e5d3e9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') From 35b3838b747631cbf43012e87fb8e6344dace39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:12:31 +0800 Subject: [PATCH 0540/1285] Enhance auto certificate renewal script Added environment checks and improved renewal logic. --- auto_cert_renewal.sh | 86 ++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 97cd09087..660faab9b 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -23,39 +23,79 @@ for cert_file in $certs_directory*_cert.pem; do # 计算距离过期还有几天 days_until_expiry=$(( ($expiration_timestamp - $current_timestamp) / 86400 )) - # 检查是否需要续签(在满足续签条件的情况下) if [ $days_until_expiry -le $days_before_expiry ]; then + echo "证书将在${days_before_expiry}天内过期,正在进行自动续签。" - - docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n - docker stop nginx > /dev/null 2>&1 + # 1. 检查目录是否存在 + docker exec nginx [ -d /var/www/letsencrypt ] && DIR_OK=true || DIR_OK=false - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi + # 2. 检查配置文件是否包含关键字 + # 假设你的配置文件在容器内的 /etc/nginx/conf.d/ 目录下(这是 Nginx 容器的默认路径) + docker exec nginx grep -q "letsencrypt" /etc/nginx/conf.d/$yuming.conf && CONF_OK=true || CONF_OK=false + + # 输出结果 + echo "--- 自动化环境检测报告 ---" + if [ "$DIR_OK" = true ]; then echo "✅ 目录检测:/var/www/letsencrypt 存在"; else echo "❌ 目录检测:/var/www/letsencrypt 不存在"; fi + if [ "$CONF_OK" = true ]; then echo "✅ 配置检测:$yuming.conf 已包含续签规则"; else echo "❌ 配置检测:$yuming.conf 未发现 letsencrypt 字样"; fi + + if [ "$DIR_OK" = true ] && [ "$CONF_OK" = true ]; then + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n + + docker run --rm \ + -v "/etc/letsencrypt:/etc/letsencrypt" \ + -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ + -v "/var/www/letsencrypt:/var/www/letsencrypt" \ + certbot/certbot certonly \ + --webroot \ + -w /var/www/letsencrypt \ + -d "lkyjp.kejilion.xyz" \ + --email your@email.com \ + --agree-tos \ + --no-eff-email \ + --key-type ecdsa \ + --force-renewal + + mkdir -p /home/web/certs/ + cp /etc/letsencrypt/live/$yuming/fullchain.pem /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + cp /etc/letsencrypt/live/$yuming/privkey.pem /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 + + openssl rand -out /home/web/certs/ticket12.key 48 + openssl rand -out /home/web/certs/ticket13.key 80 - # iptables -P INPUT ACCEPT - # iptables -P FORWARD ACCEPT - # iptables -P OUTPUT ACCEPT - # iptables -F + docker exec nginx nginx -t && docker exec nginx nginx -s reload - # ip6tables -P INPUT ACCEPT - # ip6tables -P FORWARD ACCEPT - # ip6tables -P OUTPUT ACCEPT - # ip6tables -F + else + docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d $yuming --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + docker stop nginx > /dev/null 2>&1 - mkdir -p /home/web/certs/ - cp /etc/letsencrypt/live/$yuming/fullchain.pem /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - cp /etc/letsencrypt/live/$yuming/privkey.pem /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 + if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + fi - openssl rand -out /home/web/certs/ticket12.key 48 - openssl rand -out /home/web/certs/ticket13.key 80 - - docker start nginx > /dev/null 2>&1 + # iptables -P INPUT ACCEPT + # iptables -P FORWARD ACCEPT + # iptables -P OUTPUT ACCEPT + # iptables -F + # ip6tables -P INPUT ACCEPT + # ip6tables -P FORWARD ACCEPT + # ip6tables -P OUTPUT ACCEPT + # ip6tables -F + + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d $yuming --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa + + mkdir -p /home/web/certs/ + cp /etc/letsencrypt/live/$yuming/fullchain.pem /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + cp /etc/letsencrypt/live/$yuming/privkey.pem /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 + + openssl rand -out /home/web/certs/ticket12.key 48 + openssl rand -out /home/web/certs/ticket13.key 80 + + docker start nginx > /dev/null 2>&1 + + fi echo "证书已成功续签。" else From cffc8032054ed10fe4c2cce641b355921274ffaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:14:47 +0800 Subject: [PATCH 0541/1285] Change volume mount path for Certbot Docker run --- auto_cert_renewal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 660faab9b..758d76d01 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -45,7 +45,7 @@ for cert_file in $certs_directory*_cert.pem; do docker run --rm \ -v "/etc/letsencrypt:/etc/letsencrypt" \ -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ - -v "/var/www/letsencrypt:/var/www/letsencrypt" \ + -v "/home/web/letsencrypt:/var/www/letsencrypt" \ certbot/certbot certonly \ --webroot \ -w /var/www/letsencrypt \ From c215d1557ab9e240ace8ad6c43786970d3a9c21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:24:39 +0800 Subject: [PATCH 0542/1285] Update domain name for certbot command --- auto_cert_renewal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 758d76d01..287a3fe9d 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -49,7 +49,7 @@ for cert_file in $certs_directory*_cert.pem; do certbot/certbot certonly \ --webroot \ -w /var/www/letsencrypt \ - -d "lkyjp.kejilion.xyz" \ + -d "$yuming" \ --email your@email.com \ --agree-tos \ --no-eff-email \ From ad0a3aef45da227008e55bee6e15b9013c8fa7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:36:45 +0800 Subject: [PATCH 0543/1285] Update shell version and improve docker exec command --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ea4e5d3e9..127f66e2c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.2" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "进入容器" read -e -p "请输入容器名: " dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) From 04cbf85418376343d2e4d213eadea17f18ddab97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:37:26 +0800 Subject: [PATCH 0544/1285] Update shell version and improve docker exec command --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8af1295ad..7c3d9c006 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.2" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "进入容器" read -e -p "请输入容器名: " dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) From 92d281c00e4691734a2da1518299b90e462e7581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:40:27 +0800 Subject: [PATCH 0545/1285] Update kejilion_sh_log.txt for version 4.3.2 Added new features and fixes in version 4.3.2. --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 231f3143e..2945a0ab5 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1399,4 +1399,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场优化部分项目的git更新机制,解决国内拉取卡顿的问题。 基础工具中添加了目前流行的opencode编程AI助手可以在服务器上直接AI可视化开发编程。 ------------------------ +2026-01-13 v4.3.2 +对LDNMP站点和NGINX反代站点增加不停机续签域名SSL证书机制,老配置还是走端口申请证书。 +修复docker管理器无法进入容器的问题。 +------------------------ From bde21276a1b476ee0d6cf24bd09333f56ff5cb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 11:12:59 +0800 Subject: [PATCH 0546/1285] Disable iptables rules for HTTP traffic Comment out iptables rules for port 80 acceptance. --- auto_cert_renewal.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 287a3fe9d..976d0ff40 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -70,9 +70,9 @@ for cert_file in $certs_directory*_cert.pem; do docker stop nginx > /dev/null 2>&1 - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi + # if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then + # iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT + # fi # iptables -P INPUT ACCEPT # iptables -P FORWARD ACCEPT From 014f4509ededb9e75256bb10c39f5499b47c22c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 11:15:05 +0800 Subject: [PATCH 0547/1285] Remove volume mapping for letsencrypt data Removed volume mapping for /var/lib/letsencrypt in certbot command. --- auto_cert_renewal.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index 976d0ff40..baf58087f 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -44,7 +44,6 @@ for cert_file in $certs_directory*_cert.pem; do docker run --rm \ -v "/etc/letsencrypt:/etc/letsencrypt" \ - -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ -v "/home/web/letsencrypt:/var/www/letsencrypt" \ certbot/certbot certonly \ --webroot \ From ebfffccb2f1abd25730135b1fe87a07417c11f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:06:55 +0800 Subject: [PATCH 0548/1285] Refactor cn/kejilion.sh by removing blank lines Removed unnecessary blank lines and cleaned up code formatting. --- cn/kejilion.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7c3d9c006..38aabe80a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1425,15 +1425,9 @@ install_certbot() { } - - - - - - - install_ssltls() { docker stop nginx > /dev/null 2>&1 + check_port > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From ab1b7daeb38768bd3d0b614742986464abb8fdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:07:55 +0800 Subject: [PATCH 0549/1285] Refactor install_ssltls function and clean up code --- kejilion.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 127f66e2c..2b319bdc2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1425,15 +1425,9 @@ install_certbot() { } - - - - - - - install_ssltls() { docker stop nginx > /dev/null 2>&1 + check_port > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From e1df8328d02cf916464725294c32fe09149671d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:21:17 +0800 Subject: [PATCH 0550/1285] Delete domain configuration on exit Remove configuration file for the domain when exiting. --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 38aabe80a..9944f2872 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1611,6 +1611,7 @@ certs_status() { ;; *) send_stats "退出申请" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac From b8ed9f48ac94afe05dc4ff04497d88341ff16d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:21:55 +0800 Subject: [PATCH 0551/1285] Delete domain configuration on exit Remove configuration file for the specified domain when exiting. --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 2b319bdc2..7114f347a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1611,6 +1611,7 @@ certs_status() { ;; *) send_stats "退出申请" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac From b4b826c7b3bb4ae92463eda63da2c9166d5e2a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:32:21 +0800 Subject: [PATCH 0552/1285] Reorder SSL installation and certificate status checks Reorder install_ssltls and certs_status calls to ensure they are executed after modifying the configuration files. --- kejilion.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7114f347a..7a9c5c744 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3431,10 +3431,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3450,6 +3446,9 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3480,10 +3479,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3497,6 +3492,9 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on From 4ecc70bd7babd14c1ddd0bf698e62395e1093887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:33:19 +0800 Subject: [PATCH 0553/1285] Reorganize SSL installation and certificate status checks Reorder install_ssltls and certs_status calls to ensure they are executed after configuration updates. --- cn/kejilion.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9944f2872..323bb77a9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3431,10 +3431,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3450,6 +3446,9 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3480,10 +3479,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3497,6 +3492,9 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on From eca48f4184901495aae0454990ee369e2d6d61d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:45:23 +0800 Subject: [PATCH 0554/1285] Remove check_port call in install_ssltls function Remove check_port call before stopping nginx in install_ssltls function. --- cn/kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 323bb77a9..205195ada 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1427,7 +1427,6 @@ install_certbot() { install_ssltls() { docker stop nginx > /dev/null 2>&1 - check_port > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From 0ca18abd19500d2055e3e9229f1f33979c084072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:46:04 +0800 Subject: [PATCH 0555/1285] Remove check_port from install_ssltls function Remove check_port command before stopping nginx. --- kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 7a9c5c744..b59429b4a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1427,7 +1427,6 @@ install_certbot() { install_ssltls() { docker stop nginx > /dev/null 2>&1 - check_port > /dev/null 2>&1 cd ~ local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" From b78694b31cd01c5a272ec3e6debc393f3df0244b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 16 Jan 2026 23:11:49 +0800 Subject: [PATCH 0556/1285] Update version and improve port selection logic --- cn/kejilion.sh | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 205195ada..8b1cbd5a1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.2" +sh_v="4.3.3" gl_hui='\e[37m' @@ -2896,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3009,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install From 2fbcaf38636529e275802aa4de63a29bb43ac274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 16 Jan 2026 23:12:17 +0800 Subject: [PATCH 0557/1285] Update version and improve port selection logic --- kejilion.sh | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index b59429b4a..a44abc173 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.2" +sh_v="4.3.3" gl_hui='\e[37m' @@ -2896,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3009,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install From b9db23f75fdbd9d0b0e90a168661629ed591b76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 16 Jan 2026 23:13:52 +0800 Subject: [PATCH 0558/1285] Add port conflict detection for application installation Added port conflict detection mechanism during application market installation to prompt users to choose a different port if a conflict is found. --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2945a0ab5..7b8a7b8a3 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1403,4 +1403,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 对LDNMP站点和NGINX反代站点增加不停机续签域名SSL证书机制,老配置还是走端口申请证书。 修复docker管理器无法进入容器的问题。 ------------------------ +2026-01-16 v4.3.3 +应用市场安装时添加了访问端口冲突检测机制。发现端口冲突提示用户换一个端口。 +------------------------ From 49be7f352eb3e9b2f9a60a16e0299c199a616e43 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 18 Jan 2026 04:26:09 +0000 Subject: [PATCH 0559/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-01-18=2004:26:09?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 96 +++++++++++++++------------ jp/kejilion.sh | 176 ++++++++++++++++++++++++++----------------------- kr/kejilion.sh | 156 +++++++++++++++++++++++-------------------- tw/kejilion.sh | 64 ++++++++++-------- 4 files changed, 270 insertions(+), 222 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index c2f4a0387..7f764faaf 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.3" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "Enter the container" read -e -p "Please enter the container name:" dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # Create necessary directories and files - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') @@ -1425,15 +1425,7 @@ install_certbot() { } - - - - - - - install_ssltls() { - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1453,6 +1445,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1617,6 +1610,7 @@ certs_status() { ;; *) send_stats "Withdraw application" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac @@ -2902,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}mistake:${gl_bai}port$app_portAlready occupied, please change a port" + send_stats "Application port is occupied" + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3015,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}mistake:${gl_bai}port$app_portAlready occupied, please change a port" + send_stats "Application port is occupied" + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install @@ -3436,10 +3450,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3455,6 +3465,9 @@ ldnmp_Proxy() { sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3485,10 +3498,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3502,6 +3511,9 @@ ldnmp_Proxy_backend() { sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -4863,7 +4875,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" } @@ -4913,7 +4925,7 @@ echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -5797,7 +5809,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -6060,9 +6072,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6104,7 +6116,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -9666,7 +9678,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -11404,7 +11416,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -11739,7 +11751,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13484,7 +13496,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -14421,7 +14433,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14470,7 +14482,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14832,7 +14844,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14866,7 +14878,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14983,7 +14995,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15256,7 +15268,7 @@ echo "docker container management k docker ps |k docker container" echo "docker image management k docker img |k docker image" echo "LDNMP site management k web" echo "LDNMP cache cleaning k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "Install WordPress k wp | k wordpress | k wp xxx.com" echo "Install reverse proxy k fd |k rp |k reverse proxy |k fd xxx.com" echo "Install load balancing k loadbalance |k load balancing" echo "Install L4 load balancing k stream |k L4 load balancing" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 634379b25..4af379295 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.3" gl_hui='\e[37m' @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストールする$package...${gl_bai}" + echo -e "${gl_huang}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -526,7 +526,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "すべてのコンテナを削除する" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -540,13 +540,13 @@ while true; do esac ;; 9) - send_stats "すべてのコンテナを再起動します" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "コンテナに入る" + send_stats "进入容器" read -e -p "コンテナ名を入力してください:" dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) @@ -1186,7 +1186,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # 必要なディレクトリとファイルを作成する - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') @@ -1425,15 +1425,7 @@ install_certbot() { } - - - - - - - install_ssltls() { - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1453,6 +1445,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1617,6 +1610,7 @@ certs_status() { ;; *) send_stats "申請を取り下げる" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac @@ -1760,7 +1754,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2247,7 +2241,7 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -2902,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}間違い:${gl_bai}ポート$app_portすでに占有されています。ポートを変更してください" + send_stats "アプリケーションポートが占有されています" + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3015,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}間違い:${gl_bai}ポート$app_portすでに占有されています。ポートを変更してください" + send_stats "アプリケーションポートが占有されています" + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install @@ -3436,10 +3450,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3455,6 +3465,9 @@ ldnmp_Proxy() { sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3485,10 +3498,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3502,6 +3511,9 @@ ldnmp_Proxy_backend() { sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -4745,7 +4757,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4863,7 +4875,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" } @@ -4913,7 +4925,7 @@ echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion } @@ -5770,7 +5782,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -5797,7 +5809,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6060,9 +6072,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6104,7 +6116,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6192,7 +6204,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6392,9 +6404,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントする +# パーティションのマウント mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6413,7 +6425,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6544,7 +6556,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6573,7 +6585,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -6831,7 +6843,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6890,7 +6902,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7019,7 +7031,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7327,7 +7339,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-composeコンテナです${NC}" + echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7337,7 +7349,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" continue fi @@ -7504,7 +7516,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" mkdir -p /home/docker @@ -7529,7 +7541,7 @@ docker_ssh_migration() { read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲットサーバーの SSH ポート [デフォルト 22]:" TARGET_PORT + read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" @@ -8096,7 +8108,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8480,7 +8492,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9334,7 +9346,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -9344,7 +9356,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -10057,7 +10069,7 @@ while true; do } - local docker_describe="Onlyoffice は、非常に強力なオープンソースのオンライン オフィス ツールです。" + local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -10432,7 +10444,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、PDF ファイルに対して分割マージ、変換、再編成、画像の追加、回転、圧縮などのさまざまな操作を実行できます。" + local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、分割マージ、変換、再編成、画像の追加、回転、圧縮など、PDF ファイルに対してさまざまな操作を実行できます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10478,7 +10490,7 @@ while true; do } - local docker_describe="Sun-Panel サーバー、NAS ナビゲーション パネル、ホームページ、ブラウザーのホームページ" + local docker_describe="Sun-Panel サーバー、NAS ナビゲーション パネル、ホームページ、ブラウザー ホームページ" local docker_url="公式サイト紹介:https://doc.sun-panel.top/zh_cn/" local docker_use="echo 「アカウント: admin@sun.cc パスワード: 12345678」" local docker_passwd="" @@ -10531,7 +10543,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10860,7 +10872,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:https://github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -11162,8 +11174,8 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" - local app_url="公式ウェブサイト:https://github.com/infiniflow/ragflow" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_url="公式サイト:https://github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11679,7 +11691,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -11894,7 +11906,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:https://github.com/immich-app/immich" local docker_name="immich_server" @@ -12364,7 +12376,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -12476,7 +12488,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -12953,7 +12965,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス: https://github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -13133,7 +13145,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13887,7 +13899,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -13902,7 +13914,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14129,7 +14141,7 @@ EOF 1) read -e -p "新しい解析レコード形式を入力してください: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "ローカルホストの解像度が追加されました" + send_stats "ローカルホスト解像度が追加されました" ;; 2) @@ -14512,7 +14524,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -14832,7 +14844,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14861,12 +14873,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14906,7 +14918,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -14983,7 +14995,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -15189,7 +15201,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -15358,7 +15370,7 @@ else swap) shift - send_stats "仮想メモリをすばやくセットアップする" + send_stats "仮想メモリを素早く設定する" add_swap "$@" ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index eecc5ec6f..d606532cc 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.3" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "컨테이너를 입력하세요" read -e -p "컨테이너 이름을 입력하세요:" dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # 필요한 디렉토리 및 파일 생성 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') @@ -1425,15 +1425,7 @@ install_certbot() { } - - - - - - - install_ssltls() { - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1453,6 +1445,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1617,6 +1610,7 @@ certs_status() { ;; *) send_stats "신청철회" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac @@ -1848,7 +1842,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1862,7 +1856,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -2021,7 +2015,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2078,7 +2072,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2902,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." + send_stats "애플리케이션 포트가 점유되어 있습니다." + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3015,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." + send_stats "애플리케이션 포트가 점유되어 있습니다." + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install @@ -3436,10 +3450,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3455,6 +3465,9 @@ ldnmp_Proxy() { sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3485,10 +3498,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3502,6 +3511,9 @@ ldnmp_Proxy_backend() { sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3640,7 +3652,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4021,7 +4033,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4083,7 +4095,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4330,7 +4342,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4359,7 +4371,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." + echo "서버에 연결합니다. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4863,7 +4875,7 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -5291,7 +5303,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5301,7 +5313,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -5355,7 +5367,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5444,7 +5456,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5797,7 +5809,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -6004,7 +6016,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6243,7 +6255,7 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6591,7 +6603,7 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -7295,7 +7307,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -7337,7 +7349,7 @@ docker_ssh_migration() { # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 건너뛰세요...${NC}" + echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" continue fi @@ -7434,7 +7446,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7450,7 +7462,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리용기:$container${NC}" + echo -e "${GREEN}처리 용기:$container${NC}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7569,7 +7581,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8479,7 +8491,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8808,7 +8820,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf @@ -9336,7 +9348,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9356,7 +9368,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -9364,7 +9376,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -9666,7 +9678,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -10432,7 +10444,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -10936,7 +10948,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -12021,7 +12033,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" - local docker_passwd="echo \"초기 계정 : admin 초기 비밀번호 : abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" + local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -12047,7 +12059,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 홈페이지 소개: https://github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -12120,7 +12132,7 @@ while true; do local app_name="gitea 비공개 코드 저장소" local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." - local app_url="영상 소개: https://github.com/go-gitea/gitea" + local app_url="영상소개 : https://github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12619,7 +12631,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13245,7 +13257,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -13417,7 +13429,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -13430,7 +13442,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13717,7 +13729,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -13907,7 +13919,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -14276,7 +14288,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -14832,7 +14844,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14866,7 +14878,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -14980,10 +14992,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 8f711cf7e..f6ae09de0 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.1" +sh_v="4.3.3" gl_hui='\e[37m' @@ -546,7 +546,7 @@ while true; do 11) send_stats "進入容器" read -e -p "請輸入容器名:" dockername - docker exec $dockername /bin/sh + docker exec -it $dockername /bin/sh break_end ;; 12) @@ -1303,7 +1303,7 @@ ldnmp_v() { install_ldnmp_conf() { # 創建必要的目錄和文件 - cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx && touch web/docker-compose.yml + cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1325,7 +1325,7 @@ update_docker_compose_with_db_creds() { cp /home/web/docker-compose.yml /home/web/docker-compose1.yml - if ! grep -q "stream" /home/web/docker-compose.yml; then + if ! grep -q "letsencrypt" /home/web/docker-compose.yml; then wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose1.yml | tr -d '[:space:]') @@ -1425,15 +1425,7 @@ install_certbot() { } - - - - - - - install_ssltls() { - check_port > /dev/null 2>&1 docker stop nginx > /dev/null 2>&1 cd ~ @@ -1453,6 +1445,7 @@ install_ssltls() { if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT fi + docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1617,6 +1610,7 @@ certs_status() { ;; *) send_stats "退出申請" + rm -f /home/web/conf.d/${yuming}.conf exit ;; esac @@ -2902,9 +2896,18 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + while true; do + read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}錯誤:${gl_bai}端口$app_port已被佔用,請更換一個端口" + send_stats "應用端口已被佔用" + else + local docker_port=$app_port + break + fi + done install jq install_docker @@ -3015,9 +3018,20 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port - local app_port=${app_port:-${docker_port}} - local docker_port=$app_port + + while true; do + read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + local app_port=${app_port:-${docker_port}} + + if ss -tuln | grep -q ":$app_port "; then + echo -e "${gl_hong}錯誤:${gl_bai}端口$app_port已被佔用,請更換一個端口" + send_stats "應用端口已被佔用" + else + local docker_port=$app_port + break + fi + done + install jq install_docker docker_app_install @@ -3436,10 +3450,6 @@ ldnmp_Proxy() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - install_ssltls - certs_status - - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3455,6 +3465,9 @@ ldnmp_Proxy() { sed -i "s/# 動態添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3485,10 +3498,6 @@ ldnmp_Proxy_backend() { wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf - - install_ssltls - certs_status - backend=$(tr -dc 'A-Za-z' < /dev/urandom | head -c 8) sed -i "s/backend_yuming_com/backend_$backend/g" /home/web/conf.d/"$yuming".conf @@ -3502,6 +3511,9 @@ ldnmp_Proxy_backend() { sed -i "s/# 動態添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + install_ssltls + certs_status + update_nginx_listen_port "$yuming" "$access_port" nginx_http_on From 44b49c62057d6dace1d4af7b1f4b949863014033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:44:37 +0800 Subject: [PATCH 0560/1285] Update ISP check to include CHINANET --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8b1cbd5a1..b353ca29b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -3018,7 +3018,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} From e5afa7b5007892a105a30653f731a98b8828a642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:45:35 +0800 Subject: [PATCH 0561/1285] Update ISP check and cleanup code structure --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a44abc173..1abb54460 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -3018,7 +3018,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} From 111f768258ca7e07e41329175e6b87c845146495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:12:39 +0800 Subject: [PATCH 0562/1285] Update script version and add GitHub SSH key fetching --- cn/kejilion.sh | 136 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b353ca29b..f5ee0e876 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -4909,6 +4909,123 @@ import_sshkey() { +# 函数:从 GitHub 拉取 SSH 公钥并添加到 authorized_keys +# 用法示例: +# fetch_github_ssh_keys +fetch_github_ssh_keys() { + + local username + local keys_url + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + echo "此脚本将从 GitHub 拉取您的 SSH 公钥,并添加到 ${authorized_keys}" + echo "" + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" + echo " 1. 登录 https://github.com/settings/keys" + echo " 2. 点击 New SSH key 或 Add SSH key" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo " 5. 点击 Add SSH key 完成添加" + echo "" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " https://github.com/您的用户名.keys" + echo "" + + # 提示用户输入 GitHub 用户名 + read -r -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + echo "错误:用户名不能为空" >&2 + return 1 + fi + + # 构造 GitHub 公开公钥地址 + keys_url="https://github.com/${username}.keys" + + echo "" + echo "即将从以下地址拉取公钥:" + echo " ${keys_url}" + echo "" + + # 创建临时文件 + temp_file=$(mktemp) + + # 尝试下载公钥 + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + return 1 + fi + + # 检查是否下载到有效内容 + if [[ ! -s "${temp_file}" ]]; then + echo "错误:下载到的文件为空,可能是用户名错误或该账户未添加任何公钥" >&2 + rm -f "${temp_file}" + return 1 + fi + + # 确保 .ssh 目录存在且权限正确 + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + + # 备份原有 authorized_keys(如果存在) + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "已备份原有 authorized_keys 文件" + fi + + # 追加新公钥(避免重复添加) + local added=0 + while IFS= read -r line; do + # 跳过空行和注释行 + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + # 检查是否已存在 + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + # 清理临时文件 + rm -f "${temp_file}" + + # 设置正确权限 + chmod 600 "${authorized_keys}" 2>/dev/null + + echo "" + if (( added > 0 )); then + echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "没有新的公钥需要添加(可能已全部存在)" + fi + + echo "操作完成。您现在可以使用对应的私钥通过 SSH 登录此账户。" + echo "" +} + + + + add_sshpasswd() { @@ -14245,7 +14362,7 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 生成新密钥 2. 导入已有密钥 3. 导入GitHub远端密钥 4. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -14258,13 +14375,22 @@ EOF break_end ;; - 2) + + 3) send_stats "导入已有公钥" - import_sshkey + fetch_github_ssh_keys break_end ;; + + 3) + send_stats "导入GitHub远端公钥" + import_sshkey + break_end + + ;; + 4) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From 2d4a675f41e3b6b38bc8bd6bbf3f02ab68f698a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:13:20 +0800 Subject: [PATCH 0563/1285] Implement fetch_github_ssh_keys function Add function to fetch GitHub SSH keys and update options --- kejilion.sh | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1abb54460..f5ee0e876 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -4909,6 +4909,123 @@ import_sshkey() { +# 函数:从 GitHub 拉取 SSH 公钥并添加到 authorized_keys +# 用法示例: +# fetch_github_ssh_keys +fetch_github_ssh_keys() { + + local username + local keys_url + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + echo "此脚本将从 GitHub 拉取您的 SSH 公钥,并添加到 ${authorized_keys}" + echo "" + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" + echo " 1. 登录 https://github.com/settings/keys" + echo " 2. 点击 New SSH key 或 Add SSH key" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo " 5. 点击 Add SSH key 完成添加" + echo "" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " https://github.com/您的用户名.keys" + echo "" + + # 提示用户输入 GitHub 用户名 + read -r -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + echo "错误:用户名不能为空" >&2 + return 1 + fi + + # 构造 GitHub 公开公钥地址 + keys_url="https://github.com/${username}.keys" + + echo "" + echo "即将从以下地址拉取公钥:" + echo " ${keys_url}" + echo "" + + # 创建临时文件 + temp_file=$(mktemp) + + # 尝试下载公钥 + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + return 1 + fi + + # 检查是否下载到有效内容 + if [[ ! -s "${temp_file}" ]]; then + echo "错误:下载到的文件为空,可能是用户名错误或该账户未添加任何公钥" >&2 + rm -f "${temp_file}" + return 1 + fi + + # 确保 .ssh 目录存在且权限正确 + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + + # 备份原有 authorized_keys(如果存在) + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "已备份原有 authorized_keys 文件" + fi + + # 追加新公钥(避免重复添加) + local added=0 + while IFS= read -r line; do + # 跳过空行和注释行 + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + # 检查是否已存在 + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + # 清理临时文件 + rm -f "${temp_file}" + + # 设置正确权限 + chmod 600 "${authorized_keys}" 2>/dev/null + + echo "" + if (( added > 0 )); then + echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "没有新的公钥需要添加(可能已全部存在)" + fi + + echo "操作完成。您现在可以使用对应的私钥通过 SSH 登录此账户。" + echo "" +} + + + + add_sshpasswd() { @@ -14245,7 +14362,7 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 查看本机密钥" + echo "1. 生成新密钥 2. 导入已有密钥 3. 导入GitHub远端密钥 4. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -14258,13 +14375,22 @@ EOF break_end ;; - 2) + + 3) send_stats "导入已有公钥" - import_sshkey + fetch_github_ssh_keys break_end ;; + + 3) + send_stats "导入GitHub远端公钥" + import_sshkey + break_end + + ;; + 4) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From 4bce79bdb44bf32519762060be04830ad819c6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:15:39 +0800 Subject: [PATCH 0564/1285] Add version 4.3.4 release notes --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 7b8a7b8a3..58dd3b041 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1406,4 +1406,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-01-16 v4.3.3 应用市场安装时添加了访问端口冲突检测机制。发现端口冲突提示用户换一个端口。 ------------------------ +2026-01-21 v4.3.4 +系统工具中SSH密钥登录新增GitHub远端公钥导入功能。 +------------------------ From c7dbe8cf596d0297995f2e1d6ae37cdfd1bf9699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:19:00 +0800 Subject: [PATCH 0565/1285] Change default parameter and update keys URL --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f5ee0e876..1c54a4ccb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -4941,7 +4941,7 @@ fetch_github_ssh_keys() { fi # 构造 GitHub 公开公钥地址 - keys_url="https://github.com/${username}.keys" + keys_url="${gh_proxy}github.com/${username}.keys" echo "" echo "即将从以下地址拉取公钥:" From a9c78bb60d3e84ecbc6a1a33b4990de839eca594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:19:48 +0800 Subject: [PATCH 0566/1285] Update GitHub keys URL to use proxy --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index f5ee0e876..28008e8f0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4941,7 +4941,7 @@ fetch_github_ssh_keys() { fi # 构造 GitHub 公开公钥地址 - keys_url="https://github.com/${username}.keys" + keys_url="${gh_proxy}github.com/${username}.keys" echo "" echo "即将从以下地址拉取公钥:" From 10c0d1b61d7aec376f7b1b7bdb69b32ce4f7facb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:01:16 +0800 Subject: [PATCH 0567/1285] Update GitHub keys URL to use HTTPS --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1c54a4ccb..4a2b24ccf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4941,7 +4941,7 @@ fetch_github_ssh_keys() { fi # 构造 GitHub 公开公钥地址 - keys_url="${gh_proxy}github.com/${username}.keys" + keys_url="https://github.com/${username}.keys" echo "" echo "即将从以下地址拉取公钥:" From 7f07e4cdff1e1a7d6e7c5c419e71f83e710ddf96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:02:22 +0800 Subject: [PATCH 0568/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 28008e8f0..f5ee0e876 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4941,7 +4941,7 @@ fetch_github_ssh_keys() { fi # 构造 GitHub 公开公钥地址 - keys_url="${gh_proxy}github.com/${username}.keys" + keys_url="https://github.com/${username}.keys" echo "" echo "即将从以下地址拉取公钥:" From 2b25269d02d6912ea7c3d1a5dfde930207a0aa02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:48:26 +0800 Subject: [PATCH 0569/1285] Fix .ssh directory creation and permissions Ensure .ssh directory exists and set permissions. --- cn/kejilion.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4a2b24ccf..d88f2dca3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4976,9 +4976,10 @@ fetch_github_ssh_keys() { return 1 fi - # 确保 .ssh 目录存在且权限正确 - mkdir -p "${HOME}/.ssh" - chmod 700 "${HOME}/.ssh" + chmod 700 ~/ + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch ~/.ssh/authorized_keys # 备份原有 authorized_keys(如果存在) if [[ -f "${authorized_keys}" ]]; then @@ -8925,6 +8926,7 @@ linux_ldnmp() { echo "已阻止IP+端口访问该服务" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -15481,6 +15483,7 @@ else echo "已阻止IP+端口访问该服务" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; From 26a5d26768d884ecce62db56512d9b0a66035512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:49:20 +0800 Subject: [PATCH 0570/1285] Ensure .ssh directory exists with correct permissions Refactor SSH directory creation and permissions. --- kejilion.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f5ee0e876..0f8c6dd3a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4976,9 +4976,10 @@ fetch_github_ssh_keys() { return 1 fi - # 确保 .ssh 目录存在且权限正确 - mkdir -p "${HOME}/.ssh" - chmod 700 "${HOME}/.ssh" + chmod 700 ~/ + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch ~/.ssh/authorized_keys # 备份原有 authorized_keys(如果存在) if [[ -f "${authorized_keys}" ]]; then @@ -8925,6 +8926,7 @@ linux_ldnmp() { echo "已阻止IP+端口访问该服务" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -15481,6 +15483,7 @@ else echo "已阻止IP+端口访问该服务" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; From 27218d5653179cb726f807589aca29af856b5f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:59:45 +0800 Subject: [PATCH 0571/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 58dd3b041..2f7cd8d60 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1408,5 +1408,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 ------------------------ 2026-01-21 v4.3.4 系统工具中SSH密钥登录新增GitHub远端公钥导入功能。 +站点反向代理后兼容对后端容器为host网络的服务IP+端口的处理。 ------------------------ From 0369926e7e9d6589521b8b7ae1c543a7f58d772c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:09:45 +0800 Subject: [PATCH 0572/1285] Enhance ROOT private key login mode with status check Added a check for PubkeyAuthentication status and updated the output message accordingly. --- cn/kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d88f2dca3..04d3741c6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14359,7 +14359,16 @@ EOF send_stats "私钥登录" while true; do clear - echo "ROOT私钥登录模式" + + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" + fi + + echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" From 3a91e9d596f10c474f8bef227c64d0740e35aa03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:10:27 +0800 Subject: [PATCH 0573/1285] Enhance ROOT login mode with key authentication check Add check for PubkeyAuthentication status in ROOT login mode. --- kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 0f8c6dd3a..fba3452bd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14359,7 +14359,16 @@ EOF send_stats "私钥登录" while true; do clear - echo "ROOT私钥登录模式" + + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" + fi + + echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" From fe37354ad826ecb9f0fa35f30b869cd53e708b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:11:38 +0800 Subject: [PATCH 0574/1285] Enhance ROOT key login feature with status display Added status display for enabled and disabled ROOT key login feature. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2f7cd8d60..bcff63a94 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1409,5 +1409,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-01-21 v4.3.4 系统工具中SSH密钥登录新增GitHub远端公钥导入功能。 站点反向代理后兼容对后端容器为host网络的服务IP+端口的处理。 +系统工具ROOT密钥登录功能增加了启用和未启用的状态显示功能。 ------------------------ From 5a01553a9d5ea8c3e2e270cabf6ea9af6330f56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:20:00 +0800 Subject: [PATCH 0575/1285] Swap import and fetch functions for SSH keys --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 04d3741c6..45867912f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14387,9 +14387,9 @@ EOF ;; - 3) + 2) send_stats "导入已有公钥" - fetch_github_ssh_keys + import_sshkey break_end ;; @@ -14397,7 +14397,7 @@ EOF 3) send_stats "导入GitHub远端公钥" - import_sshkey + fetch_github_ssh_keys break_end ;; From 83d5f5beed08675e6e279a34deb4b346157857e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:20:43 +0800 Subject: [PATCH 0576/1285] Swap functions for importing SSH keys --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fba3452bd..836f5b46c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14387,9 +14387,9 @@ EOF ;; - 3) + 2) send_stats "导入已有公钥" - fetch_github_ssh_keys + import_sshkey break_end ;; @@ -14397,7 +14397,7 @@ EOF 3) send_stats "导入GitHub远端公钥" - import_sshkey + fetch_github_ssh_keys break_end ;; From 1d56aa572665f72d2f34a61064b6947d95ec65cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:39:04 +0800 Subject: [PATCH 0577/1285] Refactor SSH key fetching functions and prompts --- cn/kejilion.sh | 117 ++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 45867912f..4d8ceb7e7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "首次使用脚本,请先阅读并同意用户许可协议。" echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -e -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -4909,103 +4909,79 @@ import_sshkey() { -# 函数:从 GitHub 拉取 SSH 公钥并添加到 authorized_keys -# 用法示例: -# fetch_github_ssh_keys -fetch_github_ssh_keys() { - local username - local keys_url +fetch_remote_ssh_keys() { + + local keys_url="$1" local authorized_keys="${HOME}/.ssh/authorized_keys" local temp_file - echo "此脚本将从 GitHub 拉取您的 SSH 公钥,并添加到 ${authorized_keys}" - echo "" - echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo " 1. 登录 https://github.com/settings/keys" - echo " 2. 点击 New SSH key 或 Add SSH key" - echo " 3. Title 可随意填写(例如:Home Laptop 2026)" - echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" - echo " 5. 点击 Add SSH key 完成添加" - echo "" - echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " https://github.com/您的用户名.keys" - echo "" - - # 提示用户输入 GitHub 用户名 - read -r -p "请输入您的 GitHub 用户名(username,不含 @): " username - - if [[ -z "${username}" ]]; then - echo "错误:用户名不能为空" >&2 + if [[ -z "${keys_url}" ]]; then + echo "错误:必须提供公钥 URL" + echo "用法示例:" + echo " fetch_remote_ssh_keys https://example.com/keys.txt" return 1 fi - # 构造 GitHub 公开公钥地址 - keys_url="https://github.com/${username}.keys" - + echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" echo "" - echo "即将从以下地址拉取公钥:" + echo "远程公钥地址:" echo " ${keys_url}" echo "" # 创建临时文件 temp_file=$(mktemp) - # 尝试下载公钥 + # 下载公钥 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } else echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + rm -f "${temp_file}" return 1 fi - # 检查是否下载到有效内容 + # 检查内容是否有效 if [[ ! -s "${temp_file}" ]]; then - echo "错误:下载到的文件为空,可能是用户名错误或该账户未添加任何公钥" >&2 + echo "错误:下载到的文件为空,URL 可能不包含任何公钥" >&2 rm -f "${temp_file}" return 1 fi - chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" - # 备份原有 authorized_keys(如果存在) + # 备份原有 authorized_keys if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" echo "已备份原有 authorized_keys 文件" fi - # 追加新公钥(避免重复添加) + # 追加公钥(避免重复) local added=0 while IFS= read -r line; do - # 跳过空行和注释行 [[ -z "${line}" || "${line}" =~ ^# ]] && continue - # 检查是否已存在 if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then echo "${line}" >> "${authorized_keys}" ((added++)) fi done < "${temp_file}" - # 清理临时文件 rm -f "${temp_file}" - # 设置正确权限 - chmod 600 "${authorized_keys}" 2>/dev/null - echo "" if (( added > 0 )); then echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" @@ -5020,12 +4996,41 @@ fetch_github_ssh_keys() { echo "没有新的公钥需要添加(可能已全部存在)" fi - echo "操作完成。您现在可以使用对应的私钥通过 SSH 登录此账户。" echo "" } +fetch_github_ssh_keys() { + + + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" + echo " 1. 登录 https://github.com/settings/keys" + echo " 2. 点击 New SSH key 或 Add SSH key" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo " 5. 点击 Add SSH key 完成添加" + echo "" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " https://github.com/您的用户名.keys" + echo "" + + # 提示用户输入 GitHub 用户名 + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + echo "错误:GitHub 用户名不能为空" >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + add_sshpasswd() { @@ -6200,7 +6205,7 @@ create_backup() { echo " - 备份单个目录: /var/www" echo " - 备份多个目录: /etc /home /var/log" echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then @@ -9400,11 +9405,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -13234,11 +13239,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -14373,7 +14378,9 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 导入GitHub远端密钥 4. 查看本机密钥" + echo "1. 生成新密钥 2. 手动输入已有SSH密钥" + echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" + echo "5. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -14401,7 +14408,15 @@ EOF break_end ;; + 4) + send_stats "导入URL远端公钥" + read -e -p "请输入您的远端公钥URL: " keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From 7221d304ab2e889a7a5c43707c7ed49f9e5a5b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:39:35 +0800 Subject: [PATCH 0578/1285] Refactor SSH key fetching functions and prompts --- kejilion.sh | 117 +++++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 836f5b46c..33528eda9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "首次使用脚本,请先阅读并同意用户许可协议。" echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上条款?(y/n): " user_input + read -e -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -4909,103 +4909,79 @@ import_sshkey() { -# 函数:从 GitHub 拉取 SSH 公钥并添加到 authorized_keys -# 用法示例: -# fetch_github_ssh_keys -fetch_github_ssh_keys() { - local username - local keys_url +fetch_remote_ssh_keys() { + + local keys_url="$1" local authorized_keys="${HOME}/.ssh/authorized_keys" local temp_file - echo "此脚本将从 GitHub 拉取您的 SSH 公钥,并添加到 ${authorized_keys}" - echo "" - echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo " 1. 登录 https://github.com/settings/keys" - echo " 2. 点击 New SSH key 或 Add SSH key" - echo " 3. Title 可随意填写(例如:Home Laptop 2026)" - echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" - echo " 5. 点击 Add SSH key 完成添加" - echo "" - echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " https://github.com/您的用户名.keys" - echo "" - - # 提示用户输入 GitHub 用户名 - read -r -p "请输入您的 GitHub 用户名(username,不含 @): " username - - if [[ -z "${username}" ]]; then - echo "错误:用户名不能为空" >&2 + if [[ -z "${keys_url}" ]]; then + echo "错误:必须提供公钥 URL" + echo "用法示例:" + echo " fetch_remote_ssh_keys https://example.com/keys.txt" return 1 fi - # 构造 GitHub 公开公钥地址 - keys_url="https://github.com/${username}.keys" - + echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" echo "" - echo "即将从以下地址拉取公钥:" + echo "远程公钥地址:" echo " ${keys_url}" echo "" # 创建临时文件 temp_file=$(mktemp) - # 尝试下载公钥 + # 下载公钥 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "错误:无法从 GitHub 下载公钥(网络问题或用户名不存在)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } else echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + rm -f "${temp_file}" return 1 fi - # 检查是否下载到有效内容 + # 检查内容是否有效 if [[ ! -s "${temp_file}" ]]; then - echo "错误:下载到的文件为空,可能是用户名错误或该账户未添加任何公钥" >&2 + echo "错误:下载到的文件为空,URL 可能不包含任何公钥" >&2 rm -f "${temp_file}" return 1 fi - chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" - # 备份原有 authorized_keys(如果存在) + # 备份原有 authorized_keys if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" echo "已备份原有 authorized_keys 文件" fi - # 追加新公钥(避免重复添加) + # 追加公钥(避免重复) local added=0 while IFS= read -r line; do - # 跳过空行和注释行 [[ -z "${line}" || "${line}" =~ ^# ]] && continue - # 检查是否已存在 if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then echo "${line}" >> "${authorized_keys}" ((added++)) fi done < "${temp_file}" - # 清理临时文件 rm -f "${temp_file}" - # 设置正确权限 - chmod 600 "${authorized_keys}" 2>/dev/null - echo "" if (( added > 0 )); then echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" @@ -5020,12 +4996,41 @@ fetch_github_ssh_keys() { echo "没有新的公钥需要添加(可能已全部存在)" fi - echo "操作完成。您现在可以使用对应的私钥通过 SSH 登录此账户。" echo "" } +fetch_github_ssh_keys() { + + + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" + echo " 1. 登录 https://github.com/settings/keys" + echo " 2. 点击 New SSH key 或 Add SSH key" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo " 5. 点击 Add SSH key 完成添加" + echo "" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " https://github.com/您的用户名.keys" + echo "" + + # 提示用户输入 GitHub 用户名 + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + echo "错误:GitHub 用户名不能为空" >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + add_sshpasswd() { @@ -6200,7 +6205,7 @@ create_backup() { echo " - 备份单个目录: /var/www" echo " - 备份多个目录: /etc /home /var/log" echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -r -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then @@ -9400,11 +9405,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -13234,11 +13239,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -14373,7 +14378,9 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 导入已有密钥 3. 导入GitHub远端密钥 4. 查看本机密钥" + echo "1. 生成新密钥 2. 手动输入已有SSH密钥" + echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" + echo "5. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -14401,7 +14408,15 @@ EOF break_end ;; + 4) + send_stats "导入URL远端公钥" + read -e -p "请输入您的远端公钥URL: " keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From 1848f4121b3920d7074be31f9cf000c1870c1652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:41:19 +0800 Subject: [PATCH 0579/1285] Enhance ROOT key login with URL import and menu optimization Added functionality to import public keys from a URL and optimized the interactive menu and descriptions for the ROOT key login feature. --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index bcff63a94..055c7c189 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1410,5 +1410,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具中SSH密钥登录新增GitHub远端公钥导入功能。 站点反向代理后兼容对后端容器为host网络的服务IP+端口的处理。 系统工具ROOT密钥登录功能增加了启用和未启用的状态显示功能。 +系统工具ROOT密钥登录功能增加了从URL导入公钥的功能。 +系统工具ROOT密钥登录功能交互菜单和表述进行优化。 ------------------------ From 2eb0333c86d9676aa107e8689e55a8280b1a4de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:54:55 +0800 Subject: [PATCH 0580/1285] Implement SSH key import command Add SSH public key import functionality with a URL option. --- cn/kejilion.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4d8ceb7e7..6bc04d5f0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -15434,6 +15434,8 @@ echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" +echo "SSH公钥导入(URL) k sshkey https://github.com/torvalds.keys" + } @@ -15670,8 +15672,16 @@ else fail2ban_panel ;; + + sshkey) + shift + send_stats "导入URL远端公钥" + fetch_remote_ssh_keys "$@" + *) k_info ;; esac fi + + From e73129acefc1282683943c1db18b7d8251acc2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:55:47 +0800 Subject: [PATCH 0581/1285] Implement SSH key import command Add SSH key import functionality with remote URL support. --- kejilion.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 33528eda9..f29f4b017 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -15434,6 +15434,8 @@ echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" +echo "SSH公钥导入(URL) k sshkey https://github.com/torvalds.keys" + } @@ -15670,8 +15672,16 @@ else fail2ban_panel ;; + + sshkey) + shift + send_stats "导入URL远端公钥" + fetch_remote_ssh_keys "$@" + *) k_info ;; esac fi + + From 254336663165dfb5b3b83ec6fca4f263db5c22b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:57:20 +0800 Subject: [PATCH 0582/1285] Add shortcut command for SSH key import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增k sshkey url 快捷命令 支持快速导入SSH公钥并开启SSH密钥登录模式。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 055c7c189..1a8c62093 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1412,5 +1412,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具ROOT密钥登录功能增加了启用和未启用的状态显示功能。 系统工具ROOT密钥登录功能增加了从URL导入公钥的功能。 系统工具ROOT密钥登录功能交互菜单和表述进行优化。 +新增k sshkey url 快捷命令 支持快速导入SSH公钥并开启SSH密钥登录模式。 ------------------------ From 15fc2793b90a2692b8e4f13b299738e9add03205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 22:11:59 +0800 Subject: [PATCH 0583/1285] Add case for importing remote SSH keys --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6bc04d5f0..c2608d9f3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -15677,6 +15677,7 @@ else shift send_stats "导入URL远端公钥" fetch_remote_ssh_keys "$@" + ;; *) k_info From efb8dd36420f0f2f70d72c5903380377971148bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 22:12:27 +0800 Subject: [PATCH 0584/1285] Add case for importing remote SSH keys --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index f29f4b017..519aec858 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -15677,6 +15677,7 @@ else shift send_stats "导入URL远端公钥" fetch_remote_ssh_keys "$@" + ;; *) k_info From f68aeecee47dd31d9dd47413de9af8c5369567ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 22:39:27 +0800 Subject: [PATCH 0585/1285] Update SSH key prompt message for clarity --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c2608d9f3..c39338ff7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14378,7 +14378,7 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有SSH密钥" + echo "1. 生成新密钥 2. 手动输入已有密钥" echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" echo "5. 查看本机密钥" echo "------------------------" From 92d2744dd1b70130d7fec773159e614a292347da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 24 Jan 2026 22:39:56 +0800 Subject: [PATCH 0586/1285] Update echo message for existing SSH key input --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 519aec858..8f8e923e7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14378,7 +14378,7 @@ EOF echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有SSH密钥" + echo "1. 生成新密钥 2. 手动输入已有密钥" echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" echo "5. 查看本机密钥" echo "------------------------" From 17a86ed22683ff9cfb960f01004fc71288e0fee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:21:51 +0800 Subject: [PATCH 0587/1285] Refactor SSH key management and add interactive menu --- cn/kejilion.sh | 197 +++++++++++++++++++++++++++---------------------- 1 file changed, 109 insertions(+), 88 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c39338ff7..a4da69629 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4917,10 +4916,7 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - echo "错误:必须提供公钥 URL" - echo "用法示例:" - echo " fetch_remote_ssh_keys https://example.com/keys.txt" - return 1 + read -e -p "请输入您的远端公钥URL: " keys_url fi echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" @@ -5003,6 +4999,7 @@ fetch_remote_ssh_keys() { fetch_github_ssh_keys() { + local username="$1" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" echo " 1. 登录 https://github.com/settings/keys" @@ -5015,8 +5012,10 @@ fetch_github_ssh_keys() { echo " https://github.com/您的用户名.keys" echo "" - # 提示用户输入 GitHub 用户名 - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + fi if [[ -z "${username}" ]]; then echo "错误:GitHub 用户名不能为空" >&2 @@ -5032,6 +5031,77 @@ fetch_github_ssh_keys() { +sshkey_panel() { + + root_use + send_stats "私钥登录" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" + fi + echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "将会生成密钥对,更安全的方式SSH登录" + echo "------------------------" + echo "1. 生成新密钥 2. 手动输入已有密钥" + echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" + echo "5. 查看本机密钥" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "请输入你的选择: " host_dns + case $host_dns in + 1) + send_stats "生成新密钥" + add_sshkey + break_end + ;; + 2) + send_stats "导入已有公钥" + import_sshkey + break_end + ;; + 3) + send_stats "导入GitHub远端公钥" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "导入URL远端公钥" + read -e -p "请输入您的远端公钥URL: " keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + 5) + send_stats "查看本机密钥" + echo "------------------------" + echo "公钥信息" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "私钥信息" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + + add_sshpasswd() { @@ -14359,81 +14429,7 @@ EOF 24) - - root_use - send_stats "私钥登录" - while true; do - clear - - local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') - - if [[ "$REAL_STATUS" =~ "yes" ]]; then - IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" - else - IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" - fi - - echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" - echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有密钥" - echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" - echo "5. 查看本机密钥" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "请输入你的选择: " host_dns - - case $host_dns in - 1) - send_stats "生成新密钥" - add_sshkey - break_end - - ;; - - 2) - send_stats "导入已有公钥" - import_sshkey - break_end - - ;; - - - 3) - send_stats "导入GitHub远端公钥" - fetch_github_ssh_keys - break_end - - ;; - - 4) - send_stats "导入URL远端公钥" - read -e -p "请输入您的远端公钥URL: " keys_url - fetch_remote_ssh_keys "${keys_url}" - break_end - ;; - - 5) - send_stats "查看本机密钥" - echo "------------------------" - echo "公钥信息" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "私钥信息" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) @@ -15434,7 +15430,9 @@ echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" -echo "SSH公钥导入(URL) k sshkey https://github.com/torvalds.keys" +echo "ROOT密钥管理 k sshkey" +echo "SSH公钥导入(URL) k sshkey " +echo "SSH公钥导入(GitHub) k sshkey github " } @@ -15674,11 +15672,34 @@ else sshkey) - shift - send_stats "导入URL远端公钥" - fetch_remote_ssh_keys "$@" + shift + case "$1" in + "" ) + # sshkey → 交互菜单 + send_stats "SSHKey 交互菜单" + sshkey_panel + ;; + + github ) + shift + send_stats "从 GitHub 导入 SSH 公钥" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "从 URL 导入 SSH 公钥" + fetch_remote_ssh_keys "$1" + ;; + + * ) + echo "错误:未知参数 '$1'" + echo "用法:" + echo " k sshkey 进入交互菜单" + echo " k sshkey 从 URL 导入 SSH 公钥" + echo " k sshkey github 从 GitHub 导入 SSH 公钥" + ;; + esac ;; - *) k_info ;; From d83ffcf13304bd8b6f44df5da794496eee366a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:22:40 +0800 Subject: [PATCH 0588/1285] Refactor SSH key management functions --- kejilion.sh | 197 +++++++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 88 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8f8e923e7..b8f23f76c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4917,10 +4916,7 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - echo "错误:必须提供公钥 URL" - echo "用法示例:" - echo " fetch_remote_ssh_keys https://example.com/keys.txt" - return 1 + read -e -p "请输入您的远端公钥URL: " keys_url fi echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" @@ -5003,6 +4999,7 @@ fetch_remote_ssh_keys() { fetch_github_ssh_keys() { + local username="$1" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" echo " 1. 登录 https://github.com/settings/keys" @@ -5015,8 +5012,10 @@ fetch_github_ssh_keys() { echo " https://github.com/您的用户名.keys" echo "" - # 提示用户输入 GitHub 用户名 - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + + if [[ -z "${username}" ]]; then + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + fi if [[ -z "${username}" ]]; then echo "错误:GitHub 用户名不能为空" >&2 @@ -5032,6 +5031,77 @@ fetch_github_ssh_keys() { +sshkey_panel() { + + root_use + send_stats "私钥登录" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" + fi + echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" + echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "将会生成密钥对,更安全的方式SSH登录" + echo "------------------------" + echo "1. 生成新密钥 2. 手动输入已有密钥" + echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" + echo "5. 查看本机密钥" + echo "------------------------" + echo "0. 返回上一级选单" + echo "------------------------" + read -e -p "请输入你的选择: " host_dns + case $host_dns in + 1) + send_stats "生成新密钥" + add_sshkey + break_end + ;; + 2) + send_stats "导入已有公钥" + import_sshkey + break_end + ;; + 3) + send_stats "导入GitHub远端公钥" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "导入URL远端公钥" + read -e -p "请输入您的远端公钥URL: " keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + 5) + send_stats "查看本机密钥" + echo "------------------------" + echo "公钥信息" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "私钥信息" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + + add_sshpasswd() { @@ -14359,81 +14429,7 @@ EOF 24) - - root_use - send_stats "私钥登录" - while true; do - clear - - local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') - - if [[ "$REAL_STATUS" =~ "yes" ]]; then - IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" - else - IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" - fi - - echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" - echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有密钥" - echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" - echo "5. 查看本机密钥" - echo "------------------------" - echo "0. 返回上一级选单" - echo "------------------------" - read -e -p "请输入你的选择: " host_dns - - case $host_dns in - 1) - send_stats "生成新密钥" - add_sshkey - break_end - - ;; - - 2) - send_stats "导入已有公钥" - import_sshkey - break_end - - ;; - - - 3) - send_stats "导入GitHub远端公钥" - fetch_github_ssh_keys - break_end - - ;; - - 4) - send_stats "导入URL远端公钥" - read -e -p "请输入您的远端公钥URL: " keys_url - fetch_remote_ssh_keys "${keys_url}" - break_end - ;; - - 5) - send_stats "查看本机密钥" - echo "------------------------" - echo "公钥信息" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "私钥信息" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) @@ -15434,7 +15430,9 @@ echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "显示系统信息 k info" -echo "SSH公钥导入(URL) k sshkey https://github.com/torvalds.keys" +echo "ROOT密钥管理 k sshkey" +echo "SSH公钥导入(URL) k sshkey " +echo "SSH公钥导入(GitHub) k sshkey github " } @@ -15674,11 +15672,34 @@ else sshkey) - shift - send_stats "导入URL远端公钥" - fetch_remote_ssh_keys "$@" + shift + case "$1" in + "" ) + # sshkey → 交互菜单 + send_stats "SSHKey 交互菜单" + sshkey_panel + ;; + + github ) + shift + send_stats "从 GitHub 导入 SSH 公钥" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "从 URL 导入 SSH 公钥" + fetch_remote_ssh_keys "$1" + ;; + + * ) + echo "错误:未知参数 '$1'" + echo "用法:" + echo " k sshkey 进入交互菜单" + echo " k sshkey 从 URL 导入 SSH 公钥" + echo " k sshkey github 从 GitHub 导入 SSH 公钥" + ;; + esac ;; - *) k_info ;; From e46f7922e05fb97b582aad1d264efd8709978d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:11:14 +0800 Subject: [PATCH 0589/1285] Refactor SSH key import function and usage --- cn/kejilion.sh | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a4da69629..5edafd6b7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4879,15 +4879,32 @@ add_sshkey() { } + + + import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "该公钥已存在,无需重复添加" + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4907,8 +4924,6 @@ import_sshkey() { } - - fetch_remote_ssh_keys() { local keys_url="$1" @@ -15690,13 +15705,19 @@ else send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; - + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "公钥直接导入" + import_sshkey "$1" + ;; + * ) echo "错误:未知参数 '$1'" echo "用法:" - echo " k sshkey 进入交互菜单" - echo " k sshkey 从 URL 导入 SSH 公钥" - echo " k sshkey github 从 GitHub 导入 SSH 公钥" + echo " k sshkey 进入交互菜单" + echo " k sshkey \"\" 直接导入 SSH 公钥" + echo " k sshkey 从 URL 导入 SSH 公钥" + echo " k sshkey github 从 GitHub 导入 SSH 公钥" ;; esac ;; From 5f0a4b55736464431ea927e718a05213c9de8b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:12:37 +0800 Subject: [PATCH 0590/1285] Refactor SSH key import function and usage --- kejilion.sh | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index b8f23f76c..86dfcda9b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4879,15 +4879,32 @@ add_sshkey() { } + + + import_sshkey() { - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "该公钥已存在,无需重复添加" + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4907,8 +4924,6 @@ import_sshkey() { } - - fetch_remote_ssh_keys() { local keys_url="$1" @@ -15690,13 +15705,19 @@ else send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; - + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "公钥直接导入" + import_sshkey "$1" + ;; + * ) echo "错误:未知参数 '$1'" echo "用法:" - echo " k sshkey 进入交互菜单" - echo " k sshkey 从 URL 导入 SSH 公钥" - echo " k sshkey github 从 GitHub 导入 SSH 公钥" + echo " k sshkey 进入交互菜单" + echo " k sshkey \"\" 直接导入 SSH 公钥" + echo " k sshkey 从 URL 导入 SSH 公钥" + echo " k sshkey github 从 GitHub 导入 SSH 公钥" ;; esac ;; From ed22ec5d25696440c757ecc77b80b823a54eab22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:26:26 +0800 Subject: [PATCH 0591/1285] Update prompts for SSH key management options --- cn/kejilion.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5edafd6b7..31197c591 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5063,9 +5063,9 @@ sshkey_panel() { echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有密钥" - echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" - echo "5. 查看本机密钥" + echo "1. 生成新密钥对 2. 手动输入已有公钥" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "5. 编辑公钥文件 6. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -5092,7 +5092,15 @@ sshkey_panel() { fetch_remote_ssh_keys "${keys_url}" break_end ;; + 5) + send_stats "编辑公钥文件" + insatll nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From 2e08c0ff9a5411d7ab970360a68c4c60eaa49b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:27:08 +0800 Subject: [PATCH 0592/1285] Update SSH key management options in kejilion.sh --- kejilion.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 86dfcda9b..209424e69 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5063,9 +5063,9 @@ sshkey_panel() { echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 生成新密钥 2. 手动输入已有密钥" - echo "3. 从GitHub导入已有密钥 4. 从URL导入已有密钥" - echo "5. 查看本机密钥" + echo "1. 生成新密钥对 2. 手动输入已有公钥" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "5. 编辑公钥文件 6. 查看本机密钥" echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" @@ -5092,7 +5092,15 @@ sshkey_panel() { fetch_remote_ssh_keys "${keys_url}" break_end ;; + 5) + send_stats "编辑公钥文件" + insatll nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" From e052d84946afa9fa6e61fe43daef193063c4a8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:31:17 +0800 Subject: [PATCH 0593/1285] Fix typo in install command for nano --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 209424e69..c6d9d37ff 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5095,7 +5095,7 @@ sshkey_panel() { 5) send_stats "编辑公钥文件" - insatll nano + install nano nano ~/.ssh/authorized_keys break_end ;; From 917700cf6ea1b0d6453fe79c8d48d83caec1acf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:31:56 +0800 Subject: [PATCH 0594/1285] Fix typo in install command for nano --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 31197c591..a74ea1f71 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5095,7 +5095,7 @@ sshkey_panel() { 5) send_stats "编辑公钥文件" - insatll nano + install nano nano ~/.ssh/authorized_keys break_end ;; From 023974c667a15b82cc8b0f6e436a4bc5400446ef Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 25 Jan 2026 08:38:27 +0000 Subject: [PATCH 0595/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-01-25=2008:38:27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 362 ++++++++++++++++++++++++++++++++--------- jp/kejilion.sh | 414 +++++++++++++++++++++++++++++++++++------------ kr/kejilion.sh | 432 ++++++++++++++++++++++++++++++++++++------------- tw/kejilion.sh | 332 ++++++++++++++++++++++++++++++------- 4 files changed, 1198 insertions(+), 342 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 7f764faaf..d54518a05 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "When using the script for the first time, please read and agree to the User License Agreement." echo "User License Agreement: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "Do you agree to the above terms? (y/n):" user_input + read -e -p "Do you agree to the above terms? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -2328,7 +2328,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -3018,7 +3018,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port local app_port=${app_port:-${docker_port}} @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4875,20 +4874,37 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, reconnection will take effect${gl_bai}" + echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" } + + + import_sshkey() { - read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}Error: Public key content not entered.${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}Error: Does not look like a legitimate SSH public key.${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "The public key already exists, no need to add it again" + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4908,6 +4924,206 @@ import_sshkey() { } +fetch_remote_ssh_keys() { + + local keys_url="$1" + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + if [[ -z "${keys_url}" ]]; then + read -e -p "Please enter your remote public key URL:" keys_url + fi + + echo "This script will pull the SSH public key from the remote URL and add it to${authorized_keys}" + echo "" + echo "Remote public key address:" + echo " ${keys_url}" + echo "" + + # Create temporary files + temp_file=$(mktemp) + + # Download public key + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "Error: Unable to download public key from URL (network issue or invalid address)" >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "Error: Unable to download public key from URL (network issue or invalid address)" >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "Error: curl or wget not found in system, unable to download public key" >&2 + rm -f "${temp_file}" + return 1 + fi + + # Check if content is valid + if [[ ! -s "${temp_file}" ]]; then + echo "Error: The downloaded file is empty and the URL may not contain any public key" >&2 + rm -f "${temp_file}" + return 1 + fi + + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" + + # Back up original authorized_keys + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "The original authorized_keys file has been backed up" + fi + + # Append public key (avoid duplication) + local added=0 + while IFS= read -r line; do + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + rm -f "${temp_file}" + + echo "" + if (( added > 0 )); then + echo "successfully added${added}A new public key arrives${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "No new public keys need to be added (all may already exist)" + fi + + echo "" +} + + + +fetch_github_ssh_keys() { + + local username="$1" + + echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" + echo "1. Log in to https://github.com/settings/keys" + echo "2. Click New SSH key or Add SSH key" + echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" + echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" + echo "5. Click Add SSH key to complete the addition." + echo "" + echo "Once added, all your public keys will be publicly available on GitHub at:" + echo "https://github.com/yourusername.keys" + echo "" + + + if [[ -z "${username}" ]]; then + read -e -p "Please enter your GitHub username (username without @):" username + fi + + if [[ -z "${username}" ]]; then + echo "Error: GitHub username cannot be empty" >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + + +sshkey_panel() { + + root_use + send_stats "Private key login" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}Enabled${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}Not enabled${gl_bai}" + fi + echo -e "ROOT private key login mode${IS_KEY_ENABLED}" + echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "A key pair will be generated, a more secure way to log in via SSH" + echo "------------------------" + echo "1. Generate a new key pair 2. Manually enter an existing public key" + echo "3. Import the existing public key from GitHub 4. Import the existing public key from the URL" + echo "5. Edit the public key file 6. View the local key" + echo "------------------------" + echo "0. Return to the previous menu" + echo "------------------------" + read -e -p "Please enter your choice:" host_dns + case $host_dns in + 1) + send_stats "Generate new key" + add_sshkey + break_end + ;; + 2) + send_stats "Import existing public key" + import_sshkey + break_end + ;; + 3) + send_stats "Import GitHub remote public key" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "Import URL remote public key" + read -e -p "Please enter your remote public key URL:" keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) + send_stats "Edit public key file" + install nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) + send_stats "View local key" + echo "------------------------" + echo "Public key information" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "Private key information" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + add_sshpasswd() { @@ -4925,7 +5141,7 @@ echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -5809,7 +6025,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6072,9 +6288,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6082,7 +6298,7 @@ create_backup() { echo "- Back up a single directory: /var/www" echo "- Back up multiple directories: /etc /home /var/log" echo "- Press Enter to use the default directory (/etc /usr /home)" - read -r -p "Please enter the directory to be backed up (separate multiple directories with spaces, and press Enter to use the default directory):" input + read -e -p "Please enter the directory to be backed up (separate multiple directories with spaces, and press Enter to use the default directory):" input # If the user does not enter a directory, the default directory is used if [ -z "$input" ]; then @@ -6116,7 +6332,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6537,7 +6753,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -8808,6 +9024,7 @@ linux_ldnmp() { echo "IP+port has been blocked from accessing the service" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -9281,11 +9498,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9308,7 +9525,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -13115,11 +13332,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13685,8 +13902,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -14235,53 +14452,7 @@ EOF 24) - - root_use - send_stats "Private key login" - while true; do - clear - echo "ROOT private key login mode" - echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "A key pair will be generated, a more secure way to log in via SSH" - echo "------------------------" - echo "1. Generate a new key 2. Import an existing key 3. View the local key" - echo "------------------------" - echo "0. Return to the previous menu" - echo "------------------------" - read -e -p "Please enter your choice:" host_dns - - case $host_dns in - 1) - send_stats "Generate new key" - add_sshkey - break_end - - ;; - 2) - send_stats "Import existing public key" - import_sshkey - break_end - - ;; - 3) - send_stats "View local key" - echo "------------------------" - echo "Public key information" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "Private key information" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) @@ -14433,7 +14604,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -14482,7 +14653,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -14844,7 +15015,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15234,7 +15405,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" @@ -15282,6 +15453,10 @@ echo "Application market management k app" echo "Quick management of application numbers k app 26 | k app 1panel | k app npm" echo "fail2ban management k fail2ban | k f2b" echo "Display system information k info" +echo "ROOT key management k sshkey" +echo "SSH public key import (URL) k sshkey " +echo "SSH public key import (GitHub) k sshkey github " + } @@ -15355,6 +15530,7 @@ else echo "IP+port has been blocked from accessing the service" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; @@ -15517,8 +15693,46 @@ else fail2ban_panel ;; + + sshkey) + shift + case "$1" in + "" ) + # sshkey → interactive menu + send_stats "SSHKey interactive menu" + sshkey_panel + ;; + + github ) + shift + send_stats "Import SSH public key from GitHub" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "Import SSH public key from URL" + fetch_remote_ssh_keys "$1" + ;; + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "Directly import the public key" + import_sshkey "$1" + ;; + + * ) + echo "Error: unknown parameter '$1'" + echo "usage:" + echo "k sshkey enters the interactive menu" + echo "k sshkey \"\" Directly import the SSH public key" + echo "k sshkey Import SSH public key from URL" + echo "k sshkey github Import SSH public key from GitHub" + ;; + esac + ;; *) k_info ;; esac fi + + diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4af379295..9a072b06c 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "上記の条件に同意しますか? (y/n):" user_input + read -e -p "上記の条件に同意しますか? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -251,7 +251,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストール中$package...${gl_bai}" + echo -e "${gl_huang}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -526,7 +526,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "すべてのコンテナを削除する" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -540,11 +540,11 @@ while true; do esac ;; 9) - send_stats "重启所有容器" + send_stats "すべてのコンテナを再起動します" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" + send_stats "コンテナに入る" read -e -p "コンテナ名を入力してください:" dockername docker exec -it $dockername /bin/sh break_end @@ -921,12 +921,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1754,7 +1754,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2241,7 +2241,7 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -2328,7 +2328,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2565,7 +2565,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2897,7 +2897,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3018,9 +3018,9 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3679,7 +3679,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4237,7 +4237,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4342,7 +4342,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4875,20 +4874,37 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT秘密キーログインがオンになり、ROOTパスワードログインがオフになり、再接続が有効になります${gl_bai}" + echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" } + + + import_sshkey() { - read -e -p "SSH 公開キーの内容を入力してください (通常は「ssh-rsa」または「ssh-ed25519」で始まります):" public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "SSH 公開キーの内容を入力してください (通常は「ssh-rsa」または「ssh-ed25519」で始まります):" public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}エラー: 公開キーの内容が入力されていません。${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}エラー: 正規の SSH 公開キーのようには見えません。${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "公開キーはすでに存在するため、再度追加する必要はありません" + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4908,6 +4924,206 @@ import_sshkey() { } +fetch_remote_ssh_keys() { + + local keys_url="$1" + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + if [[ -z "${keys_url}" ]]; then + read -e -p "リモート公開キーの URL を入力してください:" keys_url + fi + + echo "このスクリプトは、リモート URL から SSH 公開キーを取得し、それを${authorized_keys}" + echo "" + echo "リモート公開鍵アドレス:" + echo " ${keys_url}" + echo "" + + # 一時ファイルを作成する + temp_file=$(mktemp) + + # 公開キーをダウンロードする + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "エラー: URL から公開キーをダウンロードできません (ネットワークの問題または無効なアドレス)" >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "エラー: URL から公開キーをダウンロードできません (ネットワークの問題または無効なアドレス)" >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "エラー: システムにcurlまたはwgetが見つからないため、公開キーをダウンロードできません" >&2 + rm -f "${temp_file}" + return 1 + fi + + # コンテンツが有効かどうかを確認する + if [[ ! -s "${temp_file}" ]]; then + echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります。" >&2 + rm -f "${temp_file}" + return 1 + fi + + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" + + # 元のauthorized_keysをバックアップする + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "元のauthorized_keysファイルがバックアップされました" + fi + + # 公開キーを追加(重複を避ける) + local added=0 + while IFS= read -r line; do + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + rm -f "${temp_file}" + + echo "" + if (( added > 0 )); then + echo "正常に追加されました${added}新しい公開鍵が到着する${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "新しい公開キーを追加する必要はありません (すべてがすでに存在している可能性があります)" + fi + + echo "" +} + + + +fetch_github_ssh_keys() { + + local username="$1" + + echo "続行する前に、SSH 公開キーを GitHub アカウントに追加していることを確認してください。" + echo "1. https://github.com/settings/keys にログインします。" + echo "2. [新しい SSH キー] または [SSH キーの追加] をクリックします。" + echo "3. タイトルは必要に応じて入力できます (例: Home Laptop 2026)" + echo "4. ローカル公開鍵の内容 (通常は ~/.ssh/id_ed25519.pub または id_rsa.pub の内容全体) を「Key」フィールドに貼り付けます。" + echo "5. [SSH キーの追加] をクリックして追加を完了します。" + echo "" + echo "追加すると、すべての公開キーが GitHub で公開されます。" + echo "https://github.com/あなたのユーザー名.keys" + echo "" + + + if [[ -z "${username}" ]]; then + read -e -p "GitHub ユーザー名 (@ のないユーザー名) を入力してください:" username + fi + + if [[ -z "${username}" ]]; then + echo "エラー: GitHub ユーザー名を空にすることはできません" >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + + +sshkey_panel() { + + root_use + send_stats "秘密キーによるログイン" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}有効${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}有効になっていません${gl_bai}" + fi + echo -e "ROOT秘密鍵ログインモード${IS_KEY_ENABLED}" + echo "ビデオ紹介: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" + echo "------------------------" + echo "1. 新しいキーペアを生成します。 2. 既存の公開キーを手動で入力します。" + echo "3. GitHub から既存の公開キーをインポートします。 4. URL から既存の公開キーをインポートします。" + echo "5. 公開鍵ファイルを編集します。 6. ローカル鍵を表示します。" + echo "------------------------" + echo "0. 前のメニューに戻る" + echo "------------------------" + read -e -p "選択肢を入力してください:" host_dns + case $host_dns in + 1) + send_stats "新しいキーを生成する" + add_sshkey + break_end + ;; + 2) + send_stats "既存の公開キーをインポートする" + import_sshkey + break_end + ;; + 3) + send_stats "GitHub リモート公開キーをインポートする" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "URL リモート公開キーをインポートする" + read -e -p "リモート公開キーの URL を入力してください:" keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) + send_stats "公開鍵ファイルを編集する" + install nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) + send_stats "ローカルキーを表示する" + echo "------------------------" + echo "公開鍵情報" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "秘密鍵情報" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + add_sshpasswd() { @@ -4925,7 +5141,7 @@ echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -5522,7 +5738,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5809,7 +6025,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -5899,7 +6115,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6072,9 +6288,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6082,7 +6298,7 @@ create_backup() { echo "- 単一ディレクトリをバックアップします: /var/www" echo "- 複数のディレクトリをバックアップします: /etc /home /var/log" echo "- Enter キーを押して、デフォルトのディレクトリ (/etc /usr /home) を使用します。" - read -r -p "バックアップするディレクトリを入力してください (複数のディレクトリをスペースで区切って、Enter キーを押してデフォルトのディレクトリを使用します)。" input + read -e -p "バックアップするディレクトリを入力してください (複数のディレクトリをスペースで区切って、Enter キーを押してデフォルトのディレクトリを使用します)。" input # ユーザーがディレクトリを入力しない場合は、デフォルトのディレクトリが使用されます。 if [ -z "$input" ]; then @@ -6116,7 +6332,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6404,9 +6620,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションのマウント +# パーティションをマウントする mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6425,7 +6641,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6537,7 +6753,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6585,7 +6801,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6902,7 +7118,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7360,7 +7576,7 @@ docker_ssh_migration() { echo "# docker-compose 復元:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトの作成 [$project_name] パッケージ内容:${project_dir}${NC}" + echo -e "${GREEN}プロジェクトの作成 [$project_name]パッケージ化:${project_dir}${NC}" else echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" fi @@ -7622,7 +7838,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8808,6 +9024,7 @@ linux_ldnmp() { echo "IP+ポートはサービスへのアクセスをブロックされています" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -9281,11 +9498,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9308,7 +9525,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -10543,7 +10760,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -11691,7 +11908,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13115,11 +13332,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13430,7 +13647,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -13685,8 +13902,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -13914,7 +14131,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14235,53 +14452,7 @@ EOF 24) - - root_use - send_stats "秘密キーによるログイン" - while true; do - clear - echo "ROOT秘密鍵ログインモード" - echo "ビデオ紹介: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" - echo "------------------------" - echo "1. 新しいキーを生成します。 2. 既存のキーをインポートします。 3. ローカルキーを表示します。" - echo "------------------------" - echo "0. 前のメニューに戻る" - echo "------------------------" - read -e -p "選択肢を入力してください:" host_dns - - case $host_dns in - 1) - send_stats "新しいキーを生成する" - add_sshkey - break_end - - ;; - 2) - send_stats "既存の公開キーをインポートする" - import_sshkey - break_end - - ;; - 3) - send_stats "ローカルキーを表示する" - echo "------------------------" - echo "公開鍵情報" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "秘密鍵情報" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) @@ -14844,7 +15015,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15234,7 +15405,7 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -15282,6 +15453,10 @@ echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" echo "システム情報を表示 k info" +echo "ROOT キー管理 k sshkey" +echo "SSH 公開キーのインポート (URL) k sshkey " +echo "SSH 公開キーのインポート (GitHub) k sshkey github " + } @@ -15355,6 +15530,7 @@ else echo "IP+ポートはサービスへのアクセスをブロックされています" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; @@ -15370,7 +15546,7 @@ else swap) shift - send_stats "仮想メモリを素早く設定する" + send_stats "仮想メモリをすばやくセットアップする" add_swap "$@" ;; @@ -15517,8 +15693,46 @@ else fail2ban_panel ;; + + sshkey) + shift + case "$1" in + "" ) + # sshkey → インタラクティブメニュー + send_stats "SSHKey 対話型メニュー" + sshkey_panel + ;; + + github ) + shift + send_stats "GitHub から SSH 公開キーをインポートする" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "URLからSSH公開キーをインポート" + fetch_remote_ssh_keys "$1" + ;; + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "公開鍵を直接インポートする" + import_sshkey "$1" + ;; + + * ) + echo "エラー: 不明なパラメータ '$1'" + echo "使用法:" + echo "k sshkey は対話型メニューに入ります" + echo "k sshkey \"\" SSH 公開キーを直接インポートします" + echo "k sshkey URL から SSH 公開キーをインポートします" + echo "k sshkey github GitHub から SSH 公開キーをインポートします" + ;; + esac + ;; *) k_info ;; esac fi + + diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d606532cc..ae628f13c 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "위의 약관에 동의하십니까? (예/아니요):" user_input + read -e -p "위의 약관에 동의하십니까? (예/아니요):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -1197,7 +1197,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1856,7 +1856,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2328,7 +2328,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -3018,7 +3018,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} @@ -3351,7 +3351,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3364,7 +3364,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3652,7 +3652,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3700,7 +3700,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4033,7 +4033,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4095,7 +4095,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4371,7 +4371,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버에 연결합니다. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." + echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4875,20 +4874,37 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인 키 로그인이 활성화되었습니다. ROOT 비밀번호 로그인이 비활성화되었습니다. 다시 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" } + + + import_sshkey() { - read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}오류: 공개 키 내용이 입력되지 않았습니다.${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "공개 키가 이미 존재하므로 다시 추가할 필요가 없습니다." + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4908,6 +4924,206 @@ import_sshkey() { } +fetch_remote_ssh_keys() { + + local keys_url="$1" + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + if [[ -z "${keys_url}" ]]; then + read -e -p "원격 공개 키 URL을 입력하세요:" keys_url + fi + + echo "이 스크립트는 원격 URL에서 SSH 공개 키를 가져와서${authorized_keys}" + echo "" + echo "원격 공개 키 주소:" + echo " ${keys_url}" + echo "" + + # 임시 파일 만들기 + temp_file=$(mktemp) + + # 공개 키 다운로드 + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "오류: 시스템에서 컬 또는 wget을 찾을 수 없어 공개 키를 다운로드할 수 없습니다." >&2 + rm -f "${temp_file}" + return 1 + fi + + # 콘텐츠가 유효한지 확인하세요. + if [[ ! -s "${temp_file}" ]]; then + echo "오류: 다운로드한 파일이 비어 있으며 URL에 공개 키가 포함되어 있지 않을 수 있습니다." >&2 + rm -f "${temp_file}" + return 1 + fi + + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" + + # 원래 인증된_키 백업 + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "원본 Authorized_keys 파일이 백업되었습니다." + fi + + # 공개 키 추가(중복 방지) + local added=0 + while IFS= read -r line; do + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + rm -f "${temp_file}" + + echo "" + if (( added > 0 )); then + echo "성공적으로 추가되었습니다${added}새로운 공개 키가 도착합니다${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "새로운 공개 키를 추가할 필요가 없습니다(모두 이미 존재할 수도 있음)." + fi + + echo "" +} + + + +fetch_github_ssh_keys() { + + local username="$1" + + echo "계속하기 전에 SSH 공개 키를 GitHub 계정에 추가했는지 확인하세요." + echo "1. https://github.com/settings/keys에 로그인하세요." + echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." + echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" + echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." + echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." + echo "" + echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." + echo "https://github.com/yourusername.keys" + echo "" + + + if [[ -z "${username}" ]]; then + read -e -p "GitHub 사용자 이름(@ 없는 사용자 이름)을 입력하세요." username + fi + + if [[ -z "${username}" ]]; then + echo "오류: GitHub 사용자 이름은 비워둘 수 없습니다." >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + + +sshkey_panel() { + + root_use + send_stats "개인키 로그인" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}활성화됨${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}활성화되지 않음${gl_bai}" + fi + echo -e "ROOT 개인 키 로그인 모드${IS_KEY_ENABLED}" + echo "영상 소개: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." + echo "------------------------" + echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" + echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." + echo "5. 공개 키 파일 편집 6. 로컬 키 보기" + echo "------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "------------------------" + read -e -p "선택사항을 입력하세요:" host_dns + case $host_dns in + 1) + send_stats "새 키 생성" + add_sshkey + break_end + ;; + 2) + send_stats "기존 공개 키 가져오기" + import_sshkey + break_end + ;; + 3) + send_stats "GitHub 원격 공개 키 가져오기" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "URL 원격 공개 키 가져오기" + read -e -p "원격 공개 키 URL을 입력하세요:" keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) + send_stats "공개 키 파일 편집" + install nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) + send_stats "로컬 키 보기" + echo "------------------------" + echo "공개키 정보" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "개인 키 정보" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + add_sshpasswd() { @@ -5303,7 +5519,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5313,7 +5529,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5367,7 +5583,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5456,7 +5672,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5510,7 +5726,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5809,7 +6025,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6016,7 +6232,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6082,7 +6298,7 @@ create_backup() { echo "- 단일 디렉터리 백업: /var/www" echo "- 여러 디렉터리 백업: /etc /home /var/log" echo "- Enter를 눌러 기본 디렉터리(/etc/usr/home)를 사용합니다." - read -r -p "백업할 디렉터리를 입력하십시오(여러 디렉터리를 공백으로 구분하고 Enter를 눌러 기본 디렉터리를 사용하십시오)." input + read -e -p "백업할 디렉터리를 입력하십시오(여러 디렉터리를 공백으로 구분하고 Enter를 눌러 기본 디렉터리를 사용하십시오)." input # 사용자가 디렉터리를 입력하지 않으면 기본 디렉터리가 사용됩니다. if [ -z "$input" ]; then @@ -6255,7 +6471,7 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -6537,7 +6753,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6603,7 +6819,7 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi @@ -7307,7 +7523,7 @@ docker_ssh_migration() { echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7446,7 +7662,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" cd "$original_path" || return docker compose down || true @@ -7735,7 +7951,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7781,7 +7997,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8096,7 +8312,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8491,7 +8707,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8808,6 +9024,7 @@ linux_ldnmp() { echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -8820,7 +9037,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf @@ -9281,11 +9498,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -9308,7 +9525,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9320,7 +9537,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9348,7 +9565,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9368,7 +9585,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -9376,7 +9593,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -9589,7 +9806,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -11691,7 +11908,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12631,7 +12848,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -12980,7 +13197,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -13115,11 +13332,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -13429,7 +13646,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -13442,7 +13659,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13685,8 +13902,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -13729,7 +13946,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -13987,7 +14204,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14235,60 +14452,14 @@ EOF 24) - - root_use - send_stats "개인키 로그인" - while true; do - clear - echo "ROOT 개인 키 로그인 모드" - echo "영상 소개: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." - echo "------------------------" - echo "1. 새 키 생성 2. 기존 키 가져오기 3. 로컬 키 보기" - echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" - echo "------------------------" - read -e -p "선택사항을 입력하세요:" host_dns - - case $host_dns in - 1) - send_stats "새 키 생성" - add_sshkey - break_end - - ;; - 2) - send_stats "기존 공개 키 가져오기" - import_sshkey - break_end - - ;; - 3) - send_stats "로컬 키 보기" - echo "------------------------" - echo "공개키 정보" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "개인 키 정보" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -14836,7 +15007,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 탐색하고 명령을 실행합니다. + # 서버를 순회하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -14844,7 +15015,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -14919,7 +15090,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -14992,7 +15163,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -15234,7 +15405,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -15268,7 +15439,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" @@ -15282,6 +15453,10 @@ echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" +echo "ROOT 키 관리 k sshkey" +echo "SSH 공개 키 가져오기(URL) k sshkey " +echo "SSH 공개 키 가져오기(GitHub) k sshkey github " + } @@ -15355,6 +15530,7 @@ else echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; @@ -15517,8 +15693,46 @@ else fail2ban_panel ;; + + sshkey) + shift + case "$1" in + "" ) + # sshkey → 대화형 메뉴 + send_stats "SSHKey 대화형 메뉴" + sshkey_panel + ;; + + github ) + shift + send_stats "GitHub에서 SSH 공개 키 가져오기" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "URL에서 SSH 공개 키 가져오기" + fetch_remote_ssh_keys "$1" + ;; + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "공개 키를 직접 가져오기" + import_sshkey "$1" + ;; + + * ) + echo "오류: 알 수 없는 매개변수 '$1'" + echo "용법:" + echo "k sshkey가 대화형 메뉴로 들어갑니다." + echo "k sshkey \"\" SSH 공개 키 직접 가져오기" + echo "k sshkey URL에서 SSH 공개 키 가져오기" + echo "k sshkey github GitHub에서 SSH 공개 키 가져오기" + ;; + esac + ;; *) k_info ;; esac fi + + diff --git a/tw/kejilion.sh b/tw/kejilion.sh index f6ae09de0..0c8aec3ed 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.3" +sh_v="4.3.4" gl_hui='\e[37m' @@ -118,7 +118,7 @@ UserLicenseAgreement() { echo "首次使用腳本,請先閱讀並同意用戶許可協議。" echo "用戶許可協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -r -p "是否同意以上條款? (y/n):" user_input + read -e -p "是否同意以上條款? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -154,7 +154,7 @@ public_ip=$(get_public_ip) isp_info=$(curl -s --max-time 3 http://ipinfo.io/org) -if echo "$isp_info" | grep -Eiq 'mobile|unicom|telecom'; then +if echo "$isp_info" | grep -Eiq 'CHINANET|mobile|unicom|telecom'; then ipv4_address=$(get_local_ip) else ipv4_address="$public_ip" @@ -3018,7 +3018,7 @@ docker_app_plus() { 1) setup_docker_dir check_disk_space $app_size /home/docker - + while true; do read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port local app_port=${app_port:-${docker_port}} @@ -4852,13 +4852,12 @@ new_ssh_port() { } - add_sshkey() { chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f /root/.ssh/sshkey -N "" + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys @@ -4880,15 +4879,32 @@ add_sshkey() { } + + + import_sshkey() { - read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key + local public_key="$1" + + if [[ -z "$public_key" ]]; then + read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key + fi if [[ -z "$public_key" ]]; then echo -e "${gl_hong}錯誤:未輸入公鑰內容。${gl_bai}" return 1 fi + if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then + echo -e "${gl_hong}錯誤:看起來不像合法的 SSH 公鑰。${gl_bai}" + return 1 + fi + + if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + echo "該公鑰已存在,無需重複添加" + return 0 + fi + chmod 700 ~/ mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -4908,6 +4924,206 @@ import_sshkey() { } +fetch_remote_ssh_keys() { + + local keys_url="$1" + local authorized_keys="${HOME}/.ssh/authorized_keys" + local temp_file + + if [[ -z "${keys_url}" ]]; then + read -e -p "請輸入您的遠端公鑰URL:" keys_url + fi + + echo "此腳本將從遠程 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" + echo "" + echo "遠程公鑰地址:" + echo " ${keys_url}" + echo "" + + # 創建臨時文件 + temp_file=$(mktemp) + + # 下載公鑰 + if command -v curl >/dev/null 2>&1; then + curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { + echo "錯誤:無法從 URL 下載公鑰(網絡問題或地址無效)" >&2 + rm -f "${temp_file}" + return 1 + } + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { + echo "錯誤:無法從 URL 下載公鑰(網絡問題或地址無效)" >&2 + rm -f "${temp_file}" + return 1 + } + else + echo "錯誤:系統中未找到 curl 或 wget,無法下載公鑰" >&2 + rm -f "${temp_file}" + return 1 + fi + + # 檢查內容是否有效 + if [[ ! -s "${temp_file}" ]]; then + echo "錯誤:下載到的文件為空,URL 可能不包含任何公鑰" >&2 + rm -f "${temp_file}" + return 1 + fi + + mkdir -p ~/.ssh + chmod 700 ~/.ssh + touch "${authorized_keys}" + chmod 600 "${authorized_keys}" + + # 備份原有 authorized_keys + if [[ -f "${authorized_keys}" ]]; then + cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" + echo "已備份原有 authorized_keys 文件" + fi + + # 追加公鑰(避免重複) + local added=0 + while IFS= read -r line; do + [[ -z "${line}" || "${line}" =~ ^# ]] && continue + + if ! grep -Fxq "${line}" "${authorized_keys}" 2>/dev/null; then + echo "${line}" >> "${authorized_keys}" + ((added++)) + fi + done < "${temp_file}" + + rm -f "${temp_file}" + + echo "" + if (( added > 0 )); then + echo "成功添加${added}條新的公鑰到${authorized_keys}" + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ + -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + restart_ssh + else + echo "沒有新的公鑰需要添加(可能已全部存在)" + fi + + echo "" +} + + + +fetch_github_ssh_keys() { + + local username="$1" + + echo "操作前,請確保您已在 GitHub 賬戶中添加了 SSH 公鑰:" + echo "1. 登錄 https://github.com/settings/keys" + echo "2. 點擊 New SSH key 或 Add SSH key" + echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" + echo "4. 將本地公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)粘貼到 Key 字段" + echo "5. 點擊 Add SSH key 完成添加" + echo "" + echo "添加完成後,GitHub 會公開提供您的所有公鑰,地址為:" + echo "https://github.com/您的用戶名.keys" + echo "" + + + if [[ -z "${username}" ]]; then + read -e -p "請輸入您的 GitHub 用戶名(username,不含 @):" username + fi + + if [[ -z "${username}" ]]; then + echo "錯誤:GitHub 用戶名不能為空" >&2 + return 1 + fi + + keys_url="https://github.com/${username}.keys" + + fetch_remote_ssh_keys "${keys_url}" + +} + + + + +sshkey_panel() { + + root_use + send_stats "私鑰登錄" + while true; do + clear + local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') + if [[ "$REAL_STATUS" =~ "yes" ]]; then + IS_KEY_ENABLED="${gl_lv}已啟用${gl_bai}" + else + IS_KEY_ENABLED="${gl_hui}未啟用${gl_bai}" + fi + echo -e "ROOT私鑰登錄模式${IS_KEY_ENABLED}" + echo "視頻介紹: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "------------------------------------------------" + echo "將會生成密鑰對,更安全的方式SSH登錄" + echo "------------------------" + echo "1. 生成新密鑰對 2. 手動輸入已有公鑰" + echo "3. 從GitHub導入已有公鑰 4. 從URL導入已有公鑰" + echo "5. 編輯公鑰文件 6. 查看本機密鑰" + echo "------------------------" + echo "0. 返回上一級選單" + echo "------------------------" + read -e -p "請輸入你的選擇:" host_dns + case $host_dns in + 1) + send_stats "生成新密鑰" + add_sshkey + break_end + ;; + 2) + send_stats "導入已有公鑰" + import_sshkey + break_end + ;; + 3) + send_stats "導入GitHub遠端公鑰" + fetch_github_ssh_keys + break_end + ;; + 4) + send_stats "導入URL遠端公鑰" + read -e -p "請輸入您的遠端公鑰URL:" keys_url + fetch_remote_ssh_keys "${keys_url}" + break_end + ;; + + 5) + send_stats "編輯公鑰文件" + install nano + nano ~/.ssh/authorized_keys + break_end + ;; + + 6) + send_stats "查看本機密鑰" + echo "------------------------" + echo "公鑰信息" + cat ~/.ssh/authorized_keys + echo "------------------------" + echo "私鑰信息" + cat ~/.ssh/sshkey + echo "------------------------" + break_end + ;; + *) + break # 跳出循环,退出菜单 + ;; + esac + done + + +} + + + + + add_sshpasswd() { @@ -6082,7 +6298,7 @@ create_backup() { echo "- 備份單個目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用默認目錄 (/etc /usr /home)" - read -r -p "請輸入要備份的目錄(多個目錄用空格分隔,直接回車則使用默認目錄):" input + read -e -p "請輸入要備份的目錄(多個目錄用空格分隔,直接回車則使用默認目錄):" input # 如果用戶沒有輸入目錄,則使用默認目錄 if [ -z "$input" ]; then @@ -8808,6 +9024,7 @@ linux_ldnmp() { echo "已阻止IP+端口訪問該服務" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi @@ -9281,11 +9498,11 @@ clear cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi while true; do @@ -13115,11 +13332,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ cd ~ install git if [ ! -d apps/.git ]; then - git clone ${gh_proxy}github.com/kejilion/apps.git + timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else cd apps # git pull origin main > /dev/null 2>&1 - git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 + timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 fi local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then @@ -14235,53 +14452,7 @@ EOF 24) - - root_use - send_stats "私鑰登錄" - while true; do - clear - echo "ROOT私鑰登錄模式" - echo "視頻介紹: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" - echo "------------------------------------------------" - echo "將會生成密鑰對,更安全的方式SSH登錄" - echo "------------------------" - echo "1. 生成新密鑰 2. 導入已有密鑰 3. 查看本機密鑰" - echo "------------------------" - echo "0. 返回上一級選單" - echo "------------------------" - read -e -p "請輸入你的選擇:" host_dns - - case $host_dns in - 1) - send_stats "生成新密鑰" - add_sshkey - break_end - - ;; - 2) - send_stats "導入已有公鑰" - import_sshkey - break_end - - ;; - 3) - send_stats "查看本機密鑰" - echo "------------------------" - echo "公鑰信息" - cat ~/.ssh/authorized_keys - echo "------------------------" - echo "私鑰信息" - cat ~/.ssh/sshkey - echo "------------------------" - break_end - - ;; - *) - break # 跳出循环,退出菜单 - ;; - esac - done - + sshkey_panel ;; 25) @@ -15282,6 +15453,10 @@ echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統信息 k info" +echo "ROOT密鑰管理 k sshkey" +echo "SSH公鑰導入(URL) k sshkey " +echo "SSH公鑰導入(GitHub) k sshkey github " + } @@ -15355,6 +15530,7 @@ else echo "已阻止IP+端口訪問該服務" else ip_address + close_port "$port" block_container_port "$docker_name" "$ipv4_address" fi ;; @@ -15517,8 +15693,46 @@ else fail2ban_panel ;; + + sshkey) + shift + case "$1" in + "" ) + # sshkey → 交互菜單 + send_stats "SSHKey 交互菜單" + sshkey_panel + ;; + + github ) + shift + send_stats "從 GitHub 導入 SSH 公鑰" + fetch_github_ssh_keys "$1" + ;; + + http://*|https://* ) + send_stats "從 URL 導入 SSH 公鑰" + fetch_remote_ssh_keys "$1" + ;; + + ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) + send_stats "公鑰直接導入" + import_sshkey "$1" + ;; + + * ) + echo "錯誤:未知參數 '$1'" + echo "用法:" + echo "k sshkey 進入交互菜單" + echo "k sshkey \"\" 直接導入 SSH 公鑰" + echo "k sshkey 從 URL 導入 SSH 公鑰" + echo "k sshkey github 從 GitHub 導入 SSH 公鑰" + ;; + esac + ;; *) k_info ;; esac fi + + From 1e409052eb4277a4d0038b077af915272d508490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:04:48 +0800 Subject: [PATCH 0596/1285] Refactor case handling in kejilion.sh Remove handling for case 3 and exit application logic. --- cn/kejilion.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a74ea1f71..3118290b6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1602,17 +1602,12 @@ certs_status() { fi ;; - 3) + *) send_stats "不带证书改用HTTP访问" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; - *) - send_stats "退出申请" - rm -f /home/web/conf.d/${yuming}.conf - exit - ;; esac fi From dff2d85a8772d0115ef7adb05c996a02c1ce8888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:05:14 +0800 Subject: [PATCH 0597/1285] Refactor case handling in kejilion.sh --- kejilion.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c6d9d37ff..22713403f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1602,17 +1602,12 @@ certs_status() { fi ;; - 3) + *) send_stats "不带证书改用HTTP访问" sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; - *) - send_stats "退出申请" - rm -f /home/web/conf.d/${yuming}.conf - exit - ;; esac fi From 00ef0509a1739db3eee916381d947d41c9f54d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:16:31 +0800 Subject: [PATCH 0598/1285] Simplify certbot execution by removing iptables check Remove iptables rule check for port 80 before running certbot. --- cn/kejilion.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3118290b6..0c79bfdf2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1442,10 +1442,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From f365d07aa780f48d0d5bafd633d2261c1652e75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:17:20 +0800 Subject: [PATCH 0599/1285] Remove iptables check for HTTP port before certbot Removed iptables rule check for port 80 before running certbot. --- kejilion.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 22713403f..de3c3d3a9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1442,10 +1442,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi From f5197b5cc9ea0cfbb33f132af8ab4f12e82f8e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:18:19 +0800 Subject: [PATCH 0600/1285] Clean up commented iptables commands Removed commented out iptables commands for clarity. --- auto_cert_renewal.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/auto_cert_renewal.sh b/auto_cert_renewal.sh index baf58087f..796b9b566 100644 --- a/auto_cert_renewal.sh +++ b/auto_cert_renewal.sh @@ -69,20 +69,6 @@ for cert_file in $certs_directory*_cert.pem; do docker stop nginx > /dev/null 2>&1 - # if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - # iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - # fi - - # iptables -P INPUT ACCEPT - # iptables -P FORWARD ACCEPT - # iptables -P OUTPUT ACCEPT - # iptables -F - - # ip6tables -P INPUT ACCEPT - # ip6tables -P FORWARD ACCEPT - # ip6tables -P OUTPUT ACCEPT - # ip6tables -F - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d $yuming --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa mkdir -p /home/web/certs/ From fdf100b03512bcc2a62f86413ee3fecd0a6d4227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:48:30 +0800 Subject: [PATCH 0601/1285] Update video link to new resource for SSH key usage --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0c79bfdf2..22ce9a68e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5050,7 +5050,7 @@ sshkey_panel() { IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" fi echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" From 1e0b4fc2c9854598ed1cae376e227d25d65fe005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:49:59 +0800 Subject: [PATCH 0602/1285] Update video link to advanced usage guide --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index de3c3d3a9..884534bd6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5050,7 +5050,7 @@ sshkey_panel() { IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" fi echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" - echo "视频介绍: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" From 9ced641a691e5ce5c8a31cee4b36ddba57692e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:56:28 +0800 Subject: [PATCH 0603/1285] Update version and improve network menu --- cn/kejilion.sh | 206 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 197 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 22ce9a68e..1585af16d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.5" gl_hui='\e[37m' @@ -4889,7 +4889,7 @@ import_sshkey() { if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" return 1 - fi + fi if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then echo "该公钥已存在,无需重复添加" @@ -7790,7 +7790,7 @@ docker_ssh_migration() { echo -e "3. 还原docker项目" echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0. 返回上一级选单" echo "------------------------" read -e -p "请选择: " choice case $choice in @@ -13627,6 +13627,183 @@ fail2ban_panel() { +net_menu() { + + show_nics() { + echo "================ 当前网卡信息 ================" + printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== 网卡管理菜单 ===========" + echo "1. 启用网卡" + echo "2. 禁用网卡" + echo "3. 查看网卡详细信息" + echo "4. 刷新网卡信息" + echo "0. 返回上一级选单" + echo "====================================" + read -rp "请选择操作: " choice + + case $choice in + 1) + read -rp "请输入要启用的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 2) + read -rp "请输入要禁用的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 3) + read -rp "请输入要查看的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nic 详细信息 ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 4) + continue + ;; + 0) + echo "退出网卡管理菜单" + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} + + + +log_menu() { + + show_log_overview() { + echo "============= 系统日志概览 =============" + echo "主机名: $(hostname)" + echo "系统时间: $(date)" + echo + echo "[ /var/log 目录占用 ]" + du -sh /var/log 2>/dev/null + echo + echo "[ journal 日志占用 ]" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== 系统日志管理菜单 ===========" + echo "1. 查看最近系统日志(journal)" + echo "2. 查看指定服务日志" + echo "3. 查看登录/安全日志" + echo "4. 实时跟踪日志" + echo "5. 清理旧 journal 日志" + echo "0. 返回上一级选单" + echo "=======================================" + read -rp "请选择操作: " choice + + case $choice in + 1) + read -rp "查看最近多少行日志?[默认 100]: " lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "按回车继续..." + ;; + 2) + read -rp "请输入服务名(如 sshd、nginx): " svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ 服务不存在或无日志" + fi + read -rp "按回车继续..." + ;; + 3) + echo "====== 最近登录日志 ======" + last -n 10 + echo + echo "====== 认证日志 ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "未找到安全日志文件" + fi + read -rp "按回车继续..." + ;; + 4) + echo "1) 系统日志" + echo "2) 指定服务日志" + read -rp "选择跟踪类型: " t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "输入服务名: " svc + journalctl -u "$svc" -f + else + echo "无效选择" + fi + ;; + 5) + echo "⚠️ 清理 journal 日志(安全方式)" + echo "1) 保留最近 7 天" + echo "2) 保留最近 3 天" + echo "3) 限制日志最大 500M" + read -rp "请选择清理方式: " c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "无效选项" ;; + esac + echo "✔ journal 日志清理完成" + sleep 2 + ;; + 0) + echo "退出系统日志管理菜单" + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} + + + + linux_Settings() { @@ -13658,9 +13835,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" @@ -14571,7 +14750,17 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 61) clear send_stats "留言板" echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" @@ -15686,20 +15875,20 @@ else sshkey) - shift + shift case "$1" in "" ) # sshkey → 交互菜单 send_stats "SSHKey 交互菜单" sshkey_panel ;; - + github ) shift send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; - + http://*|https://* ) send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" @@ -15726,4 +15915,3 @@ else esac fi - From a7038c3dddb5ad30071901dc92e3f44bb4764065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:57:07 +0800 Subject: [PATCH 0604/1285] Update version and improve network menu --- kejilion.sh | 206 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 197 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 884534bd6..94b2efda8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.5" gl_hui='\e[37m' @@ -4889,7 +4889,7 @@ import_sshkey() { if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" return 1 - fi + fi if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then echo "该公钥已存在,无需重复添加" @@ -7790,7 +7790,7 @@ docker_ssh_migration() { echo -e "3. 还原docker项目" echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. 返回上一级菜单" + echo -e "0. 返回上一级选单" echo "------------------------" read -e -p "请选择: " choice case $choice in @@ -13627,6 +13627,183 @@ fail2ban_panel() { +net_menu() { + + show_nics() { + echo "================ 当前网卡信息 ================" + printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== 网卡管理菜单 ===========" + echo "1. 启用网卡" + echo "2. 禁用网卡" + echo "3. 查看网卡详细信息" + echo "4. 刷新网卡信息" + echo "0. 返回上一级选单" + echo "====================================" + read -rp "请选择操作: " choice + + case $choice in + 1) + read -rp "请输入要启用的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 2) + read -rp "请输入要禁用的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 3) + read -rp "请输入要查看的网卡名: " nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nic 详细信息 ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ 网卡不存在" + fi + read -rp "按回车继续..." + ;; + 4) + continue + ;; + 0) + echo "退出网卡管理菜单" + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} + + + +log_menu() { + + show_log_overview() { + echo "============= 系统日志概览 =============" + echo "主机名: $(hostname)" + echo "系统时间: $(date)" + echo + echo "[ /var/log 目录占用 ]" + du -sh /var/log 2>/dev/null + echo + echo "[ journal 日志占用 ]" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== 系统日志管理菜单 ===========" + echo "1. 查看最近系统日志(journal)" + echo "2. 查看指定服务日志" + echo "3. 查看登录/安全日志" + echo "4. 实时跟踪日志" + echo "5. 清理旧 journal 日志" + echo "0. 返回上一级选单" + echo "=======================================" + read -rp "请选择操作: " choice + + case $choice in + 1) + read -rp "查看最近多少行日志?[默认 100]: " lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "按回车继续..." + ;; + 2) + read -rp "请输入服务名(如 sshd、nginx): " svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ 服务不存在或无日志" + fi + read -rp "按回车继续..." + ;; + 3) + echo "====== 最近登录日志 ======" + last -n 10 + echo + echo "====== 认证日志 ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "未找到安全日志文件" + fi + read -rp "按回车继续..." + ;; + 4) + echo "1) 系统日志" + echo "2) 指定服务日志" + read -rp "选择跟踪类型: " t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "输入服务名: " svc + journalctl -u "$svc" -f + else + echo "无效选择" + fi + ;; + 5) + echo "⚠️ 清理 journal 日志(安全方式)" + echo "1) 保留最近 7 天" + echo "2) 保留最近 3 天" + echo "3) 限制日志最大 500M" + read -rp "请选择清理方式: " c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "无效选项" ;; + esac + echo "✔ journal 日志清理完成" + sleep 2 + ;; + 0) + echo "退出系统日志管理菜单" + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} + + + + linux_Settings() { @@ -13658,9 +13835,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" @@ -14571,7 +14750,17 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 61) clear send_stats "留言板" echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" @@ -15686,20 +15875,20 @@ else sshkey) - shift + shift case "$1" in "" ) # sshkey → 交互菜单 send_stats "SSHKey 交互菜单" sshkey_panel ;; - + github ) shift send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; - + http://*|https://* ) send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" @@ -15726,4 +15915,3 @@ else esac fi - From 88d9f5b48107e1ba0aa7ff7dcf0d3fe16d73366c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:59:54 +0800 Subject: [PATCH 0605/1285] Add network card and system log management tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增网卡管理和系统日志管理工具,提供基础操作和信息查看功能。 --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1a8c62093..eab9ccb4e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1414,4 +1414,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具ROOT密钥登录功能交互菜单和表述进行优化。 新增k sshkey url 快捷命令 支持快速导入SSH公钥并开启SSH密钥登录模式。 ------------------------ +2026-01-26 v4.3.5 +系统工具中新增网卡管理工具,快速查看网卡信息以及对网卡进行基础操作, +系统工具中新增系统日志管理工具,快速查看日志占用,查看各类服务日志,清理日志等基础操作, +------------------------ From ae37be96bb09d9a022c0b84d8a9bf1f95a972137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:07:26 +0800 Subject: [PATCH 0606/1285] Refactor network and log management menus Removed redundant exit options and invalid option messages in the network and log management menus. --- cn/kejilion.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1585af16d..627682260 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13629,6 +13629,7 @@ fail2ban_panel() { net_menu() { + send_stats "网卡管理工具" show_nics() { echo "================ 当前网卡信息 ================" printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" @@ -13657,6 +13658,7 @@ net_menu() { case $choice in 1) + send_stats "启用网卡" read -rp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" @@ -13666,6 +13668,7 @@ net_menu() { read -rp "按回车继续..." ;; 2) + send_stats "禁用网卡" read -rp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" @@ -13675,6 +13678,7 @@ net_menu() { read -rp "按回车继续..." ;; 3) + send_stats "查看网卡详情" read -rp "请输入要查看的网卡名: " nic if ip link show "$nic" &>/dev/null; then echo "========== $nic 详细信息 ==========" @@ -13686,15 +13690,11 @@ net_menu() { read -rp "按回车继续..." ;; 4) + send_stats "刷新网卡信息" continue ;; - 0) - echo "退出网卡管理菜单" - break - ;; *) - echo "无效选项" - sleep 1 + break ;; esac done @@ -13703,6 +13703,7 @@ net_menu() { log_menu() { + send_stats "系统日志管理工具" show_log_overview() { echo "============= 系统日志概览 =============" @@ -13733,12 +13734,14 @@ log_menu() { case $choice in 1) + send_stats "查看最近日志" read -rp "查看最近多少行日志?[默认 100]: " lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -rp "按回车继续..." ;; 2) + send_stats "查看指定服务日志" read -rp "请输入服务名(如 sshd、nginx): " svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager @@ -13748,6 +13751,7 @@ log_menu() { read -rp "按回车继续..." ;; 3) + send_stats "查看登录/安全日志" echo "====== 最近登录日志 ======" last -n 10 echo @@ -13762,6 +13766,7 @@ log_menu() { read -rp "按回车继续..." ;; 4) + send_stats "实时跟踪日志" echo "1) 系统日志" echo "2) 指定服务日志" read -rp "选择跟踪类型: " t @@ -13775,6 +13780,7 @@ log_menu() { fi ;; 5) + send_stats "清理旧 journal 日志" echo "⚠️ 清理 journal 日志(安全方式)" echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" @@ -13789,13 +13795,8 @@ log_menu() { echo "✔ journal 日志清理完成" sleep 2 ;; - 0) - echo "退出系统日志管理菜单" - break - ;; *) - echo "无效选项" - sleep 1 + break ;; esac done From 325bddc2d9b733f92507a497394561af4376c00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:08:10 +0800 Subject: [PATCH 0607/1285] Add send_stats calls to network and log menus --- kejilion.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 94b2efda8..a2f9ce831 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13629,6 +13629,7 @@ fail2ban_panel() { net_menu() { + send_stats "网卡管理工具" show_nics() { echo "================ 当前网卡信息 ================" printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" @@ -13657,6 +13658,7 @@ net_menu() { case $choice in 1) + send_stats "启用网卡" read -rp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" @@ -13666,6 +13668,7 @@ net_menu() { read -rp "按回车继续..." ;; 2) + send_stats "禁用网卡" read -rp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" @@ -13675,6 +13678,7 @@ net_menu() { read -rp "按回车继续..." ;; 3) + send_stats "查看网卡详情" read -rp "请输入要查看的网卡名: " nic if ip link show "$nic" &>/dev/null; then echo "========== $nic 详细信息 ==========" @@ -13686,15 +13690,11 @@ net_menu() { read -rp "按回车继续..." ;; 4) + send_stats "刷新网卡信息" continue ;; - 0) - echo "退出网卡管理菜单" - break - ;; *) - echo "无效选项" - sleep 1 + break ;; esac done @@ -13703,6 +13703,7 @@ net_menu() { log_menu() { + send_stats "系统日志管理工具" show_log_overview() { echo "============= 系统日志概览 =============" @@ -13733,12 +13734,14 @@ log_menu() { case $choice in 1) + send_stats "查看最近日志" read -rp "查看最近多少行日志?[默认 100]: " lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -rp "按回车继续..." ;; 2) + send_stats "查看指定服务日志" read -rp "请输入服务名(如 sshd、nginx): " svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager @@ -13748,6 +13751,7 @@ log_menu() { read -rp "按回车继续..." ;; 3) + send_stats "查看登录/安全日志" echo "====== 最近登录日志 ======" last -n 10 echo @@ -13762,6 +13766,7 @@ log_menu() { read -rp "按回车继续..." ;; 4) + send_stats "实时跟踪日志" echo "1) 系统日志" echo "2) 指定服务日志" read -rp "选择跟踪类型: " t @@ -13775,6 +13780,7 @@ log_menu() { fi ;; 5) + send_stats "清理旧 journal 日志" echo "⚠️ 清理 journal 日志(安全方式)" echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" @@ -13789,13 +13795,8 @@ log_menu() { echo "✔ journal 日志清理完成" sleep 2 ;; - 0) - echo "退出系统日志管理菜单" - break - ;; *) - echo "无效选项" - sleep 1 + break ;; esac done From d17f7782d4436e9e69c339048c59692364d28887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:21:18 +0800 Subject: [PATCH 0608/1285] Refactor SSL handling and remove HTTP access option Removed the option to access without a certificate and cleaned up redundant calls to install_ssltls, certs_status, and add_db in various sections. --- cn/kejilion.sh | 117 ++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 627682260..489558cbc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1539,7 +1539,7 @@ certs_status() { echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" - echo "1. 重新申请 2. 导入已有证书 3. 不带证书改用HTTP访问 0. 退出" + echo "1. 重新申请 2. 导入已有证书 0. 退出" echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -1596,13 +1596,9 @@ certs_status() { echo "错误:无效的证书或私钥格式!" certs_status fi - ;; *) - send_stats "不带证书改用HTTP访问" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + exit ;; esac fi @@ -3382,14 +3378,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3438,6 +3436,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3456,9 +3458,6 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3486,6 +3485,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3502,8 +3504,6 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -8535,16 +8535,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8577,14 +8577,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8615,14 +8615,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8662,15 +8663,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8714,14 +8717,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8772,15 +8778,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8814,15 +8822,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8853,14 +8862,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8991,13 +9000,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9031,12 +9042,14 @@ linux_ldnmp() { read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9089,12 +9102,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9130,12 +9144,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html From 3beff4cfc4fb278d743387dc4cad6b7c11ced7a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:22:00 +0800 Subject: [PATCH 0609/1285] Remove unnecessary SSL installation calls --- kejilion.sh | 117 +++++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a2f9ce831..ee56dd0fa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1539,7 +1539,7 @@ certs_status() { echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" - echo "1. 重新申请 2. 导入已有证书 3. 不带证书改用HTTP访问 0. 退出" + echo "1. 重新申请 2. 导入已有证书 0. 退出" echo "------------------------" read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -1596,13 +1596,9 @@ certs_status() { echo "错误:无效的证书或私钥格式!" certs_status fi - ;; *) - send_stats "不带证书改用HTTP访问" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf + exit ;; esac fi @@ -3382,14 +3378,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3438,6 +3436,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3456,9 +3458,6 @@ ldnmp_Proxy() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3486,6 +3485,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3502,8 +3504,6 @@ ldnmp_Proxy_backend() { sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -8535,16 +8535,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8577,14 +8577,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8615,14 +8615,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8662,15 +8663,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8714,14 +8717,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8772,15 +8778,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8814,15 +8822,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8853,14 +8862,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8991,13 +9000,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9031,12 +9042,14 @@ linux_ldnmp() { read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9089,12 +9102,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9130,12 +9144,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html From 8e7877b43b981a0e093778c6979e3fceac247aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:24:18 +0800 Subject: [PATCH 0610/1285] Remove insecure HTTP access option Removed option for HTTP access without a certificate due to a logical flaw causing site issues after certificate application failure. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index eab9ccb4e..79c358cd9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1417,5 +1417,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-01-26 v4.3.5 系统工具中新增网卡管理工具,快速查看网卡信息以及对网卡进行基础操作, 系统工具中新增系统日志管理工具,快速查看日志占用,查看各类服务日志,清理日志等基础操作, +申请证书失败后暂时移除不带证书HTTP访问会选项,该选项存在逻辑漏洞,导致站点异常。 ------------------------ From d7c60efc34d320cc4150ccf53ad00c171e4ef298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:07:08 +0800 Subject: [PATCH 0611/1285] Refactor SSH configuration and key management functions --- cn/kejilion.sh | 173 ++++++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 82 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 489558cbc..a817ed793 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -4798,39 +4798,31 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # 如果找到 PubkeyAuthentication 设置为 yes - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4843,30 +4835,40 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" - - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { + root_use sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" + +} + + +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on } @@ -4876,6 +4878,8 @@ add_sshkey() { import_sshkey() { local public_key="$1" + local ssh_dir="${HOME}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key @@ -4891,30 +4895,23 @@ import_sshkey() { return 1 fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "该公钥已存在,无需重复添加" return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + chmod 700 "${HOME}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" @@ -4960,8 +4957,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4986,14 +4983,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then - echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "没有新的公钥需要添加(可能已全部存在)" fi @@ -5035,12 +5025,9 @@ fetch_github_ssh_keys() { } - - sshkey_panel() { - root_use - send_stats "私钥登录" + send_stats "用户密钥登录" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5049,7 +5036,7 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" fi - echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" + echo -e "用户密钥登录模式 ${IS_KEY_ENABLED}" echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" @@ -5087,7 +5074,7 @@ sshkey_panel() { 5) send_stats "编辑公钥文件" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5095,10 +5082,10 @@ sshkey_panel() { send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "私钥信息" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5116,20 +5103,44 @@ sshkey_panel() { - add_sshpasswd() { -echo "设置你的ROOT密码" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" + root_use + send_stats "设置密码登录模式" + echo "设置密码登录模式" + + local target_user="$1" + + # 如果没有通过参数传入,则交互输入 + if [[ -z "$target_user" ]]; then + read -e -p "请输入要修改密码的用户名(默认 root): " target_user + fi + + # 回车不输入,默认 root + target_user=${target_user:-root} + + # 校验用户是否存在 + if ! id "$target_user" >/dev/null 2>&1; then + echo "错误:用户 $target_user 不存在" + return 1 + fi + + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + echo -e "${gl_lv}密码设置完毕,已更改为密码登录模式!${gl_bai}" } + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion @@ -8403,7 +8414,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -13830,7 +13840,7 @@ linux_Settings() { echo -e "系统工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" @@ -13842,7 +13852,7 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}用户密钥登录模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" @@ -13888,8 +13898,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "root密码模式" + clear add_sshpasswd ;; @@ -14047,13 +14056,14 @@ EOF fi useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" install sudo echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config echo "操作已完成。" ;; @@ -14194,7 +14204,7 @@ EOF # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" echo "操作已完成。" ;; @@ -14205,7 +14215,7 @@ EOF # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers @@ -15930,4 +15940,3 @@ else ;; esac fi - From c27a38604ebb354b81aa032199c72b4669130982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:07:38 +0800 Subject: [PATCH 0612/1285] Change default parameter value to 'CN' --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a817ed793..3f5951eea 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From e26f110d3053b315c6acae6e3f835781f03bec70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:08:36 +0800 Subject: [PATCH 0613/1285] Refactor SSH configuration functions and add user key support --- kejilion.sh | 171 +++++++++++++++++++++++++++------------------------- 1 file changed, 90 insertions(+), 81 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ee56dd0fa..a817ed793 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4798,39 +4798,31 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 设置为 yes - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # 如果找到 PubkeyAuthentication 设置为 yes - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都没有匹配,则设置默认值 - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi + + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # 备份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4843,30 +4835,40 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" - - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { + root_use sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" + +} + + +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on } @@ -4876,6 +4878,8 @@ add_sshkey() { import_sshkey() { local public_key="$1" + local ssh_dir="${HOME}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key @@ -4891,30 +4895,23 @@ import_sshkey() { return 1 fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "该公钥已存在,无需重复添加" return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}公钥已成功导入,ROOT私钥登录已开启,已关闭ROOT密码登录,重连将会生效${gl_bai}" + chmod 700 "${HOME}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" @@ -4960,8 +4957,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4986,14 +4983,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then - echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "没有新的公钥需要添加(可能已全部存在)" fi @@ -5035,12 +5025,9 @@ fetch_github_ssh_keys() { } - - sshkey_panel() { - root_use - send_stats "私钥登录" + send_stats "用户密钥登录" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5049,7 +5036,7 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" fi - echo -e "ROOT私钥登录模式 ${IS_KEY_ENABLED}" + echo -e "用户密钥登录模式 ${IS_KEY_ENABLED}" echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "将会生成密钥对,更安全的方式SSH登录" @@ -5087,7 +5074,7 @@ sshkey_panel() { 5) send_stats "编辑公钥文件" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5095,10 +5082,10 @@ sshkey_panel() { send_stats "查看本机密钥" echo "------------------------" echo "公钥信息" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "私钥信息" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5116,20 +5103,44 @@ sshkey_panel() { - add_sshpasswd() { -echo "设置你的ROOT密码" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOT登录设置完毕!${gl_bai}" + root_use + send_stats "设置密码登录模式" + echo "设置密码登录模式" + + local target_user="$1" + + # 如果没有通过参数传入,则交互输入 + if [[ -z "$target_user" ]]; then + read -e -p "请输入要修改密码的用户名(默认 root): " target_user + fi + + # 回车不输入,默认 root + target_user=${target_user:-root} + + # 校验用户是否存在 + if ! id "$target_user" >/dev/null 2>&1; then + echo "错误:用户 $target_user 不存在" + return 1 + fi + + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + echo -e "${gl_lv}密码设置完毕,已更改为密码登录模式!${gl_bai}" } + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion @@ -8403,7 +8414,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -13830,7 +13840,7 @@ linux_Settings() { echo -e "系统工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" @@ -13842,7 +13852,7 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}ROOT私钥登录模式" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}用户密钥登录模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" @@ -13888,8 +13898,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "root密码模式" + clear add_sshpasswd ;; @@ -14047,13 +14056,14 @@ EOF fi useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" install sudo echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers passwd -l root + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config echo "操作已完成。" ;; @@ -14194,7 +14204,7 @@ EOF # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" echo "操作已完成。" ;; @@ -14205,7 +14215,7 @@ EOF # 创建新用户并设置密码 useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + add_sshpasswd "$new_username" # 赋予新用户sudo权限 echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers @@ -15930,4 +15940,3 @@ else ;; esac fi - From 1238e5c1083b824c37477c83d19c645b10e00948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:10:11 +0800 Subject: [PATCH 0614/1285] Enhance SSH login permission configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化用户SSH登录权限配置以提升稳定性。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 79c358cd9..b69a0b5ed 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1418,5 +1418,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具中新增网卡管理工具,快速查看网卡信息以及对网卡进行基础操作, 系统工具中新增系统日志管理工具,快速查看日志占用,查看各类服务日志,清理日志等基础操作, 申请证书失败后暂时移除不带证书HTTP访问会选项,该选项存在逻辑漏洞,导致站点异常。 +优化用户SSH登录权限配置,提升SSH连接稳定性。 ------------------------ From 7bee4e111deb0d07cccecafb07eb75220a223a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:14:56 +0800 Subject: [PATCH 0615/1285] Update default parameter in kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3f5951eea..ff3ef70a6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -13840,7 +13840,7 @@ linux_Settings() { echo -e "系统工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" From d7ae524933890dff074a8888cb712f46d212da75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:15:20 +0800 Subject: [PATCH 0616/1285] Change default parameter value to 'CN' --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ff3ef70a6..167eeb50e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" From 58afe4b7df96a0dd18bd3d4f30ac273b90a10950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:16:21 +0800 Subject: [PATCH 0617/1285] Fix spacing in menu options in kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index a817ed793..ff3ef70a6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13840,7 +13840,7 @@ linux_Settings() { echo -e "系统工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" From 3afa75309fbaea895cddc7303a44e21225111aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:28:00 +0800 Subject: [PATCH 0618/1285] Add root_use call in sshkey_on and sshkey_panel functions --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ff3ef70a6..1a32caa9c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4837,7 +4837,7 @@ new_ssh_port() { sshkey_on() { - root_use + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ @@ -5026,7 +5026,7 @@ fetch_github_ssh_keys() { sshkey_panel() { - + root_use send_stats "用户密钥登录" while true; do clear From 109768520a00d12d04a533ee14e90a3826eae8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:28:37 +0800 Subject: [PATCH 0619/1285] Add root_use call in sshkey_on and sshkey_panel functions --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 167eeb50e..95bb82c06 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4837,7 +4837,7 @@ new_ssh_port() { sshkey_on() { - root_use + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ @@ -5026,7 +5026,7 @@ fetch_github_ssh_keys() { sshkey_panel() { - + root_use send_stats "用户密钥登录" while true; do clear From 61290872a7e183b1cf09c706af078f1a477b14c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:25:32 +0800 Subject: [PATCH 0620/1285] Refactor SSH key management functions --- cn/kejilion.sh | 160 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 118 insertions(+), 42 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 95bb82c06..7533c14d7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4878,7 +4878,8 @@ add_sshkey() { import_sshkey() { local public_key="$1" - local ssh_dir="${HOME}/.ssh" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then @@ -4900,7 +4901,6 @@ import_sshkey() { return 0 fi - chmod 700 "${HOME}" mkdir -p "$ssh_dir" chmod 700 "$ssh_dir" touch "$auth_keys" @@ -4915,7 +4915,9 @@ import_sshkey() { fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4957,8 +4959,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p "${HOME}/.ssh" - chmod 700 "${HOME}/.ssh" + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4993,9 +4995,11 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" echo " 1. 登录 https://github.com/settings/keys" @@ -5020,7 +5024,7 @@ fetch_github_ssh_keys() { keys_url="https://github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } @@ -5141,6 +5145,17 @@ add_sshpasswd() { + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion @@ -5148,6 +5163,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "重装系统" dd_xitong_MollyLau() { @@ -13832,6 +13856,72 @@ log_menu() { +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "用法:create_user_with_sshkey <用户名>" + return 1 + fi + + # 创建用户 + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "导入公钥范例:" + echo " - URL: https://github.com/torvalds.keys" + echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "从 URL 导入 SSH 公钥" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "公钥直接导入" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "错误:未知参数 '$sshkey_vl'" + return 1 + ;; + esac + + + # 修正权限 + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo 免密 + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" </dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -14187,7 +14276,7 @@ EOF echo "" echo "账户操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 创建普通用户 2. 创建高级用户" echo "------------------------" echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" @@ -14201,46 +14290,34 @@ EOF 1) # 提示用户输入新用户名 read -e -p "请输入新用户名: " new_username + create_user_with_sshkey $new_username false - # 创建新用户并设置密码 - useradd -m -s /bin/bash "$new_username" - add_sshpasswd "$new_username" - - echo "操作已完成。" ;; 2) # 提示用户输入新用户名 read -e -p "请输入新用户名: " new_username - - # 创建新用户并设置密码 - useradd -m -s /bin/bash "$new_username" - add_sshpasswd "$new_username" - - # 赋予新用户sudo权限 - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "操作已完成。" + create_user_with_sshkey $new_username true ;; 3) read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 userdel -r "$username" ;; @@ -15901,6 +15978,7 @@ else sshkey) + shift case "$1" in "" ) @@ -15908,23 +15986,19 @@ else send_stats "SSHKey 交互菜单" sshkey_panel ;; - github ) shift send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "公钥直接导入" import_sshkey "$1" ;; - * ) echo "错误:未知参数 '$1'" echo "用法:" @@ -15934,9 +16008,11 @@ else echo " k sshkey github 从 GitHub 导入 SSH 公钥" ;; esac + ;; *) k_info ;; esac fi + From e585d375986ad5550488642110e15f1c3aab3c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:26:43 +0800 Subject: [PATCH 0621/1285] Refactor SSH key handling with base directory support --- kejilion.sh | 160 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 42 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1a32caa9c..56d28efcf 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4878,7 +4878,8 @@ add_sshkey() { import_sshkey() { local public_key="$1" - local ssh_dir="${HOME}/.ssh" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then @@ -4900,7 +4901,6 @@ import_sshkey() { return 0 fi - chmod 700 "${HOME}" mkdir -p "$ssh_dir" chmod 700 "$ssh_dir" touch "$auth_keys" @@ -4915,7 +4915,9 @@ import_sshkey() { fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4957,8 +4959,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p "${HOME}/.ssh" - chmod 700 "${HOME}/.ssh" + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4993,9 +4995,11 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" echo " 1. 登录 https://github.com/settings/keys" @@ -5020,7 +5024,7 @@ fetch_github_ssh_keys() { keys_url="https://github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } @@ -5141,6 +5145,17 @@ add_sshpasswd() { + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion @@ -5148,6 +5163,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "重装系统" dd_xitong_MollyLau() { @@ -13832,6 +13856,72 @@ log_menu() { +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "用法:create_user_with_sshkey <用户名>" + return 1 + fi + + # 创建用户 + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "导入公钥范例:" + echo " - URL: https://github.com/torvalds.keys" + echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "从 URL 导入 SSH 公钥" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "公钥直接导入" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "错误:未知参数 '$sshkey_vl'" + return 1 + ;; + esac + + + # 修正权限 + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo 免密 + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" </dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -14187,7 +14276,7 @@ EOF echo "" echo "账户操作" echo "------------------------" - echo "1. 创建普通账户 2. 创建高级账户" + echo "1. 创建普通用户 2. 创建高级用户" echo "------------------------" echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" @@ -14201,46 +14290,34 @@ EOF 1) # 提示用户输入新用户名 read -e -p "请输入新用户名: " new_username + create_user_with_sshkey $new_username false - # 创建新用户并设置密码 - useradd -m -s /bin/bash "$new_username" - add_sshpasswd "$new_username" - - echo "操作已完成。" ;; 2) # 提示用户输入新用户名 read -e -p "请输入新用户名: " new_username - - # 创建新用户并设置密码 - useradd -m -s /bin/bash "$new_username" - add_sshpasswd "$new_username" - - # 赋予新用户sudo权限 - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "操作已完成。" + create_user_with_sshkey $new_username true ;; 3) read -e -p "请输入用户名: " username - # 赋予新用户sudo权限 - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "请输入要删除的用户名: " username - # 删除用户及其主目录 userdel -r "$username" ;; @@ -15901,6 +15978,7 @@ else sshkey) + shift case "$1" in "" ) @@ -15908,23 +15986,19 @@ else send_stats "SSHKey 交互菜单" sshkey_panel ;; - github ) shift send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "公钥直接导入" import_sshkey "$1" ;; - * ) echo "错误:未知参数 '$1'" echo "用法:" @@ -15934,9 +16008,11 @@ else echo " k sshkey github 从 GitHub 导入 SSH 公钥" ;; esac + ;; *) k_info ;; esac fi + From d4f65baadd6e32a229836ac1e8a4295739818022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:29:42 +0800 Subject: [PATCH 0622/1285] Refactor SSH key management and user creation process Refactor SSH key management to support custom key directory and simplify user creation process. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index b69a0b5ed..1a53baccd 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1419,5 +1419,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具中新增系统日志管理工具,快速查看日志占用,查看各类服务日志,清理日志等基础操作, 申请证书失败后暂时移除不带证书HTTP访问会选项,该选项存在逻辑漏洞,导致站点异常。 优化用户SSH登录权限配置,提升SSH连接稳定性。 +重构 SSH 密钥管理功能,使其支持自定义 SSH 密钥根目录。更新用户创建流程,以简化SSH密钥导入和权限管理。 ------------------------ From bd0d3b1f1527cee72f51223350eabf28c6980766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:21:28 +0800 Subject: [PATCH 0623/1285] Silence output for passwd and ssh-keygen commands Suppress output for user locking and SSH configuration changes. --- cn/kejilion.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7533c14d7..d234ec4ad 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13903,7 +13903,7 @@ EOF chmod 440 "/etc/sudoers.d/$new_username" fi - passwd -l "$new_username" + passwd -l "$new_username" &>/dev/null echo "用户 $new_username 创建完成" } @@ -14147,8 +14147,10 @@ EOF create_user_with_sshkey $new_username true - passwd -l root - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } ;; @@ -14325,6 +14327,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; From 469c81bab792a3716e30b29eb8cde58543ec4b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:23:44 +0800 Subject: [PATCH 0624/1285] Redirect output of passwd and ssh-keygen commands Suppress output for passwd and ssh-keygen commands. --- kejilion.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 56d28efcf..b5dabe882 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13903,7 +13903,7 @@ EOF chmod 440 "/etc/sudoers.d/$new_username" fi - passwd -l "$new_username" + passwd -l "$new_username" &>/dev/null echo "用户 $new_username 创建完成" } @@ -14147,8 +14147,10 @@ EOF create_user_with_sshkey $new_username true - passwd -l root - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } ;; @@ -14325,6 +14327,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; From 73638dd3e1ee7e7788e646562e0fff779aff3b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:32:11 +0800 Subject: [PATCH 0625/1285] Update sshd_config to enforce UsePAM setting Remove existing UsePAM setting and enforce UsePAM yes in sshd_config. --- cn/kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d234ec4ad..35d32a66a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13903,8 +13903,11 @@ EOF chmod 440 "/etc/sudoers.d/$new_username" fi + sed -i '/^\s*#\?\s*UsePAM\s\+/d' /etc/ssh/sshd_config + echo 'UsePAM yes' >> /etc/ssh/sshd_config passwd -l "$new_username" &>/dev/null + echo "用户 $new_username 创建完成" } From 1fc117daa4f7e409ee1d241c02e6a179a4a751bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:32:57 +0800 Subject: [PATCH 0626/1285] Update SSH configuration to enable UsePAM Remove existing UsePAM line and set it to 'yes' in sshd_config. --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index b5dabe882..504b5a7a9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13903,8 +13903,11 @@ EOF chmod 440 "/etc/sudoers.d/$new_username" fi + sed -i '/^\s*#\?\s*UsePAM\s\+/d' /etc/ssh/sshd_config + echo 'UsePAM yes' >> /etc/ssh/sshd_config passwd -l "$new_username" &>/dev/null + echo "用户 $new_username 创建完成" } From 1700b192250b67d2a99887ccfd3e895bdcc1bea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:37:17 +0800 Subject: [PATCH 0627/1285] Add success message for new SSH keys added --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 35d32a66a..9d863fd61 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4985,6 +4985,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then + echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" sshkey_on else echo "没有新的公钥需要添加(可能已全部存在)" From 5f17969ddb4a90987d4ae43729485052b526f509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:37:53 +0800 Subject: [PATCH 0628/1285] Add success message for new SSH keys added --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 504b5a7a9..1a175998c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4985,6 +4985,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then + echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" sshkey_on else echo "没有新的公钥需要添加(可能已全部存在)" From c958b7630bd3d01b629690383ca39d11e9d06929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:42:53 +0800 Subject: [PATCH 0629/1285] Add SSH restart after user creation --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1a175998c..e4f2f3993 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13907,7 +13907,7 @@ EOF sed -i '/^\s*#\?\s*UsePAM\s\+/d' /etc/ssh/sshd_config echo 'UsePAM yes' >> /etc/ssh/sshd_config passwd -l "$new_username" &>/dev/null - + restart_ssh echo "用户 $new_username 创建完成" } From f98d5b990beeb85cb1662a2ea7fa48234e3a7f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:43:35 +0800 Subject: [PATCH 0630/1285] Add SSH restart after creating new user --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9d863fd61..08d005658 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13907,7 +13907,7 @@ EOF sed -i '/^\s*#\?\s*UsePAM\s\+/d' /etc/ssh/sshd_config echo 'UsePAM yes' >> /etc/ssh/sshd_config passwd -l "$new_username" &>/dev/null - + restart_ssh echo "用户 $new_username 创建完成" } From 33ef9174e002a3e5575fad86b384f5ffc7b386a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:30:05 +0800 Subject: [PATCH 0631/1285] Create symbolic links for 'k' command Add symbolic links for the 'k' command in both /usr/bin and /usr/local/bin based on the value of 'kuaijiejian'. --- cn/kejilion.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 08d005658..3005fb160 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -102,6 +102,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -13977,7 +13978,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "快捷键已设置" send_stats "脚本快捷键已设置" break_end From 48d3288c09f92ba6deb870b3fbe49ec3d900c72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:31:02 +0800 Subject: [PATCH 0632/1285] Create symbolic links for 'k' command Add symbolic links for the 'k' command in both /usr/bin and /usr/local/bin, with a condition to avoid overwriting existing links. --- kejilion.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index e4f2f3993..0742f789b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -102,6 +102,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -13977,7 +13978,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "快捷键已设置" send_stats "脚本快捷键已设置" break_end From acb6f71614274bca02dd4e76235f903875ee993b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:32:45 +0800 Subject: [PATCH 0633/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1a53baccd..54b7ea7ed 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1420,5 +1420,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 申请证书失败后暂时移除不带证书HTTP访问会选项,该选项存在逻辑漏洞,导致站点异常。 优化用户SSH登录权限配置,提升SSH连接稳定性。 重构 SSH 密钥管理功能,使其支持自定义 SSH 密钥根目录。更新用户创建流程,以简化SSH密钥导入和权限管理。 +提升普通用户sudo环境下的k快捷键兼容性和可用性。 ------------------------ From 41b70b7232676d34a25a94693f80f23ee53652b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:47:54 +0800 Subject: [PATCH 0634/1285] Add tool installation check and package manager detection Added a list of tools to check installation status and display package manager used. --- cn/kejilion.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3005fb160..c4836ed06 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7205,6 +7205,58 @@ linux_tools() { clear # send_stats "基础工具" echo -e "基础工具" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ 未识别的包管理器" + exit 1 + fi + + echo "📦 使用包管理器: $PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # 左列 + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s 已安装" "${tools[i]}") + else + left=$(printf "❌ %-12s 未安装" "${tools[i]}") + fi + + # 右列(防止数组越界) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s 已安装" "${tools[i+1]}") + else + right=$(printf "❌ %-12s 未安装" "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" From f7c6d42e4f4980a91fc7fe6d95d060657023d141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:48:27 +0800 Subject: [PATCH 0635/1285] Add tool list and package manager detection --- kejilion.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 0742f789b..9fdb02b94 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7205,6 +7205,58 @@ linux_tools() { clear # send_stats "基础工具" echo -e "基础工具" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ 未识别的包管理器" + exit 1 + fi + + echo "📦 使用包管理器: $PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # 左列 + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s 已安装" "${tools[i]}") + else + left=$(printf "❌ %-12s 未安装" "${tools[i]}") + fi + + # 右列(防止数组越界) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s 已安装" "${tools[i+1]}") + else + right=$(printf "❌ %-12s 未安装" "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" From a85fc5ed2997d0c68674f88a942614475385ec99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:49:23 +0800 Subject: [PATCH 0636/1285] Enhance component functionality with installation status Added installation status for various components. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 54b7ea7ed..d39b62764 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1421,5 +1421,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 优化用户SSH登录权限配置,提升SSH连接稳定性。 重构 SSH 密钥管理功能,使其支持自定义 SSH 密钥根目录。更新用户创建流程,以简化SSH密钥导入和权限管理。 提升普通用户sudo环境下的k快捷键兼容性和可用性。 +基础组件功能增加了各个组件的安装状态。 ------------------------ From 968be36c6362ee72d56c23c865bc3da380f7d39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:29:36 +0800 Subject: [PATCH 0637/1285] Remove unnecessary blank lines in kejilion.sh --- kejilion.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9fdb02b94..863e9d5aa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7205,13 +7205,13 @@ linux_tools() { clear # send_stats "基础工具" echo -e "基础工具" - + tools=( curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ) - + if command -v apt >/dev/null 2>&1; then PM="apt" elif command -v dnf >/dev/null 2>&1; then @@ -7232,10 +7232,10 @@ linux_tools() { echo "❌ 未识别的包管理器" exit 1 fi - + echo "📦 使用包管理器: $PM" echo -e "${gl_kjlan}------------------------${gl_bai}" - + for ((i=0; i<${#tools[@]}; i+=2)); do # 左列 if command -v "${tools[i]}" >/dev/null 2>&1; then @@ -7243,7 +7243,7 @@ linux_tools() { else left=$(printf "❌ %-12s 未安装" "${tools[i]}") fi - + # 右列(防止数组越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then @@ -13662,7 +13662,7 @@ switch_mirror() { else echo "使用官方镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ + --source mirrors.xtom.com \ --protocol https \ --use-intranet-source false \ --backup true \ @@ -16078,4 +16078,3 @@ else ;; esac fi - From 5844db3400fabb3cf18e0b4e4ab40e458cc06e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:30:26 +0800 Subject: [PATCH 0638/1285] Remove unnecessary blank lines in kejilion.sh --- cn/kejilion.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c4836ed06..fbcd5c197 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7205,13 +7205,13 @@ linux_tools() { clear # send_stats "基础工具" echo -e "基础工具" - + tools=( curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ) - + if command -v apt >/dev/null 2>&1; then PM="apt" elif command -v dnf >/dev/null 2>&1; then @@ -7232,10 +7232,10 @@ linux_tools() { echo "❌ 未识别的包管理器" exit 1 fi - + echo "📦 使用包管理器: $PM" echo -e "${gl_kjlan}------------------------${gl_bai}" - + for ((i=0; i<${#tools[@]}; i+=2)); do # 左列 if command -v "${tools[i]}" >/dev/null 2>&1; then @@ -7243,7 +7243,7 @@ linux_tools() { else left=$(printf "❌ %-12s 未安装" "${tools[i]}") fi - + # 右列(防止数组越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then @@ -13662,7 +13662,7 @@ switch_mirror() { else echo "使用官方镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ + --source mirrors.xtom.com \ --protocol https \ --use-intranet-source false \ --backup true \ @@ -16078,4 +16078,3 @@ else ;; esac fi - From e6242af74e9b6d11f048342ece0fc2da281d7be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:15:57 +0800 Subject: [PATCH 0639/1285] Change install-epel option from true to false --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fbcd5c197..866ab5b91 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13657,10 +13657,10 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "使用官方镜像源..." + echo "使用海外镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ --protocol https \ @@ -13669,7 +13669,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode fi } From 6fefccad3a0425aadd87d791c4c4ed33a26f8b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:16:38 +0800 Subject: [PATCH 0640/1285] Set install-epel option to false Changed the installation option for EPEL from true to false. --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 863e9d5aa..fdf255207 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13657,10 +13657,10 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "使用官方镜像源..." + echo "使用海外镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ --protocol https \ @@ -13669,7 +13669,7 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode fi } From d4ce0224b84096b59b9b8dbe2f797b5abd173893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:52:37 +0800 Subject: [PATCH 0641/1285] Remove redundant PasswordAuthentication setting --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 866ab5b91..49acf200a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4806,12 +4806,11 @@ correct_ssh_config() { -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" else - sed -i -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } From e79d2f36a6526b381d3f29ff2f390e62d1cf72cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:54:33 +0800 Subject: [PATCH 0642/1285] Change PasswordAuthentication to 'no' in sshd_config --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fdf255207..a568a81c4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4806,12 +4806,11 @@ correct_ssh_config() { -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" else - sed -i -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } From 655ac9e97d249f2dd508a17323ba7bbb4c93382a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 18:07:52 +0800 Subject: [PATCH 0643/1285] Update version and color messages in kejilion.sh --- cn/kejilion.sh | 100 ++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 49acf200a..057e573e7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.5" +sh_v="4.3.6" gl_hui='\e[37m' @@ -177,7 +177,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_kjlan}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -252,7 +252,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_kjlan}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -449,7 +449,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_kjlan}正在安装docker环境...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -628,7 +628,7 @@ while true; do send_stats "拉取镜像" read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_kjlan}正在获取镜像: $name${gl_bai}" docker pull $name done ;; @@ -636,7 +636,7 @@ while true; do send_stats "更新镜像" read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_kjlan}正在更新镜像: $name${gl_bai}" docker pull $name done ;; @@ -4592,7 +4592,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_kjlan}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4619,7 +4619,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_kjlan}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -5743,7 +5743,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_kjlan}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5757,7 +5757,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" # 构建 mount 参数 local MOUNT_PARAMS="" @@ -7100,7 +7100,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}正在查询系统信息……${gl_bai}" send_stats "系统信息查询" ip_address @@ -7575,12 +7578,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7588,7 +7585,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}当前备份列表:${NC}" + echo -e "${gl_kjlan}当前备份列表:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -7600,7 +7597,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Docker备份" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${gl_kjlan}正在备份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers @@ -7615,7 +7612,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}没有找到容器${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7629,12 +7626,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${gl_lv}备份容器: $c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${gl_kjlan}检测到 $c 是 docker-compose 容器${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7644,7 +7641,7 @@ docker_ssh_migration() { # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" continue fi @@ -7655,9 +7652,9 @@ docker_ssh_migration() { echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已打包: ${project_dir}${gl_bai}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" fi else # 普通容器备份卷 @@ -7694,14 +7691,14 @@ docker_ssh_migration() { # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}备份 /home/docker 下的文件...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}可用还原脚本: ${RESTORE_SCRIPT}${gl_bai}" } @@ -7713,9 +7710,9 @@ docker_ssh_migration() { send_stats "Docker还原" read -e -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${gl_kjlan}开始执行还原操作...${gl_bai}" install tar jq gzip install_docker @@ -7732,7 +7729,7 @@ docker_ssh_migration() { # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${gl_bai}" continue fi @@ -7741,32 +7738,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已解压到: $original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 还原完成!${gl_bai}" fi done # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + echo -e "${gl_kjlan}检查并还原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${gl_lv}处理容器: $container${gl_bai}" # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${gl_huang}容器 [$container] 已在运行,跳过还原...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } # 端口映射 PORT_ARGS="" @@ -7800,7 +7797,7 @@ docker_ssh_migration() { # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${gl_huang}容器 [$container] 存在但未运行,删除旧容器...${gl_bai}" docker rm -f "$container" fi @@ -7809,16 +7806,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}正在还原 /home/docker 下的文件...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${gl_lv}/home/docker 下的文件已还原完成${gl_bai}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${gl_huang}未找到 /home/docker 下文件的备份,跳过...${gl_bai}" fi @@ -7832,7 +7829,7 @@ docker_ssh_migration() { send_stats "Docker迁移" install jq read -e -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } read -e -p "目标服务器IP: " TARGET_IP read -e -p "目标服务器SSH用户名: " TARGET_USER @@ -7841,7 +7838,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${gl_huang}传输备份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then # 使用密钥登录 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -7855,9 +7852,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker备份文件删除" read -e -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${gl_lv}已删除备份: ${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7887,7 +7884,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${gl_hong}无效选项${gl_bai}" ;; esac break_end done @@ -9292,7 +9289,7 @@ linux_ldnmp() { send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9390,7 +9387,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9590,6 +9587,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -13352,7 +13350,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13409,7 +13407,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else From dfd742497b45555e5df39ae2ef805804700a0f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 18:08:36 +0800 Subject: [PATCH 0644/1285] Update version and color messages in kejilion.sh --- kejilion.sh | 100 +++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a568a81c4..da03e471c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.5" +sh_v="4.3.6" gl_hui='\e[37m' @@ -177,7 +177,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安装 $package...${gl_bai}" + echo -e "${gl_kjlan}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -252,7 +252,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}正在卸载 $package...${gl_bai}" + echo -e "${gl_kjlan}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -449,7 +449,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安装docker环境...${gl_bai}" + echo -e "${gl_kjlan}正在安装docker环境...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -628,7 +628,7 @@ while true; do send_stats "拉取镜像" read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在获取镜像: $name${gl_bai}" + echo -e "${gl_kjlan}正在获取镜像: $name${gl_bai}" docker pull $name done ;; @@ -636,7 +636,7 @@ while true; do send_stats "更新镜像" read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新镜像: $name${gl_bai}" + echo -e "${gl_kjlan}正在更新镜像: $name${gl_bai}" docker pull $name done ;; @@ -4592,7 +4592,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系统更新...${gl_bai}" + echo -e "${gl_kjlan}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4619,7 +4619,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系统清理...${gl_bai}" + echo -e "${gl_kjlan}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -5743,7 +5743,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒库...${gl_bai}" + echo -e "${gl_kjlan}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5757,7 +5757,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" # 构建 mount 参数 local MOUNT_PARAMS="" @@ -7100,7 +7100,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}正在查询系统信息……${gl_bai}" send_stats "系统信息查询" ip_address @@ -7575,12 +7578,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7588,7 +7585,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}当前备份列表:${NC}" + echo -e "${gl_kjlan}当前备份列表:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } @@ -7600,7 +7597,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Docker备份" - echo -e "${YELLOW}正在备份 Docker 容器...${NC}" + echo -e "${gl_kjlan}正在备份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers @@ -7615,7 +7612,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}没有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}没有找到容器${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7629,12 +7626,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}备份容器: $c${NC}" + echo -e "${gl_lv}备份容器: $c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}检测到 $c 是 docker-compose 容器${NC}" + echo -e "${gl_kjlan}检测到 $c 是 docker-compose 容器${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7644,7 +7641,7 @@ docker_ssh_migration() { # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已备份过,跳过重复打包...${NC}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" continue fi @@ -7655,9 +7652,9 @@ docker_ssh_migration() { echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 项目 [$project_name] 已打包: ${project_dir}${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已打包: ${project_dir}${gl_bai}" else - echo -e "${RED}未找到 docker-compose.yml,跳过此容器...${NC}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" fi else # 普通容器备份卷 @@ -7694,14 +7691,14 @@ docker_ssh_migration() { # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${BLUE}备份 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}备份 /home/docker 下的文件...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}备份完成: ${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用还原脚本: ${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}可用还原脚本: ${RESTORE_SCRIPT}${gl_bai}" } @@ -7713,9 +7710,9 @@ docker_ssh_migration() { send_stats "Docker还原" read -e -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - echo -e "${BLUE}开始执行还原操作...${NC}" + echo -e "${gl_kjlan}开始执行还原操作...${gl_bai}" install tar jq gzip install_docker @@ -7732,7 +7729,7 @@ docker_ssh_migration() { # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${NC}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${gl_bai}" continue fi @@ -7741,32 +7738,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 项目 [$project_name] 已解压到: $original_path${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已解压到: $original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 项目 [$project_name] 还原完成!${NC}" + echo -e "${gl_lv}Compose 项目 [$project_name] 还原完成!${gl_bai}" fi done # --------- 继续还原普通容器 --------- - echo -e "${BLUE}检查并还原普通 Docker 容器...${NC}" + echo -e "${gl_kjlan}检查并还原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}处理容器: $container${NC}" + echo -e "${gl_lv}处理容器: $container${gl_bai}" # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在运行,跳过还原...${NC}" + echo -e "${gl_huang}容器 [$container] 已在运行,跳过还原...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到镜像信息,跳过: $container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } # 端口映射 PORT_ARGS="" @@ -7800,7 +7797,7 @@ docker_ssh_migration() { # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未运行,删除旧容器...${NC}" + echo -e "${gl_huang}容器 [$container] 存在但未运行,删除旧容器...${gl_bai}" docker rm -f "$container" fi @@ -7809,16 +7806,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的备份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在还原 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}正在还原 /home/docker 下的文件...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已还原完成${NC}" + echo -e "${gl_lv}/home/docker 下的文件已还原完成${gl_bai}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的备份,跳过...${NC}" + echo -e "${gl_huang}未找到 /home/docker 下文件的备份,跳过...${gl_bai}" fi @@ -7832,7 +7829,7 @@ docker_ssh_migration() { send_stats "Docker迁移" install jq read -e -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } read -e -p "目标服务器IP: " TARGET_IP read -e -p "目标服务器SSH用户名: " TARGET_USER @@ -7841,7 +7838,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}传输备份中...${NC}" + echo -e "${gl_huang}传输备份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then # 使用密钥登录 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -7855,9 +7852,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker备份文件删除" read -e -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}备份目录不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已删除备份: ${BACKUP_DIR}${NC}" + echo -e "${gl_lv}已删除备份: ${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7887,7 +7884,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}无效选项${NC}" ;; + *) echo -e "${gl_hong}无效选项${gl_bai}" ;; esac break_end done @@ -9292,7 +9289,7 @@ linux_ldnmp() { send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9390,7 +9387,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9590,6 +9587,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -13352,7 +13350,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13409,7 +13407,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else From 0aca24cdea2cba2a6f3d08392a87b2d46ddd86d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 28 Jan 2026 18:11:49 +0800 Subject: [PATCH 0645/1285] Refactor SSH key management and improve user experience Refactor SSH key management to support custom root directory and update user creation process for easier SSH key import and permission management. Improve compatibility and usability of the 'k' shortcut for regular users in sudo environment. --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index d39b62764..ceb91ff4a 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1423,4 +1423,9 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 提升普通用户sudo环境下的k快捷键兼容性和可用性。 基础组件功能增加了各个组件的安装状态。 ------------------------ +2026-01-28 v4.3.6 +调整正在处理事件时的等待文字的颜色方案,与脚本配色更统一。 +优化应用市场更新应用列表时的体验。 +优化系统信息查询时的等待体验。 +------------------------ From 9d6ad9522b7d86882109f6448dc2053a455a1d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:32:46 +0800 Subject: [PATCH 0646/1285] Refactor GitHub URLs to use variable Updated URLs to use a variable for GitHub HTTPS links. --- cn/kejilion.sh | 116 +++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 057e573e7..fd8a0afe6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -2134,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -4266,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP服务端 $check_frp $update_status" echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4364,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP客户端 $check_frp $update_status" echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4457,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "官网地址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "已下载视频列表:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" @@ -4476,7 +4478,7 @@ yt_menu_pro() { send_stats "正在安装 yt-dlp..." echo "正在安装 yt-dlp..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -5003,14 +5005,14 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo " 1. 登录 https://github.com/settings/keys" + echo " 1. 登录 ${gh_https_url}github.com/settings/keys" echo " 2. 点击 New SSH key 或 Add SSH key" echo " 3. Title 可随意填写(例如:Home Laptop 2026)" echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" echo " 5. 点击 Add SSH key 完成添加" echo "" echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " https://github.com/您的用户名.keys" + echo " ${gh_https_url}github.com/您的用户名.keys" echo "" @@ -5023,7 +5025,7 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" fetch_remote_ssh_keys "${keys_url}" "${base_dir}" @@ -5221,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " - echo -e "${gl_hui}bin456789项目地址: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro项目地址: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: ${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -9846,7 +9848,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_url="官网介绍: ${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -11086,7 +11088,7 @@ while true; do } local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="官网介绍: ${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11151,7 +11153,7 @@ while true; do } local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_url="官网介绍: ${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11181,7 +11183,7 @@ while true; do } local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_url="官网介绍: ${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11204,7 +11206,7 @@ while true; do } local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_url="官网介绍: ${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11237,7 +11239,7 @@ while true; do } local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_url="官网介绍: ${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11257,7 +11259,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11309,7 +11311,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11365,7 +11367,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_url="官方网站: ${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11419,7 +11421,7 @@ while true; do local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11470,7 +11472,7 @@ while true; do } local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11483,7 +11485,7 @@ while true; do local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_url="官方网站: ${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11531,7 +11533,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11549,7 +11551,7 @@ while true; do } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11585,7 +11587,7 @@ while true; do } local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_url="官网介绍: ${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11614,7 +11616,7 @@ while true; do } local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_url="官网介绍: ${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11784,7 +11786,7 @@ while true; do } local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11800,7 +11802,7 @@ while true; do local app_name="moontv私有影视" local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_url="视频介绍: ${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11866,7 +11868,7 @@ while true; do } local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_url="官网介绍: ${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11893,7 +11895,7 @@ while true; do } local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_url="官网介绍: ${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11928,7 +11930,7 @@ while true; do } local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_url="官网介绍: ${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" local docker_passwd="" local app_size="1" @@ -11943,7 +11945,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_url="官方介绍: ${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -12172,7 +12174,7 @@ while true; do } local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" local docker_passwd="" local app_size="1" @@ -12203,7 +12205,7 @@ while true; do } local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_url="官网介绍: ${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12216,7 +12218,7 @@ while true; do local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_url="官网介绍: ${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12309,7 +12311,7 @@ while true; do } local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_url="官网介绍: ${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" local docker_passwd="" local app_size="1" @@ -12368,7 +12370,7 @@ while true; do } local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_url="官网介绍: ${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" @@ -12440,7 +12442,7 @@ while true; do local app_name="gitea私有代码仓库" local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_url="视频介绍: ${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12530,7 +12532,7 @@ while true; do } local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_url="官网介绍: ${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12561,7 +12563,7 @@ while true; do } local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_url="官网介绍: ${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12625,7 +12627,7 @@ while true; do local app_name="2FAuth自托管二步验证器" local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_url="官网: ${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12856,7 +12858,7 @@ while true; do local app_name="dsm群晖虚拟机" local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_url="官网: ${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12927,7 +12929,7 @@ while true; do } local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_url="官网介绍: ${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12940,7 +12942,7 @@ while true; do local app_id="101" local app_name="AI视频生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="官方网站: ${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12995,7 +12997,7 @@ while true; do } local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_url="官网介绍: ${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -13008,7 +13010,7 @@ while true; do local app_id="103" local app_name="Umami网站统计工具" local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_url="官方网站: ${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -13074,7 +13076,7 @@ while true; do } local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_url="官网介绍: ${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13101,7 +13103,7 @@ while true; do } local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_url="官网介绍: ${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13136,7 +13138,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_url="官网介绍: ${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13151,7 +13153,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot聊天机器人" local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_url="官方网站: ${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13208,7 +13210,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_url="官网介绍: ${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13221,7 +13223,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeep书签管理" local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_url="官方网站: ${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13274,7 +13276,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13306,7 +13308,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" - local docker_url="项目地址: https://github.com/gdy666/lucky" + local docker_url="项目地址: ${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" local app_size="1" @@ -13336,7 +13338,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" - local docker_url="项目地址: https://github.com/jlesage/docker-firefox" + local docker_url="项目地址: ${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13921,7 +13923,7 @@ create_user_with_sshkey() { useradd -m -s /bin/bash "$new_username" || return 1 echo "导入公钥范例:" - echo " - URL: https://github.com/torvalds.keys" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl @@ -15525,7 +15527,7 @@ echo -e "${gl_kjlan}B站: ${gl_bai}https://b23.tv/2mqnQyh ${gl_kjla echo -e "${gl_kjlan}官网: ${gl_bai}https://kejilion.pro/ ${gl_kjlan}导航: ${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}博客: ${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}软件中心: ${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}脚本官网: ${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址: ${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}脚本官网: ${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址: ${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } From 9f8a78515f5c2eed24b14283c96e36e76508871b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:33:34 +0800 Subject: [PATCH 0647/1285] Refactor GitHub URLs to use gh_https_url variable Updated GitHub URLs to use a variable for HTTPS prefix. --- kejilion.sh | 116 ++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index da03e471c..aee28621a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -2134,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -4266,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP服务端 $check_frp $update_status" echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: https://github.com/fatedier/frp/" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4364,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP客户端 $check_frp $update_status" echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: https://github.com/fatedier/frp/" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4457,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:https://github.com/yt-dlp/yt-dlp" + echo -e "官网地址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "已下载视频列表:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" @@ -4476,7 +4478,7 @@ yt_menu_pro() { send_stats "正在安装 yt-dlp..." echo "正在安装 yt-dlp..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -5003,14 +5005,14 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo " 1. 登录 https://github.com/settings/keys" + echo " 1. 登录 ${gh_https_url}github.com/settings/keys" echo " 2. 点击 New SSH key 或 Add SSH key" echo " 3. Title 可随意填写(例如:Home Laptop 2026)" echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" echo " 5. 点击 Add SSH key 完成添加" echo "" echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " https://github.com/您的用户名.keys" + echo " ${gh_https_url}github.com/您的用户名.keys" echo "" @@ -5023,7 +5025,7 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" fetch_remote_ssh_keys "${keys_url}" "${base_dir}" @@ -5221,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " - echo -e "${gl_hui}bin456789项目地址: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro项目地址: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: ${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -9846,7 +9848,7 @@ while true; do local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: https://github.com/OpenListTeam/OpenList" + local docker_url="官网介绍: ${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -11086,7 +11088,7 @@ while true; do } local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="官网介绍: ${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11151,7 +11153,7 @@ while true; do } local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/prometheus/node_exporter" + local docker_url="官网介绍: ${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11181,7 +11183,7 @@ while true; do } local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: https://github.com/google/cadvisor" + local docker_url="官网介绍: ${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11204,7 +11206,7 @@ while true; do } local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: https://github.com/dgtlmoon/changedetection.io" + local docker_url="官网介绍: ${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11237,7 +11239,7 @@ while true; do } local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: https://github.com/donknap/dpanel" + local docker_url="官网介绍: ${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11257,7 +11259,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11309,7 +11311,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11365,7 +11367,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: https://github.com/Calcium-Ion/new-api" + local app_url="官方网站: ${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11419,7 +11421,7 @@ while true; do local app_id="60" local app_name="JumpServer开源堡垒机" local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: https://github.com/jumpserver/jumpserver" + local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11470,7 +11472,7 @@ while true; do } local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: https://github.com/LibreTranslate/LibreTranslate" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11483,7 +11485,7 @@ while true; do local app_id="62" local app_name="RAGFlow知识库" local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: https://github.com/infiniflow/ragflow" + local app_url="官方网站: ${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11531,7 +11533,7 @@ while true; do } local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: https://github.com/open-webui/open-webui" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11549,7 +11551,7 @@ while true; do } local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: https://github.com/CorentinTh/it-tools" + local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11585,7 +11587,7 @@ while true; do } local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: https://github.com/n8n-io/n8n" + local docker_url="官网介绍: ${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11614,7 +11616,7 @@ while true; do } local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: https://github.com/jeessy2/ddns-go" + local docker_url="官网介绍: ${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11784,7 +11786,7 @@ while true; do } local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: https://github.com/LibreSpark/LibreTV" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11800,7 +11802,7 @@ while true; do local app_name="moontv私有影视" local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: https://github.com/MoonTechLab/LunaTV" + local app_url="视频介绍: ${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11866,7 +11868,7 @@ while true; do } local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: https://github.com/foamzou/melody" + local docker_url="官网介绍: ${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11893,7 +11895,7 @@ while true; do } local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: https://github.com/rwv/chinese-dos-games" + local docker_url="官网介绍: ${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11928,7 +11930,7 @@ while true; do } local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: https://github.com/cnk3x/xunlei" + local docker_url="官网介绍: ${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" local docker_passwd="" local app_size="1" @@ -11943,7 +11945,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: https://github.com/chaitin/PandaWiki" + local app_url="官方介绍: ${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -12172,7 +12174,7 @@ while true; do } local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: https://github.com/komari-monitor/komari/tree/main" + local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" local docker_passwd="" local app_size="1" @@ -12203,7 +12205,7 @@ while true; do } local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: https://github.com/ellite/Wallos" + local docker_url="官网介绍: ${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12216,7 +12218,7 @@ while true; do local app_id="85" local app_name="immich图片视频管理器" local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: https://github.com/immich-app/immich" + local app_url="官网介绍: ${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12309,7 +12311,7 @@ while true; do } local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: https://github.com/synctv-org/synctv" + local docker_url="官网介绍: ${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" local docker_passwd="" local app_size="1" @@ -12368,7 +12370,7 @@ while true; do } local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: https://github.com/vastsa/FileCodeBox" + local docker_url="官网介绍: ${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" @@ -12440,7 +12442,7 @@ while true; do local app_name="gitea私有代码仓库" local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: https://github.com/go-gitea/gitea" + local app_url="视频介绍: ${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12530,7 +12532,7 @@ while true; do } local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: https://github.com/sigoden/dufs" + local docker_url="官网介绍: ${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12561,7 +12563,7 @@ while true; do } local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: https://github.com/GopeedLab/gopeed" + local docker_url="官网介绍: ${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12625,7 +12627,7 @@ while true; do local app_name="2FAuth自托管二步验证器" local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: https://github.com/Bubka/2FAuth" + local app_url="官网: ${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12856,7 +12858,7 @@ while true; do local app_name="dsm群晖虚拟机" local app_text="Docker容器中的虚拟DSM" - local app_url="官网: https://github.com/vdsm/virtual-dsm" + local app_url="官网: ${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12927,7 +12929,7 @@ while true; do } local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: https://github.com/syncthing/syncthing" + local docker_url="官网介绍: ${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12940,7 +12942,7 @@ while true; do local app_id="101" local app_name="AI视频生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="官方网站: ${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12995,7 +12997,7 @@ while true; do } local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: https://github.com/Privoce/vocechat-web" + local docker_url="官网介绍: ${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -13008,7 +13010,7 @@ while true; do local app_id="103" local app_name="Umami网站统计工具" local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: https://github.com/umami-software/umami" + local app_url="官方网站: ${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -13074,7 +13076,7 @@ while true; do } local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: https://github.com/siyuan-note/siyuan" + local docker_url="官网介绍: ${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13101,7 +13103,7 @@ while true; do } local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: https://github.com/plait-board/drawnix" + local docker_url="官网介绍: ${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13136,7 +13138,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: https://github.com/fish2018/pansou" + local docker_url="官网介绍: ${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13151,7 +13153,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot聊天机器人" local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: https://github.com/langbot-app/LangBot" + local app_url="官方网站: ${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13208,7 +13210,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: https://github.com/zfile-dev/zfile" + local docker_url="官网介绍: ${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13221,7 +13223,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeep书签管理" local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: https://github.com/karakeep-app/karakeep" + local app_url="官方网站: ${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13274,7 +13276,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: https://github.com/c4illin/ConvertX" + local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13306,7 +13308,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" - local docker_url="项目地址: https://github.com/gdy666/lucky" + local docker_url="项目地址: ${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" local app_size="1" @@ -13336,7 +13338,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" - local docker_url="项目地址: https://github.com/jlesage/docker-firefox" + local docker_url="项目地址: ${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13921,7 +13923,7 @@ create_user_with_sshkey() { useradd -m -s /bin/bash "$new_username" || return 1 echo "导入公钥范例:" - echo " - URL: https://github.com/torvalds.keys" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl @@ -15525,7 +15527,7 @@ echo -e "${gl_kjlan}B站: ${gl_bai}https://b23.tv/2mqnQyh ${gl_kjla echo -e "${gl_kjlan}官网: ${gl_bai}https://kejilion.pro/ ${gl_kjlan}导航: ${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}博客: ${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}软件中心: ${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}脚本官网: ${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址: ${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}脚本官网: ${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址: ${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } From c8cc5316b9bd1947395b62e3034f5e69f1922994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:54:48 +0800 Subject: [PATCH 0648/1285] Add conditional for Oracle OS in kejilion.sh --- cn/kejilion.sh | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fd8a0afe6..d884f8bdf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13660,16 +13660,29 @@ switch_mirror() { --pure-mode else echo "使用海外镜像源..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --source mirrors.xtom.com \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel false \ - --pure-mode + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } From 9828ea0f13d30e430a138ff1bf03fa7c0a1d5899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:55:28 +0800 Subject: [PATCH 0649/1285] Add conditional for Oracle OS in script --- kejilion.sh | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index aee28621a..8083e8f0d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13660,16 +13660,29 @@ switch_mirror() { --pure-mode else echo "使用海外镜像源..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --source mirrors.xtom.com \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel false \ - --pure-mode + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } From 77fd2f65701df22c05f7fe070d5604e900735856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:02:26 +0800 Subject: [PATCH 0650/1285] Update application names and installation scripts --- cn/kejilion.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d884f8bdf..371a7bdfb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9683,7 +9683,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color110}ClawdBot/Moltbot机器人" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -10955,25 +10955,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanel 原耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -13346,6 +13347,10 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot) + bash <(curl -sSL ${gh_proxy}raw.githubusercontent.com/sky22333/shell/main/moltbot/install.sh) + ;; + b) clear From 1a68ba21c33bd87ade087378406d93a13554bbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:03:19 +0800 Subject: [PATCH 0651/1285] Update application names and installation scripts --- kejilion.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8083e8f0d..f30e96a2c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9683,7 +9683,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color110}ClawdBot/Moltbot机器人" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -10955,25 +10955,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanel 原耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -13346,6 +13347,10 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot) + bash <(curl -sSL ${gh_proxy}raw.githubusercontent.com/sky22333/shell/main/moltbot/install.sh) + ;; + b) clear From e77fa24305893d7b7c765a0e7d53e80098b98223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:05:33 +0800 Subject: [PATCH 0652/1285] Update log with ClawdBot/Moltbot project details Added information about ClawdBot/Moltbot project installation and usage. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index ceb91ff4a..4666d0406 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1427,5 +1427,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 调整正在处理事件时的等待文字的颜色方案,与脚本配色更统一。 优化应用市场更新应用列表时的体验。 优化系统信息查询时的等待体验。 +应用市场增加了最近比较火的ClawdBot/Moltbot机器人项目的安装与使用,感谢爱折腾的sky的脚本支持。 ------------------------ From a85cbb0491f390eb46ffe3138d26a9b7b9fc018c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:38:21 +0800 Subject: [PATCH 0653/1285] Add Moltbot/Clawdbot management menu --- cn/kejilion.sh | 110 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 371a7bdfb..46cad27dd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9582,6 +9582,114 @@ linux_ldnmp() { + + + +moltbot_menu() { + + # Moltbot / Clawdbot 安装部署菜单 + + show_menu() { + clear + echo "=======================================" + echo " Moltbot / Clawdbot 管理菜单" + echo "=======================================" + echo "1) 安装" + echo "2) 初始化配置" + echo "3) 启动" + echo "4) 停止" + echo "5) 日志查看" + echo "6) 换模型" + echo "7) 卸载" + echo "0) 退出" + echo "---------------------------------------" + printf "请输入选项并回车: " + } + + install_moltbot() { + echo "开始安装 Moltbot……" + curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + echo "安装完成" + pause + } + + init_config() { + echo "开始初始化配置……" + echo "请根据提示完成引导配置" + clawdbot onboard --install-daemon + echo "配置完成" + pause + } + + start_bot() { + echo "启动 Clawdbot..." + clawdbot gateway + pause + } + + stop_bot() { + echo "停止 Clawdbot..." + clawdbot gateway stop + pause + } + + view_logs() { + echo "查看 Clawdbot 日志,Ctrl+C 退出" + # 假设日志在 standard output + clawdbot logs + pause + } + + change_model() { + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " + read model + echo "切换模型为 $model" + clawdbot models set "$model" + echo "完成,请重新启动网关" + pause + } + + uninstall_moltbot() { + echo "卸载 Moltbot..." + # 这里假设 uninstall.sh 存在于安装目录 + curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + echo "卸载完成" + pause + } + + pause() { + printf "按回车继续..." + read dummy + } + + # 主循环 + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) init_config ;; + 3) start_bot ;; + 4) stop_bot ;; + 5) view_logs ;; + 6) change_model ;; + 7) uninstall_moltbot ;; + 0) echo "退出脚本"; exit 0 ;; + *) echo "无效选项,请重新输入"; pause ;; + esac + done + +} + + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -13348,7 +13456,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; 114|Moltbot|ClawdBot|moltbot|clawdbot) - bash <(curl -sSL ${gh_proxy}raw.githubusercontent.com/sky22333/shell/main/moltbot/install.sh) + moltbot_menu ;; From ea2faa9eb3a233ff6237bb4b818f5773ebb404d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:39:01 +0800 Subject: [PATCH 0654/1285] Add Moltbot/Clawdbot installation menu functions --- kejilion.sh | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index f30e96a2c..240933a37 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9582,6 +9582,114 @@ linux_ldnmp() { + + + +moltbot_menu() { + + # Moltbot / Clawdbot 安装部署菜单 + + show_menu() { + clear + echo "=======================================" + echo " Moltbot / Clawdbot 管理菜单" + echo "=======================================" + echo "1) 安装" + echo "2) 初始化配置" + echo "3) 启动" + echo "4) 停止" + echo "5) 日志查看" + echo "6) 换模型" + echo "7) 卸载" + echo "0) 退出" + echo "---------------------------------------" + printf "请输入选项并回车: " + } + + install_moltbot() { + echo "开始安装 Moltbot……" + curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + echo "安装完成" + pause + } + + init_config() { + echo "开始初始化配置……" + echo "请根据提示完成引导配置" + clawdbot onboard --install-daemon + echo "配置完成" + pause + } + + start_bot() { + echo "启动 Clawdbot..." + clawdbot gateway + pause + } + + stop_bot() { + echo "停止 Clawdbot..." + clawdbot gateway stop + pause + } + + view_logs() { + echo "查看 Clawdbot 日志,Ctrl+C 退出" + # 假设日志在 standard output + clawdbot logs + pause + } + + change_model() { + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " + read model + echo "切换模型为 $model" + clawdbot models set "$model" + echo "完成,请重新启动网关" + pause + } + + uninstall_moltbot() { + echo "卸载 Moltbot..." + # 这里假设 uninstall.sh 存在于安装目录 + curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + echo "卸载完成" + pause + } + + pause() { + printf "按回车继续..." + read dummy + } + + # 主循环 + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) init_config ;; + 3) start_bot ;; + 4) stop_bot ;; + 5) view_logs ;; + 6) change_model ;; + 7) uninstall_moltbot ;; + 0) echo "退出脚本"; exit 0 ;; + *) echo "无效选项,请重新输入"; pause ;; + esac + done + +} + + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -13348,7 +13456,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; 114|Moltbot|ClawdBot|moltbot|clawdbot) - bash <(curl -sSL ${gh_proxy}raw.githubusercontent.com/sky22333/shell/main/moltbot/install.sh) + moltbot_menu ;; From 23bc15af89cb269fbfb50f819df0e4a9119bcbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:40:02 +0800 Subject: [PATCH 0655/1285] Update ClawdBot/Moltbot installation note Removed the mention of script support from the ClawdBot/Moltbot installation note. --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4666d0406..3e38e7386 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1427,6 +1427,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 调整正在处理事件时的等待文字的颜色方案,与脚本配色更统一。 优化应用市场更新应用列表时的体验。 优化系统信息查询时的等待体验。 -应用市场增加了最近比较火的ClawdBot/Moltbot机器人项目的安装与使用,感谢爱折腾的sky的脚本支持。 +应用市场增加了最近比较火的ClawdBot/Moltbot机器人项目的安装与使用。 ------------------------ From 074d90b3299c14b9898080a75b9bdfc9a1569ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:17:35 +0800 Subject: [PATCH 0656/1285] Update Moltbot menu and add update option --- cn/kejilion.sh | 95 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 46cad27dd..bb49004bc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9586,58 +9586,91 @@ linux_ldnmp() { moltbot_menu() { + local app_id="114" + + send_stats "clawdbot/moltbot安装" + get_install_status() { + if command -v clawdbot >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "clawdbot gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - # Moltbot / Clawdbot 安装部署菜单 show_menu() { clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) echo "=======================================" - echo " Moltbot / Clawdbot 管理菜单" + echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" echo "=======================================" - echo "1) 安装" - echo "2) 初始化配置" - echo "3) 启动" - echo "4) 停止" - echo "5) 日志查看" - echo "6) 换模型" - echo "7) 卸载" - echo "0) 退出" - echo "---------------------------------------" + echo "1. 安装" + echo "2. 初始化配置" + echo "3. 启动" + echo "4. 停止" + echo "5. 日志查看" + echo "6. 换模型" + echo "--------------------" + echo "7. 更新" + echo "8. 卸载" + echo "--------------------" + echo "0. 返回上一级选单" + echo "--------------------" printf "请输入选项并回车: " } install_moltbot() { echo "开始安装 Moltbot……" + country=$(curl -s ipinfo.io/country) + if [ "$country" = "CN" ]; then + pnpm config set registry https://registry.npmmirror.com + fi + + curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot + clawdbot doctor --fix + add_app_id echo "安装完成" pause + } init_config() { echo "开始初始化配置……" echo "请根据提示完成引导配置" clawdbot onboard --install-daemon - echo "配置完成" - pause + break_end + } + start_bot() { echo "启动 Clawdbot..." clawdbot gateway - pause + break_end } stop_bot() { echo "停止 Clawdbot..." clawdbot gateway stop - pause + break_end } view_logs() { echo "查看 Clawdbot 日志,Ctrl+C 退出" - # 假设日志在 standard output clawdbot logs - pause + break_end } change_model() { @@ -9645,22 +9678,28 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - echo "完成,请重新启动网关" - pause + clawdbot gateway stop + clawdbot gateway + break_end } + update_moltbot() { + echo "更新 Moltbot..." + clawdbot update --restart + add_app_id + echo "卸载完成" + break_end + } + + uninstall_moltbot() { echo "卸载 Moltbot..." - # 这里假设 uninstall.sh 存在于安装目录 curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" - pause + break_end } - pause() { - printf "按回车继续..." - read dummy - } # 主循环 while true; do @@ -9673,7 +9712,8 @@ moltbot_menu() { 4) stop_bot ;; 5) view_logs ;; 6) change_model ;; - 7) uninstall_moltbot ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; 0) echo "退出脚本"; exit 0 ;; *) echo "无效选项,请重新输入"; pause ;; esac @@ -9689,7 +9729,6 @@ moltbot_menu() { - linux_panel() { local sub_choice="$1" @@ -9791,7 +9830,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color110}ClawdBot/Moltbot机器人" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 8cd59cd482482751232dfdb65019afc27674daef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:17:59 +0800 Subject: [PATCH 0657/1285] Refactor moltbot menu and update options --- kejilion.sh | 95 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 240933a37..1278d3841 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9586,58 +9586,91 @@ linux_ldnmp() { moltbot_menu() { + local app_id="114" + + send_stats "clawdbot/moltbot安装" + get_install_status() { + if command -v clawdbot >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "clawdbot gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - # Moltbot / Clawdbot 安装部署菜单 show_menu() { clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) echo "=======================================" - echo " Moltbot / Clawdbot 管理菜单" + echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" echo "=======================================" - echo "1) 安装" - echo "2) 初始化配置" - echo "3) 启动" - echo "4) 停止" - echo "5) 日志查看" - echo "6) 换模型" - echo "7) 卸载" - echo "0) 退出" - echo "---------------------------------------" + echo "1. 安装" + echo "2. 初始化配置" + echo "3. 启动" + echo "4. 停止" + echo "5. 日志查看" + echo "6. 换模型" + echo "--------------------" + echo "7. 更新" + echo "8. 卸载" + echo "--------------------" + echo "0. 返回上一级选单" + echo "--------------------" printf "请输入选项并回车: " } install_moltbot() { echo "开始安装 Moltbot……" + country=$(curl -s ipinfo.io/country) + if [ "$country" = "CN" ]; then + pnpm config set registry https://registry.npmmirror.com + fi + + curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot + clawdbot doctor --fix + add_app_id echo "安装完成" pause + } init_config() { echo "开始初始化配置……" echo "请根据提示完成引导配置" clawdbot onboard --install-daemon - echo "配置完成" - pause + break_end + } + start_bot() { echo "启动 Clawdbot..." clawdbot gateway - pause + break_end } stop_bot() { echo "停止 Clawdbot..." clawdbot gateway stop - pause + break_end } view_logs() { echo "查看 Clawdbot 日志,Ctrl+C 退出" - # 假设日志在 standard output clawdbot logs - pause + break_end } change_model() { @@ -9645,22 +9678,28 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - echo "完成,请重新启动网关" - pause + clawdbot gateway stop + clawdbot gateway + break_end } + update_moltbot() { + echo "更新 Moltbot..." + clawdbot update --restart + add_app_id + echo "卸载完成" + break_end + } + + uninstall_moltbot() { echo "卸载 Moltbot..." - # 这里假设 uninstall.sh 存在于安装目录 curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" - pause + break_end } - pause() { - printf "按回车继续..." - read dummy - } # 主循环 while true; do @@ -9673,7 +9712,8 @@ moltbot_menu() { 4) stop_bot ;; 5) view_logs ;; 6) change_model ;; - 7) uninstall_moltbot ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; 0) echo "退出脚本"; exit 0 ;; *) echo "无效选项,请重新输入"; pause ;; esac @@ -9689,7 +9729,6 @@ moltbot_menu() { - linux_panel() { local sub_choice="$1" @@ -9791,7 +9830,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color110}ClawdBot/Moltbot机器人" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 0231b2a85f8dde21c52572414d81d54c49f62060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:50:00 +0800 Subject: [PATCH 0658/1285] Revise menu options and add TG input code feature --- cn/kejilion.sh | 51 +++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bb49004bc..fd128225c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9615,11 +9615,12 @@ moltbot_menu() { echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" echo "=======================================" echo "1. 安装" - echo "2. 初始化配置" - echo "3. 启动" - echo "4. 停止" - echo "5. 日志查看" - echo "6. 换模型" + echo "2. 启动" + echo "3. 停止" + echo "--------------------" + echo "4. 日志查看" + echo "5. 换模型" + echo "6. TG输入连接码" echo "--------------------" echo "7. 更新" echo "8. 卸载" @@ -9635,29 +9636,21 @@ moltbot_menu() { if [ "$country" = "CN" ]; then pnpm config set registry https://registry.npmmirror.com fi - - curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot clawdbot doctor --fix + clawdbot onboard --install-daemon add_app_id echo "安装完成" pause } - init_config() { - echo "开始初始化配置……" - echo "请根据提示完成引导配置" - clawdbot onboard --install-daemon - break_end - - } - - start_bot() { echo "启动 Clawdbot..." - clawdbot gateway + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + sleep 3 break_end } @@ -9679,7 +9672,19 @@ moltbot_menu() { echo "切换模型为 $model" clawdbot models set "$model" clawdbot gateway stop - clawdbot gateway + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + break_end + } + + + change_tg_bot_code() { + printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " + read code + clawdbot pairing approve telegram $code + clawdbot gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" break_end } @@ -9707,11 +9712,11 @@ moltbot_menu() { read choice case $choice in 1) install_moltbot ;; - 2) init_config ;; - 3) start_bot ;; - 4) stop_bot ;; - 5) view_logs ;; - 6) change_model ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; 0) echo "退出脚本"; exit 0 ;; From 951cf29a8ff9572eeb98f7057233b346dfb9955a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:50:36 +0800 Subject: [PATCH 0659/1285] Revise management menu and add TG code change option --- kejilion.sh | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1278d3841..e098ca751 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9615,11 +9615,12 @@ moltbot_menu() { echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" echo "=======================================" echo "1. 安装" - echo "2. 初始化配置" - echo "3. 启动" - echo "4. 停止" - echo "5. 日志查看" - echo "6. 换模型" + echo "2. 启动" + echo "3. 停止" + echo "--------------------" + echo "4. 日志查看" + echo "5. 换模型" + echo "6. TG输入连接码" echo "--------------------" echo "7. 更新" echo "8. 卸载" @@ -9635,29 +9636,21 @@ moltbot_menu() { if [ "$country" = "CN" ]; then pnpm config set registry https://registry.npmmirror.com fi - - curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot clawdbot doctor --fix + clawdbot onboard --install-daemon add_app_id echo "安装完成" pause } - init_config() { - echo "开始初始化配置……" - echo "请根据提示完成引导配置" - clawdbot onboard --install-daemon - break_end - - } - - start_bot() { echo "启动 Clawdbot..." - clawdbot gateway + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + sleep 3 break_end } @@ -9679,7 +9672,19 @@ moltbot_menu() { echo "切换模型为 $model" clawdbot models set "$model" clawdbot gateway stop - clawdbot gateway + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + break_end + } + + + change_tg_bot_code() { + printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " + read code + clawdbot pairing approve telegram $code + clawdbot gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" break_end } @@ -9707,11 +9712,11 @@ moltbot_menu() { read choice case $choice in 1) install_moltbot ;; - 2) init_config ;; - 3) start_bot ;; - 4) stop_bot ;; - 5) view_logs ;; - 6) change_model ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; 0) echo "退出脚本"; exit 0 ;; From 7c1eba080b12568f8683337bcf7780f241988876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:52:40 +0800 Subject: [PATCH 0660/1285] Add tmux installation in start_bot function --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index e098ca751..2a9ca13f1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9648,6 +9648,7 @@ moltbot_menu() { start_bot() { echo "启动 Clawdbot..." + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" sleep 3 @@ -9672,6 +9673,7 @@ moltbot_menu() { echo "切换模型为 $model" clawdbot models set "$model" clawdbot gateway stop + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" break_end @@ -9683,6 +9685,7 @@ moltbot_menu() { read code clawdbot pairing approve telegram $code clawdbot gateway stop + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" break_end From eedb5ae30e485c9eac8a775680af90d4de0502f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:53:18 +0800 Subject: [PATCH 0661/1285] Add tmux installation before starting gateway --- cn/kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fd128225c..f2a0f2bf6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9648,6 +9648,7 @@ moltbot_menu() { start_bot() { echo "启动 Clawdbot..." + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" sleep 3 @@ -9672,6 +9673,7 @@ moltbot_menu() { echo "切换模型为 $model" clawdbot models set "$model" clawdbot gateway stop + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" break_end @@ -9683,6 +9685,7 @@ moltbot_menu() { read code clawdbot pairing approve telegram $code clawdbot gateway stop + install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" break_end From f1aeb288c865ff5c33238705c8bbcf2a6e44f480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:01:08 +0800 Subject: [PATCH 0662/1285] Refactor bot start and stop functions Refactor bot control functions to use start_tmux for session management. --- cn/kejilion.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f2a0f2bf6..4bf87d4d8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9646,18 +9646,25 @@ moltbot_menu() { } - start_bot() { - echo "启动 Clawdbot..." + start_tmux() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" sleep 3 + } + + + start_bot() { + echo "启动 Clawdbot..." + start_tmux break_end } stop_bot() { echo "停止 Clawdbot..." - clawdbot gateway stop + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + sleep 3 break_end } @@ -9672,10 +9679,7 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - clawdbot gateway stop - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + start_tmux break_end } @@ -9684,10 +9688,7 @@ moltbot_menu() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code clawdbot pairing approve telegram $code - clawdbot gateway stop - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + start_tmux break_end } @@ -9722,7 +9723,7 @@ moltbot_menu() { 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; - 0) echo "退出脚本"; exit 0 ;; + 0) break ;; *) echo "无效选项,请重新输入"; pause ;; esac done From 45ca52868dbf076ddb778437b8795a4e98c97663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:01:33 +0800 Subject: [PATCH 0663/1285] Refactor bot start and stop functions Refactor bot management functions to use start_tmux for session handling. --- kejilion.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2a9ca13f1..8de88d04c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9646,18 +9646,25 @@ moltbot_menu() { } - start_bot() { - echo "启动 Clawdbot..." + start_tmux() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "clawdbot gateway" sleep 3 + } + + + start_bot() { + echo "启动 Clawdbot..." + start_tmux break_end } stop_bot() { echo "停止 Clawdbot..." - clawdbot gateway stop + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + sleep 3 break_end } @@ -9672,10 +9679,7 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - clawdbot gateway stop - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + start_tmux break_end } @@ -9684,10 +9688,7 @@ moltbot_menu() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code clawdbot pairing approve telegram $code - clawdbot gateway stop - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + start_tmux break_end } @@ -9722,7 +9723,7 @@ moltbot_menu() { 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; - 0) echo "退出脚本"; exit 0 ;; + 0) break ;; *) echo "无效选项,请重新输入"; pause ;; esac done From 92050abc941d0242f2ce29ba70f573099dfc1c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:05:38 +0800 Subject: [PATCH 0664/1285] Update country check for Moltbot installation --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 8de88d04c..8b72059c5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9633,7 +9633,7 @@ moltbot_menu() { install_moltbot() { echo "开始安装 Moltbot……" country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then + if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git From 9925275b58bf17975726651d3fc175197799164d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:06:10 +0800 Subject: [PATCH 0665/1285] Update country check for Moltbot installation --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4bf87d4d8..62d039511 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9633,7 +9633,7 @@ moltbot_menu() { install_moltbot() { echo "开始安装 Moltbot……" country=$(curl -s ipinfo.io/country) - if [ "$country" = "CN" ]; then + if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git From f7423441e7c3ffa286777bcc0bcb3dd431593b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:17:23 +0800 Subject: [PATCH 0666/1285] Refactor bot start/stop to use clawdbot commands Removed start_tmux function calls and replaced with clawdbot commands. --- cn/kejilion.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 62d039511..1102fde78 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9646,25 +9646,17 @@ moltbot_menu() { } - start_tmux() { - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" - sleep 3 - } - start_bot() { echo "启动 Clawdbot..." - start_tmux + clawdbot gateway start break_end } stop_bot() { echo "停止 Clawdbot..." install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - sleep 3 + clawdbot gateway stop break_end } @@ -9679,7 +9671,6 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - start_tmux break_end } @@ -9688,7 +9679,6 @@ moltbot_menu() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code clawdbot pairing approve telegram $code - start_tmux break_end } From 7ebf097a4a07173b231d1d2cf9369d9b0a5f926d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:18:02 +0800 Subject: [PATCH 0667/1285] Refactor bot control functions to remove tmux usage Removed tmux session management from start_bot, stop_bot, view_logs, and change_tg_bot_code functions. --- kejilion.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8b72059c5..75d0bdb9a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9646,25 +9646,17 @@ moltbot_menu() { } - start_tmux() { - install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" - sleep 3 - } - start_bot() { echo "启动 Clawdbot..." - start_tmux + clawdbot gateway start break_end } stop_bot() { echo "停止 Clawdbot..." install tmux - tmux kill-session -t gateway > /dev/null 2>&1 - sleep 3 + clawdbot gateway stop break_end } @@ -9679,7 +9671,6 @@ moltbot_menu() { read model echo "切换模型为 $model" clawdbot models set "$model" - start_tmux break_end } @@ -9688,7 +9679,6 @@ moltbot_menu() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code clawdbot pairing approve telegram $code - start_tmux break_end } From 9ea404acd12a5dd22ef65a2ddc09ac73e70107f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:23:25 +0800 Subject: [PATCH 0668/1285] Remove installation completion messages --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1102fde78..e4af68a0f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9641,8 +9641,7 @@ moltbot_menu() { clawdbot doctor --fix clawdbot onboard --install-daemon add_app_id - echo "安装完成" - pause + break_end } From 237d55af6f70017eab37b6ba9edc86e8f155bd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:23:56 +0800 Subject: [PATCH 0669/1285] Remove installation completion messages and pause --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 75d0bdb9a..6ca04fced 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9641,8 +9641,7 @@ moltbot_menu() { clawdbot doctor --fix clawdbot onboard --install-daemon add_app_id - echo "安装完成" - pause + break_end } From 8e3fced8b2b11c27829a7f37da8dc39269a2106a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 09:39:29 +0800 Subject: [PATCH 0670/1285] Refactor show_menu function for better formatting --- cn/kejilion.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e4af68a0f..85830dd3c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9608,7 +9608,7 @@ moltbot_menu() { show_menu() { clear - + local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" @@ -9617,14 +9617,14 @@ moltbot_menu() { echo "1. 安装" echo "2. 启动" echo "3. 停止" - echo "--------------------" + echo "--------------------" echo "4. 日志查看" echo "5. 换模型" - echo "6. TG输入连接码" - echo "--------------------" + echo "6. TG输入连接码" + echo "--------------------" echo "7. 更新" echo "8. 卸载" - echo "--------------------" + echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" printf "请输入选项并回车: " @@ -9637,12 +9637,14 @@ moltbot_menu() { pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + source ~/.bashrc + source ~/.profile ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot clawdbot doctor --fix clawdbot onboard --install-daemon add_app_id break_end - + } From 1c04e8c292e0e24ea96349d391dd120a873280ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 09:40:47 +0800 Subject: [PATCH 0671/1285] Refactor show_menu and update installation process --- kejilion.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6ca04fced..a1d88e652 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9608,7 +9608,7 @@ moltbot_menu() { show_menu() { clear - + local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" @@ -9617,14 +9617,14 @@ moltbot_menu() { echo "1. 安装" echo "2. 启动" echo "3. 停止" - echo "--------------------" + echo "--------------------" echo "4. 日志查看" echo "5. 换模型" - echo "6. TG输入连接码" - echo "--------------------" + echo "6. TG输入连接码" + echo "--------------------" echo "7. 更新" echo "8. 卸载" - echo "--------------------" + echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" printf "请输入选项并回车: " @@ -9637,12 +9637,14 @@ moltbot_menu() { pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + source ~/.bashrc + source ~/.profile ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot clawdbot doctor --fix clawdbot onboard --install-daemon add_app_id break_end - + } From 21474a274b994807d603de26a508b039088ba9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:34:24 +0800 Subject: [PATCH 0672/1285] Update version to 4.3.7 and enhance env menu --- cn/kejilion.sh | 135 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 85830dd3c..1437a77b8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.6" +sh_v="4.3.7" gl_hui='\e[37m' @@ -14071,7 +14071,132 @@ log_menu() { +env_menu() { + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "系统变量管理工具" + + show_env_vars() { + clear + send_stats "当前已生效环境变量" + echo "========== 当前已生效环境变量(节选) ==========" + printf "%-20s %s\n" "变量名" "值" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== 配置文件中定义的变量(解析) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> 来源文件:$file" + echo "-----------------------------------------------" + + # 提取 export VAR=xxx 或 VAR=xxx + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "按回车继续..." + } + + + view_file() { + local file="$1" + send_stats "查看变量文件 $file" + clear + if [ -f "$file" ]; then + echo "========== 查看文件:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "文件不存在:$file" + fi + read -rp "按回车继续..." + } + + edit_file() { + local file="$1" + send_stats "编辑变量文件 $file" + install nano + nano "$file" + } + + source_files() { + echo "正在重新加载环境变量..." + send_stats "正在重新加载环境变量" + source "$BASHRC" + source "$PROFILE" + echo "✔ 环境变量已重新加载" + read -rp "按回车继续..." + } + + while true; do + clear + echo "=========== 系统环境变量管理 ==========" + echo "当前用户:$USER" + echo "--------------------------------------" + echo "1. 查看当前常用环境变量" + echo "2. 查看 ~/.bashrc" + echo "3. 查看 ~/.profile" + echo "4. 编辑 ~/.bashrc" + echo "5. 编辑 ~/.profile" + echo "6. 重新加载环境变量(source)" + echo "--------------------------------------" + echo "0. 返回上一级选单" + echo "--------------------------------------" + read -rp "请选择操作: " choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} create_user_with_sshkey() { @@ -14174,7 +14299,7 @@ linux_Settings() { echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系统变量管理工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" @@ -15090,6 +15215,12 @@ EOF log_menu ;; + 42) + clear + env_menu + ;; + + 61) clear send_stats "留言板" From 91b5554dd6aa510322359a3c91ecb1d2bd9d0698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:35:18 +0800 Subject: [PATCH 0673/1285] Update version and add environment variable management --- kejilion.sh | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a1d88e652..fd372ddfd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.6" +sh_v="4.3.7" gl_hui='\e[37m' @@ -14071,7 +14071,132 @@ log_menu() { +env_menu() { + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "系统变量管理工具" + + show_env_vars() { + clear + send_stats "当前已生效环境变量" + echo "========== 当前已生效环境变量(节选) ==========" + printf "%-20s %s\n" "变量名" "值" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== 配置文件中定义的变量(解析) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> 来源文件:$file" + echo "-----------------------------------------------" + + # 提取 export VAR=xxx 或 VAR=xxx + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "按回车继续..." + } + + + view_file() { + local file="$1" + send_stats "查看变量文件 $file" + clear + if [ -f "$file" ]; then + echo "========== 查看文件:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "文件不存在:$file" + fi + read -rp "按回车继续..." + } + + edit_file() { + local file="$1" + send_stats "编辑变量文件 $file" + install nano + nano "$file" + } + + source_files() { + echo "正在重新加载环境变量..." + send_stats "正在重新加载环境变量" + source "$BASHRC" + source "$PROFILE" + echo "✔ 环境变量已重新加载" + read -rp "按回车继续..." + } + + while true; do + clear + echo "=========== 系统环境变量管理 ==========" + echo "当前用户:$USER" + echo "--------------------------------------" + echo "1. 查看当前常用环境变量" + echo "2. 查看 ~/.bashrc" + echo "3. 查看 ~/.profile" + echo "4. 编辑 ~/.bashrc" + echo "5. 编辑 ~/.profile" + echo "6. 重新加载环境变量(source)" + echo "--------------------------------------" + echo "0. 返回上一级选单" + echo "--------------------------------------" + read -rp "请选择操作: " choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done +} create_user_with_sshkey() { @@ -14174,7 +14299,7 @@ linux_Settings() { echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系统变量管理工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" @@ -15090,6 +15215,12 @@ EOF log_menu ;; + 42) + clear + env_menu + ;; + + 61) clear send_stats "留言板" From 734c469e6750ccd1e483606c873d946271e1e9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:37:52 +0800 Subject: [PATCH 0674/1285] Update kejilion_sh_log with new features and optimizations Added new features and optimizations for system tools and application market. --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 3e38e7386..5ab3e0927 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1429,4 +1429,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 优化系统信息查询时的等待体验。 应用市场增加了最近比较火的ClawdBot/Moltbot机器人项目的安装与使用。 ------------------------ +2026-01-30 v4.3.7 +系统工具中新增系统变量管理工具,快速查看,编辑,刷新变量等操作, +应用市场对ClawdBot/Moltbot机器人项目的安装环境进行优化,提高安装成功率。 +------------------------ From 84efd9852fffaedfa97e571e8e0361a76bc3b567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:41:06 +0800 Subject: [PATCH 0675/1285] Add tmux session management for Clawdbot --- cn/kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1437a77b8..cf2708d1d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9630,6 +9630,15 @@ moltbot_menu() { printf "请输入选项并回车: " } + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + sleep 3 + } + + install_moltbot() { echo "开始安装 Moltbot……" country=$(curl -s ipinfo.io/country) @@ -9650,7 +9659,7 @@ moltbot_menu() { start_bot() { echo "启动 Clawdbot..." - clawdbot gateway start + start_tmux break_end } From 10cc371bd8f99646d490c791eee0ad4629abbf9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:41:44 +0800 Subject: [PATCH 0676/1285] Add tmux session management for Clawdbot --- kejilion.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index fd372ddfd..e81aea150 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9630,6 +9630,15 @@ moltbot_menu() { printf "请输入选项并回车: " } + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "clawdbot gateway" + sleep 3 + } + + install_moltbot() { echo "开始安装 Moltbot……" country=$(curl -s ipinfo.io/country) @@ -9650,7 +9659,7 @@ moltbot_menu() { start_bot() { echo "启动 Clawdbot..." - clawdbot gateway start + start_tmux break_end } From 438d3195e4898b43f2c69d5c04219835d67f20e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:32:52 +0800 Subject: [PATCH 0677/1285] Replace Clawdbot references with OpenClaw --- cn/kejilion.sh | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index cf2708d1d..40b940908 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9590,7 +9590,7 @@ moltbot_menu() { send_stats "clawdbot/moltbot安装" get_install_status() { - if command -v clawdbot >/dev/null 2>&1; then + if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}已安装${gl_bai}" else echo "${gl_hui}未安装${gl_bai}" @@ -9598,7 +9598,7 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "clawdbot gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" else echo "${gl_hui}未运行${gl_bai}" @@ -9612,7 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" + echo -e " Moltbot/Clawdbot/OpenClaw 管理菜单" + echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" @@ -9634,23 +9635,23 @@ moltbot_menu() { start_tmux() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + tmux new -d -s gateway "openclaw gateway" sleep 3 } install_moltbot() { - echo "开始安装 Moltbot……" + echo "开始安装 OpenClaw..." country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git source ~/.bashrc source ~/.profile - ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot - clawdbot doctor --fix - clawdbot onboard --install-daemon + openclaw doctor --fix + openclaw onboard --install-daemon add_app_id break_end @@ -9658,21 +9659,21 @@ moltbot_menu() { start_bot() { - echo "启动 Clawdbot..." + echo "启动 OpenClaw..." start_tmux break_end } stop_bot() { - echo "停止 Clawdbot..." + echo "停止 OpenClaw..." install tmux - clawdbot gateway stop + openclaw gateway stop break_end } view_logs() { - echo "查看 Clawdbot 日志,Ctrl+C 退出" - clawdbot logs + echo "查看 OpenClaw 日志,Ctrl+C 退出" + openclaw logs break_end } @@ -9680,7 +9681,7 @@ moltbot_menu() { printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" - clawdbot models set "$model" + openclaw models set "$model" break_end } @@ -9688,13 +9689,13 @@ moltbot_menu() { change_tg_bot_code() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code - clawdbot pairing approve telegram $code + openclaw pairing approve telegram $code break_end } update_moltbot() { - echo "更新 Moltbot..." - clawdbot update --restart + echo "更新 OpenClaw..." + openclaw update --restart add_app_id echo "卸载完成" break_end @@ -9702,8 +9703,8 @@ moltbot_menu() { uninstall_moltbot() { - echo "卸载 Moltbot..." - curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + echo "卸载 OpenClaw..." + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end @@ -9723,8 +9724,7 @@ moltbot_menu() { 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; - 0) break ;; - *) echo "无效选项,请重新输入"; pause ;; + *) break ;; esac done From 56ef3ecf9fc47f2f3c498daf7ef22aa8e540d822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:33:38 +0800 Subject: [PATCH 0678/1285] Replace Clawdbot references with OpenClaw --- kejilion.sh | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e81aea150..1b33ba214 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9590,7 +9590,7 @@ moltbot_menu() { send_stats "clawdbot/moltbot安装" get_install_status() { - if command -v clawdbot >/dev/null 2>&1; then + if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}已安装${gl_bai}" else echo "${gl_hui}未安装${gl_bai}" @@ -9598,7 +9598,7 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "clawdbot gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" else echo "${gl_hui}未运行${gl_bai}" @@ -9612,7 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " Moltbot / Clawdbot 管理菜单 $install_status $running_status" + echo -e " Moltbot/Clawdbot/OpenClaw 管理菜单" + echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" @@ -9634,23 +9635,23 @@ moltbot_menu() { start_tmux() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "clawdbot gateway" + tmux new -d -s gateway "openclaw gateway" sleep 3 } install_moltbot() { - echo "开始安装 Moltbot……" + echo "开始安装 OpenClaw..." country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git source ~/.bashrc source ~/.profile - ln -s /root/.local/bin/clawdbot /usr/local/bin/clawdbot - clawdbot doctor --fix - clawdbot onboard --install-daemon + openclaw doctor --fix + openclaw onboard --install-daemon add_app_id break_end @@ -9658,21 +9659,21 @@ moltbot_menu() { start_bot() { - echo "启动 Clawdbot..." + echo "启动 OpenClaw..." start_tmux break_end } stop_bot() { - echo "停止 Clawdbot..." + echo "停止 OpenClaw..." install tmux - clawdbot gateway stop + openclaw gateway stop break_end } view_logs() { - echo "查看 Clawdbot 日志,Ctrl+C 退出" - clawdbot logs + echo "查看 OpenClaw 日志,Ctrl+C 退出" + openclaw logs break_end } @@ -9680,7 +9681,7 @@ moltbot_menu() { printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" - clawdbot models set "$model" + openclaw models set "$model" break_end } @@ -9688,13 +9689,13 @@ moltbot_menu() { change_tg_bot_code() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code - clawdbot pairing approve telegram $code + openclaw pairing approve telegram $code break_end } update_moltbot() { - echo "更新 Moltbot..." - clawdbot update --restart + echo "更新 OpenClaw..." + openclaw update --restart add_app_id echo "卸载完成" break_end @@ -9702,8 +9703,8 @@ moltbot_menu() { uninstall_moltbot() { - echo "卸载 Moltbot..." - curl -fsSL https://molt.bot/install.sh | bash -s -- --uninstall + echo "卸载 OpenClaw..." + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end @@ -9723,8 +9724,7 @@ moltbot_menu() { 6) change_tg_bot_code ;; 7) update_moltbot ;; 8) uninstall_moltbot ;; - 0) break ;; - *) echo "无效选项,请重新输入"; pause ;; + *) break ;; esac done From b54775994e8586f135d23420f978bd595f50f479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:43:02 +0800 Subject: [PATCH 0679/1285] Update installation script for openclaw Replace molt.bot installation with openclaw symlink and ensure proper installation. --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 40b940908..6d50b3626 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9646,8 +9646,8 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi - curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw source ~/.bashrc source ~/.profile openclaw doctor --fix From 23cb3f1a48702e4f9d9e9bf480812d8a8476be5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:43:53 +0800 Subject: [PATCH 0680/1285] Update installation method for openclaw Replace molt.bot installation with openclaw symlink. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1b33ba214..2ff811023 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9646,8 +9646,8 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com fi - curl -fsSL https://molt.bot/install.sh | bash -s -- --install-method git curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw source ~/.bashrc source ~/.profile openclaw doctor --fix From 80487305c7c2c6d540abac2faafe3b96f08d377b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 15:21:00 +0800 Subject: [PATCH 0681/1285] Add Gateway Watchdog cron job to kejilion.sh --- cn/kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6d50b3626..1b6f3655e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9652,6 +9652,10 @@ moltbot_menu() { source ~/.profile openclaw doctor --fix openclaw onboard --install-daemon + openclaw cron add \ + --name "Gateway Watchdog" \ + --every 2m \ + --system-event "Check if 'gateway' tmux session exists. If not, run: tmux new -d -s gateway \"openclaw gateway\" and notify user." add_app_id break_end From 3bd194fcc061481a9608910c1bce891a53094f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 15:21:43 +0800 Subject: [PATCH 0682/1285] Add cron job for Gateway Watchdog in kejilion.sh --- kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 2ff811023..3ac8ac253 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9652,6 +9652,10 @@ moltbot_menu() { source ~/.profile openclaw doctor --fix openclaw onboard --install-daemon + openclaw cron add \ + --name "Gateway Watchdog" \ + --every 2m \ + --system-event "Check if 'gateway' tmux session exists. If not, run: tmux new -d -s gateway \"openclaw gateway\" and notify user." add_app_id break_end From 8ec263e6b9f6fb220aafd2de2dad2c067b7f31c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:00:40 +0800 Subject: [PATCH 0683/1285] Update menu titles for ClawdBot and MoltBot --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1b6f3655e..4f69cfb00 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9612,7 +9612,7 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " Moltbot/Clawdbot/OpenClaw 管理菜单" + echo -e " ClawdBot -> MoltBot -> OpenClaw 管理菜单" echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" @@ -9843,7 +9843,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot/OpenClaw机器人 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 5b30e23a45e8d8a3a07c30c099fa73a51b8d8c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:01:59 +0800 Subject: [PATCH 0684/1285] Update management menu and bot references in script --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3ac8ac253..d5a3831a2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9612,7 +9612,7 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " Moltbot/Clawdbot/OpenClaw 管理菜单" + echo -e " ClawdBot -> MoltBot -> OpenClaw 管理菜单" echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" @@ -9843,7 +9843,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot/OpenClaw机器人 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 62604867925a790256c48a22c4cc9cdefac5e5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:08:19 +0800 Subject: [PATCH 0685/1285] Fix stop_bot function and update bot menu options --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4f69cfb00..72a4d610b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9672,6 +9672,7 @@ moltbot_menu() { echo "停止 OpenClaw..." install tmux openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 break_end } @@ -13507,7 +13508,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 114|Moltbot|ClawdBot|moltbot|clawdbot) + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) moltbot_menu ;; From bd52d46893fe81e3705f49f6d8b9de6e1c8a44a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:09:14 +0800 Subject: [PATCH 0686/1285] Fix stop_bot function and update case statement --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d5a3831a2..b11e710e1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9672,6 +9672,7 @@ moltbot_menu() { echo "停止 OpenClaw..." install tmux openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 break_end } @@ -13507,7 +13508,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; - 114|Moltbot|ClawdBot|moltbot|clawdbot) + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) moltbot_menu ;; From 99ef2eef2ef95828cba81c8ffbfae8d1839aeb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:18:15 +0800 Subject: [PATCH 0687/1285] Fix formatting in management menu and application list --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 72a4d610b..bc1f3705b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9612,8 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " ClawdBot -> MoltBot -> OpenClaw 管理菜单" - echo -e " $install_status $running_status" + echo -e " ClawdBot > MoltBot > OpenClaw 管理菜单" + echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" @@ -9844,7 +9844,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot/OpenClaw机器人 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 05070275d6c4cdeb0b51dc29e9dc531e6c29e110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:18:53 +0800 Subject: [PATCH 0688/1285] Fix formatting in kejilion.sh output messages --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index b11e710e1..7f4817dc6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9612,8 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " ClawdBot -> MoltBot -> OpenClaw 管理菜单" - echo -e " $install_status $running_status" + echo -e " ClawdBot > MoltBot > OpenClaw 管理菜单" + echo -e " $install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" @@ -9844,7 +9844,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot/OpenClaw机器人 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From c779fb9eaa26cb83999e645712efb5a84577a86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:32:03 +0800 Subject: [PATCH 0689/1285] Fix formatting of management menu output --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7f4817dc6..97339d36a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9612,8 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " ClawdBot > MoltBot > OpenClaw 管理菜单" - echo -e " $install_status $running_status" + echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "$install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" From e0f0eabc163cb4950007db62476eb539fdc75ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:32:43 +0800 Subject: [PATCH 0690/1285] Refactor menu display in kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bc1f3705b..66dcef701 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9612,8 +9612,8 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) echo "=======================================" - echo -e " ClawdBot > MoltBot > OpenClaw 管理菜单" - echo -e " $install_status $running_status" + echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "$install_status $running_status" echo "=======================================" echo "1. 安装" echo "2. 启动" From 464b8b75decc49880d73696be8325f18a03ca5be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:29:33 +0800 Subject: [PATCH 0691/1285] Replace curl uninstall command with openclaw command --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 66dcef701..d487ca3f0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9709,7 +9709,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --uninstall + openclaw uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From b41d02a8823d829c37219113a64865691b6252f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:30:05 +0800 Subject: [PATCH 0692/1285] Replace curl command with openclaw uninstall --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 97339d36a..33121f659 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9709,7 +9709,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --uninstall + openclaw uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 89fda169b5bf682a483c1540adba5de5d16e60e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:35:20 +0800 Subject: [PATCH 0693/1285] Add npm uninstall command for OpenClaw --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 33121f659..8039d2364 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9710,6 +9710,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." openclaw uninstall + npm uninstall -g openclaw sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 063f07bad47719f1d6c908f963bb2f0b6d8e2855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:36:05 +0800 Subject: [PATCH 0694/1285] Add npm uninstall command for OpenClaw --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d487ca3f0..1e07af5f4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9710,6 +9710,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." openclaw uninstall + npm uninstall -g openclaw sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From e911ac47e775fa847e42c7553dacc3e98fa3e45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:28:25 +0800 Subject: [PATCH 0695/1285] Refactor gateway management in kejilion.sh --- cn/kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1e07af5f4..522ddffe4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9652,10 +9652,10 @@ moltbot_menu() { source ~/.profile openclaw doctor --fix openclaw onboard --install-daemon - openclaw cron add \ - --name "Gateway Watchdog" \ - --every 2m \ - --system-event "Check if 'gateway' tmux session exists. If not, run: tmux new -d -s gateway \"openclaw gateway\" and notify user." + openclaw gateway stop + start_tmux + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - add_app_id break_end From fdd2da0e0293a7577569e495b243f038af28211b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:28:53 +0800 Subject: [PATCH 0696/1285] Replace Gateway Watchdog cron job with tmux session check --- kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8039d2364..04995fb6c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9652,10 +9652,10 @@ moltbot_menu() { source ~/.profile openclaw doctor --fix openclaw onboard --install-daemon - openclaw cron add \ - --name "Gateway Watchdog" \ - --every 2m \ - --system-event "Check if 'gateway' tmux session exists. If not, run: tmux new -d -s gateway \"openclaw gateway\" and notify user." + openclaw gateway stop + start_tmux + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - add_app_id break_end From 1d7f6dd3588cee125ebe005155d94370a8f4e55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:30:42 +0800 Subject: [PATCH 0697/1285] Enhance ClawdBot/Moltbot process health monitoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化ClawdBot/Moltbot机器人项目保活功能,增加每分钟检测进程健康状态并自动重载的机制。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5ab3e0927..8dbea197a 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1432,5 +1432,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-01-30 v4.3.7 系统工具中新增系统变量管理工具,快速查看,编辑,刷新变量等操作, 应用市场对ClawdBot/Moltbot机器人项目的安装环境进行优化,提高安装成功率。 +应用市场对ClawdBot/Moltbot机器人项目保活进行优化每分钟检测进程健康状态,如果异常自动重载。 ------------------------ From 6d9d1b28492b8edc6c55ce6822508c08d6705baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:35:05 +0800 Subject: [PATCH 0698/1285] Change uninstall message to update completion message --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 522ddffe4..f4ed1399b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9702,7 +9702,7 @@ moltbot_menu() { echo "更新 OpenClaw..." openclaw update --restart add_app_id - echo "卸载完成" + echo "更新完成" break_end } From 4eb327131c73e96ebf9d5d21eb0d4387e790f73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:35:31 +0800 Subject: [PATCH 0699/1285] Change uninstall message to update completion message --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 04995fb6c..01aa47ed0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9702,7 +9702,7 @@ moltbot_menu() { echo "更新 OpenClaw..." openclaw update --restart add_app_id - echo "卸载完成" + echo "更新完成" break_end } From 87ddf688723b2a0b89b3c5b3643409f1e8c267e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:38:52 +0800 Subject: [PATCH 0700/1285] Refactor crontab check into start_tmux function Moved crontab check to start_tmux function for better organization. --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 01aa47ed0..ddba48a12 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9636,6 +9636,8 @@ moltbot_menu() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - sleep 3 } @@ -9654,8 +9656,6 @@ moltbot_menu() { openclaw onboard --install-daemon openclaw gateway stop start_tmux - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - add_app_id break_end From 76f85f417b752066599a97b677e5b375c1b279cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:39:27 +0800 Subject: [PATCH 0701/1285] Add crontab check to start_tmux function --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f4ed1399b..133c909a0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9636,6 +9636,8 @@ moltbot_menu() { install tmux tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - sleep 3 } @@ -9654,8 +9656,6 @@ moltbot_menu() { openclaw onboard --install-daemon openclaw gateway stop start_tmux - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - add_app_id break_end From b76173ae08254393e04379c1287e77a5fdfbc353 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 1 Feb 2026 04:59:06 +0000 Subject: [PATCH 0702/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-01=2004:59:06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 1308 +++++++++++++++++++++++++++++++++------------ jp/kejilion.sh | 1350 +++++++++++++++++++++++++++++++++++------------ kr/kejilion.sh | 1368 +++++++++++++++++++++++++++++++++++------------- tw/kejilion.sh | 1272 +++++++++++++++++++++++++++++++++----------- 4 files changed, 3953 insertions(+), 1345 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index d54518a05..183b4c992 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.7" gl_hui='\e[37m' @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -102,6 +104,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -176,7 +179,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}Installing$package...${gl_bai}" + echo -e "${gl_kjlan}Installing$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -251,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}Uninstalling$package...${gl_bai}" + echo -e "${gl_kjlan}Uninstalling$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -448,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Installing docker environment...${gl_bai}" + echo -e "${gl_kjlan}Installing docker environment...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -627,7 +630,7 @@ while true; do send_stats "Pull image" read -e -p "Please enter the image name (please separate multiple image names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}Obtaining image:$name${gl_bai}" + echo -e "${gl_kjlan}Obtaining image:$name${gl_bai}" docker pull $name done ;; @@ -635,7 +638,7 @@ while true; do send_stats "Update image" read -e -p "Please enter the image name (please separate multiple image names with spaces):" imagenames for name in $imagenames; do - echo -e "${gl_huang}Updating image:$name${gl_bai}" + echo -e "${gl_kjlan}Updating image:$name${gl_bai}" docker pull $name done ;; @@ -881,7 +884,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1442,10 +1445,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1543,7 +1542,7 @@ certs_status() { echo -e "5. The number of applications exceeds the limit ➠ Let's Encrypt has a weekly limit (5 times/domain name/week)" echo -e "6. Domestic registration restrictions ➠ For mainland China environment, please confirm whether the domain name is registered" echo "------------------------" - echo "1. Apply again 2. Import the existing certificate 3. Use HTTP access without certificate 0. Exit" + echo "1. Reapply 2. Import existing certificate 0. Exit" echo "------------------------" read -e -p "Please enter your choice:" sub_choice case $sub_choice in @@ -1600,18 +1599,9 @@ certs_status() { echo "Error: Invalid certificate or private key format!" certs_status fi - - ;; - 3) - send_stats "Switch to HTTP access without a certificate" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - send_stats "Withdraw application" - rm -f /home/web/conf.d/${yuming}.conf - exit + exit ;; esac fi @@ -2146,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -2328,7 +2318,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2677,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2696,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3391,14 +3381,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3447,6 +3439,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3465,9 +3461,6 @@ ldnmp_Proxy() { sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3495,6 +3488,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3511,8 +3507,6 @@ ldnmp_Proxy_backend() { sed -i "s/# dynamically add/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -3529,7 +3523,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4274,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP server$check_frp $update_status" echo "Build an FRP intranet penetration service environment and expose devices without public IP to the Internet" - echo "Official website introduction: https://github.com/fatedier/frp/" + echo "Official website introduction:${gh_https_url}github.com/fatedier/frp/" echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4372,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP client$check_frp $update_status" echo "Connect with the server. After the connection, you can create an intranet penetration service to access the Internet." - echo "Official website introduction: https://github.com/fatedier/frp/" + echo "Official website introduction:${gh_https_url}github.com/fatedier/frp/" echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4465,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp download tool" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp is a powerful video download tool that supports thousands of sites such as YouTube, Bilibili, Twitter, etc." - echo -e "Official website address: https://github.com/yt-dlp/yt-dlp" + echo -e "Official website address:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "Downloaded video list:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(None yet)" @@ -4484,7 +4478,7 @@ yt_menu_pro() { send_stats "Installing yt-dlp..." echo "Installing yt-dlp..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -4600,7 +4594,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}System update in progress...${gl_bai}" + echo -e "${gl_kjlan}System update in progress...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4627,7 +4621,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}System cleaning in progress...${gl_bai}" + echo -e "${gl_kjlan}System cleaning in progress...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4807,39 +4801,30 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # If found PasswordAuthentication is set to yes - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # If found PubkeyAuthentication is set to yes - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # Sets default value if neither PasswordAuthentication nor PubkeyAuthentication matches - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # Back up SSH configuration files cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4852,21 +4837,8 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "The private key information has been generated. Be sure to copy and save it. It can be saved as${gl_huang}${ipv4_address}_ssh.key${gl_bai}file for future SSH logins" - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4874,17 +4846,43 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT private key login has been turned on, ROOT password login has been turned off, and reconnection will take effect.${gl_bai}" + echo -e "${gl_lv}The user key login mode has been turned on and the password login mode has been turned off. Reconnection will take effect.${gl_bai}" } +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "The private key information has been generated. Be sure to copy and save it. It can be saved as${gl_huang}${ipv4_address}_ssh.key${gl_bai}file for future SSH logins" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on +} + + + import_sshkey() { local public_key="$1" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key @@ -4898,36 +4896,30 @@ import_sshkey() { if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then echo -e "${gl_hong}Error: Does not look like a legitimate SSH public key.${gl_bai}" return 1 - fi + fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "The public key already exists, no need to add it again" return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}The public key has been successfully imported, ROOT private key login has been enabled, and ROOT password login has been closed. Reconnection will take effect.${gl_bai}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4969,8 +4961,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4996,13 +4988,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then echo "successfully added${added}A new public key arrives${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "No new public keys need to be added (all may already exist)" fi @@ -5012,19 +4998,21 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in to https://github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" echo "5. Click Add SSH key to complete the addition." echo "" echo "Once added, all your public keys will be publicly available on GitHub at:" - echo "https://github.com/yourusername.keys" + echo " ${gh_https_url}github.com/yourusername.keys" echo "" @@ -5037,19 +5025,16 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } - - sshkey_panel() { - root_use - send_stats "Private key login" + send_stats "User key login" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5058,8 +5043,8 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}Not enabled${gl_bai}" fi - echo -e "ROOT private key login mode${IS_KEY_ENABLED}" - echo "Video introduction: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo -e "User key login mode${IS_KEY_ENABLED}" + echo "Advanced gameplay: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "A key pair will be generated, a more secure way to log in via SSH" echo "------------------------" @@ -5096,7 +5081,7 @@ sshkey_panel() { 5) send_stats "Edit public key file" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5104,10 +5089,10 @@ sshkey_panel() { send_stats "View local key" echo "------------------------" echo "Public key information" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "Private key information" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5125,20 +5110,55 @@ sshkey_panel() { - add_sshpasswd() { -echo "Set your ROOT password" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOT login setup is completed!${gl_bai}" + root_use + send_stats "Set password login mode" + echo "Set password login mode" + + local target_user="$1" + + # If no parameters are passed in, enter interactively + if [[ -z "$target_user" ]]; then + read -e -p "Please enter the user name whose password you want to change (default root):" target_user + fi + + # Press Enter and do not enter, the default is root + target_user=${target_user:-root} + + # Verify that the user exists + if ! id "$target_user" >/dev/null 2>&1; then + echo "Error: user$target_userdoes not exist" + return 1 + fi + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + + echo -e "${gl_lv}The password is set and has been changed to password login mode!${gl_bai}" } + + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion @@ -5146,6 +5166,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "Reinstall the system" dd_xitong_MollyLau() { @@ -5194,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}Notice:${gl_bai}Reinstalling may cause loss of connection, so use with caution if you are worried. Reinstallation is expected to take 15 minutes, please back up your data in advance." echo -e "${gl_hui}Thanks to boss bin456789 and boss leitbogioro for their script support!${gl_bai} " - echo -e "${gl_hui}bin456789 project address: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro project address: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789 project address:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro project address:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5716,7 +5745,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}Updating virus database...${gl_bai}" + echo -e "${gl_kjlan}Updating virus database...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5730,7 +5759,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}Scanning directory $@...${gl_bai}" + echo -e "${gl_kjlan}Scanning directory $@...${gl_bai}" # Build mount parameters local MOUNT_PARAMS="" @@ -6025,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -6288,9 +6317,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6332,7 +6361,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6753,7 +6782,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6960,7 +6989,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -7073,7 +7102,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}Querying system information...${gl_bai}" send_stats "System information query" ip_address @@ -7175,8 +7207,60 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ Unrecognized package manager" + exit 1 + fi + + echo "📦 Use a package manager:$PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # left column + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s installed" "${tools[i]}") + else + left=$(printf "❌ %-12s not installed" "${tools[i]}") + fi + + # Right column (to prevent the array from going out of bounds) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s installed" "${tools[i+1]}") + else + right=$(printf "❌ %-12s not installed" "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl download tool${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget download tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo super administrative privilege tool${gl_kjlan}4. ${gl_bai}socat communication connection tool" @@ -7496,12 +7580,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7509,7 +7587,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}Current backup list:${NC}" + echo -e "${gl_kjlan}Current backup list:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "No backup" } @@ -7521,7 +7599,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Docker backup" - echo -e "${YELLOW}Backing up Docker containers...${NC}" + echo -e "${gl_kjlan}Backing up Docker containers...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "Please enter the name of the container to be backed up (separate multiple spaces and press Enter to back up all running containers):" containers @@ -7536,7 +7614,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}Container not found${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}Container not found${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7550,12 +7628,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}Backup container:$c${NC}" + echo -e "${gl_lv}Backup container:$c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}detected$cis a docker-compose container${NC}" + echo -e "${gl_kjlan}detected$cis a docker-compose container${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7565,7 +7643,7 @@ docker_ssh_migration() { # If the Compose project has already been packaged, skip if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose project [$project_name] Already backed up, skip repeated packaging...${NC}" + echo -e "${gl_huang}Compose project [$project_name] Already backed up, skip repeated packaging...${gl_bai}" continue fi @@ -7576,9 +7654,9 @@ docker_ssh_migration() { echo "# docker-compose restore:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose project [$project_name] Packaged:${project_dir}${NC}" + echo -e "${gl_lv}Compose project [$project_name] Packaged:${project_dir}${gl_bai}" else - echo -e "${RED}docker-compose.yml not found, skipping this container...${NC}" + echo -e "${gl_hong}docker-compose.yml not found, skipping this container...${gl_bai}" fi else # Ordinary container backup volume @@ -7615,14 +7693,14 @@ docker_ssh_migration() { # Back up all files under /home/docker (excluding subdirectories) if [ -d "/home/docker" ]; then - echo -e "${BLUE}Back up files under /home/docker...${NC}" + echo -e "${gl_kjlan}Back up files under /home/docker...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}Files under /home/docker have been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}Files under /home/docker have been packaged to:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}Backup completed:${BACKUP_DIR}${NC}" - echo -e "${GREEN}Available restore scripts:${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}Backup completed:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}Available restore scripts:${RESTORE_SCRIPT}${gl_bai}" } @@ -7634,9 +7712,9 @@ docker_ssh_migration() { send_stats "Docker restore" read -e -p "Please enter the backup directory to be restored:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}The backup directory does not exist${gl_bai}"; return; } - echo -e "${BLUE}Starting the restore operation...${NC}" + echo -e "${gl_kjlan}Starting the restore operation...${gl_bai}" install tar jq gzip install_docker @@ -7653,7 +7731,7 @@ docker_ssh_migration() { # Check whether the container of the compose project is already running running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose project [$project_name] Containers are already running, skip restore...${NC}" + echo -e "${gl_huang}Compose project [$project_name] Containers are already running, skip restore...${gl_bai}" continue fi @@ -7662,32 +7740,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose project [$project_name] has been extracted to:$original_path${NC}" + echo -e "${gl_lv}Compose project [$project_name] has been extracted to:$original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose project [$project_name] Restore completed!${NC}" + echo -e "${gl_lv}Compose project [$project_name] Restore completed!${gl_bai}" fi done # --------- Continue to restore normal containers --------- - echo -e "${BLUE}Check and restore normal Docker containers...${NC}" + echo -e "${gl_kjlan}Check and restore normal Docker containers...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}Processing container:$container${NC}" + echo -e "${gl_lv}Processing container:$container${gl_bai}" # Check if the container already exists and is running if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}container [$container] already running, skipping restore...${NC}" + echo -e "${gl_huang}container [$container] already running, skipping restore...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}Mirror information not found, skip:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}Mirror information not found, skip:$container${gl_bai}"; continue; } # port mapping PORT_ARGS="" @@ -7721,7 +7799,7 @@ docker_ssh_migration() { # Delete existing but not running containers if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}container [$container] exists but is not running, delete the old container...${NC}" + echo -e "${gl_huang}container [$container] exists but is not running, delete the old container...${gl_bai}" docker rm -f "$container" fi @@ -7730,16 +7808,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}No backup information for common containers found${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}No backup information for common containers found${gl_bai}" # Restore files under /home/docker if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}Restoring files under /home/docker...${NC}" + echo -e "${gl_kjlan}Restoring files under /home/docker...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}Files under /home/docker have been restored${NC}" + echo -e "${gl_lv}Files under /home/docker have been restored${gl_bai}" else - echo -e "${YELLOW}The backup of the file under /home/docker was not found, skipping...${NC}" + echo -e "${gl_huang}The backup of the file under /home/docker was not found, skipping...${gl_bai}" fi @@ -7753,7 +7831,7 @@ docker_ssh_migration() { send_stats "Docker migration" install jq read -e -p "Please enter the backup directory to be migrated:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}The backup directory does not exist${gl_bai}"; return; } read -e -p "Target server IP:" TARGET_IP read -e -p "Target server SSH username:" TARGET_USER @@ -7762,9 +7840,9 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}Transferring backup...${NC}" + echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7776,9 +7854,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker backup file deletion" read -e -p "Please enter the backup directory to be deleted:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}The backup directory does not exist${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}The backup directory does not exist${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}Deleted backup:${BACKUP_DIR}${NC}" + echo -e "${gl_lv}Deleted backup:${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7808,7 +7886,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}Invalid option${NC}" ;; + *) echo -e "${gl_hong}Invalid option${gl_bai}" ;; esac break_end done @@ -8131,7 +8209,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8412,7 +8490,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -8544,16 +8621,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8586,14 +8663,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8624,14 +8701,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8671,15 +8749,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8723,14 +8803,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8781,15 +8864,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8823,15 +8908,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8862,14 +8948,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9000,13 +9086,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9040,12 +9128,14 @@ linux_ldnmp() { read -e -p "Please enter your reverse proxy domain name:" fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9098,12 +9188,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9139,12 +9230,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9199,7 +9291,7 @@ linux_ldnmp() { send_stats "LDNMP environment backup" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}Backing up$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9297,7 +9389,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}Unzipping$filename ...${gl_bai}" + echo -e "${gl_kjlan}Unzipping$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9490,6 +9582,168 @@ linux_ldnmp() { + + + +moltbot_menu() { + local app_id="114" + + send_stats "clawdbot/moltbot installation" + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}Installed${gl_bai}" + else + echo "${gl_hui}Not installed${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}Running${gl_bai}" + else + echo "${gl_hui}Not running${gl_bai}" + fi + } + + + show_menu() { + clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) + echo "=======================================" + echo -e "ClawdBot > MoltBot > OpenClaw Management" + echo -e "$install_status $running_status" + echo "=======================================" + echo "1. Installation" + echo "2. Start" + echo "3. Stop" + echo "--------------------" + echo "4. Log viewing" + echo "5. Change model" + echo "6. Enter the connection code in TG" + echo "--------------------" + echo "7. Update" + echo "8. Uninstall" + echo "--------------------" + echo "0. Return to the previous menu" + echo "--------------------" + printf "Please enter options and press Enter:" + } + + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + sleep 3 + } + + + install_moltbot() { + echo "Start installing OpenClaw..." + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + pnpm config set registry https://registry.npmmirror.com + fi + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw + source ~/.bashrc + source ~/.profile + openclaw doctor --fix + openclaw onboard --install-daemon + openclaw gateway stop + start_tmux + add_app_id + break_end + + } + + + start_bot() { + echo "Starting OpenClaw..." + start_tmux + break_end + } + + stop_bot() { + echo "Stop OpenClaw..." + install tmux + openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + break_end + } + + view_logs() { + echo "View OpenClaw logs, Ctrl+C to exit" + openclaw logs + break_end + } + + change_model() { + printf "Please enter the model name to set (e.g. openrouter/openai/gpt-4o):" + read model + echo "Switch model to$model" + openclaw models set "$model" + break_end + } + + + change_tg_bot_code() { + printf "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F:" + read code + openclaw pairing approve telegram $code + break_end + } + + update_moltbot() { + echo "Update OpenClaw..." + openclaw update --restart + add_app_id + echo "Update completed" + break_end + } + + + uninstall_moltbot() { + echo "Uninstall OpenClaw..." + openclaw uninstall + npm uninstall -g openclaw + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + echo "Uninstall completed" + break_end + } + + + # main loop + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; + *) break ;; + esac + done + +} + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -9497,6 +9751,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}The application list is being updated. Please wait...${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -9525,7 +9780,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -9590,7 +9845,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool${gl_kjlan}112. ${color112}Lucky large intranet penetration tool" - echo -e "${gl_kjlan}113. ${color113}Firefox browser" + echo -e "${gl_kjlan}113. ${color113}Firefox browser${gl_kjlan}114. ${color114}ClawdBot/Moltbot robot${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}Third-party application list" echo -e "${gl_kjlan}Want your app to appear here? Check out the developer guide:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -9755,7 +10010,7 @@ while true; do local docker_describe="A file listing program that supports multiple storages, web browsing and WebDAV, powered by gin and Solidjs" - local docker_url="Official website introduction: https://github.com/OpenListTeam/OpenList" + local docker_url="Official website introduction:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -10862,25 +11117,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="mouse panel" - local panelurl="Official address:${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanel original mouse panel" + local panelurl="Official address:${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -10995,7 +11251,7 @@ while true; do } local docker_describe="GHProxy implemented using Go is used to accelerate the pulling of Github repositories in some areas." - local docker_url="Official website introduction: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="Official website introduction:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11060,7 +11316,7 @@ while true; do } local docker_describe="This is a Prometheus host data collection component, please deploy it on the monitored host." - local docker_url="Official website introduction: https://github.com/prometheus/node_exporter" + local docker_url="Official website introduction:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11090,7 +11346,7 @@ while true; do } local docker_describe="This is a Prometheus container data collection component, please deploy it on the monitored host." - local docker_url="Official website introduction: https://github.com/google/cadvisor" + local docker_url="Official website introduction:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11113,7 +11369,7 @@ while true; do } local docker_describe="This is a small tool for website change detection, replenishment monitoring and notification" - local docker_url="Official website introduction: https://github.com/dgtlmoon/changedetection.io" + local docker_url="Official website introduction:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11146,7 +11402,7 @@ while true; do } local docker_describe="Docker visual panel system provides complete docker management functions." - local docker_url="Official website introduction: https://github.com/donknap/dpanel" + local docker_url="Official website introduction:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11166,7 +11422,7 @@ while true; do } local docker_describe="OpenWebUI is a large language model web page framework that is connected to the new llama3 large language model." - local docker_url="Official website introduction: https://github.com/open-webui/open-webui" + local docker_url="Official website introduction:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11218,7 +11474,7 @@ while true; do } local docker_describe="OpenWebUI is a large language model web page framework that is connected to the new DeepSeek R1 large language model." - local docker_url="Official website introduction: https://github.com/open-webui/open-webui" + local docker_url="Official website introduction:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11274,7 +11530,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="New generation of large model gateway and AI asset management system" - local app_url="Official website: https://github.com/Calcium-Ion/new-api" + local app_url="Official website:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11328,7 +11584,7 @@ while true; do local app_id="60" local app_name="JumpServer open source bastion machine" local app_text="It is an open source privileged access management (PAM) tool. This program occupies port 80 and does not support adding domain names for access." - local app_url="Official introduction: https://github.com/jumpserver/jumpserver" + local app_url="Official introduction:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11379,7 +11635,7 @@ while true; do } local docker_describe="Free open source machine translation API, fully self-hosted, and its translation engine is powered by the open source Argos Translate library." - local docker_url="Official website introduction: https://github.com/LibreTranslate/LibreTranslate" + local docker_url="Official website introduction:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11392,7 +11648,7 @@ while true; do local app_id="62" local app_name="RAGFlow knowledge base" local app_text="Open source RAG (Retrieval Augmented Generation) engine based on deep document understanding" - local app_url="Official website: https://github.com/infiniflow/ragflow" + local app_url="Official website:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11440,7 +11696,7 @@ while true; do } local docker_describe="OpenWebUI is a large language model web page framework, the official simplified version supports API access to all major models." - local docker_url="Official website introduction: https://github.com/open-webui/open-webui" + local docker_url="Official website introduction:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11458,7 +11714,7 @@ while true; do } local docker_describe="Very useful tool for developers and IT workers" - local docker_url="Official website introduction: https://github.com/CorentinTh/it-tools" + local docker_url="Official website introduction:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11494,7 +11750,7 @@ while true; do } local docker_describe="It is a powerful automated workflow platform" - local docker_url="Official website introduction: https://github.com/n8n-io/n8n" + local docker_url="Official website introduction:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11523,7 +11779,7 @@ while true; do } local docker_describe="Automatically update your public IP (IPv4/IPv6) to major DNS service providers in real time to achieve dynamic domain name resolution." - local docker_url="Official website introduction: https://github.com/jeessy2/ddns-go" + local docker_url="Official website introduction:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11633,7 +11889,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -11693,7 +11949,7 @@ while true; do } local docker_describe="Free online video search and viewing platform" - local docker_url="Official website introduction: https://github.com/LibreSpark/LibreTV" + local docker_url="Official website introduction:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11709,7 +11965,7 @@ while true; do local app_name="moontv private film and television" local app_text="Free online video search and viewing platform" - local app_url="Video introduction: https://github.com/MoonTechLab/LunaTV" + local app_url="Video introduction:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11775,7 +12031,7 @@ while true; do } local docker_describe="Your music wizard, designed to help you better manage your music." - local docker_url="Official website introduction: https://github.com/foamzou/melody" + local docker_url="Official website introduction:${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11802,7 +12058,7 @@ while true; do } local docker_describe="It is a Chinese DOS game collection website" - local docker_url="Official website introduction: https://github.com/rwv/chinese-dos-games" + local docker_url="Official website introduction:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11837,7 +12093,7 @@ while true; do } local docker_describe="Xunlei, your offline high-speed BT magnetic download tool" - local docker_url="Official website introduction: https://github.com/cnk3x/xunlei" + local docker_url="Official website introduction:${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"Log in to Xunlei with your mobile phone and enter the invitation code. Invitation code: Xunlei Niutong\"" local docker_passwd="" local app_size="1" @@ -11852,7 +12108,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki is an open source intelligent document management system driven by AI large models. It is strongly recommended not to customize port deployment." - local app_url="Official introduction: https://github.com/chaitin/PandaWiki" + local app_url="Official introduction:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -12081,7 +12337,7 @@ while true; do } local docker_describe="Lightweight self-hosted server monitoring tool" - local docker_url="Official website introduction: https://github.com/komari-monitor/komari/tree/main" + local docker_url="Official website introduction:${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"Default account: admin Default password: 1212156\"" local docker_passwd="" local app_size="1" @@ -12112,7 +12368,7 @@ while true; do } local docker_describe="Open source personal subscription tracker for financial management" - local docker_url="Official website introduction: https://github.com/ellite/Wallos" + local docker_url="Official website introduction:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12125,7 +12381,7 @@ while true; do local app_id="85" local app_name="immich picture video manager" local app_text="High-performance self-hosted photo and video management solution." - local app_url="Official website introduction: https://github.com/immich-app/immich" + local app_url="Official website introduction:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12218,7 +12474,7 @@ while true; do } local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" - local docker_url="Official website introduction: https://github.com/synctv-org/synctv" + local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" local app_size="1" @@ -12277,7 +12533,7 @@ while true; do } local docker_describe="Share texts and files with anonymous passwords, and pick up files like express delivery" - local docker_url="Official website introduction: https://github.com/vastsa/FileCodeBox" + local docker_url="Official website introduction:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"The access address is followed by /#/admin to access the administrator page\"" local docker_passwd="echo \"Administrator password: FileCodeBox2023\"" local app_size="1" @@ -12349,7 +12605,7 @@ while true; do local app_name="gitea private code repository" local app_text="A free new generation code hosting platform that provides an experience close to GitHub." - local app_url="Video introduction: https://github.com/go-gitea/gitea" + local app_url="Video introduction:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12439,7 +12695,7 @@ while true; do } local docker_describe="Minimalist static file server, supports upload and download" - local docker_url="Official website introduction: https://github.com/sigoden/dufs" + local docker_url="Official website introduction:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12470,7 +12726,7 @@ while true; do } local docker_describe="Distributed high-speed download tool, supporting multiple protocols" - local docker_url="Official website introduction: https://github.com/GopeedLab/gopeed" + local docker_url="Official website introduction:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12534,7 +12790,7 @@ while true; do local app_name="2FAuth self-hosted two-step authenticator" local app_text="Self-hosted two-factor authentication (2FA) account management and verification code generation tool." - local app_url="Official website: https://github.com/Bubka/2FAuth" + local app_url="Official website:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12765,7 +13021,7 @@ while true; do local app_name="dsm synology virtual machine" local app_text="Virtual DSM in Docker container" - local app_url="Official website: https://github.com/vdsm/virtual-dsm" + local app_url="Official website:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12836,7 +13092,7 @@ while true; do } local docker_describe="An open source peer-to-peer file synchronization tool, similar to Dropbox and Resilio Sync, but completely decentralized." - local docker_url="Official website introduction: https://github.com/syncthing/syncthing" + local docker_url="Official website introduction:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12849,7 +13105,7 @@ while true; do local app_id="101" local app_name="AI video generation tool" local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" - local app_url="Official website: https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12904,7 +13160,7 @@ while true; do } local docker_describe="It is a personal cloud social media chat service that supports independent deployment." - local docker_url="Official website introduction: https://github.com/Privoce/vocechat-web" + local docker_url="Official website introduction:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12917,7 +13173,7 @@ while true; do local app_id="103" local app_name="Umami website statistics tool" local app_text="Open source, lightweight, privacy-friendly website analysis tool, similar to Google Analytics." - local app_url="Official website: https://github.com/umami-software/umami" + local app_url="Official website:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12983,7 +13239,7 @@ while true; do } local docker_describe="Siyuan Notes is a privacy-first knowledge management system" - local docker_url="Official website introduction: https://github.com/siyuan-note/siyuan" + local docker_url="Official website introduction:${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13010,7 +13266,7 @@ while true; do } local docker_describe="It is a powerful open source whiteboard tool that integrates mind maps, flow charts, etc." - local docker_url="Official website introduction: https://github.com/plait-board/drawnix" + local docker_url="Official website introduction:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13045,7 +13301,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou is a high-performance network disk resource search API service." - local docker_url="Official website introduction: https://github.com/fish2018/pansou" + local docker_url="Official website introduction:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13060,7 +13316,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot chatbot" local app_text="It is an open source large language model native instant messaging robot development platform." - local app_url="Official website: https://github.com/langbot-app/LangBot" + local app_url="Official website:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13117,7 +13373,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="It is an online network disk program suitable for individuals or small teams." - local docker_url="Official website introduction: https://github.com/zfile-dev/zfile" + local docker_url="Official website introduction:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13130,7 +13386,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeep bookmark management" local app_text="is a self-hosted bookmarking app with artificial intelligence capabilities designed for data hoarders." - local app_url="Official website: https://github.com/karakeep-app/karakeep" + local app_url="Official website:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13183,7 +13439,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="It is a powerful multi-format file conversion tool (supports documents, images, audio and video, etc.) It is strongly recommended to add domain name access" - local docker_url="Project address: https://github.com/c4illin/ConvertX" + local docker_url="Project address:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13215,7 +13471,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky is a large intranet penetration and port forwarding management tool that supports DDNS, reverse proxy, WOL and other functions." - local docker_url="Project address: https://github.com/gdy666/lucky" + local docker_url="Project address:${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"Default account password: 666\"" local docker_passwd="" local app_size="1" @@ -13245,7 +13501,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through the web page." - local docker_url="Project address: https://github.com/jlesage/docker-firefox" + local docker_url="Project address:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13253,13 +13509,17 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) + moltbot_menu + ;; + b) clear send_stats "All application backup" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}Backing up$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}Backing up$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13316,7 +13576,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}Unzipping$filename ...${gl_bai}" + echo -e "${gl_kjlan}Unzipping$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "The application data has been restored. Currently, please manually enter the specified application menu and update the application to restore the application." else @@ -13563,20 +13823,33 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "Use official mirror source..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel true \ - --pure-mode + echo "Use overseas mirror sources..." + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } @@ -13636,6 +13909,378 @@ fail2ban_panel() { +net_menu() { + + send_stats "Network card management tool" + show_nics() { + echo "================ Current network card information ================" + printf "%-18s %-12s %-20s %-26s\n" "Network card name" "state" "IP address" "MAC address" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== Network card management menu ===========" + echo "1. Enable network card" + echo "2. Disable network card" + echo "3. View network card details" + echo "4. Refresh network card information" + echo "0. Return to the previous menu" + echo "====================================" + read -rp "Please select an action:" choice + + case $choice in + 1) + send_stats "Enable network card" + read -rp "Please enter the name of the network card to be enabled:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ Network card$nicEnabled" + else + echo "✘ The network card does not exist" + fi + read -rp "Press Enter to continue..." + ;; + 2) + send_stats "Disable network card" + read -rp "Please enter the name of the network card to be disabled:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ Network card$nicDisabled" + else + echo "✘ The network card does not exist" + fi + read -rp "Press Enter to continue..." + ;; + 3) + send_stats "View network card details" + read -rp "Please enter the name of the network card you want to view:" nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nicDetails ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ The network card does not exist" + fi + read -rp "Press Enter to continue..." + ;; + 4) + send_stats "Refresh network card information" + continue + ;; + *) + break + ;; + esac + done +} + + + +log_menu() { + send_stats "System log management tool" + + show_log_overview() { + echo "============= System log overview =============" + echo "Hostname: $(hostname)" + echo "System time: $(date)" + echo + echo "[/var/log directory occupation]" + du -sh /var/log 2>/dev/null + echo + echo "[journal log occupation]" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== System log management menu ===========" + echo "1. View the latest system log (journal)" + echo "2. View the specified service log" + echo "3. View login/security logs" + echo "4. Real-time tracking logs" + echo "5. Clean up old journal logs" + echo "0. Return to the previous menu" + echo "=======================================" + read -rp "Please select an action:" choice + + case $choice in + 1) + send_stats "View recent logs" + read -rp "View the most recent log lines? [Default 100]:" lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "Press Enter to continue..." + ;; + 2) + send_stats "View specified service logs" + read -rp "Please enter the service name (such as sshd, nginx):" svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ The service does not exist or has no logs" + fi + read -rp "Press Enter to continue..." + ;; + 3) + send_stats "View login/security logs" + echo "====== Recent login log ======" + last -n 10 + echo + echo "====== Authentication Log ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "Security log file not found" + fi + read -rp "Press Enter to continue..." + ;; + 4) + send_stats "Real-time tracking log" + echo "1) System log" + echo "2) Specify service log" + read -rp "Select tracking type:" t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "Enter service name:" svc + journalctl -u "$svc" -f + else + echo "Invalid selection" + fi + ;; + 5) + send_stats "Clean up old journal logs" + echo "⚠️ Clean the journal (safe way)" + echo "1) Keep the last 7 days" + echo "2) Keep the last 3 days" + echo "3) Limit the maximum log size to 500M" + read -rp "Please select a cleaning method:" c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "Invalid option" ;; + esac + echo "✔ Journal log cleaning completed" + sleep 2 + ;; + *) + break + ;; + esac + done +} + + + +env_menu() { + + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "System variable management tool" + + show_env_vars() { + clear + send_stats "Currently in effect environment variables" + echo "========== Currently in effect environment variables (excerpt) ==========" + printf "%-20s %s\n" "variable name" "value" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== Variables defined in the configuration file (parsing) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> Source file:$file" + echo "-----------------------------------------------" + + # Extract export VAR=xxx or VAR=xxx + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "Press Enter to continue..." + } + + + view_file() { + local file="$1" + send_stats "View variable file$file" + clear + if [ -f "$file" ]; then + echo "========== View files:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "File does not exist:$file" + fi + read -rp "Press Enter to continue..." + } + + edit_file() { + local file="$1" + send_stats "Edit variable file$file" + install nano + nano "$file" + } + + source_files() { + echo "Reloading environment variables..." + send_stats "Reloading environment variables" + source "$BASHRC" + source "$PROFILE" + echo "✔ Environment variables have been reloaded" + read -rp "Press Enter to continue..." + } + + while true; do + clear + echo "=========== System environment variable management ==========" + echo "Current user:$USER" + echo "--------------------------------------" + echo "1. Check the current commonly used environment variables" + echo "2. View ~/.bashrc" + echo "3. View ~/.profile" + echo "4. Edit ~/.bashrc" + echo "5. Edit ~/.profile" + echo "6. Reload environment variables (source)" + echo "--------------------------------------" + echo "0. Return to the previous menu" + echo "--------------------------------------" + read -rp "Please select an action:" choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "Invalid option" + sleep 1 + ;; + esac + done +} + + +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "Usage: create_user_with_sshkey " + return 1 + fi + + # Create user + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "Example of importing public key:" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" + echo "- Paste directly: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "Please import${new_username}public key:" sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "Import SSH public key from URL" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "Directly import the public key" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "Error: unknown parameter '$sshkey_vl'" + return 1 + ;; + esac + + + # Fix permissions + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo password-free + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" <> /etc/ssh/sshd_config + passwd -l "$new_username" &>/dev/null + restart_ssh + + echo "user$new_usernameCreation completed" +} + + + + + + + + + + + + + linux_Settings() { @@ -13646,7 +14291,7 @@ linux_Settings() { echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" + echo -e "${gl_kjlan}3. ${gl_bai}User password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" @@ -13658,7 +14303,7 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Scheduled task management" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}Native host resolution${gl_kjlan}22. ${gl_bai}SSH defense program" - echo -e "${gl_kjlan}23. ${gl_bai}Current limiting automatic shutdown${gl_kjlan}24. ${gl_bai}ROOT private key login mode" + echo -e "${gl_kjlan}23. ${gl_bai}Current limiting automatic shutdown${gl_kjlan}24. ${gl_bai}User key login mode" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot system monitoring and early warning${gl_kjlan}26. ${gl_bai}Fix OpenSSH high-risk vulnerabilities" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux kernel upgrade${gl_kjlan}28. ${gl_bai}Linux system kernel parameter optimization${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}Virus scanning tools${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}file manager" @@ -13667,9 +14312,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}Set up system recycle bin${gl_kjlan}34. ${gl_bai}System backup and recovery" echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" - echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}Network card management tool" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}message board${gl_kjlan}66. ${gl_bai}One-stop system tuning${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}System log management tool${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}System variable management tool" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}61. ${gl_bai}message board${gl_kjlan}66. ${gl_bai}One-stop system tuning${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}Restart the server${gl_kjlan}100. ${gl_bai}Privacy and security" echo -e "${gl_kjlan}101. ${gl_bai}Advanced usage of k command${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Uninstall tech lion script" echo -e "${gl_kjlan}------------------------" @@ -13687,7 +14334,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "Shortcut keys have been set" send_stats "Script shortcut key has been set" break_end @@ -13702,8 +14352,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "root password mode" + clear add_sshpasswd ;; @@ -13713,7 +14362,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -13860,16 +14509,13 @@ EOF linux_Settings fi - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + create_user_with_sshkey $new_username true - install sudo + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - passwd -l root - - echo "The operation is complete." ;; @@ -13983,7 +14629,12 @@ EOF printf "%-24s %-34s %-20s %-10s\n" "username" "User permissions" "User group" "sudo permissions" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) - local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -13991,7 +14642,7 @@ EOF echo "" echo "Account operations" echo "------------------------" - echo "1. Create a regular account 2. Create a premium account" + echo "1. Create a normal user 2. Create an advanced user" echo "------------------------" echo "3. Grant the highest authority 4. Remove the highest authority" echo "------------------------" @@ -14005,46 +14656,34 @@ EOF 1) # Prompt user for new username read -e -p "Please enter a new username:" new_username + create_user_with_sshkey $new_username false - # Create new user and set password - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - echo "The operation is complete." ;; 2) # Prompt user for new username read -e -p "Please enter a new username:" new_username - - # Create new user and set password - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - # Give the new user sudo permissions - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "The operation is complete." + create_user_with_sshkey $new_username true ;; 3) read -e -p "Please enter username:" username - # Give the new user sudo permissions - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "Please enter the username you want to delete:" username - # Delete users and their home directories userdel -r "$username" ;; @@ -14052,6 +14691,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; @@ -14580,7 +15220,23 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 42) + clear + env_menu + ;; + + + 61) clear send_stats "message board" echo "Visit the official message board of Technology Lion. If you have any ideas about the script, please leave a message to exchange!" @@ -15015,7 +15671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15182,7 +15838,7 @@ echo -e "${gl_kjlan}Station B:${gl_bai}https://b23.tv/2mqnQyh ${gl_ echo -e "${gl_kjlan}Official website:${gl_bai}https://kejilion.pro/ ${gl_kjlan}navigation:${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}blog:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}Software Center:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}Script official website:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub address:${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}Script official website:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub address:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -15405,7 +16061,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" @@ -15695,30 +16351,27 @@ else sshkey) - shift + + shift case "$1" in "" ) # sshkey → interactive menu send_stats "SSHKey interactive menu" sshkey_panel ;; - github ) shift send_stats "Import SSH public key from GitHub" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "Import SSH public key from URL" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "Directly import the public key" import_sshkey "$1" ;; - * ) echo "Error: unknown parameter '$1'" echo "usage:" @@ -15728,11 +16381,10 @@ else echo "k sshkey github Import SSH public key from GitHub" ;; esac + ;; *) k_info ;; esac fi - - diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 9a072b06c..1815a9d87 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.7" gl_hui='\e[37m' @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -102,6 +104,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -176,7 +179,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}インストール中$package...${gl_bai}" + echo -e "${gl_kjlan}インストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -251,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}アンインストールする$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -448,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}Docker 環境をインストールしています...${gl_bai}" + echo -e "${gl_kjlan}Docker 環境をインストールしています...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -627,7 +630,7 @@ while true; do send_stats "イメージをプルする" read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}画像の取得:$name${gl_bai}" + echo -e "${gl_kjlan}画像の取得:$name${gl_bai}" docker pull $name done ;; @@ -635,7 +638,7 @@ while true; do send_stats "画像を更新" read -e -p "イメージ名を入力してください (複数のイメージ名はスペースで区切ってください):" imagenames for name in $imagenames; do - echo -e "${gl_huang}画像の更新:$name${gl_bai}" + echo -e "${gl_kjlan}画像の更新:$name${gl_bai}" docker pull $name done ;; @@ -921,12 +924,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1442,10 +1445,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1543,7 +1542,7 @@ certs_status() { echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" echo -e "6. 国内登録制限 ➠ 中国本土環境の場合は、ドメイン名が登録されているかをご確認ください。" echo "------------------------" - echo "1. 再度適用します。 2. 既存の証明書をインポートします。 3. 証明書なしで HTTP アクセスを使用します。 0. 終了します。" + echo "1. 再適用 2. 既存の証明書をインポート 0. 終了" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice case $sub_choice in @@ -1600,18 +1599,9 @@ certs_status() { echo "エラー: 証明書または秘密キーの形式が無効です。" certs_status fi - - ;; - 3) - send_stats "証明書なしの HTTP アクセスに切り替える" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - send_stats "申請を取り下げる" - rm -f /home/web/conf.d/${yuming}.conf - exit + exit ;; esac fi @@ -1754,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1995,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2146,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -2244,7 +2234,7 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" + echo "CF パラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2328,7 +2318,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2565,7 +2555,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2624,7 +2614,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2641,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2897,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3020,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3391,14 +3381,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3447,6 +3439,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3465,9 +3461,6 @@ ldnmp_Proxy() { sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3495,6 +3488,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3511,8 +3507,6 @@ ldnmp_Proxy_backend() { sed -i "s/# 動的に追加/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -3626,7 +3620,7 @@ stream_panel() { send_stats "レイヤー 4 プロキシを追加する" ;; 5) - send_stats "転送設定の編集" + send_stats "転送設定を編集する" read -e -p "編集するサービス名を入力してください:" stream_name install nano nano /home/web/stream.d/$stream_name.conf @@ -3679,7 +3673,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3890,7 +3884,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4274,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRPサーバー$check_frp $update_status" echo "FRPイントラネットペネトレーションサービス環境を構築し、パブリックIPを持たないデバイスをインターネットに公開" - echo "公式サイト紹介:https://github.com/fatedier/frp/" + echo "公式サイト紹介:${gh_https_url}github.com/fatedier/frp/" echo "ビデオチュートリアル: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4342,7 +4336,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4372,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRPクライアント$check_frp $update_status" echo "サーバーに接続します。接続後、インターネットにアクセスするためのイントラネット侵入サービスを作成できます。" - echo "公式サイト紹介:https://github.com/fatedier/frp/" + echo "公式サイト紹介:${gh_https_url}github.com/fatedier/frp/" echo "ビデオチュートリアル: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4465,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp ダウンロードツール" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp は、YouTube、Bilibili、Twitter などの何千ものサイトをサポートする強力な動画ダウンロード ツールです。" - echo -e "公式サイトアドレス:https://github.com/yt-dlp/yt-dlp" + echo -e "公式サイトアドレス:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "ダウンロードしたビデオのリスト:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(まだありません)" @@ -4484,7 +4478,7 @@ yt_menu_pro() { send_stats "yt-dlp をインストールしています..." echo "yt-dlp をインストールしています..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -4600,7 +4594,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}システムアップデート中です...${gl_bai}" + echo -e "${gl_kjlan}システムアップデート中です...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4627,7 +4621,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}システムクリーニング中...${gl_bai}" + echo -e "${gl_kjlan}システムクリーニング中...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4807,39 +4801,30 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 見つかった場合は、PasswordAuthentication が Yes に設定されます - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # 見つかった場合、PubkeyAuthentication は Yes に設定されます - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # PasswordAuthentication も PubkeyAuthentication も一致しない場合にデフォルト値を設定します - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # SSH設定ファイルをバックアップする cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4852,21 +4837,8 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4874,17 +4846,43 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 秘密キー ログインがオンになり、ROOT パスワード ログインがオフになり、再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}ユーザーキーログインモードがオンになり、パスワードログインモードがオフになりました。再接続が有効になります。${gl_bai}" } +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on +} + + + import_sshkey() { local public_key="$1" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "SSH 公開キーの内容を入力してください (通常は「ssh-rsa」または「ssh-ed25519」で始まります):" public_key @@ -4898,36 +4896,30 @@ import_sshkey() { if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then echo -e "${gl_hong}エラー: 正規の SSH 公開キーのようには見えません。${gl_bai}" return 1 - fi + fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "公開キーはすでに存在するため、再度追加する必要はありません" return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}公開キーは正常にインポートされ、ROOT 秘密キーのログインが有効になり、ROOT パスワードのログインが閉じられました。再接続が有効になります。${gl_bai}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4964,13 +4956,13 @@ fetch_remote_ssh_keys() { # コンテンツが有効かどうかを確認する if [[ ! -s "${temp_file}" ]]; then - echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります。" >&2 + echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります" >&2 rm -f "${temp_file}" return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4996,13 +4988,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then echo "正常に追加されました${added}新しい公開鍵が到着する${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "新しい公開キーを追加する必要はありません (すべてがすでに存在している可能性があります)" fi @@ -5012,19 +4998,21 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "続行する前に、SSH 公開キーを GitHub アカウントに追加していることを確認してください。" - echo "1. https://github.com/settings/keys にログインします。" + echo "1. ログイン${gh_https_url}github.com/settings/keys" echo "2. [新しい SSH キー] または [SSH キーの追加] をクリックします。" echo "3. タイトルは必要に応じて入力できます (例: Home Laptop 2026)" echo "4. ローカル公開鍵の内容 (通常は ~/.ssh/id_ed25519.pub または id_rsa.pub の内容全体) を「Key」フィールドに貼り付けます。" echo "5. [SSH キーの追加] をクリックして追加を完了します。" echo "" echo "追加すると、すべての公開キーが GitHub で公開されます。" - echo "https://github.com/あなたのユーザー名.keys" + echo " ${gh_https_url}github.com/あなたのユーザー名.keys" echo "" @@ -5037,19 +5025,16 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } - - sshkey_panel() { - root_use - send_stats "秘密キーによるログイン" + send_stats "ユーザーキーログイン" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5058,8 +5043,8 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}有効になっていません${gl_bai}" fi - echo -e "ROOT秘密鍵ログインモード${IS_KEY_ENABLED}" - echo "ビデオ紹介: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo -e "ユーザーキーログインモード${IS_KEY_ENABLED}" + echo "高度なゲームプレイ: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" echo "------------------------" @@ -5096,7 +5081,7 @@ sshkey_panel() { 5) send_stats "公開鍵ファイルを編集する" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5104,10 +5089,10 @@ sshkey_panel() { send_stats "ローカルキーを表示する" echo "------------------------" echo "公開鍵情報" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "秘密鍵情報" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5125,20 +5110,55 @@ sshkey_panel() { - add_sshpasswd() { -echo "ROOTパスワードを設定する" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOTログインの設定が完了しました!${gl_bai}" + root_use + send_stats "パスワードログインモードを設定する" + echo "パスワードログインモードを設定する" + + local target_user="$1" + + # パラメータが渡されない場合は、対話的に入力します + if [[ -z "$target_user" ]]; then + read -e -p "パスワードを変更するユーザー名を入力してください (デフォルトは root):" target_user + fi + + # Enter キーを押して入力しないでください。デフォルトは root です + target_user=${target_user:-root} + + # ユーザーが存在することを確認する + if ! id "$target_user" >/dev/null 2>&1; then + echo "エラー: ユーザー$target_user存在しません" + return 1 + fi + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + + echo -e "${gl_lv}パスワードが設定され、パスワードログインモードに変更されました。${gl_bai}" } + + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion @@ -5146,6 +5166,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "システムを再インストールする" dd_xitong_MollyLau() { @@ -5194,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" echo -e "${gl_hui}スクリプトをサポートしてくれたボス bin456789 とボス leitbogioro に感謝します。${gl_bai} " - echo -e "${gl_hui}bin456789 プロジェクトのアドレス: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro プロジェクトのアドレス: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789 プロジェクトのアドレス:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro プロジェクトのアドレス:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5356,7 +5385,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5716,7 +5745,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}ウイルスデータベースを更新しています...${gl_bai}" + echo -e "${gl_kjlan}ウイルスデータベースを更新しています...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5730,7 +5759,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}ディレクトリ $@ をスキャンしています...${gl_bai}" + echo -e "${gl_kjlan}ディレクトリ $@ をスキャンしています...${gl_bai}" # ビルドマウントパラメータ local MOUNT_PARAMS="" @@ -6025,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6288,9 +6317,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6332,7 +6361,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6620,9 +6649,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントする +# パーティションのマウント mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6641,7 +6670,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする + # パーティションのマウント mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6753,7 +6782,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6801,7 +6830,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -6960,7 +6989,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモート ホストにアクセスできますか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6969,7 +6998,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7073,7 +7102,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}システム情報を問い合わせています...${gl_bai}" send_stats "システム情報の問い合わせ" ip_address @@ -7175,8 +7207,60 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ 認識されないパッケージマネージャー" + exit 1 + fi + + echo "📦 パッケージマネージャーを使用します:$PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # 左の列 + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s がインストールされました" "${tools[i]}") + else + left=$(printf "❌ %-12s がインストールされていません" "${tools[i]}") + fi + + # 右列 (配列が範囲外になるのを防ぐため) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s がインストールされました" "${tools[i+1]}") + else + right=$(printf "❌ %-12s がインストールされていません" "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo スーパー管理者特権ツール${gl_kjlan}4. ${gl_bai}socat通信接続ツール" @@ -7496,12 +7580,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7509,7 +7587,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}現在のバックアップ リスト:${NC}" + echo -e "${gl_kjlan}現在のバックアップ リスト:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" } @@ -7521,7 +7599,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Dockerバックアップ" - echo -e "${YELLOW}Docker コンテナをバックアップしています...${NC}" + echo -e "${gl_kjlan}Docker コンテナをバックアップしています...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "バックアップするコンテナの名前を入力してください (実行中のすべてのコンテナをバックアップするには、複数のスペースを区切って Enter キーを押します)。" containers @@ -7536,7 +7614,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}コンテナが見つかりません${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}コンテナが見つかりません${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7550,12 +7628,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}バックアップコンテナ:$c${NC}" + echo -e "${gl_lv}バックアップコンテナ:$c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}検出されました$cdocker-compose コンテナーです${NC}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7565,7 +7643,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${NC}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -7576,9 +7654,9 @@ docker_ssh_migration() { echo "# docker-compose 復元:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}プロジェクトの作成 [$project_name]パッケージ化:${project_dir}${NC}" + echo -e "${gl_lv}プロジェクトの作成 [$project_name] パッケージ内容:${project_dir}${gl_bai}" else - echo -e "${RED}docker-compose.yml が見つからないため、このコンテナをスキップします...${NC}" + echo -e "${gl_hong}docker-compose.yml が見つからないため、このコンテナをスキップします...${gl_bai}" fi else # 通常のコンテナバックアップボリューム @@ -7615,14 +7693,14 @@ docker_ssh_migration() { # /home/docker 下のすべてのファイルをバックアップします (サブディレクトリを除く)。 if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home/docker 下のファイルをバックアップします...${NC}" + echo -e "${gl_kjlan}/home/docker 下のファイルをバックアップします...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}/home/docker 下のファイルは次のようにパッケージ化されています。${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}バックアップが完了しました:${BACKUP_DIR}${NC}" - echo -e "${GREEN}利用可能な復元スクリプト:${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}バックアップが完了しました:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}利用可能な復元スクリプト:${RESTORE_SCRIPT}${gl_bai}" } @@ -7634,9 +7712,9 @@ docker_ssh_migration() { send_stats "Docker の復元" read -e -p "復元するバックアップ ディレクトリを入力してください:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } - echo -e "${BLUE}復元操作を開始しています...${NC}" + echo -e "${gl_kjlan}復元操作を開始しています...${gl_bai}" install tar jq gzip install_docker @@ -7653,7 +7731,7 @@ docker_ssh_migration() { # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${NC}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" continue fi @@ -7662,32 +7740,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}プロジェクトの作成 [$project_name] は次のように抽出されました。$original_path${NC}" + echo -e "${gl_lv}プロジェクトの作成 [$project_name] は次のように抽出されました。$original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}プロジェクトの作成 [$project_name】レストア完了!${NC}" + echo -e "${gl_lv}プロジェクトの作成 [$project_name】レストア完了!${gl_bai}" fi done # --------- 通常のコンテナの復元を続行 --------- - echo -e "${BLUE}通常の Docker コンテナを確認して復元します...${NC}" + echo -e "${gl_kjlan}通常の Docker コンテナを確認して復元します...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}処理容器:$container${NC}" + echo -e "${gl_lv}処理容器:$container${gl_bai}" # コンテナがすでに存在し、実行されているかどうかを確認します if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] すでに実行中のため、復元をスキップしています...${NC}" + echo -e "${gl_huang}容器 [$container] すでに実行中のため、復元をスキップしています...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}ミラー情報が見つかりません。スキップしてください:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}ミラー情報が見つかりません。スキップしてください:$container${gl_bai}"; continue; } # ポートマッピング PORT_ARGS="" @@ -7721,7 +7799,7 @@ docker_ssh_migration() { # 既存だが実行されていないコンテナを削除する if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] は存在しますが実行されていない場合は、古いコンテナを削除してください...${NC}" + echo -e "${gl_huang}容器 [$container] は存在しますが実行されていない場合は、古いコンテナを削除してください...${gl_bai}" docker rm -f "$container" fi @@ -7730,16 +7808,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}共通コンテナのバックアップ情報が見つかりません${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home/docker の下にファイルを復元しています...${NC}" + echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下のファイルが復元されました${NC}" + echo -e "${gl_lv}/home/docker 下のファイルが復元されました${gl_bai}" else - echo -e "${YELLOW}/home/docker の下にあるファイルのバックアップが見つかりませんでした。スキップしています...${NC}" + echo -e "${gl_huang}/home/docker の下にあるファイルのバックアップが見つかりませんでした。スキップしています...${gl_bai}" fi @@ -7753,7 +7831,7 @@ docker_ssh_migration() { send_stats "Docker の移行" install jq read -e -p "移行するバックアップ ディレクトリを入力してください:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } read -e -p "ターゲットサーバーIP:" TARGET_IP read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER @@ -7762,9 +7840,9 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}バックアップを転送中...${NC}" + echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7776,9 +7854,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Dockerバックアップファイルの削除" read -e -p "削除するバックアップ ディレクトリを入力してください:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}バックアップディレクトリが存在しません${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}削除されたバックアップ:${BACKUP_DIR}${NC}" + echo -e "${gl_lv}削除されたバックアップ:${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7808,7 +7886,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}無効なオプション${NC}" ;; + *) echo -e "${gl_hong}無効なオプション${gl_bai}" ;; esac break_end done @@ -8412,7 +8490,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -8544,16 +8621,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8586,14 +8663,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8624,14 +8701,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8671,15 +8749,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8723,14 +8803,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8781,15 +8864,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8823,15 +8908,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8862,14 +8948,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9000,13 +9086,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9040,12 +9128,14 @@ linux_ldnmp() { read -e -p "リバース プロキシ ドメイン名を入力してください:" fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9098,12 +9188,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9139,12 +9230,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9199,7 +9291,7 @@ linux_ldnmp() { send_stats "LDNMP環境のバックアップ" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}バックアップ中$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9297,7 +9389,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}解凍中$filename ...${gl_bai}" + echo -e "${gl_kjlan}解凍中$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9490,6 +9582,168 @@ linux_ldnmp() { + + + +moltbot_menu() { + local app_id="114" + + send_stats "Clawdbot/moltbot のインストール" + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}インストール済み${gl_bai}" + else + echo "${gl_hui}インストールされていません${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}ランニング${gl_bai}" + else + echo "${gl_hui}稼働していない${gl_bai}" + fi + } + + + show_menu() { + clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) + echo "=======================================" + echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "$install_status $running_status" + echo "=======================================" + echo "1. インストール" + echo "2.スタート" + echo "3. 停止" + echo "--------------------" + echo "4. ログの閲覧" + echo "5.機種変更" + echo "6. TGに接続コードを入力します" + echo "--------------------" + echo "7.アップデート" + echo "8. アンインストール" + echo "--------------------" + echo "0. 前のメニューに戻る" + echo "--------------------" + printf "オプションを入力して Enter を押してください:" + } + + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + sleep 3 + } + + + install_moltbot() { + echo "OpenClaw のインストールを開始します..." + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + pnpm config set registry https://registry.npmmirror.com + fi + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw + source ~/.bashrc + source ~/.profile + openclaw doctor --fix + openclaw onboard --install-daemon + openclaw gateway stop + start_tmux + add_app_id + break_end + + } + + + start_bot() { + echo "OpenClaw を開始しています..." + start_tmux + break_end + } + + stop_bot() { + echo "OpenClaw を停止します..." + install tmux + openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + break_end + } + + view_logs() { + echo "OpenClaw ログを表示し、Ctrl+C を押して終了します" + openclaw logs + break_end + } + + change_model() { + printf "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o):" + read model + echo "モデルを次のように切り替えます$model" + openclaw models set "$model" + break_end + } + + + change_tg_bot_code() { + printf "TG ロボットが受信した接続コードを入力してください (例: ペアリング コード: NYA99R2F:" + read code + openclaw pairing approve telegram $code + break_end + } + + update_moltbot() { + echo "OpenClaw を更新..." + openclaw update --restart + add_app_id + echo "アップデート完了" + break_end + } + + + uninstall_moltbot() { + echo "OpenClaw をアンインストールします..." + openclaw uninstall + npm uninstall -g openclaw + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + echo "アンインストールが完了しました" + break_end + } + + + # メインループ + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; + *) break ;; + esac + done + +} + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -9497,6 +9751,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}アプリケーションリストは更新中です。お待ちください...${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -9525,7 +9780,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -9590,7 +9845,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール${gl_kjlan}112. ${color112}Lucky 大規模イントラネット侵入ツール" - echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ" + echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ${gl_kjlan}114. ${color114}ClawdBot/Moltbot ロボット${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" echo -e "${gl_kjlan}あなたのアプリをここに表示したいですか?開発者ガイドを確認してください。${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -9755,7 +10010,7 @@ while true; do local docker_describe="gin と Solidjs を利用した、複数のストレージ、Web ブラウジング、WebDAV をサポートするファイル一覧プログラム" - local docker_url="公式サイト紹介:https://github.com/OpenListTeam/OpenList" + local docker_url="公式サイト紹介:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9824,7 +10079,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -10760,7 +11015,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -10862,25 +11117,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="マウスパネル" - local panelurl="正式な住所:${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanelオリジナルマウスパネル" + local panelurl="正式な住所:${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -10995,7 +11251,7 @@ while true; do } local docker_describe="Go を使用して実装された GHProxy は、一部の領域で Github リポジトリのプルを高速化するために使用されます。" - local docker_url="公式サイト紹介:https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="公式サイト紹介:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11060,7 +11316,7 @@ while true; do } local docker_describe="これは Prometheus ホスト データ収集コンポーネントです。監視対象ホストにデプロイしてください。" - local docker_url="公式サイト紹介:https://github.com/prometheus/node_exporter" + local docker_url="公式サイト紹介:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11090,7 +11346,7 @@ while true; do } local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" - local docker_url="公式サイト紹介:https://github.com/google/cadvisor" + local docker_url="公式サイト紹介:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11113,7 +11369,7 @@ while true; do } local docker_describe="これは、Web サイトの変更の検出、補充の監視、通知を行うための小さなツールです。" - local docker_url="公式サイト紹介:https://github.com/dgtlmoon/changedetection.io" + local docker_url="公式サイト紹介:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11146,7 +11402,7 @@ while true; do } local docker_describe="Docker ビジュアル パネル システムは、完全な Docker 管理機能を提供します。" - local docker_url="公式サイト紹介:https://github.com/donknap/dpanel" + local docker_url="公式サイト紹介:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11166,7 +11422,7 @@ while true; do } local docker_describe="OpenWebUI は、新しい llama3 ラージ言語モデルに接続されているラージ言語モデル Web ページ フレームワークです。" - local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" + local docker_url="公式サイト紹介:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11218,7 +11474,7 @@ while true; do } local docker_describe="OpenWebUI は、新しい DeepSeek R1 大規模言語モデルに接続されている大規模言語モデル Web ページ フレームワークです。" - local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" + local docker_url="公式サイト紹介:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11274,7 +11530,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="新世代の大型モデルゲートウェイとAI資産管理システム" - local app_url="公式サイト:https://github.com/Calcium-Ion/new-api" + local app_url="公式ウェブサイト:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11328,7 +11584,7 @@ while true; do local app_id="60" local app_name="JumpServer オープンソース要塞マシン" local app_text="これは、オープンソースの特権アクセス管理 (PAM) ツールです。このプログラムはポート 80 を占有しているため、アクセス用のドメイン名の追加はサポートされていません。" - local app_url="公式紹介: https://github.com/jumpserver/jumpserver" + local app_url="公式紹介:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11379,7 +11635,7 @@ while true; do } local docker_describe="無料のオープンソース機械翻訳 API は完全に自己ホストされており、その翻訳エンジンはオープンソースの Argos Translate ライブラリを利用しています。" - local docker_url="公式サイト紹介:https://github.com/LibreTranslate/LibreTranslate" + local docker_url="公式サイト紹介:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11392,7 +11648,7 @@ while true; do local app_id="62" local app_name="RAGFlow ナレッジベース" local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" - local app_url="公式サイト:https://github.com/infiniflow/ragflow" + local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11440,7 +11696,7 @@ while true; do } local docker_describe="OpenWebUI は大規模な言語モデルの Web ページ フレームワークであり、公式の簡易バージョンではすべての主要モデルへの API アクセスがサポートされています。" - local docker_url="公式サイト紹介:https://github.com/open-webui/open-webui" + local docker_url="公式サイト紹介:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11458,7 +11714,7 @@ while true; do } local docker_describe="開発者と IT ワーカーにとって非常に便利なツール" - local docker_url="公式サイト紹介:https://github.com/CorentinTh/it-tools" + local docker_url="公式サイト紹介:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11494,7 +11750,7 @@ while true; do } local docker_describe="強力な自動ワークフロー プラットフォームです" - local docker_url="公式サイト紹介:https://github.com/n8n-io/n8n" + local docker_url="公式サイト紹介:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11523,7 +11779,7 @@ while true; do } local docker_describe="パブリック IP (IPv4/IPv6) を主要な DNS サービス プロバイダーにリアルタイムで自動的に更新し、動的なドメイン名解決を実現します。" - local docker_url="公式サイト紹介:https://github.com/jeessy2/ddns-go" + local docker_url="公式サイト紹介:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11693,7 +11949,7 @@ while true; do } local docker_describe="無料のオンラインビデオ検索および視聴プラットフォーム" - local docker_url="公式サイト紹介:https://github.com/LibreSpark/LibreTV" + local docker_url="公式サイト紹介:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11709,7 +11965,7 @@ while true; do local app_name="MoonTV プライベート映画とテレビ" local app_text="無料のオンラインビデオ検索および視聴プラットフォーム" - local app_url="ビデオ紹介: https://github.com/MoonTechLab/LunaTV" + local app_url="ビデオの紹介:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11775,7 +12031,7 @@ while true; do } local docker_describe="音楽をより適切に管理できるように設計された音楽ウィザード。" - local docker_url="公式サイト紹介:https://github.com/foamzou/melody" + local docker_url="公式サイト紹介:${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11802,7 +12058,7 @@ while true; do } local docker_describe="中華DOSゲームまとめサイトです" - local docker_url="公式サイト紹介:https://github.com/rwv/chinese-dos-games" + local docker_url="公式サイト紹介:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11837,7 +12093,7 @@ while true; do } local docker_describe="Xunlei、オフライン高速 BT 磁気ダウンロード ツール" - local docker_url="公式サイト紹介:https://github.com/cnk3x/xunlei" + local docker_url="公式サイト紹介:${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"携帯電話で Xunlei にログインし、招待コードを入力してください。招待コード: Xunlei Niutong\"" local docker_passwd="" local app_size="1" @@ -11852,7 +12108,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki は、AI 大型モデルによって駆動されるオープンソースのインテリジェントな文書管理システムです。ポートの展開をカスタマイズしないことを強くお勧めします。" - local app_url="公式紹介: https://github.com/chaitin/PandaWiki" + local app_url="公式紹介:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -11908,7 +12164,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12081,7 +12337,7 @@ while true; do } local docker_describe="軽量のセルフホスト型サーバー監視ツール" - local docker_url="公式サイト紹介:https://github.com/komari-monitor/komari/tree/main" + local docker_url="公式サイト紹介:${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"デフォルトのアカウント: admin デフォルトのパスワード: 1212156\"" local docker_passwd="" local app_size="1" @@ -12112,7 +12368,7 @@ while true; do } local docker_describe="財務管理用のオープンソースの個人サブスクリプション トラッカー" - local docker_url="公式サイト紹介:https://github.com/ellite/Wallos" + local docker_url="公式サイト紹介:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12125,7 +12381,7 @@ while true; do local app_id="85" local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" - local app_url="公式サイト紹介:https://github.com/immich-app/immich" + local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12218,7 +12474,7 @@ while true; do } local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" - local docker_url="公式サイト紹介:https://github.com/synctv-org/synctv" + local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" local app_size="1" @@ -12277,7 +12533,7 @@ while true; do } local docker_describe="匿名のパスワードでテキストやファイルを共有し、速達のようにファイルを受け取ります" - local docker_url="公式サイト紹介:https://github.com/vastsa/FileCodeBox" + local docker_url="公式サイト紹介:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /#/admin を続けます\"" local docker_passwd="echo \"管理者パスワード: FileCodeBox2023\"" local app_size="1" @@ -12349,7 +12605,7 @@ while true; do local app_name="gitea プライベート コード リポジトリ" local app_text="GitHub に近いエクスペリエンスを提供する、無料の新世代コード ホスティング プラットフォーム。" - local app_url="ビデオ紹介: https://github.com/go-gitea/gitea" + local app_url="ビデオの紹介:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12439,7 +12695,7 @@ while true; do } local docker_describe="シンプルな静的ファイル サーバー、アップロードとダウンロードをサポート" - local docker_url="公式サイト紹介:https://github.com/sigoden/dufs" + local docker_url="公式サイト紹介:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12470,7 +12726,7 @@ while true; do } local docker_describe="複数のプロトコルをサポートする分散型高速ダウンロード ツール" - local docker_url="公式サイト紹介:https://github.com/GopeedLab/gopeed" + local docker_url="公式サイト紹介:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12534,7 +12790,7 @@ while true; do local app_name="2FAuth セルフホスト型 2 段階認証システム" local app_text="セルフホスト型の 2 要素認証 (2FA) アカウント管理および検証コード生成ツール。" - local app_url="公式サイト:https://github.com/Bubka/2FAuth" + local app_url="公式ウェブサイト:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12765,7 +13021,7 @@ while true; do local app_name="DSM Synology 仮想マシン" local app_text="Dockerコンテナ内の仮想DSM" - local app_url="公式ウェブサイト:https://github.com/vdsm/virtual-dsm" + local app_url="公式ウェブサイト:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12836,7 +13092,7 @@ while true; do } local docker_describe="オープンソースのピアツーピア ファイル同期ツール。Dropbox や Resilio Sync に似ていますが、完全に分散化されています。" - local docker_url="公式サイト紹介:https://github.com/syncthing/syncthing" + local docker_url="公式サイト紹介:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12849,7 +13105,7 @@ while true; do local app_id="101" local app_name="AI動画生成ツール" local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" - local app_url="公式ウェブサイト:https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12904,7 +13160,7 @@ while true; do } local docker_describe="独自導入をサポートするパーソナルクラウドソーシャルメディアチャットサービスです。" - local docker_url="公式サイト紹介:https://github.com/Privoce/vocechat-web" + local docker_url="公式サイト紹介:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12917,7 +13173,7 @@ while true; do local app_id="103" local app_name="Umami ウェブサイト統計ツール" local app_text="Google Analytics に似た、オープンソースの軽量でプライバシーに配慮した Web サイト分析ツール。" - local app_url="公式サイト:https://github.com/umami-software/umami" + local app_url="公式ウェブサイト:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12983,7 +13239,7 @@ while true; do } local docker_describe="Siyuan Notes はプライバシーを最優先したナレッジ管理システムです" - local docker_url="公式サイト紹介:https://github.com/siyuan-note/siyuan" + local docker_url="公式サイト紹介:${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13010,7 +13266,7 @@ while true; do } local docker_describe="これは、マインド マップ、フローチャートなどを統合する強力なオープンソース ホワイトボード ツールです。" - local docker_url="公式サイト紹介:https://github.com/plait-board/drawnix" + local docker_url="公式サイト紹介:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13045,7 +13301,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou は、高パフォーマンスのネットワーク ディスク リソース検索 API サービスです。" - local docker_url="公式サイト紹介:https://github.com/fish2018/pansou" + local docker_url="公式サイト紹介:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13060,7 +13316,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot チャットボット" local app_text="これは、オープンソースの大規模言語モデルのネイティブ インスタント メッセージング ロボット開発プラットフォームです。" - local app_url="公式ウェブサイト:https://github.com/langbot-app/LangBot" + local app_url="公式ウェブサイト:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13117,7 +13373,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="これは、個人または小規模チームに適したオンライン ネットワーク ディスク プログラムです。" - local docker_url="公式サイト紹介:https://github.com/zfile-dev/zfile" + local docker_url="公式サイト紹介:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13130,7 +13386,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeepのブックマーク管理" local app_text="は、データ蓄積者向けに設計された人工知能機能を備えた自己ホスト型ブックマーク アプリです。" - local app_url="公式サイト:https://github.com/karakeep-app/karakeep" + local app_url="公式ウェブサイト:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13182,8 +13438,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" - local docker_url="プロジェクトアドレス: https://github.com/c4illin/ConvertX" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13215,7 +13471,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky は、DDNS、リバース プロキシ、WOL、その他の機能をサポートする大規模なイントラネット ペネトレーションおよびポート フォワーディング管理ツールです。" - local docker_url="プロジェクトアドレス: https://github.com/gdy666/lucky" + local docker_url="プロジェクトアドレス:${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"デフォルトのアカウントパスワード: 666\"" local docker_passwd="" local app_size="1" @@ -13245,7 +13501,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="これは、Web ページを介したデスクトップ ブラウザ インターフェイスへの直接アクセスをサポートする、Docker で実行される Firefox ブラウザです。" - local docker_url="プロジェクトアドレス: https://github.com/jlesage/docker-firefox" + local docker_url="プロジェクトアドレス:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13253,13 +13509,17 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) + moltbot_menu + ;; + b) clear send_stats "すべてのアプリケーションのバックアップ" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}バックアップ中$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}バックアップ中$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13316,7 +13576,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}解凍中$filename ...${gl_bai}" + echo -e "${gl_kjlan}解凍中$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "アプリケーションデータが復元されました。現在、アプリケーションを復元するには、手動で指定されたアプリケーションメニューに入り、アプリケーションを更新してください。" else @@ -13563,20 +13823,33 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "公式ミラーソースを使用してください..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel true \ - --pure-mode + echo "海外のミラーソースを使用..." + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } @@ -13636,6 +13909,378 @@ fail2ban_panel() { +net_menu() { + + send_stats "ネットワークカード管理ツール" + show_nics() { + echo "================ 現在のネットワークカード情報 ================" + printf "%-18s %-12s %-20s %-26s\n" "ネットワークカード名" "州" "IPアドレス" "MACアドレス" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== ネットワークカード管理メニュー ===========" + echo "1.ネットワークカードを有効にする" + echo "2.ネットワークカードを無効にする" + echo "3. ネットワークカードの詳細を表示する" + echo "4. ネットワークカード情報を更新する" + echo "0. 前のメニューに戻る" + echo "====================================" + read -rp "アクションを選択してください:" choice + + case $choice in + 1) + send_stats "ネットワークカードを有効にする" + read -rp "有効にするネットワーク カードの名前を入力してください:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ ネットワークカード$nic有効" + else + echo "✘ ネットワークカードが存在しません" + fi + read -rp "続行するには Enter キーを押してください..." + ;; + 2) + send_stats "ネットワークカードを無効にする" + read -rp "無効にするネットワーク カードの名前を入力してください:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ ネットワークカード$nic無効" + else + echo "✘ ネットワークカードが存在しません" + fi + read -rp "続行するには Enter キーを押してください..." + ;; + 3) + send_stats "ネットワークカードの詳細を表示する" + read -rp "表示したいネットワーク カードの名前を入力してください:" nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nic詳細 ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ ネットワークカードが存在しません" + fi + read -rp "続行するには Enter キーを押してください..." + ;; + 4) + send_stats "ネットワークカード情報を更新する" + continue + ;; + *) + break + ;; + esac + done +} + + + +log_menu() { + send_stats "システムログ管理ツール" + + show_log_overview() { + echo "============= システムログの概要 =============" + echo "ホスト名: $(ホスト名)" + echo "システム時間: $(日付)" + echo + echo "[/var/logディレクトリ占有]" + du -sh /var/log 2>/dev/null + echo + echo "【日記ログ職業】" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== システムログ管理メニュー ===========" + echo "1. 最新のシステムログ(ジャーナル)を表示する" + echo "2. 指定したサービスログを表示します。" + echo "3. ログイン/セキュリティログの表示" + echo "4. リアルタイム追跡ログ" + echo "5. 古いジャーナル ログをクリーンアップする" + echo "0. 前のメニューに戻る" + echo "=======================================" + read -rp "アクションを選択してください:" choice + + case $choice in + 1) + send_stats "最近のログを表示する" + read -rp "最新のログ行を表示しますか? [デフォルト 100]:" lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "続行するには Enter キーを押してください..." + ;; + 2) + send_stats "指定したサービスログを表示する" + read -rp "サービス名 (sshd、nginx など) を入力してください:" svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ サービスが存在しないか、ログがありません" + fi + read -rp "続行するには Enter キーを押してください..." + ;; + 3) + send_stats "ログイン/セキュリティログの表示" + echo "====== 最近のログインログ ======" + last -n 10 + echo + echo "====== 認証ログ ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "セキュリティログファイルが見つかりません" + fi + read -rp "続行するには Enter キーを押してください..." + ;; + 4) + send_stats "リアルタイム追跡ログ" + echo "1) システムログ" + echo "2) サービスログの指定" + read -rp "追跡タイプを選択します:" t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "サービス名を入力してください:" svc + journalctl -u "$svc" -f + else + echo "無効な選択" + fi + ;; + 5) + send_stats "古いジャーナル ログをクリーンアップする" + echo "⚠️ ジャーナルをクリーンアップします (安全な方法)" + echo "1) 過去 7 日間を保存します" + echo "2) 過去 3 日間を保存します" + echo "3) 最大ログ サイズを 500M に制限する" + read -rp "クリーニング方法を選択してください:" c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "無効なオプション" ;; + esac + echo "✔ ジャーナルログのクリーニングが完了しました" + sleep 2 + ;; + *) + break + ;; + esac + done +} + + + +env_menu() { + + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "システム変数管理ツール" + + show_env_vars() { + clear + send_stats "現在有効な環境変数" + echo "========== 現在有効な環境変数(抜粋) ==========" + printf "%-20s %s\n" "変数名" "価値" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== 設定ファイルに定義されている変数 (解析) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> ソースファイル:$file" + echo "-----------------------------------------------" + + # 抽出エクスポート VAR=xxx または VAR=xxx + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "続行するには Enter キーを押してください..." + } + + + view_file() { + local file="$1" + send_stats "変数ファイルを表示する$file" + clear + if [ -f "$file" ]; then + echo "========== ファイルを表示:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "ファイルが存在しません:$file" + fi + read -rp "続行するには Enter キーを押してください..." + } + + edit_file() { + local file="$1" + send_stats "変数ファイルを編集する$file" + install nano + nano "$file" + } + + source_files() { + echo "環境変数を再ロードしています..." + send_stats "環境変数の再読み込み" + source "$BASHRC" + source "$PROFILE" + echo "✔ 環境変数がリロードされました" + read -rp "続行するには Enter キーを押してください..." + } + + while true; do + clear + echo "=========== システム環境変数の管理 ==========" + echo "現在のユーザー:$USER" + echo "--------------------------------------" + echo "1. 現在一般的に使用されている環境変数を確認します。" + echo "2. ~/.bashrc を表示する" + echo "3. ~/.profile を表示する" + echo "4. ~/.bashrc を編集する" + echo "5. ~/.profile を編集する" + echo "6. 環境変数(ソース)をリロードします。" + echo "--------------------------------------" + echo "0. 前のメニューに戻る" + echo "--------------------------------------" + read -rp "アクションを選択してください:" choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "無効なオプション" + sleep 1 + ;; + esac + done +} + + +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "使用法: create_user_with_sshkey <ユーザー名>" + return 1 + fi + + # ユーザーの作成 + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "公開鍵をインポートする例:" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" + echo "- 直接貼り付けます: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "輸入してください${new_username}公開鍵:" sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "URLからSSH公開キーをインポート" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "公開鍵を直接インポートする" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "エラー: 不明なパラメータ '$sshkey_vl'" + return 1 + ;; + esac + + + # 権限を修正する + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo パスワード不要 + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" <> /etc/ssh/sshd_config + passwd -l "$new_username" &>/dev/null + restart_ssh + + echo "ユーザー$new_username作成完了" +} + + + + + + + + + + + + + linux_Settings() { @@ -13646,7 +14291,7 @@ linux_Settings() { echo -e "システムツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" - echo -e "${gl_kjlan}3. ${gl_bai}ROOTパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" + echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" @@ -13658,7 +14303,7 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}システムアップデート元の切り替え${gl_kjlan}20. ${gl_bai}スケジュールされたタスクの管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト解像度${gl_kjlan}22. ${gl_bai}SSH防御プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限自動シャットダウン${gl_kjlan}24. ${gl_bai}ROOT秘密鍵ログインモード" + echo -e "${gl_kjlan}23. ${gl_bai}電流制限自動シャットダウン${gl_kjlan}24. ${gl_bai}ユーザーキーログインモード" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot システムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSH の高リスク脆弱性を修正" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux カーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムのカーネルパラメータの最適化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" @@ -13667,9 +14312,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}システムのごみ箱をセットアップする${gl_kjlan}34. ${gl_bai}システムのバックアップとリカバリ" echo -e "${gl_kjlan}35. ${gl_bai}SSHリモート接続ツール${gl_kjlan}36. ${gl_bai}ハードディスクパーティション管理ツール" echo -e "${gl_kjlan}37. ${gl_bai}コマンドラインの履歴${gl_kjlan}38. ${gl_bai}rsync リモート同期ツール" - echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}コマンドのお気に入り${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}ネットワークカード管理ツール" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップのシステムチューニング${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}システムログ管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}システム変数管理ツール" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}61. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップのシステムチューニング${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" echo -e "${gl_kjlan}101. ${gl_bai}k コマンドの高度な使用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Tech Lion スクリプトをアンインストールする" echo -e "${gl_kjlan}------------------------" @@ -13687,7 +14334,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "ショートカットキーが設定されている" send_stats "スクリプトのショートカットキーが設定されました" break_end @@ -13702,8 +14352,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "rootパスワードモード" + clear add_sshpasswd ;; @@ -13860,16 +14509,13 @@ EOF linux_Settings fi - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + create_user_with_sshkey $new_username true - install sudo + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - passwd -l root - - echo "操作は完了です。" ;; @@ -13983,7 +14629,12 @@ EOF printf "%-24s %-34s %-20s %-10s\n" "ユーザー名" "ユーザー権限" "ユーザーグループ" "sudo 権限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) - local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -13991,7 +14642,7 @@ EOF echo "" echo "アカウント操作" echo "------------------------" - echo "1. 通常アカウントを作成する 2. プレミアムアカウントを作成する" + echo "1. 通常ユーザーを作成します。 2. 上級ユーザーを作成します。" echo "------------------------" echo "3. 最高の権限を付与する 4. 最高の権限を削除する" echo "------------------------" @@ -14005,46 +14656,34 @@ EOF 1) # ユーザーに新しいユーザー名の入力を求める read -e -p "新しいユーザー名を入力してください:" new_username + create_user_with_sshkey $new_username false - # 新しいユーザーを作成してパスワードを設定する - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - echo "操作は完了です。" ;; 2) # ユーザーに新しいユーザー名の入力を求める read -e -p "新しいユーザー名を入力してください:" new_username - - # 新しいユーザーを作成してパスワードを設定する - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - # 新しいユーザーに sudo 権限を付与します - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "操作は完了です。" + create_user_with_sshkey $new_username true ;; 3) read -e -p "ユーザー名を入力してください:" username - # 新しいユーザーに sudo 権限を付与します - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "削除するユーザー名を入力してください:" username - # ユーザーとそのホームディレクトリを削除する userdel -r "$username" ;; @@ -14052,6 +14691,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; @@ -14131,7 +14771,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -14580,7 +15220,23 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 42) + clear + env_menu + ;; + + + 61) clear send_stats "掲示板" echo "Technology Lion の公式掲示板をご覧ください。脚本についてのアイデアがあれば、メッセージを残して交換してください。" @@ -14595,7 +15251,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -15015,7 +15671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15182,7 +15838,7 @@ echo -e "${gl_kjlan}ステーションB:${gl_bai}https://b23.tv/2mqnQyh echo -e "${gl_kjlan}公式ウェブサイト:${gl_bai}https://kejilion.pro/ ${gl_kjlan}ナビゲーション:${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}ブログ:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}ソフトウェアセンター:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}スクリプト公式サイト:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub アドレス:${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}スクリプト公式サイト:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub アドレス:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -15405,7 +16061,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -15645,7 +16301,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) @@ -15695,30 +16351,27 @@ else sshkey) - shift + + shift case "$1" in "" ) # sshkey → インタラクティブメニュー send_stats "SSHKey 対話型メニュー" sshkey_panel ;; - github ) shift send_stats "GitHub から SSH 公開キーをインポートする" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "URLからSSH公開キーをインポート" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "公開鍵を直接インポートする" import_sshkey "$1" ;; - * ) echo "エラー: 不明なパラメータ '$1'" echo "使用法:" @@ -15728,11 +16381,10 @@ else echo "k sshkey github GitHub から SSH 公開キーをインポートします" ;; esac + ;; *) k_info ;; esac fi - - diff --git a/kr/kejilion.sh b/kr/kejilion.sh index ae628f13c..40943cc48 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.7" gl_hui='\e[37m' @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -59,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -102,6 +104,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -176,7 +179,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}설치 중$package...${gl_bai}" + echo -e "${gl_kjlan}설치 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -251,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}제거 중$package...${gl_bai}" + echo -e "${gl_kjlan}제거 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -448,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}도커 환경 설치 중...${gl_bai}" + echo -e "${gl_kjlan}도커 환경 설치 중...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -627,7 +630,7 @@ while true; do send_stats "이미지 가져오기" read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_huang}이미지 가져오기:$name${gl_bai}" + echo -e "${gl_kjlan}이미지 가져오기:$name${gl_bai}" docker pull $name done ;; @@ -635,7 +638,7 @@ while true; do send_stats "이미지 업데이트" read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_huang}이미지 업데이트 중:$name${gl_bai}" + echo -e "${gl_kjlan}이미지 업데이트 중:$name${gl_bai}" docker pull $name done ;; @@ -1090,7 +1093,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1197,7 +1200,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1259,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1442,10 +1445,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1543,7 +1542,7 @@ certs_status() { echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" - echo "1. 다시 적용 2. 기존 인증서 가져오기 3. 인증서 없이 HTTP 액세스 사용 0. 종료" + echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -1600,18 +1599,9 @@ certs_status() { echo "오류: 잘못된 인증서 또는 개인 키 형식입니다!" certs_status fi - - ;; - 3) - send_stats "인증서 없이 HTTP 액세스로 전환" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - send_stats "신청철회" - rm -f /home/web/conf.d/${yuming}.conf - exit + exit ;; esac fi @@ -2146,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -2328,7 +2318,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2677,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2696,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2897,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3020,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3351,7 +3341,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3364,7 +3354,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3391,14 +3381,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3438,7 +3430,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3447,6 +3439,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3465,9 +3461,6 @@ ldnmp_Proxy() { sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3495,6 +3488,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3511,8 +3507,6 @@ ldnmp_Proxy_backend() { sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -3652,7 +3646,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3700,7 +3694,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4033,7 +4027,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4095,7 +4089,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4274,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP 서버$check_frp $update_status" echo "FRP 인트라넷 침투 서비스 환경을 구축하고 공인 IP가 없는 장치를 인터넷에 노출시킵니다." - echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" + echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4372,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." - echo "공식 홈페이지 소개: https://github.com/fatedier/frp/" + echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4465,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp는 YouTube, Bilibili, Twitter 등과 같은 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." - echo -e "공식 홈페이지 주소: https://github.com/yt-dlp/yt-dlp" + echo -e "공식 웹사이트 주소:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "다운로드한 동영상 목록:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" @@ -4484,7 +4478,7 @@ yt_menu_pro() { send_stats "yt-dlp 설치 중..." echo "yt-dlp 설치 중..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -4600,7 +4594,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}시스템 업데이트 진행 중...${gl_bai}" + echo -e "${gl_kjlan}시스템 업데이트 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4627,7 +4621,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}시스템 청소 진행 중...${gl_bai}" + echo -e "${gl_kjlan}시스템 청소 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4807,39 +4801,30 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 발견된 경우 PasswordAuthentication이 yes로 설정되어 있습니다. - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # 발견된 경우 PubkeyAuthentication이 yes로 설정되어 있습니다. - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # PasswordAuthentication과 PubkeyAuthentication이 모두 일치하지 않는 경우 기본값을 설정합니다. - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # SSH 구성 파일 백업 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4852,21 +4837,8 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "개인키 정보가 생성되었습니다. 꼭 복사해서 저장하세요. 다음과 같이 저장될 수 있습니다.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인을 위한 파일" - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4874,17 +4846,43 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT 개인키 로그인이 활성화되어 있고, ROOT 비밀번호 로그인이 비활성화되어 재접속이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}사용자 키 로그인 모드가 켜져 있고 비밀번호 로그인 모드가 꺼졌습니다. 다시 연결이 적용됩니다.${gl_bai}" } +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "개인키 정보가 생성되었습니다. 꼭 복사해서 저장하세요. 다음과 같이 저장될 수 있습니다.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인을 위한 파일" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on +} + + + import_sshkey() { local public_key="$1" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key @@ -4896,38 +4894,32 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 - fi + fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "공개 키가 이미 존재하므로 다시 추가할 필요가 없습니다." return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}공개 키를 성공적으로 가져왔고 ROOT 개인 키 로그인이 활성화되었으며 ROOT 비밀번호 로그인이 종료되었습니다. 다시 연결이 적용됩니다.${gl_bai}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4969,15 +4961,15 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 원래 인증된_키 백업 + # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원본 Authorized_keys 파일이 백업되었습니다." + echo "원래 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -4996,13 +4988,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then echo "성공적으로 추가되었습니다${added}새로운 공개 키가 도착합니다${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "새로운 공개 키를 추가할 필요가 없습니다(모두 이미 존재할 수도 있음)." fi @@ -5012,19 +4998,21 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "계속하기 전에 SSH 공개 키를 GitHub 계정에 추가했는지 확인하세요." - echo "1. https://github.com/settings/keys에 로그인하세요." + echo "1. 로그인${gh_https_url}github.com/settings/keys" echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." echo "" echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." - echo "https://github.com/yourusername.keys" + echo " ${gh_https_url}github.com/yourusername.keys" echo "" @@ -5037,19 +5025,16 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } - - sshkey_panel() { - root_use - send_stats "개인키 로그인" + send_stats "사용자 키 로그인" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5058,8 +5043,8 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}활성화되지 않음${gl_bai}" fi - echo -e "ROOT 개인 키 로그인 모드${IS_KEY_ENABLED}" - echo "영상 소개: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" + echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" @@ -5096,7 +5081,7 @@ sshkey_panel() { 5) send_stats "공개 키 파일 편집" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5104,10 +5089,10 @@ sshkey_panel() { send_stats "로컬 키 보기" echo "------------------------" echo "공개키 정보" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "개인 키 정보" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5125,20 +5110,55 @@ sshkey_panel() { - add_sshpasswd() { -echo "루트 비밀번호를 설정하세요" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOT 로그인 설정이 완료되었습니다!${gl_bai}" + root_use + send_stats "비밀번호 로그인 모드 설정" + echo "비밀번호 로그인 모드 설정" + + local target_user="$1" + + # 매개변수가 전달되지 않으면 대화형으로 입력하세요. + if [[ -z "$target_user" ]]; then + read -e -p "비밀번호를 변경하려는 사용자 이름을 입력하십시오(기본 루트):" target_user + fi + + # Enter를 누르고 입력하지 마십시오. 기본값은 root입니다. + target_user=${target_user:-root} + + # 사용자가 존재하는지 확인 + if ! id "$target_user" >/dev/null 2>&1; then + echo "오류: 사용자$target_user존재하지 않는다" + return 1 + fi + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + + echo -e "${gl_lv}비밀번호가 설정되어 비밀번호 로그인 모드로 변경되었습니다!${gl_bai}" } + + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능을 실행하려면 루트 사용자가 필요합니다!" && break_end && kejilion @@ -5146,6 +5166,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "시스템 재설치" dd_xitong_MollyLau() { @@ -5194,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." echo -e "${gl_hui}스크립트 지원을 해주신 bin456789 보스와 leitbogioro 보스에게 감사드립니다!${gl_bai} " - echo -e "${gl_hui}bin456789 프로젝트 주소: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro 프로젝트 주소: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789 프로젝트 주소:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro 프로젝트 주소:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5690,7 +5719,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5716,7 +5745,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}바이러스 데이터베이스 업데이트 중...${gl_bai}" + echo -e "${gl_kjlan}바이러스 데이터베이스 업데이트 중...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5730,7 +5759,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}$@ 디렉터리를 검색하는 중...${gl_bai}" + echo -e "${gl_kjlan}$@ 디렉터리를 검색하는 중...${gl_bai}" # 마운트 매개변수 빌드 local MOUNT_PARAMS="" @@ -6025,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -6232,7 +6261,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6753,7 +6782,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6960,7 +6989,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -7073,7 +7102,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}시스템 정보를 쿼리하는 중...${gl_bai}" send_stats "시스템 정보 쿼리" ip_address @@ -7177,6 +7209,58 @@ linux_tools() { clear # send_stats "기본 도구" echo -e "기본 도구" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ 인식할 수 없는 패키지 관리자" + exit 1 + fi + + echo "📦 패키지 관리자를 사용하세요:$PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # 왼쪽 열 + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s 설치됨" "${tools[i]}") + else + left=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i]}") + fi + + # 오른쪽 열(배열이 범위를 벗어나는 것을 방지하기 위해) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s 설치됨" "${tools[i+1]}") + else + right=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 다운로드 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo 최고 관리 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" @@ -7496,12 +7580,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7509,7 +7587,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}현재 백업 목록:${NC}" + echo -e "${gl_kjlan}현재 백업 목록:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" } @@ -7521,7 +7599,7 @@ docker_ssh_migration() { backup_docker() { send_stats "도커 백업" - echo -e "${YELLOW}Docker 컨테이너 백업 중...${NC}" + echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers @@ -7536,7 +7614,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}컨테이너를 찾을 수 없습니다.${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}컨테이너를 찾을 수 없습니다.${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7550,12 +7628,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}백업 컨테이너:$c${NC}" + echo -e "${gl_lv}백업 컨테이너:$c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}감지됨$c도커 작성 컨테이너입니다${NC}" + echo -e "${gl_kjlan}감지됨$c도커 작성 컨테이너입니다${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7565,7 +7643,7 @@ docker_ssh_migration() { # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${NC}" + echo -e "${gl_huang}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${gl_bai}" continue fi @@ -7576,9 +7654,9 @@ docker_ssh_migration() { echo "# docker-compose 복원:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}프로젝트 작성 [$project_name] 포장:${project_dir}${NC}" + echo -e "${gl_lv}프로젝트 작성 [$project_name] 포장:${project_dir}${gl_bai}" else - echo -e "${RED}docker-compose.yml을 찾을 수 없습니다. 이 컨테이너를 건너뛰는 중입니다...${NC}" + echo -e "${gl_hong}docker-compose.yml을 찾을 수 없습니다. 이 컨테이너를 건너뛰는 중입니다...${gl_bai}" fi else # 일반 컨테이너 백업 볼륨 @@ -7615,14 +7693,14 @@ docker_ssh_migration() { # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then - echo -e "${BLUE}/home/docker 아래의 파일을 백업합니다...${NC}" + echo -e "${gl_kjlan}/home/docker 아래의 파일을 백업합니다...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}백업 완료:${BACKUP_DIR}${NC}" - echo -e "${GREEN}사용 가능한 복원 스크립트:${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}백업 완료:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}사용 가능한 복원 스크립트:${RESTORE_SCRIPT}${gl_bai}" } @@ -7634,9 +7712,9 @@ docker_ssh_migration() { send_stats "도커 복원" read -e -p "복원할 백업 디렉터리를 입력하십시오:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } - echo -e "${BLUE}복원 작업을 시작하는 중...${NC}" + echo -e "${gl_kjlan}복원 작업을 시작하는 중...${gl_bai}" install tar jq gzip install_docker @@ -7653,7 +7731,7 @@ docker_ssh_migration() { # Compose 프로젝트의 컨테이너가 이미 실행 중인지 확인하세요. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}프로젝트 작성 [$project_name] 컨테이너가 이미 실행 중입니다. 복원을 건너뛰세요...${NC}" + echo -e "${gl_huang}프로젝트 작성 [$project_name] 컨테이너가 이미 실행 중입니다. 복원을 건너뛰세요...${gl_bai}" continue fi @@ -7662,32 +7740,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${NC}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}프로젝트 작성 [$project_name] 복원 완료!${NC}" + echo -e "${gl_lv}프로젝트 작성 [$project_name] 복원 완료!${gl_bai}" fi done # --------- 일반 컨테이너를 계속 복원합니다 --------- - echo -e "${BLUE}일반 Docker 컨테이너 확인 및 복원...${NC}" + echo -e "${gl_kjlan}일반 Docker 컨테이너 확인 및 복원...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}처리 용기:$container${NC}" + echo -e "${gl_lv}처리용기:$container${gl_bai}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${NC}" + echo -e "${gl_huang}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}미러 정보를 찾을 수 없습니다. 건너뛰세요:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}미러 정보를 찾을 수 없습니다. 건너뛰세요:$container${gl_bai}"; continue; } # 포트 매핑 PORT_ARGS="" @@ -7721,7 +7799,7 @@ docker_ssh_migration() { # 기존이지만 실행되지 않는 컨테이너 삭제 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${NC}" + echo -e "${gl_huang}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${gl_bai}" docker rm -f "$container" fi @@ -7730,16 +7808,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}공통 컨테이너에 대한 백업 정보가 없습니다.${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}공통 컨테이너에 대한 백업 정보가 없습니다.${gl_bai}" # /home/docker 아래의 파일 복원 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}/home/docker 아래의 파일을 복원하는 중...${NC}" + echo -e "${gl_kjlan}/home/docker 아래의 파일을 복원하는 중...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 아래의 파일이 복원되었습니다.${NC}" + echo -e "${gl_lv}/home/docker 아래의 파일이 복원되었습니다.${gl_bai}" else - echo -e "${YELLOW}/home/docker 아래의 파일 백업을 찾을 수 없습니다. 건너뛰는 중...${NC}" + echo -e "${gl_huang}/home/docker 아래의 파일 백업을 찾을 수 없습니다. 건너뛰는 중...${gl_bai}" fi @@ -7753,7 +7831,7 @@ docker_ssh_migration() { send_stats "도커 마이그레이션" install jq read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } read -e -p "대상 서버 IP:" TARGET_IP read -e -p "대상 서버 SSH 사용자 이름:" TARGET_USER @@ -7762,9 +7840,9 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}백업 전송 중...${NC}" + echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7776,9 +7854,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker 백업 파일 삭제" read -e -p "삭제할 백업 디렉터리를 입력하십시오:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}백업 디렉터리가 존재하지 않습니다.${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}삭제된 백업:${BACKUP_DIR}${NC}" + echo -e "${gl_lv}삭제된 백업:${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7797,7 +7875,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -7808,7 +7886,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}잘못된 옵션${NC}" ;; + *) echo -e "${gl_hong}잘못된 옵션${gl_bai}" ;; esac break_end done @@ -7951,7 +8029,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -7997,7 +8075,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8312,7 +8390,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8412,7 +8490,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -8544,16 +8621,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8586,14 +8663,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8624,14 +8701,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8671,15 +8749,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8723,14 +8803,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8781,15 +8864,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8823,15 +8908,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8862,14 +8948,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9000,13 +9086,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9037,15 +9125,17 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9098,12 +9188,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9139,12 +9230,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9199,7 +9291,7 @@ linux_ldnmp() { send_stats "LDNMP 환경 백업" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업 중$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9297,7 +9389,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" + echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9490,6 +9582,168 @@ linux_ldnmp() { + + + +moltbot_menu() { + local app_id="114" + + send_stats "클로드봇/몰트봇 설치" + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}설치됨${gl_bai}" + else + echo "${gl_hui}설치되지 않음${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}달리기${gl_bai}" + else + echo "${gl_hui}실행되지 않음${gl_bai}" + fi + } + + + show_menu() { + clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) + echo "=======================================" + echo -e "ClawdBot > MoltBot > OpenClaw 관리" + echo -e "$install_status $running_status" + echo "=======================================" + echo "1. 설치" + echo "2. 시작" + echo "3. 중지" + echo "--------------------" + echo "4. 로그 보기" + echo "5. 모델 변경" + echo "6. TG에 연결 코드를 입력하세요." + echo "--------------------" + echo "7. 업데이트" + echo "8. 제거" + echo "--------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "--------------------" + printf "옵션을 입력하고 Enter를 누르십시오." + } + + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + sleep 3 + } + + + install_moltbot() { + echo "OpenClaw 설치를 시작하세요..." + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + pnpm config set registry https://registry.npmmirror.com + fi + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw + source ~/.bashrc + source ~/.profile + openclaw doctor --fix + openclaw onboard --install-daemon + openclaw gateway stop + start_tmux + add_app_id + break_end + + } + + + start_bot() { + echo "OpenClaw를 시작하는 중..." + start_tmux + break_end + } + + stop_bot() { + echo "OpenClaw를 중지하세요..." + install tmux + openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + break_end + } + + view_logs() { + echo "OpenClaw 로그 보기, 종료하려면 Ctrl+C" + openclaw logs + break_end + } + + change_model() { + printf "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o):" + read model + echo "모델을 다음으로 전환하세요.$model" + openclaw models set "$model" + break_end + } + + + change_tg_bot_code() { + printf "TG 로봇이 수신한 연결 코드를 입력하세요(예: 페어링 코드: NYA99R2F:" + read code + openclaw pairing approve telegram $code + break_end + } + + update_moltbot() { + echo "오픈클로 업데이트..." + openclaw update --restart + add_app_id + echo "업데이트 완료" + break_end + } + + + uninstall_moltbot() { + echo "OpenClaw 제거..." + openclaw uninstall + npm uninstall -g openclaw + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + echo "제거가 완료되었습니다." + break_end + } + + + # 메인 루프 + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; + *) break ;; + esac + done + +} + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -9497,6 +9751,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}신청 목록이 업데이트 중입니다. 기다리세요...${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -9525,7 +9780,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9537,7 +9792,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9585,15 +9840,15 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" - echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}ClawdBot/Moltbot 로봇${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -9755,7 +10010,7 @@ while true; do local docker_describe="gin 및 Solidjs로 구동되는 다중 저장소, 웹 브라우징 및 WebDAV를 지원하는 파일 목록 프로그램" - local docker_url="공식 홈페이지 소개: https://github.com/OpenListTeam/OpenList" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -9795,7 +10050,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -9806,7 +10061,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -9927,7 +10182,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -10495,7 +10750,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -10862,25 +11117,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="마우스 패널" - local panelurl="공식 주소:${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanel 오리지널 마우스 패널" + local panelurl="공식 주소:${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -10995,7 +11251,7 @@ while true; do } local docker_describe="Go를 사용하여 구현된 GHProxy는 일부 영역에서 Github 저장소 가져오기를 가속화하는 데 사용됩니다." - local docker_url="공식 홈페이지 소개: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11060,7 +11316,7 @@ while true; do } local docker_describe="이는 Prometheus 호스트 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." - local docker_url="공식 홈페이지 소개: https://github.com/prometheus/node_exporter" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11090,7 +11346,7 @@ while true; do } local docker_describe="이는 Prometheus 컨테이너 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." - local docker_url="공식 홈페이지 소개: https://github.com/google/cadvisor" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11113,7 +11369,7 @@ while true; do } local docker_describe="이는 웹사이트 변경 감지, 보충 모니터링 및 알림을 위한 작은 도구입니다." - local docker_url="공식 홈페이지 소개: https://github.com/dgtlmoon/changeDetection.io" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11146,7 +11402,7 @@ while true; do } local docker_describe="Docker 시각적 패널 시스템은 완전한 Docker 관리 기능을 제공합니다." - local docker_url="공식 홈페이지 소개: https://github.com/donknap/dpanel" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11166,7 +11422,7 @@ while true; do } local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." - local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11218,7 +11474,7 @@ while true; do } local docker_describe="OpenWebUI는 새로운 DeepSeek R1 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." - local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11274,7 +11530,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="차세대 대형 모델 게이트웨이 및 AI 자산 관리 시스템" - local app_url="공식 홈페이지: https://github.com/Calcium-Ion/new-api" + local app_url="공식 웹사이트:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11327,8 +11583,8 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." - local app_url="공식 소개: https://github.com/jumpserver/jumpserver" + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11379,7 +11635,7 @@ while true; do } local docker_describe="무료 오픈 소스 기계 번역 API, 완전 자체 호스팅 및 번역 엔진은 오픈 소스 Argos Translate 라이브러리에 의해 구동됩니다." - local docker_url="공식 홈페이지 소개: https://github.com/LibreTranslate/LibreTranslate" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11392,7 +11648,7 @@ while true; do local app_id="62" local app_name="RAGFlow 지식 기반" local app_text="깊은 문서 이해를 기반으로 한 오픈소스 RAG(Retrieval Augmented Generation) 엔진" - local app_url="공식 홈페이지: https://github.com/infiniflow/ragflow" + local app_url="공식 웹사이트:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11440,7 +11696,7 @@ while true; do } local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 단순화 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." - local docker_url="공식 홈페이지 소개: https://github.com/open-webui/open-webui" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11458,7 +11714,7 @@ while true; do } local docker_describe="개발자와 IT 작업자에게 매우 유용한 도구" - local docker_url="공식 홈페이지 소개: https://github.com/CorentinTh/it-tools" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11494,7 +11750,7 @@ while true; do } local docker_describe="강력한 자동화된 워크플로우 플랫폼입니다." - local docker_url="공식 홈페이지 소개: https://github.com/n8n-io/n8n" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11523,7 +11779,7 @@ while true; do } local docker_describe="동적 도메인 이름 확인을 위해 공용 IP(IPv4/IPv6)를 주요 DNS 서비스 제공업체에 실시간으로 자동 업데이트합니다." - local docker_url="공식 홈페이지 소개: https://github.com/jeessy2/ddns-go" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11693,7 +11949,7 @@ while true; do } local docker_describe="무료 온라인 비디오 검색 및 시청 플랫폼" - local docker_url="공식 홈페이지 소개: https://github.com/LibreSpark/LibreTV" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11709,7 +11965,7 @@ while true; do local app_name="Moontv 개인 영화 및 TV" local app_text="무료 온라인 비디오 검색 및 시청 플랫폼" - local app_url="영상소개 : https://github.com/MoonTechLab/LunaTV" + local app_url="비디오 소개:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11775,7 +12031,7 @@ while true; do } local docker_describe="음악을 더 잘 관리할 수 있도록 설계된 음악 마법사입니다." - local docker_url="공식 홈페이지 소개: https://github.com/foamzou/melody" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11802,7 +12058,7 @@ while true; do } local docker_describe="중국의 DOS 게임 컬렉션 웹사이트입니다." - local docker_url="공식 홈페이지 소개: https://github.com/rwv/chinese-dos-games" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11837,7 +12093,7 @@ while true; do } local docker_describe="오프라인 고속 BT 자기 다운로드 도구인 Xunlei" - local docker_url="공식 홈페이지 소개: https://github.com/cnk3x/xunlei" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"휴대폰으로 Xunlei에 로그인하고 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" local docker_passwd="" local app_size="1" @@ -11852,7 +12108,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki는 AI 대형 모델을 기반으로 하는 오픈 소스 지능형 문서 관리 시스템입니다. 포트 배포를 사용자 정의하지 않는 것이 좋습니다." - local app_url="공식 소개: https://github.com/chaitin/PandaWiki" + local app_url="공식 소개:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -12081,7 +12337,7 @@ while true; do } local docker_describe="경량 자체 호스팅 서버 모니터링 도구" - local docker_url="공식 홈페이지 소개: https://github.com/komari-monitor/komari/tree/main" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"기본 계정: admin 기본 비밀번호: 1212156\"" local docker_passwd="" local app_size="1" @@ -12112,7 +12368,7 @@ while true; do } local docker_describe="재무 관리를 위한 오픈 소스 개인 구독 추적기" - local docker_url="공식 홈페이지 소개: https://github.com/ellite/Wallos" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12125,7 +12381,7 @@ while true; do local app_id="85" local app_name="이미치 픽처 비디오 매니저" local app_text="고성능 자체 호스팅 사진 및 비디오 관리 솔루션입니다." - local app_url="공식 홈페이지 소개: https://github.com/immich-app/immich" + local app_url="공식 웹사이트 소개:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12218,7 +12474,7 @@ while true; do } local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." - local docker_url="공식 홈페이지 소개: https://github.com/synctv-org/synctv" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" @@ -12277,7 +12533,7 @@ while true; do } local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" - local docker_url="공식 홈페이지 소개: https://github.com/vastsa/FileCodeBox" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" local app_size="1" @@ -12349,7 +12605,7 @@ while true; do local app_name="gitea 비공개 코드 저장소" local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." - local app_url="영상소개 : https://github.com/go-gitea/gitea" + local app_url="비디오 소개:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12439,7 +12695,7 @@ while true; do } local docker_describe="미니멀리스트 정적 파일 서버, 업로드 및 다운로드 지원" - local docker_url="공식 홈페이지 소개: https://github.com/sigoden/dufs" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12470,7 +12726,7 @@ while true; do } local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" - local docker_url="공식 홈페이지 소개: https://github.com/GopeedLab/gopeed" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12534,7 +12790,7 @@ while true; do local app_name="2FAuth 자체 호스팅 2단계 인증자" local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." - local app_url="공식 홈페이지: https://github.com/Bubka/2FAuth" + local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12765,7 +13021,7 @@ while true; do local app_name="dsm 시놀로지 가상 머신" local app_text="Docker 컨테이너의 가상 DSM" - local app_url="공식 웹사이트: https://github.com/vdsm/virtual-dsm" + local app_url="공식 웹사이트:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12836,7 +13092,7 @@ while true; do } local docker_describe="Dropbox 및 Resilio Sync와 유사하지만 완전히 분산된 오픈 소스 P2P 파일 동기화 도구입니다." - local docker_url="공식 홈페이지 소개: https://github.com/syncthing/syncthing" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12849,7 +13105,7 @@ while true; do local app_id="101" local app_name="AI 영상 생성 도구" local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." - local app_url="공식 웹사이트: https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12904,7 +13160,7 @@ while true; do } local docker_describe="독립적인 배포를 지원하는 개인용 클라우드 소셜 미디어 채팅 서비스입니다." - local docker_url="공식 홈페이지 소개: https://github.com/Privoce/vocechat-web" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12917,7 +13173,7 @@ while true; do local app_id="103" local app_name="Umami 웹사이트 통계 도구" local app_text="Google Analytics와 유사한 오픈 소스, 가볍고 개인정보 보호 친화적인 웹사이트 분석 도구입니다." - local app_url="공식 웹사이트: https://github.com/umami-software/umami" + local app_url="공식 웹사이트:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12983,7 +13239,7 @@ while true; do } local docker_describe="Siyuan Notes는 개인 정보 보호를 최우선으로 하는 지식 관리 시스템입니다." - local docker_url="공식 홈페이지 소개: https://github.com/siyuan-note/siyuan" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13010,7 +13266,7 @@ while true; do } local docker_describe="마인드맵, 플로우차트 등을 통합한 강력한 오픈소스 화이트보드 도구입니다." - local docker_url="공식 홈페이지 소개: https://github.com/plait-board/ drawix" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13045,7 +13301,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou는 고성능 네트워크 디스크 리소스 검색 API 서비스입니다." - local docker_url="공식 홈페이지 소개: https://github.com/fish2018/pansou" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13060,7 +13316,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot 챗봇" local app_text="오픈 소스 대형 언어 모델 기반 인스턴트 메시징 로봇 개발 플랫폼입니다." - local app_url="공식 홈페이지: https://github.com/langbot-app/LangBot" + local app_url="공식 웹사이트:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13117,7 +13373,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="개인이나 소규모 팀에 적합한 온라인 네트워크 디스크 프로그램입니다." - local docker_url="공식 홈페이지 소개: https://github.com/zfile-dev/zfile" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13130,7 +13386,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeep 북마크 관리" local app_text="데이터 수집가를 위해 설계된 인공 지능 기능을 갖춘 자체 호스팅 북마크 앱입니다." - local app_url="공식 홈페이지: https://github.com/karakeep-app/karakeep" + local app_url="공식 웹사이트:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13183,7 +13439,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="강력한 다중 형식 파일 변환 도구입니다(문서, 이미지, 오디오 및 비디오 등 지원). 도메인 이름 액세스를 추가하는 것이 좋습니다." - local docker_url="프로젝트 주소: https://github.com/c4illin/ConvertX" + local docker_url="프로젝트 주소:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13215,7 +13471,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky는 DDNS, 역방향 프록시, WOL 및 기타 기능을 지원하는 대규모 인트라넷 침투 및 포트 전달 관리 도구입니다." - local docker_url="프로젝트 주소: https://github.com/gdy666/lucky" + local docker_url="프로젝트 주소:${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"기본 계정 비밀번호: 666\"" local docker_passwd="" local app_size="1" @@ -13245,7 +13501,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="웹 페이지를 통해 데스크톱 브라우저 인터페이스에 대한 직접 액세스를 지원하는 Docker에서 실행되는 Firefox 브라우저입니다." - local docker_url="프로젝트 주소: https://github.com/jlesage/docker-firefox" + local docker_url="프로젝트 주소:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13253,13 +13509,17 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) + moltbot_menu + ;; + b) clear send_stats "모든 애플리케이션 백업" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}백업 중$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13316,7 +13576,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}압축 해제 중$filename ...${gl_bai}" + echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "애플리케이션 데이터가 복원되었습니다. 현재 해당 애플리케이션을 복원하려면 지정된 애플리케이션 메뉴에 수동으로 진입한 후 애플리케이션을 업데이트하시기 바랍니다." else @@ -13563,20 +13823,33 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "공식 미러 소스를 사용하세요..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel true \ - --pure-mode + echo "해외 미러 소스를 활용하세요.." + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } @@ -13636,6 +13909,378 @@ fail2ban_panel() { +net_menu() { + + send_stats "네트워크 카드 관리 도구" + show_nics() { + echo "================ 현재 네트워크 카드 정보 =================" + printf "%-18s %-12s %-20s %-26s\n" "네트워크 카드 이름" "상태" "IP 주소" "MAC 주소" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== 네트워크 카드 관리 메뉴 ===========" + echo "1. 네트워크 카드 활성화" + echo "2. 네트워크 카드 비활성화" + echo "3. 네트워크 카드 세부정보 보기" + echo "4. 네트워크 카드 정보 새로 고침" + echo "0. 이전 메뉴로 돌아가기" + echo "====================================" + read -rp "작업을 선택하십시오:" choice + + case $choice in + 1) + send_stats "네트워크 카드 활성화" + read -rp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" + else + echo "✘ 네트워크 카드가 존재하지 않습니다." + fi + read -rp "계속하려면 Enter를 누르세요..." + ;; + 2) + send_stats "네트워크 카드 비활성화" + read -rp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" + else + echo "✘ 네트워크 카드가 존재하지 않습니다." + fi + read -rp "계속하려면 Enter를 누르세요..." + ;; + 3) + send_stats "네트워크 카드 세부정보 보기" + read -rp "보려는 네트워크 카드의 이름을 입력하십시오:" nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nic세부정보 ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ 네트워크 카드가 존재하지 않습니다." + fi + read -rp "계속하려면 Enter를 누르세요..." + ;; + 4) + send_stats "네트워크 카드 정보 새로 고침" + continue + ;; + *) + break + ;; + esac + done +} + + + +log_menu() { + send_stats "시스템 로그 관리 도구" + + show_log_overview() { + echo "============= 시스템 로그 개요 =============" + echo "호스트 이름: $(호스트 이름)" + echo "시스템 시간: $(날짜)" + echo + echo "[/var/log 디렉토리 직업]" + du -sh /var/log 2>/dev/null + echo + echo "[일지 로그 직업]" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== 시스템 로그 관리 메뉴 ===========" + echo "1. 최신 시스템 로그(일지) 보기" + echo "2. 지정된 서비스 로그 보기" + echo "3. 로그인/보안 로그 보기" + echo "4. 실시간 추적 로그" + echo "5. 오래된 저널 로그 정리" + echo "0. 이전 메뉴로 돌아가기" + echo "=======================================" + read -rp "작업을 선택하십시오:" choice + + case $choice in + 1) + send_stats "최근 로그 보기" + read -rp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "계속하려면 Enter를 누르세요..." + ;; + 2) + send_stats "지정된 서비스 로그 보기" + read -rp "서비스 이름(예: sshd, nginx)을 입력하세요." svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ 서비스가 존재하지 않거나 로그가 없습니다." + fi + read -rp "계속하려면 Enter를 누르세요..." + ;; + 3) + send_stats "로그인/보안 로그 보기" + echo "====== 최근 로그인 로그 ======" + last -n 10 + echo + echo "====== 인증 로그 ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "보안 로그 파일을 찾을 수 없습니다." + fi + read -rp "계속하려면 Enter를 누르세요..." + ;; + 4) + send_stats "실시간 추적 로그" + echo "1) 시스템 로그" + echo "2) 서비스 로그 지정" + read -rp "추적 유형 선택:" t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "서비스 이름 입력:" svc + journalctl -u "$svc" -f + else + echo "잘못된 선택" + fi + ;; + 5) + send_stats "오래된 저널 로그 정리" + echo "⚠️ 일지를 청소하세요(안전한 방법)" + echo "1) 최근 7일을 보관" + echo "2) 최근 3일을 보관한다" + echo "3) 최대 로그 크기를 500M로 제한하십시오." + read -rp "청소 방법을 선택하세요:" c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "잘못된 옵션" ;; + esac + echo "✔ 저널 로그 정리 완료" + sleep 2 + ;; + *) + break + ;; + esac + done +} + + + +env_menu() { + + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "시스템 변수 관리 도구" + + show_env_vars() { + clear + send_stats "현재 유효한 환경 변수" + echo "========== 현재 적용되는 환경변수(발췌) ==========" + printf "%-20s %s\n" "변수 이름" "값" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== 구성 파일에 정의된 변수(파싱) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> 소스 파일:$file" + echo "-----------------------------------------------" + + # 내보내기 VAR=xxx 또는 VAR=xxx 추출 + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "계속하려면 Enter를 누르세요..." + } + + + view_file() { + local file="$1" + send_stats "변수 파일 보기$file" + clear + if [ -f "$file" ]; then + echo "========== 파일 보기:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "파일이 존재하지 않습니다:$file" + fi + read -rp "계속하려면 Enter를 누르세요..." + } + + edit_file() { + local file="$1" + send_stats "변수 파일 편집$file" + install nano + nano "$file" + } + + source_files() { + echo "환경 변수를 다시 로드하는 중..." + send_stats "환경 변수 다시 로드 중" + source "$BASHRC" + source "$PROFILE" + echo "✔ 환경 변수가 다시 로드되었습니다." + read -rp "계속하려면 Enter를 누르세요..." + } + + while true; do + clear + echo "=========== 시스템 환경 변수 관리 ==========" + echo "현재 사용자:$USER" + echo "--------------------------------------" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "2. ~/.bashrc 보기" + echo "3. ~/.profile 보기" + echo "4. ~/.bashrc 편집" + echo "5. ~/.profile 편집" + echo "6. 환경 변수 다시 로드(출처)" + echo "--------------------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "--------------------------------------" + read -rp "작업을 선택하십시오:" choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "잘못된 옵션" + sleep 1 + ;; + esac + done +} + + +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "사용법: create_user_with_sshkey <사용자 이름>" + return 1 + fi + + # 사용자 생성 + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "공개 키 가져오기의 예:" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" + echo "- 직접 붙여넣기: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "수입해주세요${new_username}공개 키:" sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "URL에서 SSH 공개 키 가져오기" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "공개 키를 직접 가져오기" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "오류: 알 수 없는 매개변수 '$sshkey_vl'" + return 1 + ;; + esac + + + # 권한 수정 + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo 비밀번호가 필요하지 않음 + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" <> /etc/ssh/sshd_config + passwd -l "$new_username" &>/dev/null + restart_ssh + + echo "사용자$new_username생성 완료" +} + + + + + + + + + + + + + linux_Settings() { @@ -13646,7 +14291,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -13658,8 +14303,8 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}시스템 업데이트 소스 전환${gl_kjlan}20. ${gl_bai}예약된 작업 관리" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}ROOT 개인 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -13667,9 +14312,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}rsync 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}네트워크 카드 관리 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원스톱 시스템 튜닝${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}시스템 로그 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}시스템 변수 관리 도구" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}61. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원스톱 시스템 튜닝${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하세요${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" echo -e "${gl_kjlan}101. ${gl_bai}k 명령의 고급 사용법${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 사자 스크립트 제거" echo -e "${gl_kjlan}------------------------" @@ -13687,7 +14334,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "단축키가 설정되었습니다" send_stats "스크립트 단축키가 설정되었습니다" break_end @@ -13702,8 +14352,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "루트 비밀번호 모드" + clear add_sshpasswd ;; @@ -13860,16 +14509,13 @@ EOF linux_Settings fi - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + create_user_with_sshkey $new_username true - install sudo + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - passwd -l root - - echo "작업이 완료되었습니다." ;; @@ -13946,7 +14592,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -13983,7 +14629,12 @@ EOF printf "%-24s %-34s %-20s %-10s\n" "사용자 이름" "사용자 권한" "사용자 그룹" "sudo 권한" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) - local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -13991,7 +14642,7 @@ EOF echo "" echo "계정 운영" echo "------------------------" - echo "1. 일반 계정 생성 2. 프리미엄 계정 생성" + echo "1. 일반 사용자 생성 2. 고급 사용자 생성" echo "------------------------" echo "3. 가장 높은 권한을 부여합니다. 4. 가장 높은 권한을 제거합니다." echo "------------------------" @@ -14005,46 +14656,34 @@ EOF 1) # 사용자에게 새 사용자 이름을 묻는 메시지 표시 read -e -p "새 사용자 이름을 입력하세요:" new_username + create_user_with_sshkey $new_username false - # 새로운 사용자 생성 및 비밀번호 설정 - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - echo "작업이 완료되었습니다." ;; 2) # 사용자에게 새 사용자 이름을 묻는 메시지 표시 read -e -p "새 사용자 이름을 입력하세요:" new_username - - # 새로운 사용자 생성 및 비밀번호 설정 - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - # 새 사용자에게 sudo 권한 부여 - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "작업이 완료되었습니다." + create_user_with_sshkey $new_username true ;; 3) read -e -p "사용자 이름을 입력하세요:" username - # 새 사용자에게 sudo 권한 부여 - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "삭제하려는 사용자 이름을 입력하세요:" username - # 사용자 및 해당 홈 디렉터리 삭제 userdel -r "$username" ;; @@ -14052,6 +14691,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; @@ -14136,7 +14776,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -14204,7 +14844,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14580,7 +15220,23 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 42) + clear + env_menu + ;; + + + 61) clear send_stats "메시지 보드" echo "Technology Lion 공식 게시판을 방문해 보세요. 스크립트에 대한 아이디어가 있으시면 교환 메시지를 남겨주세요!" @@ -15015,7 +15671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15090,7 +15746,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -15163,7 +15819,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -15182,7 +15838,7 @@ echo -e "${gl_kjlan}스테이션 B:${gl_bai}https://b23.tv/2mqnQyh echo -e "${gl_kjlan}공식 웹사이트:${gl_bai}https://kejilion.pro/ ${gl_kjlan}항해:${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}블로그:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}소프트웨어 센터:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}스크립트 공식 웹사이트:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub 주소:${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}스크립트 공식 웹사이트:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub 주소:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -15405,12 +16061,12 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -15449,7 +16105,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" @@ -15695,30 +16351,27 @@ else sshkey) - shift + + shift case "$1" in "" ) # sshkey → 대화형 메뉴 send_stats "SSHKey 대화형 메뉴" sshkey_panel ;; - github ) shift send_stats "GitHub에서 SSH 공개 키 가져오기" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "URL에서 SSH 공개 키 가져오기" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "공개 키를 직접 가져오기" import_sshkey "$1" ;; - * ) echo "오류: 알 수 없는 매개변수 '$1'" echo "용법:" @@ -15728,11 +16381,10 @@ else echo "k sshkey github GitHub에서 SSH 공개 키 가져오기" ;; esac + ;; *) k_info ;; esac fi - - diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 0c8aec3ed..bda1e3acc 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.4" +sh_v="4.3.7" gl_hui='\e[37m' @@ -29,6 +29,8 @@ else gh_proxy="https://" fi +gh_https_url="https://" + } quanju_canshu @@ -102,6 +104,7 @@ sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 +ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 @@ -176,7 +179,7 @@ install() { for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_huang}正在安裝$package...${gl_bai}" + echo -e "${gl_kjlan}正在安裝$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -251,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_huang}正在卸載$package...${gl_bai}" + echo -e "${gl_kjlan}正在卸載$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -448,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_huang}正在安裝docker環境...${gl_bai}" + echo -e "${gl_kjlan}正在安裝docker環境...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -627,7 +630,7 @@ while true; do send_stats "拉取鏡像" read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在獲取鏡像:$name${gl_bai}" + echo -e "${gl_kjlan}正在獲取鏡像:$name${gl_bai}" docker pull $name done ;; @@ -635,7 +638,7 @@ while true; do send_stats "更新鏡像" read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames for name in $imagenames; do - echo -e "${gl_huang}正在更新鏡像:$name${gl_bai}" + echo -e "${gl_kjlan}正在更新鏡像:$name${gl_bai}" docker pull $name done ;; @@ -1442,10 +1445,6 @@ install_ssltls() { openssl req -x509 -key /etc/letsencrypt/live/$yuming/privkey.pem -out /etc/letsencrypt/live/$yuming/fullchain.pem -days 5475 -subj "/C=US/ST=State/L=City/O=Organization/OU=Organizational Unit/CN=Common Name" fi else - if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null; then - iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT - fi - docker run --rm -p 80:80 -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot certonly --standalone -d "$yuming" --email your@email.com --agree-tos --no-eff-email --force-renewal --key-type ecdsa fi fi @@ -1543,7 +1542,7 @@ certs_status() { echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" echo "------------------------" - echo "1. 重新申請 2. 導入已有證書 3. 不帶證書改用HTTP訪問 0. 退出" + echo "1. 重新申請 2. 導入已有證書 0. 退出" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -1600,18 +1599,9 @@ certs_status() { echo "錯誤:無效的證書或私鑰格式!" certs_status fi - - ;; - 3) - send_stats "不帶證書改用HTTP訪問" - sed -i '/if (\$scheme = http) {/,/}/s/^/#/' /home/web/conf.d/${yuming}.conf - sed -i '/ssl_certificate/d; /ssl_certificate_key/d' /home/web/conf.d/${yuming}.conf - sed -i '/443 ssl/d; /443 quic/d' /home/web/conf.d/${yuming}.conf ;; *) - send_stats "退出申請" - rm -f /home/web/conf.d/${yuming}.conf - exit + exit ;; esac fi @@ -2146,7 +2136,7 @@ web_security() { wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-418.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-deny.conf wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-unauthorized.conf - wget ${gh_proxy}https://raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf + wget ${gh_proxy}raw.githubusercontent.com/linuxserver/fail2ban-confs/master/filter.d/nginx-bad-request.conf cd /etc/fail2ban/jail.d/ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf @@ -3391,14 +3381,16 @@ ldnmp_wp() { repeat_add_yuming ldnmp_install_status + + install_ssltls + certs_status + add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on - install_ssltls - certs_status - add_db cd /home/web/html mkdir $yuming @@ -3447,6 +3439,10 @@ ldnmp_Proxy() { fi nginx_install_status + + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3465,9 +3461,6 @@ ldnmp_Proxy() { sed -i "s/# 動態添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf - install_ssltls - certs_status - update_nginx_listen_port "$yuming" "$access_port" nginx_http_on @@ -3495,6 +3488,9 @@ ldnmp_Proxy_backend() { nginx_install_status + install_ssltls + certs_status + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3511,8 +3507,6 @@ ldnmp_Proxy_backend() { sed -i "s/# 動態添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status update_nginx_listen_port "$yuming" "$access_port" @@ -4274,7 +4268,7 @@ frps_panel() { check_docker_image_update $docker_name echo -e "FRP服務端$check_frp $update_status" echo "構建FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" - echo "官網介紹: https://github.com/fatedier/frp/" + echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip @@ -4372,7 +4366,7 @@ frpc_panel() { check_docker_image_update $docker_name echo -e "FRP客戶端$check_frp $update_status" echo "與服務端對接,對接後可創建內網穿透服務到互聯網訪問" - echo "官網介紹: https://github.com/fatedier/frp/" + echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then @@ -4465,7 +4459,7 @@ yt_menu_pro() { send_stats "yt-dlp 下載工具" echo -e "yt-dlp $YTDLP_STATUS" echo -e "yt-dlp 是一個功能強大的視頻下載工具,支持 YouTube、Bilibili、Twitter 等數千站點。" - echo -e "官網地址:https://github.com/yt-dlp/yt-dlp" + echo -e "官網地址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "已下載視頻列表:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" @@ -4484,7 +4478,7 @@ yt_menu_pro() { send_stats "正在安裝 yt-dlp..." echo "正在安裝 yt-dlp..." install ffmpeg - curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp + curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id @@ -4600,7 +4594,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_huang}正在系統更新...${gl_bai}" + echo -e "${gl_kjlan}正在系統更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4627,7 +4621,7 @@ linux_update() { linux_clean() { - echo -e "${gl_huang}正在系統清理...${gl_bai}" + echo -e "${gl_kjlan}正在系統清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4807,39 +4801,30 @@ correct_ssh_config() { local sshd_config="/etc/ssh/sshd_config" - # 如果找到 PasswordAuthentication 設置為 yes - if grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - # 如果找到 PubkeyAuthentication 設置為 yes - if grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then + if grep -Eq "^\s*PasswordAuthentication\s+no" "$sshd_config"; then sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' "$sshd_config" + else + sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin yes/' \ + -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication yes/' \ + -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' "$sshd_config" fi - # 如果 PasswordAuthentication 和 PubkeyAuthentication 都沒有匹配,則設置默認值 - if ! grep -Eq "^PasswordAuthentication\s+yes" "$sshd_config" && ! grep -Eq "^PubkeyAuthentication\s+yes" "$sshd_config"; then - sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' "$sshd_config" - sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' "$sshd_config" - fi - + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* } new_ssh_port() { - # 備份 SSH 配置文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config correct_ssh_config - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh open_port $new_port @@ -4852,21 +4837,8 @@ new_ssh_port() { } -add_sshkey() { - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f ~/.ssh/sshkey -N "" - cat ~/.ssh/sshkey.pub >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - ip_address - echo -e "私鑰信息已生成,務必復制保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" - echo "--------------------------------" - cat ~/.ssh/sshkey - echo "--------------------------------" +sshkey_on() { sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ @@ -4874,17 +4846,43 @@ add_sshkey() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" + echo -e "${gl_lv}用戶密鑰登錄模式已開啟,已關閉密碼登錄模式,重連將會生效${gl_bai}" } +add_sshkey() { + chmod 700 "${HOME}" + mkdir -p "${HOME}/.ssh" + chmod 700 "${HOME}/.ssh" + touch "${HOME}/.ssh/authorized_keys" + + ssh-keygen -t ed25519 -C "xxxx@gmail.com" -f "${HOME}/.ssh/sshkey" -N "" + + cat "${HOME}/.ssh/sshkey.pub" >> "${HOME}/.ssh/authorized_keys" + chmod 600 "${HOME}/.ssh/authorized_keys" + + ip_address + echo -e "私鑰信息已生成,務必復制保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + + echo "--------------------------------" + cat "${HOME}/.ssh/sshkey" + echo "--------------------------------" + + sshkey_on +} + + + import_sshkey() { local public_key="$1" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key @@ -4898,36 +4896,30 @@ import_sshkey() { if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then echo -e "${gl_hong}錯誤:看起來不像合法的 SSH 公鑰。${gl_bai}" return 1 - fi + fi - if grep -Fxq "$public_key" ~/.ssh/authorized_keys 2>/dev/null; then + if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then echo "該公鑰已存在,無需重複添加" return 0 fi - chmod 700 ~/ - mkdir -p ~/.ssh - chmod 700 ~/.ssh - touch ~/.ssh/authorized_keys - echo "$public_key" >> ~/.ssh/authorized_keys - chmod 600 ~/.ssh/authorized_keys - - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh - echo -e "${gl_lv}公鑰已成功導入,ROOT私鑰登錄已開啟,已關閉ROOT密碼登錄,重連將會生效${gl_bai}" + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + touch "$auth_keys" + echo "$public_key" >> "$auth_keys" + chmod 600 "$auth_keys" + sshkey_on } + fetch_remote_ssh_keys() { local keys_url="$1" - local authorized_keys="${HOME}/.ssh/authorized_keys" + local base_dir="${2:-$HOME}" + local ssh_dir="${base_dir}/.ssh" + local authorized_keys="${ssh_dir}/authorized_keys" local temp_file if [[ -z "${keys_url}" ]]; then @@ -4969,8 +4961,8 @@ fetch_remote_ssh_keys() { return 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + mkdir -p "${ssh_dir}" + chmod 700 "${ssh_dir}" touch "${authorized_keys}" chmod 600 "${authorized_keys}" @@ -4996,13 +4988,7 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then echo "成功添加${added}條新的公鑰到${authorized_keys}" - sed -i -e 's/^\s*#\?\s*PermitRootLogin .*/PermitRootLogin prohibit-password/' \ - -e 's/^\s*#\?\s*PasswordAuthentication .*/PasswordAuthentication no/' \ - -e 's/^\s*#\?\s*PubkeyAuthentication .*/PubkeyAuthentication yes/' \ - -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config - - rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* - restart_ssh + sshkey_on else echo "沒有新的公鑰需要添加(可能已全部存在)" fi @@ -5012,19 +4998,21 @@ fetch_remote_ssh_keys() { + fetch_github_ssh_keys() { local username="$1" + local base_dir="${2:-$HOME}" echo "操作前,請確保您已在 GitHub 賬戶中添加了 SSH 公鑰:" - echo "1. 登錄 https://github.com/settings/keys" + echo "1. 登錄${gh_https_url}github.com/settings/keys" echo "2. 點擊 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" echo "4. 將本地公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)粘貼到 Key 字段" echo "5. 點擊 Add SSH key 完成添加" echo "" echo "添加完成後,GitHub 會公開提供您的所有公鑰,地址為:" - echo "https://github.com/您的用戶名.keys" + echo " ${gh_https_url}github.com/您的用戶名.keys" echo "" @@ -5037,19 +5025,16 @@ fetch_github_ssh_keys() { return 1 fi - keys_url="https://github.com/${username}.keys" + keys_url="${gh_https_url}github.com/${username}.keys" - fetch_remote_ssh_keys "${keys_url}" + fetch_remote_ssh_keys "${keys_url}" "${base_dir}" } - - sshkey_panel() { - root_use - send_stats "私鑰登錄" + send_stats "用戶密鑰登錄" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5058,8 +5043,8 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}未啟用${gl_bai}" fi - echo -e "ROOT私鑰登錄模式${IS_KEY_ENABLED}" - echo "視頻介紹: https://www.bilibili.com/video/BV1Q4421X78n?t=209.4" + echo -e "用戶密鑰登錄模式${IS_KEY_ENABLED}" + echo "進階玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "將會生成密鑰對,更安全的方式SSH登錄" echo "------------------------" @@ -5096,7 +5081,7 @@ sshkey_panel() { 5) send_stats "編輯公鑰文件" install nano - nano ~/.ssh/authorized_keys + nano ${HOME}/.ssh/authorized_keys break_end ;; @@ -5104,10 +5089,10 @@ sshkey_panel() { send_stats "查看本機密鑰" echo "------------------------" echo "公鑰信息" - cat ~/.ssh/authorized_keys + cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "私鑰信息" - cat ~/.ssh/sshkey + cat ${HOME}/.ssh/sshkey echo "------------------------" break_end ;; @@ -5125,20 +5110,55 @@ sshkey_panel() { - add_sshpasswd() { -echo "設置你的ROOT密碼" -passwd -sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; -sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; -rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* -restart_ssh -echo -e "${gl_lv}ROOT登錄設置完畢!${gl_bai}" + root_use + send_stats "設置密碼登錄模式" + echo "設置密碼登錄模式" + + local target_user="$1" + + # 如果沒有通過參數傳入,則交互輸入 + if [[ -z "$target_user" ]]; then + read -e -p "請輸入要修改密碼的用戶名(默認 root):" target_user + fi + + # 回車不輸入,默認 root + target_user=${target_user:-root} + + # 校驗用戶是否存在 + if ! id "$target_user" >/dev/null 2>&1; then + echo "錯誤:用戶$target_user不存在" + return 1 + fi + passwd "$target_user" + + if [[ "$target_user" == "root" ]]; then + sed -i 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + fi + + sed -i 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* + + restart_ssh + + echo -e "${gl_lv}密碼設置完畢,已更改為密碼登錄模式!${gl_bai}" } + + + + + + + + + + + + root_use() { clear [ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示:${gl_bai}該功能需要root用戶才能運行!" && break_end && kejilion @@ -5146,6 +5166,15 @@ clear + + + + + + + + + dd_xitong() { send_stats "重裝系統" dd_xitong_MollyLau() { @@ -5194,8 +5223,8 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " - echo -e "${gl_hui}bin456789項目地址: https://github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro項目地址: https://github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro項目地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5716,7 +5745,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_huang}正在更新病毒庫...${gl_bai}" + echo -e "${gl_kjlan}正在更新病毒庫...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5730,7 +5759,7 @@ clamav_scan() { return fi - echo -e "${gl_huang}正在掃描目錄$@...${gl_bai}" + echo -e "${gl_kjlan}正在掃描目錄$@...${gl_bai}" # 構建 mount 參數 local MOUNT_PARAMS="" @@ -7073,7 +7102,10 @@ rsync_manager() { linux_info() { + + clear + echo -e "${gl_kjlan}正在查詢系統信息……${gl_bai}" send_stats "系統信息查詢" ip_address @@ -7177,6 +7209,58 @@ linux_tools() { clear # send_stats "基礎工具" echo -e "基礎工具" + + tools=( + curl wget sudo socat htop iftop unzip tar tmux ffmpeg + btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders + vim nano git + ) + + if command -v apt >/dev/null 2>&1; then + PM="apt" + elif command -v dnf >/dev/null 2>&1; then + PM="dnf" + elif command -v yum >/dev/null 2>&1; then + PM="yum" + elif command -v pacman >/dev/null 2>&1; then + PM="pacman" + elif command -v apk >/dev/null 2>&1; then + PM="apk" + elif command -v zypper >/dev/null 2>&1; then + PM="zypper" + elif command -v opkg >/dev/null 2>&1; then + PM="opkg" + elif command -v pkg >/dev/null 2>&1; then + PM="pkg" + else + echo "❌ 未識別的包管理器" + exit 1 + fi + + echo "📦 使用包管理器:$PM" + echo -e "${gl_kjlan}------------------------${gl_bai}" + + for ((i=0; i<${#tools[@]}; i+=2)); do + # 左列 + if command -v "${tools[i]}" >/dev/null 2>&1; then + left=$(printf "✅ %-12s 已安裝" "${tools[i]}") + else + left=$(printf "❌ %-12s 未安裝" "${tools[i]}") + fi + + # 右列(防止數組越界) + if [[ -n "${tools[i+1]}" ]]; then + if command -v "${tools[i+1]}" >/dev/null 2>&1; then + right=$(printf "✅ %-12s 已安裝" "${tools[i+1]}") + else + right=$(printf "❌ %-12s 未安裝" "${tools[i+1]}") + fi + printf "%-42s %s\n" "$left" "$right" + else + printf "%s\n" "$left" + fi + done + echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通信連接工具" @@ -7496,12 +7580,6 @@ linux_bbr() { docker_ssh_migration() { - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[1;33m' - BLUE='\033[0;36m' - NC='\033[0m' - is_compose_container() { local container=$1 docker inspect "$container" | jq -e '.[0].Config.Labels["com.docker.compose.project"]' >/dev/null 2>&1 @@ -7509,7 +7587,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${BLUE}當前備份列表:${NC}" + echo -e "${gl_kjlan}當前備份列表:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" } @@ -7521,7 +7599,7 @@ docker_ssh_migration() { backup_docker() { send_stats "Docker備份" - echo -e "${YELLOW}正在備份 Docker 容器...${NC}" + echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' read -e -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers @@ -7536,7 +7614,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${RED}沒有找到容器${NC}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}沒有找到容器${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -7550,12 +7628,12 @@ docker_ssh_migration() { declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${GREEN}備份容器:$c${NC}" + echo -e "${gl_lv}備份容器:$c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${BLUE}檢測到$c是 docker-compose 容器${NC}" + echo -e "${gl_kjlan}檢測到$c是 docker-compose 容器${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7565,7 +7643,7 @@ docker_ssh_migration() { # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${YELLOW}Compose 項目 [$project_name] 已備份過,跳過重複打包...${NC}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已備份過,跳過重複打包...${gl_bai}" continue fi @@ -7576,9 +7654,9 @@ docker_ssh_migration() { echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${GREEN}Compose 項目 [$project_name] 已打包:${project_dir}${NC}" + echo -e "${gl_lv}Compose 項目 [$project_name] 已打包:${project_dir}${gl_bai}" else - echo -e "${RED}未找到 docker-compose.yml,跳過此容器...${NC}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳過此容器...${gl_bai}" fi else # 普通容器備份卷 @@ -7615,14 +7693,14 @@ docker_ssh_migration() { # 備份 /home/docker 下的所有文件(不含子目錄) if [ -d "/home/docker" ]; then - echo -e "${BLUE}備份 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}備份 /home/docker 下的文件...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${GREEN}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${NC}" + echo -e "${gl_lv}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${GREEN}備份完成:${BACKUP_DIR}${NC}" - echo -e "${GREEN}可用還原腳本:${RESTORE_SCRIPT}${NC}" + echo -e "${gl_lv}備份完成:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}可用還原腳本:${RESTORE_SCRIPT}${gl_bai}" } @@ -7634,9 +7712,9 @@ docker_ssh_migration() { send_stats "Docker還原" read -e -p "請輸入要還原的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } - echo -e "${BLUE}開始執行還原操作...${NC}" + echo -e "${gl_kjlan}開始執行還原操作...${gl_bai}" install tar jq gzip install_docker @@ -7653,7 +7731,7 @@ docker_ssh_migration() { # 檢查該 compose 項目的容器是否已經在運行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${YELLOW}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${NC}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${gl_bai}" continue fi @@ -7662,32 +7740,32 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${GREEN}Compose 項目 [$project_name] 已解壓到:$original_path${NC}" + echo -e "${gl_lv}Compose 項目 [$project_name] 已解壓到:$original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${GREEN}Compose 項目 [$project_name] 還原完成!${NC}" + echo -e "${gl_lv}Compose 項目 [$project_name] 還原完成!${gl_bai}" fi done # --------- 繼續還原普通容器 --------- - echo -e "${BLUE}檢查並還原普通 Docker 容器...${NC}" + echo -e "${gl_kjlan}檢查並還原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${GREEN}處理容器:$container${NC}" + echo -e "${gl_lv}處理容器:$container${gl_bai}" # 檢查容器是否已經存在且正在運行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 已在運行,跳過還原...${NC}" + echo -e "${gl_huang}容器 [$container] 已在運行,跳過還原...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${RED}未找到鏡像信息,跳過:$container${NC}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到鏡像信息,跳過:$container${gl_bai}"; continue; } # 端口映射 PORT_ARGS="" @@ -7721,7 +7799,7 @@ docker_ssh_migration() { # 刪除已存在但未運行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${YELLOW}容器 [$container] 存在但未運行,刪除舊容器...${NC}" + echo -e "${gl_huang}容器 [$container] 存在但未運行,刪除舊容器...${gl_bai}" docker rm -f "$container" fi @@ -7730,16 +7808,16 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${YELLOW}未找到普通容器的備份信息${NC}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份信息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${BLUE}正在還原 /home/docker 下的文件...${NC}" + echo -e "${gl_kjlan}正在還原 /home/docker 下的文件...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${GREEN}/home/docker 下的文件已還原完成${NC}" + echo -e "${gl_lv}/home/docker 下的文件已還原完成${gl_bai}" else - echo -e "${YELLOW}未找到 /home/docker 下文件的備份,跳過...${NC}" + echo -e "${gl_huang}未找到 /home/docker 下文件的備份,跳過...${gl_bai}" fi @@ -7753,7 +7831,7 @@ docker_ssh_migration() { send_stats "Docker遷移" install jq read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } read -e -p "目標服務器IP:" TARGET_IP read -e -p "目標服務器SSH用戶名:" TARGET_USER @@ -7762,7 +7840,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${YELLOW}傳輸備份中...${NC}" + echo -e "${gl_huang}傳輸備份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then # 使用密鑰登錄 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -7776,9 +7854,9 @@ docker_ssh_migration() { delete_backup() { send_stats "Docker備份文件刪除" read -e -p "請輸入要刪除的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${RED}備份目錄不存在${NC}"; return; } + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${GREEN}已刪除備份:${BACKUP_DIR}${NC}" + echo -e "${gl_lv}已刪除備份:${BACKUP_DIR}${gl_bai}" } # ---------------------------- @@ -7799,7 +7877,7 @@ docker_ssh_migration() { echo -e "3. 還原docker項目" echo -e "4. 刪除docker項目的備份文件" echo "------------------------" - echo -e "0. 返回上一級菜單" + echo -e "0. 返回上一級選單" echo "------------------------" read -e -p "請選擇:" choice case $choice in @@ -7808,7 +7886,7 @@ docker_ssh_migration() { 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${RED}無效選項${NC}" ;; + *) echo -e "${gl_hong}無效選項${gl_bai}" ;; esac break_end done @@ -8412,7 +8490,6 @@ linux_Oracle() { 5) clear add_sshpasswd - ;; 6) clear @@ -8544,16 +8621,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/discuz.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8586,14 +8663,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/kdy.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8624,14 +8701,15 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/maccms.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on @@ -8671,15 +8749,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/dujiaoka.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8723,14 +8803,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/flarum.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + + nginx_http_on docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini @@ -8781,15 +8864,17 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/typecho.com.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8823,15 +8908,16 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf - sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf - sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/refs/heads/main/index_php.conf + sed -i "s|/var/www/html/yuming.com/|/var/www/html/yuming.com/linkstack|g" /home/web/conf.d/$yuming.conf + sed -i "s|yuming.com|$yuming|g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -8862,14 +8948,14 @@ linux_ldnmp() { repeat_add_yuming ldnmp_install_status - wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - install_ssltls certs_status add_db + wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/index_php.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9000,13 +9086,15 @@ linux_ldnmp() { nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf - sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/rewrite.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + sed -i "s/baidu.com/$reverseproxy/g" /home/web/conf.d/$yuming.conf + nginx_http_on docker exec nginx nginx -s reload @@ -9040,12 +9128,14 @@ linux_ldnmp() { read -e -p "請輸入你的反代域名:" fandai_yuming nginx_install_status + install_ssltls + certs_status + + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-domain.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf sed -i "s|fandaicom|$fandai_yuming|g" /home/web/conf.d/$yuming.conf - install_ssltls - certs_status nginx_http_on @@ -9098,12 +9188,13 @@ linux_ldnmp() { add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9139,12 +9230,13 @@ linux_ldnmp() { repeat_add_yuming nginx_install_status - wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf - sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf install_ssltls certs_status + wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/html.conf + sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf + nginx_http_on cd /home/web/html @@ -9199,7 +9291,7 @@ linux_ldnmp() { send_stats "LDNMP環境備份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在備份$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do @@ -9297,7 +9389,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解壓$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9490,6 +9582,168 @@ linux_ldnmp() { + + + +moltbot_menu() { + local app_id="114" + + send_stats "clawdbot/moltbot安裝" + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安裝${gl_bai}" + else + echo "${gl_hui}未安裝${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}運行中${gl_bai}" + else + echo "${gl_hui}未運行${gl_bai}" + fi + } + + + show_menu() { + clear + + local install_status=$(get_install_status) + local running_status=$(get_running_status) + echo "=======================================" + echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "$install_status $running_status" + echo "=======================================" + echo "1. 安裝" + echo "2. 啟動" + echo "3. 停止" + echo "--------------------" + echo "4. 日誌查看" + echo "5. 換模型" + echo "6. TG輸入連接碼" + echo "--------------------" + echo "7. 更新" + echo "8. 卸載" + echo "--------------------" + echo "0. 返回上一級選單" + echo "--------------------" + printf "請輸入選項並回車:" + } + + + start_tmux() { + install tmux + tmux kill-session -t gateway > /dev/null 2>&1 + tmux new -d -s gateway "openclaw gateway" + check_crontab_installed + crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + sleep 3 + } + + + install_moltbot() { + echo "開始安裝 OpenClaw..." + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + pnpm config set registry https://registry.npmmirror.com + fi + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw + source ~/.bashrc + source ~/.profile + openclaw doctor --fix + openclaw onboard --install-daemon + openclaw gateway stop + start_tmux + add_app_id + break_end + + } + + + start_bot() { + echo "啟動 OpenClaw..." + start_tmux + break_end + } + + stop_bot() { + echo "停止 OpenClaw..." + install tmux + openclaw gateway stop + tmux kill-session -t gateway > /dev/null 2>&1 + break_end + } + + view_logs() { + echo "查看 OpenClaw 日誌,Ctrl+C 退出" + openclaw logs + break_end + } + + change_model() { + printf "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o):" + read model + echo "切換模型為$model" + openclaw models set "$model" + break_end + } + + + change_tg_bot_code() { + printf "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F:" + read code + openclaw pairing approve telegram $code + break_end + } + + update_moltbot() { + echo "更新 OpenClaw..." + openclaw update --restart + add_app_id + echo "更新完成" + break_end + } + + + uninstall_moltbot() { + echo "卸載 OpenClaw..." + openclaw uninstall + npm uninstall -g openclaw + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + echo "卸載完成" + break_end + } + + + # 主循環 + while true; do + show_menu + read choice + case $choice in + 1) install_moltbot ;; + 2) start_bot ;; + 3) stop_bot ;; + 4) view_logs ;; + 5) change_model ;; + 6) change_tg_bot_code ;; + 7) update_moltbot ;; + 8) uninstall_moltbot ;; + *) break ;; + esac + done + +} + + + + + + + + + linux_panel() { local sub_choice="$1" @@ -9497,6 +9751,7 @@ local sub_choice="$1" clear cd ~ install git +echo -e "${gl_kjlan}正在更新應用列表請稍等……${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -9590,7 +9845,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器" + echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}ClawdBot/Moltbot機器人${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用列表" echo -e "${gl_kjlan}想要讓你的應用出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -9755,7 +10010,7 @@ while true; do local docker_describe="一個支持多種存儲,支持網頁瀏覽和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驅動" - local docker_url="官網介紹: https://github.com/OpenListTeam/OpenList" + local docker_url="官網介紹:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -10862,25 +11117,26 @@ while true; do docker_app ;; - 41|haozi) + 41|haozi|acepanel) local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="耗子麵板" - local panelurl="官方地址:${gh_proxy}github.com/TheTNB/panel" + local panelname="AcePanel 原耗子麵板" + local panelurl="官方地址:${gh_proxy}github.com/acepanel/panel" panel_app_install() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) } panel_app_manage() { - panel-cli + acepanel help } panel_app_uninstall() { - mkdir -p ~/haozi && cd ~/haozi && curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh cd ~ + bash <(curl -sSLm 10 https://dl.acepanel.net/helper.sh) + } install_panel @@ -10995,7 +11251,7 @@ while true; do } local docker_describe="使用Go實現的GHProxy,用於加速部分地區Github倉庫的拉取。" - local docker_url="官網介紹: https://github.com/WJQSERVER-STUDIO/ghproxy" + local docker_url="官網介紹:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -11060,7 +11316,7 @@ while true; do } local docker_describe="這是一個普羅米修斯的主機數據採集組件,請部署在被監控主機上。" - local docker_url="官網介紹: https://github.com/prometheus/node_exporter" + local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -11090,7 +11346,7 @@ while true; do } local docker_describe="這是一個普羅米修斯的容器數據採集組件,請部署在被監控主機上。" - local docker_url="官網介紹: https://github.com/google/cadvisor" + local docker_url="官網介紹:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -11113,7 +11369,7 @@ while true; do } local docker_describe="這是一款網站變化檢測、補貨監控和通知的小工具" - local docker_url="官網介紹: https://github.com/dgtlmoon/changedetection.io" + local docker_url="官網介紹:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -11146,7 +11402,7 @@ while true; do } local docker_describe="Docker可視化面板系統,提供完善的docker管理功能。" - local docker_url="官網介紹: https://github.com/donknap/dpanel" + local docker_url="官網介紹:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -11166,7 +11422,7 @@ while true; do } local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的llama3大語言模型" - local docker_url="官網介紹: https://github.com/open-webui/open-webui" + local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -11218,7 +11474,7 @@ while true; do } local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的DeepSeek R1大語言模型" - local docker_url="官網介紹: https://github.com/open-webui/open-webui" + local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -11274,7 +11530,7 @@ while true; do local app_id="59" local app_name="NewAPI" local app_text="新一代大模型網關與AI資產管理系統" - local app_url="官方網站: https://github.com/Calcium-Ion/new-api" + local app_url="官方網站:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -11328,7 +11584,7 @@ while true; do local app_id="60" local app_name="JumpServer開源堡壘機" local app_text="是一個開源的特權訪問管理 (PAM) 工具,該程序佔用80端口不支持添加域名訪問了" - local app_url="官方介紹: https://github.com/jumpserver/jumpserver" + local app_url="官方介紹:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -11379,7 +11635,7 @@ while true; do } local docker_describe="免費開源機器翻譯 API,完全自託管,它的翻譯引擎由開源Argos Translate庫提供支持。" - local docker_url="官網介紹: https://github.com/LibreTranslate/LibreTranslate" + local docker_url="官網介紹:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -11392,7 +11648,7 @@ while true; do local app_id="62" local app_name="RAGFlow知識庫" local app_text="基於深度文檔理解的開源 RAG(檢索增強生成)引擎" - local app_url="官方網站: https://github.com/infiniflow/ragflow" + local app_url="官方網站:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -11440,7 +11696,7 @@ while true; do } local docker_describe="OpenWebUI一款大語言模型網頁框架,官方精簡版本,支持各大模型API接入" - local docker_url="官網介紹: https://github.com/open-webui/open-webui" + local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -11458,7 +11714,7 @@ while true; do } local docker_describe="對開發人員和 IT 工作者來說非常有用的工具" - local docker_url="官網介紹: https://github.com/CorentinTh/it-tools" + local docker_url="官網介紹:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -11494,7 +11750,7 @@ while true; do } local docker_describe="是一款功能強大的自動化工作流平台" - local docker_url="官網介紹: https://github.com/n8n-io/n8n" + local docker_url="官網介紹:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -11523,7 +11779,7 @@ while true; do } local docker_describe="自動將你的公網 IP(IPv4/IPv6)實時更新到各大 DNS 服務商,實現動態域名解析。" - local docker_url="官網介紹: https://github.com/jeessy2/ddns-go" + local docker_url="官網介紹:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -11693,7 +11949,7 @@ while true; do } local docker_describe="免費在線視頻搜索與觀看平台" - local docker_url="官網介紹: https://github.com/LibreSpark/LibreTV" + local docker_url="官網介紹:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -11709,7 +11965,7 @@ while true; do local app_name="moontv私有影視" local app_text="免費在線視頻搜索與觀看平台" - local app_url="視頻介紹: https://github.com/MoonTechLab/LunaTV" + local app_url="視頻介紹:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" @@ -11775,7 +12031,7 @@ while true; do } local docker_describe="你的音樂精靈,旨在幫助你更好地管理音樂。" - local docker_url="官網介紹: https://github.com/foamzou/melody" + local docker_url="官網介紹:${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -11802,7 +12058,7 @@ while true; do } local docker_describe="是一個中文DOS遊戲合集網站" - local docker_url="官網介紹: https://github.com/rwv/chinese-dos-games" + local docker_url="官網介紹:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -11837,7 +12093,7 @@ while true; do } local docker_describe="迅雷你的離線高速BT磁力下載工具" - local docker_url="官網介紹: https://github.com/cnk3x/xunlei" + local docker_url="官網介紹:${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"手機登錄迅雷,再輸入邀請碼,邀請碼: 迅雷牛通\"" local docker_passwd="" local app_size="1" @@ -11852,7 +12108,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki是一款AI大模型驅動的開源智能文檔管理系統,強烈建議不要自定義端口部署。" - local app_url="官方介紹: https://github.com/chaitin/PandaWiki" + local app_url="官方介紹:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -12081,7 +12337,7 @@ while true; do } local docker_describe="輕量級的自託管服務器監控工具" - local docker_url="官網介紹: https://github.com/komari-monitor/komari/tree/main" + local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" local docker_use="echo \"默認賬號: admin 默認密碼: 1212156\"" local docker_passwd="" local app_size="1" @@ -12112,7 +12368,7 @@ while true; do } local docker_describe="開源個人訂閱追踪器,可用於財務管理" - local docker_url="官網介紹: https://github.com/ellite/Wallos" + local docker_url="官網介紹:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -12125,7 +12381,7 @@ while true; do local app_id="85" local app_name="immich圖片視頻管理器" local app_text="高性能自託管照片和視頻管理解決方案。" - local app_url="官網介紹: https://github.com/immich-app/immich" + local app_url="官網介紹:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -12218,7 +12474,7 @@ while true; do } local docker_describe="遠程一起觀看電影和直播的程序。它提供了同步觀影、直播、聊天等功能" - local docker_url="官網介紹: https://github.com/synctv-org/synctv" + local docker_url="官網介紹:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初始賬號和密碼: root 登陸後請及時修改登錄密碼\"" local docker_passwd="" local app_size="1" @@ -12277,7 +12533,7 @@ while true; do } local docker_describe="匿名口令分享文本和文件,像拿快遞一樣取文件" - local docker_url="官網介紹: https://github.com/vastsa/FileCodeBox" + local docker_url="官網介紹:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"訪問地址後面帶 /#/admin 訪問管理員頁面\"" local docker_passwd="echo \"管理員密碼: FileCodeBox2023\"" local app_size="1" @@ -12349,7 +12605,7 @@ while true; do local app_name="gitea私有代碼倉庫" local app_text="免費新一代的代碼託管平台,提供接近 GitHub 的使用體驗。" - local app_url="視頻介紹: https://github.com/go-gitea/gitea" + local app_url="視頻介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -12439,7 +12695,7 @@ while true; do } local docker_describe="極簡靜態文件服務器,支持上傳下載" - local docker_url="官網介紹: https://github.com/sigoden/dufs" + local docker_url="官網介紹:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -12470,7 +12726,7 @@ while true; do } local docker_describe="分佈式高速下載工具,支持多種協議" - local docker_url="官網介紹: https://github.com/GopeedLab/gopeed" + local docker_url="官網介紹:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -12534,7 +12790,7 @@ while true; do local app_name="2FAuth自託管二步驗證器" local app_text="自託管的雙重身份驗證 (2FA) 賬戶管理和驗證碼生成工具。" - local app_url="官網: https://github.com/Bubka/2FAuth" + local app_url="官網:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -12765,7 +13021,7 @@ while true; do local app_name="dsm群暉虛擬機" local app_text="Docker容器中的虛擬DSM" - local app_url="官網: https://github.com/vdsm/virtual-dsm" + local app_url="官網:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -12836,7 +13092,7 @@ while true; do } local docker_describe="開源的點對點文件同步工具,類似於 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官網介紹: https://github.com/syncthing/syncthing" + local docker_url="官網介紹:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -12849,7 +13105,7 @@ while true; do local app_id="101" local app_name="AI視頻生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短視頻的工具" - local app_url="官方網站: https://github.com/harry0703/MoneyPrinterTurbo" + local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -12904,7 +13160,7 @@ while true; do } local docker_describe="是一款支持獨立部署的個人云社交媒體聊天服務" - local docker_url="官網介紹: https://github.com/Privoce/vocechat-web" + local docker_url="官網介紹:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -12917,7 +13173,7 @@ while true; do local app_id="103" local app_name="Umami網站統計工具" local app_text="開源、輕量、隱私友好的網站分析工具,類似於GoogleAnalytics。" - local app_url="官方網站: https://github.com/umami-software/umami" + local app_url="官方網站:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -12983,7 +13239,7 @@ while true; do } local docker_describe="思源筆記是一款隱私優先的知識管理系統" - local docker_url="官網介紹: https://github.com/siyuan-note/siyuan" + local docker_url="官網介紹:${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -13010,7 +13266,7 @@ while true; do } local docker_describe="是一款強大的開源白板工具,集成思維導圖、流程圖等。" - local docker_url="官網介紹: https://github.com/plait-board/drawnix" + local docker_url="官網介紹:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -13045,7 +13301,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou是一個高性能的網盤資源搜索API服務。" - local docker_url="官網介紹: https://github.com/fish2018/pansou" + local docker_url="官網介紹:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -13060,7 +13316,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="108" local app_name="LangBot聊天機器人" local app_text="是一個開源的大語言模型原生即時通信機器人開發平台" - local app_url="官方網站: https://github.com/langbot-app/LangBot" + local app_url="官方網站:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -13117,7 +13373,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一個適用於個人或小團隊的在線網盤程序。" - local docker_url="官網介紹: https://github.com/zfile-dev/zfile" + local docker_url="官網介紹:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -13130,7 +13386,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="110" local app_name="karakeep書籤管理" local app_text="是一款可自行託管的書籤應用,帶有人工智能功能,專為數據囤積者而設計。" - local app_url="官方網站: https://github.com/karakeep-app/karakeep" + local app_url="官方網站:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -13183,7 +13439,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一個功能強大的多格式文件轉換工具(支持文檔、圖像、音頻視頻等)強烈建議添加域名訪問" - local docker_url="項目地址: https://github.com/c4illin/ConvertX" + local docker_url="項目地址:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -13215,7 +13471,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="Lucky 是一個大內網穿透及端口轉發管理工具,支持 DDNS、反向代理、WOL 等功能。" - local docker_url="項目地址: https://github.com/gdy666/lucky" + local docker_url="項目地址:${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"默認賬號密碼: 666\"" local docker_passwd="" local app_size="1" @@ -13245,7 +13501,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支持通過網頁直接訪問桌面版瀏覽器界面。" - local docker_url="項目地址: https://github.com/jlesage/docker-firefox" + local docker_url="項目地址:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -13253,13 +13509,17 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ;; + 114|Moltbot|ClawdBot|moltbot|clawdbot|openclaw|OpenClaw) + moltbot_menu + ;; + b) clear send_stats "全部應用備份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_huang}正在備份$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在備份$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do @@ -13316,7 +13576,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi if [ -n "$filename" ]; then - echo -e "${gl_huang}正在解壓$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解壓$filename ...${gl_bai}" cd / && tar -xzf "$filename" echo "應用數據已還原,目前請手動進入指定應用菜單,更新應用,即可還原應用。" else @@ -13563,20 +13823,33 @@ switch_mirror() { --upgrade-software "$upgrade_software" \ --clean-cache "$clean_cache" \ --ignore-backup-tips \ - --install-epel true \ + --install-epel false \ --pure-mode else - echo "使用官方鏡像源..." - bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ - --use-official-source true \ - --protocol https \ - --use-intranet-source false \ - --backup true \ - --upgrade-software "$upgrade_software" \ - --clean-cache "$clean_cache" \ - --ignore-backup-tips \ - --install-epel true \ - --pure-mode + echo "使用海外鏡像源..." + if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --source mirrors.xtom.com \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + else + bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ + --use-official-source true \ + --protocol https \ + --use-intranet-source false \ + --backup true \ + --upgrade-software "$upgrade_software" \ + --clean-cache "$clean_cache" \ + --ignore-backup-tips \ + --install-epel false \ + --pure-mode + fi fi } @@ -13636,6 +13909,378 @@ fail2ban_panel() { +net_menu() { + + send_stats "網卡管理工具" + show_nics() { + echo "================ 當前網卡信息 ================" + printf "%-18s %-12s %-20s %-26s\n" "網卡名" "狀態" "IP地址" "MAC地址" + echo "------------------------------------------------" + for nic in $(ls /sys/class/net); do + state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) + ipaddr=$(ip -4 addr show $nic | awk '/inet /{print $2}' | head -n1) + mac=$(cat /sys/class/net/$nic/address 2>/dev/null) + printf "%-15s %-10s %-18s %-20s\n" "$nic" "$state" "${ipaddr:-无}" "$mac" + done + echo "================================================" + } + + while true; do + clear + show_nics + echo + echo "=========== 網卡管理菜單 ===========" + echo "1. 啟用網卡" + echo "2. 禁用網卡" + echo "3. 查看網卡詳細信息" + echo "4. 刷新網卡信息" + echo "0. 返回上一級選單" + echo "====================================" + read -rp "請選擇操作:" choice + + case $choice in + 1) + send_stats "啟用網卡" + read -rp "請輸入要啟用的網卡名:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" up && echo "✔ 網卡$nic已啟用" + else + echo "✘ 網卡不存在" + fi + read -rp "按回車繼續..." + ;; + 2) + send_stats "禁用網卡" + read -rp "請輸入要禁用的網卡名:" nic + if ip link show "$nic" &>/dev/null; then + ip link set "$nic" down && echo "✔ 網卡$nic已禁用" + else + echo "✘ 網卡不存在" + fi + read -rp "按回車繼續..." + ;; + 3) + send_stats "查看網卡詳情" + read -rp "請輸入要查看的網卡名:" nic + if ip link show "$nic" &>/dev/null; then + echo "========== $nic詳細信息 ==========" + ip addr show "$nic" + ethtool "$nic" 2>/dev/null | head -n 10 + else + echo "✘ 網卡不存在" + fi + read -rp "按回車繼續..." + ;; + 4) + send_stats "刷新網卡信息" + continue + ;; + *) + break + ;; + esac + done +} + + + +log_menu() { + send_stats "系統日誌管理工具" + + show_log_overview() { + echo "============= 系統日誌概覽 =============" + echo "主機名: $(hostname)" + echo "系統時間: $(date)" + echo + echo "[ /var/log 目錄佔用 ]" + du -sh /var/log 2>/dev/null + echo + echo "[ journal 日誌佔用 ]" + journalctl --disk-usage 2>/dev/null + echo "========================================" + } + + while true; do + clear + show_log_overview + echo + echo "=========== 系統日誌管理菜單 ===========" + echo "1. 查看最近系統日誌(journal)" + echo "2. 查看指定服務日誌" + echo "3. 查看登錄/安全日誌" + echo "4. 實時跟踪日誌" + echo "5. 清理舊 journal 日誌" + echo "0. 返回上一級選單" + echo "=======================================" + read -rp "請選擇操作:" choice + + case $choice in + 1) + send_stats "查看最近日誌" + read -rp "查看最近多少行日誌? [默認 100]:" lines + lines=${lines:-100} + journalctl -n "$lines" --no-pager + read -rp "按回車繼續..." + ;; + 2) + send_stats "查看指定服務日誌" + read -rp "請輸入服務名(如 sshd、nginx):" svc + if systemctl list-unit-files | grep -q "^$svc"; then + journalctl -u "$svc" -n 100 --no-pager + else + echo "✘ 服務不存在或無日誌" + fi + read -rp "按回車繼續..." + ;; + 3) + send_stats "查看登錄/安全日誌" + echo "====== 最近登錄日誌 ======" + last -n 10 + echo + echo "====== 認證日誌 ======" + if [ -f /var/log/secure ]; then + tail -n 20 /var/log/secure + elif [ -f /var/log/auth.log ]; then + tail -n 20 /var/log/auth.log + else + echo "未找到安全日誌文件" + fi + read -rp "按回車繼續..." + ;; + 4) + send_stats "實時跟踪日誌" + echo "1) 系統日誌" + echo "2) 指定服務日誌" + read -rp "選擇跟踪類型:" t + if [ "$t" = "1" ]; then + journalctl -f + elif [ "$t" = "2" ]; then + read -rp "輸入服務名:" svc + journalctl -u "$svc" -f + else + echo "無效選擇" + fi + ;; + 5) + send_stats "清理舊 journal 日誌" + echo "⚠️ 清理 journal 日誌(安全方式)" + echo "1) 保留最近 7 天" + echo "2) 保留最近 3 天" + echo "3) 限制日誌最大 500M" + read -rp "請選擇清理方式:" c + case $c in + 1) journalctl --vacuum-time=7d ;; + 2) journalctl --vacuum-time=3d ;; + 3) journalctl --vacuum-size=500M ;; + *) echo "無效選項" ;; + esac + echo "✔ journal 日誌清理完成" + sleep 2 + ;; + *) + break + ;; + esac + done +} + + + +env_menu() { + + BASHRC="$HOME/.bashrc" + PROFILE="$HOME/.profile" + + send_stats "系統變量管理工具" + + show_env_vars() { + clear + send_stats "當前已生效環境變量" + echo "========== 當前已生效環境變量(節選) ==========" + printf "%-20s %s\n" "變量名" "值" + echo "-----------------------------------------------" + for v in USER HOME SHELL LANG PWD; do + printf "%-20s %s\n" "$v" "${!v}" + done + + echo + echo "PATH:" + echo "$PATH" | tr ':' '\n' | nl -ba + + echo + echo "========== 配置文件中定義的變量(解析) ==========" + + parse_file_vars() { + local file="$1" + [ -f "$file" ] || return + + echo + echo ">>> 來源文件:$file" + echo "-----------------------------------------------" + + # 提取 export VAR=xxx 或 VAR=xxx + grep -Ev '^\s*#|^\s*$' "$file" \ + | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ + | while read -r line; do + var=$(echo "$line" | sed -E 's/^(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*).*/\2/') + val=$(echo "$line" | sed -E 's/^[^=]+=//') + printf "%-20s %s\n" "$var" "$val" + done + } + + parse_file_vars "$HOME/.bashrc" + parse_file_vars "$HOME/.profile" + + echo + echo "===============================================" + read -rp "按回車繼續..." + } + + + view_file() { + local file="$1" + send_stats "查看變量文件$file" + clear + if [ -f "$file" ]; then + echo "========== 查看文件:$file ==========" + cat -n "$file" + echo "====================================" + else + echo "文件不存在:$file" + fi + read -rp "按回車繼續..." + } + + edit_file() { + local file="$1" + send_stats "編輯變量文件$file" + install nano + nano "$file" + } + + source_files() { + echo "正在重新加載環境變量..." + send_stats "正在重新加載環境變量" + source "$BASHRC" + source "$PROFILE" + echo "✔ 環境變量已重新加載" + read -rp "按回車繼續..." + } + + while true; do + clear + echo "=========== 系統環境變量管理 ==========" + echo "當前用戶:$USER" + echo "--------------------------------------" + echo "1. 查看當前常用環境變量" + echo "2. 查看 ~/.bashrc" + echo "3. 查看 ~/.profile" + echo "4. 編輯 ~/.bashrc" + echo "5. 編輯 ~/.profile" + echo "6. 重新加載環境變量(source)" + echo "--------------------------------------" + echo "0. 返回上一級選單" + echo "--------------------------------------" + read -rp "請選擇操作:" choice + + case "$choice" in + 1) + show_env_vars + ;; + 2) + view_file "$BASHRC" + ;; + 3) + view_file "$PROFILE" + ;; + 4) + edit_file "$BASHRC" + ;; + 5) + edit_file "$PROFILE" + ;; + 6) + source_files + ;; + 0) + break + ;; + *) + echo "無效選項" + sleep 1 + ;; + esac + done +} + + +create_user_with_sshkey() { + local new_username="$1" + local is_sudo="${2:-false}" + local sshkey_vl + + if [[ -z "$new_username" ]]; then + echo "用法:create_user_with_sshkey <用戶名>" + return 1 + fi + + # 創建用戶 + useradd -m -s /bin/bash "$new_username" || return 1 + + echo "導入公鑰範例:" + echo " - URL: ${gh_https_url}github.com/torvalds.keys" + echo "- 直接粘貼: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "請導入${new_username}的公鑰:" sshkey_vl + + case "$sshkey_vl" in + http://*|https://*) + send_stats "從 URL 導入 SSH 公鑰" + fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" + ;; + ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) + send_stats "公鑰直接導入" + import_sshkey "$sshkey_vl" "/home/$new_username" + ;; + *) + echo "錯誤:未知參數 '$sshkey_vl'" + return 1 + ;; + esac + + + # 修正權限 + chown -R "$new_username:$new_username" "/home/$new_username/.ssh" + + install sudo + + # sudo 免密 + if [[ "$is_sudo" == "true" ]]; then + cat >"/etc/sudoers.d/$new_username" <> /etc/ssh/sshd_config + passwd -l "$new_username" &>/dev/null + restart_ssh + + echo "用戶$new_username創建完成" +} + + + + + + + + + + + + + linux_Settings() { @@ -13646,7 +14291,7 @@ linux_Settings() { echo -e "系統工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}設置腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登錄密碼" - echo -e "${gl_kjlan}3. ${gl_bai}ROOT密碼登錄模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" + echo -e "${gl_kjlan}3. ${gl_bai}用戶密碼登錄模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}開放所有端口${gl_kjlan}6. ${gl_bai}修改SSH連接端口" echo -e "${gl_kjlan}7. ${gl_bai}優化DNS地址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT賬戶創建新賬戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" @@ -13658,7 +14303,7 @@ linux_Settings() { echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}ROOT私鑰登錄模式" + echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}用戶密鑰登錄模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞" echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux內核升級${gl_kjlan}28. ${gl_bai}Linux系統內核參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" @@ -13667,9 +14312,11 @@ linux_Settings() { echo -e "${gl_kjlan}33. ${gl_bai}設置系統回收站${gl_kjlan}34. ${gl_bai}系統備份與恢復" echo -e "${gl_kjlan}35. ${gl_bai}ssh遠程連接工具${gl_kjlan}36. ${gl_bai}硬盤分區管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令行歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}網卡管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${gl_bai}系統日誌管理工具${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系統變量管理工具" + echo -e "${gl_kjlan}------------------------" + echo -e "${gl_kjlan}61. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}99. ${gl_bai}重啟服務器${gl_kjlan}100. ${gl_bai}隱私與安全" echo -e "${gl_kjlan}101. ${gl_bai}k命令高級用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸載科技lion腳本" echo -e "${gl_kjlan}------------------------" @@ -13687,7 +14334,10 @@ linux_Settings() { linux_Settings fi find /usr/local/bin/ -type l -exec bash -c 'test "$(readlink -f {})" = "/usr/local/bin/k" && rm -f {}' \; - ln -s /usr/local/bin/k /usr/local/bin/$kuaijiejian + if [ "$kuaijiejian" != "k" ]; then + ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian + fi + ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 echo "快捷鍵已設置" send_stats "腳本快捷鍵已設置" break_end @@ -13702,8 +14352,7 @@ linux_Settings() { passwd ;; 3) - root_use - send_stats "root密碼模式" + clear add_sshpasswd ;; @@ -13860,16 +14509,13 @@ EOF linux_Settings fi - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" + create_user_with_sshkey $new_username true - install sudo + ssh-keygen -l -f /home/$new_username/.ssh/authorized_keys &>/dev/null && { + passwd -l root &>/dev/null + sed -i 's/^[[:space:]]*#\?[[:space:]]*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config + } - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - passwd -l root - - echo "操作已完成。" ;; @@ -13983,7 +14629,12 @@ EOF printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "用戶權限" "用戶組" "sudo權限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) - local sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") + local sudo_status + if sudo -n -lU "$username" 2>/dev/null | grep -q "(ALL) \(NOPASSWD: \)\?ALL"; then + sudo_status="Yes" + else + sudo_status="No" + fi printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" done < /etc/passwd @@ -13991,7 +14642,7 @@ EOF echo "" echo "賬戶操作" echo "------------------------" - echo "1. 創建普通賬戶 2. 創建高級賬戶" + echo "1. 創建普通用戶 2. 創建高級用戶" echo "------------------------" echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" @@ -14005,46 +14656,34 @@ EOF 1) # 提示用戶輸入新用戶名 read -e -p "請輸入新用戶名:" new_username + create_user_with_sshkey $new_username false - # 創建新用戶並設置密碼 - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - echo "操作已完成。" ;; 2) # 提示用戶輸入新用戶名 read -e -p "請輸入新用戶名:" new_username - - # 創建新用戶並設置密碼 - useradd -m -s /bin/bash "$new_username" - passwd "$new_username" - - # 賦予新用戶sudo權限 - echo "$new_username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - - install sudo - - echo "操作已完成。" + create_user_with_sshkey $new_username true ;; 3) read -e -p "請輸入用戶名:" username - # 賦予新用戶sudo權限 - echo "$username ALL=(ALL:ALL) ALL" | tee -a /etc/sudoers - install sudo + cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f + fi + sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) read -e -p "請輸入要刪除的用戶名:" username - # 刪除用戶及其主目錄 userdel -r "$username" ;; @@ -14052,6 +14691,7 @@ EOF break # 跳出循环,退出菜单 ;; esac + done ;; @@ -14580,7 +15220,23 @@ EOF linux_fav ;; + 40) + clear + net_menu + ;; + 41) + clear + log_menu + ;; + + 42) + clear + env_menu + ;; + + + 61) clear send_stats "留言板" echo "訪問科技lion官方留言板,您對腳本有任何想法歡迎留言交流!" @@ -15182,7 +15838,7 @@ echo -e "${gl_kjlan}B站:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan echo -e "${gl_kjlan}官網:${gl_bai}https://kejilion.pro/ ${gl_kjlan}導航:${gl_bai}https://dh.kejilion.pro/${gl_bai}" echo -e "${gl_kjlan}部落格:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}軟件中心:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}腳本官網:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址:${gl_bai}https://github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}腳本官網:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -15695,30 +16351,27 @@ else sshkey) - shift + + shift case "$1" in "" ) # sshkey → 交互菜單 send_stats "SSHKey 交互菜單" sshkey_panel ;; - github ) shift send_stats "從 GitHub 導入 SSH 公鑰" fetch_github_ssh_keys "$1" ;; - http://*|https://* ) send_stats "從 URL 導入 SSH 公鑰" fetch_remote_ssh_keys "$1" ;; - ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) send_stats "公鑰直接導入" import_sshkey "$1" ;; - * ) echo "錯誤:未知參數 '$1'" echo "用法:" @@ -15728,11 +16381,10 @@ else echo "k sshkey github 從 GitHub 導入 SSH 公鑰" ;; esac + ;; *) k_info ;; esac fi - - From 3a26e7933177918185255065c3b9300708cb1ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:50:19 +0800 Subject: [PATCH 0703/1285] Add command to list all models in change_model function --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 133c909a0..e5563fe2d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9683,6 +9683,7 @@ moltbot_menu() { } change_model() { + openclaw models list --all printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" From ff54a31e469077992fc9dfd6bb1165daf1b5a7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:50:54 +0800 Subject: [PATCH 0704/1285] Add command to list all models in change_model function --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index ddba48a12..c92bdbc68 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9683,6 +9683,7 @@ moltbot_menu() { } change_model() { + openclaw models list --all printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" From c9a0e2a1b6546eab9efcf6eb1b703f8ff5d38c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 17:33:12 +0800 Subject: [PATCH 0705/1285] Update menu options and add OpenClaw provider functions --- cn/kejilion.sh | 180 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e5563fe2d..d713f15ae 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9621,10 +9621,11 @@ moltbot_menu() { echo "--------------------" echo "4. 日志查看" echo "5. 换模型" - echo "6. TG输入连接码" + echo "6. 加新模型API" + echo "7. TG输入连接码" echo "--------------------" - echo "7. 更新" - echo "8. 卸载" + echo "8. 更新" + echo "9. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9682,6 +9683,163 @@ moltbot_menu() { break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== 添加自定义 OpenAI 兼容模型到 OpenClaw ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # 检查参数 + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "错误:参数不能为空!" + echo "用法: add-openclaw-provider " + return 1 + fi + + # 检查 jq + if ! command -v jq &> /dev/null; then + echo "安装 jq: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "安装 jq 失败" + return 1 + } + fi + + # 备份原文件 + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "备份: ${config_file}.bak.*" + fi + + # 使用 jq 添加或合并 provider + jq \ + --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models //= { mode: "merge", providers: {} }; + .models.mode = "merge"; + .models.providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider: $provider_name" + echo "📦 模型引用方式: $provider_name/$models_id" + echo "🔧 设置默认模型:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 重启网关:" + echo " openclaw gateway restart" + else + echo "❌ 添加失败,检查 jq 语法" + return 1 + fi + } + + # 可选:自动设置默认并重启 + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 设置默认模型并重启网关..." + openclaw config patch "{\"agents.defaults.model.primary\": \"$1/$2\"}" 2>/dev/null + start_tmux + echo "✅ 完成!当前默认模型: $1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + echo "=== 交互式添加 OpenClaw Provider ===" + + # Provider 名称 + read -rp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -rp "请输入 Provider 名称: " provider_name + done + + # Model ID + read -rp "请输入 Model ID (如: deepseek-chat): " model_id + while [[ -z "$model_id" ]]; do + echo "❌ Model ID 不能为空" + read -rp "请输入 Model ID: " model_id + done + + # Base URL + read -rp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -rp "请输入 Base URL: " base_url + done + + # API Key(隐藏输入) + read -rsp "请输入 API Key (输入不显示): " api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done + + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "确认添加?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + } + + + change_model() { openclaw models list --all printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " @@ -9692,6 +9850,10 @@ moltbot_menu() { } + + + + change_tg_bot_code() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code @@ -9728,9 +9890,10 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) update_moltbot ;; + 9) uninstall_moltbot ;; *) break ;; esac done @@ -9740,11 +9903,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" From aaf584ac41a3c02681771f149a110bc8be09ac9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 17:33:42 +0800 Subject: [PATCH 0706/1285] Add function to include custom OpenAI models --- kejilion.sh | 180 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c92bdbc68..d64831346 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9621,10 +9621,11 @@ moltbot_menu() { echo "--------------------" echo "4. 日志查看" echo "5. 换模型" - echo "6. TG输入连接码" + echo "6. 加新模型API" + echo "7. TG输入连接码" echo "--------------------" - echo "7. 更新" - echo "8. 卸载" + echo "8. 更新" + echo "9. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9682,6 +9683,163 @@ moltbot_menu() { break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== 添加自定义 OpenAI 兼容模型到 OpenClaw ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # 检查参数 + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "错误:参数不能为空!" + echo "用法: add-openclaw-provider " + return 1 + fi + + # 检查 jq + if ! command -v jq &> /dev/null; then + echo "安装 jq: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "安装 jq 失败" + return 1 + } + fi + + # 备份原文件 + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "备份: ${config_file}.bak.*" + fi + + # 使用 jq 添加或合并 provider + jq \ + --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models //= { mode: "merge", providers: {} }; + .models.mode = "merge"; + .models.providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider: $provider_name" + echo "📦 模型引用方式: $provider_name/$models_id" + echo "🔧 设置默认模型:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 重启网关:" + echo " openclaw gateway restart" + else + echo "❌ 添加失败,检查 jq 语法" + return 1 + fi + } + + # 可选:自动设置默认并重启 + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 设置默认模型并重启网关..." + openclaw config patch "{\"agents.defaults.model.primary\": \"$1/$2\"}" 2>/dev/null + start_tmux + echo "✅ 完成!当前默认模型: $1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + echo "=== 交互式添加 OpenClaw Provider ===" + + # Provider 名称 + read -rp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -rp "请输入 Provider 名称: " provider_name + done + + # Model ID + read -rp "请输入 Model ID (如: deepseek-chat): " model_id + while [[ -z "$model_id" ]]; do + echo "❌ Model ID 不能为空" + read -rp "请输入 Model ID: " model_id + done + + # Base URL + read -rp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -rp "请输入 Base URL: " base_url + done + + # API Key(隐藏输入) + read -rsp "请输入 API Key (输入不显示): " api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done + + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "确认添加?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + } + + + change_model() { openclaw models list --all printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " @@ -9692,6 +9850,10 @@ moltbot_menu() { } + + + + change_tg_bot_code() { printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code @@ -9728,9 +9890,10 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) update_moltbot ;; + 9) uninstall_moltbot ;; *) break ;; esac done @@ -9740,11 +9903,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" From 3f5fcbd1d15846292f9bd760875a9d32e15d86b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 17:58:53 +0800 Subject: [PATCH 0707/1285] Fix formatting in kejilion.sh --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d713f15ae..fd4a3a068 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9836,6 +9836,8 @@ moltbot_menu() { "$model_id" \ "$base_url" \ "$api_key" + + break_end } From a20b82f16979b502c4a83ba682c6ec29ff727df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 17:59:27 +0800 Subject: [PATCH 0708/1285] Fix formatting in kejilion.sh --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index d64831346..2fc28e49c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9836,6 +9836,8 @@ moltbot_menu() { "$model_id" \ "$base_url" \ "$api_key" + + break_end } From cdc158032efb3f76e614aa599c3d589b5bc1ee31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:29:36 +0800 Subject: [PATCH 0709/1285] Refactor jq command for adding or merging provider --- kejilion.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2fc28e49c..b9ae808e3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9720,16 +9720,16 @@ moltbot_menu() { echo "备份: ${config_file}.bak.*" fi - # 使用 jq 添加或合并 provider - jq \ - --arg prov "$provider_name" \ - --arg url "$base_url" \ - --arg key "$api_key" \ - --arg mid "$models_id" \ - ' - .models //= { mode: "merge", providers: {} }; - .models.mode = "merge"; - .models.providers[$prov] = { + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { baseUrl: $url, apiKey: $key, api: "openai-completions", @@ -9749,7 +9749,8 @@ moltbot_menu() { } ] } - ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then echo "✅ 已添加 provider: $provider_name" @@ -9772,7 +9773,7 @@ moltbot_menu() { if [[ $? -eq 0 ]]; then echo "🔄 设置默认模型并重启网关..." - openclaw config patch "{\"agents.defaults.model.primary\": \"$1/$2\"}" 2>/dev/null + openclaw models set "$1/$2" start_tmux echo "✅ 完成!当前默认模型: $1/$2" openclaw status | grep -A2 "Sessions" @@ -9843,7 +9844,10 @@ moltbot_menu() { change_model() { + echo "所有模型:" openclaw models list --all + echo "当前模型:" + openclaw models list printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" From 22bf91a41168b91a2b99a89bd5707d84f936a90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:30:05 +0800 Subject: [PATCH 0710/1285] Refactor jq command for adding or merging provider --- cn/kejilion.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fd4a3a068..ecfd3d974 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9720,16 +9720,16 @@ moltbot_menu() { echo "备份: ${config_file}.bak.*" fi - # 使用 jq 添加或合并 provider - jq \ - --arg prov "$provider_name" \ - --arg url "$base_url" \ - --arg key "$api_key" \ - --arg mid "$models_id" \ - ' - .models //= { mode: "merge", providers: {} }; - .models.mode = "merge"; - .models.providers[$prov] = { + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { baseUrl: $url, apiKey: $key, api: "openai-completions", @@ -9749,7 +9749,8 @@ moltbot_menu() { } ] } - ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then echo "✅ 已添加 provider: $provider_name" @@ -9772,7 +9773,7 @@ moltbot_menu() { if [[ $? -eq 0 ]]; then echo "🔄 设置默认模型并重启网关..." - openclaw config patch "{\"agents.defaults.model.primary\": \"$1/$2\"}" 2>/dev/null + openclaw models set "$1/$2" start_tmux echo "✅ 完成!当前默认模型: $1/$2" openclaw status | grep -A2 "Sessions" @@ -9843,7 +9844,10 @@ moltbot_menu() { change_model() { + echo "所有模型:" openclaw models list --all + echo "当前模型:" + openclaw models list printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " read model echo "切换模型为 $model" From db28848f715f7c2972ede4a260751df77b66fbef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 19:23:23 +0800 Subject: [PATCH 0711/1285] Update OpenClaw installation method in script --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ecfd3d974..ca01048db 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9869,7 +9869,9 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." - openclaw update --restart + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + openclaw gateway stop + start_tmux add_app_id echo "更新完成" break_end From 09f104ce7f840b9c4efc83c146a3df47221c1ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 19:23:52 +0800 Subject: [PATCH 0712/1285] Change OpenClaw update method to use curl --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index b9ae808e3..f71d3e87e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9869,7 +9869,9 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." - openclaw update --restart + curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + openclaw gateway stop + start_tmux add_app_id echo "更新完成" break_end From 3ec3df4aca0ae88b20447da97c63e02ae48a2554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Feb 2026 19:25:38 +0800 Subject: [PATCH 0713/1285] Update changelog for ClawdBot/Moltbot enhancements --- kejilion_sh_log.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8dbea197a..5f79d214f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1433,5 +1433,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具中新增系统变量管理工具,快速查看,编辑,刷新变量等操作, 应用市场对ClawdBot/Moltbot机器人项目的安装环境进行优化,提高安装成功率。 应用市场对ClawdBot/Moltbot机器人项目保活进行优化每分钟检测进程健康状态,如果异常自动重载。 +应用市场对ClawdBot/Moltbot机器人项目支持添加通用模型API, deepseek 硅基流动 测试有效! +应用市场对ClawdBot/Moltbot机器人项目版本更新功能进行修复。 ------------------------ From a5f96c5386ea84354afa721f545b997d91d320b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 12:12:31 +0800 Subject: [PATCH 0714/1285] Simplify OpenClaw installation command --- cn/kejilion.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ca01048db..c2e62ada1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9648,13 +9648,9 @@ moltbot_menu() { country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon + curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux add_app_id @@ -9837,7 +9833,7 @@ moltbot_menu() { "$model_id" \ "$base_url" \ "$api_key" - + break_end } @@ -9869,7 +9865,7 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux add_app_id From 641c223656ac2f2c992c2fbbaf63ad755ef540d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 12:13:05 +0800 Subject: [PATCH 0715/1285] Simplify OpenClaw installation in kejilion.sh Removed installation method options for OpenClaw and simplified the installation command. --- kejilion.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f71d3e87e..a449771e1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9648,13 +9648,9 @@ moltbot_menu() { country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon + curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux add_app_id @@ -9837,7 +9833,7 @@ moltbot_menu() { "$model_id" \ "$base_url" \ "$api_key" - + break_end } @@ -9869,7 +9865,7 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git + curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux add_app_id From 425e35aaf665730af06b4d97c5acd01eec1af87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:54:18 +0800 Subject: [PATCH 0716/1285] Enhance install_moltbot function for RHEL support Add installation steps for OpenClaw on RHEL-based systems. --- kejilion.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index a449771e1..86e1f7a15 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9645,6 +9645,18 @@ moltbot_menu() { install_moltbot() { echo "开始安装 OpenClaw..." + + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + rhel|centos|almalinux|rocky|fedora|scientific|oracle) + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + ;; + esac + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com From fef44713f85b060c6081153cc619aa1a6201c178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:55:05 +0800 Subject: [PATCH 0717/1285] Add installation steps for OpenClaw on RHEL-based systems --- cn/kejilion.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c2e62ada1..e2472a986 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9645,6 +9645,18 @@ moltbot_menu() { install_moltbot() { echo "开始安装 OpenClaw..." + + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + rhel|centos|almalinux|rocky|fedora|scientific|oracle) + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + ;; + esac + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com From 318c234b6d7aca3f67b5b222e731914196dfcfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:03:58 +0800 Subject: [PATCH 0718/1285] Refactor moltbot_menu functions and add stats logging --- cn/kejilion.sh | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e2472a986..7b94f2285 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9588,25 +9588,26 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "clawdbot/moltbot安装" - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi - } + send_stats "clawdbot/moltbot管理" - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } + show_menu() { + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - show_menu() { clear local install_status=$(get_install_status) @@ -9645,6 +9646,7 @@ moltbot_menu() { install_moltbot() { echo "开始安装 OpenClaw..." + send_stats "开始安装 OpenClaw..." if [ -f /etc/os-release ]; then . /etc/os-release @@ -9673,12 +9675,14 @@ moltbot_menu() { start_bot() { echo "启动 OpenClaw..." + send_stats "启动 OpenClaw..." start_tmux break_end } stop_bot() { echo "停止 OpenClaw..." + send_stats "停止 OpenClaw..." install tmux openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 @@ -9687,6 +9691,7 @@ moltbot_menu() { view_logs() { echo "查看 OpenClaw 日志,Ctrl+C 退出" + send_stats "查看 OpenClaw 日志" openclaw logs break_end } @@ -9793,6 +9798,7 @@ moltbot_menu() { add-openclaw-provider-interactive() { + send_stats "添加API" echo "=== 交互式添加 OpenClaw Provider ===" # Provider 名称 @@ -9852,6 +9858,7 @@ moltbot_menu() { change_model() { + send_stats "换模型" echo "所有模型:" openclaw models list --all echo "当前模型:" @@ -9869,6 +9876,7 @@ moltbot_menu() { change_tg_bot_code() { + send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code openclaw pairing approve telegram $code @@ -9877,6 +9885,7 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." + send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux @@ -9888,6 +9897,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." + send_stats "卸载 OpenClaw..." openclaw uninstall npm uninstall -g openclaw sed -i "/\b${app_id}\b/d" /home/docker/appno.txt From 1d81674d31b1e175779c3c392f08b2d08c1d30c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:05:14 +0800 Subject: [PATCH 0719/1285] Refactor moltbot_menu and add send_stats calls --- kejilion.sh | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 86e1f7a15..f76b3eda3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9588,25 +9588,26 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "clawdbot/moltbot安装" - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi - } + send_stats "clawdbot/moltbot管理" - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } + show_menu() { + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - show_menu() { clear local install_status=$(get_install_status) @@ -9645,6 +9646,7 @@ moltbot_menu() { install_moltbot() { echo "开始安装 OpenClaw..." + send_stats "开始安装 OpenClaw..." if [ -f /etc/os-release ]; then . /etc/os-release @@ -9673,12 +9675,14 @@ moltbot_menu() { start_bot() { echo "启动 OpenClaw..." + send_stats "启动 OpenClaw..." start_tmux break_end } stop_bot() { echo "停止 OpenClaw..." + send_stats "停止 OpenClaw..." install tmux openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 @@ -9687,6 +9691,7 @@ moltbot_menu() { view_logs() { echo "查看 OpenClaw 日志,Ctrl+C 退出" + send_stats "查看 OpenClaw 日志" openclaw logs break_end } @@ -9793,6 +9798,7 @@ moltbot_menu() { add-openclaw-provider-interactive() { + send_stats "添加API" echo "=== 交互式添加 OpenClaw Provider ===" # Provider 名称 @@ -9852,6 +9858,7 @@ moltbot_menu() { change_model() { + send_stats "换模型" echo "所有模型:" openclaw models list --all echo "当前模型:" @@ -9869,6 +9876,7 @@ moltbot_menu() { change_tg_bot_code() { + send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " read code openclaw pairing approve telegram $code @@ -9877,6 +9885,7 @@ moltbot_menu() { update_moltbot() { echo "更新 OpenClaw..." + send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop start_tmux @@ -9888,6 +9897,7 @@ moltbot_menu() { uninstall_moltbot() { echo "卸载 OpenClaw..." + send_stats "卸载 OpenClaw..." openclaw uninstall npm uninstall -g openclaw sed -i "/\b${app_id}\b/d" /home/docker/appno.txt From 13ee1c93678855f5dfa34a0740e983d81629e0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:41:29 +0800 Subject: [PATCH 0720/1285] Simplify dnf installation check in kejilion.sh Refactor installation check for OpenClaw to use command detection for dnf. --- cn/kejilion.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7b94f2285..d61a8b855 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9648,15 +9648,10 @@ moltbot_menu() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - rhel|centos|almalinux|rocky|fedora|scientific|oracle) - dnf update -y - dnf groupinstall -y "Development Tools" - dnf install -y cmake - ;; - esac + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake fi country=$(curl -s ipinfo.io/country) From 4df7eb8ca269cbb07c556f06381e24e192a1b0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:42:11 +0800 Subject: [PATCH 0721/1285] Refactor OpenClaw installation for dnf command check --- kejilion.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f76b3eda3..60fbedf48 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9648,15 +9648,10 @@ moltbot_menu() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - rhel|centos|almalinux|rocky|fedora|scientific|oracle) - dnf update -y - dnf groupinstall -y "Development Tools" - dnf install -y cmake - ;; - esac + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake fi country=$(curl -s ipinfo.io/country) From d87a5a8c839d3d9862363e408e8ee1f5411bc10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 09:36:33 +0800 Subject: [PATCH 0722/1285] Remove OpenClaw cron job entry during uninstallation --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d61a8b855..4fb711f0f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9895,6 +9895,7 @@ moltbot_menu() { send_stats "卸载 OpenClaw..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 31cec7b68bba30580aadc53ad9b15c892b3fec7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 09:37:17 +0800 Subject: [PATCH 0723/1285] Update kejilion.sh --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 60fbedf48..e0a85c50c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9895,6 +9895,7 @@ moltbot_menu() { send_stats "卸载 OpenClaw..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 3aee66973c7c71da1d1c14c99f2f66454d1fb9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:25:28 +0800 Subject: [PATCH 0724/1285] Fix spacing and update menu options in kejilion.sh --- cn/kejilion.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4fb711f0f..2aae5fcd1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9616,17 +9616,18 @@ moltbot_menu() { echo -e "ClawdBot > MoltBot > OpenClaw 管理" echo -e "$install_status $running_status" echo "=======================================" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" echo "--------------------" - echo "4. 日志查看" - echo "5. 换模型" - echo "6. 加新模型API" - echo "7. TG输入连接码" + echo "4. 日志查看" + echo "5. 换模型" + echo "6. 加新模型API" + echo "7. TG输入连接码" + echo "8. 编辑主配置文件" echo "--------------------" - echo "8. 更新" - echo "9. 卸载" + echo "9. 更新" + echo "10. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9914,8 +9915,12 @@ moltbot_menu() { 5) change_model ;; 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; - 8) update_moltbot ;; - 9) uninstall_moltbot ;; + 7) + install nano + nano ~/.openclaw/openclaw.json + ;; + 9) update_moltbot ;; + 10) uninstall_moltbot ;; *) break ;; esac done From 83ab8b9aacd21a70c9b32aab4d038c997f294954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:25:58 +0800 Subject: [PATCH 0725/1285] Fix case number for installing nano in script --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2aae5fcd1..e118f4327 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9915,7 +9915,7 @@ moltbot_menu() { 5) change_model ;; 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; - 7) + 8) install nano nano ~/.openclaw/openclaw.json ;; From aedd566d906c4b1a8a40f8a306c4541d77bf9c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:26:52 +0800 Subject: [PATCH 0726/1285] Fix spacing and add edit config option in menu --- kejilion.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e0a85c50c..9d4ba858c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9616,17 +9616,18 @@ moltbot_menu() { echo -e "ClawdBot > MoltBot > OpenClaw 管理" echo -e "$install_status $running_status" echo "=======================================" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" echo "--------------------" - echo "4. 日志查看" - echo "5. 换模型" - echo "6. 加新模型API" - echo "7. TG输入连接码" + echo "4. 日志查看" + echo "5. 换模型" + echo "6. 加新模型API" + echo "7. TG输入连接码" + echo "8. 编辑主配置文件" echo "--------------------" - echo "8. 更新" - echo "9. 卸载" + echo "9. 更新" + echo "10. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9914,8 +9915,12 @@ moltbot_menu() { 5) change_model ;; 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; - 8) update_moltbot ;; - 9) uninstall_moltbot ;; + 8) + install nano + nano ~/.openclaw/openclaw.json + ;; + 9) update_moltbot ;; + 10) uninstall_moltbot ;; *) break ;; esac done From 7c97a23614c8d2338be805a0322cd646acdace55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:27:55 +0800 Subject: [PATCH 0727/1285] Send stats message before editing OpenClaw config Add a message before opening the OpenClaw configuration file. --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 9d4ba858c..250a20976 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9916,6 +9916,7 @@ moltbot_menu() { 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; 8) + send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; From 3efdd2512fe36234dc2249a1400d7ffc738b1b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:28:36 +0800 Subject: [PATCH 0728/1285] Add send_stats call before opening OpenClaw config --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e118f4327..a2bb4f05c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9916,6 +9916,7 @@ moltbot_menu() { 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; 8) + send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; From 82528e010a2b7f29cc0b62d18151c2fbf0a5a23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:29:50 +0800 Subject: [PATCH 0729/1285] Enhance ClawdBot with config file editing support Added configuration file editing feature for ClawdBot. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5f79d214f..7e2c3aaf7 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1435,5 +1435,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目保活进行优化每分钟检测进程健康状态,如果异常自动重载。 应用市场对ClawdBot/Moltbot机器人项目支持添加通用模型API, deepseek 硅基流动 测试有效! 应用市场对ClawdBot/Moltbot机器人项目版本更新功能进行修复。 +应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 ------------------------ From f89c9eb2f4ef9328950be4fcf5cad69c6cd21170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:22:34 +0800 Subject: [PATCH 0730/1285] Update plugin installation options in kejilion.sh --- cn/kejilion.sh | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a2bb4f05c..d21404e85 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -9624,10 +9624,11 @@ moltbot_menu() { echo "5. 换模型" echo "6. 加新模型API" echo "7. TG输入连接码" - echo "8. 编辑主配置文件" + echo "8. 安装插件(如:飞书)" + echo "9. 编辑主配置文件" echo "--------------------" - echo "9. 更新" - echo "10. 卸载" + echo "10. 更新" + echo "11. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9869,6 +9870,39 @@ moltbot_menu() { + install_plugin() { + # 输出推荐的实用插件列表,便于用户复制 + echo "推荐的实用插件(可直接复制名称输入):" + echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" + echo "@openclaw/matrix # 为 Matrix 协议提供消息通道集成" + echo "@openclaw/nostr # 支持 Nostr 协议的消息通道" + echo "@adongguo/openclaw-dingtalk # 集成钉钉消息通道" + echo "@openclaw/msteams # 添加 Microsoft Teams 支持" + + # 提示用户输入插件名称 + echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件): " + read plugin_name + + # 验证输入是否为空 + if [ -z "$plugin_name" ]; then + echo "错误:插件名称不能为空。请重试。" + return 1 + fi + + # 执行安装命令 + echo "正在安装插件:$plugin_name" + openclaw plugins install "$plugin_name" + + # 检查命令执行结果 + if [ $? -eq 0 ]; then + echo "插件 $plugin_name 安装成功。请重启 OpenClaw Gateway 服务(命令:openclaw gateway --restart)以应用更改。" + else + echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" + fi + break_end + } + + change_tg_bot_code() { @@ -9915,13 +9949,14 @@ moltbot_menu() { 5) change_model ;; 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; - 8) + 8) install_plugin ;; + 9) send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; - 9) update_moltbot ;; - 10) uninstall_moltbot ;; + 10) update_moltbot ;; + 11) uninstall_moltbot ;; *) break ;; esac done From c858885456911d4b60e9ca0a2cc8436b0fface49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:23:26 +0800 Subject: [PATCH 0731/1285] Update version and add plugin installation feature --- kejilion.sh | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 250a20976..72a6e7480 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -9624,10 +9624,11 @@ moltbot_menu() { echo "5. 换模型" echo "6. 加新模型API" echo "7. TG输入连接码" - echo "8. 编辑主配置文件" + echo "8. 安装插件(如:飞书)" + echo "9. 编辑主配置文件" echo "--------------------" - echo "9. 更新" - echo "10. 卸载" + echo "10. 更新" + echo "11. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9869,6 +9870,39 @@ moltbot_menu() { + install_plugin() { + # 输出推荐的实用插件列表,便于用户复制 + echo "推荐的实用插件(可直接复制名称输入):" + echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" + echo "@openclaw/matrix # 为 Matrix 协议提供消息通道集成" + echo "@openclaw/nostr # 支持 Nostr 协议的消息通道" + echo "@adongguo/openclaw-dingtalk # 集成钉钉消息通道" + echo "@openclaw/msteams # 添加 Microsoft Teams 支持" + + # 提示用户输入插件名称 + echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件): " + read plugin_name + + # 验证输入是否为空 + if [ -z "$plugin_name" ]; then + echo "错误:插件名称不能为空。请重试。" + return 1 + fi + + # 执行安装命令 + echo "正在安装插件:$plugin_name" + openclaw plugins install "$plugin_name" + + # 检查命令执行结果 + if [ $? -eq 0 ]; then + echo "插件 $plugin_name 安装成功。请重启 OpenClaw Gateway 服务(命令:openclaw gateway --restart)以应用更改。" + else + echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" + fi + break_end + } + + change_tg_bot_code() { @@ -9915,13 +9949,14 @@ moltbot_menu() { 5) change_model ;; 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; - 8) + 8) install_plugin ;; + 9) send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; - 9) update_moltbot ;; - 10) uninstall_moltbot ;; + 10) update_moltbot ;; + 11) uninstall_moltbot ;; *) break ;; esac done From 7b38ae3f28673d0b2215280b0fbd523ea4905aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:25:01 +0800 Subject: [PATCH 0732/1285] Enhance plugin installation function with recommendations Add plugin installation recommendations and success messages. --- kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 72a6e7480..eadc5fd0f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9871,6 +9871,8 @@ moltbot_menu() { install_plugin() { + + send_stats "安装插件" # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" @@ -9899,12 +9901,11 @@ moltbot_menu() { else echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" fi + break_end } - - change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " From 4c064a861dedc4d999f665218db1aaa2708574c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:25:42 +0800 Subject: [PATCH 0733/1285] Send stats when installing plugins Add a message to send statistics when installing plugins. --- cn/kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d21404e85..581e43eb1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9871,6 +9871,8 @@ moltbot_menu() { install_plugin() { + + send_stats "安装插件" # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" @@ -9899,12 +9901,11 @@ moltbot_menu() { else echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" fi + break_end } - - change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " From 4a9449409b3b6eb77081c7953749430195229741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:27:36 +0800 Subject: [PATCH 0734/1285] Enhance ClawdBot/Moltbot with config editing and plugin install Added support for editing configuration files directly with nano and installed Feishu plugin. --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 7e2c3aaf7..830cf0d32 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1437,4 +1437,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目版本更新功能进行修复。 应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 ------------------------ +2026-02-3 v4.3.8 +应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 +应用市场对ClawdBot/Moltbot机器人项目版增安装插件功能,可以安装飞书插件了。 +------------------------ From 72fdcf7aa173952377b5b90ba4078cf725cca514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:33:54 +0800 Subject: [PATCH 0735/1285] Update success message for plugin installation Remove instruction to restart OpenClaw Gateway after plugin installation. --- cn/kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 581e43eb1..09d915846 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9894,10 +9894,11 @@ moltbot_menu() { # 执行安装命令 echo "正在安装插件:$plugin_name" openclaw plugins install "$plugin_name" + start_tmux # 检查命令执行结果 if [ $? -eq 0 ]; then - echo "插件 $plugin_name 安装成功。请重启 OpenClaw Gateway 服务(命令:openclaw gateway --restart)以应用更改。" + echo "插件 $plugin_name 安装成功。" else echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" fi From 83d6221779c01204df77a1e544bd5a49d9fdff70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:34:29 +0800 Subject: [PATCH 0736/1285] Simplify success message for plugin installation Remove instruction to restart OpenClaw Gateway after plugin installation. --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index eadc5fd0f..cda3bde1a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9894,10 +9894,11 @@ moltbot_menu() { # 执行安装命令 echo "正在安装插件:$plugin_name" openclaw plugins install "$plugin_name" + start_tmux # 检查命令执行结果 if [ $? -eq 0 ]; then - echo "插件 $plugin_name 安装成功。请重启 OpenClaw Gateway 服务(命令:openclaw gateway --restart)以应用更改。" + echo "插件 $plugin_name 安装成功。" else echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" fi From 9337d15f5112ca3cf3fc5022908867408219d5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:54:14 +0800 Subject: [PATCH 0737/1285] Update installation options for skills and plugins --- cn/kejilion.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 09d915846..d9bf7bb32 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9625,10 +9625,11 @@ moltbot_menu() { echo "6. 加新模型API" echo "7. TG输入连接码" echo "8. 安装插件(如:飞书)" - echo "9. 编辑主配置文件" + echo "9. 安装技能(skills)" + echo "10. 编辑主配置文件" echo "--------------------" - echo "10. 更新" - echo "11. 卸载" + echo "11. 更新" + echo "12. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9873,6 +9874,9 @@ moltbot_menu() { install_plugin() { send_stats "安装插件" + + echo "所有插件" + openclaw plugins list # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" @@ -9907,6 +9911,46 @@ moltbot_menu() { } + install_skill() { + send_stats "安装技能" + + echo "所有技能" + openclaw skills list + # 输出推荐的实用技能列表,便于用户复制 + echo "推荐的实用技能(可直接复制名称输入):" + echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" + echo "notion-integration # 操作 Notion 数据库和页面" + echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" + echo "home-assistant # 通过 Home Assistant Hub 控制智能家居" + echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" + + # 提示用户输入技能名称 + echo -n "请输入要安装的技能名称(例如:github-integration): " + read skill_name + + # 验证输入是否为空 + if [ -z "$skill_name" ]; then + echo "错误:技能名称不能为空。请重试。" + return 1 + fi + + # 执行安装命令 + echo "正在安装技能:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # 检查命令执行结果 + if [ $? -eq 0 ]; then + echo "技能 $skill_name 安装成功。" + else + echo "安装失败。请检查技能名称是否正确,或参考 OpenClaw 文档排查问题。" + fi + + break_end + } + + + change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " @@ -9952,13 +9996,14 @@ moltbot_menu() { 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; 8) install_plugin ;; - 9) + 9) install_skill ;; + 10) send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; - 10) update_moltbot ;; - 11) uninstall_moltbot ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done From f8bdc0e6e66f92a5ebcec68285e513f1c7cbe9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:54:54 +0800 Subject: [PATCH 0738/1285] Update menu options and add skill installation function --- kejilion.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index cda3bde1a..3e64275bb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9625,10 +9625,11 @@ moltbot_menu() { echo "6. 加新模型API" echo "7. TG输入连接码" echo "8. 安装插件(如:飞书)" - echo "9. 编辑主配置文件" + echo "9. 安装技能(skills)" + echo "10. 编辑主配置文件" echo "--------------------" - echo "10. 更新" - echo "11. 卸载" + echo "11. 更新" + echo "12. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -9873,6 +9874,9 @@ moltbot_menu() { install_plugin() { send_stats "安装插件" + + echo "所有插件" + openclaw plugins list # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" @@ -9907,6 +9911,46 @@ moltbot_menu() { } + install_skill() { + send_stats "安装技能" + + echo "所有技能" + openclaw skills list + # 输出推荐的实用技能列表,便于用户复制 + echo "推荐的实用技能(可直接复制名称输入):" + echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" + echo "notion-integration # 操作 Notion 数据库和页面" + echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" + echo "home-assistant # 通过 Home Assistant Hub 控制智能家居" + echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" + + # 提示用户输入技能名称 + echo -n "请输入要安装的技能名称(例如:github-integration): " + read skill_name + + # 验证输入是否为空 + if [ -z "$skill_name" ]; then + echo "错误:技能名称不能为空。请重试。" + return 1 + fi + + # 执行安装命令 + echo "正在安装技能:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # 检查命令执行结果 + if [ $? -eq 0 ]; then + echo "技能 $skill_name 安装成功。" + else + echo "安装失败。请检查技能名称是否正确,或参考 OpenClaw 文档排查问题。" + fi + + break_end + } + + + change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " @@ -9952,13 +9996,14 @@ moltbot_menu() { 6) add-openclaw-provider-interactive ;; 7) change_tg_bot_code ;; 8) install_plugin ;; - 9) + 9) install_skill ;; + 10) send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json ;; - 10) update_moltbot ;; - 11) uninstall_moltbot ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done From 00bcd7224119833883bd26a829506f8ddd90b93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:56:28 +0800 Subject: [PATCH 0739/1285] Update ClawdBot/Moltbot with skill installation feature Added skill installation feature to ClawdBot/Moltbot. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 830cf0d32..759477e5e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1440,5 +1440,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-02-3 v4.3.8 应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 应用市场对ClawdBot/Moltbot机器人项目版增安装插件功能,可以安装飞书插件了。 +应用市场对ClawdBot/Moltbot机器人项目版增安装技能功能。 ------------------------ From 64f24c838711bbc47fef9520c5cd4b080b991c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:07:46 +0800 Subject: [PATCH 0740/1285] Update prompts to include exit option for user inputs --- cn/kejilion.sh | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d9bf7bb32..b5d387d03 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9861,8 +9861,21 @@ moltbot_menu() { openclaw models list --all echo "当前模型:" openclaw models list - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " read model + + # 检查是否输入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 验证输入是否为空 + if [ -z "$model" ]; then + echo "错误:模型名称不能为空。请重试。" + return 1 + fi + echo "切换模型为 $model" openclaw models set "$model" break_end @@ -9886,9 +9899,14 @@ moltbot_menu() { echo "@openclaw/msteams # 添加 Microsoft Teams 支持" # 提示用户输入插件名称 - echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件): " + echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " read plugin_name + if [ "$plugin_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + # 验证输入是否为空 if [ -z "$plugin_name" ]; then echo "错误:插件名称不能为空。请重试。" @@ -9925,9 +9943,14 @@ moltbot_menu() { echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" # 提示用户输入技能名称 - echo -n "请输入要安装的技能名称(例如:github-integration): " + echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " read skill_name + if [ "$skill_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + # 验证输入是否为空 if [ -z "$skill_name" ]; then echo "错误:技能名称不能为空。请重试。" @@ -9953,8 +9976,21 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" - printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " + printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " read code + + # 检查是否输入 0 以退出 + if [ "$code" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 验证输入是否为空 + if [ -z "$code" ]; then + echo "错误:连接码不能为空。请重试。" + return 1 + fi + openclaw pairing approve telegram $code break_end } From 2abb7aac768b2685e46e426b723c6d660e8388c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:08:33 +0800 Subject: [PATCH 0741/1285] Update prompts to include exit option for user inputs --- kejilion.sh | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3e64275bb..cab578203 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9861,8 +9861,21 @@ moltbot_menu() { openclaw models list --all echo "当前模型:" openclaw models list - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o): " + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " read model + + # 检查是否输入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 验证输入是否为空 + if [ -z "$model" ]; then + echo "错误:模型名称不能为空。请重试。" + return 1 + fi + echo "切换模型为 $model" openclaw models set "$model" break_end @@ -9886,9 +9899,14 @@ moltbot_menu() { echo "@openclaw/msteams # 添加 Microsoft Teams 支持" # 提示用户输入插件名称 - echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件): " + echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " read plugin_name + if [ "$plugin_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + # 验证输入是否为空 if [ -z "$plugin_name" ]; then echo "错误:插件名称不能为空。请重试。" @@ -9925,9 +9943,14 @@ moltbot_menu() { echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" # 提示用户输入技能名称 - echo -n "请输入要安装的技能名称(例如:github-integration): " + echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " read skill_name + if [ "$skill_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + # 验证输入是否为空 if [ -z "$skill_name" ]; then echo "错误:技能名称不能为空。请重试。" @@ -9953,8 +9976,21 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" - printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F: " + printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " read code + + # 检查是否输入 0 以退出 + if [ "$code" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 验证输入是否为空 + if [ -z "$code" ]; then + echo "错误:连接码不能为空。请重试。" + return 1 + fi + openclaw pairing approve telegram $code break_end } From a2232e6a20676c2994dc5b9a938c9d5a4735a1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:25:20 +0800 Subject: [PATCH 0742/1285] Remove redundant openclaw gateway stop calls --- cn/kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b5d387d03..4e9eae5cf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9639,6 +9639,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9663,7 +9664,6 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop start_tmux add_app_id break_end @@ -9681,7 +9681,6 @@ moltbot_menu() { stop_bot() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." - install tmux openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end From 05a11d690aa9b44e1bd518e7b068d1a58e8941a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:26:13 +0800 Subject: [PATCH 0743/1285] Add openclaw gateway stop command in start and stop functions --- kejilion.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index cab578203..fcede878d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9639,6 +9639,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9663,7 +9664,6 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop start_tmux add_app_id break_end @@ -9681,7 +9681,6 @@ moltbot_menu() { stop_bot() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." - install tmux openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end From c4780c593957453a81e6e59b0229036b4d9559d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:56:11 +0800 Subject: [PATCH 0744/1285] Update kejilion.sh --- cn/kejilion.sh | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4e9eae5cf..2be60c3dc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9590,6 +9590,32 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" + check_openclaw_update() { + # 先检查 NPM 是否可用 + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # 使用 NPM 查询本地版本,并去除前缀(如 openclaw@) + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # 使用 NPM 查询远程版本 + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}检测到新版本: $remote_version${gl_bai}" + else + echo "${gl_lv}当前版本已是最新: $local_version${gl_bai}" + fi + } + + show_menu() { get_install_status() { @@ -9612,9 +9638,11 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw 管理" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" echo "2. 启动" From 75e39da20ee68bbd0832ca3183eb117c900c6c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:57:04 +0800 Subject: [PATCH 0745/1285] Update kejilion.sh --- kejilion.sh | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index fcede878d..291cad35c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9590,6 +9590,32 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" + check_openclaw_update() { + # 先检查 NPM 是否可用 + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # 使用 NPM 查询本地版本,并去除前缀(如 openclaw@) + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # 使用 NPM 查询远程版本 + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}检测到新版本: $remote_version${gl_bai}" + else + echo "${gl_lv}当前版本已是最新: $local_version${gl_bai}" + fi + } + + show_menu() { get_install_status() { @@ -9612,9 +9638,11 @@ moltbot_menu() { local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw 管理" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" echo "2. 启动" From 8f1738223b1b056f5e46e33327dc95ec31cd6a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:10:53 +0800 Subject: [PATCH 0746/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 291cad35c..2fa1564e6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9609,9 +9609,9 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本: $remote_version${gl_bai}" + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}当前版本已是最新: $local_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } From 4d409e23d74eab5ac4efc6deb948995817d1a00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:11:35 +0800 Subject: [PATCH 0747/1285] Remove spaces in version check messages --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2be60c3dc..999ae9899 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9609,9 +9609,9 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本: $remote_version${gl_bai}" + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}当前版本已是最新: $local_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } From 35f5402c8dadb90009d0401b4a7d31c3cc24130e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:13:16 +0800 Subject: [PATCH 0748/1285] Add version detection reminder feature to ClawdBot Added a new feature for version detection reminders in the ClawdBot/Moltbot project. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 759477e5e..45d00b119 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1441,5 +1441,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 应用市场对ClawdBot/Moltbot机器人项目版增安装插件功能,可以安装飞书插件了。 应用市场对ClawdBot/Moltbot机器人项目版增安装技能功能。 +应用市场对ClawdBot/Moltbot机器人项目加入新版本检测提醒功能。 ------------------------ From b6c22e8dc25bb6f3155dbd591fd18ecc9c3b7d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:24:19 +0800 Subject: [PATCH 0749/1285] Refactor installation and running status functions --- cn/kejilion.sh | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 999ae9899..0e30d7bde 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9615,24 +9615,24 @@ moltbot_menu() { fi } + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } - show_menu() { + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi - } + show_menu() { - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } clear @@ -10040,6 +10040,7 @@ moltbot_menu() { openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 0246ddba91b7ba0e6967eff1dd062fdf14376f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:25:33 +0800 Subject: [PATCH 0750/1285] Refactor installation and running status functions --- kejilion.sh | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2fa1564e6..617ef8e82 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9615,24 +9615,24 @@ moltbot_menu() { fi } + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } - show_menu() { + get_running_status() { + if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi + } - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi - } + show_menu() { - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } clear @@ -10040,6 +10040,7 @@ moltbot_menu() { openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" break_end From 4b7529758ddf660b1ed3690e8fb12b1f1b3b4a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:27:06 +0800 Subject: [PATCH 0751/1285] Fix uninstalled ClawdBot/Moltbot display issue Fixed issue where uninstalled ClawdBot/Moltbot still showed as installed. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 45d00b119..d50381d8c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1442,5 +1442,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目版增安装插件功能,可以安装飞书插件了。 应用市场对ClawdBot/Moltbot机器人项目版增安装技能功能。 应用市场对ClawdBot/Moltbot机器人项目加入新版本检测提醒功能。 +应用市场对ClawdBot/Moltbot机器人项目修复了卸载后仍然显示已安装的问题。 ------------------------ From 4dcb19939c6c0648ffbf3e39e50980ad474e8d03 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 4 Feb 2026 04:42:06 +0000 Subject: [PATCH 0752/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-04=2004:42:06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 419 +++++++++++++++++++++++++++++++++---- jp/kejilion.sh | 551 +++++++++++++++++++++++++++++++++++++++---------- kr/kejilion.sh | 491 ++++++++++++++++++++++++++++++++++++------- tw/kejilion.sh | 395 ++++++++++++++++++++++++++++++++--- 4 files changed, 1594 insertions(+), 262 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 183b4c992..44cd6893e 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3523,7 +3523,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -5005,7 +5005,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -6054,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6317,9 +6317,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6361,7 +6361,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6782,7 +6782,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6989,7 +6989,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -7207,7 +7207,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -7842,7 +7842,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8209,7 +8209,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9588,7 +9588,33 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "clawdbot/moltbot installation" + send_stats "clawdbot/moltbot management" + + check_openclaw_update() { + # First check if NPM is available + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # Use NPM to query the local version and remove the prefix (such as openclaw@) + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # Query remote versions using NPM + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}New version detected:$remote_version${gl_bai}" + else + echo "${gl_lv}The current version is the latest:$local_version${gl_bai}" + fi + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}Installed${gl_bai}" @@ -9605,15 +9631,18 @@ moltbot_menu() { fi } - show_menu() { + + clear local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw Management" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. Installation" echo "2. Start" @@ -9621,10 +9650,14 @@ moltbot_menu() { echo "--------------------" echo "4. Log viewing" echo "5. Change model" - echo "6. Enter the connection code in TG" + echo "6. Add new model API" + echo "7. Enter the connection code in TG" + echo "8. Install plug-ins (such as Feishu)" + echo "9. Install skills" + echo "10. Edit the main configuration file" echo "--------------------" - echo "7. Update" - echo "8. Uninstall" + echo "11. Update" + echo "12. Uninstall" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" @@ -9634,6 +9667,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9644,17 +9678,20 @@ moltbot_menu() { install_moltbot() { echo "Start installing OpenClaw..." + send_stats "Start installing OpenClaw..." + + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon - openclaw gateway stop + curl -fsSL https://openclaw.ai/install.sh | bash start_tmux add_app_id break_end @@ -9663,14 +9700,15 @@ moltbot_menu() { start_bot() { - echo "Starting OpenClaw..." + echo "Start OpenClaw..." + send_stats "Start OpenClaw..." start_tmux break_end } stop_bot() { echo "Stop OpenClaw..." - install tmux + send_stats "Stop OpenClaw..." openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end @@ -9678,29 +9716,318 @@ moltbot_menu() { view_logs() { echo "View OpenClaw logs, Ctrl+C to exit" + send_stats "View OpenClaw logs" openclaw logs break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== Add custom OpenAI compatible models to OpenClaw ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # Check parameters + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "Error: Parameter cannot be empty!" + echo "Usage: add-openclaw-provider " + return 1 + fi + + # Check jq + if ! command -v jq &> /dev/null; then + echo "Install jq: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "Installation of jq failed" + return 1 + } + fi + + # Back up original files + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "Backup:${config_file}.bak.*" + fi + + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ Provider added:$provider_name" + echo "📦 Model reference method:$provider_name/$models_id" + echo "🔧 Set default model:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 Restart the gateway:" + echo " openclaw gateway restart" + else + echo "❌ Add failed, check jq syntax" + return 1 + fi + } + + # Optional: Automatically set defaults and restart + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 Set default model and restart gateway..." + openclaw models set "$1/$2" + start_tmux + echo "✅ Done! Current default model:$1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + send_stats "Add API" + echo "=== Add OpenClaw Provider interactively ===" + + # Provider name + read -rp "Please enter the Provider name (eg: deepseek):" provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider name cannot be empty" + read -rp "Please enter Provider name:" provider_name + done + + # Model ID + read -rp "Please enter Model ID (eg: deepseek-chat):" model_id + while [[ -z "$model_id" ]]; do + echo "❌ Model ID cannot be empty" + read -rp "Please enter Model ID:" model_id + done + + # Base URL + read -rp "Please enter Base URL (eg: https://api.xxx.com/v1):" base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL cannot be empty" + read -rp "Please enter Base URL:" base_url + done + + # API Key (hidden input) + read -rsp "Please enter API Key (input will not be displayed):" api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key cannot be empty" + read -rsp "Please enter API Key:" api_key + echo + done + + echo + echo "====== Confirmation ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "Confirm to add? (y/N):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ Canceled" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end + } + + + change_model() { - printf "Please enter the model name to set (e.g. openrouter/openai/gpt-4o):" + send_stats "Change model" + echo "All models:" + openclaw models list --all + echo "Current model:" + openclaw models list + printf "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" read model + + # Check if 0 is entered to exit + if [ "$model" = "0" ]; then + echo "The operation has been cancelled." + return 0 # 正常退出函数 + fi + + # Verify input is empty + if [ -z "$model" ]; then + echo "Error: Model name cannot be empty. Please try again." + return 1 + fi + echo "Switch model to$model" openclaw models set "$model" break_end } + + + install_plugin() { + + send_stats "Install plugin" + + echo "All plugins" + openclaw plugins list + # Output a list of recommended practical plug-ins for users to copy + echo "Recommended practical plug-ins (you can directly copy the name input):" + echo "@openclaw/voice-call # Enable voice call function, support Twilio integration" + echo "@openclaw/matrix # Provide message channel integration for the Matrix protocol" + echo "@openclaw/nostr # Support message channel of Nostr protocol" + echo "@adongguo/openclaw-dingtalk # Integrated DingTalk message channel" + echo "@openclaw/msteams # Add Microsoft Teams support" + + # Prompt user for plugin name + echo -n "Please enter the name of the plug-in to be installed (for example: @xzq-xu/feishu Feishu plug-in) (enter 0 to exit):" + read plugin_name + + if [ "$plugin_name" = "0" ]; then + echo "The operation has been cancelled." + return 0 # 正常退出函数 + fi + + # Verify input is empty + if [ -z "$plugin_name" ]; then + echo "Error: Plugin name cannot be empty. Please try again." + return 1 + fi + + # Execute installation command + echo "Installing plugin:$plugin_name" + openclaw plugins install "$plugin_name" + start_tmux + + # Check command execution results + if [ $? -eq 0 ]; then + echo "plug-in$plugin_nameInstallation successful." + else + echo "Installation failed. Please check that the plugin name is correct, or refer to the OpenClaw documentation to troubleshoot the issue." + fi + + break_end + } + + + install_skill() { + send_stats "Installation skills" + + echo "All skills" + openclaw skills list + # Output a list of recommended practical skills for users to copy + echo "Recommended practical skills (you can directly copy the name and enter it):" + echo "github-integration #Manage GitHub Issues and Pull Requests, support Webhook" + echo "notion-integration # Manipulate Notion database and pages" + echo "apple-notes # Manage Apple Notes for macOS/iOS" + echo "home-assistant # Control smart home via Home Assistant Hub" + echo "agent-browser # Headless browser automation using Playwright" + + # Prompt user to enter skill name + echo -n "Please enter the name of the skill to be installed (for example: github-integration) (enter 0 to exit):" + read skill_name + + if [ "$skill_name" = "0" ]; then + echo "The operation has been cancelled." + return 0 # 正常退出函数 + fi + + # Verify input is empty + if [ -z "$skill_name" ]; then + echo "Error: Skill name cannot be empty. Please try again." + return 1 + fi + + # Execute installation command + echo "Installing skills:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # Check command execution results + if [ $? -eq 0 ]; then + echo "Skill$skill_nameInstallation successful." + else + echo "Installation failed. Please check that the skill name is correct, or refer to the OpenClaw documentation to troubleshoot the issue." + fi + + break_end + } + + + change_tg_bot_code() { - printf "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F:" + send_stats "Robot docking" + printf "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F) (enter 0 to exit):" read code + + # Check if 0 is entered to exit + if [ "$code" = "0" ]; then + echo "The operation has been cancelled." + return 0 # 正常退出函数 + fi + + # Verify input is empty + if [ -z "$code" ]; then + echo "Error: Connection code cannot be empty. Please try again." + return 1 + fi + openclaw pairing approve telegram $code break_end } update_moltbot() { echo "Update OpenClaw..." - openclaw update --restart + send_stats "Update OpenClaw..." + curl -fsSL https://openclaw.ai/install.sh | bash + openclaw gateway stop + start_tmux add_app_id echo "Update completed" break_end @@ -9709,8 +10036,11 @@ moltbot_menu() { uninstall_moltbot() { echo "Uninstall OpenClaw..." + send_stats "Uninstall OpenClaw..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "Uninstall completed" break_end @@ -9727,9 +10057,17 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) install_plugin ;; + 9) install_skill ;; + 10) + send_stats "Edit the OpenClaw configuration file" + install nano + nano ~/.openclaw/openclaw.json + ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done @@ -9739,11 +10077,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" @@ -14362,7 +14695,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -15671,7 +16004,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15822,7 +16155,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 1815a9d87..a8eac2d93 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -861,12 +861,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -924,12 +924,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1189,7 +1189,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2234,8 +2234,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CFパラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2555,7 +2555,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2691,7 +2691,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3530,7 +3530,7 @@ list_stream_services() { fi for conf in "$STREAM_DIR"/*; do - # サービス名はファイル名を取得します + # サービス名がファイル名になります service_name=$(basename "$conf" .conf) # 上流ブロックでサーバーのバックエンド IP:ポートを取得します。 @@ -3620,7 +3620,7 @@ stream_panel() { send_stats "レイヤー 4 プロキシを追加する" ;; 5) - send_stats "転送設定を編集する" + send_stats "転送設定の編集" read -e -p "編集するサービス名を入力してください:" stream_name install nano nano /home/web/stream.d/$stream_name.conf @@ -4231,7 +4231,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4336,7 +4336,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5520,7 +5520,7 @@ bbrv3() { clear local kernel_version=$(uname -r) echo "xanmod の BBRv3 カーネルがインストールされている" - echo "現在のカーネル バージョン:$kernel_version" + echo "現在のカーネルのバージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5678,7 +5678,7 @@ elrepo() { clear kernel_version=$(uname -r) echo "elrepo カーネルがインストールされています" - echo "現在のカーネル バージョン:$kernel_version" + echo "現在のカーネルのバージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5719,7 +5719,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6027,7 +6027,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -6054,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6144,7 +6144,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6317,9 +6317,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6361,7 +6361,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6449,7 +6449,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -6649,9 +6649,9 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションのマウント +# パーティションをマウントする mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION # パーティションが存在するかどうかを確認する @@ -6670,7 +6670,7 @@ mount_partition() { MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションのマウント + # パーティションをマウントする mount "/dev/$PARTITION" "$MOUNT_POINT" if [ $? -eq 0 ]; then @@ -6782,7 +6782,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6801,7 +6801,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -6830,7 +6830,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -6989,7 +6989,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモート ホストにアクセスできますか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -6998,7 +6998,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7088,7 +7088,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter キーを押して続行します..." done } @@ -7150,7 +7150,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7207,7 +7207,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7271,7 +7271,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7331,7 +7331,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7389,7 +7389,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncdu をインストールする" + send_stats "ncduをインストールする" ;; 14) clear @@ -7643,7 +7643,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -7728,7 +7728,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -7810,7 +7810,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -7842,7 +7842,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7916,7 +7916,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7960,7 +7960,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8059,7 +8059,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9588,7 +9588,33 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "Clawdbot/moltbot のインストール" + send_stats "クロードボット/モルトボットの管理" + + check_openclaw_update() { + # まず、NPM が利用可能かどうかを確認します + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # NPM を使用してローカル バージョンをクエリし、プレフィックス (openclaw@ など) を削除します。 + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # NPM を使用してリモート バージョンをクエリする + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}新しいバージョンが検出されました:$remote_version${gl_bai}" + else + echo "${gl_lv}現在のバージョンは最新です:$local_version${gl_bai}" + fi + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}インストール済み${gl_bai}" @@ -9605,15 +9631,18 @@ moltbot_menu() { fi } - show_menu() { + + clear local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw 管理" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. インストール" echo "2.スタート" @@ -9621,10 +9650,14 @@ moltbot_menu() { echo "--------------------" echo "4. ログの閲覧" echo "5.機種変更" - echo "6. TGに接続コードを入力します" + echo "6. 新しいモデル API を追加する" + echo "7. TGに接続コードを入力します" + echo "8. プラグイン(Feishuなど)をインストールする" + echo "9. スキルのインストール" + echo "10. メイン設定ファイルを編集します" echo "--------------------" - echo "7.アップデート" - echo "8. アンインストール" + echo "11. アップデート" + echo "12. アンインストール" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -9634,6 +9667,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9644,17 +9678,20 @@ moltbot_menu() { install_moltbot() { echo "OpenClaw のインストールを開始します..." + send_stats "OpenClaw のインストールを開始します..." + + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon - openclaw gateway stop + curl -fsSL https://openclaw.ai/install.sh | bash start_tmux add_app_id break_end @@ -9663,14 +9700,15 @@ moltbot_menu() { start_bot() { - echo "OpenClaw を開始しています..." + echo "OpenClaw を開始します..." + send_stats "OpenClaw を開始します..." start_tmux break_end } stop_bot() { echo "OpenClaw を停止します..." - install tmux + send_stats "OpenClaw を停止します..." openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end @@ -9678,29 +9716,318 @@ moltbot_menu() { view_logs() { echo "OpenClaw ログを表示し、Ctrl+C を押して終了します" + send_stats "OpenClaw ログを表示する" openclaw logs break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== OpenAI 互換のカスタム モデルを OpenClaw に追加 ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # パラメータをチェックする + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "エラー: パラメータを空にすることはできません。" + echo "使用法: add-openclaw-provider <プロバイダー> <モデル ID> <ベース URL> " + return 1 + fi + + # jqをチェックする + if ! command -v jq &> /dev/null; then + echo "jq をインストールします: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "jqのインストールに失敗しました" + return 1 + } + fi + + # 元のファイルをバックアップする + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "バックアップ:${config_file}.bak.*" + fi + + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ プロバイダーが追加しました:$provider_name" + echo "📦 モデル参照方法:$provider_name/$models_id" + echo "🔧 デフォルトのモデルを設定します:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 ゲートウェイを再起動します。" + echo " openclaw gateway restart" + else + echo "❌ 追加に失敗しました。jq 構文を確認してください" + return 1 + fi + } + + # オプション: 自動的にデフォルトを設定して再起動します + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." + openclaw models set "$1/$2" + start_tmux + echo "✅完了!現在のデフォルトモデル:$1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + send_stats "APIの追加" + echo "=== OpenClaw プロバイダーを対話的に追加します ===" + + # プロバイダ名 + read -rp "プロバイダー名を入力してください (例: deepseek):" provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ プロバイダー名を空にすることはできません" + read -rp "プロバイダー名を入力してください:" provider_name + done + + # Model ID + read -rp "モデル ID を入力してください (例: deepseek-chat):" model_id + while [[ -z "$model_id" ]]; do + echo "❌ モデル ID を空にすることはできません" + read -rp "モデルIDを入力してください:" model_id + done + + # Base URL + read -rp "ベース URL (例: https://api.xxx.com/v1) を入力してください:" base_url + while [[ -z "$base_url" ]]; do + echo "❌ ベース URL を空にすることはできません" + read -rp "ベース URL を入力してください:" base_url + done + + # API キー (隠し入力) + read -rsp "API キーを入力してください (入力は表示されません):" api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API キーを空にすることはできません" + read -rsp "API キーを入力してください:" api_key + echo + done + + echo + echo "====== 確認 ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "追加を確認しますか? (y/N):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ キャンセルされました" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end + } + + + change_model() { - printf "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o):" + send_stats "機種変更" + echo "すべてのモデル:" + openclaw models list --all + echo "現在のモデル:" + openclaw models list + printf "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" read model + + # 終了するには0が入力されているかどうかを確認してください + if [ "$model" = "0" ]; then + echo "操作はキャンセルされました。" + return 0 # 正常退出函数 + fi + + # 入力が空であることを確認してください + if [ -z "$model" ]; then + echo "エラー: モデル名を空にすることはできません。もう一度試してください。" + return 1 + fi + echo "モデルを次のように切り替えます$model" openclaw models set "$model" break_end } + + + install_plugin() { + + send_stats "プラグインのインストール" + + echo "すべてのプラグイン" + openclaw plugins list + # ユーザーがコピーできる推奨実用プラグインのリストを出力します + echo "推奨される実用的なプラグイン (名前入力を直接コピーできます):" + echo "@openclaw/voice-call # 音声通話機能を有効にし、Twilio 統合をサポートします" + echo "@openclaw/matrix # Matrix プロトコルのメッセージ チャネル統合を提供します" + echo "@openclaw/nostr # Nostr プロトコルのメッセージ チャネルをサポート" + echo "@adongguo/openclaw-dingtalk # 統合された DingTalk メッセージ チャネル" + echo "@openclaw/msteams # Microsoft Teams サポートを追加" + + # ユーザーにプラグイン名の入力を求めるプロンプト + echo -n "インストールするプラグインの名前を入力してください (例: @xzq-xu/feishu Feishu プラグイン) (終了するには 0 を入力します):" + read plugin_name + + if [ "$plugin_name" = "0" ]; then + echo "操作はキャンセルされました。" + return 0 # 正常退出函数 + fi + + # 入力が空であることを確認してください + if [ -z "$plugin_name" ]; then + echo "エラー: プラグイン名を空にすることはできません。もう一度試してください。" + return 1 + fi + + # インストールコマンドを実行する + echo "プラグインのインストール:$plugin_name" + openclaw plugins install "$plugin_name" + start_tmux + + # コマンドの実行結果を確認する + if [ $? -eq 0 ]; then + echo "プラグイン$plugin_nameインストールが成功しました。" + else + echo "インストールに失敗しました。プラグイン名が正しいことを確認するか、OpenClaw のドキュメントを参照して問題のトラブルシューティングを行ってください。" + fi + + break_end + } + + + install_skill() { + send_stats "取り付けスキル" + + echo "すべてのスキル" + openclaw skills list + # ユーザーが真似できる推奨実践スキルリストを出力 + echo "推奨される実践スキル (名前を直接コピーして入力できます):" + echo "github-integration #GitHub の問題とプル リクエストの管理、Webhook のサポート" + echo "notion-integration # Notion データベースとページを操作する" + echo "apple-notes # macOS/iOS 用の Apple Notes を管理する" + echo "home-assist # ホーム アシスタント ハブ経由でスマート ホームを制御" + echo "Agent-Browser # Playwright を使用したヘッドレス ブラウザ自動化" + + # ユーザーにスキル名の入力を求める + echo -n "インストールするスキルの名前を入力してください (例: github-integration) (終了するには 0 を入力します):" + read skill_name + + if [ "$skill_name" = "0" ]; then + echo "操作はキャンセルされました。" + return 0 # 正常退出函数 + fi + + # 入力が空であることを確認してください + if [ -z "$skill_name" ]; then + echo "エラー: スキル名を空にすることはできません。もう一度試してください。" + return 1 + fi + + # インストールコマンドを実行する + echo "スキルのインストール:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # コマンドの実行結果を確認する + if [ $? -eq 0 ]; then + echo "スキル$skill_nameインストールが成功しました。" + else + echo "インストールに失敗しました。スキル名が正しいことを確認するか、OpenClaw のドキュメントを参照して問題のトラブルシューティングを行ってください。" + fi + + break_end + } + + + change_tg_bot_code() { - printf "TG ロボットが受信した接続コードを入力してください (例: ペアリング コード: NYA99R2F:" + send_stats "ロボットドッキング" + printf "TG ロボットが受信した接続コード (例: ペアリング コード: NYA99R2F) を入力してください (終了するには 0 を入力します)。" read code + + # 終了するには0が入力されているかどうかを確認してください + if [ "$code" = "0" ]; then + echo "操作はキャンセルされました。" + return 0 # 正常退出函数 + fi + + # 入力が空であることを確認してください + if [ -z "$code" ]; then + echo "エラー: 接続コードを空にすることはできません。もう一度試してください。" + return 1 + fi + openclaw pairing approve telegram $code break_end } update_moltbot() { echo "OpenClaw を更新..." - openclaw update --restart + send_stats "OpenClaw を更新..." + curl -fsSL https://openclaw.ai/install.sh | bash + openclaw gateway stop + start_tmux add_app_id echo "アップデート完了" break_end @@ -9709,8 +10036,11 @@ moltbot_menu() { uninstall_moltbot() { echo "OpenClaw をアンインストールします..." + send_stats "OpenClaw をアンインストールします..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アンインストールが完了しました" break_end @@ -9727,9 +10057,17 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) install_plugin ;; + 9) install_skill ;; + 10) + send_stats "OpenClaw 設定ファイルを編集する" + install nano + nano ~/.openclaw/openclaw.json + ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done @@ -9739,11 +10077,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" @@ -9818,7 +10151,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -9828,7 +10161,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -11647,7 +11980,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -12164,7 +12497,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12379,7 +12712,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチピクチャービデオマネージャー" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -12503,7 +12836,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -12961,7 +13294,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -13438,7 +13771,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -13947,7 +14280,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -13957,7 +14290,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -13969,7 +14302,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -13995,7 +14328,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記ログ職業】" + echo "【日記帳の職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -14020,7 +14353,7 @@ log_menu() { read -rp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -14030,7 +14363,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -14045,7 +14378,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -14133,7 +14466,7 @@ env_menu() { echo echo "===============================================" - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." } @@ -14148,7 +14481,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." } edit_file() { @@ -14164,7 +14497,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -rp "続行するには Enter キーを押してください..." + read -rp "Enter キーを押して続行します..." } while true; do @@ -14292,7 +14625,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -14367,7 +14700,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -15251,7 +15584,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -15483,7 +15816,7 @@ linux_file() { 4) # 重命名目录 read -e -p "現在のディレクトリ名を入力してください:" current_name read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前の変更に失敗しました" + mv "$current_name" "$new_name" && echo "ディレクトリ名が変更されました" || echo "名前の変更に失敗しました" send_stats "ディレクトリの名前を変更する" ;; 5) # 删除目录 @@ -15544,7 +15877,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -15564,7 +15897,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -15671,7 +16004,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15700,10 +16033,10 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -15745,7 +16078,7 @@ while true; do 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -15819,10 +16152,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16077,7 +16410,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -16091,16 +16424,16 @@ echo "ドメイン名証明書アプリケーション k ssl" echo "ドメイン名証明書の有効期限のクエリ k ssl ps" echo "docker 管理プレーン k docker" echo "docker 環境のインストール k docker install |k docker インストール" -echo "docker コンテナ管理 k docker ps |k docker コンテナ" +echo "docker容器管理 k docker ps |k docker 容器" echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 40943cc48..9f05189dd 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -1093,7 +1093,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 삭제" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1832,7 +1832,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2005,7 +2005,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2062,7 +2062,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3341,10 +3341,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3354,7 +3354,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3646,7 +3646,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -3694,7 +3694,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -5548,7 +5548,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5558,7 +5558,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -5612,7 +5612,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5701,7 +5701,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5719,7 +5719,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5755,7 +5755,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6054,7 +6054,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6261,7 +6261,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6782,7 +6782,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6989,7 +6989,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -7601,7 +7601,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -7842,7 +7842,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7875,7 +7875,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8029,7 +8029,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8390,7 +8390,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9588,7 +9588,33 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "클로드봇/몰트봇 설치" + send_stats "클로드봇/몰트봇 관리" + + check_openclaw_update() { + # 먼저 NPM을 사용할 수 있는지 확인하세요. + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # NPM을 사용하여 로컬 버전을 쿼리하고 접두사(예: openclaw@)를 제거합니다. + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # NPM을 사용하여 원격 버전 쿼리 + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}새 버전이 감지되었습니다.$remote_version${gl_bai}" + else + echo "${gl_lv}현재 버전이 최신 버전입니다.$local_version${gl_bai}" + fi + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}설치됨${gl_bai}" @@ -9605,15 +9631,18 @@ moltbot_menu() { fi } - show_menu() { + + clear local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw 관리" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 설치" echo "2. 시작" @@ -9621,10 +9650,14 @@ moltbot_menu() { echo "--------------------" echo "4. 로그 보기" echo "5. 모델 변경" - echo "6. TG에 연결 코드를 입력하세요." + echo "6. 새로운 모델 API 추가" + echo "7. TG에 연결 코드를 입력하세요." + echo "8. 플러그인 설치(예: Feishu)" + echo "9. 스킬 설치" + echo "10. 기본 구성 파일 편집" echo "--------------------" - echo "7. 업데이트" - echo "8. 제거" + echo "11. 업데이트" + echo "12. 제거" echo "--------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------" @@ -9634,6 +9667,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9643,18 +9677,21 @@ moltbot_menu() { install_moltbot() { - echo "OpenClaw 설치를 시작하세요..." + echo "OpenClaw 설치를 시작합니다..." + send_stats "OpenClaw 설치를 시작합니다..." + + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon - openclaw gateway stop + curl -fsSL https://openclaw.ai/install.sh | bash start_tmux add_app_id break_end @@ -9663,14 +9700,15 @@ moltbot_menu() { start_bot() { - echo "OpenClaw를 시작하는 중..." + echo "OpenClaw를 시작하세요..." + send_stats "OpenClaw를 시작하세요..." start_tmux break_end } stop_bot() { echo "OpenClaw를 중지하세요..." - install tmux + send_stats "OpenClaw를 중지하세요..." openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end @@ -9678,29 +9716,318 @@ moltbot_menu() { view_logs() { echo "OpenClaw 로그 보기, 종료하려면 Ctrl+C" + send_stats "OpenClaw 로그 보기" openclaw logs break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== OpenClaw에 맞춤형 OpenAI 호환 모델 추가 ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # 매개변수 확인 + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "오류: 매개변수는 비워둘 수 없습니다!" + echo "사용법: add-openclaw-provider " + return 1 + fi + + # jq를 확인하세요 + if ! command -v jq &> /dev/null; then + echo "jq 설치: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "jq 설치 실패" + return 1 + } + fi + + # 원본 파일 백업 + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "지원:${config_file}.bak.*" + fi + + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ 제공업체 추가됨:$provider_name" + echo "📦 모델 참조 방법:$provider_name/$models_id" + echo "🔧 기본 모델 설정:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 게이트웨이를 다시 시작하세요:" + echo " openclaw gateway restart" + else + echo "❌ 추가 실패. jq 구문을 확인하세요." + return 1 + fi + } + + # 선택사항: 자동으로 기본값을 설정하고 다시 시작합니다. + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." + openclaw models set "$1/$2" + start_tmux + echo "✅ 완료! 현재 기본 모델:$1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + send_stats "API 추가" + echo "=== 대화식으로 OpenClaw 공급자 추가 ===" + + # 제공자 이름 + read -rp "공급자 이름을 입력하십시오(예: deepseek):" provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ 제공업체 이름은 비워둘 수 없습니다." + read -rp "제공업체 이름을 입력하세요." provider_name + done + + # Model ID + read -rp "모델 ID를 입력하세요(예: deepseek-chat):" model_id + while [[ -z "$model_id" ]]; do + echo "❌ 모델 ID는 비워둘 수 없습니다." + read -rp "모델 ID를 입력하세요:" model_id + done + + # Base URL + read -rp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url + while [[ -z "$base_url" ]]; do + echo "❌ 기본 URL은 비워둘 수 없습니다." + read -rp "기본 URL을 입력하세요:" base_url + done + + # API 키(숨겨진 입력) + read -rsp "API 키를 입력하세요(입력은 표시되지 않습니다):" api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API 키는 비워둘 수 없습니다." + read -rsp "API 키를 입력하세요:" api_key + echo + done + + echo + echo "====== 확인 ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "추가하시겠습니까? (예/아니요):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 취소됨" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end + } + + + change_model() { - printf "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o):" + send_stats "모델 변경" + echo "모든 모델:" + openclaw models list --all + echo "현재 모델:" + openclaw models list + printf "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." read model + + # 0을 입력했는지 확인하여 종료하세요. + if [ "$model" = "0" ]; then + echo "작업이 취소되었습니다." + return 0 # 正常退出函数 + fi + + # 입력이 비어 있는지 확인 + if [ -z "$model" ]; then + echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + return 1 + fi + echo "모델을 다음으로 전환하세요.$model" openclaw models set "$model" break_end } + + + install_plugin() { + + send_stats "플러그인 설치" + + echo "모든 플러그인" + openclaw plugins list + # 사용자가 복사할 수 있는 권장 실무 플러그인 목록 출력 + echo "추천 실용 플러그인(이름 입력을 직접 복사할 수 있음):" + echo "@openclaw/voice-call # 음성 통화 기능 활성화, Twilio 통합 지원" + echo "@openclaw/matrix # Matrix 프로토콜에 대한 메시지 채널 통합 제공" + echo "@openclaw/nostr # Nostr 프로토콜의 메시지 채널 지원" + echo "@adongguo/openclaw-dingtalk # 통합된 DingTalk 메시지 채널" + echo "@openclaw/msteams # Microsoft Teams 지원 추가" + + # 사용자에게 플러그인 이름을 묻는 메시지 표시 + echo -n "설치할 플러그인의 이름을 입력하십시오(예: @xzq-xu/feishu Feishu 플러그인)(종료하려면 0 입력)." + read plugin_name + + if [ "$plugin_name" = "0" ]; then + echo "작업이 취소되었습니다." + return 0 # 正常退出函数 + fi + + # 입력이 비어 있는지 확인 + if [ -z "$plugin_name" ]; then + echo "오류: 플러그인 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + return 1 + fi + + # 설치 명령 실행 + echo "플러그인 설치:$plugin_name" + openclaw plugins install "$plugin_name" + start_tmux + + # 명령 실행 결과 확인 + if [ $? -eq 0 ]; then + echo "플러그인$plugin_name설치가 성공했습니다." + else + echo "설치에 실패했습니다. 플러그인 이름이 올바른지 확인하거나 OpenClaw 설명서를 참조하여 문제를 해결하세요." + fi + + break_end + } + + + install_skill() { + send_stats "설치 기술" + + echo "모든 기술" + openclaw skills list + # 사용자가 복사할 수 있는 권장 실무 기술 목록을 출력합니다. + echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" + echo "github-integration #GitHub 문제 및 끌어오기 요청 관리, 웹후크 지원" + echo "notion-integration # Notion 데이터베이스 및 페이지 조작" + echo "apple-notes # macOS/iOS용 Apple Notes 관리" + echo "home-assistant # 홈어시스턴트 허브를 통해 스마트 홈 제어" + echo "Agent-browser # Playwright를 사용한 헤드리스 브라우저 자동화" + + # 사용자에게 스킬 이름을 입력하라는 메시지를 표시합니다. + echo -n "설치할 스킬의 이름을 입력하세요(예: github-integration)(종료하려면 0을 입력하세요):" + read skill_name + + if [ "$skill_name" = "0" ]; then + echo "작업이 취소되었습니다." + return 0 # 正常退出函数 + fi + + # 입력이 비어 있는지 확인 + if [ -z "$skill_name" ]; then + echo "오류: 스킬 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + return 1 + fi + + # 설치 명령 실행 + echo "기술 설치:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # 명령 실행 결과 확인 + if [ $? -eq 0 ]; then + echo "기능$skill_name설치가 성공했습니다." + else + echo "설치에 실패했습니다. 스킬 이름이 올바른지 확인하거나 OpenClaw 설명서를 참조하여 문제를 해결하십시오." + fi + + break_end + } + + + change_tg_bot_code() { - printf "TG 로봇이 수신한 연결 코드를 입력하세요(예: 페어링 코드: NYA99R2F:" + send_stats "로봇 도킹" + printf "TG 로봇이 수신한 연결 코드(예: 페어링 코드: NYA99R2F)를 입력하세요(종료하려면 0 입력)." read code + + # 0을 입력했는지 확인하여 종료하세요. + if [ "$code" = "0" ]; then + echo "작업이 취소되었습니다." + return 0 # 正常退出函数 + fi + + # 입력이 비어 있는지 확인 + if [ -z "$code" ]; then + echo "오류: 연결 코드는 비워둘 수 없습니다. 다시 시도해 주세요." + return 1 + fi + openclaw pairing approve telegram $code break_end } update_moltbot() { echo "오픈클로 업데이트..." - openclaw update --restart + send_stats "오픈클로 업데이트..." + curl -fsSL https://openclaw.ai/install.sh | bash + openclaw gateway stop + start_tmux add_app_id echo "업데이트 완료" break_end @@ -9709,8 +10036,11 @@ moltbot_menu() { uninstall_moltbot() { echo "OpenClaw 제거..." + send_stats "OpenClaw 제거..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "제거가 완료되었습니다." break_end @@ -9727,9 +10057,17 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) install_plugin ;; + 9) install_skill ;; + 10) + send_stats "OpenClaw 구성 파일 편집" + install nano + nano ~/.openclaw/openclaw.json + ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done @@ -9739,11 +10077,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" @@ -9792,7 +10125,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -9820,7 +10153,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -9848,7 +10181,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}ClawdBot/Moltbot 로봇${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -10050,7 +10383,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -10182,7 +10515,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -10750,7 +11083,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -11583,7 +11916,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12164,7 +12497,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13104,7 +13437,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13453,7 +13786,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -14160,7 +14493,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드 중" + send_stats "환경 변수 다시 로드" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -14172,7 +14505,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -14291,7 +14624,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -14304,7 +14637,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -14592,7 +14925,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -14776,7 +15109,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -14844,7 +15177,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -14939,7 +15272,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -15671,7 +16004,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -15746,7 +16079,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -15819,10 +16152,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16066,7 +16399,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -16095,7 +16428,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" @@ -16105,7 +16438,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index bda1e3acc..a764ef612 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.7" +sh_v="4.3.8" gl_hui='\e[37m' @@ -9588,7 +9588,33 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "clawdbot/moltbot安裝" + send_stats "clawdbot/moltbot管理" + + check_openclaw_update() { + # 先檢查 NPM 是否可用 + if ! command -v npm >/dev/null 2>&1; then + return 1 + fi + + # 使用 NPM 查詢本地版本,並去除前綴(如 openclaw@) + local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + if [ -z "$local_version" ]; then + return 1 + fi + + # 使用 NPM 查詢遠程版本 + remote_version=$(npm view openclaw version 2>/dev/null) + if [ -z "$remote_version" ]; then + return 1 + fi + + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}檢測到新版本:$remote_version${gl_bai}" + else + echo "${gl_lv}當前版本已是最新:$local_version${gl_bai}" + fi + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}已安裝${gl_bai}" @@ -9605,26 +9631,33 @@ moltbot_menu() { fi } - show_menu() { + + clear local install_status=$(get_install_status) local running_status=$(get_running_status) + local update_message=$(check_openclaw_update) + echo "=======================================" echo -e "ClawdBot > MoltBot > OpenClaw 管理" - echo -e "$install_status $running_status" + echo -e "$install_status $running_status $update_message" echo "=======================================" - echo "1. 安裝" - echo "2. 啟動" - echo "3. 停止" + echo "1. 安裝" + echo "2. 啟動" + echo "3. 停止" echo "--------------------" - echo "4. 日誌查看" - echo "5. 換模型" - echo "6. TG輸入連接碼" + echo "4. 日誌查看" + echo "5. 換模型" + echo "6. 加新模型API" + echo "7. TG輸入連接碼" + echo "8. 安裝插件(如:飛書)" + echo "9. 安裝技能(skills)" + echo "10. 編輯主配置文件" echo "--------------------" - echo "7. 更新" - echo "8. 卸載" + echo "11. 更新" + echo "12. 卸載" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -9634,6 +9667,7 @@ moltbot_menu() { start_tmux() { install tmux + openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 tmux new -d -s gateway "openclaw gateway" check_crontab_installed @@ -9644,17 +9678,20 @@ moltbot_menu() { install_moltbot() { echo "開始安裝 OpenClaw..." + send_stats "開始安裝 OpenClaw..." + + if command -v dnf &>/dev/null; then + dnf update -y + dnf groupinstall -y "Development Tools" + dnf install -y cmake + fi + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw - source ~/.bashrc - source ~/.profile - openclaw doctor --fix - openclaw onboard --install-daemon - openclaw gateway stop + curl -fsSL https://openclaw.ai/install.sh | bash start_tmux add_app_id break_end @@ -9664,13 +9701,14 @@ moltbot_menu() { start_bot() { echo "啟動 OpenClaw..." + send_stats "啟動 OpenClaw..." start_tmux break_end } stop_bot() { echo "停止 OpenClaw..." - install tmux + send_stats "停止 OpenClaw..." openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 break_end @@ -9678,29 +9716,318 @@ moltbot_menu() { view_logs() { echo "查看 OpenClaw 日誌,Ctrl+C 退出" + send_stats "查看 OpenClaw 日誌" openclaw logs break_end } + + + add-openclaw-provider() { + local config_file="${HOME}/.openclaw/openclaw.json" + local provider_name="$1" + local models_id="$2" + local base_url="$3" + local api_key="$4" + + echo "=== 添加自定義 OpenAI 兼容模型到 OpenClaw ===" + echo "Provider: $provider_name" + echo "Model ID: $models_id" + echo "Base URL: $base_url" + echo "API Key: ${api_key:0:8}****" + + # 檢查參數 + if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then + echo "錯誤:參數不能為空​​!" + echo "用法: add-openclaw-provider " + return 1 + fi + + # 檢查 jq + if ! command -v jq &> /dev/null; then + echo "安裝 jq: apt update && apt install -y jq" + apt update && apt install -y jq || { + echo "安裝 jq 失敗" + return 1 + } + fi + + # 備份原文件 + if [[ -f "$config_file" ]]; then + cp "$config_file" "${config_file}.bak.$(date +%s)" + echo "備份:${config_file}.bak.*" + fi + + + jq --arg prov "$provider_name" \ + --arg url "$base_url" \ + --arg key "$api_key" \ + --arg mid "$models_id" \ + ' + .models |= ( + (. // { mode: "merge", providers: {} }) + | .mode = "merge" + | .providers[$prov] = { + baseUrl: $url, + apiKey: $key, + api: "openai-completions", + models: [ + { + id: $mid, + name: ($prov + " / " + $mid), + input: ["text"], + contextWindow: 131072, + maxTokens: 8192, + cost: { + input: 0.14, + output: 0.28, + cacheRead: 0, + cacheWrite: 0 + } + } + ] + } + ) + ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider:$provider_name" + echo "📦 模型引用方式:$provider_name/$models_id" + echo "🔧 設置默認模型:" + echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" + echo "🔄 重啟網關:" + echo " openclaw gateway restart" + else + echo "❌ 添加失敗,檢查 jq 語法" + return 1 + fi + } + + # 可選:自動設置默認並重啟 + add-openclaw-provider-and-switch() { + install jq + + add-openclaw-provider "$1" "$2" "$3" "$4" + + if [[ $? -eq 0 ]]; then + echo "🔄 設置默認模型並重啟網關..." + openclaw models set "$1/$2" + start_tmux + echo "✅ 完成!當前默認模型:$1/$2" + openclaw status | grep -A2 "Sessions" + fi + } + + + + + + add-openclaw-provider-interactive() { + send_stats "添加API" + echo "=== 交互式添加 OpenClaw Provider ===" + + # Provider 名稱 + read -rp "請輸入 Provider 名稱 (如: deepseek):" provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名稱不能為空" + read -rp "請輸入 Provider 名稱:" provider_name + done + + # Model ID + read -rp "請輸入 Model ID (如: deepseek-chat):" model_id + while [[ -z "$model_id" ]]; do + echo "❌ Model ID 不能為空" + read -rp "請輸入 Model ID:" model_id + done + + # Base URL + read -rp "請輸入 Base URL (如: https://api.xxx.com/v1):" base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能為空" + read -rp "請輸入 Base URL:" base_url + done + + # API Key(隱藏輸入) + read -rsp "請輸入 API Key (輸入不顯示):" api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能為空" + read -rsp "請輸入 API Key:" api_key + echo + done + + echo + echo "====== 確認信息 ======" + echo "Provider : $provider_name" + echo "Model ID : $model_id" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "======================" + + read -rp "確認添加? (y/N):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end + } + + + change_model() { - printf "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o):" + send_stats "換模型" + echo "所有模型:" + openclaw models list --all + echo "當前模型:" + openclaw models list + printf "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" read model + + # 檢查是否輸入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 驗證輸入是否為空 + if [ -z "$model" ]; then + echo "錯誤:模型名稱不能為空。請重試。" + return 1 + fi + echo "切換模型為$model" openclaw models set "$model" break_end } + + + install_plugin() { + + send_stats "安裝插件" + + echo "所有插件" + openclaw plugins list + # 輸出推薦的實用插件列表,便於用戶複製 + echo "推薦的實用插件(可直接複製名稱輸入):" + echo "@openclaw/voice-call # 啟用語音通話功能,支持 Twilio 集成" + echo "@openclaw/matrix # 為 Matrix 協議提供消息通道集成" + echo "@openclaw/nostr # 支持 Nostr 協議的消息通道" + echo "@adongguo/openclaw-dingtalk # 集成釘釘消息通道" + echo "@openclaw/msteams # 添加 Microsoft Teams 支持" + + # 提示用戶輸入插件名稱 + echo -n "請輸入要安裝的插件名稱(例如:@xzq-xu/feishu 飛書插件)(輸入 0 退出):" + read plugin_name + + if [ "$plugin_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 驗證輸入是否為空 + if [ -z "$plugin_name" ]; then + echo "錯誤:插件名稱不能為空。請重試。" + return 1 + fi + + # 執行安裝命令 + echo "正在安裝插件:$plugin_name" + openclaw plugins install "$plugin_name" + start_tmux + + # 檢查命令執行結果 + if [ $? -eq 0 ]; then + echo "插件$plugin_name安裝成功。" + else + echo "安裝失敗。請檢查插件名稱是否正確,或參考 OpenClaw 文檔排查問題。" + fi + + break_end + } + + + install_skill() { + send_stats "安裝技能" + + echo "所有技能" + openclaw skills list + # 輸出推薦的實用技能列表,便於用戶複製 + echo "推薦的實用技能(可直接複製名稱輸入):" + echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" + echo "notion-integration # 操作 Notion 數據庫和頁面" + echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" + echo "home-assistant # 通過 Home Assistant Hub 控制智能家居" + echo "agent-browser # 使用 Playwright 進行無頭瀏覽器自動化" + + # 提示用戶輸入技能名稱 + echo -n "請輸入要安裝的技能名稱(例如:github-integration)(輸入 0 退出):" + read skill_name + + if [ "$skill_name" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 驗證輸入是否為空 + if [ -z "$skill_name" ]; then + echo "錯誤:技能名稱不能為空。請重試。" + return 1 + fi + + # 執行安裝命令 + echo "正在安裝技能:$skill_name" + openclaw skills install "$skill_name" + start_tmux + + # 檢查命令執行結果 + if [ $? -eq 0 ]; then + echo "技能$skill_name安裝成功。" + else + echo "安裝失敗。請檢查技能名稱是否正確,或參考 OpenClaw 文檔排查問題。" + fi + + break_end + } + + + change_tg_bot_code() { - printf "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F:" + send_stats "機器人對接" + printf "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" read code + + # 檢查是否輸入 0 以退出 + if [ "$code" = "0" ]; then + echo "操作已取消。" + return 0 # 正常退出函数 + fi + + # 驗證輸入是否為空 + if [ -z "$code" ]; then + echo "錯誤:連接碼不能為空。請重試。" + return 1 + fi + openclaw pairing approve telegram $code break_end } update_moltbot() { echo "更新 OpenClaw..." - openclaw update --restart + send_stats "更新 OpenClaw..." + curl -fsSL https://openclaw.ai/install.sh | bash + openclaw gateway stop + start_tmux add_app_id echo "更新完成" break_end @@ -9709,8 +10036,11 @@ moltbot_menu() { uninstall_moltbot() { echo "卸載 OpenClaw..." + send_stats "卸載 OpenClaw..." openclaw uninstall npm uninstall -g openclaw + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" break_end @@ -9727,9 +10057,17 @@ moltbot_menu() { 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) change_tg_bot_code ;; - 7) update_moltbot ;; - 8) uninstall_moltbot ;; + 6) add-openclaw-provider-interactive ;; + 7) change_tg_bot_code ;; + 8) install_plugin ;; + 9) install_skill ;; + 10) + send_stats "編輯 OpenClaw 配置文件" + install nano + nano ~/.openclaw/openclaw.json + ;; + 11) update_moltbot ;; + 12) uninstall_moltbot ;; *) break ;; esac done @@ -9739,11 +10077,6 @@ moltbot_menu() { - - - - - linux_panel() { local sub_choice="$1" From d9acd9f1a851ef11150e4956b39026fc9bf56c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:06:36 +0800 Subject: [PATCH 0753/1285] Refactor OpenClaw config editing into a function --- cn/kejilion.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0e30d7bde..7539253ef 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10046,6 +10046,12 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "编辑 OpenClaw 配置文件" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } # 主循环 while true; do @@ -10061,11 +10067,7 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "编辑 OpenClaw 配置文件" - install nano - nano ~/.openclaw/openclaw.json - ;; + 10) nano_openclaw_json ;; 11) update_moltbot ;; 12) uninstall_moltbot ;; *) break ;; From 4f09d236ef19ab45839b99652290f766d8c7834a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:07:10 +0800 Subject: [PATCH 0754/1285] Refactor OpenClaw config editing into a function --- kejilion.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 617ef8e82..165d99808 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10046,6 +10046,12 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "编辑 OpenClaw 配置文件" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } # 主循环 while true; do @@ -10061,11 +10067,7 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "编辑 OpenClaw 配置文件" - install nano - nano ~/.openclaw/openclaw.json - ;; + 10) nano_openclaw_json ;; 11) update_moltbot ;; 12) uninstall_moltbot ;; *) break ;; From 3818347e5e33696cccee3462ec8107b7024e0bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:20:45 +0800 Subject: [PATCH 0755/1285] Change read prompts to use -e option for editing --- cn/kejilion.sh | 68 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7539253ef..c028cc358 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3652,20 +3652,20 @@ ldnmp_Proxy_backend_stream() { echo "开始部署 $webname" # 获取代理名称 - read -rp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name if [ -z "$proxy_name" ]; then echo "名称不能为空"; return 1 fi # 获取监听端口 - read -rp "请输入本机监听端口 (如 3306): " listen_port + read -erp "请输入本机监听端口 (如 3306): " listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "端口必须是数字"; return 1 fi echo "请选择协议类型:" echo "1. TCP 2. UDP" - read -rp "请输入序号 [1-2]: " proto_choice + read -erp "请输入序号 [1-2]: " proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -9827,24 +9827,24 @@ moltbot_menu() { echo "=== 交互式添加 OpenClaw Provider ===" # Provider 名称 - read -rp "请输入 Provider 名称 (如: deepseek): " provider_name + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider 名称不能为空" - read -rp "请输入 Provider 名称: " provider_name + read -erp "请输入 Provider 名称: " provider_name done # Model ID - read -rp "请输入 Model ID (如: deepseek-chat): " model_id + read -erp "请输入 Model ID (如: deepseek-chat): " model_id while [[ -z "$model_id" ]]; do echo "❌ Model ID 不能为空" - read -rp "请输入 Model ID: " model_id + read -erp "请输入 Model ID: " model_id done # Base URL - read -rp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL 不能为空" - read -rp "请输入 Base URL: " base_url + read -erp "请输入 Base URL: " base_url done # API Key(隐藏输入) @@ -9864,7 +9864,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "确认添加?(y/N): " confirm + read -erp "确认添加?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 已取消" return 1 @@ -9889,7 +9889,7 @@ moltbot_menu() { echo "当前模型:" openclaw models list printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read model + read -e model # 检查是否输入 0 以退出 if [ "$model" = "0" ]; then @@ -9927,7 +9927,7 @@ moltbot_menu() { # 提示用户输入插件名称 echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " - read plugin_name + read -e plugin_name if [ "$plugin_name" = "0" ]; then echo "操作已取消。" @@ -9971,7 +9971,7 @@ moltbot_menu() { # 提示用户输入技能名称 echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " - read skill_name + read -e skill_name if [ "$skill_name" = "0" ]; then echo "操作已取消。" @@ -10004,7 +10004,7 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " - read code + read -e code # 检查是否输入 0 以退出 if [ "$code" = "0" ]; then @@ -14271,32 +14271,32 @@ net_menu() { echo "4. 刷新网卡信息" echo "0. 返回上一级选单" echo "====================================" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case $choice in 1) send_stats "启用网卡" - read -rp "请输入要启用的网卡名: " nic + read -erp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 2) send_stats "禁用网卡" - read -rp "请输入要禁用的网卡名: " nic + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 3) send_stats "查看网卡详情" - read -rp "请输入要查看的网卡名: " nic + read -erp "请输入要查看的网卡名: " nic if ip link show "$nic" &>/dev/null; then echo "========== $nic 详细信息 ==========" ip addr show "$nic" @@ -14304,7 +14304,7 @@ net_menu() { else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 4) send_stats "刷新网卡信息" @@ -14347,25 +14347,25 @@ log_menu() { echo "5. 清理旧 journal 日志" echo "0. 返回上一级选单" echo "=======================================" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case $choice in 1) send_stats "查看最近日志" - read -rp "查看最近多少行日志?[默认 100]: " lines + read -erp "查看最近多少行日志?[默认 100]: " lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 2) send_stats "查看指定服务日志" - read -rp "请输入服务名(如 sshd、nginx): " svc + read -erp "请输入服务名(如 sshd、nginx): " svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ 服务不存在或无日志" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 3) send_stats "查看登录/安全日志" @@ -14380,17 +14380,17 @@ log_menu() { else echo "未找到安全日志文件" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 4) send_stats "实时跟踪日志" echo "1) 系统日志" echo "2) 指定服务日志" - read -rp "选择跟踪类型: " t + read -erp "选择跟踪类型: " t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "输入服务名: " svc + read -erp "输入服务名: " svc journalctl -u "$svc" -f else echo "无效选择" @@ -14402,7 +14402,7 @@ log_menu() { echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" echo "3) 限制日志最大 500M" - read -rp "请选择清理方式: " c + read -erp "请选择清理方式: " c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14468,7 +14468,7 @@ env_menu() { echo echo "===============================================" - read -rp "按回车继续..." + read -erp "按回车继续..." } @@ -14483,7 +14483,7 @@ env_menu() { else echo "文件不存在:$file" fi - read -rp "按回车继续..." + read -erp "按回车继续..." } edit_file() { @@ -14499,7 +14499,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 环境变量已重新加载" - read -rp "按回车继续..." + read -erp "按回车继续..." } while true; do @@ -14516,7 +14516,7 @@ env_menu() { echo "--------------------------------------" echo "0. 返回上一级选单" echo "--------------------------------------" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case "$choice" in 1) From 20817c9876f750128bd3c8360e34200da7e76afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:22:19 +0800 Subject: [PATCH 0756/1285] Change read command to use -e option for input --- kejilion.sh | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 165d99808..097d3a200 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3652,20 +3652,20 @@ ldnmp_Proxy_backend_stream() { echo "开始部署 $webname" # 获取代理名称 - read -rp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name if [ -z "$proxy_name" ]; then echo "名称不能为空"; return 1 fi # 获取监听端口 - read -rp "请输入本机监听端口 (如 3306): " listen_port + read -erp "请输入本机监听端口 (如 3306): " listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "端口必须是数字"; return 1 fi echo "请选择协议类型:" echo "1. TCP 2. UDP" - read -rp "请输入序号 [1-2]: " proto_choice + read -erp "请输入序号 [1-2]: " proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -9827,24 +9827,24 @@ moltbot_menu() { echo "=== 交互式添加 OpenClaw Provider ===" # Provider 名称 - read -rp "请输入 Provider 名称 (如: deepseek): " provider_name + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider 名称不能为空" - read -rp "请输入 Provider 名称: " provider_name + read -erp "请输入 Provider 名称: " provider_name done # Model ID - read -rp "请输入 Model ID (如: deepseek-chat): " model_id + read -erp "请输入 Model ID (如: deepseek-chat): " model_id while [[ -z "$model_id" ]]; do echo "❌ Model ID 不能为空" - read -rp "请输入 Model ID: " model_id + read -erp "请输入 Model ID: " model_id done # Base URL - read -rp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL 不能为空" - read -rp "请输入 Base URL: " base_url + read -erp "请输入 Base URL: " base_url done # API Key(隐藏输入) @@ -9864,7 +9864,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "确认添加?(y/N): " confirm + read -erp "确认添加?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 已取消" return 1 @@ -9889,7 +9889,7 @@ moltbot_menu() { echo "当前模型:" openclaw models list printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read model + read -e model # 检查是否输入 0 以退出 if [ "$model" = "0" ]; then @@ -9927,7 +9927,7 @@ moltbot_menu() { # 提示用户输入插件名称 echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " - read plugin_name + read -e plugin_name if [ "$plugin_name" = "0" ]; then echo "操作已取消。" @@ -9971,7 +9971,7 @@ moltbot_menu() { # 提示用户输入技能名称 echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " - read skill_name + read -e skill_name if [ "$skill_name" = "0" ]; then echo "操作已取消。" @@ -10004,7 +10004,7 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " - read code + read -e code # 检查是否输入 0 以退出 if [ "$code" = "0" ]; then @@ -14271,32 +14271,32 @@ net_menu() { echo "4. 刷新网卡信息" echo "0. 返回上一级选单" echo "====================================" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case $choice in 1) send_stats "启用网卡" - read -rp "请输入要启用的网卡名: " nic + read -erp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 2) send_stats "禁用网卡" - read -rp "请输入要禁用的网卡名: " nic + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 3) send_stats "查看网卡详情" - read -rp "请输入要查看的网卡名: " nic + read -erp "请输入要查看的网卡名: " nic if ip link show "$nic" &>/dev/null; then echo "========== $nic 详细信息 ==========" ip addr show "$nic" @@ -14304,7 +14304,7 @@ net_menu() { else echo "✘ 网卡不存在" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 4) send_stats "刷新网卡信息" @@ -14347,25 +14347,25 @@ log_menu() { echo "5. 清理旧 journal 日志" echo "0. 返回上一级选单" echo "=======================================" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case $choice in 1) send_stats "查看最近日志" - read -rp "查看最近多少行日志?[默认 100]: " lines + read -erp "查看最近多少行日志?[默认 100]: " lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 2) send_stats "查看指定服务日志" - read -rp "请输入服务名(如 sshd、nginx): " svc + read -erp "请输入服务名(如 sshd、nginx): " svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ 服务不存在或无日志" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 3) send_stats "查看登录/安全日志" @@ -14380,17 +14380,17 @@ log_menu() { else echo "未找到安全日志文件" fi - read -rp "按回车继续..." + read -erp "按回车继续..." ;; 4) send_stats "实时跟踪日志" echo "1) 系统日志" echo "2) 指定服务日志" - read -rp "选择跟踪类型: " t + read -erp "选择跟踪类型: " t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "输入服务名: " svc + read -erp "输入服务名: " svc journalctl -u "$svc" -f else echo "无效选择" @@ -14402,7 +14402,7 @@ log_menu() { echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" echo "3) 限制日志最大 500M" - read -rp "请选择清理方式: " c + read -erp "请选择清理方式: " c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14468,7 +14468,7 @@ env_menu() { echo echo "===============================================" - read -rp "按回车继续..." + read -erp "按回车继续..." } @@ -14483,7 +14483,7 @@ env_menu() { else echo "文件不存在:$file" fi - read -rp "按回车继续..." + read -erp "按回车继续..." } edit_file() { @@ -14499,7 +14499,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 环境变量已重新加载" - read -rp "按回车继续..." + read -erp "按回车继续..." } while true; do @@ -14516,7 +14516,7 @@ env_menu() { echo "--------------------------------------" echo "0. 返回上一级选单" echo "--------------------------------------" - read -rp "请选择操作: " choice + read -erp "请选择操作: " choice case "$choice" in 1) From 09e612e466aa01430ee176448e0ebd5b9a8dc76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:42:26 +0800 Subject: [PATCH 0757/1285] Refactor model and plugin installation functions --- cn/kejilion.sh | 211 ++++++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 88 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c028cc358..786361a02 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9884,28 +9884,41 @@ moltbot_menu() { change_model() { send_stats "换模型" - echo "所有模型:" - openclaw models list --all - echo "当前模型:" - openclaw models list - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read -e model - # 检查是否输入 0 以退出 - if [ "$model" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + while true; do + clear + echo "--- 模型管理 ---" + echo "所有模型:" + openclaw models list --all + echo "----------------" + echo "当前模型:" + openclaw models list + echo "----------------" + + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " + read -e model + + # 1. 检查是否输入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消,正在退出..." + break # 跳出 while 循环 - # 验证输入是否为空 - if [ -z "$model" ]; then - echo "错误:模型名称不能为空。请重试。" - return 1 - fi + fi + + # 2. 验证输入是否为空 + if [ -z "$model" ]; then + echo "错误:模型名称不能为空。请重试。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. 执行切换逻辑 + echo "正在切换模型为: $model ..." + openclaw models set "$model" + + break_end + done - echo "切换模型为 $model" - openclaw models set "$model" - break_end } @@ -9914,89 +9927,110 @@ moltbot_menu() { install_plugin() { send_stats "安装插件" + while true; do + clear + echo "========================================" + echo " 插件管理 (安装) " + echo "========================================" + echo "当前已安装插件:" + openclaw plugins list + echo "----------------------------------------" + + # 输出推荐的实用插件列表,便于用户复制 + echo "推荐的实用插件(可直接复制名称输入):" + echo "@openclaw/voice-call # 语音通话 (Twilio)" + echo "@openclaw/matrix # Matrix 协议" + echo "@openclaw/nostr # Nostr 协议" + echo "@adongguo/openclaw-dingtalk # 钉钉集成" + echo "@openclaw/msteams # Microsoft Teams" + echo "----------------------------------------" + + # 提示用户输入插件名称 + printf "请输入要安装的插件名称(输入 0 退出): " + read -e plugin_name + + # 1. 检查是否输入 0 以退出 + if [ "$plugin_name" = "0" ]; then + echo "操作已取消,退出插件安装。" + break + fi - echo "所有插件" - openclaw plugins list - # 输出推荐的实用插件列表,便于用户复制 - echo "推荐的实用插件(可直接复制名称输入):" - echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" - echo "@openclaw/matrix # 为 Matrix 协议提供消息通道集成" - echo "@openclaw/nostr # 支持 Nostr 协议的消息通道" - echo "@adongguo/openclaw-dingtalk # 集成钉钉消息通道" - echo "@openclaw/msteams # 添加 Microsoft Teams 支持" - - # 提示用户输入插件名称 - echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " - read -e plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi - - # 验证输入是否为空 - if [ -z "$plugin_name" ]; then - echo "错误:插件名称不能为空。请重试。" - return 1 - fi + # 2. 验证输入是否为空 + if [ -z "$plugin_name" ]; then + echo "错误:插件名称不能为空,请重新输入。" + echo "" + continue + fi - # 执行安装命令 - echo "正在安装插件:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 3. 执行安装命令 + echo "正在安装插件:$plugin_name ..." + openclaw plugins install "$plugin_name" - # 检查命令执行结果 - if [ $? -eq 0 ]; then - echo "插件 $plugin_name 安装成功。" - else - echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" - fi + # 检查命令执行结果 ($? 获取上一条命令的状态码) + if [ $? -eq 0 ]; then + echo "✅ 插件 $plugin_name 安装成功!" + start_tmux + else + echo "❌ 安装失败。请检查名称是否正确或查看网络连接。" + fi - break_end + break_end + done } install_skill() { send_stats "安装技能" + while true; do + echo "========================================" + echo " 技能管理 (安装) " + echo "========================================" + echo "当前已安装技能:" + openclaw skills list + echo "----------------------------------------" + + # 输出推荐的实用技能列表 + echo "推荐的实用技能(可直接复制名称输入):" + echo "github-integration # 管理 GitHub Issues/PR" + echo "notion-integration # 操作 Notion 数据库" + echo "apple-notes # 管理 Apple Notes" + echo "home-assistant # 控制智能家居" + echo "agent-browser # Playwright 浏览器自动化" + echo "----------------------------------------" + + # 提示用户输入技能名称 + printf "请输入要安装的技能名称(输入 0 退出): " + read -e skill_name + + # 1. 检查是否输入 0 以退出 + if [ "$skill_name" = "0" ]; then + echo "操作已取消,退出技能安装。" + break + fi - echo "所有技能" - openclaw skills list - # 输出推荐的实用技能列表,便于用户复制 - echo "推荐的实用技能(可直接复制名称输入):" - echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" - echo "notion-integration # 操作 Notion 数据库和页面" - echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" - echo "home-assistant # 通过 Home Assistant Hub 控制智能家居" - echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" - - # 提示用户输入技能名称 - echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " - read -e skill_name - - if [ "$skill_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + # 2. 验证输入是否为空 + if [ -z "$skill_name" ]; then + echo "错误:技能名称不能为空。请重试。" + echo "" + continue + fi - # 验证输入是否为空 - if [ -z "$skill_name" ]; then - echo "错误:技能名称不能为空。请重试。" - return 1 - fi + # 3. 执行安装命令 + echo "正在安装技能:$skill_name ..." + openclaw skills install "$skill_name" - # 执行安装命令 - echo "正在安装技能:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # 获取上一条命令的退出状态 + if [ $? -eq 0 ]; then + echo "✅ 技能 $skill_name 安装成功。" + # 执行重启/启动服务逻辑 + start_tmux + else + echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" + fi - # 检查命令执行结果 - if [ $? -eq 0 ]; then - echo "技能 $skill_name 安装成功。" - else - echo "安装失败。请检查技能名称是否正确,或参考 OpenClaw 文档排查问题。" - fi + break_end + done - break_end } @@ -10022,6 +10056,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." From 3048be485d708e069a4b75de560030a63d0bad43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:43:08 +0800 Subject: [PATCH 0758/1285] Enhance input validation and user prompts in scripts Refactor model and plugin installation functions to improve user input handling and feedback. --- kejilion.sh | 211 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 88 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 097d3a200..c82743fee 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9884,28 +9884,41 @@ moltbot_menu() { change_model() { send_stats "换模型" - echo "所有模型:" - openclaw models list --all - echo "当前模型:" - openclaw models list - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read -e model - # 检查是否输入 0 以退出 - if [ "$model" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + while true; do + clear + echo "--- 模型管理 ---" + echo "所有模型:" + openclaw models list --all + echo "----------------" + echo "当前模型:" + openclaw models list + echo "----------------" + + printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " + read -e model + + # 1. 检查是否输入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消,正在退出..." + break # 跳出 while 循环 - # 验证输入是否为空 - if [ -z "$model" ]; then - echo "错误:模型名称不能为空。请重试。" - return 1 - fi + fi + + # 2. 验证输入是否为空 + if [ -z "$model" ]; then + echo "错误:模型名称不能为空。请重试。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. 执行切换逻辑 + echo "正在切换模型为: $model ..." + openclaw models set "$model" + + break_end + done - echo "切换模型为 $model" - openclaw models set "$model" - break_end } @@ -9914,89 +9927,110 @@ moltbot_menu() { install_plugin() { send_stats "安装插件" + while true; do + clear + echo "========================================" + echo " 插件管理 (安装) " + echo "========================================" + echo "当前已安装插件:" + openclaw plugins list + echo "----------------------------------------" + + # 输出推荐的实用插件列表,便于用户复制 + echo "推荐的实用插件(可直接复制名称输入):" + echo "@openclaw/voice-call # 语音通话 (Twilio)" + echo "@openclaw/matrix # Matrix 协议" + echo "@openclaw/nostr # Nostr 协议" + echo "@adongguo/openclaw-dingtalk # 钉钉集成" + echo "@openclaw/msteams # Microsoft Teams" + echo "----------------------------------------" + + # 提示用户输入插件名称 + printf "请输入要安装的插件名称(输入 0 退出): " + read -e plugin_name + + # 1. 检查是否输入 0 以退出 + if [ "$plugin_name" = "0" ]; then + echo "操作已取消,退出插件安装。" + break + fi - echo "所有插件" - openclaw plugins list - # 输出推荐的实用插件列表,便于用户复制 - echo "推荐的实用插件(可直接复制名称输入):" - echo "@openclaw/voice-call # 启用语音通话功能,支持 Twilio 集成" - echo "@openclaw/matrix # 为 Matrix 协议提供消息通道集成" - echo "@openclaw/nostr # 支持 Nostr 协议的消息通道" - echo "@adongguo/openclaw-dingtalk # 集成钉钉消息通道" - echo "@openclaw/msteams # 添加 Microsoft Teams 支持" - - # 提示用户输入插件名称 - echo -n "请输入要安装的插件名称(例如:@xzq-xu/feishu 飞书插件)(输入 0 退出): " - read -e plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi - - # 验证输入是否为空 - if [ -z "$plugin_name" ]; then - echo "错误:插件名称不能为空。请重试。" - return 1 - fi + # 2. 验证输入是否为空 + if [ -z "$plugin_name" ]; then + echo "错误:插件名称不能为空,请重新输入。" + echo "" + continue + fi - # 执行安装命令 - echo "正在安装插件:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 3. 执行安装命令 + echo "正在安装插件:$plugin_name ..." + openclaw plugins install "$plugin_name" - # 检查命令执行结果 - if [ $? -eq 0 ]; then - echo "插件 $plugin_name 安装成功。" - else - echo "安装失败。请检查插件名称是否正确,或参考 OpenClaw 文档排查问题。" - fi + # 检查命令执行结果 ($? 获取上一条命令的状态码) + if [ $? -eq 0 ]; then + echo "✅ 插件 $plugin_name 安装成功!" + start_tmux + else + echo "❌ 安装失败。请检查名称是否正确或查看网络连接。" + fi - break_end + break_end + done } install_skill() { send_stats "安装技能" + while true; do + echo "========================================" + echo " 技能管理 (安装) " + echo "========================================" + echo "当前已安装技能:" + openclaw skills list + echo "----------------------------------------" + + # 输出推荐的实用技能列表 + echo "推荐的实用技能(可直接复制名称输入):" + echo "github-integration # 管理 GitHub Issues/PR" + echo "notion-integration # 操作 Notion 数据库" + echo "apple-notes # 管理 Apple Notes" + echo "home-assistant # 控制智能家居" + echo "agent-browser # Playwright 浏览器自动化" + echo "----------------------------------------" + + # 提示用户输入技能名称 + printf "请输入要安装的技能名称(输入 0 退出): " + read -e skill_name + + # 1. 检查是否输入 0 以退出 + if [ "$skill_name" = "0" ]; then + echo "操作已取消,退出技能安装。" + break + fi - echo "所有技能" - openclaw skills list - # 输出推荐的实用技能列表,便于用户复制 - echo "推荐的实用技能(可直接复制名称输入):" - echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" - echo "notion-integration # 操作 Notion 数据库和页面" - echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" - echo "home-assistant # 通过 Home Assistant Hub 控制智能家居" - echo "agent-browser # 使用 Playwright 进行无头浏览器自动化" - - # 提示用户输入技能名称 - echo -n "请输入要安装的技能名称(例如:github-integration)(输入 0 退出): " - read -e skill_name - - if [ "$skill_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + # 2. 验证输入是否为空 + if [ -z "$skill_name" ]; then + echo "错误:技能名称不能为空。请重试。" + echo "" + continue + fi - # 验证输入是否为空 - if [ -z "$skill_name" ]; then - echo "错误:技能名称不能为空。请重试。" - return 1 - fi + # 3. 执行安装命令 + echo "正在安装技能:$skill_name ..." + openclaw skills install "$skill_name" - # 执行安装命令 - echo "正在安装技能:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # 获取上一条命令的退出状态 + if [ $? -eq 0 ]; then + echo "✅ 技能 $skill_name 安装成功。" + # 执行重启/启动服务逻辑 + start_tmux + else + echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" + fi - # 检查命令执行结果 - if [ $? -eq 0 ]; then - echo "技能 $skill_name 安装成功。" - else - echo "安装失败。请检查技能名称是否正确,或参考 OpenClaw 文档排查问题。" - fi + break_end + done - break_end } @@ -10022,6 +10056,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." From 454b5f80db0426bbdc5a584e918a6735849790a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:49:46 +0800 Subject: [PATCH 0759/1285] Add clear command to install_skill function --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index c82743fee..676ec8593 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9982,6 +9982,7 @@ moltbot_menu() { install_skill() { send_stats "安装技能" while true; do + clear echo "========================================" echo " 技能管理 (安装) " echo "========================================" From 7b109d11f5d1737fcc3d180bd251d9505a71b63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:50:27 +0800 Subject: [PATCH 0760/1285] Add clear command in install_skill function --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 786361a02..4513af117 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9982,6 +9982,7 @@ moltbot_menu() { install_skill() { send_stats "安装技能" while true; do + clear echo "========================================" echo " 技能管理 (安装) " echo "========================================" From 854b1703d3a50ac6f955fa16d597ab14e206850e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:51:24 +0800 Subject: [PATCH 0761/1285] Refactor new_ssh_port function to accept port argument --- cn/kejilion.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4513af117..a90708470 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -14825,7 +14827,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14843,7 +14845,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH端口已修改" - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "退出SSH端口修改" break @@ -15655,8 +15657,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd From be6ce7223066f551f8102dcf41ed72769d328e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:52:04 +0800 Subject: [PATCH 0762/1285] Refactor new_ssh_port function to accept port argument --- kejilion.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 676ec8593..be38f24db 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -14825,7 +14827,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14843,7 +14845,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH端口已修改" - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "退出SSH端口修改" break @@ -15655,8 +15657,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd From 62607580b0da15affb8f911c29abdbce5afde48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:10:29 +0800 Subject: [PATCH 0763/1285] Enhance mount_partition function with UUID and fstab support Refactor mount_partition function for improved error handling and UUID retrieval. --- cn/kejilion.sh | 54 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a90708470..a90c67c0b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6651,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 + +# 持久化挂载分区 mount_partition() { send_stats "挂载分区" read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # 检查分区是否存在 - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "分区不存在!" - return + return 1 fi - # 检查分区是否已经挂载 - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # 检查是否已挂载 + if mount | grep -qw "$DEVICE"; then echo "分区已经挂载!" - return + return 1 + fi + + # 获取 UUID + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "无法获取 UUID!" + return 1 + fi + + # 获取文件系统类型 + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "无法获取文件系统类型!" + return 1 fi # 创建挂载点 - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" - else + # 挂载 + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "分区挂载失败!" rmdir "$MOUNT_POINT" + return 1 fi + + echo "分区已成功挂载到 $MOUNT_POINT" + + # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "/etc/fstab 中已存在该分区记录,跳过写入" + return 0 + fi + + # 写入 /etc/fstab + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "已写入 /etc/fstab,实现持久化挂载" } + # 卸载分区 unmount_partition() { send_stats "卸载分区" From 91e634edc5cec846a716d0232a878db24d8ebb2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:11:03 +0800 Subject: [PATCH 0764/1285] Update kejilion.sh --- kejilion.sh | 54 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index be38f24db..83e2fbc74 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6651,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 挂载分区 + +# 持久化挂载分区 mount_partition() { send_stats "挂载分区" read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # 检查分区是否存在 - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "分区不存在!" - return + return 1 fi - # 检查分区是否已经挂载 - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # 检查是否已挂载 + if mount | grep -qw "$DEVICE"; then echo "分区已经挂载!" - return + return 1 + fi + + # 获取 UUID + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "无法获取 UUID!" + return 1 + fi + + # 获取文件系统类型 + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "无法获取文件系统类型!" + return 1 fi # 创建挂载点 - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 挂载分区 - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "分区挂载成功: $MOUNT_POINT" - else + # 挂载 + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "分区挂载失败!" rmdir "$MOUNT_POINT" + return 1 fi + + echo "分区已成功挂载到 $MOUNT_POINT" + + # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "/etc/fstab 中已存在该分区记录,跳过写入" + return 0 + fi + + # 写入 /etc/fstab + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "已写入 /etc/fstab,实现持久化挂载" } + # 卸载分区 unmount_partition() { send_stats "卸载分区" From 9131535be616922d6adfaa27687104961fd0b5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:12:27 +0800 Subject: [PATCH 0765/1285] Add persistent partition mounting in disk management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增分区挂载持久化机制以增强系统工具磁盘管理功能。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index d50381d8c..b112d04fe 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1443,5 +1443,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目版增安装技能功能。 应用市场对ClawdBot/Moltbot机器人项目加入新版本检测提醒功能。 应用市场对ClawdBot/Moltbot机器人项目修复了卸载后仍然显示已安装的问题。 +系统工具磁盘管理新增分区挂载持久化机制。 ------------------------ From 0c147003d2def5f2d0f049dc20fe9d4f2260692c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:35:58 +0800 Subject: [PATCH 0766/1285] Update version and modify menu options in kejilion.sh --- cn/kejilion.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a90c67c0b..bacd4f742 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -9685,9 +9685,11 @@ moltbot_menu() { echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" + echo "11. 初始化配置向导" + echo "12. 健康检测与修复" echo "--------------------" - echo "11. 更新" - echo "12. 卸载" + echo "13. 更新" + echo "14. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10134,8 +10136,14 @@ moltbot_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 11) clawdbot onboard --install-daemon + break_end + ;; + 12) clawdbot doctor --fix + break_end + ;; + 13) update_moltbot ;; + 14) uninstall_moltbot ;; *) break ;; esac done From f906799b75645e3cdd854f380b59122aa2320ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:36:37 +0800 Subject: [PATCH 0767/1285] Update version and modify menu options in kejilion.sh --- kejilion.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 83e2fbc74..bd358b531 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -9685,9 +9685,11 @@ moltbot_menu() { echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" + echo "11. 初始化配置向导" + echo "12. 健康检测与修复" echo "--------------------" - echo "11. 更新" - echo "12. 卸载" + echo "13. 更新" + echo "14. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10134,8 +10136,14 @@ moltbot_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 11) clawdbot onboard --install-daemon + break_end + ;; + 12) clawdbot doctor --fix + break_end + ;; + 13) update_moltbot ;; + 14) uninstall_moltbot ;; *) break ;; esac done From 3646523f2e067576a300ce1052cf6c19668ba9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:38:52 +0800 Subject: [PATCH 0768/1285] Update commands to include send_stats for localization --- kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index bd358b531..20c05f398 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10136,10 +10136,12 @@ moltbot_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) clawdbot onboard --install-daemon + 11) send_stats "初始化配置向导" + clawdbot onboard --install-daemon break_end ;; - 12) clawdbot doctor --fix + 12) send_stats "健康检测与修复" + clawdbot doctor --fix break_end ;; 13) update_moltbot ;; From 5c0564fddea2280d51dbc485e880c1c945e3240f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:20 +0800 Subject: [PATCH 0769/1285] Update stats sending for initialization and health check --- cn/kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bacd4f742..3e28c3abf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10136,10 +10136,12 @@ moltbot_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) clawdbot onboard --install-daemon + 11) send_stats "初始化配置向导" + clawdbot onboard --install-daemon break_end ;; - 12) clawdbot doctor --fix + 12) send_stats "健康检测与修复" + clawdbot doctor --fix break_end ;; 13) update_moltbot ;; From 76666097b2a5af8fa39336f81babec89bf136582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:42:11 +0800 Subject: [PATCH 0770/1285] Fix date format and update version log Correct date format and add new version details for ClawdBot/Moltbot. --- kejilion_sh_log.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index b112d04fe..685882911 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1437,12 +1437,15 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目版本更新功能进行修复。 应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 ------------------------ -2026-02-3 v4.3.8 +2026-02-03 v4.3.8 应用市场对ClawdBot/Moltbot机器人项目版增加配置文件编辑功能,支持nano直接编辑。 应用市场对ClawdBot/Moltbot机器人项目版增安装插件功能,可以安装飞书插件了。 应用市场对ClawdBot/Moltbot机器人项目版增安装技能功能。 应用市场对ClawdBot/Moltbot机器人项目加入新版本检测提醒功能。 应用市场对ClawdBot/Moltbot机器人项目修复了卸载后仍然显示已安装的问题。 +------------------------ +2026-02-05 v4.3.9 +应用市场对ClawdBot/Moltbot机器人项目新增重置向导和健康检测功能。 系统工具磁盘管理新增分区挂载持久化机制。 ------------------------ From f13dfed0e4f728fc3d8c810c2cedd5fd22669215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:41:54 +0800 Subject: [PATCH 0771/1285] =?UTF-8?q?Rename=20'=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=90=91=E5=AF=BC'=20to=20'=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=90=91=E5=AF=BC'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3e28c3abf..138d9630b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9685,7 +9685,7 @@ moltbot_menu() { echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" - echo "11. 初始化配置向导" + echo "11. 配置向导" echo "12. 健康检测与修复" echo "--------------------" echo "13. 更新" From 7c31b50dbe96980f660a34bcc2b28b57c0415014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:43:01 +0800 Subject: [PATCH 0772/1285] =?UTF-8?q?Rename=20'=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=90=91=E5=AF=BC'=20to=20'=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=90=91=E5=AF=BC'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 20c05f398..677289800 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9685,7 +9685,7 @@ moltbot_menu() { echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" - echo "11. 初始化配置向导" + echo "11. 配置向导" echo "12. 健康检测与修复" echo "--------------------" echo "13. 更新" From b51177323fdac6d4db61cc575e9e0fb1807cae36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:51:23 +0800 Subject: [PATCH 0773/1285] Replace 'clawdbot' with 'openclaw' in script --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 138d9630b..83fe77fab 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10137,11 +10137,11 @@ moltbot_menu() { 9) install_skill ;; 10) nano_openclaw_json ;; 11) send_stats "初始化配置向导" - clawdbot onboard --install-daemon + openclaw onboard --install-daemon break_end ;; 12) send_stats "健康检测与修复" - clawdbot doctor --fix + openclaw doctor --fix break_end ;; 13) update_moltbot ;; From 9e36f0087c6a7bfb06a00d3aa372923baad05b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:51:56 +0800 Subject: [PATCH 0774/1285] Replace 'clawdbot' with 'openclaw' commands --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 677289800..a070035ff 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10137,11 +10137,11 @@ moltbot_menu() { 9) install_skill ;; 10) nano_openclaw_json ;; 11) send_stats "初始化配置向导" - clawdbot onboard --install-daemon + openclaw onboard --install-daemon break_end ;; 12) send_stats "健康检测与修复" - clawdbot doctor --fix + openclaw doctor --fix break_end ;; 13) update_moltbot ;; From 5b7aa3907d9cace98371e85215dfffcc265f3610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:08:01 +0800 Subject: [PATCH 0775/1285] Enhance npm version check with no-update-notifier Updated npm version checks to include --no-update-notifier. --- cn/kejilion.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 83fe77fab..bbcde0f74 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -7187,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" @@ -9621,19 +9620,19 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" check_openclaw_update() { - # 先检查 NPM 是否可用 if ! command -v npm >/dev/null 2>&1; then return 1 fi - # 使用 NPM 查询本地版本,并去除前缀(如 openclaw@) - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # 加上 --no-update-notifier,并确保错误重定向位置正确 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # 使用 NPM 查询远程版本 - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi From 6d2040598ff75ded7be04b86fc343ce01a7b0795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:08:43 +0800 Subject: [PATCH 0776/1285] Improve npm version check commands Updated npm version checks to include --no-update-notifier option. --- kejilion.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a070035ff..6e1b96c6d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -7187,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" @@ -9621,19 +9620,19 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" check_openclaw_update() { - # 先检查 NPM 是否可用 if ! command -v npm >/dev/null 2>&1; then return 1 fi - # 使用 NPM 查询本地版本,并去除前缀(如 openclaw@) - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # 加上 --no-update-notifier,并确保错误重定向位置正确 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # 使用 NPM 查询远程版本 - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi From 49e3233669c121bbba86e3c81844dde642b644a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:27:01 +0800 Subject: [PATCH 0777/1285] Replace printf with read -e -p for prompts --- cn/kejilion.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bbcde0f74..f0e926664 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9925,9 +9925,7 @@ moltbot_menu() { echo "当前模型:" openclaw models list echo "----------------" - - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read -e model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " model # 1. 检查是否输入 0 以退出 if [ "$model" = "0" ]; then @@ -9977,8 +9975,7 @@ moltbot_menu() { echo "----------------------------------------" # 提示用户输入插件名称 - printf "请输入要安装的插件名称(输入 0 退出): " - read -e plugin_name + read -e -p "请输入要安装的插件名称(输入 0 退出): " plugin_name # 1. 检查是否输入 0 以退出 if [ "$plugin_name" = "0" ]; then @@ -10031,8 +10028,7 @@ moltbot_menu() { echo "----------------------------------------" # 提示用户输入技能名称 - printf "请输入要安装的技能名称(输入 0 退出): " - read -e skill_name + read -e -p "请输入要安装的技能名称(输入 0 退出): " skill_name # 1. 检查是否输入 0 以退出 if [ "$skill_name" = "0" ]; then @@ -10069,8 +10065,7 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" - printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " - read -e code + read -e -p "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " code # 检查是否输入 0 以退出 if [ "$code" = "0" ]; then From de2989416fc094b3bcc01afd73fac7cfd1645e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:27:32 +0800 Subject: [PATCH 0778/1285] Simplify user prompts with read -e -p --- kejilion.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6e1b96c6d..0e4135f2f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9925,9 +9925,7 @@ moltbot_menu() { echo "当前模型:" openclaw models list echo "----------------" - - printf "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " - read -e model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " model # 1. 检查是否输入 0 以退出 if [ "$model" = "0" ]; then @@ -9977,8 +9975,7 @@ moltbot_menu() { echo "----------------------------------------" # 提示用户输入插件名称 - printf "请输入要安装的插件名称(输入 0 退出): " - read -e plugin_name + read -e -p "请输入要安装的插件名称(输入 0 退出): " plugin_name # 1. 检查是否输入 0 以退出 if [ "$plugin_name" = "0" ]; then @@ -10031,8 +10028,7 @@ moltbot_menu() { echo "----------------------------------------" # 提示用户输入技能名称 - printf "请输入要安装的技能名称(输入 0 退出): " - read -e skill_name + read -e -p "请输入要安装的技能名称(输入 0 退出): " skill_name # 1. 检查是否输入 0 以退出 if [ "$skill_name" = "0" ]; then @@ -10069,8 +10065,7 @@ moltbot_menu() { change_tg_bot_code() { send_stats "机器人对接" - printf "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " - read -e code + read -e -p "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " code # 检查是否输入 0 以退出 if [ "$code" = "0" ]; then From 93ebe23158506bbd4a36cb06a05fd42c4b235b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:50:28 +0800 Subject: [PATCH 0779/1285] Update recommended plugins and skills list --- cn/kejilion.sh | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f0e926664..fd1ed8d79 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9967,11 +9967,18 @@ moltbot_menu() { # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" - echo "@openclaw/voice-call # 语音通话 (Twilio)" - echo "@openclaw/matrix # Matrix 协议" - echo "@openclaw/nostr # Nostr 协议" - echo "@adongguo/openclaw-dingtalk # 钉钉集成" - echo "@openclaw/msteams # Microsoft Teams" + echo "feishu # 飞书/Lark 集成 (当前已加载 ✓)" + echo "telegram # Telegram 机器人集成 (当前已加载 ✓)" + echo "memory-core # 核心记忆增强:基于文件的上下文搜索 (当前已加载 ✓)" + echo "@openclaw/slack # Slack 频道与 DMs 深度连接" + echo "@openclaw/bluebubbles # iMessage 桥接 (macOS 用户首选)" + echo "@openclaw/msteams # Microsoft Teams 企业通讯集成" + echo "@openclaw/voice-call # 语音通话插件 (基于 Twilio 等后端)" + echo "@openclaw/discord # Discord 频道自动化管理" + echo "@openclaw/nostr # Nostr 协议:隐私安全加密聊天" + echo "lobster # 审批工作流:带有人工干预的自动任务" + echo "memory-lancedb # 长期记忆增强:基于向量数据库的精准召回" + echo "copilot-proxy # GitHub Copilot 代理接入增强" echo "----------------------------------------" # 提示用户输入插件名称 @@ -10020,11 +10027,20 @@ moltbot_menu() { # 输出推荐的实用技能列表 echo "推荐的实用技能(可直接复制名称输入):" - echo "github-integration # 管理 GitHub Issues/PR" - echo "notion-integration # 操作 Notion 数据库" - echo "apple-notes # 管理 Apple Notes" - echo "home-assistant # 控制智能家居" - echo "agent-browser # Playwright 浏览器自动化" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 页面、数据库和块" + echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" + echo "apple-reminders # macOS 提醒事项管理 (待办清单)" + echo "1password # 自动化读取和注入 1Password 密钥" + echo "gog # Google Workspace (Gmail/云盘/文档) 全能助手" + echo "things-mac # 深度整合 Things 3 任务管理" + echo "bluebubbles # 通过 BlueBubbles 完美收发 iMessage" + echo "himalaya # 终端邮件管理 (IMAP/SMTP 强力工具)" + echo "summarize # 网页/播客/YouTube 视频内容一键总结" + echo "openhue # 控制 Philips Hue 智能灯光场景" + echo "video-frames # 视频抽帧与短片剪辑 (ffmpeg 驱动)" + echo "openai-whisper # 本地音频转文字 (离线隐私保护)" + echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" echo "----------------------------------------" # 提示用户输入技能名称 From 9aec1c6942984e23582c6129b0bc95fb43540632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:51:04 +0800 Subject: [PATCH 0780/1285] Update recommended plugins and skills list --- kejilion.sh | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0e4135f2f..f2bf003a5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9967,11 +9967,18 @@ moltbot_menu() { # 输出推荐的实用插件列表,便于用户复制 echo "推荐的实用插件(可直接复制名称输入):" - echo "@openclaw/voice-call # 语音通话 (Twilio)" - echo "@openclaw/matrix # Matrix 协议" - echo "@openclaw/nostr # Nostr 协议" - echo "@adongguo/openclaw-dingtalk # 钉钉集成" - echo "@openclaw/msteams # Microsoft Teams" + echo "feishu # 飞书/Lark 集成 (当前已加载 ✓)" + echo "telegram # Telegram 机器人集成 (当前已加载 ✓)" + echo "memory-core # 核心记忆增强:基于文件的上下文搜索 (当前已加载 ✓)" + echo "@openclaw/slack # Slack 频道与 DMs 深度连接" + echo "@openclaw/bluebubbles # iMessage 桥接 (macOS 用户首选)" + echo "@openclaw/msteams # Microsoft Teams 企业通讯集成" + echo "@openclaw/voice-call # 语音通话插件 (基于 Twilio 等后端)" + echo "@openclaw/discord # Discord 频道自动化管理" + echo "@openclaw/nostr # Nostr 协议:隐私安全加密聊天" + echo "lobster # 审批工作流:带有人工干预的自动任务" + echo "memory-lancedb # 长期记忆增强:基于向量数据库的精准召回" + echo "copilot-proxy # GitHub Copilot 代理接入增强" echo "----------------------------------------" # 提示用户输入插件名称 @@ -10020,11 +10027,20 @@ moltbot_menu() { # 输出推荐的实用技能列表 echo "推荐的实用技能(可直接复制名称输入):" - echo "github-integration # 管理 GitHub Issues/PR" - echo "notion-integration # 操作 Notion 数据库" - echo "apple-notes # 管理 Apple Notes" - echo "home-assistant # 控制智能家居" - echo "agent-browser # Playwright 浏览器自动化" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 页面、数据库和块" + echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" + echo "apple-reminders # macOS 提醒事项管理 (待办清单)" + echo "1password # 自动化读取和注入 1Password 密钥" + echo "gog # Google Workspace (Gmail/云盘/文档) 全能助手" + echo "things-mac # 深度整合 Things 3 任务管理" + echo "bluebubbles # 通过 BlueBubbles 完美收发 iMessage" + echo "himalaya # 终端邮件管理 (IMAP/SMTP 强力工具)" + echo "summarize # 网页/播客/YouTube 视频内容一键总结" + echo "openhue # 控制 Philips Hue 智能灯光场景" + echo "video-frames # 视频抽帧与短片剪辑 (ffmpeg 驱动)" + echo "openai-whisper # 本地音频转文字 (离线隐私保护)" + echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" echo "----------------------------------------" # 提示用户输入技能名称 From 02716f1a344441209bf8ae3562a987a69e288be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:16:55 +0800 Subject: [PATCH 0781/1285] Update plugin and skill installation commands --- kejilion.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f2bf003a5..55de7dc81 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9999,7 +9999,11 @@ moltbot_menu() { # 3. 执行安装命令 echo "正在安装插件:$plugin_name ..." - openclaw plugins install "$plugin_name" + # 1. 先尝试通过 npm 安装(如果它是外部插件) + npm install -g "$plugin_name" + + # 2. 尝试启用该插件 + openclaw plugins enable "$plugin_name" # 检查命令执行结果 ($? 获取上一条命令的状态码) if [ $? -eq 0 ]; then @@ -10014,6 +10018,10 @@ moltbot_menu() { } + + + + install_skill() { send_stats "安装技能" while true; do @@ -10061,7 +10069,7 @@ moltbot_menu() { # 3. 执行安装命令 echo "正在安装技能:$skill_name ..." - openclaw skills install "$skill_name" + npx clawhub install "$skill_name" # 获取上一条命令的退出状态 if [ $? -eq 0 ]; then From d7d08217f194c4b01ab2e511f56a6fc275d43d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:17:40 +0800 Subject: [PATCH 0782/1285] Update plugin and skill installation commands --- cn/kejilion.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index fd1ed8d79..39197d9de 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9999,7 +9999,11 @@ moltbot_menu() { # 3. 执行安装命令 echo "正在安装插件:$plugin_name ..." - openclaw plugins install "$plugin_name" + # 1. 先尝试通过 npm 安装(如果它是外部插件) + npm install -g "$plugin_name" + + # 2. 尝试启用该插件 + openclaw plugins enable "$plugin_name" # 检查命令执行结果 ($? 获取上一条命令的状态码) if [ $? -eq 0 ]; then @@ -10014,6 +10018,10 @@ moltbot_menu() { } + + + + install_skill() { send_stats "安装技能" while true; do @@ -10061,7 +10069,7 @@ moltbot_menu() { # 3. 执行安装命令 echo "正在安装技能:$skill_name ..." - openclaw skills install "$skill_name" + npx clawhub install "$skill_name" # 获取上一条命令的退出状态 if [ $? -eq 0 ]; then From 2b058816754f166c90be594391e792d0731dd689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:25:27 +0800 Subject: [PATCH 0783/1285] Improve plugin installation and activation process Refactor plugin installation logic to handle existing plugins and fallback options. --- cn/kejilion.sh | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 39197d9de..d8ed8efd5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9997,22 +9997,29 @@ moltbot_menu() { continue fi - # 3. 执行安装命令 - echo "正在安装插件:$plugin_name ..." - # 1. 先尝试通过 npm 安装(如果它是外部插件) - npm install -g "$plugin_name" - - # 2. 尝试启用该插件 - openclaw plugins enable "$plugin_name" + # 1. 彻底清理之前失败的残留(用户目录) + rm -rf "/root/.openclaw/extensions/$plugin_name" - # 检查命令执行结果 ($? 获取上一条命令的状态码) - if [ $? -eq 0 ]; then - echo "✅ 插件 $plugin_name 安装成功!" - start_tmux + # 2. 检查系统是否已经预装(防止 duplicate id 冲突) + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 检测到系统目录已存在该插件,正在直接激活..." + openclaw plugins enable "$plugin_name" else - echo "❌ 安装失败。请检查名称是否正确或查看网络连接。" + echo "📥 正在通过官方渠道下载安装插件..." + # 使用 openclaw 自己的 install 命令,它会自动处理 package.json 的规范检查 + openclaw plugins install "$plugin_name" + + # 3. 如果 openclaw install 报错,再尝试作为普通 npm 包安装(最后的备选) + if [ $? -ne 0 ]; then + echo "⚠️ 官方安装失败,尝试通过 npm 全局强制安装..." + npm install -g "$plugin_name" --unsafe-perm + fi + + # 4. 最后统一执行启用 + openclaw plugins enable "$plugin_name" fi + start_tmux break_end done } From 9223b020bb2c61129dd778237e4e6faaac72f3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:26:07 +0800 Subject: [PATCH 0784/1285] Improve plugin installation logic in kejilion.sh Refactor plugin installation process to handle existing plugins and provide fallback installation methods. --- kejilion.sh | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 55de7dc81..91e990a93 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9997,22 +9997,29 @@ moltbot_menu() { continue fi - # 3. 执行安装命令 - echo "正在安装插件:$plugin_name ..." - # 1. 先尝试通过 npm 安装(如果它是外部插件) - npm install -g "$plugin_name" - - # 2. 尝试启用该插件 - openclaw plugins enable "$plugin_name" + # 1. 彻底清理之前失败的残留(用户目录) + rm -rf "/root/.openclaw/extensions/$plugin_name" - # 检查命令执行结果 ($? 获取上一条命令的状态码) - if [ $? -eq 0 ]; then - echo "✅ 插件 $plugin_name 安装成功!" - start_tmux + # 2. 检查系统是否已经预装(防止 duplicate id 冲突) + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 检测到系统目录已存在该插件,正在直接激活..." + openclaw plugins enable "$plugin_name" else - echo "❌ 安装失败。请检查名称是否正确或查看网络连接。" + echo "📥 正在通过官方渠道下载安装插件..." + # 使用 openclaw 自己的 install 命令,它会自动处理 package.json 的规范检查 + openclaw plugins install "$plugin_name" + + # 3. 如果 openclaw install 报错,再尝试作为普通 npm 包安装(最后的备选) + if [ $? -ne 0 ]; then + echo "⚠️ 官方安装失败,尝试通过 npm 全局强制安装..." + npm install -g "$plugin_name" --unsafe-perm + fi + + # 4. 最后统一执行启用 + openclaw plugins enable "$plugin_name" fi + start_tmux break_end done } From 6ce3d9d241c9a667a079335a69451cd9140b5dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:40:39 +0800 Subject: [PATCH 0785/1285] Add plugin installation function to kejilion.sh --- kejilion.sh | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 91e990a93..184b8c9d5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10024,6 +10024,91 @@ moltbot_menu() { done } + install_plugin() { + send_stats "安装插件" + while true; do + clear + echo "========================================" + echo " 插件管理 (安装) " + echo "========================================" + echo "当前插件列表:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推荐的常用插件 ID (直接复制括号内的 ID 即可):" + echo "--------------------------------------------------------" + echo "📱 通讯渠道:" + echo " - [feishu] # 飞书/Lark 集成" + echo " - [telegram] # Telegram 机器人" + echo " - [slack] # Slack 企业通讯" + echo " - [msteams] # Microsoft Teams" + echo " - [discord] # Discord 社区管理" + echo " - [whatsapp] # WhatsApp 自动化" + echo "" + echo "🧠 记忆与 AI:" + echo " - [memory-core] # 基础记忆 (文件检索)" + echo " - [memory-lancedb] # 增强记忆 (向量数据库)" + echo " - [copilot-proxy] # Copilot 接口转发" + echo "" + echo "⚙️ 功能扩展:" + echo " - [lobster] # 审批流 (带人工确认)" + echo " - [voice-call] # 语音通话能力" + echo " - [nostr] # 加密隐私聊天" + echo "--------------------------------------------------------" + + read -e -p "请输入插件 ID(输入 0 退出): " raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 正在检查插件状态..." + + # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已预装,正在激活..." + openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" + + # 3. 检查系统物理目录是否存在 + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + openclaw plugins enable "$plugin_id" + + else + # 4. 远程安装逻辑 + echo "📥 本地未发现,尝试下载安装..." + + # 清理旧的失败残留 + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # 执行安装,并捕获结果 + if openclaw plugins install "$plugin_full"; then + echo "✅ 下载成功,正在启用..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ 官方渠道下载失败,尝试备选方案..." + # 备选 npm 安装 + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm 安装成功,尝试启用..." + openclaw plugins enable "$plugin_id" + else + echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" + # 关键:这里直接 return 或 continue,不走下面的 start_tmux,防止写死配置 + break_end + continue + fi + fi + fi + + echo "🔄 正在重启 OpenClaw 服务以加载新插件..." + start_tmux + break_end + done + } + + From 913b9d06b82090ff658306bb30ec776392569910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:41:26 +0800 Subject: [PATCH 0786/1285] Add plugin installation function to kejilion.sh --- cn/kejilion.sh | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d8ed8efd5..4aa3136dc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10024,6 +10024,91 @@ moltbot_menu() { done } + install_plugin() { + send_stats "安装插件" + while true; do + clear + echo "========================================" + echo " 插件管理 (安装) " + echo "========================================" + echo "当前插件列表:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推荐的常用插件 ID (直接复制括号内的 ID 即可):" + echo "--------------------------------------------------------" + echo "📱 通讯渠道:" + echo " - [feishu] # 飞书/Lark 集成" + echo " - [telegram] # Telegram 机器人" + echo " - [slack] # Slack 企业通讯" + echo " - [msteams] # Microsoft Teams" + echo " - [discord] # Discord 社区管理" + echo " - [whatsapp] # WhatsApp 自动化" + echo "" + echo "🧠 记忆与 AI:" + echo " - [memory-core] # 基础记忆 (文件检索)" + echo " - [memory-lancedb] # 增强记忆 (向量数据库)" + echo " - [copilot-proxy] # Copilot 接口转发" + echo "" + echo "⚙️ 功能扩展:" + echo " - [lobster] # 审批流 (带人工确认)" + echo " - [voice-call] # 语音通话能力" + echo " - [nostr] # 加密隐私聊天" + echo "--------------------------------------------------------" + + read -e -p "请输入插件 ID(输入 0 退出): " raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 正在检查插件状态..." + + # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已预装,正在激活..." + openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" + + # 3. 检查系统物理目录是否存在 + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + openclaw plugins enable "$plugin_id" + + else + # 4. 远程安装逻辑 + echo "📥 本地未发现,尝试下载安装..." + + # 清理旧的失败残留 + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # 执行安装,并捕获结果 + if openclaw plugins install "$plugin_full"; then + echo "✅ 下载成功,正在启用..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ 官方渠道下载失败,尝试备选方案..." + # 备选 npm 安装 + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm 安装成功,尝试启用..." + openclaw plugins enable "$plugin_id" + else + echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" + # 关键:这里直接 return 或 continue,不走下面的 start_tmux,防止写死配置 + break_end + continue + fi + fi + fi + + echo "🔄 正在重启 OpenClaw 服务以加载新插件..." + start_tmux + break_end + done + } + + From 56c27a4a4950d316c31dc7d3f462f39508c1911f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:47:41 +0800 Subject: [PATCH 0787/1285] Update ClawdBot/Moltbot features and fix installation issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化技能和插件安装体验,修复安装失败问题。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 685882911..316513056 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1447,5 +1447,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-02-05 v4.3.9 应用市场对ClawdBot/Moltbot机器人项目新增重置向导和健康检测功能。 系统工具磁盘管理新增分区挂载持久化机制。 +应用市场对ClawdBot/Moltbot机器人项目优化技能和插件安装体验,修复安装失败问题。 ------------------------ From a840d6a34223a60393b4429946518127efbca52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:28:46 +0800 Subject: [PATCH 0788/1285] Add WebUI access and domain management functions --- cn/kejilion.sh | 134 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4aa3136dc..e18c1c0be 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9686,9 +9686,10 @@ moltbot_menu() { echo "10. 编辑主配置文件" echo "11. 配置向导" echo "12. 健康检测与修复" + echo "13. WebUI访问与设置" echo "--------------------" - echo "13. 更新" - echo "14. 卸载" + echo "14. 更新" + echo "15. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10231,6 +10232,130 @@ moltbot_menu() { start_tmux } + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI 访问地址" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "本机地址:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "域名地址:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # 添加域名(调用你给的函数) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "访问地址:" + echo "https://${yuming}/?token=$token" + echo "先访问URL触发设备ID,然后回车下一步进行配对。" + read + echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" + openclaw devices list + + read -e -p "请输入 Request_Key: " Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key 不能为空" + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # 删除域名 + openclaw_remove_domain() { + echo "域名格式 example.com 不带https://" + web_del + } + + # 主菜单 + openclaw_webui_menu() { + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. 添加域名访问" + echo "2. 删除域名访问" + echo "0. 退出" + echo + read -e -p "请选择: " choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "按回车返回菜单..." + ;; + 2) + openclaw_remove_domain + read -p "按回车返回菜单..." + ;; + 0) + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done + } + + + # 主循环 while true; do show_menu @@ -10254,8 +10379,9 @@ moltbot_menu() { openclaw doctor --fix break_end ;; - 13) update_moltbot ;; - 14) uninstall_moltbot ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done From 94cfd24d8073f5174a05c7d499742b199e62eb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:30:57 +0800 Subject: [PATCH 0789/1285] Add send_stats call in openclaw_webui_menu --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e18c1c0be..c8bfe43a9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10323,6 +10323,8 @@ moltbot_menu() { # 主菜单 openclaw_webui_menu() { + + send_stats "WebUI访问与设置" while true; do clear openclaw_show_webui_addr From ec5d558c1b2dcd54007a2656dcf250a6d2b0ce7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:32:08 +0800 Subject: [PATCH 0790/1285] Add WebUI access and settings menu options --- kejilion.sh | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 184b8c9d5..e7519c898 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9686,9 +9686,10 @@ moltbot_menu() { echo "10. 编辑主配置文件" echo "11. 配置向导" echo "12. 健康检测与修复" + echo "13. WebUI访问与设置" echo "--------------------" - echo "13. 更新" - echo "14. 卸载" + echo "14. 更新" + echo "15. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10231,6 +10232,132 @@ moltbot_menu() { start_tmux } + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI 访问地址" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "本机地址:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "域名地址:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # 添加域名(调用你给的函数) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "访问地址:" + echo "https://${yuming}/?token=$token" + echo "先访问URL触发设备ID,然后回车下一步进行配对。" + read + echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" + openclaw devices list + + read -e -p "请输入 Request_Key: " Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key 不能为空" + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # 删除域名 + openclaw_remove_domain() { + echo "域名格式 example.com 不带https://" + web_del + } + + # 主菜单 + openclaw_webui_menu() { + + send_stats "WebUI访问与设置" + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. 添加域名访问" + echo "2. 删除域名访问" + echo "0. 退出" + echo + read -e -p "请选择: " choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "按回车返回菜单..." + ;; + 2) + openclaw_remove_domain + read -p "按回车返回菜单..." + ;; + 0) + break + ;; + *) + echo "无效选项" + sleep 1 + ;; + esac + done + } + + + # 主循环 while true; do show_menu @@ -10254,8 +10381,9 @@ moltbot_menu() { openclaw doctor --fix break_end ;; - 13) update_moltbot ;; - 14) uninstall_moltbot ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done From 9e84303626e72821981e00050aa59d24aff8ebb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:33:38 +0800 Subject: [PATCH 0791/1285] Add web UI access settings feature Added web UI access settings feature for ClawdBot/Moltbot. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 316513056..1dfbe0a7e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1448,5 +1448,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目新增重置向导和健康检测功能。 系统工具磁盘管理新增分区挂载持久化机制。 应用市场对ClawdBot/Moltbot机器人项目优化技能和插件安装体验,修复安装失败问题。 +应用市场对ClawdBot/Moltbot机器人项目新增webui访问设置功能,可以用域名访问后台。 ------------------------ From 72d92b6c8854620998940fae1cd5d557a4e49e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:51:20 +0800 Subject: [PATCH 0792/1285] Update proxy port in openclaw_domain_webui function Change the proxy port from the default to 18789. --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c8bfe43a9..f0bee3672 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10288,7 +10288,7 @@ moltbot_menu() { # 添加域名(调用你给的函数) openclaw_domain_webui() { add_yuming - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + ldnmp_Proxy ${yuming} 127.0.0.1 18789 token=$( openclaw dashboard 2>/dev/null \ From dc181d426725b59659c1fabdbbca9fdadd57c1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:52:47 +0800 Subject: [PATCH 0793/1285] Change proxy port to 18789 in domain function Update the proxy port in openclaw_domain_webui function. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index e7519c898..e7855af68 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10288,7 +10288,7 @@ moltbot_menu() { # 添加域名(调用你给的函数) openclaw_domain_webui() { add_yuming - ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} + ldnmp_Proxy ${yuming} 127.0.0.1 18789 token=$( openclaw dashboard 2>/dev/null \ From 18b1fc95898545f336fca22759fa380252254588 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 8 Feb 2026 05:08:00 +0000 Subject: [PATCH 0794/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-08=2005:08:00?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 753 +++++++++++++++++++++++++++++++++-------------- jp/kejilion.sh | 785 ++++++++++++++++++++++++++++++++++--------------- kr/kejilion.sh | 763 +++++++++++++++++++++++++++++++++-------------- tw/kejilion.sh | 623 +++++++++++++++++++++++++++++---------- 4 files changed, 2092 insertions(+), 832 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 44cd6893e..1889bc601 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -884,7 +884,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3523,7 +3523,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3652,20 +3652,20 @@ ldnmp_Proxy_backend_stream() { echo "Start deployment$webname" # Get agent name - read -rp "Please enter a proxy forwarding name (e.g. mysql_proxy):" proxy_name + read -erp "Please enter a proxy forwarding name (e.g. mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then echo "Name cannot be empty"; return 1 fi # Get listening port - read -rp "Please enter the local listening port (such as 3306):" listen_port + read -erp "Please enter the local listening port (such as 3306):" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "Port must be numeric"; return 1 fi echo "Please select agreement type:" echo "1. TCP 2. UDP" - read -rp "Please enter the serial number [1-2]:" proto_choice + read -erp "Please enter the serial number [1-2]:" proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -4313,7 +4313,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4410,7 +4410,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -5441,7 +5443,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5975,7 +5977,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -6317,9 +6319,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6361,7 +6363,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6504,7 +6506,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6649,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# Mount partition + +# Persistently mounted partition mount_partition() { send_stats "Mount partition" read -e -p "Please enter the name of the partition to be mounted (e.g. sda1):" PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # Check if the partition exists - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "The partition does not exist!" - return + return 1 fi - # Check whether the partition is mounted - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # Check if it is mounted + if mount | grep -qw "$DEVICE"; then echo "The partition has been mounted!" - return + return 1 + fi + + # Get UUID + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "Unable to get UUID!" + return 1 + fi + + # Get file system type + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "Unable to get file system type!" + return 1 fi # Create mount point - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # Mount partition - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "Partition mounted successfully:$MOUNT_POINT" - else + # mount + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "Partition mount failed!" rmdir "$MOUNT_POINT" + return 1 + fi + + echo "The partition was successfully mounted to$MOUNT_POINT" + + # Check /etc/fstab to see if the UUID or mount point already exists + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "The partition record already exists in /etc/fstab, skip writing" + return 0 fi + + # Write to /etc/fstab + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "Written to /etc/fstab to achieve persistent mounting" } + # Unmount partition unmount_partition() { send_stats "Unmount partition" @@ -6782,7 +6812,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6852,7 +6882,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7157,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "System information query" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Hostname:${gl_bai}$hostname" @@ -7207,7 +7236,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" tools=( @@ -7274,7 +7303,7 @@ linux_tools() { echo -e "${gl_kjlan}17. ${gl_bai}git version control system${gl_kjlan}18. ${gl_bai}opencode AI programming assistant${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Running train screensaver" - echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake mini game" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}Snake mini game" echo -e "${gl_kjlan}28. ${gl_bai}space invaders mini game" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}Install all (excluding screensavers and games)${gl_huang}★${gl_bai}" @@ -8209,7 +8238,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9591,19 +9620,19 @@ moltbot_menu() { send_stats "clawdbot/moltbot management" check_openclaw_update() { - # First check if NPM is available if ! command -v npm >/dev/null 2>&1; then return 1 fi - # Use NPM to query the local version and remove the prefix (such as openclaw@) - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # Add --no-update-notifier and make sure error redirection is in the correct location + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # Query remote versions using NPM - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi @@ -9655,9 +9684,12 @@ moltbot_menu() { echo "8. Install plug-ins (such as Feishu)" echo "9. Install skills" echo "10. Edit the main configuration file" + echo "11. Configuration Wizard" + echo "12. Health detection and repair" + echo "13. WebUI access and settings" echo "--------------------" - echo "11. Update" - echo "12. Uninstall" + echo "14. Update" + echo "15. Uninstall" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" @@ -9827,24 +9859,24 @@ moltbot_menu() { echo "=== Add OpenClaw Provider interactively ===" # Provider name - read -rp "Please enter the Provider name (eg: deepseek):" provider_name + read -erp "Please enter the Provider name (eg: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider name cannot be empty" - read -rp "Please enter Provider name:" provider_name + read -erp "Please enter Provider name:" provider_name done # Model ID - read -rp "Please enter Model ID (eg: deepseek-chat):" model_id + read -erp "Please enter Model ID (eg: deepseek-chat):" model_id while [[ -z "$model_id" ]]; do echo "❌ Model ID cannot be empty" - read -rp "Please enter Model ID:" model_id + read -erp "Please enter Model ID:" model_id done # Base URL - read -rp "Please enter Base URL (eg: https://api.xxx.com/v1):" base_url + read -erp "Please enter Base URL (eg: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL cannot be empty" - read -rp "Please enter Base URL:" base_url + read -erp "Please enter Base URL:" base_url done # API Key (hidden input) @@ -9864,7 +9896,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "Confirm to add? (y/N):" confirm + read -erp "Confirm to add? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ Canceled" return 1 @@ -9884,28 +9916,39 @@ moltbot_menu() { change_model() { send_stats "Change model" - echo "All models:" - openclaw models list --all - echo "Current model:" - openclaw models list - printf "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" - read model - # Check if 0 is entered to exit - if [ "$model" = "0" ]; then - echo "The operation has been cancelled." - return 0 # 正常退出函数 - fi + while true; do + clear + echo "---Model Management ---" + echo "All models:" + openclaw models list --all + echo "----------------" + echo "Current model:" + openclaw models list + echo "----------------" + read -e -p "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" model + + # 1. Check if you entered 0 to exit + if [ "$model" = "0" ]; then + echo "Operation canceled, exiting..." + break # 跳出 while 循环 - # Verify input is empty - if [ -z "$model" ]; then - echo "Error: Model name cannot be empty. Please try again." - return 1 - fi + fi + + # 2. Verify that the input is empty + if [ -z "$model" ]; then + echo "Error: Model name cannot be empty. Please try again." + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. Execute switching logic + echo "The model being switched is:$model ..." + openclaw models set "$model" + + break_end + done - echo "Switch model to$model" - openclaw models set "$model" - break_end } @@ -9914,97 +9957,232 @@ moltbot_menu() { install_plugin() { send_stats "Install plugin" + while true; do + clear + echo "========================================" + echo "Plug-in management (installation)" + echo "========================================" + echo "Currently installed plugins:" + openclaw plugins list + echo "----------------------------------------" + + # Output a list of recommended practical plug-ins for users to copy + echo "Recommended practical plug-ins (you can directly copy the name input):" + echo "feishu # Feishu/Lark integration (currently loaded ✓)" + echo "telegram # Telegram bot integration (currently loaded ✓)" + echo "memory-core # Core memory enhancement: file-based contextual search (currently loaded ✓)" + echo "@openclaw/slack # Deep connections between Slack channels and DMs" + echo "@openclaw/bluebubbles # iMessage bridge (preferred for macOS users)" + echo "@openclaw/msteams #Microsoft Teams Enterprise Communications Integration" + echo "@openclaw/voice-call # Voice call plug-in (based on backends such as Twilio)" + echo "@openclaw/discord # Discord channel automatic management" + echo "@openclaw/nostr # Nostr protocol: private and secure encrypted chat" + echo "lobster # Approval workflow: automated tasks with human intervention" + echo "memory-lancedb # Long-term memory enhancement: precise recall based on vector database" + echo "copilot-proxy # GitHub Copilot proxy access enhancement" + echo "----------------------------------------" + + # Prompt user for plugin name + read -e -p "Please enter the name of the plugin you want to install (enter 0 to exit):" plugin_name + + # 1. Check if you entered 0 to exit + if [ "$plugin_name" = "0" ]; then + echo "The operation has been canceled and the plug-in installation has been exited." + break + fi - echo "All plugins" - openclaw plugins list - # Output a list of recommended practical plug-ins for users to copy - echo "Recommended practical plug-ins (you can directly copy the name input):" - echo "@openclaw/voice-call # Enable voice call function, support Twilio integration" - echo "@openclaw/matrix # Provide message channel integration for the Matrix protocol" - echo "@openclaw/nostr # Support message channel of Nostr protocol" - echo "@adongguo/openclaw-dingtalk # Integrated DingTalk message channel" - echo "@openclaw/msteams # Add Microsoft Teams support" - - # Prompt user for plugin name - echo -n "Please enter the name of the plug-in to be installed (for example: @xzq-xu/feishu Feishu plug-in) (enter 0 to exit):" - read plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "The operation has been cancelled." - return 0 # 正常退出函数 - fi + # 2. Verify that the input is empty + if [ -z "$plugin_name" ]; then + echo "Error: The plug-in name cannot be empty, please re-enter it." + echo "" + continue + fi - # Verify input is empty - if [ -z "$plugin_name" ]; then - echo "Error: Plugin name cannot be empty. Please try again." - return 1 - fi + # 1. Completely clean up the remnants of previous failures (user directory) + rm -rf "/root/.openclaw/extensions/$plugin_name" - # Execute installation command - echo "Installing plugin:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 2. Check whether the system has been pre-installed (to prevent duplicate ID conflicts) + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 It is detected that the plug-in already exists in the system directory and is being activated directly..." + openclaw plugins enable "$plugin_name" + else + echo "📥 Downloading and installing the plug-in through official channels..." + # Use openclaw's own install command, which automatically handles spec checking of package.json + openclaw plugins install "$plugin_name" + + # 3. If openclaw install reports an error, try installing it as a normal npm package (last alternative) + if [ $? -ne 0 ]; then + echo "⚠️ The official installation failed, try to force the installation globally through npm..." + npm install -g "$plugin_name" --unsafe-perm + fi - # Check command execution results - if [ $? -eq 0 ]; then - echo "plug-in$plugin_nameInstallation successful." - else - echo "Installation failed. Please check that the plugin name is correct, or refer to the OpenClaw documentation to troubleshoot the issue." - fi + # 4. Finally, unified execution and activation + openclaw plugins enable "$plugin_name" + fi - break_end + start_tmux + break_end + done + } + + install_plugin() { + send_stats "Install plugin" + while true; do + clear + echo "========================================" + echo "Plug-in management (installation)" + echo "========================================" + echo "Current plugin list:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "Recommended commonly used plug-in IDs (just copy the ID in brackets):" + echo "--------------------------------------------------------" + echo "📱 Communication channels:" + echo "- [feishu] # Feishu/Lark integration" + echo "- [telegram] # Telegram bot" + echo "- [slack] #Slack Corporate Communications" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] # Discord community management" + echo "- [whatsapp] #WhatsApp Automation" + echo "" + echo "🧠 Memory and AI:" + echo "- [memory-core] # Basic memory (file retrieval)" + echo "- [memory-lancedb] # Enhanced memory (vector database)" + echo "- [copilot-proxy] # Copilot interface forwarding" + echo "" + echo "⚙️ Function expansion:" + echo "- [lobster] # Approval flow (with manual confirmation)" + echo "- [voice-call] # Voice call capability" + echo "- [nostr] # Encrypted private chat" + echo "--------------------------------------------------------" + + read -e -p "Please enter the plugin ID (enter 0 to exit):" raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. Automatic processing: If the user input contains @openclaw/, extract the pure ID to facilitate path checking + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 Checking plugin status..." + + # 2. Check whether it is already in the list and disabled (the most common case) + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 Plugin [$plugin_id] Pre-installed, activating..." + openclaw plugins enable "$plugin_id" && echo "✅Activation successful" || echo "❌ Activation failed" + + # 3. Check whether the system physical directory exists + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 Found that the plug-in exists in the system's built-in directory, try to enable it directly..." + openclaw plugins enable "$plugin_id" + + else + # 4. Remote installation logic + echo "📥 Not found locally, try to download and install..." + + # Clean up old failed remnants + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # Perform the installation and capture the results + if openclaw plugins install "$plugin_full"; then + echo "✅ Download successful, activating..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ Download from official channels failed, try alternatives..." + # Alternative npm installation + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm installed successfully, try to enable..." + openclaw plugins enable "$plugin_id" + else + echo "❌ Fatal error: Unable to obtain the plug-in. Please check if the ID is correct or if the network is available." + # Key: Return or continue directly here instead of starting_tmux below to prevent hard-coding the configuration. + break_end + continue + fi + fi + fi + + echo "🔄 Restarting OpenClaw service to load new plugins..." + start_tmux + break_end + done } + + + + + install_skill() { send_stats "Installation skills" + while true; do + clear + echo "========================================" + echo "Skill Management (Installation)" + echo "========================================" + echo "Currently installed skills:" + openclaw skills list + echo "----------------------------------------" + + # Output a list of recommended practical skills + echo "Recommended practical skills (you can directly copy the name and enter it):" + echo "github # Manage GitHub Issues/PR/CI (gh CLI)" + echo "notion # Manipulate Notion pages, databases and blocks" + echo "apple-notes # macOS native note management (create/edit/search)" + echo "apple-reminders # macOS reminder management (to-do list)" + echo "1password # Automate reading and injecting 1Password keys" + echo "gog # Google Workspace (Gmail/cloud disk/documents) all-round assistant" + echo "things-mac # Deep integration of Things 3 task management" + echo "bluebubbles # Send and receive iMessages perfectly with BlueBubbles" + echo "himalaya # Terminal mail management (IMAP/SMTP powerful tool)" + echo "summarize # One-click summary of webpage/podcast/YouTube video content" + echo "openhue # Control Philips Hue smart lighting scenes" + echo "video-frames # Video frame extraction and short clip editing (ffmpeg driver)" + echo "openai-whisper # Convert local audio to text (offline privacy protection)" + echo "coding-agent # Automatically run programming assistants such as Claude Code/Codex" + echo "----------------------------------------" + + # Prompt user to enter skill name + read -e -p "Please enter the name of the skill to be installed (enter 0 to exit):" skill_name + + # 1. Check if you entered 0 to exit + if [ "$skill_name" = "0" ]; then + echo "The operation has been canceled and the skill installation has been exited." + break + fi - echo "All skills" - openclaw skills list - # Output a list of recommended practical skills for users to copy - echo "Recommended practical skills (you can directly copy the name and enter it):" - echo "github-integration #Manage GitHub Issues and Pull Requests, support Webhook" - echo "notion-integration # Manipulate Notion database and pages" - echo "apple-notes # Manage Apple Notes for macOS/iOS" - echo "home-assistant # Control smart home via Home Assistant Hub" - echo "agent-browser # Headless browser automation using Playwright" - - # Prompt user to enter skill name - echo -n "Please enter the name of the skill to be installed (for example: github-integration) (enter 0 to exit):" - read skill_name - - if [ "$skill_name" = "0" ]; then - echo "The operation has been cancelled." - return 0 # 正常退出函数 - fi + # 2. Verify that the input is empty + if [ -z "$skill_name" ]; then + echo "Error: Skill name cannot be empty. Please try again." + echo "" + continue + fi - # Verify input is empty - if [ -z "$skill_name" ]; then - echo "Error: Skill name cannot be empty. Please try again." - return 1 - fi + # 3. Execute the installation command + echo "Installing skills:$skill_name ..." + npx clawhub install "$skill_name" - # Execute installation command - echo "Installing skills:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # Get the exit status of the previous command + if [ $? -eq 0 ]; then + echo "✅ Skills$skill_nameInstallation successful." + # Execute restart/start service logic + start_tmux + else + echo "❌ Installation failed. Please check whether the skill name is correct, or refer to the documentation for troubleshooting." + fi - # Check command execution results - if [ $? -eq 0 ]; then - echo "Skill$skill_nameInstallation successful." - else - echo "Installation failed. Please check that the skill name is correct, or refer to the OpenClaw documentation to troubleshoot the issue." - fi + break_end + done - break_end } change_tg_bot_code() { send_stats "Robot docking" - printf "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F) (enter 0 to exit):" - read code + read -e -p "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F) (enter 0 to exit):" code # Check if 0 is entered to exit if [ "$code" = "0" ]; then @@ -10022,6 +10200,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "Update OpenClaw..." send_stats "Update OpenClaw..." @@ -10046,6 +10225,138 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "Edit the OpenClaw configuration file" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } + + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI access address" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "Local address:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "Domain name address:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # Add a domain name (call the function you gave) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 18789 + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "Visit address:" + echo "https://${yuming}/?token=$token" + echo "First access the URL to trigger the device ID, then press Enter to proceed with pairing." + read + echo -e "${gl_kjlan}Loading device list...${gl_bai}" + openclaw devices list + + read -e -p "Please enter Request_Key:" Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key cannot be empty" + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # Delete domain name + openclaw_remove_domain() { + echo "Domain name format example.com without https://" + web_del + } + + # Main menu + openclaw_webui_menu() { + + send_stats "WebUI access and settings" + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. Add domain name access" + echo "2. Delete domain name access" + echo "0. Exit" + echo + read -e -p "Please select:" choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "Press Enter to return to the menu..." + ;; + 2) + openclaw_remove_domain + read -p "Press Enter to return to the menu..." + ;; + 0) + break + ;; + *) + echo "Invalid option" + sleep 1 + ;; + esac + done + } + + # main loop while true; do @@ -10061,13 +10372,18 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "Edit the OpenClaw configuration file" - install nano - nano ~/.openclaw/openclaw.json + 10) nano_openclaw_json ;; + 11) send_stats "Initial configuration wizard" + openclaw onboard --install-daemon + break_end ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 12) send_stats "Health detection and repair" + openclaw doctor --fix + break_end + ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done @@ -10113,7 +10429,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -10587,7 +10903,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -10641,7 +10957,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -10739,7 +11055,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11625,7 +11941,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11852,7 +12168,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11904,7 +12220,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11945,7 +12261,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12008,7 +12324,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12222,7 +12538,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -12249,7 +12565,7 @@ while true; do } - local docker_describe="A password manager that puts you in control of your data" + local docker_describe="A password manager where you can control your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12336,7 +12652,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12557,7 +12873,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12607,7 +12923,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12743,7 +13059,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12806,7 +13122,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -12970,7 +13286,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13058,7 +13374,7 @@ while true; do } - local docker_describe="Distributed high-speed download tool, supporting multiple protocols" + local docker_describe="分布式高速下载工具,支持多种协议" local docker_url="Official website introduction:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -13108,7 +13424,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13162,7 +13478,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13395,7 +13711,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13437,7 +13753,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13466,7 +13782,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13535,7 +13851,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13676,7 +13992,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13746,7 +14062,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13833,7 +14149,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through the web page." + local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through web pages." local docker_url="Project address:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -13892,7 +14208,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13954,7 +14270,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -13970,7 +14286,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" @@ -14269,32 +14585,32 @@ net_menu() { echo "4. Refresh network card information" echo "0. Return to the previous menu" echo "====================================" - read -rp "Please select an action:" choice + read -erp "Please select an action:" choice case $choice in 1) send_stats "Enable network card" - read -rp "Please enter the name of the network card to be enabled:" nic + read -erp "Please enter the name of the network card to be enabled:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ Network card$nicEnabled" else echo "✘ The network card does not exist" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 2) send_stats "Disable network card" - read -rp "Please enter the name of the network card to be disabled:" nic + read -erp "Please enter the name of the network card to be disabled:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ Network card$nicDisabled" else echo "✘ The network card does not exist" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 3) send_stats "View network card details" - read -rp "Please enter the name of the network card you want to view:" nic + read -erp "Please enter the name of the network card you want to view:" nic if ip link show "$nic" &>/dev/null; then echo "========== $nicDetails ==========" ip addr show "$nic" @@ -14302,7 +14618,7 @@ net_menu() { else echo "✘ The network card does not exist" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 4) send_stats "Refresh network card information" @@ -14338,32 +14654,32 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. View the latest system log (journal)" + echo "1. Check the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" echo "5. Clean up old journal logs" echo "0. Return to the previous menu" echo "=======================================" - read -rp "Please select an action:" choice + read -erp "Please select an action:" choice case $choice in 1) send_stats "View recent logs" - read -rp "View the most recent log lines? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 2) send_stats "View specified service logs" - read -rp "Please enter the service name (such as sshd, nginx):" svc + read -erp "Please enter the service name (such as sshd, nginx):" svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ The service does not exist or has no logs" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 3) send_stats "View login/security logs" @@ -14378,17 +14694,17 @@ log_menu() { else echo "Security log file not found" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." ;; 4) send_stats "Real-time tracking log" echo "1) System log" echo "2) Specify service log" - read -rp "Select tracking type:" t + read -erp "Select tracking type:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "Enter service name:" svc + read -erp "Enter service name:" svc journalctl -u "$svc" -f else echo "Invalid selection" @@ -14400,7 +14716,7 @@ log_menu() { echo "1) Keep the last 7 days" echo "2) Keep the last 3 days" echo "3) Limit the maximum log size to 500M" - read -rp "Please select a cleaning method:" c + read -erp "Please select a cleaning method:" c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14428,7 +14744,7 @@ env_menu() { show_env_vars() { clear - send_stats "Currently in effect environment variables" + send_stats "Environment variables currently in effect" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -14466,7 +14782,7 @@ env_menu() { echo echo "===============================================" - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." } @@ -14481,7 +14797,7 @@ env_menu() { else echo "File does not exist:$file" fi - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." } edit_file() { @@ -14497,7 +14813,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ Environment variables have been reloaded" - read -rp "Press Enter to continue..." + read -erp "Press Enter to continue..." } while true; do @@ -14514,7 +14830,7 @@ env_menu() { echo "--------------------------------------" echo "0. Return to the previous menu" echo "--------------------------------------" - read -rp "Please select an action:" choice + read -erp "Please select an action:" choice case "$choice" in 1) @@ -14695,7 +15011,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -14787,7 +15103,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # Read the current SSH port number local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14805,7 +15121,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH port has been modified" - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "Exit SSH port modification" break @@ -14881,8 +15197,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -15114,7 +15430,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil time 26. Argentina time" + echo "25. Brazil Time 26. Argentina Time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -15372,7 +15688,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -15593,7 +15909,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -15617,8 +15933,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 3/12. Set up virtual memory${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. Set the SSH port number to${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd @@ -15642,7 +15957,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -16004,7 +16319,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16038,7 +16353,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16146,7 +16461,7 @@ echo "------------------------" echo -e "${gl_zi}Hostinger $52.7 per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan SoftBank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" +echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT $28 per quarter US CN2GIA 1 core 2G memory 20G hard drive 800G traffic per month${gl_bai}" @@ -16155,7 +16470,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16361,7 +16676,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}Collection of game server opening scripts" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}Exit script" +echo -e "${gl_kjlan}0. ${gl_bai}exit script" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "Please enter your choice:" choice @@ -16394,7 +16709,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" @@ -16599,12 +16914,12 @@ else ;; stop|停止) shift - send_stats "software pause" + send_stats "Software paused" stop "$@" ;; restart|重启) shift - send_stats "Software restart" + send_stats "software restart" restart "$@" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a8eac2d93..48236959d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -866,7 +866,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1189,7 +1189,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2116,7 +2116,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2234,7 +2234,7 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" + echo "CF パラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2349,7 +2349,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2555,7 +2555,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2691,7 +2691,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3530,7 +3530,7 @@ list_stream_services() { fi for conf in "$STREAM_DIR"/*; do - # サービス名がファイル名になります + # サービス名はファイル名を取得します service_name=$(basename "$conf" .conf) # 上流ブロックでサーバーのバックエンド IP:ポートを取得します。 @@ -3652,20 +3652,20 @@ ldnmp_Proxy_backend_stream() { echo "導入を開始する$webname" # エージェント名を取得する - read -rp "プロキシ転送名を入力してください (例: mysql_proxy):" proxy_name + read -erp "プロキシ転送名を入力してください (例: mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then echo "名前を空にすることはできません"; return 1 fi # リスニングポートの取得 - read -rp "ローカルのリスニング ポート (3306 など) を入力してください。" listen_port + read -erp "ローカルのリスニング ポート (3306 など) を入力してください。" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "ポートは数値である必要があります"; return 1 fi echo "契約の種類を選択してください:" echo "1. TCP 2. UDP" - read -rp "シリアル番号を入力してください [1-2]:" proto_choice + read -erp "シリアル番号を入力してください [1-2]:" proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -4231,7 +4231,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4336,7 +4336,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4751,7 +4751,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -5385,7 +5387,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5520,7 +5522,7 @@ bbrv3() { clear local kernel_version=$(uname -r) echo "xanmod の BBRv3 カーネルがインストールされている" - echo "現在のカーネルのバージョン:$kernel_version" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5678,7 +5680,7 @@ elrepo() { clear kernel_version=$(uname -r) echo "elrepo カーネルがインストールされています" - echo "現在のカーネルのバージョン:$kernel_version" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5719,7 +5721,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5767,7 +5769,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6027,7 +6029,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -6144,7 +6146,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6317,9 +6319,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6361,7 +6363,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6449,7 +6451,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6649,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# パーティションをマウントする + +# 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # パーティションが存在するかどうかを確認する - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "パーティションが存在しません!" - return + return 1 fi - # パーティションがマウントされているかどうかを確認する - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # 実装されているか確認する + if mount | grep -qw "$DEVICE"; then echo "パーティションが取り付けられました!" - return + return 1 + fi + + # UUIDを取得する + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "UUIDを取得できません!" + return 1 + fi + + # ファイルシステムの種類を取得する + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "ファイル システム タイプを取得できません!" + return 1 fi # マウントポイントの作成 - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # パーティションをマウントする - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "パーティションは正常にマウントされました:$MOUNT_POINT" - else + # マウント + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "パーティションのマウントに失敗しました!" rmdir "$MOUNT_POINT" + return 1 + fi + + echo "パーティションは正常にマウントされました$MOUNT_POINT" + + # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "パーティション レコードは /etc/fstab にすでに存在するため、書き込みをスキップします" + return 0 fi + + # /etc/fstab に書き込みます + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "永続的なマウントを実現するために /etc/fstab に書き込まれます" } + # パーティションをアンマウントする unmount_partition() { send_stats "パーティションをアンマウントする" @@ -6782,7 +6812,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6801,7 +6831,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -6830,7 +6860,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -6998,7 +7028,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7088,7 +7118,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7157,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "システム情報の問い合わせ" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" @@ -7207,7 +7236,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" tools=( @@ -7331,7 +7360,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7389,7 +7418,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncduをインストールする" + send_stats "ncdu をインストールする" ;; 14) clear @@ -7633,7 +7662,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7728,7 +7757,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -7810,7 +7839,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -7916,7 +7945,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -7960,7 +7989,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8059,7 +8088,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9591,19 +9620,19 @@ moltbot_menu() { send_stats "クロードボット/モルトボットの管理" check_openclaw_update() { - # まず、NPM が利用可能かどうかを確認します if ! command -v npm >/dev/null 2>&1; then return 1 fi - # NPM を使用してローカル バージョンをクエリし、プレフィックス (openclaw@ など) を削除します。 - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # --no-update-notifier を追加し、エラー リダイレクトが正しい場所にあることを確認します。 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # NPM を使用してリモート バージョンをクエリする - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi @@ -9627,7 +9656,7 @@ moltbot_menu() { if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}ランニング${gl_bai}" else - echo "${gl_hui}稼働していない${gl_bai}" + echo "${gl_hui}実行されていません${gl_bai}" fi } @@ -9655,9 +9684,12 @@ moltbot_menu() { echo "8. プラグイン(Feishuなど)をインストールする" echo "9. スキルのインストール" echo "10. メイン設定ファイルを編集します" + echo "11. 設定ウィザード" + echo "12. 健全性の検出と修復" + echo "13. WebUI へのアクセスと設定" echo "--------------------" - echo "11. アップデート" - echo "12. アンインストール" + echo "14. アップデート" + echo "15. アンインストール" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -9730,7 +9762,7 @@ moltbot_menu() { local base_url="$3" local api_key="$4" - echo "=== OpenAI 互換のカスタム モデルを OpenClaw に追加 ===" + echo "=== カスタム OpenAI 互換モデルを OpenClaw に追加 ===" echo "Provider: $provider_name" echo "Model ID: $models_id" echo "Base URL: $base_url" @@ -9827,24 +9859,24 @@ moltbot_menu() { echo "=== OpenClaw プロバイダーを対話的に追加します ===" # プロバイダ名 - read -rp "プロバイダー名を入力してください (例: deepseek):" provider_name + read -erp "プロバイダー名を入力してください (例: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ プロバイダー名を空にすることはできません" - read -rp "プロバイダー名を入力してください:" provider_name + read -erp "プロバイダー名を入力してください:" provider_name done # Model ID - read -rp "モデル ID を入力してください (例: deepseek-chat):" model_id + read -erp "モデル ID を入力してください (例: deepseek-chat):" model_id while [[ -z "$model_id" ]]; do echo "❌ モデル ID を空にすることはできません" - read -rp "モデルIDを入力してください:" model_id + read -erp "モデルIDを入力してください:" model_id done # Base URL - read -rp "ベース URL (例: https://api.xxx.com/v1) を入力してください:" base_url + read -erp "ベース URL (例: https://api.xxx.com/v1) を入力してください:" base_url while [[ -z "$base_url" ]]; do echo "❌ ベース URL を空にすることはできません" - read -rp "ベース URL を入力してください:" base_url + read -erp "ベース URL を入力してください:" base_url done # API キー (隠し入力) @@ -9864,7 +9896,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "追加を確認しますか? (y/N):" confirm + read -erp "追加を確認しますか? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ キャンセルされました" return 1 @@ -9884,28 +9916,39 @@ moltbot_menu() { change_model() { send_stats "機種変更" - echo "すべてのモデル:" - openclaw models list --all - echo "現在のモデル:" - openclaw models list - printf "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" - read model - # 終了するには0が入力されているかどうかを確認してください - if [ "$model" = "0" ]; then - echo "操作はキャンセルされました。" - return 0 # 正常退出函数 - fi + while true; do + clear + echo "---モデル管理---" + echo "すべてのモデル:" + openclaw models list --all + echo "----------------" + echo "現在のモデル:" + openclaw models list + echo "----------------" + read -e -p "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" model + + # 1.終了するには0を入力したかどうかを確認します + if [ "$model" = "0" ]; then + echo "操作がキャンセルされました。終了しています..." + break # 跳出 while 循环 - # 入力が空であることを確認してください - if [ -z "$model" ]; then - echo "エラー: モデル名を空にすることはできません。もう一度試してください。" - return 1 - fi + fi + + # 2. 入力が空であることを確認します + if [ -z "$model" ]; then + echo "エラー: モデル名を空にすることはできません。もう一度試してください。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. スイッチングロジックの実行 + echo "切り替わる機種は以下の通りです。$model ..." + openclaw models set "$model" + + break_end + done - echo "モデルを次のように切り替えます$model" - openclaw models set "$model" - break_end } @@ -9914,97 +9957,232 @@ moltbot_menu() { install_plugin() { send_stats "プラグインのインストール" + while true; do + clear + echo "========================================" + echo "プラグイン管理(インストール)" + echo "========================================" + echo "現在インストールされているプラ​​グイン:" + openclaw plugins list + echo "----------------------------------------" + + # ユーザーがコピーできる推奨実用プラグインのリストを出力します + echo "推奨される実用的なプラグイン (名前入力を直接コピーできます):" + echo "feishu # Feishu/Lark 統合 (現在ロード中 ✓)" + echo "telegram # Telegram ボットの統合 (現在ロードされています ✓)" + echo "Memory-core # コア メモリの強化: ファイルベースのコンテキスト検索 (現在ロードされています ✓)" + echo "@openclaw/slack # Slack チャネルと DM 間の深いつながり" + echo "@openclaw/bluebubbles # iMessage ブリッジ (macOS ユーザーに推奨)" + echo "@openclaw/msteams #Microsoft Teams エンタープライズ コミュニケーションの統合" + echo "@openclaw/voice-call # 音声通話プラグイン (Twilio などのバックエンドに基づく)" + echo "@openclaw/discord #Discordチャンネル自動管理" + echo "@openclaw/nostr # Nostr プロトコル: プライベートで安全な暗号化チャット" + echo "lobster # 承認ワークフロー: 人間の介入によるタスクの自動化" + echo "Memory-lancedb # 長期記憶強化: ベクトルデータベースに基づく正確な記憶" + echo "copilot-proxy # GitHub Copilot プロキシ アクセスの強化" + echo "----------------------------------------" + + # ユーザーにプラグイン名の入力を求めるプロンプト + read -e -p "インストールするプラグインの名前を入力してください (終了するには 0 を入力します):" plugin_name + + # 1.終了するには0を入力したかどうかを確認します + if [ "$plugin_name" = "0" ]; then + echo "操作がキャンセルされ、プラグインのインストールが終了しました。" + break + fi - echo "すべてのプラグイン" - openclaw plugins list - # ユーザーがコピーできる推奨実用プラグインのリストを出力します - echo "推奨される実用的なプラグイン (名前入力を直接コピーできます):" - echo "@openclaw/voice-call # 音声通話機能を有効にし、Twilio 統合をサポートします" - echo "@openclaw/matrix # Matrix プロトコルのメッセージ チャネル統合を提供します" - echo "@openclaw/nostr # Nostr プロトコルのメッセージ チャネルをサポート" - echo "@adongguo/openclaw-dingtalk # 統合された DingTalk メッセージ チャネル" - echo "@openclaw/msteams # Microsoft Teams サポートを追加" - - # ユーザーにプラグイン名の入力を求めるプロンプト - echo -n "インストールするプラグインの名前を入力してください (例: @xzq-xu/feishu Feishu プラグイン) (終了するには 0 を入力します):" - read plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "操作はキャンセルされました。" - return 0 # 正常退出函数 - fi + # 2. 入力が空であることを確認します + if [ -z "$plugin_name" ]; then + echo "エラー: プラグイン名を空にすることはできません。再入力してください。" + echo "" + continue + fi - # 入力が空であることを確認してください - if [ -z "$plugin_name" ]; then - echo "エラー: プラグイン名を空にすることはできません。もう一度試してください。" - return 1 - fi + # 1. 以前の失敗の残骸 (ユーザー ディレクトリ) を完全にクリーンアップします。 + rm -rf "/root/.openclaw/extensions/$plugin_name" - # インストールコマンドを実行する - echo "プラグインのインストール:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 2. システムがプリインストールされているかどうかを確認します (重複 ID の競合を防ぐため)。 + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 プラグインが既にシステム ディレクトリに存在し、直接アクティブ化されていることが検出されました..." + openclaw plugins enable "$plugin_name" + else + echo "📥 公式チャネルを通じてプラグインをダウンロードしてインストールしています..." + # openclaw 独自の install コマンドを使用して、package.json の仕様チェックを自動的に処理します。 + openclaw plugins install "$plugin_name" + + # 3. openclaw のインストールでエラーが報告された場合は、通常の npm パッケージとしてインストールしてみてください (最後の選択肢) + if [ $? -ne 0 ]; then + echo "⚠️ 公式インストールが失敗しました。npm を介してグローバルにインストールを強制してみてください..." + npm install -g "$plugin_name" --unsafe-perm + fi - # コマンドの実行結果を確認する - if [ $? -eq 0 ]; then - echo "プラグイン$plugin_nameインストールが成功しました。" - else - echo "インストールに失敗しました。プラグイン名が正しいことを確認するか、OpenClaw のドキュメントを参照して問題のトラブルシューティングを行ってください。" - fi + # 4. 最後に、統合された実行とアクティブ化 + openclaw plugins enable "$plugin_name" + fi - break_end + start_tmux + break_end + done } + install_plugin() { + send_stats "プラグインのインストール" + while true; do + clear + echo "========================================" + echo "プラグイン管理(インストール)" + echo "========================================" + echo "現在のプラグインのリスト:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推奨される一般的に使用されるプラグイン ID (括弧内の ID をコピーするだけです):" + echo "--------------------------------------------------------" + echo "📱 コミュニケーションチャネル:" + echo "- [フェイシュ] #フェイシュ/ラーク統合" + echo "- [電報] #電報ボット" + echo "- [slack] #Slack コーポレートコミュニケーション" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] #Discordコミュニティ運営" + echo "- [whatsapp] #WhatsApp オートメーション" + echo "" + echo "🧠 メモリと AI:" + echo "- [memory-core] # 基本メモリ (ファイル検索)" + echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" + echo "- [copilot-proxy] # コパイロットインターフェイスの転送" + echo "" + echo "⚙️機能拡張:" + echo "- [lobster] # 承認フロー(手動確認あり)" + echo "- [voice-call] # 音声通話機能" + echo "- [nostr] # 暗号化されたプライベートチャット" + echo "--------------------------------------------------------" + + read -e -p "プラグイン ID を入力してください (終了するには 0 を入力してください):" raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. 自動処理: ユーザー入力に @openclaw/ が含まれている場合、パスのチェックを容易にするために純粋な ID を抽出します。 + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 プラグインのステータスを確認しています..." + + # 2. すでにリストに含まれていて無効になっているかどうかを確認します (最も一般的なケース)。 + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡プラグイン [$plugin_id] プリインストールされており、アクティベート中..." + openclaw plugins enable "$plugin_id" && echo "✅アクティベーション成功" || echo "❌ アクティベーションに失敗しました" + + # 3. システムの物理ディレクトリが存在するかどうかを確認します + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 プラグインがシステムの組み込みディレクトリに存在することがわかりました。直接有効にしてみてください..." + openclaw plugins enable "$plugin_id" + + else + # 4. リモートインストールロジック + echo "📥 ローカルに見つかりません。ダウンロードしてインストールしてください..." + + # 失敗した古い残骸をクリーンアップする + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # インストールを実行し、結果を取得します + if openclaw plugins install "$plugin_full"; then + echo "✅ ダウンロードが成功しました。アクティブ化されています..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ 公式チャネルからのダウンロードに失敗しました。代替手段をお試しください..." + # 代替の npm インストール + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm が正常にインストールされました。有効にしてみてください..." + openclaw plugins enable "$plugin_id" + else + echo "❌ 致命的なエラー: プラグインを取得できません。 IDが正しいか、ネットワークが利用可能か確認してください。" + # キー: 構成のハードコーディングを防ぐために、以下の starting_tmux ではなく、ここに直接戻るか続行します。 + break_end + continue + fi + fi + fi + + echo "🔄 新しいプラグインをロードするために OpenClaw サービスを再起動しています..." + start_tmux + break_end + done + } + + + + + + install_skill() { send_stats "取り付けスキル" + while true; do + clear + echo "========================================" + echo "スキル管理(インストール)" + echo "========================================" + echo "現在インストールされているスキル:" + openclaw skills list + echo "----------------------------------------" + + # 推奨実践スキルリストを出力 + echo "推奨される実践スキル (名前を直接コピーして入力できます):" + echo "github # GitHub の問題/PR/CI を管理する (gh CLI)" + echo "notion # Notion のページ、データベース、ブロックを操作する" + echo "apple-notes # macOS ネイティブのノート管理 (作成/編集/検索)" + echo "apple-reminders # macOS リマインダー管理 (ToDo リスト)" + echo "1password # 1Password キーの読み取りと挿入を自動化します" + echo "gog # Google Workspace (Gmail/クラウド ディスク/ドキュメント) 万能アシスタント" + echo "things-mac # Things 3 タスク管理の緊密な統合" + echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" + echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "openhue # Philips Hue スマート照明シーンを制御する" + echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" + echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" + echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" + echo "----------------------------------------" + + # ユーザーにスキル名の入力を求める + read -e -p "インストールするスキルの名前を入力してください (終了するには 0 を入力してください):" skill_name + + # 1.終了するには0を入力したかどうかを確認します + if [ "$skill_name" = "0" ]; then + echo "操作がキャンセルされ、スキルのインストールが終了しました。" + break + fi - echo "すべてのスキル" - openclaw skills list - # ユーザーが真似できる推奨実践スキルリストを出力 - echo "推奨される実践スキル (名前を直接コピーして入力できます):" - echo "github-integration #GitHub の問題とプル リクエストの管理、Webhook のサポート" - echo "notion-integration # Notion データベースとページを操作する" - echo "apple-notes # macOS/iOS 用の Apple Notes を管理する" - echo "home-assist # ホーム アシスタント ハブ経由でスマート ホームを制御" - echo "Agent-Browser # Playwright を使用したヘッドレス ブラウザ自動化" - - # ユーザーにスキル名の入力を求める - echo -n "インストールするスキルの名前を入力してください (例: github-integration) (終了するには 0 を入力します):" - read skill_name - - if [ "$skill_name" = "0" ]; then - echo "操作はキャンセルされました。" - return 0 # 正常退出函数 - fi + # 2. 入力が空であることを確認します + if [ -z "$skill_name" ]; then + echo "エラー: スキル名を空にすることはできません。もう一度試してください。" + echo "" + continue + fi - # 入力が空であることを確認してください - if [ -z "$skill_name" ]; then - echo "エラー: スキル名を空にすることはできません。もう一度試してください。" - return 1 - fi + # 3. インストールコマンドを実行します。 + echo "スキルのインストール:$skill_name ..." + npx clawhub install "$skill_name" - # インストールコマンドを実行する - echo "スキルのインストール:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # 前のコマンドの終了ステータスを取得する + if [ $? -eq 0 ]; then + echo "✅ スキル$skill_nameインストールが成功しました。" + # 再起動/サービス開始ロジックの実行 + start_tmux + else + echo "❌ インストールに失敗しました。スキル名が正しいか確認するか、ドキュメントを参照してトラブルシューティングを行ってください。" + fi - # コマンドの実行結果を確認する - if [ $? -eq 0 ]; then - echo "スキル$skill_nameインストールが成功しました。" - else - echo "インストールに失敗しました。スキル名が正しいことを確認するか、OpenClaw のドキュメントを参照して問題のトラブルシューティングを行ってください。" - fi + break_end + done - break_end } change_tg_bot_code() { send_stats "ロボットドッキング" - printf "TG ロボットが受信した接続コード (例: ペアリング コード: NYA99R2F) を入力してください (終了するには 0 を入力します)。" - read code + read -e -p "TG ロボットが受信した接続コード (例: ペアリング コード: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code # 終了するには0が入力されているかどうかを確認してください if [ "$code" = "0" ]; then @@ -10022,6 +10200,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "OpenClaw を更新..." send_stats "OpenClaw を更新..." @@ -10046,6 +10225,138 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "OpenClaw 構成ファイルを編集する" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } + + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI アクセス アドレス" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "ローカルアドレス:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "ドメイン名アドレス:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # ドメイン名を追加します(指定した関数を呼び出します) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 18789 + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "訪問先住所:" + echo "https://${yuming}/?token=$token" + echo "まず URL にアクセスしてデバイス ID をトリガーし、Enter キーを押してペアリングを続行します。" + read + echo -e "${gl_kjlan}デバイスリストを読み込んでいます...${gl_bai}" + openclaw devices list + + read -e -p "Request_Key を入力してください:" Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key を空にすることはできません" + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # ドメイン名の削除 + openclaw_remove_domain() { + echo "ドメイン名の形式 example.com (https:// なし)" + web_del + } + + # メインメニュー + openclaw_webui_menu() { + + send_stats "WebUI へのアクセスと設定" + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. ドメイン名アクセスを追加する" + echo "2. ドメイン名アクセスの削除" + echo "0.終了" + echo + read -e -p "選択してください:" choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "Enter を押してメニューに戻ります..." + ;; + 2) + openclaw_remove_domain + read -p "Enter を押してメニューに戻ります..." + ;; + 0) + break + ;; + *) + echo "無効なオプション" + sleep 1 + ;; + esac + done + } + + # メインループ while true; do @@ -10061,13 +10372,18 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "OpenClaw 設定ファイルを編集する" - install nano - nano ~/.openclaw/openclaw.json + 10) nano_openclaw_json ;; + 11) send_stats "初期設定ウィザード" + openclaw onboard --install-daemon + break_end ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 12) send_stats "健全性の検出と修復" + openclaw doctor --fix + break_end + ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done @@ -10113,7 +10429,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -10151,7 +10467,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -10161,7 +10477,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -11348,7 +11664,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -12249,7 +12565,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12497,7 +12813,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12712,7 +13028,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -12806,7 +13122,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -12836,7 +13152,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -13182,7 +13498,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -13437,7 +13753,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13892,7 +14208,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリケーションのバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13954,8 +14270,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -13970,7 +14286,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo.10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" @@ -14269,32 +14585,32 @@ net_menu() { echo "4. ネットワークカード情報を更新する" echo "0. 前のメニューに戻る" echo "====================================" - read -rp "アクションを選択してください:" choice + read -erp "アクションを選択してください:" choice case $choice in 1) send_stats "ネットワークカードを有効にする" - read -rp "有効にするネットワーク カードの名前を入力してください:" nic + read -erp "有効にするネットワーク カードの名前を入力してください:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ ネットワークカード$nic有効" else echo "✘ ネットワークカードが存在しません" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" - read -rp "無効にするネットワーク カードの名前を入力してください:" nic + read -erp "無効にするネットワーク カードの名前を入力してください:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ ネットワークカード$nic無効" else echo "✘ ネットワークカードが存在しません" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" - read -rp "表示したいネットワーク カードの名前を入力してください:" nic + read -erp "表示したいネットワーク カードの名前を入力してください:" nic if ip link show "$nic" &>/dev/null; then echo "========== $nic詳細 ==========" ip addr show "$nic" @@ -14302,7 +14618,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -14328,7 +14644,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記帳の職業】" + echo "【日記ログ職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -14338,32 +14654,32 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を表示する" + echo "1. 最新のシステムログ(ジャーナル)を確認する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" echo "5. 古いジャーナル ログをクリーンアップする" echo "0. 前のメニューに戻る" echo "=======================================" - read -rp "アクションを選択してください:" choice + read -erp "アクションを選択してください:" choice case $choice in 1) send_stats "最近のログを表示する" - read -rp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" - read -rp "サービス名 (sshd、nginx など) を入力してください:" svc + read -erp "サービス名 (sshd、nginx など) を入力してください:" svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ サービスが存在しないか、ログがありません" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -14378,17 +14694,17 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" echo "1) システムログ" echo "2) サービスログの指定" - read -rp "追跡タイプを選択します:" t + read -erp "追跡タイプを選択します:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "サービス名を入力してください:" svc + read -erp "サービス名を入力してください:" svc journalctl -u "$svc" -f else echo "無効な選択" @@ -14400,7 +14716,7 @@ log_menu() { echo "1) 過去 7 日間を保存します" echo "2) 過去 3 日間を保存します" echo "3) 最大ログ サイズを 500M に制限する" - read -rp "クリーニング方法を選択してください:" c + read -erp "クリーニング方法を選択してください:" c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14466,7 +14782,7 @@ env_menu() { echo echo "===============================================" - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -14481,7 +14797,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -14497,7 +14813,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -rp "Enter キーを押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -14508,13 +14824,13 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集する" + echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" - read -rp "アクションを選択してください:" choice + read -erp "アクションを選択してください:" choice case "$choice" in 1) @@ -14625,7 +14941,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -14700,7 +15016,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -14787,7 +15103,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # 現在の SSH ポート番号を読み取ります local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14805,7 +15121,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSHポートが変更されました" - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "SSHポート変更の終了" break @@ -14881,8 +15197,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -15372,7 +15688,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -15617,8 +15933,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}】3/12。仮想メモリを設定する${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}】4/12。 SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd @@ -15816,7 +16131,7 @@ linux_file() { 4) # 重命名目录 read -e -p "現在のディレクトリ名を入力してください:" current_name read -e -p "新しいディレクトリ名を入力してください:" new_name - mv "$current_name" "$new_name" && echo "ディレクトリ名が変更されました" || echo "名前の変更に失敗しました" + mv "$current_name" "$new_name" && echo "ディレクトリの名前が変更されました" || echo "名前の変更に失敗しました" send_stats "ディレクトリの名前を変更する" ;; 5) # 删除目录 @@ -15877,7 +16192,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -15897,7 +16212,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -16004,7 +16319,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16033,12 +16348,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16078,7 +16393,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -16152,10 +16467,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16394,7 +16709,7 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -16410,7 +16725,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -16424,16 +16739,16 @@ echo "ドメイン名証明書アプリケーション k ssl" echo "ドメイン名証明書の有効期限のクエリ k ssl ps" echo "docker 管理プレーン k docker" echo "docker 環境のインストール k docker install |k docker インストール" -echo "docker容器管理 k docker ps |k docker 容器" +echo "docker コンテナ管理 k docker ps |k docker コンテナ" echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -16599,7 +16914,7 @@ else ;; stop|停止) shift - send_stats "ソフトウェアの一時停止" + send_stats "ソフトウェアが一時停止されました" stop "$@" ;; restart|重启) @@ -16634,7 +16949,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 9f05189dd..55b9135b9 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1093,7 +1093,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 삭제" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1200,7 +1200,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1540,7 +1540,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -1832,7 +1832,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2005,7 +2005,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2062,7 +2062,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2783,7 +2783,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2799,7 +2799,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3341,10 +3341,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3354,7 +3354,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3430,7 +3430,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3646,26 +3646,26 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" # 에이전트 이름 가져오기 - read -rp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name + read -erp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name if [ -z "$proxy_name" ]; then echo "이름은 비워둘 수 없습니다."; return 1 fi # 수신 포트 가져오기 - read -rp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port + read -erp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "포트는 숫자여야 합니다."; return 1 fi echo "계약 유형을 선택하십시오:" echo "1. TCP 2. UDP" - read -rp "일련 번호 [1-2]를 입력하십시오:" proto_choice + read -erp "일련 번호 [1-2]를 입력하십시오:" proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -3694,7 +3694,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4336,7 +4336,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -4894,7 +4896,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5008,7 +5010,7 @@ fetch_github_ssh_keys() { echo "1. 로그인${gh_https_url}github.com/settings/keys" echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" - echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." + echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여 넣습니다." echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." echo "" echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." @@ -5719,7 +5721,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6261,7 +6263,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6500,11 +6502,11 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6649,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 마운트 파티션 + +# 지속적으로 마운트된 파티션 mount_partition() { send_stats "마운트 파티션" read -e -p "마운트할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # 파티션이 존재하는지 확인 - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "파티션이 존재하지 않습니다!" - return + return 1 fi - # 파티션이 마운트되었는지 확인 - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # 마운트되어 있는지 확인해보세요 + if mount | grep -qw "$DEVICE"; then echo "파티션이 마운트되었습니다!" - return + return 1 + fi + + # UUID 가져오기 + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "UUID를 얻을 수 없습니다!" + return 1 + fi + + # 파일 시스템 유형 가져오기 + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "파일 시스템 유형을 가져올 수 없습니다!" + return 1 fi # 마운트 지점 생성 - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 마운트 파티션 - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "파티션이 성공적으로 마운트되었습니다:$MOUNT_POINT" - else + # 산 + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "파티션 마운트에 실패했습니다!" rmdir "$MOUNT_POINT" + return 1 + fi + + echo "파티션이 성공적으로 마운트되었습니다.$MOUNT_POINT" + + # /etc/fstab을 확인하여 UUID 또는 마운트 지점이 이미 존재하는지 확인하세요. + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "파티션 기록이 /etc/fstab에 이미 존재합니다. 쓰기를 건너뛰세요." + return 0 fi + + # /etc/fstab에 쓰기 + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "지속적인 마운트를 위해 /etc/fstab에 기록" } + # 파티션 마운트 해제 unmount_partition() { send_stats "파티션 마운트 해제" @@ -6782,7 +6812,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6848,11 +6878,11 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7157,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "시스템 정보 쿼리" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}호스트 이름:${gl_bai}$hostname" @@ -7830,7 +7859,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -8029,7 +8058,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8390,7 +8419,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9125,7 +9154,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -9591,19 +9620,19 @@ moltbot_menu() { send_stats "클로드봇/몰트봇 관리" check_openclaw_update() { - # 먼저 NPM을 사용할 수 있는지 확인하세요. if ! command -v npm >/dev/null 2>&1; then return 1 fi - # NPM을 사용하여 로컬 버전을 쿼리하고 접두사(예: openclaw@)를 제거합니다. - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # --no-update-notifier를 추가하고 오류 리디렉션이 올바른 위치에 있는지 확인하세요. + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # NPM을 사용하여 원격 버전 쿼리 - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi @@ -9655,9 +9684,12 @@ moltbot_menu() { echo "8. 플러그인 설치(예: Feishu)" echo "9. 스킬 설치" echo "10. 기본 구성 파일 편집" + echo "11. 구성 마법사" + echo "12. 건강 상태 감지 및 복구" + echo "13. WebUI 접속 및 설정" echo "--------------------" - echo "11. 업데이트" - echo "12. 제거" + echo "14. 업데이트" + echo "15. 제거" echo "--------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------" @@ -9803,7 +9835,7 @@ moltbot_menu() { fi } - # 선택사항: 자동으로 기본값을 설정하고 다시 시작합니다. + # 선택 사항: 자동으로 기본값을 설정하고 다시 시작합니다. add-openclaw-provider-and-switch() { install jq @@ -9827,24 +9859,24 @@ moltbot_menu() { echo "=== 대화식으로 OpenClaw 공급자 추가 ===" # 제공자 이름 - read -rp "공급자 이름을 입력하십시오(예: deepseek):" provider_name + read -erp "공급자 이름을 입력하십시오(예: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ 제공업체 이름은 비워둘 수 없습니다." - read -rp "제공업체 이름을 입력하세요." provider_name + read -erp "제공업체 이름을 입력하세요." provider_name done # Model ID - read -rp "모델 ID를 입력하세요(예: deepseek-chat):" model_id + read -erp "모델 ID를 입력하세요(예: deepseek-chat):" model_id while [[ -z "$model_id" ]]; do echo "❌ 모델 ID는 비워둘 수 없습니다." - read -rp "모델 ID를 입력하세요:" model_id + read -erp "모델 ID를 입력하세요:" model_id done # Base URL - read -rp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url + read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ 기본 URL은 비워둘 수 없습니다." - read -rp "기본 URL을 입력하세요:" base_url + read -erp "기본 URL을 입력하세요:" base_url done # API 키(숨겨진 입력) @@ -9864,7 +9896,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "추가하시겠습니까? (예/아니요):" confirm + read -erp "추가하시겠습니까? (예/아니요):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 취소됨" return 1 @@ -9884,28 +9916,39 @@ moltbot_menu() { change_model() { send_stats "모델 변경" - echo "모든 모델:" - openclaw models list --all - echo "현재 모델:" - openclaw models list - printf "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." - read model - # 0을 입력했는지 확인하여 종료하세요. - if [ "$model" = "0" ]; then - echo "작업이 취소되었습니다." - return 0 # 正常退出函数 - fi + while true; do + clear + echo "---모델 관리 ---" + echo "모든 모델:" + openclaw models list --all + echo "----------------" + echo "현재 모델:" + openclaw models list + echo "----------------" + read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." model + + # 1. 0을 입력하여 종료했는지 확인하세요. + if [ "$model" = "0" ]; then + echo "작업이 취소되었습니다. 종료하는 중..." + break # 跳出 while 循环 - # 입력이 비어 있는지 확인 - if [ -z "$model" ]; then - echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." - return 1 - fi + fi + + # 2. 입력이 비어 있는지 확인하십시오. + if [ -z "$model" ]; then + echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. 스위칭 로직 실행 + echo "전환되는 모델은 다음과 같습니다.$model ..." + openclaw models set "$model" + + break_end + done - echo "모델을 다음으로 전환하세요.$model" - openclaw models set "$model" - break_end } @@ -9914,97 +9957,232 @@ moltbot_menu() { install_plugin() { send_stats "플러그인 설치" + while true; do + clear + echo "========================================" + echo "플러그인 관리(설치)" + echo "========================================" + echo "현재 설치된 플러그인:" + openclaw plugins list + echo "----------------------------------------" + + # 사용자가 복사할 수 있는 권장 실무 플러그인 목록 출력 + echo "추천 실용 플러그인(이름 입력을 직접 복사할 수 있음):" + echo "feishu # Feishu/Lark 통합 (현재 로드됨 ✓)" + echo "텔레그램 # 텔레그램 봇 통합 (현재 로드됨 ✓)" + echo "memory-core # 핵심 메모리 강화: 파일 기반 상황별 검색(현재 로드됨 ✓)" + echo "@openclaw/slack # Slack 채널과 DM 간의 깊은 연결" + echo "@openclaw/bluebubbles # iMessage 브리지(macOS 사용자에게 선호됨)" + echo "@openclaw/msteams #Microsoft Teams 엔터프라이즈 커뮤니케이션 통합" + echo "@openclaw/voice-call # 음성 통화 플러그인 (Twilio와 같은 백엔드 기반)" + echo "@openclaw/discord # 디스코드 채널 자동 관리" + echo "@openclaw/nostr # Nostr 프로토콜: 비공개적이고 안전한 암호화된 채팅" + echo "랍스터 # 승인 워크플로: 사람의 개입으로 자동화된 작업" + echo "memory-lancedb # 장기 기억력 향상: 벡터 데이터베이스 기반의 정확한 재현" + echo "copilot-proxy # GitHub Copilot 프록시 액세스 향상" + echo "----------------------------------------" + + # 사용자에게 플러그인 이름을 묻는 메시지 표시 + read -e -p "설치하려는 플러그인의 이름을 입력하십시오(종료하려면 0을 입력하십시오):" plugin_name + + # 1. 0을 입력하여 종료했는지 확인하세요. + if [ "$plugin_name" = "0" ]; then + echo "작업이 취소되고 플러그인 설치가 종료되었습니다." + break + fi - echo "모든 플러그인" - openclaw plugins list - # 사용자가 복사할 수 있는 권장 실무 플러그인 목록 출력 - echo "추천 실용 플러그인(이름 입력을 직접 복사할 수 있음):" - echo "@openclaw/voice-call # 음성 통화 기능 활성화, Twilio 통합 지원" - echo "@openclaw/matrix # Matrix 프로토콜에 대한 메시지 채널 통합 제공" - echo "@openclaw/nostr # Nostr 프로토콜의 메시지 채널 지원" - echo "@adongguo/openclaw-dingtalk # 통합된 DingTalk 메시지 채널" - echo "@openclaw/msteams # Microsoft Teams 지원 추가" - - # 사용자에게 플러그인 이름을 묻는 메시지 표시 - echo -n "설치할 플러그인의 이름을 입력하십시오(예: @xzq-xu/feishu Feishu 플러그인)(종료하려면 0 입력)." - read plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "작업이 취소되었습니다." - return 0 # 正常退出函数 - fi + # 2. 입력이 비어 있는지 확인하십시오. + if [ -z "$plugin_name" ]; then + echo "오류: 플러그인 이름은 비워둘 수 없습니다. 다시 입력하세요." + echo "" + continue + fi - # 입력이 비어 있는지 확인 - if [ -z "$plugin_name" ]; then - echo "오류: 플러그인 이름은 비워둘 수 없습니다. 다시 시도해 주세요." - return 1 - fi + # 1. 이전 실패의 잔재(사용자 디렉터리)를 완전히 정리합니다. + rm -rf "/root/.openclaw/extensions/$plugin_name" - # 설치 명령 실행 - echo "플러그인 설치:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 2. 시스템이 사전 설치되어 있는지 확인하세요. (ID 중복 방지를 위해) + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 플러그인이 시스템 디렉터리에 이미 존재하며 직접 활성화되고 있는 것으로 감지되었습니다..." + openclaw plugins enable "$plugin_name" + else + echo "📥 공식 채널을 통해 플러그인 다운로드 및 설치..." + # package.json의 사양 확인을 자동으로 처리하는 openclaw의 자체 설치 명령을 사용합니다. + openclaw plugins install "$plugin_name" + + # 3. openclaw install에서 오류가 보고되면 일반 npm 패키지로 설치해 보세요(마지막 대안). + if [ $? -ne 0 ]; then + echo "⚠️ 공식 설치에 실패했습니다. npm을 통해 전역적으로 강제 설치를 시도해보세요..." + npm install -g "$plugin_name" --unsafe-perm + fi - # 명령 실행 결과 확인 - if [ $? -eq 0 ]; then - echo "플러그인$plugin_name설치가 성공했습니다." - else - echo "설치에 실패했습니다. 플러그인 이름이 올바른지 확인하거나 OpenClaw 설명서를 참조하여 문제를 해결하세요." - fi + # 4. 마지막으로 통합 실행 및 활성화 + openclaw plugins enable "$plugin_name" + fi - break_end + start_tmux + break_end + done + } + + install_plugin() { + send_stats "플러그인 설치" + while true; do + clear + echo "========================================" + echo "플러그인 관리(설치)" + echo "========================================" + echo "현재 플러그인 목록:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "--------------------------------------------------------" + echo "📱 커뮤니케이션 채널:" + echo "- [feishu] # 페이슈/종달새 통합" + echo "- [텔레그램] # 텔레그램 봇" + echo "- [slack] #Slack 기업 커뮤니케이션" + echo " - [msteams] # Microsoft Teams" + echo "- [디스코드] # 디스코드 커뮤니티 관리" + echo "- [whatsapp] #WhatsApp 자동화" + echo "" + echo "🧠 메모리와 AI:" + echo "- [memory-core] # 기본 메모리(파일 검색)" + echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" + echo "- [copilot-proxy] # Copilot 인터페이스 전달" + echo "" + echo "⚙️ 기능 확장:" + echo "- [랍스터] # 승인 흐름(수동 확인 포함)" + echo "- [음성통화] # 음성통화 기능" + echo "- [nostr] # 암호화된 비공개 채팅" + echo "--------------------------------------------------------" + + read -e -p "플러그인 ID를 입력하십시오(종료하려면 0을 입력하십시오):" raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. 자동 처리: 사용자 입력에 @openclaw/가 포함된 경우 경로 확인을 용이하게 하기 위해 순수 ID를 추출합니다. + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 플러그인 상태 확인 중..." + + # 2. 이미 목록에 있고 비활성화되어 있는지 확인합니다(가장 일반적인 경우). + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." + openclaw plugins enable "$plugin_id" && echo "✅활성화 성공" || echo "❌ 활성화 실패" + + # 3. 시스템 물리적 디렉토리가 존재하는지 확인하십시오. + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + openclaw plugins enable "$plugin_id" + + else + # 4. 원격 설치 논리 + echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요..." + + # 오래되고 실패한 잔재를 정리합니다. + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # 설치 수행 및 결과 캡처 + if openclaw plugins install "$plugin_full"; then + echo "✅ 다운로드 성공, 활성화 중..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ 공식 채널에서 다운로드하지 못했습니다. 대안을 시도해 보세요..." + # 대체 npm 설치 + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm이 성공적으로 설치되었습니다. 활성화해 보세요..." + openclaw plugins enable "$plugin_id" + else + echo "❌ 치명적인 오류: 플러그인을 얻을 수 없습니다. ID가 맞는지, 네트워크 사용이 가능한지 확인해주세요." + # 키: 구성이 하드 코딩되는 것을 방지하려면 아래의 Starting_tmux 대신 여기로 직접 돌아가거나 계속하세요. + break_end + continue + fi + fi + fi + + echo "🔄 새 플러그인을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." + start_tmux + break_end + done } + + + + + install_skill() { send_stats "설치 기술" + while true; do + clear + echo "========================================" + echo "스킬 관리(설치)" + echo "========================================" + echo "현재 설치된 스킬:" + openclaw skills list + echo "----------------------------------------" + + # 추천 실기 목록 출력 + echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" + echo "github # GitHub 문제/PR/CI 관리(gh CLI)" + echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." + echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" + echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" + echo "1password # 1Password 키 읽기 및 삽입 자동화" + echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" + echo "things-mac # Things 3 작업 관리의 심층 통합" + echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." + echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" + echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" + echo "openhue # Philips Hue 스마트 조명 장면 제어" + echo "video-frames # 비디오 프레임 추출 및 짧은 클립 편집(ffmpeg 드라이버)" + echo "openai-whisper # 로컬 오디오를 텍스트로 변환(오프라인 개인 정보 보호)" + echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." + echo "----------------------------------------" + + # 사용자에게 스킬 이름을 입력하라는 메시지를 표시합니다. + read -e -p "설치할 스킬의 이름을 입력하십시오(종료하려면 0을 입력하십시오):" skill_name + + # 1. 0을 입력하여 종료했는지 확인하세요. + if [ "$skill_name" = "0" ]; then + echo "동작이 취소되어 스킬 설치가 종료되었습니다." + break + fi - echo "모든 기술" - openclaw skills list - # 사용자가 복사할 수 있는 권장 실무 기술 목록을 출력합니다. - echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" - echo "github-integration #GitHub 문제 및 끌어오기 요청 관리, 웹후크 지원" - echo "notion-integration # Notion 데이터베이스 및 페이지 조작" - echo "apple-notes # macOS/iOS용 Apple Notes 관리" - echo "home-assistant # 홈어시스턴트 허브를 통해 스마트 홈 제어" - echo "Agent-browser # Playwright를 사용한 헤드리스 브라우저 자동화" - - # 사용자에게 스킬 이름을 입력하라는 메시지를 표시합니다. - echo -n "설치할 스킬의 이름을 입력하세요(예: github-integration)(종료하려면 0을 입력하세요):" - read skill_name - - if [ "$skill_name" = "0" ]; then - echo "작업이 취소되었습니다." - return 0 # 正常退出函数 - fi + # 2. 입력이 비어 있는지 확인하십시오. + if [ -z "$skill_name" ]; then + echo "오류: 스킬 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "" + continue + fi - # 입력이 비어 있는지 확인 - if [ -z "$skill_name" ]; then - echo "오류: 스킬 이름은 비워둘 수 없습니다. 다시 시도해 주세요." - return 1 - fi + # 3. 설치 명령을 실행합니다. + echo "기술 설치:$skill_name ..." + npx clawhub install "$skill_name" - # 설치 명령 실행 - echo "기술 설치:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # 이전 명령의 종료 상태를 가져옵니다. + if [ $? -eq 0 ]; then + echo "✅ 스킬$skill_name설치가 성공했습니다." + # 서비스 재시작/시작 로직 실행 + start_tmux + else + echo "❌ 설치에 실패했습니다. 스킬 이름이 올바른지 확인하시거나, 문제 해결을 위해 문서를 참고하시기 바랍니다." + fi - # 명령 실행 결과 확인 - if [ $? -eq 0 ]; then - echo "기능$skill_name설치가 성공했습니다." - else - echo "설치에 실패했습니다. 스킬 이름이 올바른지 확인하거나 OpenClaw 설명서를 참조하여 문제를 해결하십시오." - fi + break_end + done - break_end } change_tg_bot_code() { send_stats "로봇 도킹" - printf "TG 로봇이 수신한 연결 코드(예: 페어링 코드: NYA99R2F)를 입력하세요(종료하려면 0 입력)." - read code + read -e -p "TG 로봇이 수신한 연결 코드(예: 페어링 코드: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code # 0을 입력했는지 확인하여 종료하세요. if [ "$code" = "0" ]; then @@ -10022,6 +10200,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "오픈클로 업데이트..." send_stats "오픈클로 업데이트..." @@ -10046,6 +10225,138 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "OpenClaw 구성 파일 편집" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } + + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI 접속 주소" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "현지 주소:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "도메인 이름 주소:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # 도메인 이름 추가(제공한 기능 호출) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 18789 + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "방문 주소:" + echo "https://${yuming}/?token=$token" + echo "먼저 URL에 액세스하여 장치 ID를 트리거한 다음 Enter를 눌러 페어링을 진행하세요." + read + echo -e "${gl_kjlan}기기 목록 로드 중...${gl_bai}" + openclaw devices list + + read -e -p "Request_Key를 입력하십시오:" Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key는 비워둘 수 없습니다." + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # 도메인 이름 삭제 + openclaw_remove_domain() { + echo "https://가 없는 도메인 이름 형식 example.com" + web_del + } + + # 메인 메뉴 + openclaw_webui_menu() { + + send_stats "WebUI 액세스 및 설정" + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. 도메인 이름 액세스 추가" + echo "2. 도메인 이름 액세스 삭제" + echo "0. 종료" + echo + read -e -p "선택하세요:" choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "메뉴로 돌아가려면 Enter를 누르세요..." + ;; + 2) + openclaw_remove_domain + read -p "메뉴로 돌아가려면 Enter를 누르세요..." + ;; + 0) + break + ;; + *) + echo "잘못된 옵션" + sleep 1 + ;; + esac + done + } + + # 메인 루프 while true; do @@ -10061,13 +10372,18 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "OpenClaw 구성 파일 편집" - install nano - nano ~/.openclaw/openclaw.json + 10) nano_openclaw_json ;; + 11) send_stats "초기 구성 마법사" + openclaw onboard --install-daemon + break_end ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 12) send_stats "상태 감지 및 복구" + openclaw doctor --fix + break_end + ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done @@ -10113,7 +10429,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -10125,7 +10441,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -10153,7 +10469,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -10181,7 +10497,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}ClawdBot/Moltbot 로봇${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -10515,7 +10831,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -11249,7 +11565,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -11754,7 +12070,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -11916,7 +12232,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12249,7 +12565,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12497,7 +12813,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12806,7 +13122,7 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -12838,7 +13154,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -12865,7 +13181,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -13892,7 +14208,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -13954,7 +14270,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -13970,7 +14286,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10호" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" @@ -14269,32 +14585,32 @@ net_menu() { echo "4. 네트워크 카드 정보 새로 고침" echo "0. 이전 메뉴로 돌아가기" echo "====================================" - read -rp "작업을 선택하십시오:" choice + read -erp "작업을 선택하십시오:" choice case $choice in 1) send_stats "네트워크 카드 활성화" - read -rp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic + read -erp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" else echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 2) send_stats "네트워크 카드 비활성화" - read -rp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic + read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" else echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 3) send_stats "네트워크 카드 세부정보 보기" - read -rp "보려는 네트워크 카드의 이름을 입력하십시오:" nic + read -erp "보려는 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then echo "========== $nic세부정보 ==========" ip addr show "$nic" @@ -14302,7 +14618,7 @@ net_menu() { else echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 4) send_stats "네트워크 카드 정보 새로 고침" @@ -14338,32 +14654,32 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 보기" + echo "1. 최신 시스템 로그(일지) 확인" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" echo "5. 오래된 저널 로그 정리" echo "0. 이전 메뉴로 돌아가기" echo "=======================================" - read -rp "작업을 선택하십시오:" choice + read -erp "작업을 선택하십시오:" choice case $choice in 1) send_stats "최근 로그 보기" - read -rp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 2) send_stats "지정된 서비스 로그 보기" - read -rp "서비스 이름(예: sshd, nginx)을 입력하세요." svc + read -erp "서비스 이름(예: sshd, nginx)을 입력하세요." svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ 서비스가 존재하지 않거나 로그가 없습니다." fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 3) send_stats "로그인/보안 로그 보기" @@ -14378,17 +14694,17 @@ log_menu() { else echo "보안 로그 파일을 찾을 수 없습니다." fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." ;; 4) send_stats "실시간 추적 로그" echo "1) 시스템 로그" echo "2) 서비스 로그 지정" - read -rp "추적 유형 선택:" t + read -erp "추적 유형 선택:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "서비스 이름 입력:" svc + read -erp "서비스 이름 입력:" svc journalctl -u "$svc" -f else echo "잘못된 선택" @@ -14400,7 +14716,7 @@ log_menu() { echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" echo "3) 최대 로그 크기를 500M로 제한하십시오." - read -rp "청소 방법을 선택하세요:" c + read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14466,7 +14782,7 @@ env_menu() { echo echo "===============================================" - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." } @@ -14481,7 +14797,7 @@ env_menu() { else echo "파일이 존재하지 않습니다:$file" fi - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." } edit_file() { @@ -14493,11 +14809,11 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드" + send_stats "환경 변수 다시 로드 중" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." - read -rp "계속하려면 Enter를 누르세요..." + read -erp "계속하려면 Enter를 누르세요..." } while true; do @@ -14514,7 +14830,7 @@ env_menu() { echo "--------------------------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------------------------" - read -rp "작업을 선택하십시오:" choice + read -erp "작업을 선택하십시오:" choice case "$choice" in 1) @@ -14624,7 +14940,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -14787,7 +15103,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # 현재 SSH 포트 번호 읽기 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14805,7 +15121,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH 포트가 수정되었습니다." - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "SSH 포트 수정 종료" break @@ -14881,8 +15197,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -15109,7 +15425,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -15177,7 +15493,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -15372,7 +15688,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -15617,8 +15933,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 3/12. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd @@ -15904,7 +16219,7 @@ linux_file() { continue fi - # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -16004,7 +16319,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16038,7 +16353,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16080,7 +16395,7 @@ while true; do clear send_stats "클러스터 복원" echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -16146,7 +16461,7 @@ echo "------------------------" echo -e "${gl_zi}Hostinger 연간 $52.7 미국 1 코어 4G 메모리 50G 하드 드라이브 월별 4T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}벽돌공 분기당 49달러 미국 CN2GIA 일본 SoftBank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_huang}벽돌공 분기당 49달러 미국 CN2GIA 일본 Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}웹사이트: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" @@ -16155,7 +16470,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16361,7 +16676,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" +echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택사항을 입력하세요:" choice @@ -16394,12 +16709,12 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -16433,12 +16748,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" @@ -16599,12 +16914,12 @@ else ;; stop|停止) shift - send_stats "소프트웨어 일시 중지" + send_stats "소프트웨어가 일시중지됨" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 재시작" + send_stats "소프트웨어 다시 시작" restart "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index a764ef612..8c08346da 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.8" +sh_v="4.3.9" gl_hui='\e[37m' @@ -3652,20 +3652,20 @@ ldnmp_Proxy_backend_stream() { echo "開始部署$webname" # 獲取代理名稱 - read -rp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name + read -erp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then echo "名稱不能為空"; return 1 fi # 獲取監聽端口 - read -rp "請輸入本機監聽端口 (如 3306):" listen_port + read -erp "請輸入本機監聽端口 (如 3306):" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "端口必須是數字"; return 1 fi echo "請選擇協議類型:" echo "1. TCP 2. UDP" - read -rp "請輸入序號 [1-2]:" proto_choice + read -erp "請輸入序號 [1-2]:" proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; @@ -4819,10 +4819,12 @@ correct_ssh_config() { new_ssh_port() { + local new_port=$1 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + echo "Port $new_port" >> /etc/ssh/sshd_config correct_ssh_config @@ -6649,38 +6651,66 @@ list_partitions() { lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 掛載分區 + +# 持久化掛載分區 mount_partition() { send_stats "掛載分區" read -e -p "請輸入要掛載的分區名稱(例如 sda1):" PARTITION + DEVICE="/dev/$PARTITION" + MOUNT_POINT="/mnt/$PARTITION" + # 檢查分區是否存在 - if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then + if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "分區不存在!" - return + return 1 fi - # 檢查分區是否已經掛載 - if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then + # 檢查是否已掛載 + if mount | grep -qw "$DEVICE"; then echo "分區已經掛載!" - return + return 1 + fi + + # 獲取 UUID + UUID=$(blkid -s UUID -o value "$DEVICE") + if [ -z "$UUID" ]; then + echo "無法獲取 UUID!" + return 1 + fi + + # 獲取文件系統類型 + FSTYPE=$(blkid -s TYPE -o value "$DEVICE") + if [ -z "$FSTYPE" ]; then + echo "無法獲取文件系統類型!" + return 1 fi # 創建掛載點 - MOUNT_POINT="/mnt/$PARTITION" mkdir -p "$MOUNT_POINT" - # 掛載分區 - mount "/dev/$PARTITION" "$MOUNT_POINT" - - if [ $? -eq 0 ]; then - echo "分區掛載成功:$MOUNT_POINT" - else + # 掛載 + if ! mount "$DEVICE" "$MOUNT_POINT"; then echo "分區掛載失敗!" rmdir "$MOUNT_POINT" + return 1 + fi + + echo "分區已成功掛載到$MOUNT_POINT" + + # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 + if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then + echo "/etc/fstab 中已存在該分區記錄,跳過寫入" + return 0 fi + + # 寫入 /etc/fstab + echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab + + echo "已寫入 /etc/fstab,實現持久化掛載" } + # 卸載分區 unmount_partition() { send_stats "卸載分區" @@ -7157,8 +7187,7 @@ linux_info() { local tcp_count=$(ss -t | wc -l) local udp_count=$(ss -u | wc -l) - - echo "" + clear echo -e "系統信息查詢" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}主機名:${gl_bai}$hostname" @@ -9591,19 +9620,19 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" check_openclaw_update() { - # 先檢查 NPM 是否可用 if ! command -v npm >/dev/null 2>&1; then return 1 fi - # 使用 NPM 查詢本地版本,並去除前綴(如 openclaw@) - local_version=$(npm list -g openclaw --depth=0 | grep openclaw | awk '{print $NF}' | sed 's/^.*@//' 2>/dev/null) + # 加上 --no-update-notifier,並確保錯誤重定向位置正確 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + if [ -z "$local_version" ]; then return 1 fi - # 使用 NPM 查詢遠程版本 - remote_version=$(npm view openclaw version 2>/dev/null) + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + if [ -z "$remote_version" ]; then return 1 fi @@ -9655,9 +9684,12 @@ moltbot_menu() { echo "8. 安裝插件(如:飛書)" echo "9. 安裝技能(skills)" echo "10. 編輯主配置文件" + echo "11. 配置嚮導" + echo "12. 健康檢測與修復" + echo "13. WebUI訪問與設置" echo "--------------------" - echo "11. 更新" - echo "12. 卸載" + echo "14. 更新" + echo "15. 卸載" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -9827,24 +9859,24 @@ moltbot_menu() { echo "=== 交互式添加 OpenClaw Provider ===" # Provider 名稱 - read -rp "請輸入 Provider 名稱 (如: deepseek):" provider_name + read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider 名稱不能為空" - read -rp "請輸入 Provider 名稱:" provider_name + read -erp "請輸入 Provider 名稱:" provider_name done # Model ID - read -rp "請輸入 Model ID (如: deepseek-chat):" model_id + read -erp "請輸入 Model ID (如: deepseek-chat):" model_id while [[ -z "$model_id" ]]; do echo "❌ Model ID 不能為空" - read -rp "請輸入 Model ID:" model_id + read -erp "請輸入 Model ID:" model_id done # Base URL - read -rp "請輸入 Base URL (如: https://api.xxx.com/v1):" base_url + read -erp "請輸入 Base URL (如: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL 不能為空" - read -rp "請輸入 Base URL:" base_url + read -erp "請輸入 Base URL:" base_url done # API Key(隱藏輸入) @@ -9864,7 +9896,7 @@ moltbot_menu() { echo "API Key : ${api_key:0:8}****" echo "======================" - read -rp "確認添加? (y/N):" confirm + read -erp "確認添加? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 已取消" return 1 @@ -9884,28 +9916,39 @@ moltbot_menu() { change_model() { send_stats "換模型" - echo "所有模型:" - openclaw models list --all - echo "當前模型:" - openclaw models list - printf "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" - read model - # 檢查是否輸入 0 以退出 - if [ "$model" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + while true; do + clear + echo "--- 模型管理 ---" + echo "所有模型:" + openclaw models list --all + echo "----------------" + echo "當前模型:" + openclaw models list + echo "----------------" + read -e -p "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" model + + # 1. 檢查是否輸入 0 以退出 + if [ "$model" = "0" ]; then + echo "操作已取消,正在退出..." + break # 跳出 while 循环 - # 驗證輸入是否為空 - if [ -z "$model" ]; then - echo "錯誤:模型名稱不能為空。請重試。" - return 1 - fi + fi + + # 2. 驗證輸入是否為空 + if [ -z "$model" ]; then + echo "錯誤:模型名稱不能為空。請重試。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + + # 3. 執行切換邏輯 + echo "正在切換模型為:$model ..." + openclaw models set "$model" + + break_end + done - echo "切換模型為$model" - openclaw models set "$model" - break_end } @@ -9914,97 +9957,232 @@ moltbot_menu() { install_plugin() { send_stats "安裝插件" + while true; do + clear + echo "========================================" + echo "插件管理 (安裝)" + echo "========================================" + echo "當前已安裝插件:" + openclaw plugins list + echo "----------------------------------------" + + # 輸出推薦的實用插件列表,便於用戶複製 + echo "推薦的實用插件(可直接複製名稱輸入):" + echo "feishu # 飛書/Lark 集成 (當前已加載 ✓)" + echo "telegram # Telegram 機器人集成 (當前已加載 ✓)" + echo "memory-core # 核心記憶增強:基於文件的上下文搜索 (當前已加載 ✓)" + echo "@openclaw/slack # Slack 頻道與 DMs 深度連接" + echo "@openclaw/bluebubbles # iMessage 橋接 (macOS 用戶首選)" + echo "@openclaw/msteams # Microsoft Teams 企業通訊集成" + echo "@openclaw/voice-call # 語音通話插件 (基於 Twilio 等後端)" + echo "@openclaw/discord # Discord 頻道自動化管理" + echo "@openclaw/nostr # Nostr 協議:隱私安全加密聊天" + echo "lobster # 審批工作流:帶有人工干預的自動任務" + echo "memory-lancedb # 長期記憶增強:基於向量數據庫的精準召回" + echo "copilot-proxy # GitHub Copilot 代理接入增強" + echo "----------------------------------------" + + # 提示用戶輸入插件名稱 + read -e -p "請輸入要安裝的插件名稱(輸入 0 退出):" plugin_name + + # 1. 檢查是否輸入 0 以退出 + if [ "$plugin_name" = "0" ]; then + echo "操作已取消,退出插件安裝。" + break + fi - echo "所有插件" - openclaw plugins list - # 輸出推薦的實用插件列表,便於用戶複製 - echo "推薦的實用插件(可直接複製名稱輸入):" - echo "@openclaw/voice-call # 啟用語音通話功能,支持 Twilio 集成" - echo "@openclaw/matrix # 為 Matrix 協議提供消息通道集成" - echo "@openclaw/nostr # 支持 Nostr 協議的消息通道" - echo "@adongguo/openclaw-dingtalk # 集成釘釘消息通道" - echo "@openclaw/msteams # 添加 Microsoft Teams 支持" - - # 提示用戶輸入插件名稱 - echo -n "請輸入要安裝的插件名稱(例如:@xzq-xu/feishu 飛書插件)(輸入 0 退出):" - read plugin_name - - if [ "$plugin_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + # 2. 驗證輸入是否為空 + if [ -z "$plugin_name" ]; then + echo "錯誤:插件名稱不能為空,請重新輸入。" + echo "" + continue + fi - # 驗證輸入是否為空 - if [ -z "$plugin_name" ]; then - echo "錯誤:插件名稱不能為空。請重試。" - return 1 - fi + # 1. 徹底清理之前失敗的殘留(用戶目錄) + rm -rf "/root/.openclaw/extensions/$plugin_name" - # 執行安裝命令 - echo "正在安裝插件:$plugin_name" - openclaw plugins install "$plugin_name" - start_tmux + # 2. 檢查系統是否已經預裝(防止 duplicate id 衝突) + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then + echo "💡 檢測到系統目錄已存在該插件,正在直接激活..." + openclaw plugins enable "$plugin_name" + else + echo "📥 正在通過官方渠道下載安裝插件..." + # 使用 openclaw 自己的 install 命令,它會自動處理 package.json 的規範檢查 + openclaw plugins install "$plugin_name" + + # 3. 如果 openclaw install 報錯,再嘗試作為普通 npm 包安裝(最後的備選) + if [ $? -ne 0 ]; then + echo "⚠️ 官方安裝失敗,嘗試通過 npm 全局強制安裝..." + npm install -g "$plugin_name" --unsafe-perm + fi - # 檢查命令執行結果 - if [ $? -eq 0 ]; then - echo "插件$plugin_name安裝成功。" - else - echo "安裝失敗。請檢查插件名稱是否正確,或參考 OpenClaw 文檔排查問題。" - fi + # 4. 最後統一執行啟用 + openclaw plugins enable "$plugin_name" + fi - break_end + start_tmux + break_end + done + } + + install_plugin() { + send_stats "安裝插件" + while true; do + clear + echo "========================================" + echo "插件管理 (安裝)" + echo "========================================" + echo "當前插件列表:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推薦的常用插件 ID (直接複製括號內的 ID 即可):" + echo "--------------------------------------------------------" + echo "📱 通訊渠道:" + echo "- [feishu] # 飛書/Lark 集成" + echo "- [telegram] # Telegram 機器人" + echo "- [slack] # Slack 企業通訊" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] # Discord 社區管理" + echo "- [whatsapp] # WhatsApp 自動化" + echo "" + echo "🧠 記憶與 AI:" + echo "- [memory-core] # 基礎記憶 (文件檢索)" + echo "- [memory-lancedb] # 增強記憶 (向量數據庫)" + echo "- [copilot-proxy] # Copilot 接口轉發" + echo "" + echo "⚙️ 功能擴展:" + echo "- [lobster] # 審批流 (帶人工確認)" + echo "- [voice-call] # 語音通話能力" + echo "- [nostr] # 加密隱私聊天" + echo "--------------------------------------------------------" + + read -e -p "請輸入插件 ID(輸入 0 退出):" raw_input + + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + # 1. 自動處理:如果用戶輸入帶 @openclaw/,提取純 ID 方便路徑檢查 + local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_full="$raw_input" + + echo "🔍 正在檢查插件狀態..." + + # 2. 檢查是否已經在 list 中且為 disabled (最常見的情況) + if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已預裝,正在激活..." + openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失敗" + + # 3. 檢查系統物理目錄是否存在 + elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 發現系統內置目錄存在該插件,嘗試直接啟用..." + openclaw plugins enable "$plugin_id" + + else + # 4. 遠程安裝邏輯 + echo "📥 本地未發現,嘗試下載安裝..." + + # 清理舊的失敗殘留 + rm -rf "/root/.openclaw/extensions/$plugin_id" + + # 執行安裝,並捕獲結果 + if openclaw plugins install "$plugin_full"; then + echo "✅ 下載成功,正在啟用..." + openclaw plugins enable "$plugin_id" + else + echo "⚠️ 官方渠道下載失敗,嘗試備選方案..." + # 備選 npm 安裝 + if npm install -g "$plugin_full" --unsafe-perm; then + echo "✅ npm 安裝成功,嘗試啟用..." + openclaw plugins enable "$plugin_id" + else + echo "❌ 嚴重錯誤:無法獲取該插件。請檢查 ID 是否正確或網絡是否可用。" + # 關鍵:這裡直接 return 或 continue,不走下面的 start_tmux,防止寫死配置 + break_end + continue + fi + fi + fi + + echo "🔄 正在重啟 OpenClaw 服務以加載新插件..." + start_tmux + break_end + done } + + + + + install_skill() { send_stats "安裝技能" + while true; do + clear + echo "========================================" + echo "技能管理 (安裝)" + echo "========================================" + echo "當前已安裝技能:" + openclaw skills list + echo "----------------------------------------" + + # 輸出推薦的實用技能列表 + echo "推薦的實用技能(可直接複製名稱輸入):" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 頁面、數據庫和塊" + echo "apple-notes # macOS 原生筆記管理 (創建/編輯/搜索)" + echo "apple-reminders # macOS 提醒事項管理 (待辦清單)" + echo "1password # 自動化讀取和注入 1Password 密鑰" + echo "gog # Google Workspace (Gmail/雲盤/文檔) 全能助手" + echo "things-mac # 深度整合 Things 3 任務管理" + echo "bluebubbles # 通過 BlueBubbles 完美收發 iMessage" + echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" + echo "summarize # 網頁/播客/YouTube 視頻內容一鍵總結" + echo "openhue # 控制 Philips Hue 智能燈光場景" + echo "video-frames # 視頻抽幀與短片剪輯 (ffmpeg 驅動)" + echo "openai-whisper # 本地音頻轉文字 (離線隱私保護)" + echo "coding-agent # 自動運行 Claude Code/Codex 等編程助手" + echo "----------------------------------------" + + # 提示用戶輸入技能名稱 + read -e -p "請輸入要安裝的技能名稱(輸入 0 退出):" skill_name + + # 1. 檢查是否輸入 0 以退出 + if [ "$skill_name" = "0" ]; then + echo "操作已取消,退出技能安裝。" + break + fi - echo "所有技能" - openclaw skills list - # 輸出推薦的實用技能列表,便於用戶複製 - echo "推薦的實用技能(可直接複製名稱輸入):" - echo "github-integration # 管理 GitHub Issues 和 Pull Requests,支持 Webhook" - echo "notion-integration # 操作 Notion 數據庫和頁面" - echo "apple-notes # 管理 macOS/iOS 的 Apple Notes" - echo "home-assistant # 通過 Home Assistant Hub 控制智能家居" - echo "agent-browser # 使用 Playwright 進行無頭瀏覽器自動化" - - # 提示用戶輸入技能名稱 - echo -n "請輸入要安裝的技能名稱(例如:github-integration)(輸入 0 退出):" - read skill_name - - if [ "$skill_name" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi + # 2. 驗證輸入是否為空 + if [ -z "$skill_name" ]; then + echo "錯誤:技能名稱不能為空。請重試。" + echo "" + continue + fi - # 驗證輸入是否為空 - if [ -z "$skill_name" ]; then - echo "錯誤:技能名稱不能為空。請重試。" - return 1 - fi + # 3. 執行安裝命令 + echo "正在安裝技能:$skill_name ..." + npx clawhub install "$skill_name" - # 執行安裝命令 - echo "正在安裝技能:$skill_name" - openclaw skills install "$skill_name" - start_tmux + # 獲取上一條命令的退出狀態 + if [ $? -eq 0 ]; then + echo "✅ 技能$skill_name安裝成功。" + # 執行重啟/啟動服務邏輯 + start_tmux + else + echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文檔排查。" + fi - # 檢查命令執行結果 - if [ $? -eq 0 ]; then - echo "技能$skill_name安裝成功。" - else - echo "安裝失敗。請檢查技能名稱是否正確,或參考 OpenClaw 文檔排查問題。" - fi + break_end + done - break_end } change_tg_bot_code() { send_stats "機器人對接" - printf "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" - read code + read -e -p "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" code # 檢查是否輸入 0 以退出 if [ "$code" = "0" ]; then @@ -10022,6 +10200,7 @@ moltbot_menu() { break_end } + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." @@ -10046,6 +10225,138 @@ moltbot_menu() { break_end } + nano_openclaw_json() { + send_stats "編輯 OpenClaw 配置文件" + install nano + nano ~/.openclaw/openclaw.json + start_tmux + } + + + + + + + openclaw_find_webui_domain() { + local conf domain_list + + domain_list=$( + grep -R "18789" /home/web/conf.d/*.conf 2>/dev/null \ + | awk -F: '{print $1}' \ + | sort -u \ + | while read conf; do + basename "$conf" .conf + done + ) + + if [ -n "$domain_list" ]; then + echo "$domain_list" + fi + } + + + + openclaw_show_webui_addr() { + local local_ip token domains + + echo "==================================" + echo "OpenClaw WebUI 訪問地址" + local_ip="127.0.0.1" + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + echo + echo "本機地址:" + echo "http://${local_ip}:18789/?token=${token}" + + domains=$(openclaw_find_webui_domain) + if [ -n "$domains" ]; then + echo "域名地址:" + echo "$domains" | while read d; do + echo "https://${d}/?token=${token}" + done + fi + + echo "==================================" + } + + + + # 添加域名(調用你給的函數) + openclaw_domain_webui() { + add_yuming + ldnmp_Proxy ${yuming} 127.0.0.1 18789 + + token=$( + openclaw dashboard 2>/dev/null \ + | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | head -n 1 + ) + + clear + echo "訪問地址:" + echo "https://${yuming}/?token=$token" + echo "先訪問URL觸發設備ID,然後回車下一步進行配對。" + read + echo -e "${gl_kjlan}正在加載設備列表……${gl_bai}" + openclaw devices list + + read -e -p "請輸入 Request_Key:" Request_Key + + [ -z "$Request_Key" ] && { + echo "Request_Key 不能為空" + return 1 + } + + openclaw devices approve "$Request_Key" + + } + + # 刪除域名 + openclaw_remove_domain() { + echo "域名格式 example.com 不帶https://" + web_del + } + + # 主菜單 + openclaw_webui_menu() { + + send_stats "WebUI訪問與設置" + while true; do + clear + openclaw_show_webui_addr + echo + echo "1. 添加域名訪問" + echo "2. 刪除域名訪問" + echo "0. 退出" + echo + read -e -p "請選擇:" choice + + case "$choice" in + 1) + openclaw_domain_webui + echo + read -p "按回車返回菜單..." + ;; + 2) + openclaw_remove_domain + read -p "按回車返回菜單..." + ;; + 0) + break + ;; + *) + echo "無效選項" + sleep 1 + ;; + esac + done + } + + # 主循環 while true; do @@ -10061,13 +10372,18 @@ moltbot_menu() { 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; - 10) - send_stats "編輯 OpenClaw 配置文件" - install nano - nano ~/.openclaw/openclaw.json + 10) nano_openclaw_json ;; + 11) send_stats "初始化配置嚮導" + openclaw onboard --install-daemon + break_end ;; - 11) update_moltbot ;; - 12) uninstall_moltbot ;; + 12) send_stats "健康檢測與修復" + openclaw doctor --fix + break_end + ;; + 13) openclaw_webui_menu ;; + 14) update_moltbot ;; + 15) uninstall_moltbot ;; *) break ;; esac done @@ -14269,32 +14585,32 @@ net_menu() { echo "4. 刷新網卡信息" echo "0. 返回上一級選單" echo "====================================" - read -rp "請選擇操作:" choice + read -erp "請選擇操作:" choice case $choice in 1) send_stats "啟用網卡" - read -rp "請輸入要啟用的網卡名:" nic + read -erp "請輸入要啟用的網卡名:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 網卡$nic已啟用" else echo "✘ 網卡不存在" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 2) send_stats "禁用網卡" - read -rp "請輸入要禁用的網卡名:" nic + read -erp "請輸入要禁用的網卡名:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 網卡$nic已禁用" else echo "✘ 網卡不存在" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 3) send_stats "查看網卡詳情" - read -rp "請輸入要查看的網卡名:" nic + read -erp "請輸入要查看的網卡名:" nic if ip link show "$nic" &>/dev/null; then echo "========== $nic詳細信息 ==========" ip addr show "$nic" @@ -14302,7 +14618,7 @@ net_menu() { else echo "✘ 網卡不存在" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 4) send_stats "刷新網卡信息" @@ -14345,25 +14661,25 @@ log_menu() { echo "5. 清理舊 journal 日誌" echo "0. 返回上一級選單" echo "=======================================" - read -rp "請選擇操作:" choice + read -erp "請選擇操作:" choice case $choice in 1) send_stats "查看最近日誌" - read -rp "查看最近多少行日誌? [默認 100]:" lines + read -erp "查看最近多少行日誌? [默認 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 2) send_stats "查看指定服務日誌" - read -rp "請輸入服務名(如 sshd、nginx):" svc + read -erp "請輸入服務名(如 sshd、nginx):" svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ 服務不存在或無日誌" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 3) send_stats "查看登錄/安全日誌" @@ -14378,17 +14694,17 @@ log_menu() { else echo "未找到安全日誌文件" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." ;; 4) send_stats "實時跟踪日誌" echo "1) 系統日誌" echo "2) 指定服務日誌" - read -rp "選擇跟踪類型:" t + read -erp "選擇跟踪類型:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -rp "輸入服務名:" svc + read -erp "輸入服務名:" svc journalctl -u "$svc" -f else echo "無效選擇" @@ -14400,7 +14716,7 @@ log_menu() { echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" echo "3) 限制日誌最大 500M" - read -rp "請選擇清理方式:" c + read -erp "請選擇清理方式:" c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; @@ -14466,7 +14782,7 @@ env_menu() { echo echo "===============================================" - read -rp "按回車繼續..." + read -erp "按回車繼續..." } @@ -14481,7 +14797,7 @@ env_menu() { else echo "文件不存在:$file" fi - read -rp "按回車繼續..." + read -erp "按回車繼續..." } edit_file() { @@ -14497,7 +14813,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境變量已重新加載" - read -rp "按回車繼續..." + read -erp "按回車繼續..." } while true; do @@ -14514,7 +14830,7 @@ env_menu() { echo "--------------------------------------" echo "0. 返回上一級選單" echo "--------------------------------------" - read -rp "請選擇操作:" choice + read -erp "請選擇操作:" choice case "$choice" in 1) @@ -14787,7 +15103,7 @@ EOF while true; do clear - sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config # 讀取當前的 SSH 端口號 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') @@ -14805,7 +15121,7 @@ EOF if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH端口已修改" - new_ssh_port + new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then send_stats "退出SSH端口修改" break @@ -15617,8 +15933,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設置虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - local new_port=5522 - new_ssh_port + new_ssh_port 5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. 設置SSH端口號為${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd From 5a4cb35d7966b7b62674abe6318565049ead8d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:54:00 +0800 Subject: [PATCH 0795/1285] Enhance add-openclaw-provider-interactive function Refactor interactive provider addition to include model list retrieval and improved user prompts. --- cn/kejilion.sh | 144 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 49 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f0bee3672..2318bbdc7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9755,6 +9755,9 @@ moltbot_menu() { + + + add-openclaw-provider() { local config_file="${HOME}/.openclaw/openclaw.json" local provider_name="$1" @@ -9835,6 +9838,7 @@ moltbot_menu() { fi } + # 可选:自动设置默认并重启 add-openclaw-provider-and-switch() { install jq @@ -9852,64 +9856,106 @@ moltbot_menu() { + add-openclaw-provider-interactive() { + send_stats "添加API" + echo "=== 交互式添加 OpenClaw Provider ===" + + # 1. Provider 名称 + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -erp "请输入 Provider 名称: " provider_name + done + # 2. Base URL + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -erp "请输入 Base URL: " base_url + done + # 自动处理结尾的 / + base_url="${base_url%/}" - add-openclaw-provider-interactive() { - send_stats "添加API" - echo "=== 交互式添加 OpenClaw Provider ===" - - # Provider 名称 - read -erp "请输入 Provider 名称 (如: deepseek): " provider_name - while [[ -z "$provider_name" ]]; do - echo "❌ Provider 名称不能为空" - read -erp "请输入 Provider 名称: " provider_name - done + # 3. API Key + read -rsp "请输入 API Key (输入不显示): " api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done - # Model ID - read -erp "请输入 Model ID (如: deepseek-chat): " model_id - while [[ -z "$model_id" ]]; do - echo "❌ Model ID 不能为空" - read -erp "请输入 Model ID: " model_id - done + # --- ✨ 新增逻辑:自动获取模型列表 --- + echo "🔍 正在尝试获取可用模型列表..." - # Base URL - read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url - while [[ -z "$base_url" ]]; do - echo "❌ Base URL 不能为空" - read -erp "请输入 Base URL: " base_url - done + # 尝试请求 /models 端点 + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") - # API Key(隐藏输入) - read -rsp "请输入 API Key (输入不显示): " api_key - echo - while [[ -z "$api_key" ]]; do - echo "❌ API Key 不能为空" - read -rsp "请输入 API Key: " api_key - echo - done + # 简单的正则提取模型 ID (兼容性好,无需 jq) + if [[ -n "$models_json" ]]; then + # 提取 "id": "xxx" 格式的字符串 + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) - echo - echo "====== 确认信息 ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "======================" - - read -erp "确认添加?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 + if [[ -n "$available_models" ]]; then + echo "✅ 发现以下可用模型:" + echo "--------------------------------" + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + echo "💡 你可以输入序号选择,也可以直接输入模型 ID" + else + echo "⚠️ 未能解析出模型列表 (可能是格式不兼容),请手动输入。" fi + else + echo "⚠️ 连接 API 失败,请检查 URL 或网络。" + fi + # ------------------------------------- - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + # 4. Model ID + read -erp "请输入 Model ID (或序号): " input_model - break_end + # 检查是否输入了序号 + if [[ -n "${model_map[$input_model]}" ]]; then + model_id="${model_map[$input_model]}" + echo "🎯 已选择模型: $model_id" + else + model_id="$input_model" + fi + + while [[ -z "$model_id" ]]; do + echo "❌ Model ID 不能为空" + read -erp "请输入 Model ID: " model_id + done + + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "Model ID : $model_id" + echo "======================" + + read -erp "确认添加?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end } From 5e0f8f0040f2e2d0312a9a59b2709b34a15076d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:23:16 +0800 Subject: [PATCH 0796/1285] Enhance interactive provider addition with model fetching Refactor add-openclaw-provider-interactive function to include automatic model list retrieval and improve user prompts for input. --- kejilion.sh | 144 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 49 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index e7855af68..3bee4a597 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9755,6 +9755,9 @@ moltbot_menu() { + + + add-openclaw-provider() { local config_file="${HOME}/.openclaw/openclaw.json" local provider_name="$1" @@ -9835,6 +9838,7 @@ moltbot_menu() { fi } + # 可选:自动设置默认并重启 add-openclaw-provider-and-switch() { install jq @@ -9852,64 +9856,106 @@ moltbot_menu() { + add-openclaw-provider-interactive() { + send_stats "添加API" + echo "=== 交互式添加 OpenClaw Provider ===" + + # 1. Provider 名称 + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -erp "请输入 Provider 名称: " provider_name + done + # 2. Base URL + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -erp "请输入 Base URL: " base_url + done + # 自动处理结尾的 / + base_url="${base_url%/}" - add-openclaw-provider-interactive() { - send_stats "添加API" - echo "=== 交互式添加 OpenClaw Provider ===" - - # Provider 名称 - read -erp "请输入 Provider 名称 (如: deepseek): " provider_name - while [[ -z "$provider_name" ]]; do - echo "❌ Provider 名称不能为空" - read -erp "请输入 Provider 名称: " provider_name - done + # 3. API Key + read -rsp "请输入 API Key (输入不显示): " api_key + echo + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done - # Model ID - read -erp "请输入 Model ID (如: deepseek-chat): " model_id - while [[ -z "$model_id" ]]; do - echo "❌ Model ID 不能为空" - read -erp "请输入 Model ID: " model_id - done + # --- ✨ 新增逻辑:自动获取模型列表 --- + echo "🔍 正在尝试获取可用模型列表..." - # Base URL - read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url - while [[ -z "$base_url" ]]; do - echo "❌ Base URL 不能为空" - read -erp "请输入 Base URL: " base_url - done + # 尝试请求 /models 端点 + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") - # API Key(隐藏输入) - read -rsp "请输入 API Key (输入不显示): " api_key - echo - while [[ -z "$api_key" ]]; do - echo "❌ API Key 不能为空" - read -rsp "请输入 API Key: " api_key - echo - done + # 简单的正则提取模型 ID (兼容性好,无需 jq) + if [[ -n "$models_json" ]]; then + # 提取 "id": "xxx" 格式的字符串 + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) - echo - echo "====== 确认信息 ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "======================" - - read -erp "确认添加?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 + if [[ -n "$available_models" ]]; then + echo "✅ 发现以下可用模型:" + echo "--------------------------------" + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + echo "💡 你可以输入序号选择,也可以直接输入模型 ID" + else + echo "⚠️ 未能解析出模型列表 (可能是格式不兼容),请手动输入。" fi + else + echo "⚠️ 连接 API 失败,请检查 URL 或网络。" + fi + # ------------------------------------- - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + # 4. Model ID + read -erp "请输入 Model ID (或序号): " input_model - break_end + # 检查是否输入了序号 + if [[ -n "${model_map[$input_model]}" ]]; then + model_id="${model_map[$input_model]}" + echo "🎯 已选择模型: $model_id" + else + model_id="$input_model" + fi + + while [[ -z "$model_id" ]]; do + echo "❌ Model ID 不能为空" + read -erp "请输入 Model ID: " model_id + done + + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "Model ID : $model_id" + echo "======================" + + read -erp "确认添加?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi + + echo + add-openclaw-provider-and-switch \ + "$provider_name" \ + "$model_id" \ + "$base_url" \ + "$api_key" + + break_end } From ab16fb68e2c248331674a09b1f2bb5d44693ee3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:38:46 +0800 Subject: [PATCH 0797/1285] Refactor model addition process in kejilion.sh Refactor add-openclaw-provider function to add all models from a provider and improve error handling. Update interactive model addition process to streamline user input and model selection. --- cn/kejilion.sh | 328 +++++++++++++++++++++++++------------------------ 1 file changed, 170 insertions(+), 158 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2318bbdc7..1bf2ff005 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9757,47 +9757,99 @@ moltbot_menu() { - - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + # 核心函数:获取并添加所有模型 + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== 添加自定义 OpenAI 兼容模型到 OpenClaw ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # 检查参数 - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "错误:参数不能为空!" - echo "用法: add-openclaw-provider " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 正在获取 $provider_name 的所有可用模型..." + + # 获取模型列表 + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 无法获取模型列表" return 1 fi - # 检查 jq - if ! command -v jq &> /dev/null; then - echo "安装 jq: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "安装 jq 失败" - return 1 - } - fi + # 提取所有模型ID + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # 备份原文件 - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "备份: ${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 发现 $model_count 个模型" + + # 智能推断模型参数 + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # 根据模型名称推断上下文窗口 + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ 已添加 provider: $provider_name" - echo "📦 模型引用方式: $provider_name/$models_id" - echo "🔧 设置默认模型:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 重启网关:" - echo " openclaw gateway restart" + echo "✅ 成功添加 $model_count 个模型到 $provider_name" + echo "📦 模型引用格式: $provider_name/" + return 0 else - echo "❌ 添加失败,检查 jq 语法" + echo "❌ 配置注入失败" return 1 fi } - - # 可选:自动设置默认并重启 - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 设置默认模型并重启网关..." - openclaw models set "$1/$2" - start_tmux - echo "✅ 完成!当前默认模型: $1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - add-openclaw-provider-interactive() { - send_stats "添加API" - echo "=== 交互式添加 OpenClaw Provider ===" - - # 1. Provider 名称 - read -erp "请输入 Provider 名称 (如: deepseek): " provider_name - while [[ -z "$provider_name" ]]; do - echo "❌ Provider 名称不能为空" - read -erp "请输入 Provider 名称: " provider_name - done + send_stats "添加API" + echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" + + # 1. Provider 名称 + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -erp "请输入 Provider 名称: " provider_name + done - # 2. Base URL - read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url - while [[ -z "$base_url" ]]; do - echo "❌ Base URL 不能为空" - read -erp "请输入 Base URL: " base_url - done - # 自动处理结尾的 / - base_url="${base_url%/}" + # 2. Base URL + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -erp "请输入 Base URL: " base_url + done + base_url="${base_url%/}" - # 3. API Key - read -rsp "请输入 API Key (输入不显示): " api_key - echo - while [[ -z "$api_key" ]]; do - echo "❌ API Key 不能为空" - read -rsp "请输入 API Key: " api_key + # 3. API Key + read -rsp "请输入 API Key (输入不显示): " api_key echo - done - - # --- ✨ 新增逻辑:自动获取模型列表 --- - echo "🔍 正在尝试获取可用模型列表..." - - # 尝试请求 /models 端点 - models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done - # 简单的正则提取模型 ID (兼容性好,无需 jq) - if [[ -n "$models_json" ]]; then - # 提取 "id": "xxx" 格式的字符串 - available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + # 4. 获取模型列表 + echo "🔍 正在获取可用模型列表..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ 发现 $model_count 个可用模型:" + echo "--------------------------------" + # 全部显示,带序号 + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi - if [[ -n "$available_models" ]]; then - echo "✅ 发现以下可用模型:" - echo "--------------------------------" - i=1 - declare -A model_map - while read -r model; do - echo "[$i] $model" - model_map[$i]="$model" - ((i++)) - done <<< "$available_models" - echo "--------------------------------" - echo "💡 你可以输入序号选择,也可以直接输入模型 ID" + # 5. 选择默认模型 + echo + read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 使用第一个模型: $default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 已选择模型: $default_model" else - echo "⚠️ 未能解析出模型列表 (可能是格式不兼容),请手动输入。" + default_model="$input_model" fi - else - echo "⚠️ 连接 API 失败,请检查 URL 或网络。" - fi - # ------------------------------------- - - # 4. Model ID - read -erp "请输入 Model ID (或序号): " input_model - # 检查是否输入了序号 - if [[ -n "${model_map[$input_model]}" ]]; then - model_id="${model_map[$input_model]}" - echo "🎯 已选择模型: $model_id" - else - model_id="$input_model" - fi - - while [[ -z "$model_id" ]]; do - echo "❌ Model ID 不能为空" - read -erp "请输入 Model ID: " model_id - done + # 6. 确认信息 + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "默认模型 : $default_model" + echo "模型总数 : $model_count" + echo "======================" + + read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi - echo - echo "====== 确认信息 ======" - echo "Provider : $provider_name" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "Model ID : $model_id" - echo "======================" - - read -erp "确认添加?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + if [[ $? -eq 0 ]]; then + echo + echo "🔄 设置默认模型并重启网关..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅ 完成!所有 $model_count 个模型已加载" + fi - break_end + break_end } From d34a63fad42a343ac5a8ab7bac965fab9b8482f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:40:05 +0800 Subject: [PATCH 0798/1285] Refactor add-openclaw-provider for better model handling Refactor add-openclaw-provider function to improve model handling and add all models from provider. Enhance user interaction for provider setup. --- kejilion.sh | 328 +++++++++++++++++++++++++++------------------------- 1 file changed, 170 insertions(+), 158 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3bee4a597..31bdd42ec 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9757,47 +9757,99 @@ moltbot_menu() { - - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + # 核心函数:获取并添加所有模型 + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== 添加自定义 OpenAI 兼容模型到 OpenClaw ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # 检查参数 - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "错误:参数不能为空!" - echo "用法: add-openclaw-provider " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 正在获取 $provider_name 的所有可用模型..." + + # 获取模型列表 + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 无法获取模型列表" return 1 fi - # 检查 jq - if ! command -v jq &> /dev/null; then - echo "安装 jq: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "安装 jq 失败" - return 1 - } - fi + # 提取所有模型ID + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # 备份原文件 - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "备份: ${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 发现 $model_count 个模型" + + # 智能推断模型参数 + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # 根据模型名称推断上下文窗口 + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ 已添加 provider: $provider_name" - echo "📦 模型引用方式: $provider_name/$models_id" - echo "🔧 设置默认模型:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 重启网关:" - echo " openclaw gateway restart" + echo "✅ 成功添加 $model_count 个模型到 $provider_name" + echo "📦 模型引用格式: $provider_name/" + return 0 else - echo "❌ 添加失败,检查 jq 语法" + echo "❌ 配置注入失败" return 1 fi } - - # 可选:自动设置默认并重启 - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 设置默认模型并重启网关..." - openclaw models set "$1/$2" - start_tmux - echo "✅ 完成!当前默认模型: $1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - add-openclaw-provider-interactive() { - send_stats "添加API" - echo "=== 交互式添加 OpenClaw Provider ===" - - # 1. Provider 名称 - read -erp "请输入 Provider 名称 (如: deepseek): " provider_name - while [[ -z "$provider_name" ]]; do - echo "❌ Provider 名称不能为空" - read -erp "请输入 Provider 名称: " provider_name - done + send_stats "添加API" + echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" + + # 1. Provider 名称 + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + while [[ -z "$provider_name" ]]; do + echo "❌ Provider 名称不能为空" + read -erp "请输入 Provider 名称: " provider_name + done - # 2. Base URL - read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url - while [[ -z "$base_url" ]]; do - echo "❌ Base URL 不能为空" - read -erp "请输入 Base URL: " base_url - done - # 自动处理结尾的 / - base_url="${base_url%/}" + # 2. Base URL + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + while [[ -z "$base_url" ]]; do + echo "❌ Base URL 不能为空" + read -erp "请输入 Base URL: " base_url + done + base_url="${base_url%/}" - # 3. API Key - read -rsp "请输入 API Key (输入不显示): " api_key - echo - while [[ -z "$api_key" ]]; do - echo "❌ API Key 不能为空" - read -rsp "请输入 API Key: " api_key + # 3. API Key + read -rsp "请输入 API Key (输入不显示): " api_key echo - done - - # --- ✨ 新增逻辑:自动获取模型列表 --- - echo "🔍 正在尝试获取可用模型列表..." - - # 尝试请求 /models 端点 - models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") + while [[ -z "$api_key" ]]; do + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key + echo + done - # 简单的正则提取模型 ID (兼容性好,无需 jq) - if [[ -n "$models_json" ]]; then - # 提取 "id": "xxx" 格式的字符串 - available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + # 4. 获取模型列表 + echo "🔍 正在获取可用模型列表..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ 发现 $model_count 个可用模型:" + echo "--------------------------------" + # 全部显示,带序号 + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi - if [[ -n "$available_models" ]]; then - echo "✅ 发现以下可用模型:" - echo "--------------------------------" - i=1 - declare -A model_map - while read -r model; do - echo "[$i] $model" - model_map[$i]="$model" - ((i++)) - done <<< "$available_models" - echo "--------------------------------" - echo "💡 你可以输入序号选择,也可以直接输入模型 ID" + # 5. 选择默认模型 + echo + read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 使用第一个模型: $default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 已选择模型: $default_model" else - echo "⚠️ 未能解析出模型列表 (可能是格式不兼容),请手动输入。" + default_model="$input_model" fi - else - echo "⚠️ 连接 API 失败,请检查 URL 或网络。" - fi - # ------------------------------------- - - # 4. Model ID - read -erp "请输入 Model ID (或序号): " input_model - # 检查是否输入了序号 - if [[ -n "${model_map[$input_model]}" ]]; then - model_id="${model_map[$input_model]}" - echo "🎯 已选择模型: $model_id" - else - model_id="$input_model" - fi - - while [[ -z "$model_id" ]]; do - echo "❌ Model ID 不能为空" - read -erp "请输入 Model ID: " model_id - done + # 6. 确认信息 + echo + echo "====== 确认信息 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "默认模型 : $default_model" + echo "模型总数 : $model_count" + echo "======================" + + read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 已取消" + return 1 + fi - echo - echo "====== 确认信息 ======" - echo "Provider : $provider_name" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "Model ID : $model_id" - echo "======================" - - read -erp "确认添加?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + if [[ $? -eq 0 ]]; then + echo + echo "🔄 设置默认模型并重启网关..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅ 完成!所有 $model_count 个模型已加载" + fi - break_end + break_end } From 9b0161e6defd12ed066276ac634bb209414a6090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:15:42 +0800 Subject: [PATCH 0799/1285] Update version to 4.3.10 and add image input --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1bf2ff005..e2676f0ae 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -9826,7 +9826,7 @@ moltbot_menu() { { "id": "$model_id", "name": "$provider_name / $model_id", - "input": ["text"], + "input": ["text", "image"], "contextWindow": $context_window, "maxTokens": $max_tokens, "cost": { From 05e80904bce59c80c7cf5a4a630b2c4642f905de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:16:33 +0800 Subject: [PATCH 0800/1285] Update version and input types in kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 31bdd42ec..ad65de246 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -9826,7 +9826,7 @@ moltbot_menu() { { "id": "$model_id", "name": "$provider_name / $model_id", - "input": ["text"], + "input": ["text", "image"], "contextWindow": $context_window, "maxTokens": $max_tokens, "cost": { From 2c1222e75fb14639e130063e9a5cb3f450274000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:18:53 +0800 Subject: [PATCH 0801/1285] Update changelog for ClawdBot/Moltbot enhancements --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1dfbe0a7e..5bf75ac64 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1450,4 +1450,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目优化技能和插件安装体验,修复安装失败问题。 应用市场对ClawdBot/Moltbot机器人项目新增webui访问设置功能,可以用域名访问后台。 ------------------------ +2026-02-11 v4.3.10 +应用市场对ClawdBot/Moltbot机器人项目添加API支持批量导入模型。 +------------------------ From e4eeb29727eae9854ff000039104c4b94e9476b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 15 Feb 2026 00:16:22 +0800 Subject: [PATCH 0802/1285] Update token URL format in kejilion.sh --- cn/kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e2676f0ae..7906a2781 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10323,18 +10323,18 @@ EOF token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "本机地址:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then echo "域名地址:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10350,13 +10350,13 @@ EOF token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "访问地址:" - echo "https://${yuming}/?token=$token" + echo "https://${yuming}/#token=$token" echo "先访问URL触发设备ID,然后回车下一步进行配对。" read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" From 0518e7189fab6d354a144ec46da7aec1bc9d11de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 15 Feb 2026 00:16:51 +0800 Subject: [PATCH 0803/1285] Update token URL format in kejilion.sh --- kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ad65de246..d482c6575 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10323,18 +10323,18 @@ EOF token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "本机地址:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then echo "域名地址:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10350,13 +10350,13 @@ EOF token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "访问地址:" - echo "https://${yuming}/?token=$token" + echo "https://${yuming}/#token=$token" echo "先访问URL触发设备ID,然后回车下一步进行配对。" read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" From 0e3751136307c240082fd1e153889c6486b68293 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 15 Feb 2026 05:12:45 +0000 Subject: [PATCH 0804/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-15=2005:12:45?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 370 +++--- jp/kejilion.sh | 356 ++--- kr/kejilion.sh | 396 +++--- tw/kejilion.sh | 3426 ++++++++++++++++++++++++------------------------ 4 files changed, 2390 insertions(+), 2158 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 1889bc601..5ab06c21f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -2318,7 +2318,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -4313,7 +4313,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4410,7 +4410,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -5163,7 +5163,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -6056,7 +6056,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -6319,9 +6319,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6363,7 +6363,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6506,7 +6506,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6882,7 +6882,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7236,7 +7236,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -7303,7 +7303,7 @@ linux_tools() { echo -e "${gl_kjlan}17. ${gl_bai}git version control system${gl_kjlan}18. ${gl_bai}opencode AI programming assistant${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}The Matrix Screensaver${gl_kjlan}22. ${gl_bai}Running train screensaver" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}Snake mini game" + echo -e "${gl_kjlan}26. ${gl_bai}Tetris mini game${gl_kjlan}27. ${gl_bai}Snake mini game" echo -e "${gl_kjlan}28. ${gl_bai}space invaders mini game" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Install all${gl_kjlan}32. ${gl_bai}Install all (excluding screensavers and games)${gl_huang}★${gl_bai}" @@ -7710,7 +7710,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8238,7 +8238,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9732,8 +9732,8 @@ moltbot_menu() { start_bot() { - echo "Start OpenClaw..." - send_stats "Start OpenClaw..." + echo "Starting OpenClaw..." + send_stats "Starting OpenClaw..." start_tmux break_end } @@ -9755,46 +9755,101 @@ moltbot_menu() { - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + + + # Core function: get and add all models + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== Add custom OpenAI compatible models to OpenClaw ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # Check parameters - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "Error: Parameter cannot be empty!" - echo "Usage: add-openclaw-provider " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 Getting$provider_nameAll available models of..." + + # Get model list + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ Unable to obtain model list" return 1 fi - # Check jq - if ! command -v jq &> /dev/null; then - echo "Install jq: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "Installation of jq failed" - return 1 - } - fi + # Extract all model IDs + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # Back up original files - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "Backup:${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ No models found" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ Discover$model_countmodels" + + # Intelligent inference of model parameters + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # Infer context window based on model name + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ Provider added:$provider_name" - echo "📦 Model reference method:$provider_name/$models_id" - echo "🔧 Set default model:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 Restart the gateway:" - echo " openclaw gateway restart" + echo "✅ Added successfully$model_countmodels arrive$provider_name" + echo "📦 Model reference format:$provider_name/" + return 0 else - echo "❌ Add failed, check jq syntax" + echo "❌ Configuration injection failed" return 1 fi } - # Optional: Automatically set defaults and restart - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 Set default model and restart gateway..." - openclaw models set "$1/$2" - start_tmux - echo "✅ Done! Current default model:$1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - - - add-openclaw-provider-interactive() { send_stats "Add API" - echo "=== Add OpenClaw Provider interactively ===" + echo "=== Interactively add OpenClaw Provider (full model) ===" - # Provider name + # 1. Provider name read -erp "Please enter the Provider name (eg: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider name cannot be empty" read -erp "Please enter Provider name:" provider_name done - # Model ID - read -erp "Please enter Model ID (eg: deepseek-chat):" model_id - while [[ -z "$model_id" ]]; do - echo "❌ Model ID cannot be empty" - read -erp "Please enter Model ID:" model_id - done - - # Base URL + # 2. Base URL read -erp "Please enter Base URL (eg: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL cannot be empty" read -erp "Please enter Base URL:" base_url done + base_url="${base_url%/}" - # API Key (hidden input) + # 3. API Key read -rsp "Please enter API Key (input will not be displayed):" api_key echo while [[ -z "$api_key" ]]; do @@ -9888,26 +9901,71 @@ moltbot_menu() { echo done + # 4. Get model list + echo "🔍 Getting list of available models..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ Discover$model_countAvailable models:" + echo "--------------------------------" + # Show all, with serial number + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi + + # 5. Select the default model + echo + read -erp "Please enter the default Model ID (or serial number, leave blank to use the first one):" input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 Using the first model:$default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 Selected models:$default_model" + else + default_model="$input_model" + fi + + # 6. Confirm information echo echo "====== Confirmation ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "Default model:$default_model" + echo "Total number of models:$model_count" echo "======================" - read -erp "Confirm to add? (y/N):" confirm + read -erp "Confirm to add all$model_countA model? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ Canceled" return 1 fi - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 Set default model and restart gateway..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅ Done! all$model_countmodels loaded" + fi break_end } @@ -10006,7 +10064,7 @@ moltbot_menu() { echo "💡 It is detected that the plug-in already exists in the system directory and is being activated directly..." openclaw plugins enable "$plugin_name" else - echo "📥 Downloading and installing the plug-in through official channels..." + echo "📥 Downloading and installing plug-ins through official channels..." # Use openclaw's own install command, which automatically handles spec checking of package.json openclaw plugins install "$plugin_name" @@ -10265,18 +10323,18 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "Local address:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then echo "Domain name address:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10292,13 +10350,13 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "Visit address:" - echo "https://${yuming}/?token=$token" + echo "https://${yuming}/#token=$token" echo "First access the URL to trigger the device ID, then press Enter to proceed with pairing." read echo -e "${gl_kjlan}Loading device list...${gl_bai}" @@ -10903,7 +10961,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -10957,7 +11015,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11055,7 +11113,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11941,7 +11999,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12168,7 +12226,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12220,7 +12278,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12261,7 +12319,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12324,7 +12382,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12538,7 +12596,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -12565,7 +12623,7 @@ while true; do } - local docker_describe="A password manager where you can control your data" + local docker_describe="A password manager that puts you in control of your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12652,7 +12710,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12873,7 +12931,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12923,7 +12981,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13059,7 +13117,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13122,7 +13180,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -13286,7 +13344,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13374,7 +13432,7 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" + local docker_describe="Distributed high-speed download tool, supporting multiple protocols" local docker_url="Official website introduction:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -13424,7 +13482,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13478,7 +13536,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13711,7 +13769,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13753,7 +13811,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13782,7 +13840,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13851,7 +13909,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13992,7 +14050,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14062,7 +14120,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14149,7 +14207,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through web pages." + local docker_describe="It is a Firefox browser running in Docker that supports direct access to the desktop browser interface through the web page." local docker_url="Project address:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -14208,7 +14266,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14270,7 +14328,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -14286,7 +14344,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" - echo -e "${gl_kjlan}10. ${gl_bai}Workspace No. 10" + echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" @@ -14666,7 +14724,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -14744,7 +14802,7 @@ env_menu() { show_env_vars() { clear - send_stats "Environment variables currently in effect" + send_stats "Currently in effect environment variables" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -15430,7 +15488,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil Time 26. Argentina Time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -16319,7 +16377,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16461,7 +16519,7 @@ echo "------------------------" echo -e "${gl_zi}Hostinger $52.7 per year United States 1 core 4G memory 50G hard drive 4T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" +echo -e "${gl_huang}Bricklayer 49 dollars per quarter US CN2GIA Japan SoftBank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}Website: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT $28 per quarter US CN2GIA 1 core 2G memory 20G hard drive 800G traffic per month${gl_bai}" @@ -16676,7 +16734,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}Collection of game server opening scripts" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}exit script" +echo -e "${gl_kjlan}0. ${gl_bai}Exit script" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "Please enter your choice:" choice @@ -16709,7 +16767,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" @@ -16914,12 +16972,12 @@ else ;; stop|停止) shift - send_stats "Software paused" + send_stats "software pause" stop "$@" ;; restart|重启) shift - send_stats "software restart" + send_stats "Software restart" restart "$@" ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 48236959d..e8295d3b0 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -254,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -924,12 +924,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2116,7 +2116,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2231,11 +2231,11 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2349,7 +2349,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2614,7 +2614,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2631,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3884,7 +3884,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4231,7 +4231,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -5163,7 +5163,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion } @@ -6029,7 +6029,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -6056,7 +6056,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6319,9 +6319,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6363,7 +6363,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6700,7 +6700,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードは /etc/fstab にすでに存在するため、書き込みをスキップします" + echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7236,7 +7236,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7300,7 +7300,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7672,7 +7672,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -7692,7 +7692,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包量:$path" + echo "梱包体積:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -9656,7 +9656,7 @@ moltbot_menu() { if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}ランニング${gl_bai}" else - echo "${gl_hui}実行されていません${gl_bai}" + echo "${gl_hui}稼働していない${gl_bai}" fi } @@ -9732,8 +9732,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw を開始します..." - send_stats "OpenClaw を開始します..." + echo "OpenClaw を開始しています..." + send_stats "OpenClaw を開始しています..." start_tmux break_end } @@ -9755,46 +9755,101 @@ moltbot_menu() { - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + + + # コア機能: すべてのモデルの取得と追加 + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== カスタム OpenAI 互換モデルを OpenClaw に追加 ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # パラメータをチェックする - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "エラー: パラメータを空にすることはできません。" - echo "使用法: add-openclaw-provider <プロバイダー> <モデル ID> <ベース URL> " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 取得中$provider_name利用可能なすべてのモデル..." + + # モデルリストの取得 + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ モデルリストを取得できません" return 1 fi - # jqをチェックする - if ! command -v jq &> /dev/null; then - echo "jq をインストールします: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "jqのインストールに失敗しました" - return 1 - } - fi + # すべてのモデル ID を抽出します + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # 元のファイルをバックアップする - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "バックアップ:${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ モデルが見つかりません" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 発見する$model_countモデル" + + # モデルパラメータのインテリジェントな推論 + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # モデル名に基づいてコンテキスト ウィンドウを推測する + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ プロバイダーが追加しました:$provider_name" - echo "📦 モデル参照方法:$provider_name/$models_id" - echo "🔧 デフォルトのモデルを設定します:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 ゲートウェイを再起動します。" - echo " openclaw gateway restart" + echo "✅ 正常に追加されました$model_countモデルが到着$provider_name" + echo "📦 モデル参照形式:$provider_name/" + return 0 else - echo "❌ 追加に失敗しました。jq 構文を確認してください" + echo "❌ 構成の挿入に失敗しました" return 1 fi } - # オプション: 自動的にデフォルトを設定して再起動します - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." - openclaw models set "$1/$2" - start_tmux - echo "✅完了!現在のデフォルトモデル:$1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - - - add-openclaw-provider-interactive() { send_stats "APIの追加" - echo "=== OpenClaw プロバイダーを対話的に追加します ===" + echo "=== OpenClaw プロバイダー (フルモデル) を対話的に追加 ===" - # プロバイダ名 + # 1.プロバイダ名 read -erp "プロバイダー名を入力してください (例: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ プロバイダー名を空にすることはできません" read -erp "プロバイダー名を入力してください:" provider_name done - # Model ID - read -erp "モデル ID を入力してください (例: deepseek-chat):" model_id - while [[ -z "$model_id" ]]; do - echo "❌ モデル ID を空にすることはできません" - read -erp "モデルIDを入力してください:" model_id - done - - # Base URL + # 2. Base URL read -erp "ベース URL (例: https://api.xxx.com/v1) を入力してください:" base_url while [[ -z "$base_url" ]]; do echo "❌ ベース URL を空にすることはできません" read -erp "ベース URL を入力してください:" base_url done + base_url="${base_url%/}" - # API キー (隠し入力) + # 3. API Key read -rsp "API キーを入力してください (入力は表示されません):" api_key echo while [[ -z "$api_key" ]]; do @@ -9888,26 +9901,71 @@ moltbot_menu() { echo done + # 4. モデルリストの取得 + echo "🔍 利用可能なモデルのリストを取得中..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ 発見する$model_count利用可能なモデル:" + echo "--------------------------------" + # すべて表示 (シリアル番号付き) + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi + + # 5. デフォルトのモデルを選択します + echo + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 最初のモデルの使用:$default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 選択されたモデル:$default_model" + else + default_model="$input_model" + fi + + # 6. 情報の確認 echo echo "====== 確認 ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "デフォルトのモデル:$default_model" + echo "モデルの総数:$model_count" echo "======================" - read -erp "追加を確認しますか? (y/N):" confirm + read -erp "すべて追加することを確認します$model_countモデル? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ キャンセルされました" return 1 fi - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅完了!全て$model_countロードされたモデル" + fi break_end } @@ -10086,7 +10144,7 @@ moltbot_menu() { # インストールを実行し、結果を取得します if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードが成功しました。アクティブ化されています..." + echo "✅ ダウンロードに成功しました。アクティブ化しています..." openclaw plugins enable "$plugin_id" else echo "⚠️ 公式チャネルからのダウンロードに失敗しました。代替手段をお試しください..." @@ -10265,18 +10323,18 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "ローカルアドレス:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then echo "ドメイン名アドレス:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10292,16 +10350,16 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "訪問先住所:" - echo "https://${yuming}/?token=$token" + echo "https://${yuming}/#token=$token" echo "まず URL にアクセスしてデバイス ID をトリガーし、Enter キーを押してペアリングを続行します。" read - echo -e "${gl_kjlan}デバイスリストを読み込んでいます...${gl_bai}" + echo -e "${gl_kjlan}デバイスリストをロード中...${gl_bai}" openclaw devices list read -e -p "Request_Key を入力してください:" Request_Key @@ -11664,7 +11722,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -12565,7 +12623,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -13122,7 +13180,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -13498,7 +13556,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -13610,7 +13668,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -13753,7 +13811,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14208,7 +14266,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリのバックアップ" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14270,8 +14328,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -14286,7 +14344,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" - echo -e "${gl_kjlan}10. ${gl_bai}ワークスペースNo.10" + echo -e "${gl_kjlan}10. ${gl_bai}ワークスペース10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐モード${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}ワークスペースの作成/入力" @@ -14666,7 +14724,7 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "続行するには Enter キーを押してください..." @@ -14824,7 +14882,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集します" + echo "4. ~/.bashrc を編集する" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -15405,7 +15463,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -15900,7 +15958,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -16319,7 +16377,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16709,7 +16767,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -16748,7 +16806,7 @@ echo "リバース プロキシをインストールします k fd |k rp |k リ echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -16914,7 +16972,7 @@ else ;; stop|停止) shift - send_stats "ソフトウェアが一時停止されました" + send_stats "ソフトウェアの一時停止" stop "$@" ;; restart|重启) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 55b9135b9..6bc342181 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -117,7 +117,7 @@ CheckFirstRun_false() { # 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear - echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다.${gl_bai}" echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -1540,7 +1540,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -1846,7 +1846,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -2125,7 +2125,7 @@ web_security() { echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3430,7 +3430,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3646,7 +3646,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4896,7 +4896,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5010,7 +5010,7 @@ fetch_github_ssh_keys() { echo "1. 로그인${gh_https_url}github.com/settings/keys" echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" - echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여 넣습니다." + echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." echo "" echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." @@ -5550,7 +5550,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5560,7 +5560,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5614,7 +5614,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5703,7 +5703,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5721,7 +5721,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5757,7 +5757,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -6056,7 +6056,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -6263,7 +6263,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6502,11 +6502,11 @@ add_connection() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6878,11 +6878,11 @@ add_task() { echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함되어 있으면 입력을 종료합니다. + # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7630,7 +7630,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7769,7 +7769,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -7785,7 +7785,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}처리용기:$container${gl_bai}" + echo -e "${gl_lv}처리 용기:$container${gl_bai}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -7859,7 +7859,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "도커 마이그레이션" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } read -e -p "대상 서버 IP:" TARGET_IP @@ -8104,7 +8104,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8419,7 +8419,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9732,8 +9732,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw를 시작하세요..." - send_stats "OpenClaw를 시작하세요..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_tmux break_end } @@ -9755,46 +9755,101 @@ moltbot_menu() { - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + + + # 핵심 기능: 모든 모델 가져오기 및 추가 + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== OpenClaw에 맞춤형 OpenAI 호환 모델 추가 ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # 매개변수 확인 - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "오류: 매개변수는 비워둘 수 없습니다!" - echo "사용법: add-openclaw-provider " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 받기$provider_name사용 가능한 모든 모델..." + + # 모델 목록 가져오기 + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 모델 목록을 가져올 수 없습니다" return 1 fi - # jq를 확인하세요 - if ! command -v jq &> /dev/null; then - echo "jq 설치: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "jq 설치 실패" - return 1 - } - fi + # 모든 모델 ID 추출 + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # 원본 파일 백업 - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "지원:${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ 모델을 찾을 수 없습니다" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 발견$model_count모델" + + # 모델 매개변수의 지능적 추론 + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # 모델명을 기준으로 컨텍스트 창 추론 + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ 제공업체 추가됨:$provider_name" - echo "📦 모델 참조 방법:$provider_name/$models_id" - echo "🔧 기본 모델 설정:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 게이트웨이를 다시 시작하세요:" - echo " openclaw gateway restart" + echo "✅ 성공적으로 추가되었습니다$model_count모델 도착$provider_name" + echo "📦 모델 참조 형식:$provider_name/" + return 0 else - echo "❌ 추가 실패. jq 구문을 확인하세요." + echo "❌ 구성 삽입 실패" return 1 fi } - # 선택 사항: 자동으로 기본값을 설정하고 다시 시작합니다. - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." - openclaw models set "$1/$2" - start_tmux - echo "✅ 완료! 현재 기본 모델:$1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - - - add-openclaw-provider-interactive() { send_stats "API 추가" - echo "=== 대화식으로 OpenClaw 공급자 추가 ===" + echo "=== 대화식으로 OpenClaw 공급자 추가(전체 모델) ===" - # 제공자 이름 + # 1. 제공자 이름 read -erp "공급자 이름을 입력하십시오(예: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ 제공업체 이름은 비워둘 수 없습니다." read -erp "제공업체 이름을 입력하세요." provider_name done - # Model ID - read -erp "모델 ID를 입력하세요(예: deepseek-chat):" model_id - while [[ -z "$model_id" ]]; do - echo "❌ 모델 ID는 비워둘 수 없습니다." - read -erp "모델 ID를 입력하세요:" model_id - done - - # Base URL + # 2. Base URL read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ 기본 URL은 비워둘 수 없습니다." read -erp "기본 URL을 입력하세요:" base_url done + base_url="${base_url%/}" - # API 키(숨겨진 입력) + # 3. API Key read -rsp "API 키를 입력하세요(입력은 표시되지 않습니다):" api_key echo while [[ -z "$api_key" ]]; do @@ -9888,26 +9901,71 @@ moltbot_menu() { echo done + # 4. 모델 목록 가져오기 + echo "🔍 사용 가능한 모델 목록을 가져오는 중..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ 발견$model_count사용 가능한 모델:" + echo "--------------------------------" + # 일련번호와 함께 모두 표시 + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi + + # 5. 기본 모델을 선택하세요 + echo + read -erp "기본 모델 ID(또는 일련번호, 첫 번째 번호를 사용하려면 비워 두세요)를 입력하세요." input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 첫 번째 모델 사용:$default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 선택 모델:$default_model" + else + default_model="$input_model" + fi + + # 6. 정보 확인 echo echo "====== 확인 ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "기본 모델:$default_model" + echo "총 모델 수:$model_count" echo "======================" - read -erp "추가하시겠습니까? (예/아니요):" confirm + read -erp "모두 추가하려면 확인하세요.$model_count모델? (예/아니요):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 취소됨" return 1 fi - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅ 완료! 모두$model_count로드된 모델" + fi break_end } @@ -10074,7 +10132,7 @@ moltbot_menu() { # 3. 시스템 물리적 디렉토리가 존재하는지 확인하십시오. elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." openclaw plugins enable "$plugin_id" else @@ -10096,7 +10154,7 @@ moltbot_menu() { openclaw plugins enable "$plugin_id" else echo "❌ 치명적인 오류: 플러그인을 얻을 수 없습니다. ID가 맞는지, 네트워크 사용이 가능한지 확인해주세요." - # 키: 구성이 하드 코딩되는 것을 방지하려면 아래의 Starting_tmux 대신 여기로 직접 돌아가거나 계속하세요. + # 키: 구성이 하드 코딩되는 것을 방지하려면 아래의 start_tmux 대신 여기로 직접 돌아가거나 계속하세요. break_end continue fi @@ -10265,18 +10323,18 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "현지 주소:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then echo "도메인 이름 주소:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10292,13 +10350,13 @@ moltbot_menu() { token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "방문 주소:" - echo "https://${yuming}/?token=$token" + echo "https://${yuming}/#token=$token" echo "먼저 URL에 액세스하여 장치 ID를 트리거한 다음 Enter를 눌러 페어링을 진행하세요." read echo -e "${gl_kjlan}기기 목록 로드 중...${gl_bai}" @@ -10441,7 +10499,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -10489,7 +10547,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -10497,7 +10555,7 @@ while true; do echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}ClawdBot/Moltbot 로봇${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -10699,7 +10757,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -10710,7 +10768,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -10831,7 +10889,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -11399,7 +11457,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -11538,7 +11596,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -11565,7 +11623,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -12070,7 +12128,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -12232,7 +12290,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12565,7 +12623,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -13122,7 +13180,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -13154,7 +13212,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -13753,7 +13811,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14208,7 +14266,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14270,7 +14328,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -14286,7 +14344,7 @@ linux_work() { echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10호" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" @@ -14666,7 +14724,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -14940,10 +14998,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -15425,7 +15483,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -15588,7 +15646,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -16219,7 +16277,7 @@ linux_file() { continue fi - # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -16311,7 +16369,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 순회하고 명령을 실행합니다. + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -16319,7 +16377,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16395,7 +16453,7 @@ while true; do clear send_stats "클러스터 복원" echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -16461,7 +16519,7 @@ echo "------------------------" echo -e "${gl_zi}Hostinger 연간 $52.7 미국 1 코어 4G 메모리 50G 하드 드라이브 월별 4T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}벽돌공 분기당 49달러 미국 CN2GIA 일본 Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_huang}벽돌공 분기당 49달러 미국 CN2GIA 일본 SoftBank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}웹사이트: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" @@ -16676,7 +16734,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}종료 스크립트" +echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택사항을 입력하세요:" choice @@ -16709,12 +16767,12 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -16748,12 +16806,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" @@ -16914,12 +16972,12 @@ else ;; stop|停止) shift - send_stats "소프트웨어가 일시중지됨" + send_stats "소프트웨어 일시 중지" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 다시 시작" + send_stats "소프트웨어 재시작" restart "$@" ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 8c08346da..f5c0eea88 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.9" +sh_v="4.3.10" gl_hui='\e[37m' @@ -59,9 +59,9 @@ CheckFirstRun_true() { -# 收集功能埋點信息的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! -# 為什麼要設計這個功能,目的更好的了解用戶喜歡使用的功能,進一步優化功能推出更多符合用戶需求的功能。 -# 全文可搜搜 send_stats 函數調用位置,透明開源,如有顧慮可拒絕使用。 +# 收集功能埋藏資訊的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! +# 為什麼要設計這個功能,目的更好的了解使用者喜歡使用的功能,進一步優化功能推出更多符合使用者需求的功能。 +# 全文可搜尋 send_stats 函數呼叫位置,透明開源,如有顧慮可拒絕使用。 @@ -114,12 +114,12 @@ CheckFirstRun_false() { fi } -# 提示用戶同意條款 +# 提示使用者同意條款 UserLicenseAgreement() { clear echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" - echo "首次使用腳本,請先閱讀並同意用戶許可協議。" - echo "用戶許可協議: https://blog.kejilion.pro/user-license-agreement/" + echo "首次使用腳本,請先閱讀並同意使用者授權協議。" + echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "是否同意以上條款? (y/n):" user_input @@ -173,7 +173,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供軟件包參數!" + echo "未提供軟體包參數!" return 1 fi @@ -207,7 +207,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "未知的套件管理器!" return 1 fi fi @@ -225,11 +225,11 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}提示:${gl_bai}磁盤空間不足!" - echo "當前可用空間: $((available_space_mb/1024))G" + echo -e "${gl_huang}提示:${gl_bai}磁碟空間不足!" + echo "目前可用空間: $((available_space_mb/1024))G" echo "最小需求空間:${required_gb}G" - echo "無法繼續安裝,請清理磁盤空間後重試。" - send_stats "磁盤空間不足" + echo "無法繼續安裝,請清理磁碟空間後重試。" + send_stats "磁碟空間不足" break_end kejilion fi @@ -249,7 +249,7 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供軟件包參數!" + echo "未提供軟體包參數!" return 1 fi @@ -272,7 +272,7 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "未知的套件管理器!" return 1 fi done @@ -341,7 +341,7 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME已設置為開機自啟。" + echo "$SERVICE_NAME已設定為開機自啟動。" } @@ -479,45 +479,45 @@ while true; do echo "" echo "容器操作" echo "------------------------" - echo "1. 創建新的容器" + echo "1. 建立新的容器" echo "------------------------" - echo "2. 啟動指定容器 6. 啟動所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 刪除指定容器 8. 刪除所有容器" - echo "5. 重啟指定容器 9. 重啟所有容器" + echo "2. 啟動指定容器 6. 啟動所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 刪除指定容器 8. 刪除所有容器" + echo "5. 重啟指定容器 9. 重新啟動所有容器" echo "------------------------" - echo "11. 進入指定容器 12. 查看容器日誌" - echo "13. 查看容器網絡 14. 查看容器佔用" + echo "11. 進入指定容器 12. 查看容器日誌" + echo "13. 查看容器網路 14. 查看容器佔用" echo "------------------------" - echo "15. 開啟容器端口訪問 16. 關閉容器端口訪問" + echo "15. 開啟容器連接埠存取 16. 關閉容器連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "請輸入創建命令:" dockername + send_stats "新容器" + read -e -p "請輸入建立命令:" dockername $dockername ;; 2) send_stats "啟動指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker start $dockername ;; 3) send_stats "停止指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker stop $dockername ;; 4) send_stats "刪除指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker rm -f $dockername ;; 5) send_stats "重啟指定容器" - read -e -p "請輸入容器名(多個容器名請用空格分隔):" dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker restart $dockername ;; 6) @@ -548,13 +548,13 @@ while true; do ;; 11) send_stats "進入容器" - read -e -p "請輸入容器名:" dockername + read -e -p "請輸入容器名稱:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) send_stats "查看容器日誌" - read -e -p "請輸入容器名:" dockername + read -e -p "請輸入容器名稱:" dockername docker logs $dockername break_end ;; @@ -563,7 +563,7 @@ while true; do echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "容器名稱" "網絡名稱" "IP地址" + printf "%-25s %-25s %-25s\n" "容器名稱" "網路名稱" "IP位址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -583,8 +583,8 @@ while true; do ;; 15) - send_stats "允許容器端口訪問" - read -e -p "請輸入容器名:" docker_name + send_stats "允許容器連接埠訪問" + read -e -p "請輸入容器名稱:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -593,8 +593,8 @@ while true; do ;; 16) - send_stats "阻止容器端口訪問" - read -e -p "請輸入容器名:" docker_name + send_stats "阻止容器連接埠訪問" + read -e -p "請輸入容器名稱:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -613,14 +613,14 @@ done docker_image() { while true; do clear - send_stats "Docker鏡像管理" - echo "Docker鏡像列表" + send_stats "Docker映像管理" + echo "Docker映像列表" docker image ls echo "" echo "鏡像操作" echo "------------------------" - echo "1. 獲取指定鏡像 3. 刪除指定鏡像" - echo "2. 更新指定鏡像 4. 刪除所有鏡像" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -628,15 +628,15 @@ while true; do case $sub_choice in 1) send_stats "拉取鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do - echo -e "${gl_kjlan}正在獲取鏡像:$name${gl_bai}" + echo -e "${gl_kjlan}正在取得鏡像:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + send_stats "更新镜像" + read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do echo -e "${gl_kjlan}正在更新鏡像:$name${gl_bai}" docker pull $name @@ -644,7 +644,7 @@ while true; do ;; 3) send_stats "刪除鏡像" - read -e -p "請輸入鏡像名(多個鏡像名請用空格分隔):" imagenames + read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do docker rmi -f $name done @@ -727,16 +727,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的發行版:$ID" + echo "不支援的發行版:$ID" return ;; esac else - echo "無法確定操作系統。" + echo "無法確定作業系統。" return fi - echo -e "${gl_lv}crontab 已安裝且 cron 服務正在運行。${gl_bai}" + echo -e "${gl_lv}crontab 已安裝且 cron 服務正在執行。${gl_bai}" } @@ -748,15 +748,15 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 檢查配置文件是否存在,如果不存在則創建文件並寫入默認設置 + # 檢查設定檔是否存在,如果不存在則建立檔案並寫入預設設定 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq處理配置文件的更新 + # 使用jq處理設定檔的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 檢查當前配置是否已經有 ipv6 設置 + # 檢查目前配置是否已經有 ipv6 設定 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') # 更新配置,開啟 IPv6 @@ -766,9 +766,9 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 對比原始配置與新配置 + # 比較原始配置與新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}當前已開啟ipv6訪問${gl_bai}" + echo -e "${gl_huang}目前已開啟ipv6訪問${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -783,24 +783,24 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 檢查配置文件是否存在 + # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}設定檔不存在${gl_bai}" return fi - # 讀取當前配置 + # 讀取目前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq處理配置文件的更新 + # 使用jq處理設定檔的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 檢查當前的 ipv6 狀態 + # 檢查目前的 ipv6 狀態 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 對比原始配置與新配置 + # 比較原始配置與新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}當前已關閉ipv6訪問${gl_bai}" + echo -e "${gl_huang}目前已關閉ipv6訪問${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -843,7 +843,7 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "請提供至少一個端口號" + echo "請提供至少一個連接埠號" return 1 fi @@ -854,44 +854,44 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打開規則 + # 新增開啟規則 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打開端口$port" + echo "已開啟連接埠$port" fi done save_iptables_rules - send_stats "已打開端口" + send_stats "已開啟連接埠" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "請提供至少一個端口號" + echo "請提供至少一個連接埠號" return 1 fi install iptables for port in "${ports[@]}"; do - # 刪除已存在的打開規則 + # 刪除已存在的開啟規則 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加關閉規則 + # 新增關閉規則 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已關閉端口$port" + echo "已關閉連接埠$port" fi done @@ -904,14 +904,14 @@ close_port() { iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已關閉端口" + send_stats "已關閉連接埠" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "請提供至少一個IP地址或IP段" + echo "請提供至少一個IP位址或IP段" return 1 fi @@ -921,7 +921,7 @@ allow_ip() { # 刪除已存在的阻止規則 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允許規則 + # 新增允許規則 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "已放行IP$ip" @@ -935,7 +935,7 @@ allow_ip() { block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "請提供至少一個IP地址或IP段" + echo "請提供至少一個IP位址或IP段" return 1 fi @@ -945,7 +945,7 @@ block_ip() { # 刪除已存在的允許規則 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止規則 + # 新增阻止規則 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP echo "已阻止IP$ip" @@ -1013,7 +1013,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" + echo "錯誤:下載$country_code的 IP 區域檔案失敗" continue fi @@ -1023,7 +1023,7 @@ manage_country_rules() { iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - echo "已成功阻止$country_code的 IP 地址" + echo "已成功阻止$country_code的 IP 位址" rm "${country_code,,}.zone" ;; @@ -1033,7 +1033,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域文件失敗" + echo "錯誤:下載$country_code的 IP 區域檔案失敗" continue fi @@ -1046,7 +1046,7 @@ manage_country_rules() { iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - echo "已成功允許$country_code的 IP 地址" + echo "已成功允許$country_code的 IP 位址" rm "${country_code,,}.zone" ;; @@ -1057,7 +1057,7 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "已成功解除$country_code的 IP 地址限制" + echo "已成功解除$country_code的 IP 位址限制" ;; *) @@ -1082,24 +1082,24 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高級防火牆管理" - send_stats "高級防火牆管理" + echo "進階防火牆管理" + send_stats "進階防火牆管理" echo "------------------------" iptables -L INPUT echo "" echo "防火牆管理" echo "------------------------" - echo "1. 開放指定端口 2. 關閉指定端口" - echo "3. 開放所有端口 4. 關閉所有端口" + echo "1. 開放指定連接埠 2. 關閉指定連接埠" + echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" - echo "5. IP白名單 6. IP黑名單" - echo "7. 清除指定IP" + echo "5. IP白名單 6. IP黑名單" + echo "7. 清除指定IP" echo "------------------------" - echo "11. 允許PING 12. 禁止PING" + echo "11. 允許PING 12. 禁止PING" echo "------------------------" - echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" + echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" echo "------------------------" - echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" + echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" echo "17. 解除指定國家IP限制" echo "------------------------" echo "0. 返回上一級選單" @@ -1107,17 +1107,17 @@ iptables_panel() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - read -e -p "請輸入開放的端口號:" o_port + read -e -p "請輸入開放的連接埠號碼:" o_port open_port $o_port - send_stats "開放指定端口" + send_stats "開放指定連接埠" ;; 2) - read -e -p "請輸入關閉的端口號:" c_port + read -e -p "請輸入關閉的連接埠號碼:" c_port close_port $c_port - send_stats "關閉指定端口" + send_stats "關閉指定連接埠" ;; 3) - # 開放所有端口 + # 開放所有連接埠 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1130,10 +1130,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "開放所有端口" + send_stats "開放所有連接埠" ;; 4) - # 關閉所有端口 + # 關閉所有連接埠 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1146,7 +1146,7 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "關閉所有端口" + send_stats "關閉所有連接埠" ;; 5) @@ -1221,10 +1221,10 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 獲取當前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍歷並刪除所有的 swap 分區 + # 遍歷並刪除所有的 swap 分割區 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" @@ -1237,7 +1237,7 @@ add_swap() { # 刪除舊的 /swapfile rm -f /swapfile - # 創建新的 swap 分區 + # 建立新的 swap 分割區 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1252,7 +1252,7 @@ add_swap() { rc-update add local fi - echo -e "虛擬內存大小已調整為${gl_huang}${new_swap}${gl_bai}M" + echo -e "虛擬記憶體大小已調整為${gl_huang}${new_swap}${gl_bai}M" } @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判斷是否需要創建虛擬內存 +# 判斷是否需要建立虛擬記憶體 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1278,21 +1278,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 獲取nginx版本 + # 取得nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 獲取mysql版本 + # 取得mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 獲取php版本 + # 取得php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 獲取redis版本 + # 取得redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1305,18 +1305,18 @@ ldnmp_v() { install_ldnmp_conf() { - # 創建必要的目錄和文件 + # 建立必要的目錄和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf default_server_ssl - # 下載 docker-compose.yml 文件並進行替換 + # 下載 docker-compose.yml 檔案並進行替換 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中進行替換 + # 在 docker-compose.yml 檔案中進行替換 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1352,10 +1352,10 @@ update_docker_compose_with_db_creds() { auto_optimize_dns() { - # 獲取國家代碼(如 CN、US 等) + # 取得國家代碼(如 CN、US 等) local country=$(curl -s ipinfo.io/country) - # 根據國家設置 DNS + # 根據國家設定 DNS if [ "$country" = "CN" ]; then local dns1_ipv4="223.5.5.5" local dns2_ipv4="183.60.83.19" @@ -1458,10 +1458,10 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公鑰信息${gl_bai}" + echo -e "${gl_huang}$yuming公鑰資訊${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming私鑰信息${gl_bai}" + echo -e "${gl_huang}$yuming私鑰資訊${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" echo -e "${gl_huang}證書存放路徑${gl_bai}" @@ -1475,7 +1475,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1492,7 +1492,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點信息 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1531,18 +1531,18 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名證書申請成功" + send_stats "網域證書申請成功" else - send_stats "域名證書申請失敗" + send_stats "網域證書申請失敗" echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" - echo -e "1. 域名拼寫錯誤 ➠ 請檢查域名輸入是否正確" - echo -e "2. DNS解析問題 ➠ 確認域名已正確解析到本服務器IP" - echo -e "3. 網絡配置問題 ➠ 如使用Cloudflare Warp等虛擬網絡請暫時關閉" - echo -e "4. 防火牆限制 ➠ 檢查80/443端口是否開放,確保驗證可訪問" - echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/域名/週)" - echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認域名是否備案" + echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" + echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" + echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" + echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" + echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" + echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" echo "------------------------" - echo "1. 重新申請 2. 導入已有證書 0. 退出" + echo "1. 重新申請 2. 匯入已有憑證 0. 退出" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -1557,22 +1557,22 @@ certs_status() { 2) send_stats "導入已有證書" - # 定義文件路徑 + # 定義檔案路徑 local cert_file="/home/web/certs/${yuming}_cert.pem" local key_file="/home/web/certs/${yuming}_key.pem" mkdir -p /home/web/certs - # 1. 輸入證書 (ECC 和 RSA 證書開頭都是 BEGIN CERTIFICATE) - echo "請粘貼 證書 (CRT/PEM) 內容 (按兩次回車結束):" + # 1. 輸入憑證 (ECC 和 RSA 憑證開頭都是 BEGIN CERTIFICATE) + echo "請貼上 證書 (CRT/PEM) 內容 (以兩次回車結束):" local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break cert_content+="${line}"$'\n' done - # 2. 輸入私鑰 (兼容 RSA, ECC, PKCS#8) - echo "請粘貼 證書私鑰 (Private Key) 內容 (按兩次回車結束):" + # 2. 輸入私鑰 (相容 RSA, ECC, PKCS#8) + echo "請貼上 憑證私鑰 (Private Key) 內容 (按兩次回車結束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1580,7 +1580,7 @@ certs_status() { done # 3. 智能校驗 - # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通過 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可透過 if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1588,15 +1588,15 @@ certs_status() { chmod 644 "$cert_file" chmod 600 "$key_file" - # 識別當前證書類型並顯示 + # 識別目前證書類型並顯示 if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then - echo "檢測到 ECC 證書已成功保存。" + echo "偵測到 ECC 憑證已成功儲存。" else - echo "檢測到 RSA 證書已成功保存。" + echo "偵測到 RSA 憑證已成功儲存。" fi auth_method="ssl_imported" else - echo "錯誤:無效的證書或私鑰格式!" + echo "錯誤:無效的憑證或私鑰格式!" certs_status fi ;; @@ -1611,7 +1611,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重複使用" + send_stats "網域重複使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1620,8 +1620,8 @@ fi add_yuming() { ip_address - echo -e "先將域名解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "請輸入你的IP或者解析過的域名:" yuming + echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "請輸入你的IP或解析過的網域名稱:" yuming } @@ -1632,7 +1632,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "請輸入訪問/監聽端口,回車默認使用 80:" access_port + read -e -p "請輸入訪問/監聽端口,回車預設使用 80:" access_port access_port=${access_port:-80} fi } @@ -1720,7 +1720,7 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登錄信息:" + echo "登入資訊:" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo @@ -1734,29 +1734,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 檢查配置文件是否存在 + # 檢查設定檔是否存在 if [ -f "$CONFIG_FILE" ]; then - # 從配置文件讀取 API_TOKEN 和 zone_id + # 從設定檔讀取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" # 將 ZONE_IDS 轉換為數組 ZONE_IDS=($ZONE_IDS) else - # 提示用戶是否清理緩存 - read -e -p "需要清理 Cloudflare 的緩存嗎? (y/n):" answer + # 提示使用者是否清理快取 + read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以後期修改CF信息" + echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN read -e -p "請輸入你的CF用戶名:" EMAIL - read -e -p "請輸入 zone_id(多個用空格分隔):" -a ZONE_IDS + read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循環遍歷每個 zone_id 並執行清除緩存命令 + # 循環遍歷每個 zone_id 並執行清除快取命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除緩存 for zone_id:$ZONE_ID" + echo "正在清除快取 for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1764,13 +1764,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "緩存清除請求已發送完畢。" + echo "快取清除請求已發送完畢。" } web_cache() { - send_stats "清理站點緩存" + send_stats "清理網站快取" cf_purge_cache cd /home/web && docker compose restart } @@ -1782,25 +1782,25 @@ web_del() { send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "刪除站點數據,請輸入你的域名(多個域名用空格隔開):" yuming_list + read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在刪除域名:$yuming" + echo "正在刪除網域名稱:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 將域名轉換為數據庫名 + # 將網域名稱轉換為資料庫名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 刪除數據庫前檢查是否存在,避免報錯 - echo "正在刪除數據庫:$dbname" + # 刪除資料庫前檢查是否存在,避免報錯 + echo "正在刪除資料庫:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1816,7 +1816,7 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根據 mode 參數來決定開啟或關閉 WAF + # 根據 mode 參數決定開啟或關閉 WAF if [ "$mode" == "on" ]; then # 開啟 WAF:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1937,7 +1937,7 @@ patch_wp_url() { sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" - # 生成插入內容 + # 產生插入內容 INSERT=" define('WP_HOME', '$HOME_URL'); define('WP_SITEURL', '$SITE_URL'); @@ -2109,19 +2109,19 @@ web_security() { check_waf_status check_cf_mode clear - echo -e "服務器網站防禦程序${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "伺服器網站防禦程序${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" - echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" - echo "7. 查看防禦規則列表 8. 查看日誌實時監控" + echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" + echo "7. 檢視防禦規則清單 8. 查看日誌即時監控" echo "------------------------" - echo "11. 配置攔截參數 12. 清除所有拉黑的IP" + echo "11. 設定攔截參數 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. cloudflare模式 22. 高負載開啟5秒盾" + echo "21. cloudflare模式 22. 高負載開啟5秒盾" echo "------------------------" - echo "31. 開啟WAF 32. 關閉WAF" - echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" + echo "31. 開啟WAF 32. 關閉WAF" + echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" echo "------------------------" echo "9. 卸載防禦程序" echo "------------------------" @@ -2209,9 +2209,9 @@ web_security() { 21) send_stats "cloudflare模式" - echo "到cf後台右上角我的個人資料,選擇左側API令牌,獲取Global API Key" + echo "到cf後台右上角我的個人資料,選擇左側API令牌,取得Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "輸入CF的賬號:" cfuser + read -e -p "輸入CF的帳號:" cfuser read -e -p "輸入CF的Global API Key:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf @@ -2232,16 +2232,16 @@ web_security() { 22) send_stats "高負載開啟5秒盾" - echo -e "${gl_huang}網站每5分鐘自動檢測,當達檢測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" + echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" - echo "獲取CF參數:" - echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,獲取${gl_huang}Global API Key${gl_bai}" + echo "取得CF參數:" + echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "輸入CF的賬號:" cfuser + read -e -p "輸入CF的帳號:" cfuser read -e -p "輸入CF的Global API Key:" cftoken - read -e -p "輸入CF中域名的區域ID:" cfzonID + read -e -p "輸入CF中網域名稱的區域ID:" cfzonID cd ~ install jq bc @@ -2258,7 +2258,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負載自動開盾腳本已添加" + echo "高負載自動開盾腳本已新增" else echo "自動開盾腳本已存在,無需添加" fi @@ -2300,7 +2300,7 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # 檢查 MySQL 配置文件中是否包含 4096M + # 檢查 MySQL 設定檔中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="高性能模式" else @@ -2316,7 +2316,7 @@ check_nginx_compression() { local CONFIG_FILE="/home/web/nginx.conf" - # 檢查 zstd 是否開啟且未被註釋(整行以 zstd on; 開頭) + # 檢查 zstd 是否開啟且未被註解(整行以 zstd on; 開頭) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then zstd_status="zstd壓縮已開啟" else @@ -2349,11 +2349,11 @@ web_optimization() { send_stats "優化LDNMP環境" echo -e "優化LDNMP環境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 標準模式 2. 高性能模式 (推薦2H4G以上)" + echo "1. 標準模式 2. 高效能模式 (建議2H4G以上)" echo "------------------------" - echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" - echo "5. 開啟br壓縮 6. 關閉br壓縮" - echo "7. 開啟zstd壓縮 8. 關閉zstd壓縮" + echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" + echo "5. 開啟br壓縮 6. 關閉br壓縮" + echo "7. 開啟zstd壓縮 8. 關閉zstd壓縮" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -2397,11 +2397,11 @@ web_optimization() { optimize_balanced - echo "LDNMP環境已設置成 標準模式" + echo "LDNMP環境已設定成 標準模式" ;; 2) - send_stats "站點高性能模式" + send_stats "站點高效能模式" # nginx調優 local cpu_cores=$(nproc) @@ -2436,7 +2436,7 @@ web_optimization() { optimize_web_server - echo "LDNMP環境已設置成 高性能模式" + echo "LDNMP環境已設定成 高效能模式" ;; 3) @@ -2542,7 +2542,7 @@ check_docker_image_update() { local country=$(curl -s --max-time 2 ipinfo.io/country) [[ "$country" == "CN" ]] && return - # 2. 獲取本地鏡像信息 + # 2. 取得本地鏡像訊息 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return @@ -2550,17 +2550,17 @@ check_docker_image_update() { local full_image_name=$(echo "$container_info" | cut -d',' -f2) local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 智能路由判斷 + # 3. 智慧路由判斷 if [[ "$full_image_name" == ghcr.io* ]]; then # --- 場景 A: 鏡像在 GitHub (ghcr.io) --- # 提取倉庫路徑,例如 ghcr.io/onexru/oneimg -> onexru/oneimg local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注意:ghcr.io 的 API 比較複雜,通常最快的方法是查 GitHub Repo 的 Release + # 註:ghcr.io 的 API 比較複雜,通常最快的方法是查 GitHub Repo 的 Release local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想通過 GitHub Release 判斷) --- + # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想透過 GitHub Release 判斷) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2594,7 +2594,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 獲取容器的 IP 地址 + # 取得容器的 IP 位址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2604,7 +2604,7 @@ block_container_port() { install iptables - # 檢查並封禁其他所有 IP + # 檢查並封鎖其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi @@ -2614,14 +2614,14 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 檢查並放行本地網絡 127.0.0.0/8 + # 檢查並放行本地網路 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 檢查並封禁其他所有 IP + # 檢查並封鎖其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi @@ -2631,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 檢查並放行本地網絡 127.0.0.0/8 + # 檢查並放行本地網路 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2641,7 +2641,7 @@ block_container_port() { fi - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+連接埠存取該服務" save_iptables_rules } @@ -2652,7 +2652,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 獲取容器的 IP 地址 + # 取得容器的 IP 位址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2662,7 +2662,7 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的規則 + # 清除封鎖其他所有 IP 的規則 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi @@ -2672,7 +2672,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地網絡 127.0.0.0/8 的規則 + # 清除放行本地網路 127.0.0.0/8 的規則 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2681,7 +2681,7 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的規則 + # 清除封鎖其他所有 IP 的規則 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi @@ -2691,7 +2691,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地網絡 127.0.0.0/8 的規則 + # 清除放行本地網路 127.0.0.0/8 的規則 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2702,7 +2702,7 @@ clear_container_rules() { fi - echo "已允許IP+端口訪問該服務" + echo "已允許IP+連接埠存取該服務" save_iptables_rules } @@ -2716,8 +2716,8 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供端口號和允許訪問的 IP。" - echo "用法: block_host_port <端口號> <允許的IP>" + echo "錯誤:請提供連接埠號碼和允許存取的 IP。" + echo "用法: block_host_port <連接埠號碼> <允許的IP>" return 1 fi @@ -2729,7 +2729,7 @@ block_host_port() { iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允許指定 IP 訪問 + # 允許指定 IP 存取 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2748,7 +2748,7 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允許指定 IP 訪問 + # 允許指定 IP 存取 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi @@ -2758,12 +2758,12 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允許已建立和相關連接的流量 + # 允許已建立和相關連線的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+連接埠存取該服務" save_iptables_rules } @@ -2775,47 +2775,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供端口號和允許訪問的 IP。" - echo "用法: clear_host_port_rules <端口號> <允許的IP>" + echo "錯誤:請提供連接埠號碼和允許存取的 IP。" + echo "用法: clear_host_port_rules <連接埠號碼> <允許的IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 訪問的規則 + # 清除封鎖所有其他 IP 存取的規則 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允許本機訪問的規則 + # 清除允許本機存取的規則 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允許指定 IP 訪問的規則 + # 清除允許指定 IP 存取的規則 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 訪問的規則 + # 清除封鎖所有其他 IP 存取的規則 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允許本機訪問的規則 + # 清除允許本機存取的規則 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允許指定 IP 訪問的規則 + # 清除允許指定 IP 存取的規則 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允許IP+端口訪問該服務" + echo "已允許IP+連接埠存取該服務" save_iptables_rules } @@ -2874,10 +2874,10 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名訪問 6. 刪除域名訪問" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "5. 新增網域存取 6. 刪除網域存取" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -2887,12 +2887,12 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}錯誤:${gl_bai}端口$app_port已被佔用,請更換一個端口" - send_stats "應用端口已被佔用" + echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" + send_stats "應用程式連接埠已被佔用" else local docker_port=$app_port break @@ -2936,25 +2936,25 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "應用程式已解除安裝" send_stats "解除安裝$docker_name" ;; 5) - echo "${docker_name}域名訪問設置" - send_stats "${docker_name}域名訪問設置" + echo "${docker_name}域名存取設定" + send_stats "${docker_name}域名存取設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "網域格式 example.com 不含https://" web_del ;; 7) - send_stats "允許IP訪問${docker_name}" + send_stats "允許IP存取${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; @@ -2996,10 +2996,10 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名訪問 6. 刪除域名訪問" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "5. 新增網域存取 6. 刪除網域存取" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3010,12 +3010,12 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "輸入應用對外服務端口,回車默認使用${docker_port}端口:" app_port + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}錯誤:${gl_bai}端口$app_port已被佔用,請更換一個端口" - send_stats "應用端口已被佔用" + echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" + send_stats "應用程式連接埠已被佔用" else local docker_port=$app_port break @@ -3046,19 +3046,19 @@ docker_app_plus() { ;; 5) - echo "${docker_name}域名訪問設置" - send_stats "${docker_name}域名訪問設置" + echo "${docker_name}域名存取設定" + send_stats "${docker_name}域名存取設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "網域格式 example.com 不含https://" web_del ;; 7) - send_stats "允許IP訪問${docker_name}" + send_stats "允許IP存取${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) @@ -3157,7 +3157,7 @@ while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 創建新的 tmux 會話 +# 建立新的 tmux 會話 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3309,7 +3309,7 @@ clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo "nginx已安裝完成" -echo -e "當前版本:${gl_huang}v$nginx_version${gl_bai}" +echo -e "目前版本:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3344,7 +3344,7 @@ ldnmp_web_on() { echo "您的$webname搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname安裝信息如下:" + echo "$webname安裝資訊如下:" } @@ -3416,7 +3416,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="反向代理-IP+埠" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3430,7 +3430,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "請輸入你的反代IP (回車默認本機IP 127.0.0.1):" reverseproxy + read -e -p "請輸入你的反代IP (回車預設本機IP 127.0.0.1):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3472,7 +3472,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-負載均衡" + webname="反向代理-負載平衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3483,7 +3483,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "請輸入你的多個反代IP+端口用空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "請輸入你的多個反代IP+埠以空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3523,27 +3523,27 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服務名" "通信類型" "本機地址" "後端地址" + printf "%-25s %-18s %-25s %-20s\n" "服務名" "通訊類型" "本機地址" "後端地址" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return fi for conf in "$STREAM_DIR"/*; do - # 服務名取文件名 + # 服務名取檔名 service_name=$(basename "$conf" .conf) - # 獲取 upstream 塊中的 server 後端 IP:端口 + # 取得 upstream 區塊中的 server 後端 IP:端口 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) - # 獲取 listen 端口 + # 取得 listen 端口 listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) - # 默認本地 IP + # 預設本地 IP ip_address local_ip="$ipv4_address" - # 獲取通信類型,優先從文件名後綴或內容判斷 + # 取得通訊類型,優先從檔案名稱後綴或內容判斷 if grep -qi 'udp;' "$conf"; then proto="udp" else @@ -3574,17 +3574,17 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四層代理轉發工具$check_docker $update_status" - echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模塊,用於實現高性能的 傳輸層流量轉發和負載均衡。" + echo -e "Stream四層代理轉送工具$check_docker $update_status" + echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模組,用於實現高效能的 傳輸層流量轉送和負載平衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then list_stream_services fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "4. 添加轉發服務 5. 修改轉發服務 6. 刪除轉發服務" + echo "4. 新增轉送服務 5. 修改轉送服務 6. 刪除轉送服務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3617,19 +3617,19 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "添加四層代理" + send_stats "新增四層代理" ;; 5) - send_stats "編輯轉發配置" - read -e -p "請輸入你要編輯的服務名:" stream_name + send_stats "編輯轉送配置" + read -e -p "請輸入你要編輯的服務名稱:" stream_name install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx send_stats "修改四層代理" ;; 6) - send_stats "刪除轉發配置" - read -e -p "請輸入你要刪除的服務名:" stream_name + send_stats "刪除轉送配置" + read -e -p "請輸入你要刪除的服務名稱:" stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx send_stats "刪除四層代理" @@ -3646,21 +3646,21 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四層代理-負載均衡" + webname="Stream四層代理-負載平衡" send_stats "安裝$webname" echo "開始部署$webname" - # 獲取代理名稱 + # 取得代理名稱 read -erp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then echo "名稱不能為空"; return 1 fi - # 獲取監聽端口 - read -erp "請輸入本機監聽端口 (如 3306):" listen_port + # 取得監聽埠 + read -erp "請輸入本機監聽埠 (如 3306):" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then - echo "端口必須是數字"; return 1 + echo "連接埠必須是數字"; return 1 fi echo "請選擇協議類型:" @@ -3673,7 +3673,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無效選擇"; return 1 ;; esac - read -e -p "請輸入你的一個或者多個後端IP+端口用空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "請輸入你的一個或多個後端IP+埠以空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3735,7 +3735,7 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站點管理" + send_stats "LDNMP站台管理" echo "LDNMP環境" echo "------------------------" ldnmp_v @@ -3779,18 +3779,18 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo "站點目錄" + echo "網站目錄" echo "------------------------" echo -e "數據${gl_hui}/home/web/html${gl_bai}證書${gl_hui}/home/web/certs${gl_bai}配置${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "操作" echo "------------------------" - echo "1. 申請/更新域名證書 2. 克隆站點域名" - echo "3. 清理站點緩存 4. 創建關聯站點" - echo "5. 查看訪問日誌 6. 查看錯誤日誌" - echo "7. 編輯全局配置 8. 編輯站點配置" - echo "9. 管理站點數據庫 10. 查看站點分析報告" + echo "1. 申請/更新網域憑證 2. 克隆站點域名" + echo "3. 清理站點快取 4. 建立關聯站點" + echo "5. 查看訪問日誌 6. 查看錯誤日誌" + echo "7. 編輯全域配置 8. 編輯站點配置" + echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" echo "20. 刪除指定站點數據" echo "------------------------" @@ -3799,8 +3799,8 @@ ldnmp_web_status() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "申請域名證書" - read -e -p "請輸入你的域名:" yuming + send_stats "申請網域證書" + read -e -p "請輸入你的網域名稱:" yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3810,8 +3810,8 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" - read -e -p "請輸入舊域名:" oddyuming - read -e -p "請輸入新域名:" yuming + read -e -p "請輸入舊網域名稱:" oddyuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3849,10 +3849,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "創建關聯站點" - echo -e "為現有的站點再關聯一個新域名用於訪問" - read -e -p "請輸入現有的域名:" oddyuming - read -e -p "請輸入新域名:" yuming + send_stats "建立關聯站點" + echo -e "為現有的站點再關聯一個新網域用於訪問" + read -e -p "請輸入現有的網域名稱:" oddyuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3876,15 +3876,15 @@ ldnmp_web_status() { break_end ;; 7) - send_stats "編輯全局配置" + send_stats "編輯全域配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "編輯站點配置" - read -e -p "編輯站點配置,請輸入你要編輯的域名:" yuming + send_stats "編輯網站配置" + read -e -p "編輯網站配置,請輸入你要編輯的網域:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3894,7 +3894,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站點數據" + send_stats "查看網站數據" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3930,12 +3930,12 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款時下流行且強大的運維管理面板。" + echo "${panelname}是一款時下流行且強大的維運管理面板。" echo "官網介紹:$panelurl " echo "" echo "------------------------" - echo "1. 安裝 2. 管理 3. 卸載" + echo "1. 安裝 2. 管理 3. 卸載" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4006,7 +4006,7 @@ donlond_frp() { generate_frps_config() { send_stats "安裝frp服務端" - # 生成隨機端口和憑證 + # 產生隨機連接埠和憑證 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -4027,16 +4027,16 @@ EOF donlond_frp frps - # 輸出生成的信息 + # 輸出產生的信息 ip_address echo "------------------------" - echo "客戶端部署時需要用的參數" + echo "客戶端部署時所需使用的參數" echo "服務IP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用戶名:$dashboard_user" + echo "FRP面板資訊" + echo "FRP面板位址: http://$ipv4_address:$dashboard_port" + echo "FRP面板使用者名稱:$dashboard_user" echo "FRP面板密碼:$dashboard_pwd" echo @@ -4069,17 +4069,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp內網服務" - # 提示用戶輸入服務名稱和轉發信息 + send_stats "新增frp內網服務" + # 提示使用者輸入服務名稱和轉發訊息 read -e -p "請輸入服務名稱:" service_name - read -e -p "請輸入轉發類型 (tcp/udp) [回​​車默認tcp]:" service_type + read -e -p "請輸入轉送類型 (tcp/udp) [回​​車預設tcp]:" service_type local service_type=${service_type:-tcp} - read -e -p "請輸入內網IP [回車默認127.0.0.1]:" local_ip + read -e -p "請輸入內網IP [回車預設127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "請輸入內網端口:" local_port - read -e -p "請輸入外網端口:" remote_port + read -e -p "請輸入內部網路連接埠:" local_port + read -e -p "請輸入外網埠:" remote_port - # 將用戶輸入寫入配置文件 + # 將使用者輸入寫入設定檔 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -4089,8 +4089,8 @@ remote_port = ${remote_port} EOF - # 輸出生成的信息 - echo "服務$service_name已成功添加到 frpc.toml" + # 輸出產生的信息 + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4102,7 +4102,7 @@ EOF delete_forwarding_service() { send_stats "刪除frp內網服務" - # 提示用戶輸入需要刪除的服務名稱 + # 提示使用者輸入需要刪除的服務名稱 read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml @@ -4116,8 +4116,8 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表頭 - printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內網地址" "外網地址" "協定" + # 列印表頭 + printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" awk ' BEGIN { @@ -4137,7 +4137,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服務信息,在處理新服務之前打印當前服務 + # 如果已有服務訊息,在處理新服務之前列印目前服務 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4146,7 +4146,7 @@ list_forwarding_services() { type } - # 更新當前服務名稱 + # 更新目前服務名稱 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -4179,7 +4179,7 @@ list_forwarding_services() { } END { - # 打印最後一個服務的信息 + # 列印最後一個服務的訊息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4192,14 +4192,14 @@ list_forwarding_services() { -# 獲取 FRP 服務端端口 +# 取得 FRP 服務端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成訪問地址 +# 產生訪問地址 generate_access_urls() { - # 首先獲取所有端口 + # 首先獲取所有連接埠 get_frp_ports # 檢查是否有非 8055/8056 的端口 @@ -4211,18 +4211,18 @@ generate_access_urls() { fi done - # 只在有有效端口時顯示標題和內容 + # 只在有有效連接埠時顯示標題和內容 if [ "$has_valid_ports" = true ]; then - echo "FRP服務對外訪問地址:" + echo "FRP服務對外存取位址:" - # 處理 IPv4 地址 + # 處理 IPv4 位址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 處理 IPv6 地址(如果存在) + # 處理 IPv6 位址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4267,22 +4267,22 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP服務端$check_frp $update_status" - echo "構建FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" + echo "建構FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 內網服務域名訪問 6. 刪除域名訪問" + echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" - echo "7. 允許IP+端口訪問 8. 阻止IP+端口訪問" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" - echo "00. 刷新服務狀態 0. 返回上一級選單" + echo "00. 刷新服務狀態 0. 返回上一級選單" echo "------------------------" read -e -p "輸入你的選擇:" choice case $choice in @@ -4313,36 +4313,36 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "應用程式已解除安裝" ;; 5) echo "將內網穿透服務反代成域名訪問" send_stats "FRP對外域名訪問" add_yuming - read -e -p "請輸入你的內網穿透服務端口:" frps_port + read -e -p "請輸入你的內部網路穿透服務埠:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不帶https://" + echo "網域格式 example.com 不含https://" web_del ;; 7) - send_stats "允許IP訪問" - read -e -p "請輸入需要放行的端口:" frps_port + send_stats "允許IP存取" + read -e -p "請輸入需要放行的連接埠:" frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) send_stats "阻止IP訪問" echo "如果你已經反代域名訪問了,可用此功能阻止IP+端口訪問,這樣更安全。" - read -e -p "請輸入需要阻止的端口:" frps_port + read -e -p "請輸入需要阻止的連接埠:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服務狀態" + send_stats "重新整理FRP服務狀態" echo "已經刷新FRP服務狀態" ;; @@ -4365,9 +4365,9 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP客戶端$check_frp $update_status" - echo "與服務端對接,對接後可創建內網穿透服務到互聯網訪問" + echo "與服務端對接,對接後可建立內網穿透服務到網際網路存取" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "視頻教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -4375,9 +4375,9 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "4. 添加對外服務 5. 刪除對外服務 6. 手動配置服務" + echo "4. 新增對外服務 5. 刪除對外服務 6. 手動設定服務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4410,7 +4410,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "應用程式已解除安裝" ;; 4) @@ -4458,16 +4458,16 @@ yt_menu_pro() { clear send_stats "yt-dlp 下載工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一個功能強大的視頻下載工具,支持 YouTube、Bilibili、Twitter 等數千站點。" - echo -e "官網地址:${gh_https_url}github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一個功能強大的影片下載工具,支援 YouTube、Bilibili、Twitter 等數千網站。" + echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下載視頻列表:" + echo "已下載影片清單:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" - echo "5. 單個視頻下載 6. 批量視頻下載 7. 自定義參數下載" - echo "8. 下載為MP3音頻 9. 刪除視頻目錄 10. Cookie管理(開發中)" + echo "5. 單一影片下載 6. 大量影片下載 7. 自訂參數下載" + echo "8. 下載為MP3音訊 9.刪除影片目錄 10. Cookie管理(開發中)" echo "-------------------------" echo "0. 返回上一級選單" echo "-------------------------" @@ -4501,20 +4501,20 @@ yt_menu_pro() { echo "卸載完成。按任意鍵繼續..." read ;; 5) - send_stats "單個視頻下載" - read -e -p "請輸入視頻鏈接:" url + send_stats "單一影片下載" + read -e -p "請輸入影片連結:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下載完成,按任意鍵繼續..." ;; + read -e -p "下載完成,按任何鍵繼續..." ;; 6) - send_stats "批量視頻下載" + send_stats "大量影片下載" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 輸入多個視頻鏈接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 輸入多個視訊連結位址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE echo "現在開始批量下載..." @@ -4525,9 +4525,9 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下載完成,按任意鍵繼續..." ;; + read -e -p "批次下載完成,按任何鍵繼續..." ;; 7) - send_stats "自定義視頻下載" + send_stats "自訂影片下載" read -e -p "請輸入完整 yt-dlp 參數(不含 yt-dlp):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ @@ -4538,18 +4538,18 @@ yt_menu_pro() { read -e -p "執行完成,按任意鍵繼續..." ;; 8) send_stats "MP3下載" - read -e -p "請輸入視頻鏈接:" url + read -e -p "請輸入影片連結:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音頻下載完成,按任意鍵繼續..." ;; + read -e -p "音訊下載完成,按任意鍵繼續..." ;; 9) - send_stats "刪除視頻" - read -e -p "請輸入刪除視頻名稱:" rmdir + send_stats "刪除影片" + read -e -p "請輸入刪除影片名稱:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4613,7 +4613,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "未知的套件管理器!" return fi } @@ -4650,13 +4650,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器緩存..." + echo "清理包管理器快取..." apk cache clean echo "刪除系統日誌..." rm -rf /var/log/* - echo "刪除APK緩存..." + echo "刪除APK快取..." rm -rf /var/cache/apk/* - echo "刪除臨時文件..." + echo "刪除臨時檔案..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4676,21 +4676,21 @@ linux_clean() { elif command -v opkg &>/dev/null; then echo "刪除系統日誌..." rm -rf /var/log/* - echo "刪除臨時文件..." + echo "刪除臨時檔案..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then echo "清理未使用的依賴..." pkg autoremove -y - echo "清理包管理器緩存..." + echo "清理包管理器快取..." pkg clean -y echo "刪除系統日誌..." rm -rf /var/log/* - echo "刪除臨時文件..." + echo "刪除臨時檔案..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "未知的套件管理器!" return fi return @@ -4739,9 +4739,9 @@ root_use send_stats "優化DNS" while true; do clear - echo "優化DNS地址" + echo "優化DNS位址" echo "------------------------" - echo "當前DNS地址" + echo "目前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" @@ -4832,7 +4832,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改為:$new_port" + echo "SSH 連接埠已修改為:$new_port" sleep 1 @@ -4848,7 +4848,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}用戶密鑰登錄模式已開啟,已關閉密碼登錄模式,重連將會生效${gl_bai}" + echo -e "${gl_lv}使用者金鑰登入模式已開啟,已關閉密碼登入模式,重連將會生效${gl_bai}" } @@ -4866,7 +4866,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰信息已生成,務必復制保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -4928,25 +4928,25 @@ fetch_remote_ssh_keys() { read -e -p "請輸入您的遠端公鑰URL:" keys_url fi - echo "此腳本將從遠程 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" + echo "此腳本將從遠端 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" echo "" - echo "遠程公鑰地址:" + echo "遠端公鑰地址:" echo " ${keys_url}" echo "" - # 創建臨時文件 + # 建立臨時文件 temp_file=$(mktemp) # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "錯誤:無法從 URL 下載公鑰(網絡問題或地址無效)" >&2 + echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "錯誤:無法從 URL 下載公鑰(網絡問題或地址無效)" >&2 + echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 rm -f "${temp_file}" return 1 } @@ -4958,7 +4958,7 @@ fetch_remote_ssh_keys() { # 檢查內容是否有效 if [[ ! -s "${temp_file}" ]]; then - echo "錯誤:下載到的文件為空,URL 可能不包含任何公鑰" >&2 + echo "錯誤:下載到的檔案為空,URL 可能不包含任何公鑰" >&2 rm -f "${temp_file}" return 1 fi @@ -5006,24 +5006,24 @@ fetch_github_ssh_keys() { local username="$1" local base_dir="${2:-$HOME}" - echo "操作前,請確保您已在 GitHub 賬戶中添加了 SSH 公鑰:" - echo "1. 登錄${gh_https_url}github.com/settings/keys" - echo "2. 點擊 New SSH key 或 Add SSH key" + echo "操作前,請確保您已在 GitHub 帳戶中新增了 SSH 公鑰:" + echo "1. 登入${gh_https_url}github.com/settings/keys" + echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" - echo "4. 將本地公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)粘貼到 Key 字段" - echo "5. 點擊 Add SSH key 完成添加" + echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" + echo "5. 點選 Add SSH key 完成新增" echo "" - echo "添加完成後,GitHub 會公開提供您的所有公鑰,地址為:" - echo " ${gh_https_url}github.com/您的用戶名.keys" + echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" + echo " ${gh_https_url}github.com/您的使用者名稱.keys" echo "" if [[ -z "${username}" ]]; then - read -e -p "請輸入您的 GitHub 用戶名(username,不含 @):" username + read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username fi if [[ -z "${username}" ]]; then - echo "錯誤:GitHub 用戶名不能為空" >&2 + echo "錯誤:GitHub 使用者名稱不能為空" >&2 return 1 fi @@ -5036,7 +5036,7 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "用戶密鑰登錄" + send_stats "用户密钥登录" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5045,21 +5045,21 @@ sshkey_panel() { else IS_KEY_ENABLED="${gl_hui}未啟用${gl_bai}" fi - echo -e "用戶密鑰登錄模式${IS_KEY_ENABLED}" + echo -e "使用者密鑰登入模式${IS_KEY_ENABLED}" echo "進階玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "將會生成密鑰對,更安全的方式SSH登錄" + echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 生成新密鑰對 2. 手動輸入已有公鑰" - echo "3. 從GitHub導入已有公鑰 4. 從URL導入已有公鑰" - echo "5. 編輯公鑰文件 6. 查看本機密鑰" + echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" + echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" + echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" read -e -p "請輸入你的選擇:" host_dns case $host_dns in 1) - send_stats "生成新密鑰" + send_stats "產生新密鑰" add_sshkey break_end ;; @@ -5090,10 +5090,10 @@ sshkey_panel() { 6) send_stats "查看本機密鑰" echo "------------------------" - echo "公鑰信息" + echo "公鑰資訊" cat ${HOME}/.ssh/authorized_keys echo "------------------------" - echo "私鑰信息" + echo "私鑰資訊" cat ${HOME}/.ssh/sshkey echo "------------------------" break_end @@ -5115,17 +5115,17 @@ sshkey_panel() { add_sshpasswd() { root_use - send_stats "設置密碼登錄模式" - echo "設置密碼登錄模式" + send_stats "設定密碼登入模式" + echo "設定密碼登入模式" local target_user="$1" - # 如果沒有通過參數傳入,則交互輸入 + # 如果沒有透過參數傳入,則交互輸入 if [[ -z "$target_user" ]]; then - read -e -p "請輸入要修改密碼的用戶名(默認 root):" target_user + read -e -p "請輸入要修改密碼的使用者名稱(預設 root):" target_user fi - # 回車不輸入,默認 root + # 回車不輸入,預設 root target_user=${target_user:-root} # 校驗用戶是否存在 @@ -5145,7 +5145,7 @@ add_sshpasswd() { restart_ssh - echo -e "${gl_lv}密碼設置完畢,已更改為密碼登錄模式!${gl_bai}" + echo -e "${gl_lv}密碼設定完畢,已更改為密碼登入模式!${gl_bai}" } @@ -5163,7 +5163,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示:${gl_bai}該功能需要root用戶才能運行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示:${gl_bai}該功能需要root用戶才能運作!" && break_end && kejilion } @@ -5189,8 +5189,8 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始端口:${gl_huang}22${gl_bai}" - echo -e "${gl_huang}重裝後請及時修改初始密碼,防止暴力入侵。命令行輸入passwd修改密碼${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -5198,7 +5198,7 @@ dd_xitong() { } dd_xitong_2() { - echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai}初始端口:${gl_huang}3389${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai}初始連接埠:${gl_huang}3389${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -5206,14 +5206,14 @@ dd_xitong() { } dd_xitong_3() { - echo -e "重裝後初始用戶名:${gl_huang}root${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}22${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重裝後初始用戶名:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始端口:${gl_huang}3389${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}123@@@${gl_bai}初始連接埠:${gl_huang}3389${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" dd_xitong_bin456789 @@ -5223,10 +5223,10 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro項目地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5242,7 +5242,7 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" + echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" @@ -5522,12 +5522,12 @@ bbrv3() { clear local kernel_version=$(uname -r) echo "您已安裝xanmod的BBRv3內核" - echo "當前內核版本:$kernel_version" + echo "當前核心版本:$kernel_version" echo "" - echo "內核管理" + echo "核心管理" echo "------------------------" - echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" + echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5541,7 +5541,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步驟3:添加存儲庫 + # 步驟3:新增儲存庫 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5550,7 +5550,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod內核已更新。重啟後生效" + echo "XanMod核心已更新。重啟後生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5560,7 +5560,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod內核已卸載。重啟後生效" + echo "XanMod核心已卸載。重啟後生效" server_reboot ;; @@ -5573,11 +5573,11 @@ bbrv3() { else clear - echo "設置BBR3加速" - echo "視頻介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "設定BBR3加速" + echo "影片介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "僅支持Debian/Ubuntu" - echo "請備份數據,將為你升級Linux內核開啟BBR3" + echo "僅支援Debian/Ubuntu" + echo "請備份數據,將為你升級Linux核心開啟BBR3" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -5587,12 +5587,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "當前環境不支持,僅支持Debian和Ubuntu系統" + echo "目前環境不支持,僅支援Debian和Ubuntu系統" break_end linux_Settings fi else - echo "無法確定操作系統類型" + echo "無法確定作業系統類型" break_end linux_Settings fi @@ -5603,7 +5603,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步驟3:添加存儲庫 + # 步驟3:新增儲存庫 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5614,7 +5614,7 @@ bbrv3() { bbr_on - echo "XanMod內核安裝並BBR3啟用成功。重啟後生效" + echo "XanMod核心安裝並BBR3啟用成功。重啟後生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5639,34 +5639,34 @@ elrepo_install() { # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 確保我們在一個支持的操作系統上運行 + # 確保我們在一個支援的作業系統上運行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系統:$os_name" + echo "不支援的作業系統:$os_name" break_end linux_Settings fi - # 打印檢測到的操作系統信息 - echo "檢測到的操作系統:$os_name $os_version" + # 列印偵測到的作業系統訊息 + echo "偵測到的作業系統:$os_name $os_version" # 根據系統版本安裝對應的 ELRepo 倉庫配置 if [[ "$os_version" == 8 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 8)..." + echo "安裝 ELRepo 倉庫設定 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 9)..." + echo "安裝 ELRepo 倉庫設定 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安裝 ELRepo 倉庫配置 (版本 10)..." + echo "安裝 ELRepo 倉庫設定 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系統版本:$os_version" + echo "不支援的系統版本:$os_version" break_end linux_Settings fi # 啟用 ELRepo 內核倉庫並安裝最新的主線內核 - echo "啟用 ELRepo 內核倉庫並安裝最新的主線內核..." + echo "啟用 ELRepo 核心倉庫並安裝最新的主線核心..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安裝 ELRepo 倉庫配置並更新到最新主線內核。" + echo "已安裝 ELRepo 倉庫配置並更新至最新主線核心。" server_reboot } @@ -5680,12 +5680,12 @@ elrepo() { clear kernel_version=$(uname -r) echo "您已安裝elrepo內核" - echo "當前內核版本:$kernel_version" + echo "當前核心版本:$kernel_version" echo "" - echo "內核管理" + echo "核心管理" echo "------------------------" - echo "1. 更新elrepo內核 2. 卸載elrepo內核" + echo "1. 更新elrepo內核 2. 卸載elrepo內核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5703,8 +5703,8 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo內核已卸載。重啟後生效" - send_stats "卸載紅帽內核" + echo "elrepo核心已卸載。重啟後生效" + send_stats "解除安裝紅帽內核" server_reboot ;; @@ -5718,10 +5718,10 @@ elrepo() { clear echo "請備份數據,將為你升級Linux內核" - echo "視頻介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "影片介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "僅支持紅帽系列發行版 CentOS/RedHat/Alma/Rocky/oracle" - echo "升級Linux內核可提升系統性能和安全,建議有條件的嘗試,生產環境謹慎升級!" + echo "僅支援紅帽系列發行 CentOS/RedHat/Alma/Rocky/oracle" + echo "升級Linux核心可提升系統效能與安全,建議有條件的嘗試,生產環境謹慎升級!" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -5763,13 +5763,13 @@ clamav_scan() { echo -e "${gl_kjlan}正在掃描目錄$@...${gl_bai}" - # 構建 mount 參數 + # 建構 mount 參數 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 構建 clamscan 命令參數 + # 建構 clamscan 指令參數 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5788,7 +5788,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜索FOUND關鍵字確認病毒位置${gl_bai}" + echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜尋FOUND關鍵字確認病毒位置${gl_bai}" } @@ -5804,19 +5804,19 @@ clamav() { while true; do clear echo "clamav病毒掃描工具" - echo "視頻介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "影片介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "是一個開源的防病毒軟件工具,主要用於檢測和刪除各種類型的惡意軟件。" - echo "包括病毒、特洛伊木馬、間諜軟件、惡意腳本和其他有害軟件。" + echo "是一個開源的防毒軟體工具,主要用於偵測和刪除各種類型的惡意軟體。" + echo "包括病毒、木馬、間諜軟體、惡意腳本和其他有害軟體。" echo "------------------------" - echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自定義目錄掃描${gl_bai}" + echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自訂目錄掃描${gl_bai}" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "全盤掃描" + send_stats "全碟掃描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5833,7 +5833,7 @@ clamav() { break_end ;; 3) - send_stats "自定義目錄掃描" + send_stats "自訂目錄掃描" read -e -p "請輸入要掃描的目錄,用空格分隔(例如:/etc /var /usr /home /root):" directories install_docker clamav_freshclam @@ -5851,21 +5851,21 @@ clamav() { -# 高性能模式優化函數 +# 高效能模式最佳化函數 optimize_high_performance() { echo -e "${gl_lv}切換到${tiaoyou_moshi}...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化檔案描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=15 2>/dev/null sysctl -w vm.dirty_background_ratio=5 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}優化網路設定...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null @@ -5877,10 +5877,10 @@ optimize_high_performance() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}優化快取管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}優化CPU設定...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}其他優化...${gl_bai}" @@ -5892,21 +5892,21 @@ optimize_high_performance() { } -# 均衡模式優化函數 +# 均衡模式最佳化函數 optimize_balanced() { echo -e "${gl_lv}切換到均衡模式...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化檔案描述符...${gl_bai}" ulimit -n 32768 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" sysctl -w vm.swappiness=30 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=32768 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}優化網路設定...${gl_bai}" sysctl -w net.core.rmem_max=8388608 2>/dev/null sysctl -w net.core.wmem_max=8388608 2>/dev/null sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null @@ -5918,10 +5918,10 @@ optimize_balanced() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}優化快取管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}優化CPU設定...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}其他優化...${gl_bai}" @@ -5933,21 +5933,21 @@ optimize_balanced() { } -# 還原默認設置函數 +# 還原預設設定函數 restore_defaults() { - echo -e "${gl_lv}還原到默認設置...${gl_bai}" + echo -e "${gl_lv}還原到預設值...${gl_bai}" - echo -e "${gl_lv}還原文件描述符...${gl_bai}" + echo -e "${gl_lv}還原檔案描述符...${gl_bai}" ulimit -n 1024 - echo -e "${gl_lv}還原虛擬內存...${gl_bai}" + echo -e "${gl_lv}還原虛擬記憶體...${gl_bai}" sysctl -w vm.swappiness=60 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=0 2>/dev/null sysctl -w vm.min_free_kbytes=16384 2>/dev/null - echo -e "${gl_lv}還原網絡設置...${gl_bai}" + echo -e "${gl_lv}還原網路設定...${gl_bai}" sysctl -w net.core.rmem_max=212992 2>/dev/null sysctl -w net.core.wmem_max=212992 2>/dev/null sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null @@ -5959,10 +5959,10 @@ restore_defaults() { sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - echo -e "${gl_lv}還原緩存管理...${gl_bai}" + echo -e "${gl_lv}還原快取管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - echo -e "${gl_lv}還原CPU設置...${gl_bai}" + echo -e "${gl_lv}還原CPU設定...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null echo -e "${gl_lv}還原其他優化...${gl_bai}" @@ -5975,21 +5975,21 @@ restore_defaults() { -# 網站搭建優化函數 +# 網站建置優化函數 optimize_web_server() { - echo -e "${gl_lv}切換到網站搭建優化模式...${gl_bai}" + echo -e "${gl_lv}切換到網站建置優化模式...${gl_bai}" - echo -e "${gl_lv}優化文件描述符...${gl_bai}" + echo -e "${gl_lv}優化檔案描述符...${gl_bai}" ulimit -n 65535 - echo -e "${gl_lv}優化虛擬內存...${gl_bai}" + echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" sysctl -w vm.swappiness=10 2>/dev/null sysctl -w vm.dirty_ratio=20 2>/dev/null sysctl -w vm.dirty_background_ratio=10 2>/dev/null sysctl -w vm.overcommit_memory=1 2>/dev/null sysctl -w vm.min_free_kbytes=65536 2>/dev/null - echo -e "${gl_lv}優化網絡設置...${gl_bai}" + echo -e "${gl_lv}優化網路設定...${gl_bai}" sysctl -w net.core.rmem_max=16777216 2>/dev/null sysctl -w net.core.wmem_max=16777216 2>/dev/null sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null @@ -6001,10 +6001,10 @@ optimize_web_server() { sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - echo -e "${gl_lv}優化緩存管理...${gl_bai}" + echo -e "${gl_lv}優化快取管理...${gl_bai}" sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - echo -e "${gl_lv}優化CPU設置...${gl_bai}" + echo -e "${gl_lv}優化CPU設定...${gl_bai}" sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null echo -e "${gl_lv}其他優化...${gl_bai}" @@ -6021,19 +6021,19 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux內核調優管理" - echo "Linux系統內核參數優化" - echo "視頻介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + send_stats "Linux核心調優管理" + echo "Linux系統核心參數優化" + echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多種系統參數調優模式,用戶可以根據自身使用場景進行選擇切換。" + echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo "--------------------" - echo "1. 高性能優化模式: 最大化系統性能,優化文件描述符、虛擬內存、網絡設置、緩存管理和CPU設置。" - echo "2. 均衡優化模式: 在性能與資源消耗之間取得平衡,適合日常使用。" - echo "3. 網站優化模式: 針對網站服務器進行優化,提高並發連接處理能力、響應速度和整體性能。" - echo "4. 直播優化模式: 針對直播推流的特殊需求進行優化,減少延遲,提高傳輸性能。" - echo "5. 遊戲服優化模式: 針對遊戲服務器進行優化,提高並發處理能力和響應速度。" - echo "6. 還原默認設置: 將系統設置還原為默認配置。" + echo "1. 高效能最佳化模式: 最大化系統效能,最佳化檔案描述符、虛擬記憶體、網路設定、快取管理和CPU設定。" + echo "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" + echo "3. 網站最佳化模式: 針對網站伺服器進行最佳化,提升並發連線處理能力、回應速度及整體效能。" + echo "4. 直播最佳化模式: 針對直播推流的特殊需求進行最佳化,減少延遲,提升傳輸效能。" + echo "5. 遊戲服最佳化模式: 針對遊戲伺服器進行最佳化,提升並發處理能力與回應速度。" + echo "6. 還原預設設定: 將系統設定還原為預設配置。" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -6042,15 +6042,15 @@ Kernel_optimize() { 1) cd ~ clear - local tiaoyou_moshi="高性能優化模式" + local tiaoyou_moshi="高效能最佳化模式" optimize_high_performance - send_stats "高性能模式優化" + send_stats "高性能模式最​​佳化" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式優化" + send_stats "均衡模式最佳化" ;; 3) cd ~ @@ -6076,7 +6076,7 @@ Kernel_optimize() { cd ~ clear restore_defaults - send_stats "還原默認設置" + send_stats "還原預設設定" ;; *) break @@ -6103,7 +6103,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" hash -r break_end @@ -6112,17 +6112,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系統語言已經修改為:$lang重新連接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系統:$ID" + echo "不支援的系統:$ID" break_end ;; esac else - echo "不支持的系統,無法識別系統類型。" + echo "不支援的系統,無法辨識系統類型。" break_end fi } @@ -6137,7 +6137,7 @@ while true; do clear echo "當前系統語言:$LANG" echo "------------------------" - echo "1. 英文 2. 簡體中文 3. 繁體中文" + echo "1. 英文 2. 簡體中文 3. 繁體中文" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6187,10 +6187,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "命令列美化工具" while true; do clear - echo "命令行美化工具" + echo "命令列美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -6262,13 +6262,13 @@ linux_trash() { fi clear - echo -e "當前回收站${trash_status}" - echo -e "啟用後rm刪除的文件先進入回收站,防止誤刪重要文件!" + echo -e "目前回收站${trash_status}" + echo -e "啟用後rm刪除的檔案先進入回收站,防止誤刪重要檔案!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站為空" echo "------------------------" - echo "1. 啟用回收站 2. 關閉回收站" - echo "3. 還原內容 4. 清空回收站" + echo "1. 啟用回收站 2. 關閉回收站" + echo "3. 還原內容 4. 清空回收站" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6280,7 +6280,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已啟用,刪除的文件將移至回收站。" + echo "回收站已啟用,刪除的檔案將移至回收站。" sleep 2 ;; 2) @@ -6288,11 +6288,11 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已關閉,文件將直接刪除。" + echo "回收站已關閉,檔案將直接刪除。" sleep 2 ;; 3) - read -e -p "輸入要還原的文件名:" file_to_restore + read -e -p "輸入要還原的檔名:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" echo "$file_to_restore已還原到主目錄。" @@ -6319,19 +6319,19 @@ send_stats "命令收藏夾" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 創建備份 +# 建立備份 create_backup() { - send_stats "創建備份" + send_stats "建立備份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用戶輸入備份目錄 - echo "創建備份示例:" - echo "- 備份單個目錄: /var/www" + # 提示使用者輸入備份目錄 + echo "建立備份範例:" + echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" - echo "- 直接回車將使用默認目錄 (/etc /usr /home)" - read -e -p "請輸入要備份的目錄(多個目錄用空格分隔,直接回車則使用默認目錄):" input + echo "- 直接回車將使用預設目錄 (/etc /usr /home)" + read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input - # 如果用戶沒有輸入目錄,則使用默認目錄 + # 如果使用者沒有輸入目錄,則使用預設目錄 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6339,11 +6339,11 @@ create_backup() { "/home" # 用户数据 ) else - # 將用戶輸入的目錄按空格分隔成數組 + # 將使用者輸入的目錄以空格分隔成數組 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成備份文件前綴 + # 產生備份檔案前綴 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do # 提取目錄名稱並去除斜杠 @@ -6351,28 +6351,28 @@ create_backup() { PREFIX+="${dir_name}_" done - # 去除最後一個下劃線 + # 去除最後一條底線 local PREFIX=${PREFIX%_} - # 生成備份文件名 + # 產生備份檔名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用戶選擇的目錄 + # 列印使用者選擇的目錄 echo "您選擇的備份目錄為:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 創建備份 - echo "正在創建備份$BACKUP_NAME..." + # 建立備份 + echo "正在建立備份$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" # 檢查命令是否成功 if [ $? -eq 0 ]; then - echo "備份創建成功:$BACKUP_DIR/$BACKUP_NAME" + echo "備份建立成功:$BACKUP_DIR/$BACKUP_NAME" else - echo "備份創建失敗!" + echo "備份建立失敗!" exit 1 fi } @@ -6380,12 +6380,12 @@ create_backup() { # 恢復備份 restore_backup() { send_stats "恢復備份" - # 選擇要恢復的備份 - read -e -p "請輸入要恢復的備份文件名:" BACKUP_NAME + # 選擇要還原的備份 + read -e -p "請輸入要還原的備份檔名:" BACKUP_NAME - # 檢查備份文件是否存在 + # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "備份文件不存在!" + echo "備份檔案不存在!" exit 1 fi @@ -6410,11 +6410,11 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "請輸入要刪除的備份文件名:" BACKUP_NAME + read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME - # 檢查備份文件是否存在 + # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "備份文件不存在!" + echo "備份檔案不存在!" exit 1 fi @@ -6429,7 +6429,7 @@ delete_backup() { fi } -# 備份主菜單 +# 備份主選單 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" @@ -6440,7 +6440,7 @@ linux_backup() { echo "------------------------" list_backups echo "------------------------" - echo "1. 創建備份 2. 恢復備份 3. 刪除備份" + echo "1. 建立備份 2. 恢復備份 3. 刪除備份" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6451,7 +6451,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按下回車鍵繼續..." done } @@ -6463,29 +6463,29 @@ linux_backup() { -# 顯示連接列表 +# 顯示連線清單 list_connections() { - echo "已保存的連接:" + echo "已儲存的連線:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新連接 +# 新增連接 add_connection() { - send_stats "添加新連接" - echo "創建新連接示例:" - echo "- 連接名稱: my_server" - echo "- IP地址: 192.168.1.100" - echo "- 用戶名: root" - echo "- 端口: 22" + send_stats "新增連接" + echo "建立新連接範例:" + echo "- 連線名稱: my_server" + echo "- IP位址: 192.168.1.100" + echo "- 使用者名稱: root" + echo "- 連接埠: 22" echo "------------------------" - read -e -p "請輸入連接名稱:" name - read -e -p "請輸入IP地址:" ip - read -e -p "請輸入用戶名 (默認: root):" user + read -e -p "請輸入連線名稱:" name + read -e -p "請輸入IP位址:" ip + read -e -p "請輸入使用者名稱 (預設: root):" user local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "請輸入端口號 (默認: 22):" port + read -e -p "請輸入連接埠號碼 (預設: 22):" port local port=${port:-22} # 如果用户未输入,则使用默认值 22 echo "請選擇身份驗證方式:" @@ -6499,20 +6499,20 @@ add_connection() { echo # 换行 ;; 2) - echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" + echo "請貼上金鑰內容 (貼上完成後按兩次回車):" local password_or_key="" while IFS= read -r line; do - # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 + # 如果輸入為空白行且金鑰內容已經包含了開頭,則結束輸入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 + # 如果是第一行或已經開始輸入金鑰內容,則繼續新增 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi done - # 檢查是否是密鑰內容 + # 檢查是否為密鑰內容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/$name.key" echo -n "$password_or_key" > "$key_file" @@ -6527,7 +6527,7 @@ add_connection() { esac echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" - echo "連接已保存!" + echo "連線已儲存!" } @@ -6539,7 +6539,7 @@ delete_connection() { local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "錯誤:未找到對應的連接。" + echo "錯誤:未找到對應的連線。" return fi @@ -6551,7 +6551,7 @@ delete_connection() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "連接已刪除!" + echo "連線已刪除!" } # 使用連接 @@ -6561,7 +6561,7 @@ use_connection() { local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "錯誤:未找到對應的連接。" + echo "錯誤:未找到對應的連線。" return fi @@ -6572,10 +6572,10 @@ use_connection() { # 使用密鑰連接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "連接失敗!請檢查以下內容:" - echo "1. 密鑰文件路徑是否正確:$password_or_key" - echo "2. 密鑰文件權限是否正確(應為 600)。" - echo "3. 目標服務器是否允許使用密鑰登錄。" + echo "連線失敗!請檢查以下內容:" + echo "1. 密鑰檔案路徑是否正確:$password_or_key" + echo "2. 密鑰檔案權限是否正確(應為 600)。" + echo "3. 目標伺服器是否允許使用金鑰登入。" fi else # 使用密碼連接 @@ -6588,22 +6588,22 @@ use_connection() { fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "連接失敗!請檢查以下內容:" - echo "1. 用戶名和密碼是否正確。" - echo "2. 目標服務器是否允許密碼登錄。" - echo "3. 目標服務器的 SSH 服務是否正常運行。" + echo "連線失敗!請檢查以下內容:" + echo "1. 使用者名稱和密碼是否正確。" + echo "2. 目標伺服器是否允許密碼登入。" + echo "3. 目標伺服器的 SSH 服務是否正常運作。" fi fi } ssh_manager() { - send_stats "ssh遠程連接工具" + send_stats "ssh遠端連線工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 檢查配置文件和密鑰目錄是否存在,如果不存在則創建 + # 檢查設定檔和金鑰目錄是否存在,如果不存在則創建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -6615,11 +6615,11 @@ ssh_manager() { while true; do clear - echo "SSH 遠程連接工具" - echo "可以通過SSH連接到其他Linux系統上" + echo "SSH 遠端連線工具" + echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections - echo "1. 創建新連接 2. 使用連接 3. 刪除連接" + echo "1. 建立新連接 2. 使用連接 3. 刪除連接" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6645,22 +6645,22 @@ ssh_manager() { -# 列出可用的硬盤分區 +# 列出可用的硬碟分割區 list_partitions() { - echo "可用的硬盤分區:" + echo "可用的硬碟分割區:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } # 持久化掛載分區 mount_partition() { - send_stats "掛載分區" - read -e -p "請輸入要掛載的分區名稱(例如 sda1):" PARTITION + send_stats "掛載分割區" + read -e -p "請輸入要掛載的分割區名稱(例如 sda1):" PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" - # 檢查分區是否存在 + # 檢查分割區是否存在 if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "分區不存在!" return 1 @@ -6672,21 +6672,21 @@ mount_partition() { return 1 fi - # 獲取 UUID + # 取得 UUID UUID=$(blkid -s UUID -o value "$DEVICE") if [ -z "$UUID" ]; then - echo "無法獲取 UUID!" + echo "無法取得 UUID!" return 1 fi - # 獲取文件系統類型 + # 取得檔案系統類型 FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then - echo "無法獲取文件系統類型!" + echo "無法取得檔案系統類型!" return 1 fi - # 創建掛載點 + # 建立掛載點 mkdir -p "$MOUNT_POINT" # 掛載 @@ -6711,54 +6711,54 @@ mount_partition() { } -# 卸載分區 +# 解除安裝分割區 unmount_partition() { - send_stats "卸載分區" - read -e -p "請輸入要卸載的分區名稱(例如 sda1):" PARTITION + send_stats "解除安裝分割區" + read -e -p "請輸入要卸載的分割區名稱(例如 sda1):" PARTITION - # 檢查分區是否已經掛載 + # 檢查分割區是否已經掛載 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then echo "分區未掛載!" return fi - # 卸載分區 + # 解除安裝分割區 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分區卸載成功:$MOUNT_POINT" + echo "分割區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else echo "分區卸載失敗!" fi } -# 列出已掛載的分區 +# 列出已掛載的分割區 list_mounted_partitions() { - echo "已掛載的分區:" + echo "已掛載的分割區:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分區 +# 格式化分割區 format_partition() { - send_stats "格式化分區" - read -e -p "請輸入要格式化的分區名稱(例如 sda1):" PARTITION + send_stats "格式化分割區" + read -e -p "請輸入要格式化的分割區名稱(例如 sda1):" PARTITION - # 檢查分區是否存在 + # 檢查分割區是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "分區不存在!" return fi - # 檢查分區是否已經掛載 + # 檢查分割區是否已經掛載 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分區已經掛載,請先卸載!" + echo "分割區已經掛載,請先卸載!" return fi - # 選擇文件系統類型 - echo "請選擇文件系統類型:" + # 選擇檔案系統類型 + echo "請選擇檔案系統類型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" @@ -6774,51 +6774,51 @@ format_partition() { esac # 確認格式化 - read -e -p "確認格式化分區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM + read -e -p "確認格式化分割區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return fi - # 格式化分區 - echo "正在格式化分區 /dev/$PARTITION為$FS_TYPE ..." + # 格式化分割區 + echo "正在格式化分割區 /dev/$PARTITION為$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分區格式化成功!" + echo "分割區格式化成功!" else - echo "分區格式化失敗!" + echo "分割區格式化失敗!" fi } # 檢查分區狀態 check_partition() { send_stats "檢查分區狀態" - read -e -p "請輸入要檢查的分區名稱(例如 sda1):" PARTITION + read -e -p "請輸入要檢查的分割區名稱(例如 sda1):" PARTITION - # 檢查分區是否存在 + # 檢查分割區是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "分區不存在!" return fi # 檢查分區狀態 - echo "檢查分區 /dev/$PARTITION的狀態:" + echo "檢查分割區 /dev/$PARTITION的狀態:" fsck "/dev/$PARTITION" } -# 主菜單 +# 主選單 disk_manager() { - send_stats "硬盤管理功能" + send_stats "硬碟管理功能" while true; do clear - echo "硬盤分區管理" - echo -e "${gl_huang}該功能內部測試階段,請勿在生產環境使用。${gl_bai}" + echo "硬碟分割管理" + echo -e "${gl_huang}此功能內部測試階段,請勿在生產環境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 掛載分區 2. 卸載分區 3. 查看已掛載分區" - echo "4. 格式化分區 5. 檢查分區狀態" + echo "1. 掛載分割區 2. 卸載分割區 3. 檢視已掛載分割區" + echo "4. 格式化分割區 5. 檢查分割區狀態" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6831,7 +6831,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按下回車鍵繼續..." done } @@ -6840,27 +6840,27 @@ disk_manager() { # 顯示任務列表 list_tasks() { - echo "已保存的同步任務:" + echo "已儲存的同步任務:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任務 +# 新增任務 add_task() { - send_stats "添加新同步任務" - echo "創建新同步任務示例:" + send_stats "新增同步任務" + echo "建立新同步任務範例:" echo "- 任務名稱: backup_www" - echo "- 本地目錄: /var/www" - echo "- 遠程地址: user@192.168.1.100" - echo "- 遠程目錄: /backup/www" - echo "- 端口號 (默認 22)" + echo "- 本機目錄: /var/www" + echo "- 遠端位址: user@192.168.1.100" + echo "- 遠端目錄: /backup/www" + echo "- 連接埠號碼 (預設 22)" echo "---------------------------------" read -e -p "請輸入任務名稱:" name read -e -p "請輸入本地目錄:" local_path - read -e -p "請輸入遠程目錄:" remote_path - read -e -p "請輸入遠程用戶@IP:" remote - read -e -p "請輸入 SSH 端口 (默認 22):" port + read -e -p "請輸入遠端目錄:" remote_path + read -e -p "請輸入遠端使用者@IP:" remote + read -e -p "請輸入 SSH 連接埠 (預設 22):" port port=${port:-22} echo "請選擇身份驗證方式:" @@ -6875,20 +6875,20 @@ add_task() { auth_method="password" ;; 2) - echo "請粘貼密鑰內容 (粘貼完成後按兩次回車):" + echo "請貼上金鑰內容 (貼上完成後按兩次回車):" local password_or_key="" while IFS= read -r line; do - # 如果輸入為空行且密鑰內容已經包含了開頭,則結束輸入 + # 如果輸入為空白行且金鑰內容已經包含了開頭,則結束輸入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已經開始輸入密鑰內容,則繼續添加 + # 如果是第一行或已經開始輸入金鑰內容,則繼續新增 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi done - # 檢查是否是密鑰內容 + # 檢查是否為密鑰內容 if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then local key_file="$KEY_DIR/${name}_sync.key" echo -n "$password_or_key" > "$key_file" @@ -6908,19 +6908,19 @@ add_task() { echo "請選擇同步模式:" echo "1. 標準模式 (-avz)" - echo "2. 刪除目標文件 (-avz --delete)" + echo "2. 刪除目標檔 (-avz --delete)" read -e -p "請選擇 (1/2):" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "無效選擇,使用默認 -avz"; options="-avz" ;; + *) echo "無效選擇,使用預設 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任務已保存!" + echo "任務已儲存!" } # 刪除任務 @@ -6936,7 +6936,7 @@ delete_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任務使用的是密鑰文件,則刪除該密鑰文件 + # 如果任務使用的是金鑰文件,則刪除該金鑰文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -6963,7 +6963,7 @@ run_task() { num="$1" fi - # 如果沒有傳入任務編號,提示用戶輸入 + # 如果沒有傳入任務編號,提示使用者輸入 if [[ -z "$num" ]]; then read -e -p "請輸入要執行的任務編號:" num fi @@ -6976,7 +6976,7 @@ run_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根據同步方向調整源和目標路徑 + # 根據同步方向調整來源和目標路徑 if [[ "$direction" == "pull" ]]; then echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" source="$remote:$local_path" @@ -6987,7 +6987,7 @@ run_task() { destination="$remote:$remote_path" fi - # 添加 SSH 連接通用參數 + # 新增 SSH 連線通用參數 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then @@ -7000,14 +7000,14 @@ run_task() { fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 檢查密鑰文件是否存在和權限是否正確 + # 檢查密鑰檔案是否存在和權限是否正確 if [[ ! -f "$password_or_key" ]]; then - echo "錯誤:密鑰文件不存在:$password_or_key" + echo "錯誤:密鑰檔案不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密鑰文件權限不正確,正在修復..." + echo "警告:密鑰檔案權限不正確,正在修復..." chmod 600 "$password_or_key" fi @@ -7018,17 +7018,17 @@ run_task() { echo "同步完成!" else echo "同步失敗! 請檢查以下內容:" - echo "1. 網絡連接是否正常" - echo "2. 遠程主機是否可訪問" - echo "3. 認證信息是否正確" - echo "4. 本地和遠程目錄是否有正確的訪問權限" + echo "1. 網路連線是否正常" + echo "2. 遠端主機是否可存取" + echo "3. 認證資訊是否正確" + echo "4. 本機和遠端目錄是否有正確的存取權限" fi } -# 創建定時任務 +# 建立定時任務 schedule_task() { - send_stats "添加同步定時任務" + send_stats "新增同步定時任務" read -e -p "請輸入要定時同步的任務編號:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7060,14 +7060,14 @@ schedule_task() { return fi - # 創建到用戶的 crontab + # 建立到使用者的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定時任務已創建:$cron_job" + echo "定時任務已建立:$cron_job" } # 查看定時任務 view_tasks() { - echo "當前的定時任務:" + echo "目前的定時任務:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" @@ -7087,23 +7087,23 @@ delete_task_schedule() { } -# 任務管理主菜單 +# 工作管理員主選單 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 遠程同步工具" - echo "遠程目錄之間同步,支持增量同步,高效穩定。" + echo "Rsync 遠端同步工具" + echo "遠端目錄之間同步,支援增量同步,高效穩定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 創建新任務 2. 刪除任務" - echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" - echo "5. 創建定時任務 6. 刪除定時任務" + echo "1. 建立新任務 2. 刪除任務" + echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" + echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" echo "---------------------------------" @@ -7118,7 +7118,7 @@ rsync_manager() { 0) break ;; *) echo "無效的選擇,請重試。" ;; esac - read -e -p "按回車鍵繼續..." + read -e -p "按下回車鍵繼續..." done } @@ -7135,8 +7135,8 @@ linux_info() { clear - echo -e "${gl_kjlan}正在查詢系統信息……${gl_bai}" - send_stats "系統信息查詢" + echo -e "${gl_kjlan}正在查詢系統資訊…${gl_bai}" + send_stats "系統資訊查詢" ip_address @@ -7188,9 +7188,9 @@ linux_info() { local udp_count=$(ss -u | wc -l) clear - echo -e "系統信息查詢" + echo -e "系統資訊查詢" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主機名:${gl_bai}$hostname" + echo -e "${gl_kjlan}主機名稱:${gl_bai}$hostname" echo -e "${gl_kjlan}系統版本:${gl_bai}$os_info" echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" @@ -7201,25 +7201,25 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}系統負載:${gl_bai}$load" - echo -e "${gl_kjlan}TCP|UDP連接數:${gl_bai}$tcp_count|$udp_count" - echo -e "${gl_kjlan}物理內存:${gl_bai}$mem_info" - echo -e "${gl_kjlan}虛擬內存:${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盤佔用:${gl_bai}$disk_info" + echo -e "${gl_kjlan}TCP|UDP連線數:${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}實體記憶體:${gl_bai}$mem_info" + echo -e "${gl_kjlan}虛擬記憶體:${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬碟佔用:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}總接收:${gl_bai}$rx" echo -e "${gl_kjlan}總發送:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}網絡算法:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}網路演算法:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}運營商:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4位址:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6位址:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}DNS位址:${gl_bai}$dns_addresses" echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" @@ -7262,11 +7262,11 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未識別的包管理器" + echo "❌ 未識別的套件管理器" exit 1 fi - echo "📦 使用包管理器:$PM" + echo "📦 使用套件管理器:$PM" echo -e "${gl_kjlan}------------------------${gl_bai}" for ((i=0; i<${#tools[@]}; i+=2)); do @@ -7292,26 +7292,26 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通信連接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網絡流量監控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視頻編碼直播推流工具" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盤佔用查看工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本編輯器${gl_kjlan}16. ${gl_bai}nano 文本編輯器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI編程助手${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文字編輯器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI程式設計助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝國屏保${gl_kjlan}22. ${gl_bai}跑火車屏保" + echo -e "${gl_kjlan}21. ${gl_bai}駭客任務螢幕保${gl_kjlan}22. ${gl_bai}跑火車屏保" echo -e "${gl_kjlan}26. ${gl_bai}俄羅斯方塊小遊戲${gl_kjlan}27. ${gl_bai}貪吃蛇小遊戲" echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小遊戲" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安裝${gl_kjlan}32. ${gl_bai}全部安裝(不含屏保和遊戲)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸載" + echo -e "${gl_kjlan}31. ${gl_bai}全部安裝${gl_kjlan}32. ${gl_bai}全部安裝(不含螢幕保護程式和遊戲)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部解除安裝" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安裝指定工具${gl_kjlan}42. ${gl_bai}卸載指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}安裝指定工具${gl_kjlan}42. ${gl_bai}解除安裝指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -7515,14 +7515,14 @@ linux_tools() { 32) clear - send_stats "全部安裝(不含遊戲和屏保)" + send_stats "全部安裝(不含遊戲和螢幕保護程式)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸載" + send_stats "全部解除安裝" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git opencode uninstall rm -rf ~/.opencode @@ -7530,15 +7530,15 @@ linux_tools() { 41) clear - read -e -p "請輸入安裝的工具名(wget curl sudo htop):" installname + read -e -p "請輸入已安裝的工具名稱(wget curl sudo htop):" installname install $installname - send_stats "安裝指定軟件" + send_stats "安裝指定軟體" ;; 42) clear - read -e -p "請輸入卸載的工具名(htop ufw tmux cmatrix):" removename + read -e -p "請輸入卸載的工具名稱(htop ufw tmux cmatrix):" removename remove $removename - send_stats "卸載指定軟件" + send_stats "解除安裝指定軟體" ;; 0) @@ -7566,12 +7566,12 @@ linux_bbr() { clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "當前TCP阻塞算法:$congestion_algorithm $queue_algorithm" + echo "當前TCP阻塞演算法:$congestion_algorithm $queue_algorithm" echo "" echo "BBR管理" echo "------------------------" - echo "1. 開啟BBRv3 2. 關閉BBRv3(會重啟)" + echo "1. 開啟BBRv3 2. 關閉BBRv3(會重新啟動)" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7616,7 +7616,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${gl_kjlan}當前備份列表:${gl_bai}" + echo -e "${gl_kjlan}目前備份清單:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "無備份" } @@ -7630,7 +7630,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "請輸入要備份的容器名(多個空格分隔,回車備份全部運行中容器):" containers + read -e -p "請輸入要備份的容器名稱(多個空格分隔,回車備份全部運行中容器):" containers install tar jq gzip install_docker @@ -7651,9 +7651,9 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自動生成的還原腳本" >> "$RESTORE_SCRIPT" + echo "# 自動產生的還原腳本" >> "$RESTORE_SCRIPT" - # 記錄已打包過的 Compose 項目路徑,避免重複打包 + # 記錄已打包過的 Compose 專案路徑,避免重複打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -7667,7 +7667,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未檢測到 compose 目錄,請手動輸入路徑:" project_dir + read -e -p "未偵測到 compose 目錄,請手動輸入路徑:" project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -7696,12 +7696,12 @@ docker_ssh_migration() { tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 端口 + # 連接埠 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 環境變量 + # 環境變數 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done @@ -7720,11 +7720,11 @@ docker_ssh_migration() { done - # 備份 /home/docker 下的所有文件(不含子目錄) + # 備份 /home/docker 下的所有檔案(不含子目錄) if [ -d "/home/docker" ]; then - echo -e "${gl_kjlan}備份 /home/docker 下的文件...${gl_bai}" + echo -e "${gl_kjlan}備份 /home/docker 下的檔案...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的文件已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的檔案已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" @@ -7748,7 +7748,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # --------- 優先還原 Compose 項目 --------- + # --------- 優先還原 Compose 專案 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -7757,7 +7757,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "未找到原始路徑,請輸入還原目錄路徑:" original_path - # 檢查該 compose 項目的容器是否已經在運行 + # 檢查該 compose 項目的容器是否已在運作 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}Compose 項目 [$project_name] 已有容器在運行,跳過還原...${gl_bai}" @@ -7769,7 +7769,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}Compose 項目 [$project_name] 已解壓到:$original_path${gl_bai}" + echo -e "${gl_lv}Compose 項目 [$project_name] 已解壓縮到:$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -7778,7 +7778,7 @@ docker_ssh_migration() { fi done - # --------- 繼續還原普通容器 --------- + # --------- 繼續還原一般容器 --------- echo -e "${gl_kjlan}檢查並還原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do @@ -7794,23 +7794,23 @@ docker_ssh_migration() { fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到鏡像信息,跳過:$container${gl_bai}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到鏡像訊息,跳過:$container${gl_bai}"; continue; } - # 端口映射 + # 連接埠映射 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 環境變量 + # 環境變數 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷數據恢復 + # 卷映射 + 卷資料恢復 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -7821,7 +7821,7 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢復卷數據:$VOL_SRC" + echo "恢復卷宗資料:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done @@ -7833,20 +7833,20 @@ docker_ssh_migration() { fi # 啟動容器 - echo "執行還原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + echo "執行還原指令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份信息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${gl_kjlan}正在還原 /home/docker 下的文件...${gl_bai}" + echo -e "${gl_kjlan}正在還原 /home/docker 下的檔案...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${gl_lv}/home/docker 下的文件已還原完成${gl_bai}" + echo -e "${gl_lv}/home/docker 下的檔案已還原完成${gl_bai}" else - echo -e "${gl_huang}未找到 /home/docker 下文件的備份,跳過...${gl_bai}" + echo -e "${gl_huang}未找到 /home/docker 下檔案的備份,跳過...${gl_bai}" fi @@ -7862,16 +7862,16 @@ docker_ssh_migration() { read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } - read -e -p "目標服務器IP:" TARGET_IP - read -e -p "目標服務器SSH用戶名:" TARGET_USER - read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + read -e -p "目標伺服器IP:" TARGET_IP + read -e -p "目標伺服器SSH用戶名:" TARGET_USER + read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} local LATEST_TAR="$BACKUP_DIR" echo -e "${gl_huang}傳輸備份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密鑰登錄 + # 使用密鑰登入 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7881,7 +7881,7 @@ docker_ssh_migration() { # 刪除備份 # ---------------------------- delete_backup() { - send_stats "Docker備份文件刪除" + send_stats "Docker備份檔案刪除" read -e -p "請輸入要刪除的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" @@ -7889,7 +7889,7 @@ docker_ssh_migration() { } # ---------------------------- - # 主菜單 + # 主選單 # ---------------------------- main_menu() { send_stats "Docker備份遷移還原" @@ -7904,7 +7904,7 @@ docker_ssh_migration() { echo -e "1. 備份docker項目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" - echo -e "4. 刪除docker項目的備份文件" + echo -e "4. 刪除docker專案的備份文件" echo "------------------------" echo -e "0. 返回上一級選單" echo "------------------------" @@ -7938,14 +7938,14 @@ linux_docker() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}安裝更新Docker環境${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局狀態${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全域狀態${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker鏡像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker網絡管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker捲管理" + echo -e "${gl_kjlan}4. ${gl_bai}Docker映像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker網路管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker磁碟區管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和鏡像網絡數據卷" + echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和映像網路資料卷" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}更換Docker源" echo -e "${gl_kjlan}9. ${gl_bai}編輯daemon.json文件" @@ -7954,9 +7954,9 @@ linux_docker() { echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" - echo -e "${gl_kjlan}20. ${gl_bai}卸載Docker環境" + echo -e "${gl_kjlan}20. ${gl_bai}解除安裝Docker環境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -7974,22 +7974,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局狀態" + send_stats "docker全域狀態" echo "Docker版本" docker -v docker compose version echo "" - echo -e "Docker鏡像:${gl_lv}$image_count${gl_bai} " + echo -e "Docker映像:${gl_lv}$image_count${gl_bai} " docker image ls echo "" echo -e "Docker容器:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker磁碟區:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker網絡:${gl_lv}$network_count${gl_bai}" + echo -e "Docker網路:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8004,15 +8004,15 @@ linux_docker() { 5) while true; do clear - send_stats "Docker網絡管理" - echo "Docker網絡列表" + send_stats "Docker網路管理" + echo "Docker網路列表" echo "------------------------------------------------------------" docker network ls echo "" echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名稱" "網絡名稱" "IP地址" + printf "%-25s %-25s %-25s\n" "容器名稱" "網路名稱" "IP位址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -8029,9 +8029,9 @@ linux_docker() { done echo "" - echo "網絡操作" + echo "網路操作" echo "------------------------" - echo "1. 創建網絡" + echo "1. 建立網絡" echo "2. 加入網絡" echo "3. 退出網絡" echo "4. 刪除網絡" @@ -8042,23 +8042,23 @@ linux_docker() { case $sub_choice in 1) - send_stats "創建網絡" - read -e -p "設置新網絡名:" dockernetwork + send_stats "創建網路" + read -e -p "設定新網路名稱:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入網絡" - read -e -p "加入網絡名:" dockernetwork - read -e -p "那些容器加入該網絡(多個容器名請用空格分隔):" dockernames + send_stats "加入網路" + read -e -p "加入網路名稱:" dockernetwork + read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入網絡" - read -e -p "退出網絡名:" dockernetwork - read -e -p "那些容器退出該網絡(多個容器名請用空格分隔):" dockernames + send_stats "加入網路" + read -e -p "退出網路名稱:" dockernetwork + read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8068,7 +8068,7 @@ linux_docker() { 4) send_stats "刪除網絡" - read -e -p "請輸入要刪除的網絡名:" dockernetwork + read -e -p "請輸入要刪除的網路名稱:" dockernetwork docker network rm $dockernetwork ;; @@ -8082,13 +8082,13 @@ linux_docker() { 6) while true; do clear - send_stats "Docker捲管理" + send_stats "Docker磁碟區管理" echo "Docker卷列表" docker volume ls echo "" echo "卷操作" echo "------------------------" - echo "1. 創建新卷" + echo "1. 建立新卷" echo "2. 刪除指定卷" echo "3. 刪除所有捲" echo "------------------------" @@ -8098,13 +8098,13 @@ linux_docker() { case $sub_choice in 1) - send_stats "新建卷" - read -e -p "設置新卷名:" dockerjuan + send_stats "新磁碟區" + read -e -p "設定新卷名:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "輸入刪除卷名(多個卷名請用空格分隔):" dockerjuans + read -e -p "輸入刪除卷名(多個卷名請以空格分隔):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8150,7 +8150,7 @@ linux_docker() { ;; 8) clear - send_stats "Docker源" + send_stats "Docker來源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -8183,7 +8183,7 @@ linux_docker() { 20) clear - send_stats "Docker卸載" + send_stats "Docker解除安裝" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8221,61 +8221,61 @@ linux_test() { while true; do clear - # send_stats "測試腳本合集" + # send_stats "測試腳本集合" echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解鎖狀態檢測" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態檢測" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒體解鎖測試" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒體解鎖檢測" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP質量體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解鎖狀態偵測" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" + echo -e "${gl_kjlan}2. ${gl_bai}Region 串流解鎖測試" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 串流媒體解鎖偵測" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP品質體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}網絡線路測速" + echo -e "${gl_kjlan}網路線路測速" echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三網線路測試" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網絡質量體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能測試" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能測試" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能測試腳本" + echo -e "${gl_kjlan}硬體效能測試" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 效能測試" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU效能測試腳本" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}綜合性測試" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能測試" + echo -e "${gl_kjlan}31. ${gl_bai}bench 效能測試" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪測評${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪測評${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解鎖狀態檢測" + send_stats "ChatGPT解鎖狀態偵測" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒體解鎖測試" + send_stats "Region串流解鎖測試" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒體解鎖檢測" + send_stats "yeahwu串流解鎖偵測" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP質量體檢腳本" + send_stats "xykt_IP品質體檢腳本" bash <(curl -Ls IP.Check.Place) ;; @@ -8331,7 +8331,7 @@ linux_test() { 16) clear - send_stats "ludashi2020三網線路測試" + send_stats "ludashi2020三線線路測試" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; @@ -8343,26 +8343,26 @@ linux_test() { 18) clear - send_stats "網絡質量測試腳本" + send_stats "網路品質測試腳本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能測試" + send_stats "yabs效能測試" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能測試腳本" + send_stats "icu/gb5 CPU效能測試腳本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能測試" + send_stats "bench效能測試" curl -Lso- bench.sh | bash ;; 32) @@ -8400,48 +8400,48 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云腳本合集" - echo -e "甲骨文云腳本合集" + send_stats "甲骨文雲腳本合集" + echo -e "甲骨文雲腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}安裝閒置機器活躍腳本" echo -e "${gl_kjlan}2. ${gl_bai}卸載閒置機器活躍腳本" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD重裝系統腳本" echo -e "${gl_kjlan}4. ${gl_bai}R探長開機腳本" - echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登錄模式" + echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登入模式" echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢復工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) clear - echo "活躍腳本: CPU佔用10-20% 內存佔用20%" + echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" read -e -p "確定安裝嗎? (Y/N):" choice case "$choice" in [Yy]) install_docker - # 設置默認值 + # 設定預設值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用戶輸入CPU核心數和占用百分比,如果回車則使用默認值 - read -e -p "請輸入CPU核心數 [默認:$DEFAULT_CPU_CORE]: " cpu_core + # 提示使用者輸入CPU核心數和占用百分比,如果回車則使用預設值 + read -e -p "請輸入CPU核心數 [預設:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [默認:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [預設:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "請輸入內存佔用百分比 [默認:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "請輸入記憶體佔用百分比 [預設:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "請輸入Speedtest間隔時間(秒) [默認:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "請輸入Speedtest間隔時間(秒) [預設:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 運行Docker容器 @@ -8452,7 +8452,7 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安裝活躍腳本" + send_stats "甲骨文雲安裝活躍腳本" ;; [Nn]) @@ -8467,20 +8467,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸載活躍腳本" + send_stats "甲骨文雲端卸載活躍腳本" ;; 3) clear echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份數據。" + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) while true; do - read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice case "$sys_choice" in 1) @@ -8500,7 +8500,7 @@ linux_Oracle() { read -e -p "請輸入你重裝後的密碼:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重裝系統腳本" + send_stats "甲骨文雲端重裝系統腳本" ;; [Nn]) echo "已取消" @@ -8523,7 +8523,7 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "該功能由jhb大神提供,感謝他!" + echo "此功能由jhb大神提供,感謝他!" send_stats "ipv6修復" ;; 0) @@ -8555,7 +8555,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}環境已經安裝${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡像:${gl_lv}$image_count${gl_bai}網絡:${gl_lv}$network_count${gl_bai}卷:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}環境已經安裝${gl_bai}容器:${gl_lv}$container_count${gl_bai}鏡像:${gl_lv}$image_count${gl_bai}網路:${gl_lv}$network_count${gl_bai}卷:${gl_lv}$volume_count${gl_bai}" fi } @@ -8604,29 +8604,29 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" + # send_stats "LDNMP建置站" echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道云桌面" + echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" - echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量博客網站" - echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack共享鏈接平台${gl_huang}20. ${gl_bai}自定義動態站點" + echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" + echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站點重定向" + echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo博客網站" - echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞生成器${gl_huang}28. ${gl_bai}站點反向代理-負載均衡" - echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自定義靜態站點" + echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo部落格網站" + echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" + echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站點數據管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" - echo -e "${gl_huang}33. ${gl_bai}定時遠程備份${gl_huang}34. ${gl_bai}還原全站數據" + echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" + echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸載LDNMP環境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}解除安裝LDNMP環境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜單" + echo -e "${gl_huang}0. ${gl_bai}返回主選單" echo -e "${gl_huang}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -8673,8 +8673,8 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo "表前綴: discuz_" @@ -8684,8 +8684,8 @@ linux_ldnmp() { 4) clear - # 可道云桌面 - webname="可道云桌面" + # 可道雲桌面 + webname="可道雲桌面" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -8712,10 +8712,10 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "數據庫地址: mysql" + echo "資料庫位址: mysql" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "數據庫名:$dbname" + echo "資料庫名稱:$dbname" echo "redis主機: redis" ;; @@ -8756,14 +8756,14 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫連接埠: 3306" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "數據庫前綴: mac_" + echo "資料庫前綴: mac_" echo "------------------------" - echo "安裝成功後登錄後台地址" + echo "安裝成功後登入後台位址" echo "https://$yuming/vip.php" ;; @@ -8800,23 +8800,23 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫連接埠: 3306" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo "" echo "redis地址: redis" - echo "redis密碼: 默認不填寫" - echo "redis端口: 6379" + echo "redis密碼: 預設不填寫" + echo "redis 埠: 6379" echo "" - echo "網站url: https://$yuming" - echo "後台登錄路徑: /admin" + echo "網址url: https://$yuming" + echo "後台登入路徑: /admin" echo "------------------------" - echo "用戶名: admin" + echo "使用者名稱: admin" echo "密碼: admin" echo "------------------------" - echo "登錄時右上角如果出現紅色error0請使用如下命令:" + echo "登入時右上角如果出現紅色error0請使用下列指令:" echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -8874,12 +8874,12 @@ linux_ldnmp() { ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "表前綴: flarum_" - echo "管理員信息自行設置" + echo "表字首: flarum_" + echo "管理員資訊自行設定" ;; @@ -8918,11 +8918,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "數據庫前綴: typecho_" - echo "數據庫地址: mysql" + echo "資料庫前綴: typecho_" + echo "資料庫位址: mysql" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "數據庫名:$dbname" + echo "資料庫名稱:$dbname" ;; @@ -8961,9 +8961,9 @@ linux_ldnmp() { clear ldnmp_web_on - echo "數據庫地址: mysql" - echo "數據庫端口: 3306" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫連接埠: 3306" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" ;; @@ -8992,10 +8992,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP源碼" + echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download + read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9035,9 +9035,9 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}4/6${gl_bai}] 安裝指定擴展" + echo -e "[${gl_huang}4/6${gl_bai}] 安裝指定擴充" echo "-------------" - echo "已經安裝的擴展" + echo "已經安裝的擴充" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -9047,25 +9047,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 編輯站點配置" + echo -e "[${gl_huang}5/6${gl_bai}] 編輯網站配置" echo "-------------" - echo "按任意鍵繼續,可以詳細設置站點配置,如偽靜態等內容" + echo "按任一鍵繼續,可詳細設定網站配置,如偽靜態等內容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 數據庫管理" + echo -e "[${gl_huang}6/6${gl_bai}] 資料庫管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有數據庫備份:" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有資料庫備份:" use_db case $use_db in 1) echo ;; 2) - echo "數據庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支持寶塔/1panel備份數據導入。" - read -e -p "也可以輸入下載鏈接,遠程下載備份數據,直接回車將跳過遠程下載:" url_download_db + echo "資料庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" + read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -9075,10 +9075,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "數據庫導入的表數據" + echo "資料庫匯入的表數據" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "數據庫導入完成" + echo "資料庫導入完成" ;; *) echo @@ -9090,12 +9090,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "數據庫地址: mysql" - echo "數據庫名:$dbname" + echo "資料庫位址: mysql" + echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo "表前綴:$prefix" - echo "管理員登錄信息自行設置" + echo "管理員登入資訊自行設定" ;; @@ -9107,7 +9107,7 @@ linux_ldnmp() { 22) clear - webname="站點重定向" + webname="網站重定向" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -9138,7 +9138,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+連接埠存取該服務" else ip_address close_port "$port" @@ -9154,7 +9154,7 @@ linux_ldnmp() { echo "開始部署$webname" add_yuming echo -e "域名格式:${gl_huang}google.com${gl_bai}" - read -e -p "請輸入你的反代域名:" fandai_yuming + read -e -p "請輸入你的反代網域:" fandai_yuming nginx_install_status install_ssltls @@ -9211,7 +9211,7 @@ linux_ldnmp() { 27) clear - webname="AI繪畫提示詞生成器" + webname="AI繪畫提示詞產生器" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -9274,10 +9274,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態源碼" + echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠程下載源碼包,直接回車將跳過遠程下載:" url_download + read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9325,15 +9325,15 @@ linux_ldnmp() { while true; do clear - echo "備份文件已創建: /home/$backup_filename" - read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice + echo "備份檔案已建立: /home/$backup_filename" + read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "請輸入遠端服務器IP:" remote_ip - read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + read -e -p "請輸入遠端伺服器IP:" remote_ip + read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" + echo "錯誤: 請輸入遠端伺服器IP。" continue fi local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -9341,7 +9341,7 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已傳送至遠程服務器home目錄。" + echo "檔案已傳送至遠端伺服器home目錄。" else echo "未找到要傳送的文件。" fi @@ -9359,9 +9359,9 @@ linux_ldnmp() { 33) clear - send_stats "定時遠程備份" - read -e -p "輸入遠程服務器IP:" useip - read -e -p "輸入遠程服務器密碼:" usepasswd + send_stats "定時遠端備份" + read -e -p "輸入遠端伺服器IP:" useip + read -e -p "輸入遠端伺服器密碼:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -9371,13 +9371,13 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周備份 2. 每天備份" + echo "1. 每週備份 2. 每天備份" read -e -p "請輸入你的選擇:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "選擇每周備份的星期幾 (0-6,0代表星期日):" weekday + read -e -p "選擇每週備份的星期幾 (0-6,0代表星期日):" weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) @@ -9401,14 +9401,14 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用戶沒有輸入文件名,使用最新的壓縮包 + # 如果使用者沒有輸入檔名,使用最新的壓縮包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -9418,7 +9418,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_kjlan}正在解壓$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9448,7 +9448,7 @@ linux_ldnmp() { echo "更新LDNMP環境" echo "------------------------" ldnmp_v - echo "發現新版本的組件" + echo "發現新版本的元件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -9468,7 +9468,7 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" echo "5. 更新完整環境" echo "------------------------" @@ -9483,7 +9483,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "請輸入${ldnmp_pods}版本號 (如: 8.0 8.3 8.4 9.0)(回車獲取最新版):" version + read -e -p "請輸入${ldnmp_pods}版本號碼 (如: 8.0 8.3 8.4 9.0)(回車取得最新版):" version local version=${version:-latest} cd /home/web/ @@ -9500,7 +9500,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車獲取最新版):" version + read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車取得最新版):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -9577,7 +9577,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸載LDNMP環境" + send_stats "解除安裝LDNMP環境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -9638,9 +9638,9 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}檢測到新版本:$remote_version${gl_bai}" + echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}當前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" fi } @@ -9654,7 +9654,7 @@ moltbot_menu() { get_running_status() { if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}運行中${gl_bai}" + echo "${gl_lv}運作中${gl_bai}" else echo "${gl_hui}未運行${gl_bai}" fi @@ -9673,20 +9673,20 @@ moltbot_menu() { echo -e "ClawdBot > MoltBot > OpenClaw 管理" echo -e "$install_status $running_status $update_message" echo "=======================================" - echo "1. 安裝" - echo "2. 啟動" - echo "3. 停止" + echo "1. 安裝" + echo "2. 啟動" + echo "3. 停止" echo "--------------------" - echo "4. 日誌查看" - echo "5. 換模型" - echo "6. 加新模型API" - echo "7. TG輸入連接碼" - echo "8. 安裝插件(如:飛書)" - echo "9. 安裝技能(skills)" - echo "10. 編輯主配置文件" - echo "11. 配置嚮導" + echo "4. 日誌查看" + echo "5. 換模型" + echo "6. 加新模型API" + echo "7. TG輸入連接碼" + echo "8. 安裝插件(如:飛書)" + echo "9. 安裝技能(skills)" + echo "10. 編輯主設定文件" + echo "11. 配置精靈" echo "12. 健康檢測與修復" - echo "13. WebUI訪問與設置" + echo "13. WebUI存取與設置" echo "--------------------" echo "14. 更新" echo "15. 卸載" @@ -9755,46 +9755,101 @@ moltbot_menu() { - add-openclaw-provider() { - local config_file="${HOME}/.openclaw/openclaw.json" + + + # 核心函數:取得並加入所有模型 + add-all-models-from-provider() { local provider_name="$1" - local models_id="$2" - local base_url="$3" - local api_key="$4" - - echo "=== 添加自定義 OpenAI 兼容模型到 OpenClaw ===" - echo "Provider: $provider_name" - echo "Model ID: $models_id" - echo "Base URL: $base_url" - echo "API Key: ${api_key:0:8}****" - - # 檢查參數 - if [[ -z "$provider_name" || -z "$models_id" || -z "$base_url" || -z "$api_key" ]]; then - echo "錯誤:參數不能為空​​!" - echo "用法: add-openclaw-provider " + local base_url="$2" + local api_key="$3" + local config_file="${HOME}/.openclaw/openclaw.json" + + echo "🔍 正在獲取$provider_name的所有可用模型..." + + # 取得模型列表 + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 無法取得模型列表" return 1 fi - # 檢查 jq - if ! command -v jq &> /dev/null; then - echo "安裝 jq: apt update && apt install -y jq" - apt update && apt install -y jq || { - echo "安裝 jq 失敗" - return 1 - } - fi + # 提取所有模型ID + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - # 備份原文件 - if [[ -f "$config_file" ]]; then - cp "$config_file" "${config_file}.bak.$(date +%s)" - echo "備份:${config_file}.bak.*" + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 fi + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 發現$model_count個模型" + + # 智慧推斷模型參數 + local models_array="[" + local first=true + + while read -r model_id; do + [[ $first == false ]] && models_array+="," + first=false + + # 根據模型名稱推斷上下文窗口 + local context_window=131072 + local max_tokens=8192 + local input_cost=0.14 + local output_cost=0.28 + + case "$model_id" in + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M + max_tokens=16384 + input_cost=0.30 + output_cost=0.60 + ;; + *gpt-5*|*codex*) + context_window=131072 # 128K + max_tokens=8192 + input_cost=0.20 + output_cost=0.40 + ;; + *flash*|*lite*|*haiku*) + context_window=131072 + max_tokens=8192 + input_cost=0.07 + output_cost=0.14 + ;; + esac + + models_array+=$(cat < "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ 已添加 provider:$provider_name" - echo "📦 模型引用方式:$provider_name/$models_id" - echo "🔧 設置默認模型:" - echo " openclaw config patch '{\"agents.defaults.model.primary\": \"$provider_name/$models_id\"}'" - echo "🔄 重啟網關:" - echo " openclaw gateway restart" + echo "✅ 成功添加$model_count個模型到$provider_name" + echo "📦 模型引用格式:$provider_name/" + return 0 else - echo "❌ 添加失敗,檢查 jq 語法" + echo "❌ 配置注入失敗" return 1 fi } - # 可選:自動設置默認並重啟 - add-openclaw-provider-and-switch() { - install jq - - add-openclaw-provider "$1" "$2" "$3" "$4" - - if [[ $? -eq 0 ]]; then - echo "🔄 設置默認模型並重啟網關..." - openclaw models set "$1/$2" - start_tmux - echo "✅ 完成!當前默認模型:$1/$2" - openclaw status | grep -A2 "Sessions" - fi - } - - - - - add-openclaw-provider-interactive() { - send_stats "添加API" - echo "=== 交互式添加 OpenClaw Provider ===" + send_stats "新增API" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" - # Provider 名稱 + # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider 名稱不能為空" read -erp "請輸入 Provider 名稱:" provider_name done - # Model ID - read -erp "請輸入 Model ID (如: deepseek-chat):" model_id - while [[ -z "$model_id" ]]; do - echo "❌ Model ID 不能為空" - read -erp "請輸入 Model ID:" model_id - done - - # Base URL + # 2. Base URL read -erp "請輸入 Base URL (如: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ Base URL 不能為空" read -erp "請輸入 Base URL:" base_url done + base_url="${base_url%/}" - # API Key(隱藏輸入) + # 3. API Key read -rsp "請輸入 API Key (輸入不顯示):" api_key echo while [[ -z "$api_key" ]]; do @@ -9888,26 +9901,71 @@ moltbot_menu() { echo done + # 4. 取得模型列表 + echo "🔍 正在取得可用模型清單..." + models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -n "$models_json" ]]; then + available_models=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+' | sort) + + if [[ -n "$available_models" ]]; then + model_count=$(echo "$available_models" | wc -l) + echo "✅ 發現$model_count個可用模型:" + echo "--------------------------------" + # 全部顯示,附序號 + i=1 + declare -A model_map + while read -r model; do + echo "[$i] $model" + model_map[$i]="$model" + ((i++)) + done <<< "$available_models" + echo "--------------------------------" + fi + fi + + # 5. 選擇預設模型 echo - echo "====== 確認信息 ======" - echo "Provider : $provider_name" - echo "Model ID : $model_id" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" + read -erp "請輸入預設 Model ID (或序號,留空則使用第一個):" input_model + + if [[ -z "$input_model" && -n "$available_models" ]]; then + default_model=$(echo "$available_models" | head -1) + echo "🎯 使用第一個模型:$default_model" + elif [[ -n "${model_map[$input_model]}" ]]; then + default_model="${model_map[$input_model]}" + echo "🎯 已選擇模型:$default_model" + else + default_model="$input_model" + fi + + # 6. 確認訊息 + echo + echo "====== 確認訊息 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "默认模型 : $default_model" + echo "模型總數 :$model_count" echo "======================" - read -erp "確認添加? (y/N):" confirm + read -erp "確認添加所有$model_count個模型? (y/N):" confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "❎ 已取消" return 1 fi - echo - add-openclaw-provider-and-switch \ - "$provider_name" \ - "$model_id" \ - "$base_url" \ - "$api_key" + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 設定預設模型並重新啟動網關..." + openclaw models set "$provider_name/$default_model" + start_tmux + echo "✅ 完成!所有$model_count個模型已載入" + fi break_end } @@ -9926,9 +9984,9 @@ moltbot_menu() { echo "當前模型:" openclaw models list echo "----------------" - read -e -p "請輸入要設置的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" model + read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" model - # 1. 檢查是否輸入 0 以退出 + # 1. 檢查是否輸入 0 退出 if [ "$model" = "0" ]; then echo "操作已取消,正在退出..." break # 跳出 while 循环 @@ -9960,32 +10018,32 @@ moltbot_menu() { while true; do clear echo "========================================" - echo "插件管理 (安裝)" + echo "外掛程式管理 (安裝)" echo "========================================" echo "當前已安裝插件:" openclaw plugins list echo "----------------------------------------" - # 輸出推薦的實用插件列表,便於用戶複製 - echo "推薦的實用插件(可直接複製名稱輸入):" - echo "feishu # 飛書/Lark 集成 (當前已加載 ✓)" - echo "telegram # Telegram 機器人集成 (當前已加載 ✓)" - echo "memory-core # 核心記憶增強:基於文件的上下文搜索 (當前已加載 ✓)" - echo "@openclaw/slack # Slack 頻道與 DMs 深度連接" + # 輸出推薦的實用外掛程式列表,方便用戶複製 + echo "建議的實用外掛程式(可直接複製名稱輸入):" + echo "feishu # 飛書/Lark 整合 (目前已載入 ✓)" + echo "telegram # Telegram 機器人整合 (目前已載入 ✓)" + echo "memory-core # 核心記憶增強:基於檔案的上下文搜尋 (目前已載入 ✓)" + echo "@openclaw/slack # Slack 頻道與 DMs 深度連接" echo "@openclaw/bluebubbles # iMessage 橋接 (macOS 用戶首選)" - echo "@openclaw/msteams # Microsoft Teams 企業通訊集成" - echo "@openclaw/voice-call # 語音通話插件 (基於 Twilio 等後端)" - echo "@openclaw/discord # Discord 頻道自動化管理" - echo "@openclaw/nostr # Nostr 協議:隱私安全加密聊天" - echo "lobster # 審批工作流:帶有人工干預的自動任務" - echo "memory-lancedb # 長期記憶增強:基於向量數據庫的精準召回" - echo "copilot-proxy # GitHub Copilot 代理接入增強" + echo "@openclaw/msteams # Microsoft Teams 企業通訊集成" + echo "@openclaw/voice-call # 語音通話外掛程式 (基於 Twilio 等後端)" + echo "@openclaw/discord # Discord 頻道自動化管理" + echo "@openclaw/nostr # Nostr 協定:隱私安全加密聊天" + echo "lobster # 審批工作流程:帶有人工幹預的自動任務" + echo "memory-lancedb # 長期記憶增強:基於向量資料庫的精準召回" + echo "copilot-proxy # GitHub Copilot 代理程式存取增強" echo "----------------------------------------" - # 提示用戶輸入插件名稱 + # 提示使用者輸入外掛名稱 read -e -p "請輸入要安裝的插件名稱(輸入 0 退出):" plugin_name - # 1. 檢查是否輸入 0 以退出 + # 1. 檢查是否輸入 0 退出 if [ "$plugin_name" = "0" ]; then echo "操作已取消,退出插件安裝。" break @@ -9998,21 +10056,21 @@ moltbot_menu() { continue fi - # 1. 徹底清理之前失敗的殘留(用戶目錄) + # 1. 徹底清理之前失敗的殘留(使用者目錄) rm -rf "/root/.openclaw/extensions/$plugin_name" - # 2. 檢查系統是否已經預裝(防止 duplicate id 衝突) + # 2. 檢查系統是否已預先安裝(防止 duplicate id 衝突) if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 檢測到系統目錄已存在該插件,正在直接激活..." + echo "💡 偵測到系統目錄已存在該插件,正在直接啟動..." openclaw plugins enable "$plugin_name" else - echo "📥 正在通過官方渠道下載安裝插件..." - # 使用 openclaw 自己的 install 命令,它會自動處理 package.json 的規範檢查 + echo "📥 正在透過官方管道下載安裝插件..." + # 使用 openclaw 自己的 install 指令,它會自動處理 package.json 的規格檢查 openclaw plugins install "$plugin_name" - # 3. 如果 openclaw install 報錯,再嘗試作為普通 npm 包安裝(最後的備選) + # 3. 如果 openclaw install 報錯,再嘗試作為普通 npm 套件安裝(最後的備選) if [ $? -ne 0 ]; then - echo "⚠️ 官方安裝失敗,嘗試通過 npm 全局強制安裝..." + echo "⚠️ 官方安裝失敗,嘗試透過 npm 全域強制安裝..." npm install -g "$plugin_name" --unsafe-perm fi @@ -10030,38 +10088,38 @@ moltbot_menu() { while true; do clear echo "========================================" - echo "插件管理 (安裝)" + echo "外掛程式管理 (安裝)" echo "========================================" echo "當前插件列表:" openclaw plugins list echo "--------------------------------------------------------" - echo "推薦的常用插件 ID (直接複製括號內的 ID 即可):" + echo "推薦的常用外掛 ID (直接複製括號內的 ID 即可):" echo "--------------------------------------------------------" - echo "📱 通訊渠道:" - echo "- [feishu] # 飛書/Lark 集成" - echo "- [telegram] # Telegram 機器人" - echo "- [slack] # Slack 企業通訊" + echo "📱 通訊頻道:" + echo "- [feishu] # 飛書/Lark 集成" + echo "- [telegram] # Telegram 機器人" + echo "- [slack] # Slack 企業通訊" echo " - [msteams] # Microsoft Teams" - echo "- [discord] # Discord 社區管理" - echo "- [whatsapp] # WhatsApp 自動化" + echo "- [discord] # Discord 社群管理" + echo "- [whatsapp] # WhatsApp 自動化" echo "" echo "🧠 記憶與 AI:" - echo "- [memory-core] # 基礎記憶 (文件檢索)" - echo "- [memory-lancedb] # 增強記憶 (向量數據庫)" - echo "- [copilot-proxy] # Copilot 接口轉發" + echo "- [memory-core] # 基礎記憶 (文件檢索)" + echo "- [memory-lancedb] # 增強記憶 (向量資料庫)" + echo "- [copilot-proxy] # Copilot 介面轉發" echo "" - echo "⚙️ 功能擴展:" - echo "- [lobster] # 審批流 (帶人工確認)" - echo "- [voice-call] # 語音通話能力" - echo "- [nostr] # 加密隱私聊天" + echo "⚙️ 功能擴充:" + echo "- [lobster] # 審批流 (附人工確認)" + echo "- [voice-call] # 語音通話能力" + echo "- [nostr] # 加密隱私聊天" echo "--------------------------------------------------------" - read -e -p "請輸入插件 ID(輸入 0 退出):" raw_input + read -e -p "請輸入外掛 ID(輸入 0 退出):" raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue - # 1. 自動處理:如果用戶輸入帶 @openclaw/,提取純 ID 方便路徑檢查 + # 1. 自動處理:如果使用者輸入帶 @openclaw/,提取純 ID 方便路徑檢查 local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') local plugin_full="$raw_input" @@ -10069,17 +10127,17 @@ moltbot_menu() { # 2. 檢查是否已經在 list 中且為 disabled (最常見的情況) if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已預裝,正在激活..." - openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失敗" + echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." + openclaw plugins enable "$plugin_id" && echo "✅ 啟動成功" || echo "❌ 啟動失敗" - # 3. 檢查系統物理目錄是否存在 + # 3. 檢查系統實體目錄是否存在 elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 發現系統內置目錄存在該插件,嘗試直接啟用..." + echo "💡 發現系統內建目錄存在該插件,嘗試直接啟用..." openclaw plugins enable "$plugin_id" else - # 4. 遠程安裝邏輯 - echo "📥 本地未發現,嘗試下載安裝..." + # 4. 遠端安裝邏輯 + echo "📥 本機未發現,嘗試下載安裝..." # 清理舊的失敗殘留 rm -rf "/root/.openclaw/extensions/$plugin_id" @@ -10089,13 +10147,13 @@ moltbot_menu() { echo "✅ 下載成功,正在啟用..." openclaw plugins enable "$plugin_id" else - echo "⚠️ 官方渠道下載失敗,嘗試備選方案..." + echo "⚠️ 官方頻道下載失敗,嘗試備選方案..." # 備選 npm 安裝 if npm install -g "$plugin_full" --unsafe-perm; then echo "✅ npm 安裝成功,嘗試啟用..." openclaw plugins enable "$plugin_id" else - echo "❌ 嚴重錯誤:無法獲取該插件。請檢查 ID 是否正確或網絡是否可用。" + echo "❌ 嚴重錯誤:無法取得該外掛程式。請檢查 ID 是否正確或網路是否可用。" # 關鍵:這裡直接 return 或 continue,不走下面的 start_tmux,防止寫死配置 break_end continue @@ -10103,7 +10161,7 @@ moltbot_menu() { fi fi - echo "🔄 正在重啟 OpenClaw 服務以加載新插件..." + echo "🔄 正在重啟 OpenClaw 服務以載入新插件..." start_tmux break_end done @@ -10122,32 +10180,32 @@ moltbot_menu() { echo "========================================" echo "技能管理 (安裝)" echo "========================================" - echo "當前已安裝技能:" + echo "目前已安裝技能:" openclaw skills list echo "----------------------------------------" - # 輸出推薦的實用技能列表 - echo "推薦的實用技能(可直接複製名稱輸入):" - echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 頁面、數據庫和塊" - echo "apple-notes # macOS 原生筆記管理 (創建/編輯/搜索)" - echo "apple-reminders # macOS 提醒事項管理 (待辦清單)" - echo "1password # 自動化讀取和注入 1Password 密鑰" - echo "gog # Google Workspace (Gmail/雲盤/文檔) 全能助手" - echo "things-mac # 深度整合 Things 3 任務管理" - echo "bluebubbles # 通過 BlueBubbles 完美收發 iMessage" - echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" - echo "summarize # 網頁/播客/YouTube 視頻內容一鍵總結" - echo "openhue # 控制 Philips Hue 智能燈光場景" - echo "video-frames # 視頻抽幀與短片剪輯 (ffmpeg 驅動)" - echo "openai-whisper # 本地音頻轉文字 (離線隱私保護)" - echo "coding-agent # 自動運行 Claude Code/Codex 等編程助手" + # 輸出建議的實用技能列表 + echo "建議的實用技能(可直接複製名稱輸入):" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 頁面、資料庫和區塊" + echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" + echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" + echo "1password # 自動化讀取和注入 1Password 金鑰" + echo "gog # Google Workspace (Gmail/雲端盤/文件) 全能助手" + echo "things-mac # 深度整合 Things 3 任務管理" + echo "bluebubbles # 透過 BlueBubbles 完美收發 iMessage" + echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" + echo "summarize # 網頁/播客/YouTube 影片內容一鍵總結" + echo "openhue # 控制 Philips Hue 智慧燈光場景" + echo "video-frames # 視訊抽幀與短片剪輯 (ffmpeg 驅動)" + echo "openai-whisper # 本地音訊轉文字 (離線隱私保護)" + echo "coding-agent # 自動運行 Claude Code/Codex 等程式設計助手" echo "----------------------------------------" - # 提示用戶輸入技能名稱 + # 提示使用者輸入技能名稱 read -e -p "請輸入要安裝的技能名稱(輸入 0 退出):" skill_name - # 1. 檢查是否輸入 0 以退出 + # 1. 檢查是否輸入 0 退出 if [ "$skill_name" = "0" ]; then echo "操作已取消,退出技能安裝。" break @@ -10160,17 +10218,17 @@ moltbot_menu() { continue fi - # 3. 執行安裝命令 + # 3. 執行安裝指令 echo "正在安裝技能:$skill_name ..." npx clawhub install "$skill_name" - # 獲取上一條命令的退出狀態 + # 取得上一條指令的退出狀態 if [ $? -eq 0 ]; then echo "✅ 技能$skill_name安裝成功。" # 執行重啟/啟動服務邏輯 start_tmux else - echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文檔排查。" + echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文件排查。" fi break_end @@ -10182,9 +10240,9 @@ moltbot_menu() { change_tg_bot_code() { send_stats "機器人對接" - read -e -p "請輸入TG機器人收到的連接碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入TG機器人收到的連線碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" code - # 檢查是否輸入 0 以退出 + # 檢查是否輸入 0 退出 if [ "$code" = "0" ]; then echo "操作已取消。" return 0 # 正常退出函数 @@ -10226,7 +10284,7 @@ moltbot_menu() { } nano_openclaw_json() { - send_stats "編輯 OpenClaw 配置文件" + send_stats "編輯 OpenClaw 設定檔" install nano nano ~/.openclaw/openclaw.json start_tmux @@ -10260,23 +10318,23 @@ moltbot_menu() { local local_ip token domains echo "==================================" - echo "OpenClaw WebUI 訪問地址" + echo "OpenClaw WebUI 存取位址" local_ip="127.0.0.1" token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) echo echo "本機地址:" - echo "http://${local_ip}:18789/?token=${token}" + echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "域名地址:" + echo "網域地址:" echo "$domains" | while read d; do - echo "https://${d}/?token=${token}" + echo "https://${d}/#token=${token}" done fi @@ -10285,23 +10343,23 @@ moltbot_menu() { - # 添加域名(調用你給的函數) + # 新增網域(呼叫你給的函數) openclaw_domain_webui() { add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 18789 token=$( openclaw dashboard 2>/dev/null \ - | sed -n 's/.*:18789\/?token=\([a-f0-9]\+\).*/\1/p' \ + | sed -n 's/.*:18789\/#token=\([a-f0-9]\+\).*/\1/p' \ | head -n 1 ) clear echo "訪問地址:" - echo "https://${yuming}/?token=$token" - echo "先訪問URL觸發設備ID,然後回車下一步進行配對。" + echo "https://${yuming}/#token=$token" + echo "先造訪URL觸發設備ID,然後回車下一步進行配對。" read - echo -e "${gl_kjlan}正在加載設備列表……${gl_bai}" + echo -e "${gl_kjlan}正在載入設備列表…${gl_bai}" openclaw devices list read -e -p "請輸入 Request_Key:" Request_Key @@ -10317,20 +10375,20 @@ moltbot_menu() { # 刪除域名 openclaw_remove_domain() { - echo "域名格式 example.com 不帶https://" + echo "網域格式 example.com 不含https://" web_del } - # 主菜單 + # 主選單 openclaw_webui_menu() { - send_stats "WebUI訪問與設置" + send_stats "WebUI存取與設定" while true; do clear openclaw_show_webui_addr echo - echo "1. 添加域名訪問" - echo "2. 刪除域名訪問" + echo "1. 添加網域訪問" + echo "2. 刪除網域名稱訪問" echo "0. 退出" echo read -e -p "請選擇:" choice @@ -10339,11 +10397,11 @@ moltbot_menu() { 1) openclaw_domain_webui echo - read -p "按回車返回菜單..." + read -p "按回車返回選單..." ;; 2) openclaw_remove_domain - read -p "按回車返回菜單..." + read -p "按回車返回選單..." ;; 0) break @@ -10373,7 +10431,7 @@ moltbot_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初始化配置嚮導" + 11) send_stats "初始化配置精靈" openclaw onboard --install-daemon break_end ;; @@ -10400,7 +10458,7 @@ local sub_choice="$1" clear cd ~ install git -echo -e "${gl_kjlan}正在更新應用列表請稍等……${gl_bai}" +echo -e "${gl_kjlan}正在更新應用程式清單請稍等…${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -10418,7 +10476,7 @@ while true; do local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循環設置顏色 + # 用循環設定顏色 for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -10428,31 +10486,31 @@ while true; do done echo -e "${gl_kjlan}1. ${color1}寶塔面板官方版${gl_kjlan}2. ${color2}aaPanel寶塔國際版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager可視化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存儲文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠程桌面網頁版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager視覺化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多重儲存文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠端桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io郵件服務器程序${gl_kjlan}10. ${color10}RocketChat多人在線聊天系統" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}禪道項目管理軟件${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" + echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟件${gl_kjlan}18. ${color18}onlyoffice在線辦公OFFICE" + echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" - echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠程桌面網頁版${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud網盤${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆棧管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相冊系統" + echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜尋站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相簿系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的在線圖表軟件${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播錄製工具${gl_kjlan}40. ${color40}webssh網頁版SSH連接工具" + echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠程連接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk遠程桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠程桌面(中繼端)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" @@ -10463,50 +10521,50 @@ while true; do echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}61. ${color61}在線翻譯服務器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自託管AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp視頻下載工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL證書管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" + echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自架AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp影片下載工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo檔案傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂服務器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" - echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}在線DOS老遊戲" - echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智能文檔管理系統" - echo -e "${gl_kjlan}79. ${color79}Beszel服務器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" + echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}線上DOS老遊戲" + echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智慧文件管理系統" + echo -e "${gl_kjlan}79. ${color79}Beszel伺服器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet視頻會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服務器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" - echo -e "${gl_kjlan}85. ${color85}immich圖片視頻管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自託管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet視訊會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari伺服器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" + echo -e "${gl_kjlan}85. ${color85}immich圖片影片管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自架直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox檔案快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態文件服務器${gl_kjlan}94. ${color94}Gopeed高速下載工具" - echo -e "${gl_kjlan}95. ${color95}paperless文檔管理平台${gl_kjlan}96. ${color96}2FAuth自託管二步驗證器" + echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" + echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" - echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點文件同步工具" + echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI視頻生成工具${gl_kjlan}102. ${color102}VoceChat多人在線聊天系統" - echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉發工具" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" - echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜索${gl_kjlan}108. ${color108}LangBot聊天機器人" - echo -e "${gl_kjlan}109. ${color109}ZFile在線網盤${gl_kjlan}110. ${color110}Karakeep書籤管理" + echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" + echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" + echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}ClawdBot/Moltbot機器人${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方應用列表" - echo -e "${gl_kjlan}想要讓你的應用出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}第三方應用程式列表" + echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) - # 獲取應用描述 + # 取得應用描述 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") # 檢查安裝狀態 (匹配 appno.txt 中的 ID) - # 這裡假設 appno.txt 中記錄的是 base_name (即文件名) + # 這裡假設 appno.txt 中記錄的是 base_name (即檔名) if echo "$app_numbers" | grep -q "^$base_name$"; then # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" @@ -10521,7 +10579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}b. ${gl_bai}備份全部應用數據${gl_kjlan}r. ${gl_bai}還原全部應用數據" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice fi @@ -10623,9 +10681,9 @@ while true; do } - local docker_describe="一個Nginx反向代理工具面板,不支持添加域名訪問。" + local docker_describe="一個Nginx反向代理工具面板,不支援新增網域存取。" local docker_url="官網介紹: https://nginxproxymanager.com/" - local docker_use="echo \"初始用戶名: admin@example.com\"" + local docker_use="echo \"初始使用者名稱: admin@example.com\"" local docker_passwd="echo \"初始密碼: changeme\"" local app_size="1" @@ -10658,7 +10716,7 @@ while true; do } - local docker_describe="一個支持多種存儲,支持網頁瀏覽和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驅動" + local docker_describe="一個支援多種存儲,支援網頁瀏覽和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驅動" local docker_url="官網介紹:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" @@ -10676,8 +10734,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "設定登入用戶名:" admin + read -e -p "設定登入用戶密碼:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -10699,7 +10757,7 @@ while true; do } - local docker_describe="webtop基於Ubuntu的容器。若IP無法訪問,請添加域名訪問。" + local docker_describe="webtop基於Ubuntu的容器。若IP無法訪問,請新增網域訪問。" local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -10720,8 +10778,8 @@ while true; do check_docker_image_update $docker_name clear echo -e "哪吒監控$check_docker $update_status" - echo "開源、輕量、易用的服務器監控與運維工具" - echo "官網搭建文檔: https://nezha.wiki/guide/dashboard.html" + echo "開源、輕量、易用的伺服器監控與維運工具" + echo "官網搭建文件: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip @@ -10800,17 +10858,17 @@ while true; do clear echo -e "郵局服務$check_docker $update_status" - echo "poste.io 是一個開源的郵件服務器解決方案," - echo "視頻介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo "poste.io 是一個開源的郵件伺服器解決方案," + echo "影片介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "端口檢測" + echo "連接埠偵測" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口$port當前可用${gl_bai}" + echo -e "${gl_lv}連接埠$port目前可用${gl_bai}" else - echo -e "${gl_hong}端口$port當前不可用${gl_bai}" + echo -e "${gl_hong}連接埠$port目前不可用${gl_bai}" fi echo "" @@ -10821,7 +10879,7 @@ while true; do fi echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -10831,7 +10889,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "請設置郵箱域名 例如 mail.yuming.com :" yuming + read -e -p "請設定郵箱網域名稱 例如 mail.yuming.com :" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -10867,7 +10925,7 @@ while true; do clear echo "poste.io已經安裝完成" echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" + echo "您可以使用以下地址存取poste.io:" echo "https://$yuming" echo "" @@ -10892,7 +10950,7 @@ while true; do clear echo "poste.io已經安裝完成" echo "------------------------" - echo "您可以使用以下地址訪問poste.io:" + echo "您可以使用以下地址存取poste.io:" echo "https://$yuming" echo "" ;; @@ -10903,7 +10961,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用已卸載" + echo "應用程式已解除安裝" ;; *) @@ -10920,7 +10978,7 @@ while true; do local app_id="10" local app_name="Rocket.Chat聊天系統" - local app_text="Rocket.Chat 是一個開源的團隊通訊平台,支持實時聊天、音視頻通話、文件共享等多種功能," + local app_text="Rocket.Chat 是一個開源的團隊通訊平台,支援即時聊天、音訊視訊通話、檔案共享等多種功能," local app_url="官方介紹: https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" @@ -10957,7 +11015,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -10987,9 +11045,9 @@ while true; do } - local docker_describe="禪道是通用的項目管理軟件" + local docker_describe="禪道是通用的專案管理軟體" local docker_url="官網介紹: https://www.zentao.net/" - local docker_use="echo \"初始用戶名: admin\"" + local docker_use="echo \"初始使用者名稱: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -11028,8 +11086,8 @@ while true; do local app_id="13" local app_name="cloudreve網盤" - local app_text="cloudreve是一個支持多家云存儲的網盤系統" - local app_url="視頻介紹: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_text="cloudreve是一個支援多家雲端儲存的網盤系統" + local app_url="影片介紹: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -11055,7 +11113,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -11109,7 +11167,7 @@ while true; do } - local docker_describe="emby是一個主從式架構的媒體服務器軟件,可以用來整理服務器上的視頻和音頻,並將音頻和視頻流式傳輸到客戶端設備" + local docker_describe="emby是一個主從式架構的媒體伺服器軟體,可以用來整理伺服器上的視訊和音頻,並將音頻和視訊串流傳輸到客戶端設備" local docker_url="官網介紹: https://emby.media/" local docker_use="" local docker_passwd="" @@ -11130,7 +11188,7 @@ while true; do } - local docker_describe="Speedtest測速面板是一個VPS網速測試工具,多項測試功能,還可以實時監控VPS進出站流量" + local docker_describe="Speedtest測速面板是VPS網路速度測試工具,多項測試功能,還可以即時監控VPS進出站流量" local docker_url="官網介紹:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -11161,7 +11219,7 @@ while true; do } - local docker_describe="AdGuardHome是一款全網廣告攔截與反跟踪軟件,未來將不止是一個DNS服務器。" + local docker_describe="AdGuardHome是一款全網廣告攔截與反追蹤軟體,未來不只一個DNS伺服器。" local docker_url="官網介紹: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" @@ -11190,7 +11248,7 @@ while true; do } - local docker_describe="onlyoffice是一款開源的在線office工具,太強大了!" + local docker_describe="onlyoffice是一款開源的線上office工具,太強大了!" local docker_url="官網介紹: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -11209,15 +11267,15 @@ while true; do check_docker_app clear echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程序面板,可以反代站點進行自動化防禦" - echo "視頻介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" + echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 重置密碼 4. 卸載" + echo "1. 安裝 2. 更新 3. 重設密碼 4. 解除安裝" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -11255,7 +11313,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默認安裝目錄那現在項目已經卸載。如果你是自定義安裝目錄你需要到安裝目錄下自行執行:" + echo "如果你是預設安裝目錄那現在項目已經卸載。如果你是自訂安裝目錄你需要到安裝目錄下自行執行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -11310,7 +11368,7 @@ while true; do } - local docker_describe="VScode是一款強大的在線代碼編寫工具" + local docker_describe="VScode是一款強大的線上程式碼編寫工具" local docker_url="官網介紹:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" @@ -11338,7 +11396,7 @@ while true; do } - local docker_describe="Uptime Kuma 易於使用的自託管監控工具" + local docker_describe="Uptime Kuma 易於使用的自架監控工具" local docker_url="官網介紹:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" @@ -11358,7 +11416,7 @@ while true; do } - local docker_describe="Memos是一款輕量級、自託管的備忘錄中心" + local docker_describe="Memos是一款輕量、自架的備忘錄中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -11374,8 +11432,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "設定登入用戶名:" admin + read -e -p "設定登入用戶密碼:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -11399,7 +11457,7 @@ while true; do } - local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請添加域名訪問。" + local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -11422,7 +11480,7 @@ while true; do local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" local docker_url="官網介紹: https://nextcloud.com/" - local docker_use="echo \"賬號: nextcloud 密碼:$rootpasswd\"" + local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -11440,7 +11498,7 @@ while true; do } - local docker_describe="QD-Today是一個HTTP請求定時任務自動執行框架" + local docker_describe="QD-Today是HTTP請求定時任務自動執行框架" local docker_url="官網介紹: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" @@ -11505,7 +11563,7 @@ while true; do } - local docker_describe="searxng是一個私有且隱私的搜索引擎站點" + local docker_describe="searxng是一個私有且隱私的搜尋引擎站點" local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" @@ -11537,9 +11595,9 @@ while true; do } - local docker_describe="photoprism非常強大的私有相冊系統" + local docker_describe="photoprism非常強大的私有相簿系統" local docker_url="官網介紹: https://www.photoprism.app/" - local docker_use="echo \"賬號: admin 密碼:$rootpasswd\"" + local docker_use="echo \"帳號: admin 密碼:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -11565,7 +11623,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="這是一個強大的本地託管基於 Web 的 PDF 操作工具,使用 docker,允許您對 PDF 文件執行各種操作,例如拆分合併、轉換、重新組織、添加圖像、旋轉、壓縮等。" + local docker_describe="這是一個強大的本機託管基於 Web 的 PDF 操作工具,使用 docker,可讓您對 PDF 檔案執行各種操作,例如分割合併、轉換、重新組織、新增映像、旋轉、壓縮等。" local docker_url="官網介紹:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -11586,7 +11644,7 @@ while true; do } - local docker_describe="這是一個強大圖表繪製軟件。思維導圖,拓撲圖,流程圖,都能畫" + local docker_describe="這是一個強大圖表繪製軟體。心智圖,拓樸圖,流程圖,都能畫" local docker_url="官網介紹: https://www.drawio.com/" local docker_use="" local docker_passwd="" @@ -11611,9 +11669,9 @@ while true; do } - local docker_describe="Sun-Panel服務器、NAS導航面板、Homepage、瀏覽器首頁" + local docker_describe="Sun-Panel伺服器、NAS導覽面板、Homepage、瀏覽器首頁" local docker_url="官網介紹: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"賬號: admin@sun.cc 密碼: 12345678\"" + local docker_use="echo \"帳號: admin@sun.cc 密碼: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -11635,7 +11693,7 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一個可自建的文件分享平台,是 WeTransfer 的一個替代品" + local docker_describe="Pingvin Share 是一個可自建的文件分享平台,是 WeTransfer 的替代品" local docker_url="官網介紹:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" @@ -11664,7 +11722,7 @@ while true; do local docker_describe="極簡朋友圈,高仿微信朋友圈,記錄你的美好生活" local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"賬號: admin 密碼: a123456\"" + local docker_use="echo \"帳號: admin 密碼: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -11707,7 +11765,7 @@ while true; do } - local docker_describe="是一個多功能IP工具箱,可以查看自己IP信息及連通性,用網頁面板呈現" + local docker_describe="是多功能IP工具箱,可以查看自己IP資訊及連結性,用網頁面板呈現" local docker_url="官網介紹:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" @@ -11741,7 +11799,7 @@ while true; do } - local docker_describe="Bililive-go是一個支持多種直播平台的直播錄製工具" + local docker_describe="Bililive-go是一個支援多種直播平台的直播錄製工具" local docker_url="官網介紹:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" @@ -11758,7 +11816,7 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="簡易在線ssh連接工具和sftp工具" + local docker_describe="簡易線上ssh連線工具和sftp工具" local docker_url="官網介紹:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" @@ -11812,7 +11870,7 @@ while true; do } - local docker_describe="nexterm是一款強大的在線SSH/VNC/RDP連接工具。" + local docker_describe="nexterm是一款強大的線上SSH/VNC/RDP連線工具。" local docker_url="官網介紹:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" @@ -11833,10 +11891,10 @@ while true; do } - local docker_describe="rustdesk開源的遠程桌面(服務端),類似自己的向日葵私服。" + local docker_describe="rustdesk開源的遠端桌面(服務端),類似自己的向日葵私服。" local docker_url="官網介紹: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key記錄下,會在遠程桌面客戶端中用到。去44選項裝中繼端吧!\"" + local docker_passwd="echo \"把你的IP和key記錄下,會在遠端桌面客戶端中用到。去44選項裝中繼端吧!\"" local app_size="1" docker_app ;; @@ -11853,9 +11911,9 @@ while true; do } - local docker_describe="rustdesk開源的遠程桌面(中繼端),類似自己的向日葵私服。" + local docker_describe="rustdesk開源的遠端桌面(中繼端),類似自己的向日葵私服。" local docker_url="官網介紹: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官網下載遠程桌面的客戶端: https://rustdesk.com/zh-cn/\"" + local docker_use="echo \"前往官網下載遠端桌面的客戶端: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -11879,7 +11937,7 @@ while true; do } - local docker_describe="Docker Registry 是一個用於存儲和分發 Docker 鏡像的服務。" + local docker_describe="Docker Registry 是一個用於儲存和分發 Docker 映像的服務。" local docker_url="官網介紹: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" @@ -11923,7 +11981,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始用戶名密碼均為: admin" + echo "初始使用者名稱密碼均為: admin" } docker_app_update() { @@ -11941,7 +11999,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -11964,7 +12022,7 @@ while true; do } - local docker_describe="這是一個普羅米修斯的主機數據採集組件,請部署在被監控主機上。" + local docker_describe="這是一個普羅米修斯的主機資料擷取元件,請部署在被監控主機上。" local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" @@ -11994,7 +12052,7 @@ while true; do } - local docker_describe="這是一個普羅米修斯的容器數據採集組件,請部署在被監控主機上。" + local docker_describe="這是一個普羅米修斯的容器資料擷取元件,請部署在被監控主機上。" local docker_url="官網介紹:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -12017,7 +12075,7 @@ while true; do } - local docker_describe="這是一款網站變化檢測、補貨監控和通知的小工具" + local docker_describe="這是一個網站變更偵測、補貨監控和通知的小工具" local docker_url="官網介紹:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" @@ -12050,7 +12108,7 @@ while true; do } - local docker_describe="Docker可視化面板系統,提供完善的docker管理功能。" + local docker_describe="Docker視覺化面板系統,提供完善的docker管理功能。" local docker_url="官網介紹:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" @@ -12070,7 +12128,7 @@ while true; do } - local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的llama3大語言模型" + local docker_describe="OpenWebUI一款大語言模型網頁框架,連結全新的llama3大語言模型" local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -12122,7 +12180,7 @@ while true; do } - local docker_describe="OpenWebUI一款大語言模型網頁框架,接入全新的DeepSeek R1大語言模型" + local docker_describe="OpenWebUI一款大語言模型網頁框架,連結全新的DeepSeek R1大語言模型" local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" @@ -12134,7 +12192,7 @@ while true; do 58|dify) local app_id="58" local app_name="Dify知識庫" - local app_text="是一款開源的大語言模型(LLM) 應用開發平台。自託管訓練數據用於AI生成" + local app_text="是一款開源的大語言模型(LLM) 應用開發平台。自託管訓練資料用於AI生成" local app_url="官方網站: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" @@ -12168,7 +12226,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12178,7 +12236,7 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型網關與AI資產管理系統" + local app_text="新一代大模型閘道與AI資產管理系統" local app_url="官方網站:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" @@ -12220,7 +12278,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12232,7 +12290,7 @@ while true; do local app_id="60" local app_name="JumpServer開源堡壘機" - local app_text="是一個開源的特權訪問管理 (PAM) 工具,該程序佔用80端口不支持添加域名訪問了" + local app_text="是一個開源的特權存取管理 (PAM) 工具,該程式佔用80連接埠不支援新增網域存取了" local app_url="官方介紹:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12243,7 +12301,7 @@ while true; do clear echo "已經安裝完成" check_docker_app_ip - echo "初始用戶名: admin" + echo "初始使用者名稱: admin" echo "初始密碼: ChangeMe" } @@ -12251,7 +12309,7 @@ while true; do docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "應用已更新" + echo "應用程式已更新" } @@ -12261,7 +12319,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12283,7 +12341,7 @@ while true; do } - local docker_describe="免費開源機器翻譯 API,完全自託管,它的翻譯引擎由開源Argos Translate庫提供支持。" + local docker_describe="免費開源機器翻譯 API,完全自託管,它的翻譯引擎由開源Argos Translate庫提供支援。" local docker_url="官網介紹:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" @@ -12296,7 +12354,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow知識庫" - local app_text="基於深度文檔理解的開源 RAG(檢索增強生成)引擎" + local app_text="基於深度文件理解的開源 RAG(檢索增強生成)引擎" local app_url="官方網站:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -12324,7 +12382,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12344,7 +12402,7 @@ while true; do } - local docker_describe="OpenWebUI一款大語言模型網頁框架,官方精簡版本,支持各大模型API接入" + local docker_describe="OpenWebUI一款大語言模型網頁框架,官方精簡版本,支援各大模型API接入" local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" @@ -12398,7 +12456,7 @@ while true; do } - local docker_describe="是一款功能強大的自動化工作流平台" + local docker_describe="是一款功能強大的自動化工作流程平台" local docker_url="官網介紹:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" @@ -12427,7 +12485,7 @@ while true; do } - local docker_describe="自動將你的公網 IP(IPv4/IPv6)實時更新到各大 DNS 服務商,實現動態域名解析。" + local docker_describe="自動將你的公網 IP(IPv4/IPv6)即時更新到各大 DNS 服務商,實現動態網域解析。" local docker_url="官網介紹:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" @@ -12445,10 +12503,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="開源免費的 SSL 證書自動化管理平台" + local docker_describe="開源免費的 SSL 憑證自動化管理平台" local docker_url="官網介紹: https://allinssl.com" local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用戶名: allinssl 密碼: allinssldocker\"" + local docker_passwd="echo \"使用者名稱: allinssl 密碼: allinssldocker\"" local app_size="1" docker_app ;; @@ -12477,7 +12535,7 @@ while true; do } - local docker_describe="開源免費隨時隨地SFTP FTP WebDAV 文件傳輸工具" + local docker_describe="開源免費隨時隨地SFTP FTP WebDAV 檔案傳輸工具" local docker_url="官網介紹: https://sftpgo.com/" local docker_use="" local docker_passwd="" @@ -12509,9 +12567,9 @@ while true; do } - local docker_describe="開源AI聊天機器人框架,支持微信,QQ,TG接入AI大模型" + local docker_describe="開源AI聊天機器人框架,支援微信,QQ,TG接入AI大模型" local docker_url="官網介紹: https://astrbot.app/" - local docker_use="echo \"用戶名: astrbot 密碼: astrbot\"" + local docker_use="echo \"使用者名稱: astrbot 密碼: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -12538,7 +12596,7 @@ while true; do } - local docker_describe="是一個輕量、高性能的音樂流媒體服務器" + local docker_describe="是一個輕量、高效能的音樂串流伺服器" local docker_url="官網介紹: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -12565,8 +12623,8 @@ while true; do } - local docker_describe="一個你可以控制數據的密碼管理器" - local docker_url="官網介紹: https://bitwarden.com/" + local docker_describe="一個你可以控制資料的密碼管理器" + local docker_url="官網導論: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -12586,7 +12644,7 @@ while true; do docker_rum() { - read -e -p "設置LibreTV的登錄密碼:" app_passwd + read -e -p "設定LibreTV的登入密碼:" app_passwd docker run -d \ --name libretv \ @@ -12597,7 +12655,7 @@ while true; do } - local docker_describe="免費在線視頻搜索與觀看平台" + local docker_describe="免費線上影片搜尋與觀看平台" local docker_url="官網介紹:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" @@ -12613,15 +12671,15 @@ while true; do local app_id="74" local app_name="moontv私有影視" - local app_text="免費在線視頻搜索與觀看平台" - local app_url="視頻介紹:${gh_https_url}github.com/MoonTechLab/LunaTV" + local app_text="免費線上影片搜尋與觀看平台" + local app_url="影片介紹:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" docker_app_install() { - read -e -p "設置登錄用戶名:" admin - read -e -p "設置登錄用戶密碼:" admin_password + read -e -p "設定登入用戶名:" admin + read -e -p "設定登入用戶密碼:" admin_password read -e -p "輸入授權碼:" shouquanma @@ -12652,7 +12710,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12706,7 +12764,7 @@ while true; do } - local docker_describe="是一個中文DOS遊戲合集網站" + local docker_describe="是一個中文DOS遊戲收藏網站" local docker_url="官網介紹:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" @@ -12725,8 +12783,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" app_use - read -e -p "設置登錄密碼:" app_passwd + read -e -p "設定登入用戶名:" app_use + read -e -p "設定登入密碼:" app_passwd docker run -d \ --name xunlei \ @@ -12743,7 +12801,7 @@ while true; do local docker_describe="迅雷你的離線高速BT磁力下載工具" local docker_url="官網介紹:${gh_https_url}github.com/cnk3x/xunlei" - local docker_use="echo \"手機登錄迅雷,再輸入邀請碼,邀請碼: 迅雷牛通\"" + local docker_use="echo \"手機登入迅雷,再輸入邀請碼,邀請碼: 迅雷牛通\"" local docker_passwd="" local app_size="1" docker_app @@ -12756,7 +12814,7 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驅動的開源智能文檔管理系統,強烈建議不要自定義端口部署。" + local app_text="PandaWiki是一款以AI大模型驅動的開源智慧文件管理系統,強烈建議不要自訂連接埠部署。" local app_url="官方介紹:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" @@ -12799,7 +12857,7 @@ while true; do } - local docker_describe="Beszel輕量易用的服務器監控" + local docker_describe="Beszel輕易易用的伺服器監控" local docker_url="官網介紹: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" @@ -12813,7 +12871,7 @@ while true; do local app_id="80" local app_name="linkwarden書籤管理" - local app_text="一個開源的自託管書籤管理平台,支持標籤、搜索和團隊協作。" + local app_text="一個開源的自架書籤管理平台,支援標籤、搜尋和團隊協作。" local app_url="官方網站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -12827,7 +12885,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成隨機密鑰與密碼 + # 產生隨機密鑰與密碼 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -12836,7 +12894,7 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理員賬號信息 + # 追加管理員帳號資訊 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env @@ -12856,7 +12914,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的變量 + # 保留原本的變數 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -12873,7 +12931,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12884,8 +12942,8 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet視頻會議" - local app_text="一個開源的安全視頻會議解決方案,支持多人在線會議、屏幕共享與加密通信。" + local app_name="JitsiMeet視訊會議" + local app_text="一個開源的安全視訊會議解決方案,支援多人線上會議、螢幕分享與加密通訊。" local app_url="官方網站: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" @@ -12923,7 +12981,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -12941,7 +12999,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登錄密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -12952,7 +13010,7 @@ while true; do } - local docker_describe="高性能AI接口透明代理服務" + local docker_describe="高效能AI介面透明代理服務" local docker_url="官網介紹: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" @@ -12985,9 +13043,9 @@ while true; do } - local docker_describe="輕量級的自託管服務器監控工具" + local docker_describe="輕量級的自架伺服器監控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默認賬號: admin 默認密碼: 1212156\"" + local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -13016,7 +13074,7 @@ while true; do } - local docker_describe="開源個人訂閱追踪器,可用於財務管理" + local docker_describe="開源個人訂閱追蹤器,可用於財務管理" local docker_url="官網介紹:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" @@ -13028,8 +13086,8 @@ while true; do 85|immich) local app_id="85" - local app_name="immich圖片視頻管理器" - local app_text="高性能自託管照片和視頻管理解決方案。" + local app_name="immich圖片影片管理器" + local app_text="高效能自架照片和影片管理解決方案。" local app_url="官網介紹:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" @@ -13059,7 +13117,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13094,7 +13152,7 @@ while true; do } - local docker_describe="是一款開源媒體服務器軟件" + local docker_describe="是一款開源媒體伺服器軟體" local docker_url="官網介紹: https://jellyfin.org/" local docker_use="" local docker_passwd="" @@ -13122,9 +13180,9 @@ while true; do } - local docker_describe="遠程一起觀看電影和直播的程序。它提供了同步觀影、直播、聊天等功能" + local docker_describe="遠端一起觀看電影和直播的程式。它提供了同步觀影、直播、聊天等功能" local docker_url="官網介紹:${gh_https_url}github.com/synctv-org/synctv" - local docker_use="echo \"初始賬號和密碼: root 登陸後請及時修改登錄密碼\"" + local docker_use="echo \"初始帳號與密碼: root 登陸後請及時修改登入密碼\"" local docker_passwd="" local app_size="1" docker_app @@ -13155,7 +13213,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" - local docker_passwd="echo \"初始賬號: admin 初始密碼: abc123 登陸後請及時修改登錄密碼\"" + local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" local app_size="1" docker_app @@ -13181,7 +13239,7 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快遞一樣取文件" + local docker_describe="匿名口令分享文字和文件,像拿快遞一樣取文件" local docker_url="官網介紹:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"訪問地址後面帶 /#/admin 訪問管理員頁面\"" local docker_passwd="echo \"管理員密碼: FileCodeBox2023\"" @@ -13220,7 +13278,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "創建初始用戶或管理員。請設置以下內容用戶名和密碼以及是否為管理員。" + echo "建立初始使用者或管理員。請設定以下內容使用者名稱和密碼以及是否為管理員。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -13252,9 +13310,9 @@ while true; do local app_id="91" - local app_name="gitea私有代碼倉庫" - local app_text="免費新一代的代碼託管平台,提供接近 GitHub 的使用體驗。" - local app_url="視頻介紹:${gh_https_url}github.com/go-gitea/gitea" + local app_name="gitea私有程式碼倉庫" + local app_text="免費新一代的程式碼託管平台,提供接近 GitHub 的使用體驗。" + local app_url="影片介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -13286,7 +13344,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13343,7 +13401,7 @@ while true; do } - local docker_describe="極簡靜態文件服務器,支持上傳下載" + local docker_describe="極簡靜態檔案伺服器,支援上傳下載" local docker_url="官網介紹:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" @@ -13361,8 +13419,8 @@ while true; do docker_rum() { - read -e -p "設置登錄用戶名:" app_use - read -e -p "設置登錄密碼:" app_passwd + read -e -p "設定登入用戶名:" app_use + read -e -p "設定登入密碼:" app_passwd docker run -d \ --name ${docker_name} \ @@ -13374,7 +13432,7 @@ while true; do } - local docker_describe="分佈式高速下載工具,支持多種協議" + local docker_describe="分散式高速下載工具,支援多種協議" local docker_url="官網介紹:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -13389,9 +13447,9 @@ while true; do local app_id="95" - local app_name="paperless文檔管理平台" - local app_text="開源的電子文檔管理系統,它的主要用途是把你的紙質文件數字化並管理起來。" - local app_url="視頻介紹: https://docs.paperless-ngx.com/" + local app_name="paperless文件管理平台" + local app_text="開源的電子文件管理系統,它的主要用途是把你的紙本文件數位化並管理起來。" + local app_url="影片介紹: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -13424,7 +13482,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13437,8 +13495,8 @@ while true; do local app_id="96" - local app_name="2FAuth自託管二步驗證器" - local app_text="自託管的雙重身份驗證 (2FA) 賬戶管理和驗證碼生成工具。" + local app_name="2FAuth自架二步驟驗證器" + local app_text="自託管的雙重身分驗證 (2FA) 帳戶管理和驗證碼產生工具。" local app_url="官網:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" @@ -13478,7 +13536,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13496,9 +13554,9 @@ while true; do docker_rum() { - read -e -p "請輸入組網的客戶端數量 (默認 5):" COUNT + read -e -p "請輸入組網的用戶端數量 (預設 5):" COUNT COUNT=${COUNT:-5} - read -e -p "請輸入 WireGuard 網段 (默認 10.13.13.0):" NETWORK + read -e -p "請輸入 WireGuard 網段 (預設 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -13576,15 +13634,15 @@ while true; do docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可以快速連接網絡${gl_bai}" - echo -e "${gl_lv}2. Windows下載客戶端,複製配置代碼連接網絡。${gl_bai}" - echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製配置代碼連接網絡。${gl_bai}" + echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可快速連接網絡${gl_bai}" + echo -e "${gl_lv}2. Windows下載客戶端,複製設定碼連接網路。${gl_bai}" + echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製設定碼連接網路。${gl_bai}" echo -e "${gl_lv}官方客戶端下載方式: https://www.wireguard.com/install/${gl_bai}" break_end } - local docker_describe="現代化、高性能的虛擬專用網絡工具" + local docker_describe="現代化、高效能的虛擬專用網路工具" local docker_url="官網介紹: https://www.wireguard.com/" local docker_use="" local docker_passwd="" @@ -13607,16 +13665,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 創建目錄(如果不存在) + # 建立目錄(如果不存在) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "請粘貼你的客戶端配置,連續按兩次回車保存:" + echo "請貼上你的客戶端配置,連續按兩次回車保存:" - # 初始化變量 + # 初始化變數 input="" empty_line_count=0 - # 逐行讀取用戶輸入 + # 逐行讀取使用者輸入 while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -13629,10 +13687,10 @@ while true; do fi done - # 寫入配置文件 + # 寫入設定檔 echo "$input" > "$CONFIG_FILE" - echo "客戶端配置已保存到$CONFIG_FILE" + echo "客戶端配置已儲存到$CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -13654,7 +13712,7 @@ while true; do } - local docker_describe="現代化、高性能的虛擬專用網絡工具" + local docker_describe="現代化、高效能的虛擬專用網路工具" local docker_url="官網介紹: https://www.wireguard.com/" local docker_use="" local docker_passwd="" @@ -13677,10 +13735,10 @@ while true; do docker_app_install() { - read -e -p "設置 CPU 核數 (默認 2):" CPU_CORES + read -e -p "設定 CPU 核數 (預設 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "設置內存大小 (默認 4G):" RAM_SIZE + read -e -p "設定記憶體大小 (預設 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -13711,7 +13769,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13740,7 +13798,7 @@ while true; do syncthing/syncthing:latest } - local docker_describe="開源的點對點文件同步工具,類似於 Dropbox、Resilio Sync,但完全去中心化。" + local docker_describe="開源的點對點檔案同步工具,類似 Dropbox、Resilio Sync,但完全去中心化。" local docker_url="官網介紹:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" @@ -13752,8 +13810,8 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI視頻生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短視頻的工具" + local app_name="AI影片生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13782,7 +13840,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13808,7 +13866,7 @@ while true; do } - local docker_describe="是一款支持獨立部署的個人云社交媒體聊天服務" + local docker_describe="是一款支援獨立部署的個人雲端社群媒體聊天服務" local docker_url="官網介紹:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" @@ -13821,7 +13879,7 @@ while true; do 103|umami) local app_id="103" local app_name="Umami網站統計工具" - local app_text="開源、輕量、隱私友好的網站分析工具,類似於GoogleAnalytics。" + local app_text="開源、輕量、隱私友善的網站分析工具,類似GoogleAnalytics。" local app_url="官方網站:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" @@ -13836,7 +13894,7 @@ while true; do clear echo "已經安裝完成" check_docker_app_ip - echo "初始用戶名: admin" + echo "初始使用者名稱: admin" echo "初始密碼: umami" } @@ -13851,7 +13909,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -13872,7 +13930,7 @@ while true; do docker_rum() { - read -e -p "設置登錄密碼:" app_passwd + read -e -p "設定登入密碼:" app_passwd docker run -d \ --name siyuan \ @@ -13914,7 +13972,7 @@ while true; do } - local docker_describe="是一款強大的開源白板工具,集成思維導圖、流程圖等。" + local docker_describe="是一款強大的開源白板工具,整合心智圖、流程圖等。" local docker_url="官網介紹:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" @@ -13949,7 +14007,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一個高性能的網盤資源搜索API服務。" + local docker_describe="PanSou是一個高效能的網盤資源搜尋API服務。" local docker_url="官網介紹:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" @@ -13964,7 +14022,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" local app_name="LangBot聊天機器人" - local app_text="是一個開源的大語言模型原生即時通信機器人開發平台" + local app_text="是一個開源的大語言模式原生即時通訊機器人開發平台" local app_url="官方網站:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" @@ -13992,7 +14050,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -14021,7 +14079,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一個適用於個人或小團隊的在線網盤程序。" + local docker_describe="是一個適用於個人或小型團隊的線上網盤程式。" local docker_url="官網介紹:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" @@ -14034,7 +14092,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" local app_name="karakeep書籤管理" - local app_text="是一款可自行託管的書籤應用,帶有人工智能功能,專為數據囤積者而設計。" + local app_text="是一款可自行託管的書籤應用,具有人工智慧功能,專為資料囤積者而設計。" local app_url="官方網站:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" @@ -14062,7 +14120,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "應用已卸載" + echo "應用程式已解除安裝" } docker_app_plus @@ -14087,7 +14145,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一個功能強大的多格式文件轉換工具(支持文檔、圖像、音頻視頻等)強烈建議添加域名訪問" + local docker_describe="是一個功能強大的多格式文件轉換工具(支援文件、圖像、音訊視訊等)強烈建議添加域名訪問" local docker_url="項目地址:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -14102,7 +14160,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由於 Lucky 使用 host 網絡模式,這裡的端口僅作記錄/說明參考,實際由應用自身控制(默認16601) + # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) local docker_port=8112 docker_rum() { @@ -14119,9 +14177,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="Lucky 是一個大內網穿透及端口轉發管理工具,支持 DDNS、反向代理、WOL 等功能。" + local docker_describe="Lucky 是一個大內部網路穿透及連接埠轉送管理工具,支援 DDNS、反向代理、WOL 等功能。" local docker_url="項目地址:${gh_https_url}github.com/gdy666/lucky" - local docker_use="echo \"默認賬號密碼: 666\"" + local docker_use="echo \"預設帳號密碼: 666\"" local docker_passwd="" local app_size="1" docker_app @@ -14138,7 +14196,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_rum() { - read -e -p "設置登錄密碼:" admin_password + read -e -p "設定登入密碼:" admin_password docker run -d --name=${docker_name} --restart=always \ -p ${docker_port}:5800 \ @@ -14149,7 +14207,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支持通過網頁直接訪問桌面版瀏覽器界面。" + local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支援透過網頁直接存取桌面版瀏覽器介面。" local docker_url="項目地址:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -14165,7 +14223,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ b) clear - send_stats "全部應用備份" + send_stats "全部應用程式備份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_kjlan}正在備份$backup_filename ...${gl_bai}" @@ -14173,16 +14231,16 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ while true; do clear - echo "備份文件已創建: /$backup_filename" - read -e -p "要傳送備份數據到遠程服務器嗎? (Y/N):" choice + echo "備份檔案已建立: /$backup_filename" + read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "請輸入遠端服務器IP:" remote_ip - read -e -p "目標服務器SSH端口 [默認22]:" TARGET_PORT + read -e -p "請輸入遠端伺服器IP:" remote_ip + read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT local TARGET_PORT=${TARGET_PORT:-22} if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" + echo "錯誤: 請輸入遠端伺服器IP。" continue fi local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -14190,14 +14248,14 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已傳送至遠程服務器/根目錄。" + echo "檔案已傳送至遠端伺服器/根目錄。" else echo "未找到要傳送的文件。" fi break ;; *) - echo "注意: 目前備份僅包含docker項目,不包含寶塔,1panel等建站面板的數據備份。" + echo "注意: 目前備份僅包含docker項目,不包含寶塔,1panel等建站面板的資料備份。" break ;; esac @@ -14208,26 +14266,26 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "全部應用還原" - echo "可用的應用備份" + echo "可用的應用程式備份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份文件名還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用戶沒有輸入文件名,使用最新的壓縮包 + # 如果使用者沒有輸入檔名,使用最新的壓縮包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_kjlan}正在解壓$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "應用數據已還原,目前請手動進入指定應用菜單,更新應用,即可還原應用。" + echo "應用資料已還原,目前請手動進入指定應用程式選單,更新應用,即可還原應用程式。" else echo "沒有找到壓縮包。" fi @@ -14251,7 +14309,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -f "$custom_app" ]; then . "$custom_app" else - echo -e "${gl_hong}錯誤: 未找到編號為${sub_choice}的應用配置${gl_bai}" + echo -e "${gl_hong}錯誤: 未找到編號為${sub_choice}的應用程式配置${gl_bai}" fi ;; esac @@ -14269,11 +14327,11 @@ linux_work() { clear send_stats "後台工作區" echo -e "後台工作區" - echo -e "系統將為你提供可以後台常駐運行的工作區,你可以用來執行長時間的任務" - echo -e "即使你斷開SSH,工作區中的任務也不會中斷,後台常駐任務。" - echo -e "${gl_huang}提示:${gl_bai}進入工作區後使用Ctrl+b再單獨按d,退出工作區!" + echo -e "系統將為你提供可以後台常駐運作的工作區,你可以用來執行長時間的任務" + echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" + echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" - echo "當前已存在的工作區列表" + echo "目前已存在的工作區列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" @@ -14290,10 +14348,10 @@ linux_work() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐模式${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}創建/進入工作區" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到後台工作區" + echo -e "${gl_kjlan}23. ${gl_bai}注入指令到後台工作區" echo -e "${gl_kjlan}24. ${gl_bai}刪除指定工作區" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -14381,9 +14439,9 @@ linux_work() { fi send_stats "SSH常駐模式" echo -e "SSH常駐模式${tmux_sshd_status}" - echo "開啟後SSH連接後會直接進入常駐模式,直接回到之前的工作狀態。" + echo "開啟後SSH連線後會直接進入常駐模式,直接回到先前的工作狀態。" echo "------------------------" - echo "1. 開啟 2. 關閉" + echo "1. 開啟 2. 關閉" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -14409,16 +14467,16 @@ linux_work() { ;; 22) - read -e -p "請輸入你創建或進入的工作區名稱,如1​​001 kj001 work1:" SESSION_NAME + read -e -p "請輸入你所建立或進入的工作區名稱,如1​​001 kj001 work1:" SESSION_NAME tmux_run - send_stats "自定義工作區" + send_stats "自訂工作區" ;; 23) - read -e -p "請輸入你要後台執行的命令,如:curl -fsSL https://get.docker.com | sh:" tmuxd + read -e -p "請輸入你要後台執行的指令,如:curl -fsSL https://get.docker.com | sh:" tmuxd tmux_run_d - send_stats "注入命令到後台工作區" + send_stats "注入指令到後台工作區" ;; 24) @@ -14450,20 +14508,20 @@ linux_work() { -# 智能切換鏡像源函數 +# 智慧切換鏡像來源函數 switch_mirror() { - # 可選參數,默認為 false + # 可選參數,預設為 false local upgrade_software=${1:-false} local clean_cache=${2:-false} - # 獲取用戶國家 + # 取得用戶國家 local country country=$(curl -s ipinfo.io/country) echo "檢測到國家:$country" if [ "$country" = "CN" ]; then - echo "使用國內鏡像源..." + echo "使用國內鏡像來源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.huaweicloud.com \ --protocol https \ @@ -14475,7 +14533,7 @@ switch_mirror() { --install-epel false \ --pure-mode else - echo "使用海外鏡像源..." + echo "使用海外鏡像來源..." if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ @@ -14516,7 +14574,7 @@ fail2ban_panel() { echo "1. 安裝防禦程序" echo "------------------------" echo "2. 查看SSH攔截記錄" - echo "3. 日誌實時監控" + echo "3. 日誌即時監控" echo "------------------------" echo "9. 卸載防禦程序" echo "------------------------" @@ -14560,10 +14618,10 @@ fail2ban_panel() { net_menu() { - send_stats "網卡管理工具" + send_stats "網路卡管理工具" show_nics() { - echo "================ 當前網卡信息 ================" - printf "%-18s %-12s %-20s %-26s\n" "網卡名" "狀態" "IP地址" "MAC地址" + echo "================ 目前網卡資訊 ==================" + printf "%-18s %-12s %-20s %-26s\n" "網路卡名" "狀態" "IP位址" "MAC位址" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -14578,11 +14636,11 @@ net_menu() { clear show_nics echo - echo "=========== 網卡管理菜單 ===========" + echo "=========== 網路卡管理選單 ===========" echo "1. 啟用網卡" - echo "2. 禁用網卡" + echo "2. 停用網路卡" echo "3. 查看網卡詳細信息" - echo "4. 刷新網卡信息" + echo "4. 刷新网卡信息" echo "0. 返回上一級選單" echo "====================================" read -erp "請選擇操作:" choice @@ -14590,38 +14648,38 @@ net_menu() { case $choice in 1) send_stats "啟用網卡" - read -erp "請輸入要啟用的網卡名:" nic + read -erp "請輸入要啟用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 網卡$nic已啟用" + ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else - echo "✘ 網卡不存在" + echo "✘ 網路卡不存在" fi read -erp "按回車繼續..." ;; 2) - send_stats "禁用網卡" - read -erp "請輸入要禁用的網卡名:" nic + send_stats "停用網路卡" + read -erp "請輸入要停用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" down && echo "✔ 網卡$nic已禁用" + ip link set "$nic" down && echo "✔ 網路卡$nic已停用" else - echo "✘ 網卡不存在" + echo "✘ 網路卡不存在" fi read -erp "按回車繼續..." ;; 3) send_stats "查看網卡詳情" - read -erp "請輸入要查看的網卡名:" nic + read -erp "請輸入要查看的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - echo "========== $nic詳細信息 ==========" + echo "========== $nic詳細資訊 ==========" ip addr show "$nic" ethtool "$nic" 2>/dev/null | head -n 10 else - echo "✘ 網卡不存在" + echo "✘ 網路卡不存在" fi read -erp "按回車繼續..." ;; 4) - send_stats "刷新網卡信息" + send_stats "刷新網卡資訊" continue ;; *) @@ -14638,7 +14696,7 @@ log_menu() { show_log_overview() { echo "============= 系統日誌概覽 =============" - echo "主機名: $(hostname)" + echo "主機名稱: $(hostname)" echo "系統時間: $(date)" echo echo "[ /var/log 目錄佔用 ]" @@ -14653,11 +14711,11 @@ log_menu() { clear show_log_overview echo - echo "=========== 系統日誌管理菜單 ===========" + echo "=========== 系統日誌管理選單 ===========" echo "1. 查看最近系統日誌(journal)" echo "2. 查看指定服務日誌" - echo "3. 查看登錄/安全日誌" - echo "4. 實時跟踪日誌" + echo "3. 查看登入/安全日誌" + echo "4. 即時追蹤日誌" echo "5. 清理舊 journal 日誌" echo "0. 返回上一級選單" echo "=======================================" @@ -14666,14 +14724,14 @@ log_menu() { case $choice in 1) send_stats "查看最近日誌" - read -erp "查看最近多少行日誌? [默認 100]:" lines + read -erp "查看最近多少行日誌? [預設 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "按回車繼續..." ;; 2) send_stats "查看指定服務日誌" - read -erp "請輸入服務名(如 sshd、nginx):" svc + read -erp "請輸入服務名稱(如 sshd、nginx):" svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else @@ -14682,8 +14740,8 @@ log_menu() { read -erp "按回車繼續..." ;; 3) - send_stats "查看登錄/安全日誌" - echo "====== 最近登錄日誌 ======" + send_stats "查看登入/安全日誌" + echo "====== 最近登入日誌 ======" last -n 10 echo echo "====== 認證日誌 ======" @@ -14697,14 +14755,14 @@ log_menu() { read -erp "按回車繼續..." ;; 4) - send_stats "實時跟踪日誌" + send_stats "即時追蹤日誌" echo "1) 系統日誌" echo "2) 指定服務日誌" - read -erp "選擇跟踪類型:" t + read -erp "選擇追蹤類型:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -erp "輸入服務名:" svc + read -erp "輸入服務名稱:" svc journalctl -u "$svc" -f else echo "無效選擇" @@ -14740,13 +14798,13 @@ env_menu() { BASHRC="$HOME/.bashrc" PROFILE="$HOME/.profile" - send_stats "系統變量管理工具" + send_stats "系統變數管理工具" show_env_vars() { clear - send_stats "當前已生效環境變量" - echo "========== 當前已生效環境變量(節選) ==========" - printf "%-20s %s\n" "變量名" "值" + send_stats "目前已生效環境變數" + echo "========== 目前已生效環境變數(節選) ==========" + printf "%-20s %s\n" "變數名" "值" echo "-----------------------------------------------" for v in USER HOME SHELL LANG PWD; do printf "%-20s %s\n" "$v" "${!v}" @@ -14757,7 +14815,7 @@ env_menu() { echo "$PATH" | tr ':' '\n' | nl -ba echo - echo "========== 配置文件中定義的變量(解析) ==========" + echo "========== 設定檔中定義的變數(解析) ==========" parse_file_vars() { local file="$1" @@ -14788,7 +14846,7 @@ env_menu() { view_file() { local file="$1" - send_stats "查看變量文件$file" + send_stats "查看變數文件$file" clear if [ -f "$file" ]; then echo "========== 查看文件:$file ==========" @@ -14802,31 +14860,31 @@ env_menu() { edit_file() { local file="$1" - send_stats "編輯變量文件$file" + send_stats "編輯變數文件$file" install nano nano "$file" } source_files() { - echo "正在重新加載環境變量..." - send_stats "正在重新加載環境變量" + echo "正在重新載入環境變數..." + send_stats "正在重新載入環境變數" source "$BASHRC" source "$PROFILE" - echo "✔ 環境變量已重新加載" + echo "✔ 環境變數已重新載入" read -erp "按回車繼續..." } while true; do clear - echo "=========== 系統環境變量管理 ==========" - echo "當前用戶:$USER" + echo "=========== 系統環境變數管理 ==========" + echo "目前使用者:$USER" echo "--------------------------------------" - echo "1. 查看當前常用環境變量" + echo "1. 查看目前常用環境變數" echo "2. 查看 ~/.bashrc" echo "3. 查看 ~/.profile" echo "4. 編輯 ~/.bashrc" echo "5. 編輯 ~/.profile" - echo "6. 重新加載環境變量(source)" + echo "6. 重新載入環境變數(source)" echo "--------------------------------------" echo "0. 返回上一級選單" echo "--------------------------------------" @@ -14869,7 +14927,7 @@ create_user_with_sshkey() { local sshkey_vl if [[ -z "$new_username" ]]; then - echo "用法:create_user_with_sshkey <用戶名>" + echo "用法:create_user_with_sshkey <使用者名稱>" return 1 fi @@ -14878,12 +14936,12 @@ create_user_with_sshkey() { echo "導入公鑰範例:" echo " - URL: ${gh_https_url}github.com/torvalds.keys" - echo "- 直接粘貼: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + echo "- 直接貼上: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." read -e -p "請導入${new_username}的公鑰:" sshkey_vl case "$sshkey_vl" in http://*|https://*) - send_stats "從 URL 導入 SSH 公鑰" + send_stats "從 URL 匯入 SSH 公鑰" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) @@ -14915,7 +14973,7 @@ EOF passwd -l "$new_username" &>/dev/null restart_ssh - echo "用戶$new_username創建完成" + echo "使用者$new_username創建完成" } @@ -14939,37 +14997,37 @@ linux_Settings() { # send_stats "系統工具" echo -e "系統工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}設置腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登錄密碼" - echo -e "${gl_kjlan}3. ${gl_bai}用戶密碼登錄模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}開放所有端口${gl_kjlan}6. ${gl_bai}修改SSH連接端口" - echo -e "${gl_kjlan}7. ${gl_bai}優化DNS地址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT賬戶創建新賬戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}設定腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登入密碼" + echo -e "${gl_kjlan}3. ${gl_bai}使用者密碼登入模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}開放所有連接埠${gl_kjlan}6. ${gl_bai}修改SSH連接埠" + echo -e "${gl_kjlan}7. ${gl_bai}優化DNS位址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}停用ROOT帳戶建立新帳戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用狀態${gl_kjlan}12. ${gl_bai}修改虛擬內存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用戶管理${gl_kjlan}14. ${gl_bai}用戶/密碼生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火牆高級管理器${gl_kjlan}18. ${gl_bai}修改主機名" - echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新源${gl_kjlan}20. ${gl_bai}定時任務管理" + echo -e "${gl_kjlan}11. ${gl_bai}查看連接埠佔用狀態${gl_kjlan}12. ${gl_bai}修改虛擬記憶體大小" + echo -e "${gl_kjlan}13. ${gl_bai}使用者管理${gl_kjlan}14. ${gl_bai}使用者/密碼產生器" + echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設定BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主機名" + echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新來源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}用戶密鑰登錄模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux內核升級${gl_kjlan}28. ${gl_bai}Linux系統內核參數優化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高風險漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux核心升級${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令行美化工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}設置系統回收站${gl_kjlan}34. ${gl_bai}系統備份與恢復" - echo -e "${gl_kjlan}35. ${gl_bai}ssh遠程連接工具${gl_kjlan}36. ${gl_bai}硬盤分區管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}網卡管理工具" + echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令列美化工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}設定係統回收站${gl_kjlan}34. ${gl_bai}系統備份與復原" + echo -e "${gl_kjlan}35. ${gl_bai}ssh遠端連線工具${gl_kjlan}36. ${gl_bai}硬碟分割區管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令列歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠端同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}網路卡管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}系統日誌管理工具${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系統變量管理工具" + echo -e "${gl_kjlan}41. ${gl_bai}系統日誌管理工具${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系統變數管理工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重啟服務器${gl_kjlan}100. ${gl_bai}隱私與安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高級用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸載科技lion腳本" + echo -e "${gl_kjlan}99. ${gl_bai}重啟伺服器${gl_kjlan}100. ${gl_bai}隱私與安全" + echo -e "${gl_kjlan}101. ${gl_bai}k指令進階用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}解除安裝科技lion腳本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -14977,7 +15035,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "請輸入你的快捷按鍵(輸入0退出):" kuaijiejian + read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -14987,8 +15045,8 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快捷鍵已設置" - send_stats "腳本快捷鍵已設置" + echo "快速鍵已設定" + send_stats "腳本快捷鍵已設定" break_end linux_Settings done @@ -14996,8 +15054,8 @@ linux_Settings() { 2) clear - send_stats "設置你的登錄密碼" - echo "設置你的登錄密碼" + send_stats "設定你的登入密碼" + echo "設定你的登入密碼" passwd ;; 3) @@ -15009,16 +15067,16 @@ linux_Settings() { root_use send_stats "py版本管理" echo "python版本管理" - echo "視頻介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + echo "影片介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "該功能可無縫安裝python官方支持的任何版本!" + echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" + echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" echo "查詢更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "輸入你要安裝的python版本號(輸入0退出):" py_new_v + read -e -p "輸入你要安裝的python版本號碼(輸入0退出):" py_new_v if [[ "$py_new_v" == "0" ]]; then @@ -15055,7 +15113,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "未知的套件管理器!" return fi @@ -15084,17 +15142,17 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "當前python版本號:${gl_huang}$VERSION${gl_bai}" + echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" send_stats "腳本PY版本切換" ;; 5) root_use - send_stats "開放端口" + send_stats "開放埠" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部開放" + echo "連接埠已全部開放" ;; 6) @@ -15105,28 +15163,28 @@ EOF clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 讀取當前的 SSH 端口號 + # 讀取目前的 SSH 連接埠號 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印當前的 SSH 端口號 - echo -e "當前的 SSH 端口號是:${gl_huang}$current_port ${gl_bai}" + # 列印目前的 SSH 連接埠號碼 + echo -e "目前的 SSH 連接埠號碼是:${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口號範圍1到65535之間的數字。 (輸入0退出)" + echo "連接埠號碼範圍1到65535之間的數字。 (輸入0退出)" - # 提示用戶輸入新的 SSH 端口號 - read -e -p "請輸入新的 SSH 端口號:" new_port + # 提示使用者輸入新的 SSH 連接埠號碼 + read -e -p "請輸入新的 SSH 連接埠號碼:" new_port - # 判斷端口號是否在有效範圍內 + # 判斷連接埠號碼是否在有效範圍內 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "退出SSH埠修改" break else - echo "端口號無效,請輸入1到65535之間的數字。" + echo "連接埠號碼無效,請輸入1到65535之間的數字。" send_stats "輸入無效SSH端口" break_end fi @@ -15152,7 +15210,7 @@ EOF 9) root_use send_stats "新用戶禁用root" - read -e -p "請輸入新用戶名(輸入0退出):" new_username + read -e -p "請輸入新使用者名稱(輸入0退出):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -15170,26 +15228,26 @@ EOF 10) root_use - send_stats "設置v4/v6優先級" + send_stats "設定v4/v6優先級" while true; do clear - echo "設置v4/v6優先級" + echo "設定v4/v6優先級" echo "------------------------" if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "當前網絡優先級設置:${gl_huang}IPv4${gl_bai}優先" + echo -e "目前網路優先權設定:${gl_huang}IPv4${gl_bai}優先" else - echo -e "當前網絡優先級設置:${gl_huang}IPv6${gl_bai}優先" + echo -e "目前網路優先權設定:${gl_huang}IPv6${gl_bai}優先" fi echo "" echo "------------------------" - echo "1. IPv4 優先 2. IPv6 優先 3. IPv6 修復工具" + echo "1. IPv4 優先 2. IPv6 優先權 3. IPv6 修復工具" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "選擇優先的網絡:" choice + read -e -p "選擇優先的網路:" choice case $choice in 1) @@ -15204,7 +15262,7 @@ EOF 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "該功能由jhb大神提供,感謝他!" + echo "此功能由jhb大神提供,感謝他!" send_stats "ipv6修復" ;; @@ -15223,17 +15281,17 @@ EOF 12) root_use - send_stats "設置虛擬內存" + send_stats "設定虛擬記憶體" while true; do clear - echo "設置虛擬內存" + echo "設定虛擬記憶體" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "當前虛擬內存:${gl_huang}$swap_info${gl_bai}" + echo -e "當前虛擬記憶體:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定義大小" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自訂大小" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15241,25 +15299,25 @@ EOF case "$choice" in 1) - send_stats "已設置1G虛擬內存" + send_stats "已設定1G虛擬內存" add_swap 1024 ;; 2) - send_stats "已設置2G虛擬內存" + send_stats "已設定2G虛擬內存" add_swap 2048 ;; 3) - send_stats "已設置4G虛擬內存" + send_stats "已設定4G虛擬內存" add_swap 4096 ;; 4) - read -e -p "請輸入虛擬內存大小(單位M):" new_swap + read -e -p "請輸入虛擬記憶體大小(單位M):" new_swap add_swap "$new_swap" - send_stats "已設置自定義虛擬內存" + send_stats "已設定自訂虛擬內存" ;; *) @@ -15272,10 +15330,10 @@ EOF 13) while true; do root_use - send_stats "用戶管理" - echo "用戶列表" + send_stats "使用者管理" + echo "使用者列表" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "用戶權限" "用戶組" "sudo權限" + printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "使用者權限" "使用者群組" "sudo權限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status @@ -15289,13 +15347,13 @@ EOF echo "" - echo "賬戶操作" + echo "帳戶操作" echo "------------------------" - echo "1. 創建普通用戶 2. 創建高級用戶" + echo "1. 建立普通用戶 2. 建立進階用戶" echo "------------------------" - echo "3. 賦予最高權限 4. 取消最高權限" + echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" - echo "5. 刪除賬號" + echo "5. 刪除帳號" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15303,20 +15361,20 @@ EOF case $sub_choice in 1) - # 提示用戶輸入新用戶名 + # 提示使用者輸入新使用者名稱 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false ;; 2) - # 提示用戶輸入新用戶名 + # 提示使用者輸入新使用者名稱 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username true ;; 3) - read -e -p "請輸入用戶名:" username + read -e -p "請輸入使用者名稱:" username install sudo cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f fi sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "請輸入要刪除的用戶名:" username + read -e -p "請輸入要刪除的使用者名稱:" username userdel -r "$username" ;; @@ -15346,21 +15404,21 @@ EOF 14) clear - send_stats "用戶信息生成器" - echo "隨機用戶名" + send_stats "使用者資訊產生器" + echo "隨機使用者名稱" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "隨機用戶名$i: $username" + echo "隨機使用者名稱$i: $username" done echo "" - echo "隨機姓名" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5個隨機用戶姓名 + # 產生5個隨機用戶姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) @@ -15400,37 +15458,37 @@ EOF send_stats "換時區" while true; do clear - echo "系統時間信息" + echo "系統時間資訊" - # 獲取當前系統時區 + # 取得目前系統時區 local timezone=$(current_timezone) - # 獲取當前系統時間 + # 取得目前系統時間 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 顯示時區和時間 - echo "當前系統時區:$timezone" - echo "當前系統時間:$current_time" + echo "目前系統時區:$timezone" + echo "目前系統時間:$current_time" echo "" echo "時區切換" echo "------------------------" echo "亞洲" - echo "1. 中國上海時間 2. 中國香港時間" - echo "3. 日本東京時間 4. 韓國首爾時間" - echo "5. 新加坡時間 6. 印度加爾各答時間" - echo "7. 阿聯酋迪拜時間 8. 澳大利亞悉尼時間" - echo "9. 泰國曼谷時間" + echo "1. 中國上海時間 2. 中國香港時間" + echo "3. 日本東京時間 4. 韓國首爾時間" + echo "5. 新加坡時間 6. 印度加爾各答時間" + echo "7. 阿聯酋杜拜時間 8. 澳洲雪梨時間" + echo "9. 泰國曼谷時間" echo "------------------------" echo "歐洲" - echo "11. 英國倫敦時間 12. 法國巴黎時間" - echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" - echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" + echo "11. 英國倫敦時間 12. 法國巴黎時間" + echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" + echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" echo "------------------------" echo "美洲" - echo "21. 美國西部時間 22. 美國東部時間" - echo "23. 加拿大時間 24. 墨西哥時間" - echo "25. 巴西時間 26. 阿根廷時間" + echo "21. 美國西部時間 22. 美國東部時間" + echo "23. 加拿大時間 24. 墨西哥時間" + echo "25. 巴西時間 26. 阿根廷時間" echo "------------------------" echo "31. UTC全球標準時間" echo "------------------------" @@ -15484,9 +15542,9 @@ EOF while true; do clear local current_hostname=$(uname -n) - echo -e "當前主機名:${gl_huang}$current_hostname${gl_bai}" + echo -e "目前主機名稱:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "請輸入新的主機名(輸入0退出):" new_hostname + read -e -p "請輸入新的主機名稱(輸入0退出):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine @@ -15511,11 +15569,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主機名已更改為:$new_hostname" - send_stats "主機名已更改" + echo "主機名稱已更改為:$new_hostname" + send_stats "主機名稱已更改" sleep 1 else - echo "已退出,未更改主機名。" + echo "已退出,未更改主機名稱。" break fi done @@ -15523,12 +15581,12 @@ EOF 19) root_use - send_stats "換系統更新源" + send_stats "換系統更新來源" clear - echo "選擇更新源區域" - echo "接入LinuxMirrors切換系統更新源" + echo "選擇更新來源區域" + echo "接入LinuxMirrors切換系統更新來源" echo "------------------------" - echo "1. 中國大陸【默認】 2. 中國大陸【教育網】 3. 海外地區 4. 智能切換更新源" + echo "1. 中國大陸【預設】 2. 中國大陸【教育網】 3. 海外地區 4. 智慧切換更新源" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15536,7 +15594,7 @@ EOF case $choice in 1) - send_stats "中國大陸默認源" + send_stats "中國大陸預設來源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -15548,7 +15606,7 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; 4) - send_stats "智能切換更新源" + send_stats "智慧切換更新來源" switch_mirror false false ;; @@ -15571,7 +15629,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 添加定時任務 2. 刪除定時任務 3. 編輯定時任務" + echo "1. 新增定時任務 2. 刪除定時任務 3. 編輯定時任務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15579,10 +15637,10 @@ EOF case $sub_choice in 1) - read -e -p "請輸入新任務的執行命令:" newquest + read -e -p "請輸入新任務的執行指令:" newquest echo "------------------------" - echo "1. 每月任務 2. 每週任務" - echo "3. 每天任務 4. 每小時任務" + echo "1. 每月任務 2. 每週任務" + echo "3. 每天任務 4. 每小時任務" echo "------------------------" read -e -p "請輸入你的選擇:" dingshi @@ -15607,7 +15665,7 @@ EOF break # 跳出 ;; esac - send_stats "添加定時任務" + send_stats "新增定時任務" ;; 2) read -e -p "請輸入需要刪除任務的關鍵字:" kquest @@ -15616,7 +15674,7 @@ EOF ;; 3) crontab -e - send_stats "編輯定時任務" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -15637,7 +15695,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 添加新的解析 2. 刪除解析地址" + echo "1. 新增新的解析 2. 刪除解析位址" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15647,13 +15705,13 @@ EOF 1) read -e -p "請輸入新的解析記錄 格式: 110.25.5.33 kejilion.pro :" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "本機host解析新增" ;; 2) read -e -p "請輸入需要刪除的解析內容關鍵字:" delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析刪除" + send_stats "本機host解析刪除" ;; *) break # 跳出循环,退出菜单 @@ -15673,29 +15731,29 @@ EOF while true; do clear echo "限流關機功能" - echo "視頻介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "影片介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "當前流量使用情況,重啟服務器流量計算會清零!" + echo "目前流量使用情況,重啟伺服器流量計算會清除!" output_status echo -e "${gl_kjlan}總接收:${gl_bai}$rx" echo -e "${gl_kjlan}總發送:${gl_bai}$tx" # 檢查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # 獲取 threshold_gb 的值 + # 取得 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}當前設置的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}當前設置的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}目前設定的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}目前設定的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}當前未啟用限流關機功能${gl_bai}" + echo -e "${gl_hui}目前未啟用限流關機功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "系統每分鐘會檢測實際流量是否到達閾值,到達後會自動關閉服務器!" + echo "系統每分鐘會偵測實際流量是否到達閾值,到達後會自動關閉伺服器!" echo "------------------------" - echo "1. 開啟限流關機功能 2. 停用限流關機功能" + echo "1. 開啟限流關機功能 2. 停用限流關機功能" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -15703,13 +15761,13 @@ EOF case "$Limiting" in 1) - # 輸入新的虛擬內存大小 - echo "如果實際服務器就100G流量,可設置閾值為95G,提前關機,以免出現流量誤差或溢出。" - read -e -p "請輸入進站流量閾值(單位為G,默認100G):" rx_threshold_gb + # 輸入新的虛擬記憶體大小 + echo "若實際伺服器就100G流量,可設定閾值為95G,提前關機,以免出現流量誤差或溢位。" + read -e -p "請輸入進站流量閾值(單位為G,預設100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "請輸入出站流量閾值(單位為G,默認100G):" tx_threshold_gb + read -e -p "請輸入出站流量閾值(單位為G,預設100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "請輸入流量重置日期(默認每月1日重置):" cz_day + read -e -p "請輸入流量重置日期(預設每月1日重設):" cz_day cz_day=${cz_day:-1} cd ~ @@ -15722,8 +15780,8 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流關機已設置" - send_stats "限流關機已設置" + echo "限流關機已設定" + send_stats "限流關機已設定" ;; 2) check_crontab_installed @@ -15748,11 +15806,11 @@ EOF root_use send_stats "電報預警" echo "TG-bot監控預警功能" - echo "視頻介紹: https://youtu.be/vLL-eb3Z_TY" + echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要配置tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬盤,流量,SSH登錄的實時監控預警" - echo "到達閾值後會向用戶發預警消息" - echo -e "${gl_hui}-關於流量,重啟服務器將重新計算-${gl_bai}" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "到達閾值後會向用戶發送預警訊息" + echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in @@ -15779,7 +15837,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # 加入 ~/.profile 檔案中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -15791,7 +15849,7 @@ EOF clear echo "TG-bot預警系統已啟動" - echo -e "${gl_hui}你還可以將root目錄中的TG-check-notify.sh預警文件放到其他機器上直接使用!${gl_bai}" + echo -e "${gl_hui}你也可以將root目錄中的TG-check-notify.sh預警檔案放到其他機器上直接使用!${gl_bai}" ;; [Nn]) echo "已取消" @@ -15804,7 +15862,7 @@ EOF 26) root_use - send_stats "修復SSH高危漏洞" + send_stats "修復SSH高風險漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -15848,7 +15906,7 @@ EOF ;; 37) clear - send_stats "命令行歷史記錄" + send_stats "命令列歷史記錄" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -15888,7 +15946,7 @@ EOF 61) clear send_stats "留言板" - echo "訪問科技lion官方留言板,您對腳本有任何想法歡迎留言交流!" + echo "造訪科技lion官方留言板,您對腳本有任何想法歡迎留言交流!" echo "https://board.kejilion.pro" echo "公共密碼: kejilion.sh" ;; @@ -15900,18 +15958,18 @@ EOF echo "一條龍系統調優" echo "------------------------------------------------" echo "將對以下內容進行操作與優化" - echo "1. 優化系統更新源,更新系統到最新" + echo "1. 最佳化系統更新來源,更新系統到最新" echo "2. 清理系統垃圾文件" - echo -e "3. 設置虛擬內存${gl_huang}1G${gl_bai}" - echo -e "4. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo -e "3. 設定虛擬內存${gl_huang}1G${gl_bai}" + echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo -e "5. 啟動fail2ban防禦SSH暴力破解" echo -e "6. 開放所有端口" echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" - echo -e "8. 設置時區到${gl_huang}上海${gl_bai}" - echo -e "9. 自動優化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 設置網絡為${gl_huang}ipv4優先${gl_bai}" + echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" + echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" + echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux系統內核參數優化切換到${gl_huang}均衡優化模式${gl_bai}" + echo -e "12. Linux系統核心參數優化切換到${gl_huang}均衡最佳化模式${gl_bai}" echo "------------------------------------------------" read -e -p "確定一鍵保養嗎? (Y/N):" choice @@ -15930,11 +15988,11 @@ EOF echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設置虛擬內存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設定虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 - echo -e "[${gl_lv}OK${gl_bai}] 4/12. 設置SSH端口號為${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd cd ~ @@ -15950,14 +16008,14 @@ EOF echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 設置時區到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 設定時區到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自動優化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自動最佳化DNS位址${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 設置網絡為${gl_huang}ipv4優先${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 設定網路為${gl_huang}ipv4優先${gl_bai}}" echo "------------------------------------------------" install_docker @@ -15966,7 +16024,7 @@ EOF echo "------------------------------------------------" optimize_balanced - echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系統內核參數優化" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系統核心參數最佳化" echo -e "${gl_lv}一條龍系統調優已完成${gl_bai}" ;; @@ -15999,10 +16057,10 @@ EOF fi echo "隱私與安全" - echo "腳本將收集用戶使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" + echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" - echo -e "當前狀態:$status_message" + echo -e "目前狀態:$status_message" echo "--------------------" echo "1. 開啟採集" echo "2. 關閉採集" @@ -16015,8 +16073,8 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已開啟採集" - send_stats "隱私與安全已開啟採集" + echo "已開啟擷取" + send_stats "隱私與安全已開啟擷取" ;; 2) cd ~ @@ -16039,8 +16097,8 @@ EOF 102) clear - send_stats "卸載科技lion腳本" - echo "卸載科技lion腳本" + send_stats "解除安裝科技lion腳本" + echo "解除安裝科技lion腳本" echo "------------------------------------------------" echo "將徹底卸載kejilion腳本,不影響你其他功能" read -e -p "確定繼續嗎? (Y/N):" choice @@ -16093,21 +16151,21 @@ linux_file() { clear echo "文件管理器" echo "------------------------" - echo "當前路徑" + echo "目前路徑" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 進入目錄 2. 創建目錄 3. 修改目錄權限 4. 重命名目錄" - echo "5. 刪除目錄 6. 返回上一級選單目錄" + echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" + echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 創建文件 12. 編輯文件 13. 修改文件權限 14. 重命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" - echo "21. 壓縮文件目錄 22. 解壓文件目錄 23. 移動文件目錄 24. 複製文件目錄" - echo "25. 傳文件至其他服務器" + echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" + echo "25. 傳文件至其他伺服器" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一級選單" echo "------------------------" read -e -p "請輸入你的選擇:" Limiting @@ -16118,9 +16176,9 @@ linux_file() { send_stats "進入目錄" ;; 2) # 创建目录 - read -e -p "請輸入要創建的目錄名:" dirname - mkdir -p "$dirname" && echo "目錄已創建" || echo "創建失敗" - send_stats "創建目錄" + read -e -p "請輸入要建立的目錄名稱:" dirname + mkdir -p "$dirname" && echo "目錄已建立" || echo "創建失敗" + send_stats "建立目錄" ;; 3) # 修改目录权限 read -e -p "請輸入目錄名:" dirname @@ -16129,129 +16187,129 @@ linux_file() { send_stats "修改目錄權限" ;; 4) # 重命名目录 - read -e -p "請輸入當前目錄名:" current_name - read -e -p "請輸入新目錄名:" new_name - mv "$current_name" "$new_name" && echo "目錄已重命名" || echo "重命名失敗" - send_stats "重命名目錄" + read -e -p "請輸入目前目錄名稱:" current_name + read -e -p "請輸入新目錄名稱:" new_name + mv "$current_name" "$new_name" && echo "目錄已重新命名" || echo "重新命名失敗" + send_stats "重新命名目錄" ;; 5) # 删除目录 - read -e -p "請輸入要刪除的目錄名:" dirname + read -e -p "請輸入要刪除的目錄名稱:" dirname rm -rf "$dirname" && echo "目錄已刪除" || echo "刪除失敗" send_stats "刪除目錄" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一級選單目錄" + send_stats "返回上一層選單目錄" ;; 11) # 创建文件 - read -e -p "請輸入要創建的文件名:" filename - touch "$filename" && echo "文件已創建" || echo "創建失敗" - send_stats "創建文件" + read -e -p "請輸入要建立的檔案名稱:" filename + touch "$filename" && echo "文件已建立" || echo "創建失敗" + send_stats "建立文件" ;; 12) # 编辑文件 - read -e -p "請輸入要編輯的文件名:" filename + read -e -p "請輸入要編輯的檔名:" filename install nano nano "$filename" send_stats "編輯文件" ;; 13) # 修改文件权限 - read -e -p "請輸入文件名:" filename + read -e -p "請輸入檔名:" filename read -e -p "請輸入權限 (如 755):" perm chmod "$perm" "$filename" && echo "權限已修改" || echo "修改失敗" - send_stats "修改文件權限" + send_stats "修改檔案權限" ;; 14) # 重命名文件 - read -e -p "請輸入當前文件名:" current_name - read -e -p "請輸入新文件名:" new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失敗" - send_stats "重命名文件" + read -e -p "請輸入目前檔名:" current_name + read -e -p "請輸入新檔名:" new_name + mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" + send_stats "重新命名文件" ;; 15) # 删除文件 - read -e -p "請輸入要刪除的文件名:" filename + read -e -p "請輸入要刪除的檔名:" filename rm -f "$filename" && echo "文件已刪除" || echo "刪除失敗" send_stats "刪除文件" ;; 21) # 压缩文件/目录 - read -e -p "請輸入要壓縮的文件/目錄名:" name + read -e -p "請輸入要壓縮的檔案/目錄名稱:" name install tar tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "壓縮失敗" - send_stats "壓縮文件/目錄" + send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓的文件名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "已解壓$filename" || echo "解壓失敗" - send_stats "解壓文件/目錄" + tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" + send_stats "解壓縮檔案/目錄" ;; 23) # 移动文件或目录 - read -e -p "請輸入要移動的文件或目錄路徑:" src_path + read -e -p "請輸入要移動的檔案或目錄路徑:" src_path if [ ! -e "$src_path" ]; then - echo "錯誤: 文件或目錄不存在。" - send_stats "移動文件或目錄失敗: 文件或目錄不存在" + echo "錯誤: 檔案或目錄不存在。" + send_stats "移動檔案或目錄失敗: 檔案或目錄不存在" continue fi - read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path + read -e -p "請輸入目標路徑 (包括新檔案名稱或目錄名稱):" dest_path if [ -z "$dest_path" ]; then echo "錯誤: 請輸入目標路徑。" - send_stats "移動文件或目錄失敗: 目標路徑未指定" + send_stats "移動檔案或目錄失敗: 目標路徑未指定" continue fi - mv "$src_path" "$dest_path" && echo "文件或目錄已移動到$dest_path" || echo "移動文件或目錄失敗" - send_stats "移動文件或目錄" + mv "$src_path" "$dest_path" && echo "檔案或目錄已移動到$dest_path" || echo "移動檔案或目錄失敗" + send_stats "移動檔案或目錄" ;; 24) # 复制文件目录 - read -e -p "請輸入要復制的文件或目錄路徑:" src_path + read -e -p "請輸入要複製的檔案或目錄路徑:" src_path if [ ! -e "$src_path" ]; then - echo "錯誤: 文件或目錄不存在。" - send_stats "複製文件或目錄失敗: 文件或目錄不存在" + echo "錯誤: 檔案或目錄不存在。" + send_stats "複製檔案或目錄失敗: 檔案或目錄不存在" continue fi - read -e -p "請輸入目標路徑 (包括新文件名或目錄名):" dest_path + read -e -p "請輸入目標路徑 (包括新檔案名稱或目錄名稱):" dest_path if [ -z "$dest_path" ]; then echo "錯誤: 請輸入目標路徑。" - send_stats "複製文件或目錄失敗: 目標路徑未指定" + send_stats "複製檔案或目錄失敗: 目標路徑未指定" continue fi - # 使用 -r 選項以遞歸方式複制目錄 - cp -r "$src_path" "$dest_path" && echo "文件或目錄已復製到$dest_path" || echo "複製文件或目錄失敗" - send_stats "複製文件或目錄" + # 使用 -r 選項以遞歸方式複製目錄 + cp -r "$src_path" "$dest_path" && echo "檔案或目錄已複製到$dest_path" || echo "複製檔案或目錄失敗" + send_stats "複製檔案或目錄" ;; 25) # 传送文件至远端服务器 - read -e -p "請輸入要傳送的文件路徑:" file_to_transfer + read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "錯誤: 文件不存在。" send_stats "傳送文件失敗: 文件不存在" continue fi - read -e -p "請輸入遠端服務器IP:" remote_ip + read -e -p "請輸入遠端伺服器IP:" remote_ip if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端服務器IP。" - send_stats "傳送文件失敗: 未輸入遠端服務器IP" + echo "錯誤: 請輸入遠端伺服器IP。" + send_stats "傳送檔案失敗: 未輸入遠端伺服器IP" continue fi - read -e -p "請輸入遠端服務器用戶名 (默認root):" remote_user + read -e -p "請輸入遠端伺服器使用者名稱 (預設root):" remote_user remote_user=${remote_user:-root} - read -e -p "請輸入遠端服務器密碼:" -s remote_password + read -e -p "請輸入遠端伺服器密碼:" -s remote_password echo if [ -z "$remote_password" ]; then - echo "錯誤: 請輸入遠端服務器密碼。" - send_stats "傳送文件失敗: 未輸入遠端服務器密碼" + echo "錯誤: 請輸入遠端伺服器密碼。" + send_stats "傳送檔案失敗: 未輸入遠端伺服器密碼" continue fi - read -e -p "請輸入登錄端口 (默認22):" remote_port + read -e -p "請輸入登入連接埠 (預設22):" remote_port remote_port=${remote_port:-22} # 清除已知主機的舊條目 @@ -16264,7 +16322,7 @@ $remote_password EOF if [ $? -eq 0 ]; then - echo "文件已傳送至遠程服務器home目錄。" + echo "檔案已傳送至遠端伺服器home目錄。" send_stats "文件傳送成功" else echo "文件傳送失敗。" @@ -16277,7 +16335,7 @@ EOF 0) # 返回上一级选单 - send_stats "返回上一級選單菜單" + send_stats "返回上一層選單選單" break ;; *) # 处理无效输入 @@ -16308,10 +16366,10 @@ run_commands_on_servers() { local SERVERS_FILE="$HOME/cluster/servers.py" local SERVERS=$(grep -oP '{"name": "\K[^"]+|"hostname": "\K[^"]+|"port": \K[^,]+|"username": "\K[^"]+|"password": "\K[^"]+' "$SERVERS_FILE") - # 將提取的信息轉換為數組 + # 將提取的資訊轉換為數組 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 遍歷服務器並執行命令 + # 遍歷伺服器並執行命令 for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -16342,58 +16400,58 @@ fi while true; do clear send_stats "集群控制中心" - echo "服務器集群控制" + echo "伺服器叢集控制" cat ~/cluster/servers.py echo echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}服務器列表管理${gl_bai}" - echo -e "${gl_kjlan}1. ${gl_bai}添加服務器${gl_kjlan}2. ${gl_bai}刪除服務器${gl_kjlan}3. ${gl_bai}編輯服務器" - echo -e "${gl_kjlan}4. ${gl_bai}備份集群${gl_kjlan}5. ${gl_bai}還原集群" + echo -e "${gl_kjlan}伺服器清單管理${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}新增伺服器${gl_kjlan}2. ${gl_bai}刪除伺服器${gl_kjlan}3. ${gl_bai}編輯伺服器" + echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}批量執行任務${gl_bai}" + echo -e "${gl_kjlan}批次執行任務${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" - echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設置1G虛擬內存" - echo -e "${gl_kjlan}17. ${gl_bai}設置時區到上海${gl_kjlan}18. ${gl_bai}開放所有端口${gl_kjlan}51. ${gl_bai}自定義指令" + echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" + echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "添加集群服務器" - read -e -p "服務器名稱:" server_name - read -e -p "服務器IP:" server_ip - read -e -p "服務器端口(22):" server_port + send_stats "新增叢集伺服器" + read -e -p "伺服器名稱:" server_name + read -e -p "伺服器IP:" server_ip + read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} - read -e -p "服務器用戶名(root):" server_username + read -e -p "伺服器使用者名稱(root):" server_username local server_username=${server_username:-root} - read -e -p "服務器用戶密碼:" server_password + read -e -p "伺服器用戶密碼:" server_password sed -i "/servers = \[/a\ {\"name\": \"$server_name\", \"hostname\": \"$server_ip\", \"port\": $server_port, \"username\": \"$server_username\", \"password\": \"$server_password\", \"remote_path\": \"/home/\"}," ~/cluster/servers.py ;; 2) - send_stats "刪除集群服務器" + send_stats "刪除叢集伺服器" read -e -p "請輸入需要刪除的關鍵字:" rmserver sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) - send_stats "編輯集群服務器" + send_stats "編輯叢集伺服器" install nano nano ~/cluster/servers.py ;; 4) clear - send_stats "備份集群" - echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai}文件下載,完成備份!" + send_stats "備份叢集" + echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai}檔案下載,完成備份!" break_end ;; 5) clear - send_stats "還原集群" + send_stats "還原叢集" echo "請上傳您的servers.py,按任意鍵開始上傳!" echo -e "請上傳您的${gl_huang}servers.py${gl_bai}文件到${gl_huang}/root/cluster/${gl_bai}完成還原!" break_end @@ -16426,8 +16484,8 @@ while true; do ;; 51) - send_stats "自定義執行命令" - read -e -p "請輸入批量執行的命令:" mingling + send_stats "自訂執行命令" + read -e -p "請輸入批次執行的命令:" mingling run_commands_on_servers "${mingling}" ;; @@ -16450,41 +16508,41 @@ echo "廣告專欄" echo "------------------------" echo "將為用戶提供更簡單優雅的推廣與購買體驗!" echo "" -echo -e "服務器優惠" +echo -e "伺服器優惠" echo "------------------------" echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活動${gl_bai}" echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" -echo -e "${gl_lan}RackNerd 10.99刀每年 美國 1核心 1G內存 20G硬盤 1T流量每月${gl_bai}" +echo -e "${gl_lan}RackNerd 10.99刀每年 美國 1核心 1G記憶體 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" -echo -e "${gl_zi}Hostinger 52.7刀每年 美國 1核心 4G內存 50G硬盤 4T流量每月${gl_bai}" +echo -e "${gl_zi}Hostinger 52.7刀每年 美國 1核心 4G記憶體 50G硬碟 4T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}搬瓦工 49刀每季 美國CN2GIA 日本軟銀 2核心 1G內存 20G硬盤 1T流量每月${gl_bai}" +echo -e "${gl_huang}搬運工 49刀每季 美國CN2GIA 日本軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" -echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G內存 20G硬盤 800G流量每月${gl_bai}" +echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G記憶體 20G硬碟 800G流量每月${gl_bai}" echo -e "${gl_bai}網址: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬盤 1T流量每月${gl_bai}" +echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" -echo -e "域名優惠" +echo -e "網域優惠" echo "------------------------" echo -e "${gl_lan}GNAME 8.8刀首年COM域名 6.68刀首年CC域名${gl_bai}" echo -e "${gl_bai}網址: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" echo "------------------------" echo "" -echo -e "科技lion周邊" +echo -e "科技lion週邊" echo "------------------------" echo -e "${gl_kjlan}B站:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}油管:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" echo -e "${gl_kjlan}官網:${gl_bai}https://kejilion.pro/ ${gl_kjlan}導航:${gl_bai}https://dh.kejilion.pro/${gl_bai}" -echo -e "${gl_kjlan}部落格:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}軟件中心:${gl_bai}https://app.kejilion.pro/${gl_bai}" +echo -e "${gl_kjlan}部落格:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}軟體中心:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}腳本官網:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" @@ -16503,7 +16561,7 @@ games_server_tools() { echo -e "${gl_kjlan}1. ${gl_bai}幻獸帕魯開服腳本" echo -e "${gl_kjlan}2. ${gl_bai}我的世界開服腳本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜單" + echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "請輸入你的選擇:" sub_choice @@ -16572,7 +16630,7 @@ while true; do send_stats "腳本已經最新了,無需更新" else echo "發現新版本!" - echo -e "當前版本 v$sh_v最新版本${gl_huang}v$sh_v_new${gl_bai}" + echo -e "目前版本 v$sh_v最新版本${gl_huang}v$sh_v_new${gl_bai}" fi @@ -16585,9 +16643,9 @@ while true; do fi echo "------------------------" - echo "1. 現在更新 2. 開啟自動更新 3. 關閉自動更新" + echo "1. 現在更新 2. 開啟自動更新 3. 關閉自動更新" echo "------------------------" - echo "0. 返回主菜單" + echo "0. 返回主選單" echo "------------------------" read -e -p "請輸入你的選擇:" choice case "$choice" in @@ -16603,7 +16661,7 @@ while true; do CheckFirstRun_true yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" break_end ~/kejilion.sh @@ -16655,9 +16713,9 @@ echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" echo -e "科技lion腳本工具箱 v$sh_v" -echo -e "命令行輸入${gl_huang}k${gl_kjlan}可快速啟動腳本${gl_bai}" +echo -e "命令列輸入${gl_huang}k${gl_kjlan}可快速啟動腳本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系統信息查詢" +echo -e "${gl_kjlan}1. ${gl_bai}系統資訊查詢" echo -e "${gl_kjlan}2. ${gl_bai}系統更新" echo -e "${gl_kjlan}3. ${gl_bai}系統清理" echo -e "${gl_kjlan}4. ${gl_bai}基礎工具" @@ -16665,12 +16723,12 @@ echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" echo -e "${gl_kjlan}8. ${gl_bai}測試腳本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云腳本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文雲腳本合集" echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" echo -e "${gl_kjlan}11. ${gl_bai}應用市場" echo -e "${gl_kjlan}12. ${gl_bai}後台工作區" echo -e "${gl_kjlan}13. ${gl_bai}系統工具" -echo -e "${gl_kjlan}14. ${gl_bai}服務器集群控制" +echo -e "${gl_kjlan}14. ${gl_bai}伺服器叢集控制" echo -e "${gl_kjlan}15. ${gl_bai}廣告專欄" echo -e "${gl_kjlan}16. ${gl_bai}遊戲開服腳本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16709,56 +16767,56 @@ done k_info() { -send_stats "k命令參考用例" +send_stats "k指令參考用例" echo "-------------------" -echo "視頻介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "影片介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下是k命令參考用例:" -echo "啟動腳本 k" -echo "安裝軟件包 k install nano wget | k add nano wget | k 安裝 nano wget" -echo "卸載軟件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" -echo "更新系統 k update | k 更新" -echo "清理系統垃圾 k clean | k 清理" -echo "重裝系統面板 k dd | k 重裝" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "內核調優面板 k nhyh | k 內核優化" -echo "設置虛擬內存 k swap 2048" -echo "設置虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" -echo "系統回收站 k trash | k hsz | k 回收站" -echo "系統備份功能 k backup | k bf | k 備份" -echo "ssh遠程連接工具 k ssh | k 遠程連接" -echo "rsync遠程同步工具 k rsync | k 遠程同步" -echo "硬盤管理工具 k disk | k 硬盤管理" -echo "內網穿透(服務端) k frps" -echo "內網穿透(客戶端) k frpc" -echo "軟件啟動 k start sshd | k 啟動 sshd" -echo "軟件停止 k stop sshd | k 停止 sshd" -echo "軟件重啟 k restart sshd | k 重啟 sshd" -echo "軟件狀態查看 k status sshd | k 狀態 sshd" -echo "軟件開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" -echo "域名證書申請 k ssl" -echo "域名證書到期查詢 k ssl ps" -echo "docker管理平面 k docker" -echo "docker環境安裝 k docker install |k docker 安裝" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker鏡像管理 k docker img |k docker 鏡像" -echo "LDNMP站點管理 k web" -echo "LDNMP緩存清理 k web cache" -echo "安裝WordPress k wp |k wordpress |k wp xxx.com" -echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安裝負載均衡 k loadbalance |k 負載均衡" -echo "安裝L4負載均衡 k stream |k L4負載均衡" -echo "防火牆面板 k fhq |k 防火牆" -echo "開放端口 k dkdk 8080 |k 打開端口 8080" -echo "關閉端口 k gbdk 7800 |k 關閉端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夾 k fav | k 命令收藏夾" -echo "應用市場管理 k app" -echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" -echo "顯示系統信息 k info" -echo "ROOT密鑰管理 k sshkey" -echo "SSH公鑰導入(URL) k sshkey " +echo "啟動腳本 k" +echo "安裝軟體包 k install nano wget | k add nano wget | k 安裝 nano wget" +echo "卸載軟體包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" +echo "更新系統 k update | k 更新" +echo "清理系統垃圾 k clean | k 清理" +echo "重裝系統面板 k dd | k 重裝" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "核心調優面板 k nhyh | k 核心最佳化" +echo "設定虛擬記憶體 k swap 2048" +echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" +echo "系統回收站 k trash | k hsz | k 回收站" +echo "系統備份功能 k backup | k bf | k 備份" +echo "ssh遠端連線工具 k ssh | k 遠端連線" +echo "rsync遠端同步工具 k rsync | k 遠端同步" +echo "硬碟管理工具 k disk | k 硬碟管理" +echo "內網穿透(服務端) k frps" +echo "內網穿透(客戶端) k frpc" +echo "軟體啟動 k start sshd | k 啟動 sshd" +echo "軟體停止 k stop sshd | k 停止 sshd" +echo "軟體重啟 k restart sshd | k 重啟 sshd" +echo "軟體狀態檢視 k status sshd | k 狀態 sshd" +echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" +echo "網域憑證申請 k ssl" +echo "網域名稱憑證到期查詢 k ssl ps" +echo "docker管理平面 k docker" +echo "docker環境安裝 k docker install |k docker 安裝" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker映像管理 k docker img |k docker 映像" +echo "LDNMP站台管理 k web" +echo "LDNMP快取清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安裝負載平衡 k loadbalance |k 負載平衡" +echo "安裝L4負載平衡 k stream |k L4負載平衡" +echo "防火牆面板 k fhq |k 防火牆" +echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" +echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏 k fav | k 指令收藏夾" +echo "應用市場管理 k app" +echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" +echo "fail2ban管理 k fail2ban | k f2b" +echo "顯示系統資訊 k info" +echo "ROOT金鑰管理 k sshkey" +echo "SSH公鑰導入(URL) k sshkey " echo "SSH公鑰導入(GitHub) k sshkey github " } @@ -16766,19 +16824,19 @@ echo "SSH公鑰導入(GitHub) k sshkey github " if [ "$#" -eq 0 ]; then - # 如果沒有參數,運行交互式邏輯 + # 如果沒有參數,運行互動式邏輯 kejilion_sh else - # 如果有參數,執行相應函數 + # 如果有參數,執行對應函數 case $1 in install|add|安装) shift - send_stats "安裝軟件" + send_stats "安裝軟體" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸載軟件" + send_stats "解除安裝軟體" remove "$@" ;; update|更新) @@ -16831,7 +16889,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口訪問該服務" + echo "已阻止IP+連接埠存取該服務" else ip_address close_port "$port" @@ -16850,13 +16908,13 @@ else swap) shift - send_stats "快速設置虛擬內存" + send_stats "快速設定虛擬記憶體" add_swap "$@" ;; time|时区) shift - send_stats "快速設置時區" + send_stats "快速設定時區" set_timedate "$@" ;; @@ -16904,28 +16962,28 @@ else status|状态) shift - send_stats "軟件狀態查看" + send_stats "軟體狀態檢視" status "$@" ;; start|启动) shift - send_stats "軟件啟動" + send_stats "軟體啟動" start "$@" ;; stop|停止) shift - send_stats "軟件暫停" + send_stats "軟體暫停" stop "$@" ;; restart|重启) shift - send_stats "軟件重啟" + send_stats "軟體重啟" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "軟件開機自啟" + send_stats "軟體開機自啟" enable "$@" ;; @@ -16949,15 +17007,15 @@ else shift case $1 in install|安装) - send_stats "快捷安裝docker" + send_stats "快速安裝docker" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "快速容器管理" docker_ps ;; img|镜像) - send_stats "快捷鏡像管理" + send_stats "快速鏡像管理" docker_image ;; *) @@ -17003,8 +17061,8 @@ else shift case "$1" in "" ) - # sshkey → 交互菜單 - send_stats "SSHKey 交互菜單" + # sshkey → 互動選單 + send_stats "SSHKey 互動選單" sshkey_panel ;; github ) @@ -17013,7 +17071,7 @@ else fetch_github_ssh_keys "$1" ;; http://*|https://* ) - send_stats "從 URL 導入 SSH 公鑰" + send_stats "從 URL 匯入 SSH 公鑰" fetch_remote_ssh_keys "$1" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) @@ -17023,10 +17081,10 @@ else * ) echo "錯誤:未知參數 '$1'" echo "用法:" - echo "k sshkey 進入交互菜單" - echo "k sshkey \"\" 直接導入 SSH 公鑰" - echo "k sshkey 從 URL 導入 SSH 公鑰" - echo "k sshkey github 從 GitHub 導入 SSH 公鑰" + echo "k sshkey 進入互動選單" + echo "k sshkey \"\" 直接導入 SSH 公鑰" + echo "k sshkey 從 URL 匯入 SSH 公鑰" + echo "k sshkey github 從 GitHub 匯入 SSH 公鑰" ;; esac From 80a308e948727c09d3d4945686691d198ca46735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:53:51 +0800 Subject: [PATCH 0805/1285] Fix grep option for plugin list check --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7906a2781..076d743d4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10126,7 +10126,7 @@ EOF echo "🔍 正在检查插件状态..." # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡 插件 [$plugin_id] 已预装,正在激活..." openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" From 392d41f5106bdbd26199e8d4d38b37828f7825bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:54:38 +0800 Subject: [PATCH 0806/1285] Fix grep options for plugin status check --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d482c6575..6ecc13b71 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10126,7 +10126,7 @@ EOF echo "🔍 正在检查插件状态..." # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡 插件 [$plugin_id] 已预装,正在激活..." openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" From 343105c9c7d570420109e1a02f295edf6dcd3c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:29:08 +0800 Subject: [PATCH 0807/1285] Install npm and pnpm in kejilion.sh Added installation commands for npm and pnpm. --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 076d743d4..b2e2fea05 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9718,6 +9718,8 @@ moltbot_menu() { dnf install -y cmake fi + install npm pnpm + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com From f7e4d18f88f29b9e0654e1b48c40767699ef450d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:29:38 +0800 Subject: [PATCH 0808/1285] Install npm and pnpm for country-specific registry Added installation of npm and pnpm based on country detection. --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 6ecc13b71..8ce91a11a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9718,6 +9718,8 @@ moltbot_menu() { dnf install -y cmake fi + install npm pnpm + country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then pnpm config set registry https://registry.npmmirror.com From e61dfcff95ae6b11110839fe049e6b2a68f584b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:25:56 +0800 Subject: [PATCH 0809/1285] Modify nginx installation script and fix formatting Removed check_disk_space call and added missing newline. --- cn/kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b2e2fea05..e709c6257 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3299,7 +3299,6 @@ send_stats "安装nginx环境" root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot From 2d91278f72b756a543a503db9d034c04e49fd460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:26:37 +0800 Subject: [PATCH 0810/1285] Fix conditional block and remove disk space check --- kejilion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 8ce91a11a..3de3bcdd2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3299,7 +3299,6 @@ send_stats "安装nginx环境" root_use clear echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot From dd586a9bc0c45d79fd268c65f837359748eef7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:22:00 +0800 Subject: [PATCH 0811/1285] Update OpenClaw gateway start process --- cn/kejilion.sh | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e709c6257..824ea6587 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -9696,17 +9696,12 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -9725,7 +9720,7 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + start_gateway add_app_id break_end @@ -9735,7 +9730,7 @@ moltbot_menu() { start_bot() { echo "启动 OpenClaw..." send_stats "启动 OpenClaw..." - start_tmux + start_gateway break_end } @@ -9743,7 +9738,6 @@ moltbot_menu() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 break_end } @@ -9964,7 +9958,7 @@ EOF echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅ 完成!所有 $model_count 个模型已加载" fi @@ -10079,7 +10073,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10155,7 +10149,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" - # 关键:这里直接 return 或 continue,不走下面的 start_tmux,防止写死配置 + # 关键:这里直接 return 或 continue,不走下面的 start_gateway,防止写死配置 break_end continue fi @@ -10163,7 +10157,7 @@ EOF fi echo "🔄 正在重启 OpenClaw 服务以加载新插件..." - start_tmux + start_gateway break_end done } @@ -10227,7 +10221,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ 技能 $skill_name 安装成功。" # 执行重启/启动服务逻辑 - start_tmux + start_gateway else echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" fi @@ -10265,7 +10259,7 @@ EOF send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop - start_tmux + start_gateway add_app_id echo "更新完成" break_end @@ -10288,7 +10282,7 @@ EOF send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } From 4cfa75be9d62a4332909484273f881cca2037cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:22:30 +0800 Subject: [PATCH 0812/1285] Update version and replace start_tmux with start_gateway --- kejilion.sh | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3de3bcdd2..b38c940a8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -9696,17 +9696,12 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -9725,7 +9720,7 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + start_gateway add_app_id break_end @@ -9735,7 +9730,7 @@ moltbot_menu() { start_bot() { echo "启动 OpenClaw..." send_stats "启动 OpenClaw..." - start_tmux + start_gateway break_end } @@ -9743,7 +9738,6 @@ moltbot_menu() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 break_end } @@ -9964,7 +9958,7 @@ EOF echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅ 完成!所有 $model_count 个模型已加载" fi @@ -10079,7 +10073,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10155,7 +10149,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" - # 关键:这里直接 return 或 continue,不走下面的 start_tmux,防止写死配置 + # 关键:这里直接 return 或 continue,不走下面的 start_gateway,防止写死配置 break_end continue fi @@ -10163,7 +10157,7 @@ EOF fi echo "🔄 正在重启 OpenClaw 服务以加载新插件..." - start_tmux + start_gateway break_end done } @@ -10227,7 +10221,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ 技能 $skill_name 安装成功。" # 执行重启/启动服务逻辑 - start_tmux + start_gateway else echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" fi @@ -10265,7 +10259,7 @@ EOF send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash openclaw gateway stop - start_tmux + start_gateway add_app_id echo "更新完成" break_end @@ -10288,7 +10282,7 @@ EOF send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } From ee83f3886bb63417a47352b234fe4ea4e7a0dae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:23:52 +0800 Subject: [PATCH 0813/1285] Update kejilion_sh_log.txt with new version details Add log entries for version 4.4.0 release and improvements. --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5bf75ac64..f12aed1a7 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1453,4 +1453,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-02-11 v4.3.10 应用市场对ClawdBot/Moltbot机器人项目添加API支持批量导入模型。 ------------------------ +2026-02-22 v4.4.0 +应用市场对ClawdBot/Moltbot机器人项目使用原生启动保活机制,之前原生不稳定。 +------------------------ From 2791c11bcd6dd12dcfdaaf247cb181af21be61e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:26:29 +0800 Subject: [PATCH 0814/1285] Fix stop_bot function and add missing newline --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 824ea6587..ff646714f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9737,6 +9737,7 @@ moltbot_menu() { stop_bot() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." + tmux kill-session -t gateway > /dev/null 2>&1 openclaw gateway stop break_end } From 92bf0319ebb5841556384697b5842a5756a3c691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:26:55 +0800 Subject: [PATCH 0815/1285] Fix stop_bot function and add missing newline --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index b38c940a8..0a86e807a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9737,6 +9737,7 @@ moltbot_menu() { stop_bot() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." + tmux kill-session -t gateway > /dev/null 2>&1 openclaw gateway stop break_end } From adf641be65c228a0f0e9fae038fdbc8b4185e661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:35:59 +0800 Subject: [PATCH 0816/1285] Add function to check if openclaw-gateway is running --- cn/kejilion.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ff646714f..9d10a6996 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9643,14 +9643,14 @@ moltbot_menu() { fi } - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi + get_running_status() { + if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi } - + get_running_status() { if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" From bbc46e911dce1722843e18e375160111f532c8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:36:32 +0800 Subject: [PATCH 0817/1285] Refactor get_install_status to get_running_status --- kejilion.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0a86e807a..b439cc9b7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9643,14 +9643,14 @@ moltbot_menu() { fi } - get_install_status() { - if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" - else - echo "${gl_hui}未安装${gl_bai}" - fi + get_running_status() { + if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi } - + get_running_status() { if pgrep -f "openclaw gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" From 7663aa6e2edf4bd88b95eb8c9f35c28eaed6e8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:47:37 +0800 Subject: [PATCH 0818/1285] Add installation status check for openclaw --- cn/kejilion.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9d10a6996..396a3189d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9643,6 +9643,15 @@ moltbot_menu() { fi } + + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + get_running_status() { if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" @@ -9651,13 +9660,6 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } show_menu() { From 2f44c79e8f4f7b337e3302b079aa17fa5a66b5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:48:00 +0800 Subject: [PATCH 0819/1285] Refactor get_running_status function in kejilion.sh --- kejilion.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index b439cc9b7..eddead105 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9643,6 +9643,15 @@ moltbot_menu() { fi } + + get_install_status() { + if command -v openclaw >/dev/null 2>&1; then + echo "${gl_lv}已安装${gl_bai}" + else + echo "${gl_hui}未安装${gl_bai}" + fi + } + get_running_status() { if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" @@ -9651,13 +9660,6 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi - } show_menu() { From 0618a2a470fe0c2701afbe6ac9ff2175c0883c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:05:36 +0800 Subject: [PATCH 0820/1285] Change service status check from systemctl to pgrep --- kejilion.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index eddead105..fa853f750 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9653,13 +9653,13 @@ moltbot_menu() { } get_running_status() { - if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi } - + show_menu() { From 994a7cc02352a0c6a95eb0eb27c056610d458eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:06:12 +0800 Subject: [PATCH 0821/1285] Change service status check from systemctl to pgrep --- cn/kejilion.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 396a3189d..8a0379681 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9653,13 +9653,13 @@ moltbot_menu() { } get_running_status() { - if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" - else - echo "${gl_hui}未运行${gl_bai}" - fi + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + echo "${gl_lv}运行中${gl_bai}" + else + echo "${gl_hui}未运行${gl_bai}" + fi } - + show_menu() { From 912823871793c15801e5730f238a79f762ab8922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:20:46 +0800 Subject: [PATCH 0822/1285] Rename log view option to status log view --- cn/kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8a0379681..76c883dfb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9678,7 +9678,7 @@ moltbot_menu() { echo "2. 启动" echo "3. 停止" echo "--------------------" - echo "4. 日志查看" + echo "4. 状态日志查看" echo "5. 换模型" echo "6. 加新模型API" echo "7. TG输入连接码" @@ -9745,8 +9745,10 @@ moltbot_menu() { } view_logs() { - echo "查看 OpenClaw 日志,Ctrl+C 退出" + echo "查看 OpenClaw 状态日志" send_stats "查看 OpenClaw 日志" + openclaw status + openclaw gateway status openclaw logs break_end } From b5ae16139bfc5956b6dac8aaf640c1fd508bb9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:21:16 +0800 Subject: [PATCH 0823/1285] Rename log view option to status log view --- kejilion.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fa853f750..e612d6172 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9678,7 +9678,7 @@ moltbot_menu() { echo "2. 启动" echo "3. 停止" echo "--------------------" - echo "4. 日志查看" + echo "4. 状态日志查看" echo "5. 换模型" echo "6. 加新模型API" echo "7. TG输入连接码" @@ -9745,8 +9745,10 @@ moltbot_menu() { } view_logs() { - echo "查看 OpenClaw 日志,Ctrl+C 退出" + echo "查看 OpenClaw 状态日志" send_stats "查看 OpenClaw 日志" + openclaw status + openclaw gateway status openclaw logs break_end } From e359949a7361fad6bfce646df393cdc03247bed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:23:00 +0800 Subject: [PATCH 0824/1285] =?UTF-8?q?=E4=BC=98=E5=8C=96ClawdBot/Moltbot?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化ClawdBot/Moltbot机器人项目的日志选项,以便在查看日志时同时显示运行状态信息。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f12aed1a7..555a11057 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1455,5 +1455,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 ------------------------ 2026-02-22 v4.4.0 应用市场对ClawdBot/Moltbot机器人项目使用原生启动保活机制,之前原生不稳定。 +应用市场对ClawdBot/Moltbot机器人项目日志选项进行优化,看日志同时显示运行状态信息。 ------------------------ From b7c3d0d2182778bfa9e5fffe0fa3dad668795e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:45:49 +0800 Subject: [PATCH 0825/1285] Update start_gateway to link openclaw and source files Add symbolic link for openclaw and source environment files in start_gateway function. --- cn/kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 76c883dfb..bccca9c88 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9699,6 +9699,9 @@ moltbot_menu() { start_gateway() { + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 openclaw gateway stop openclaw gateway start sleep 3 From 918bb435b84ada9ed111e78a8f86f120d8d1bf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:46:27 +0800 Subject: [PATCH 0826/1285] Enhance start_gateway function in kejilion.sh Add symbolic link for openclaw and source bash profile --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index e612d6172..5bb4646d4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9699,6 +9699,9 @@ moltbot_menu() { start_gateway() { + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 openclaw gateway stop openclaw gateway start sleep 3 From acdb53ff2d38d43b07e62afdba72cc9dd68bae86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:52:14 +0800 Subject: [PATCH 0827/1285] Add registry configuration checks for pnpm and npm Added checks for pnpm and npm before setting registry. --- kejilion.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 5bb4646d4..93cb283ba 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9716,13 +9716,18 @@ moltbot_menu() { dnf groupinstall -y "Development Tools" dnf install -y cmake fi - - install npm pnpm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com - npm config set registry https://registry.npmmirror.com + # 检查并设置 pnpm + if command -v pnpm &> /dev/null; then + pnpm config set registry https://registry.npmmirror.com + fi + + # 检查并设置 npm + if command -v npm &> /dev/null; then + npm config set registry https://registry.npmmirror.com + fi fi curl -fsSL https://openclaw.ai/install.sh | bash start_gateway From 28de8ae540ac602e2edea4351547859136d670d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:53:01 +0800 Subject: [PATCH 0828/1285] Add registry configuration checks for npm and pnpm Added checks before setting npm and pnpm registries for specific countries. --- cn/kejilion.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bccca9c88..9a9a3d8ba 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9716,13 +9716,18 @@ moltbot_menu() { dnf groupinstall -y "Development Tools" dnf install -y cmake fi - - install npm pnpm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com - npm config set registry https://registry.npmmirror.com + # 检查并设置 pnpm + if command -v pnpm &> /dev/null; then + pnpm config set registry https://registry.npmmirror.com + fi + + # 检查并设置 npm + if command -v npm &> /dev/null; then + npm config set registry https://registry.npmmirror.com + fi fi curl -fsSL https://openclaw.ai/install.sh | bash start_gateway From 7ef62de635ebbe803090e2ab2c7dc4aa93d53fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:56:25 +0800 Subject: [PATCH 0829/1285] Restore symlink and profile sourcing in scripts Reintroduce symlink creation and sourcing of bash profile in start_gateway and update_moltbot functions. --- cn/kejilion.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9a9a3d8ba..9406e7f27 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9699,9 +9699,6 @@ moltbot_menu() { start_gateway() { - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 openclaw gateway stop openclaw gateway start sleep 3 @@ -9730,6 +9727,9 @@ moltbot_menu() { fi fi curl -fsSL https://openclaw.ai/install.sh | bash + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 start_gateway add_app_id break_end @@ -10271,7 +10271,9 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 start_gateway add_app_id echo "更新完成" From 2f881a454190ea38c86150587f5b799ed63728d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:56:56 +0800 Subject: [PATCH 0830/1285] Refactor openclaw installation and gateway start Reorganize the start_gateway function and update installation steps for openclaw. --- kejilion.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 93cb283ba..3c444021e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9699,9 +9699,6 @@ moltbot_menu() { start_gateway() { - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 openclaw gateway stop openclaw gateway start sleep 3 @@ -9730,6 +9727,9 @@ moltbot_menu() { fi fi curl -fsSL https://openclaw.ai/install.sh | bash + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 start_gateway add_app_id break_end @@ -10271,7 +10271,9 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop + ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 + source ~/.bashrc > /dev/null 2>&1 + source ~/.profile > /dev/null 2>&1 start_gateway add_app_id echo "更新完成" From be227526e4c4887883bfd11ea0a624482031f1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:11:58 +0800 Subject: [PATCH 0831/1285] Refactor OpenClaw installation process Updated installation commands for OpenClaw and removed unnecessary lines. --- cn/kejilion.sh | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9406e7f27..be4c91eb9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9710,26 +9710,17 @@ moltbot_menu() { if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi - + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - # 检查并设置 pnpm - if command -v pnpm &> /dev/null; then - pnpm config set registry https://registry.npmmirror.com - fi - - # 检查并设置 npm - if command -v npm &> /dev/null; then - npm config set registry https://registry.npmmirror.com - fi + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 + npm install -g openclaw@latest + openclaw onboard --install-daemon start_gateway add_app_id break_end @@ -10270,10 +10261,7 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 + npm install -g openclaw@latest start_gateway add_app_id echo "更新完成" From 7582c482e1f9239d49b365dd83cc7dd52082473b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:12:48 +0800 Subject: [PATCH 0832/1285] Refactor OpenClaw installation in kejilion.sh Updated installation commands for OpenClaw and removed unnecessary lines. --- kejilion.sh | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3c444021e..1df385e1b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9710,26 +9710,17 @@ moltbot_menu() { if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi - + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - # 检查并设置 pnpm - if command -v pnpm &> /dev/null; then - pnpm config set registry https://registry.npmmirror.com - fi - - # 检查并设置 npm - if command -v npm &> /dev/null; then - npm config set registry https://registry.npmmirror.com - fi + npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 + npm install -g openclaw@latest + openclaw onboard --install-daemon start_gateway add_app_id break_end @@ -10270,10 +10261,7 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash - ln -s /root/.local/bin/openclaw /usr/local/bin/openclaw > /dev/null 2>&1 - source ~/.bashrc > /dev/null 2>&1 - source ~/.profile > /dev/null 2>&1 + npm install -g openclaw@latest start_gateway add_app_id echo "更新完成" From 2cac860100a1f0fc9d49f0073efeb53fb2b8c774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:24:18 +0800 Subject: [PATCH 0833/1285] Update permission_granted and add apt installation Changed permission_granted to true and added apt package installation for build tools. --- kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 1df385e1b..9ee3952b9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -9714,6 +9714,11 @@ moltbot_menu() { dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then From 74c0e849d9605e75266ab8fdfe734b3ba96adaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:24:52 +0800 Subject: [PATCH 0834/1285] Change permission_granted to true and update package install --- cn/kejilion.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index be4c91eb9..26284a05d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="CN" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -9714,6 +9714,11 @@ moltbot_menu() { dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then From 1744117acb5f3dff9d6e39c372a9eb7a09bbfedb Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 22 Feb 2026 09:13:27 +0000 Subject: [PATCH 0835/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-22=2009:13:27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 105 ++++++++++++++++++------------------ jp/kejilion.sh | 139 ++++++++++++++++++++++++------------------------ kr/kejilion.sh | 141 +++++++++++++++++++++++++------------------------ tw/kejilion.sh | 91 ++++++++++++++++--------------- 4 files changed, 244 insertions(+), 232 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 5ab06c21f..2e62ef8e6 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3299,7 +3299,6 @@ send_stats "Install nginx environment" root_use clear echo -e "${gl_huang}nginx is not installed, start installing nginx environment...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot @@ -3523,7 +3522,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -5163,7 +5162,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -5443,7 +5442,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5977,7 +5976,7 @@ restore_defaults() { # Website building optimization function optimize_web_server() { - echo -e "${gl_lv}Switch to website building optimization mode...${gl_bai}" + echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" ulimit -n 65535 @@ -6056,7 +6055,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6696,7 +6695,7 @@ mount_partition() { return 1 fi - echo "The partition was successfully mounted to$MOUNT_POINT" + echo "Partition successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7710,7 +7709,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -9644,6 +9643,7 @@ moltbot_menu() { fi } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}Installed${gl_bai}" @@ -9653,13 +9653,14 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then echo "${gl_lv}Running${gl_bai}" else echo "${gl_hui}Not running${gl_bai}" fi } + show_menu() { @@ -9677,7 +9678,7 @@ moltbot_menu() { echo "2. Start" echo "3. Stop" echo "--------------------" - echo "4. Log viewing" + echo "4. View status log" echo "5. Change model" echo "6. Add new model API" echo "7. Enter the connection code in TG" @@ -9697,34 +9698,35 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "Start installing OpenClaw..." send_stats "Start installing OpenClaw..." if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway add_app_id break_end @@ -9734,21 +9736,23 @@ moltbot_menu() { start_bot() { echo "Starting OpenClaw..." send_stats "Starting OpenClaw..." - start_tmux + start_gateway break_end } stop_bot() { echo "Stop OpenClaw..." send_stats "Stop OpenClaw..." - openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 + openclaw gateway stop break_end } view_logs() { - echo "View OpenClaw logs, Ctrl+C to exit" + echo "View the OpenClaw status log" send_stats "View OpenClaw logs" + openclaw status + openclaw gateway status openclaw logs break_end } @@ -9963,7 +9967,7 @@ EOF echo echo "🔄 Set default model and restart gateway..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅ Done! all$model_countmodels loaded" fi @@ -10078,7 +10082,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10126,7 +10130,7 @@ EOF echo "🔍 Checking plugin status..." # 2. Check whether it is already in the list and disabled (the most common case) - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡 Plugin [$plugin_id] Pre-installed, activating..." openclaw plugins enable "$plugin_id" && echo "✅Activation successful" || echo "❌ Activation failed" @@ -10154,7 +10158,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ Fatal error: Unable to obtain the plug-in. Please check if the ID is correct or if the network is available." - # Key: Return or continue directly here instead of starting_tmux below to prevent hard-coding the configuration. + # Key: Return or continue directly here instead of using the start_gateway below to prevent hard-coding the configuration. break_end continue fi @@ -10162,7 +10166,7 @@ EOF fi echo "🔄 Restarting OpenClaw service to load new plugins..." - start_tmux + start_gateway break_end done } @@ -10226,7 +10230,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ Skills$skill_nameInstallation successful." # Execute restart/start service logic - start_tmux + start_gateway else echo "❌ Installation failed. Please check whether the skill name is correct, or refer to the documentation for troubleshooting." fi @@ -10262,9 +10266,8 @@ EOF update_moltbot() { echo "Update OpenClaw..." send_stats "Update OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop - start_tmux + npm install -g openclaw@latest + start_gateway add_app_id echo "Update completed" break_end @@ -10287,7 +10290,7 @@ EOF send_stats "Edit the OpenClaw configuration file" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } @@ -10487,7 +10490,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -12596,7 +12599,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -14339,7 +14342,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -14712,7 +14715,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. Check the latest system log (journal)" + echo "1. View the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -14724,7 +14727,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -14802,7 +14805,7 @@ env_menu() { show_env_vars() { clear - send_stats "Currently in effect environment variables" + send_stats "Environment variables currently in effect" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -15255,8 +15258,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -15746,7 +15749,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -15967,7 +15970,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" echo "------------------------------------------------" @@ -16015,7 +16018,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -16411,7 +16414,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16528,7 +16531,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index e8295d3b0..a25688abc 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -866,7 +866,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -1099,7 +1099,7 @@ iptables_panel() { echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" - echo "15. 指定した国の IP をブロックする 16. 指定した国の IP のみを許可する" + echo "15. 指定した国の IP をブロック 16. 指定した国の IP のみを許可" echo "17. 指定国における知的財産制限を解除する" echo "------------------------" echo "0. 前のメニューに戻る" @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2231,7 +2231,7 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" @@ -2555,7 +2555,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2614,7 +2614,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2631,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3299,7 +3299,6 @@ send_stats "nginx環境をインストールする" root_use clear echo -e "${gl_huang}nginx がインストールされていません。nginx 環境のインストールを開始してください...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot @@ -4336,7 +4335,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5163,7 +5162,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を使用するには、root ユーザーが実行する必要があります。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -6029,7 +6028,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo "--------------------" echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" @@ -6056,7 +6055,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6146,7 +6145,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6654,7 +6653,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -6696,7 +6695,7 @@ mount_partition() { return 1 fi - echo "パーティションは正常にマウントされました$MOUNT_POINT" + echo "パーティションが正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -6860,7 +6859,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port + read -e -p "SSH ポートを入力してください (デフォルトは 22):" port port=${port:-22} echo "認証方法を選択してください:" @@ -7662,7 +7661,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -7692,7 +7691,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包体積:$path" + echo "梱包量:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -7945,7 +7944,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8817,7 +8816,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9644,6 +9643,7 @@ moltbot_menu() { fi } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}インストール済み${gl_bai}" @@ -9653,13 +9653,14 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then echo "${gl_lv}ランニング${gl_bai}" else echo "${gl_hui}稼働していない${gl_bai}" fi } + show_menu() { @@ -9677,7 +9678,7 @@ moltbot_menu() { echo "2.スタート" echo "3. 停止" echo "--------------------" - echo "4. ログの閲覧" + echo "4. ステータスログの表示" echo "5.機種変更" echo "6. 新しいモデル API を追加する" echo "7. TGに接続コードを入力します" @@ -9697,34 +9698,35 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "OpenClaw のインストールを開始します..." send_stats "OpenClaw のインストールを開始します..." if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway add_app_id break_end @@ -9734,21 +9736,23 @@ moltbot_menu() { start_bot() { echo "OpenClaw を開始しています..." send_stats "OpenClaw を開始しています..." - start_tmux + start_gateway break_end } stop_bot() { echo "OpenClaw を停止します..." send_stats "OpenClaw を停止します..." - openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 + openclaw gateway stop break_end } view_logs() { - echo "OpenClaw ログを表示し、Ctrl+C を押して終了します" + echo "OpenClaw ステータス ログを表示する" send_stats "OpenClaw ログを表示する" + openclaw status + openclaw gateway status openclaw logs break_end } @@ -9928,7 +9932,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -9963,7 +9967,7 @@ EOF echo echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅完了!全て$model_countロードされたモデル" fi @@ -10078,7 +10082,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10126,7 +10130,7 @@ EOF echo "🔍 プラグインのステータスを確認しています..." # 2. すでにリストに含まれていて無効になっているかどうかを確認します (最も一般的なケース)。 - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡プラグイン [$plugin_id] プリインストールされており、アクティベート中..." openclaw plugins enable "$plugin_id" && echo "✅アクティベーション成功" || echo "❌ アクティベーションに失敗しました" @@ -10154,7 +10158,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 致命的なエラー: プラグインを取得できません。 IDが正しいか、ネットワークが利用可能か確認してください。" - # キー: 構成のハードコーディングを防ぐために、以下の starting_tmux ではなく、ここに直接戻るか続行します。 + # 重要: 構成のハードコーディングを防ぐために、以下の start_gateway を使用する代わりに、ここに直接戻るか続行します。 break_end continue fi @@ -10162,7 +10166,7 @@ EOF fi echo "🔄 新しいプラグインをロードするために OpenClaw サービスを再起動しています..." - start_tmux + start_gateway break_end done } @@ -10226,7 +10230,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ スキル$skill_nameインストールが成功しました。" # 再起動/サービス開始ロジックの実行 - start_tmux + start_gateway else echo "❌ インストールに失敗しました。スキル名が正しいか確認するか、ドキュメントを参照してトラブルシューティングを行ってください。" fi @@ -10262,9 +10266,8 @@ EOF update_moltbot() { echo "OpenClaw を更新..." send_stats "OpenClaw を更新..." - curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop - start_tmux + npm install -g openclaw@latest + start_gateway add_app_id echo "アップデート完了" break_end @@ -10287,7 +10290,7 @@ EOF send_stats "OpenClaw 構成ファイルを編集する" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } @@ -10487,7 +10490,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -12871,7 +12874,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13210,7 +13213,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -14339,7 +14342,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -14702,7 +14705,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記ログ職業】" + echo "【日記帳の職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -14712,7 +14715,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を確認する" + echo "1. 最新のシステムログ(ジャーナル)を表示する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -14724,7 +14727,7 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "続行するには Enter キーを押してください..." @@ -14882,7 +14885,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集する" + echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -15255,8 +15258,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -15463,7 +15466,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -15746,7 +15749,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -15958,7 +15961,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -16406,12 +16409,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16444,7 +16447,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -16528,7 +16531,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16643,7 +16646,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" + echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -16806,7 +16809,7 @@ echo "リバース プロキシをインストールします k fd |k rp |k リ echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 6bc342181..378c9f367 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -117,7 +117,7 @@ CheckFirstRun_false() { # 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear - echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다.${gl_bai}" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -1093,7 +1093,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -2125,7 +2125,7 @@ web_security() { echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -2232,7 +2232,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2783,7 +2783,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2799,7 +2799,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3299,7 +3299,6 @@ send_stats "nginx 환경 설치" root_use clear echo -e "${gl_huang}nginx가 설치되지 않았습니다. nginx 환경 설치를 시작하세요...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot @@ -3341,10 +3340,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3354,7 +3353,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3430,7 +3429,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3694,7 +3693,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4027,7 +4026,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4089,7 +4088,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4971,7 +4970,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원래 Authorized_keys 파일이 백업되었습니다." + echo "원본 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5757,7 +5756,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6056,7 +6055,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6263,7 +6262,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7630,7 +7629,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -7904,7 +7903,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -9154,7 +9153,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -9644,6 +9643,7 @@ moltbot_menu() { fi } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}설치됨${gl_bai}" @@ -9653,13 +9653,14 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then echo "${gl_lv}달리기${gl_bai}" else echo "${gl_hui}실행되지 않음${gl_bai}" fi } + show_menu() { @@ -9677,7 +9678,7 @@ moltbot_menu() { echo "2. 시작" echo "3. 중지" echo "--------------------" - echo "4. 로그 보기" + echo "4. 상태 로그 보기" echo "5. 모델 변경" echo "6. 새로운 모델 API 추가" echo "7. TG에 연결 코드를 입력하세요." @@ -9697,34 +9698,35 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "OpenClaw 설치를 시작합니다..." send_stats "OpenClaw 설치를 시작합니다..." if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway add_app_id break_end @@ -9734,21 +9736,23 @@ moltbot_menu() { start_bot() { echo "OpenClaw를 시작하는 중..." send_stats "OpenClaw를 시작하는 중..." - start_tmux + start_gateway break_end } stop_bot() { echo "OpenClaw를 중지하세요..." send_stats "OpenClaw를 중지하세요..." - openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 + openclaw gateway stop break_end } view_logs() { - echo "OpenClaw 로그 보기, 종료하려면 Ctrl+C" + echo "OpenClaw 상태 로그 보기" send_stats "OpenClaw 로그 보기" + openclaw status + openclaw gateway status openclaw logs break_end } @@ -9963,7 +9967,7 @@ EOF echo echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅ 완료! 모두$model_count로드된 모델" fi @@ -10033,7 +10037,7 @@ EOF echo "@openclaw/bluebubbles # iMessage 브리지(macOS 사용자에게 선호됨)" echo "@openclaw/msteams #Microsoft Teams 엔터프라이즈 커뮤니케이션 통합" echo "@openclaw/voice-call # 음성 통화 플러그인 (Twilio와 같은 백엔드 기반)" - echo "@openclaw/discord # 디스코드 채널 자동 관리" + echo "@openclaw/discord # 디스코드 채널 자동관리" echo "@openclaw/nostr # Nostr 프로토콜: 비공개적이고 안전한 암호화된 채팅" echo "랍스터 # 승인 워크플로: 사람의 개입으로 자동화된 작업" echo "memory-lancedb # 장기 기억력 향상: 벡터 데이터베이스 기반의 정확한 재현" @@ -10078,7 +10082,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10126,7 +10130,7 @@ EOF echo "🔍 플러그인 상태 확인 중..." # 2. 이미 목록에 있고 비활성화되어 있는지 확인합니다(가장 일반적인 경우). - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." openclaw plugins enable "$plugin_id" && echo "✅활성화 성공" || echo "❌ 활성화 실패" @@ -10154,7 +10158,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 치명적인 오류: 플러그인을 얻을 수 없습니다. ID가 맞는지, 네트워크 사용이 가능한지 확인해주세요." - # 키: 구성이 하드 코딩되는 것을 방지하려면 아래의 start_tmux 대신 여기로 직접 돌아가거나 계속하세요. + # 키: 구성 하드 코딩을 방지하려면 아래 start_gateway를 사용하는 대신 여기로 직접 돌아가거나 계속하세요. break_end continue fi @@ -10162,7 +10166,7 @@ EOF fi echo "🔄 새 플러그인을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." - start_tmux + start_gateway break_end done } @@ -10226,7 +10230,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ 스킬$skill_name설치가 성공했습니다." # 서비스 재시작/시작 로직 실행 - start_tmux + start_gateway else echo "❌ 설치에 실패했습니다. 스킬 이름이 올바른지 확인하시거나, 문제 해결을 위해 문서를 참고하시기 바랍니다." fi @@ -10262,9 +10266,8 @@ EOF update_moltbot() { echo "오픈클로 업데이트..." send_stats "오픈클로 업데이트..." - curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop - start_tmux + npm install -g openclaw@latest + start_gateway add_app_id echo "업데이트 완료" break_end @@ -10287,7 +10290,7 @@ EOF send_stats "OpenClaw 구성 파일 편집" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } @@ -10435,7 +10438,7 @@ EOF openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "상태 감지 및 수리" openclaw doctor --fix break_end ;; @@ -10487,7 +10490,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -10547,7 +10550,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -10777,7 +10780,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -13811,7 +13814,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14339,7 +14342,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -14712,7 +14715,7 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 확인" + echo "1. 최신 시스템 로그(일지) 보기" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" @@ -14724,7 +14727,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -14773,7 +14776,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "3) 최대 로그 크기를 500M로 제한합니다." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -15001,7 +15004,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -15255,8 +15258,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -15746,7 +15749,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -16369,7 +16372,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 탐색하고 명령을 실행합니다. + # 서버를 순회하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -16411,7 +16414,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16528,7 +16531,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index f5c0eea88..aaf536160 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.3.10" +sh_v="4.4.0" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="false" +permission_granted="true" ENABLE_STATS="true" @@ -619,7 +619,7 @@ while true; do echo "" echo "鏡像操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" + echo "1. 取得指定鏡像 3. 刪除指定鏡像" echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" @@ -635,7 +635,7 @@ while true; do done ;; 2) - send_stats "更新镜像" + send_stats "更新鏡像" read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do echo -e "${gl_kjlan}正在更新鏡像:$name${gl_bai}" @@ -3299,7 +3299,6 @@ send_stats "安裝nginx環境" root_use clear echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" -check_disk_space 1 /home install_dependency install_docker install_certbot @@ -3811,7 +3810,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3852,7 +3851,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -5036,7 +5035,7 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "用户密钥登录" + send_stats "使用者密鑰登入" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -6696,7 +6695,7 @@ mount_partition() { return 1 fi - echo "分區已成功掛載到$MOUNT_POINT" + echo "分割區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -9644,6 +9643,7 @@ moltbot_menu() { fi } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then echo "${gl_lv}已安裝${gl_bai}" @@ -9653,13 +9653,14 @@ moltbot_menu() { } get_running_status() { - if pgrep -f "openclaw gateway" >/dev/null 2>&1; then + if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then echo "${gl_lv}運作中${gl_bai}" else echo "${gl_hui}未運行${gl_bai}" fi } + show_menu() { @@ -9677,7 +9678,7 @@ moltbot_menu() { echo "2. 啟動" echo "3. 停止" echo "--------------------" - echo "4. 日誌查看" + echo "4. 狀態日誌查看" echo "5. 換模型" echo "6. 加新模型API" echo "7. TG輸入連接碼" @@ -9697,34 +9698,35 @@ moltbot_menu() { } - start_tmux() { - install tmux + start_gateway() { openclaw gateway stop - tmux kill-session -t gateway > /dev/null 2>&1 - tmux new -d -s gateway "openclaw gateway" - check_crontab_installed - crontab -l 2>/dev/null | grep -q "s gateway" || (crontab -l 2>/dev/null; echo "* * * * * tmux has-session -t gateway 2>/dev/null || tmux new -d -s gateway 'openclaw gateway'") | crontab - + openclaw gateway start sleep 3 } - install_moltbot() { echo "開始安裝 OpenClaw..." send_stats "開始安裝 OpenClaw..." if command -v dnf &>/dev/null; then dnf update -y - dnf groupinstall -y "Development Tools" + dnf group install -y "Development Tools" "Development Libraries" dnf install -y cmake fi + if command -v apt &>/dev/null; then + apt update -y + apt install build-essential python3 -y + fi + + install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then - pnpm config set registry https://registry.npmmirror.com npm config set registry https://registry.npmmirror.com fi - curl -fsSL https://openclaw.ai/install.sh | bash - start_tmux + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway add_app_id break_end @@ -9734,21 +9736,23 @@ moltbot_menu() { start_bot() { echo "啟動 OpenClaw..." send_stats "啟動 OpenClaw..." - start_tmux + start_gateway break_end } stop_bot() { echo "停止 OpenClaw..." send_stats "停止 OpenClaw..." - openclaw gateway stop tmux kill-session -t gateway > /dev/null 2>&1 + openclaw gateway stop break_end } view_logs() { - echo "查看 OpenClaw 日誌,Ctrl+C 退出" + echo "查看 OpenClaw 狀態日誌" send_stats "查看 OpenClaw 日誌" + openclaw status + openclaw gateway status openclaw logs break_end } @@ -9946,7 +9950,7 @@ EOF echo "Provider : $provider_name" echo "Base URL : $base_url" echo "API Key : ${api_key:0:8}****" - echo "默认模型 : $default_model" + echo "預設模型 :$default_model" echo "模型總數 :$model_count" echo "======================" @@ -9963,7 +9967,7 @@ EOF echo echo "🔄 設定預設模型並重新啟動網關..." openclaw models set "$provider_name/$default_model" - start_tmux + start_gateway echo "✅ 完成!所有$model_count個模型已載入" fi @@ -10078,7 +10082,7 @@ EOF openclaw plugins enable "$plugin_name" fi - start_tmux + start_gateway break_end done } @@ -10126,7 +10130,7 @@ EOF echo "🔍 正在檢查插件狀態..." # 2. 檢查是否已經在 list 中且為 disabled (最常見的情況) - if echo "$plugin_list" | grep -qW "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." openclaw plugins enable "$plugin_id" && echo "✅ 啟動成功" || echo "❌ 啟動失敗" @@ -10154,7 +10158,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 嚴重錯誤:無法取得該外掛程式。請檢查 ID 是否正確或網路是否可用。" - # 關鍵:這裡直接 return 或 continue,不走下面的 start_tmux,防止寫死配置 + # 關鍵:這裡直接 return 或 continue,不走下面的 start_gateway,防止寫死配置 break_end continue fi @@ -10162,7 +10166,7 @@ EOF fi echo "🔄 正在重啟 OpenClaw 服務以載入新插件..." - start_tmux + start_gateway break_end done } @@ -10226,7 +10230,7 @@ EOF if [ $? -eq 0 ]; then echo "✅ 技能$skill_name安裝成功。" # 執行重啟/啟動服務邏輯 - start_tmux + start_gateway else echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文件排查。" fi @@ -10262,9 +10266,8 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." - curl -fsSL https://openclaw.ai/install.sh | bash - openclaw gateway stop - start_tmux + npm install -g openclaw@latest + start_gateway add_app_id echo "更新完成" break_end @@ -10287,7 +10290,7 @@ EOF send_stats "編輯 OpenClaw 設定檔" install nano nano ~/.openclaw/openclaw.json - start_tmux + start_gateway } @@ -10545,7 +10548,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -13810,7 +13813,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -14640,7 +14643,7 @@ net_menu() { echo "1. 啟用網卡" echo "2. 停用網路卡" echo "3. 查看網卡詳細信息" - echo "4. 刷新网卡信息" + echo "4. 刷新網卡資訊" echo "0. 返回上一級選單" echo "====================================" read -erp "請選擇操作:" choice @@ -15181,7 +15184,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH埠修改" + send_stats "退出SSH連接埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -15413,7 +15416,7 @@ EOF done echo "" - echo "随机姓名" + echo "隨機姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") @@ -15674,7 +15677,7 @@ EOF ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "編輯定時任務" ;; *) break # 跳出循环,退出菜单 @@ -16801,8 +16804,8 @@ echo "docker容器管理 k docker ps |k docker 容器" echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安裝WordPress k wp |k wordpress |k wp xxx.com" +echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" From 9e8644da9473f4eaf39e38520c6bb44a30017e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:51:57 +0800 Subject: [PATCH 0836/1285] Update package installations and add Node.js setup Added libatomic to package installations and included NVM installation for Node.js. --- cn/kejilion.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 26284a05d..571bb0b90 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9711,15 +9711,22 @@ moltbot_menu() { if command -v dnf &>/dev/null; then dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic fi if command -v apt &>/dev/null; then apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 -y fi - install node npm + + curl -o- ${gh_proxy}raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash + + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" + + nvm install node country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com From d5379e518c71373813d26195142fc59063eafe79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:52:29 +0800 Subject: [PATCH 0837/1285] Enhance package installations and add nvm setup Added libatomic package installation for dnf and apt. Included nvm installation for managing Node.js versions. --- kejilion.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9ee3952b9..75e3d9857 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9711,15 +9711,22 @@ moltbot_menu() { if command -v dnf &>/dev/null; then dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic fi if command -v apt &>/dev/null; then apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 -y fi - install node npm + + curl -o- ${gh_proxy}raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash + + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" + + nvm install node country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com From 771fb9f555dc32ee60efd463985f736a01028ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:16:51 +0800 Subject: [PATCH 0838/1285] Add nodejs installation to OpenClaw setup script Updated installation script to include nodejs for both dnf and apt package managers. Removed unnecessary nvm installation steps. --- cn/kejilion.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 571bb0b90..7a46e35a3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9709,24 +9709,18 @@ moltbot_menu() { send_stats "开始安装 OpenClaw..." if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake libatomic + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 libatomic1 -y + apt install build-essential python3 libatomic1 nodejs -y fi - - curl -o- ${gh_proxy}raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash - - export NVM_DIR="$HOME/.nvm" - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" - - nvm install node country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com From 068dd64bd2a3f486c5bf5ca35b93e7a88883db6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:17:22 +0800 Subject: [PATCH 0839/1285] Add nodejs to package installations in kejilion.sh Updated package installation commands to include nodejs for both dnf and apt package managers. Removed nvm installation steps. --- kejilion.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 75e3d9857..130cc20a9 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9709,24 +9709,18 @@ moltbot_menu() { send_stats "开始安装 OpenClaw..." if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake libatomic + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 libatomic1 -y + apt install build-essential python3 libatomic1 nodejs -y fi - - curl -o- ${gh_proxy}raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash - - export NVM_DIR="$HOME/.nvm" - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" - - nvm install node country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com From 3ffba8a7ea921be6849743392a7bad000195cc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:27:04 +0800 Subject: [PATCH 0840/1285] Refactor installation functions in kejilion.sh --- cn/kejilion.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7a46e35a3..7007402ca 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9704,10 +9704,8 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "开始安装 OpenClaw..." - send_stats "开始安装 OpenClaw..." + install_node_and_tools() { if command -v dnf &>/dev/null; then curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y @@ -9720,6 +9718,13 @@ moltbot_menu() { apt update -y apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "开始安装 OpenClaw..." + send_stats "开始安装 OpenClaw..." + + install_node_and_tools country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then @@ -10267,6 +10272,7 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." + install_node_and_tools npm install -g openclaw@latest start_gateway add_app_id From e8cd98fb1869b6d5a96ef3631e78d29bde7d178f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:27:52 +0800 Subject: [PATCH 0841/1285] Refactor installation functions in kejilion.sh --- kejilion.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 130cc20a9..7da87dd52 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9704,10 +9704,8 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "开始安装 OpenClaw..." - send_stats "开始安装 OpenClaw..." + install_node_and_tools() { if command -v dnf &>/dev/null; then curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y @@ -9720,6 +9718,13 @@ moltbot_menu() { apt update -y apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "开始安装 OpenClaw..." + send_stats "开始安装 OpenClaw..." + + install_node_and_tools country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then @@ -10267,6 +10272,7 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." + install_node_and_tools npm install -g openclaw@latest start_gateway add_app_id From 98bb62cb8394f5877a2ee4d23db5b8af912484e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:37:34 +0800 Subject: [PATCH 0842/1285] Add hash -r command and fix if statement syntax --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7007402ca..dacfc75d9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10275,6 +10275,7 @@ EOF install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "更新完成" break_end From 7c894e014b7399c018a5514401f583b7130d73eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:38:10 +0800 Subject: [PATCH 0843/1285] Add hash refresh and fix newline issue in kejilion.sh Add hash -r command to refresh the hash table and fix missing newline at end of file. --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 7da87dd52..f807e26cb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10275,6 +10275,7 @@ EOF install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "更新完成" break_end From 6f6ce07a2d7d57dd24e4294b03b4a334ff9357c0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 22 Feb 2026 12:45:44 +0000 Subject: [PATCH 0844/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-02-22=2012:45:44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 20 ++++++++++++++------ jp/kejilion.sh | 20 ++++++++++++++------ kr/kejilion.sh | 20 ++++++++++++++------ tw/kejilion.sh | 20 ++++++++++++++------ 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 2e62ef8e6..387fca812 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -9704,22 +9704,28 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "Start installing OpenClaw..." - send_stats "Start installing OpenClaw..." + install_node_and_tools() { if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "Start installing OpenClaw..." + send_stats "Start installing OpenClaw..." + + install_node_and_tools - install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com @@ -10266,8 +10272,10 @@ EOF update_moltbot() { echo "Update OpenClaw..." send_stats "Update OpenClaw..." + install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "Update completed" break_end diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a25688abc..57cdf450d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -9704,22 +9704,28 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "OpenClaw のインストールを開始します..." - send_stats "OpenClaw のインストールを開始します..." + install_node_and_tools() { if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "OpenClaw のインストールを開始します..." + send_stats "OpenClaw のインストールを開始します..." + + install_node_and_tools - install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com @@ -10266,8 +10272,10 @@ EOF update_moltbot() { echo "OpenClaw を更新..." send_stats "OpenClaw を更新..." + install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "アップデート完了" break_end diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 378c9f367..64804ad6d 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -9704,22 +9704,28 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "OpenClaw 설치를 시작합니다..." - send_stats "OpenClaw 설치를 시작합니다..." + install_node_and_tools() { if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "OpenClaw 설치를 시작합니다..." + send_stats "OpenClaw 설치를 시작합니다..." + + install_node_and_tools - install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com @@ -10266,8 +10272,10 @@ EOF update_moltbot() { echo "오픈클로 업데이트..." send_stats "오픈클로 업데이트..." + install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "업데이트 완료" break_end diff --git a/tw/kejilion.sh b/tw/kejilion.sh index aaf536160..3d9a1b56c 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -9704,22 +9704,28 @@ moltbot_menu() { sleep 3 } - install_moltbot() { - echo "開始安裝 OpenClaw..." - send_stats "開始安裝 OpenClaw..." + install_node_and_tools() { if command -v dnf &>/dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash - dnf update -y dnf group install -y "Development Tools" "Development Libraries" - dnf install -y cmake + dnf install -y cmake libatomic nodejs fi if command -v apt &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - apt update -y - apt install build-essential python3 -y + apt install build-essential python3 libatomic1 nodejs -y fi + } + + install_moltbot() { + echo "開始安裝 OpenClaw..." + send_stats "開始安裝 OpenClaw..." + + install_node_and_tools - install node npm country=$(curl -s ipinfo.io/country) if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com @@ -10266,8 +10272,10 @@ EOF update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." + install_node_and_tools npm install -g openclaw@latest start_gateway + hash -r add_app_id echo "更新完成" break_end From 5fa03e17e9e9b70402f1d789021c41d05f648f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:07:20 +0800 Subject: [PATCH 0845/1285] Update model parameters and costs in kejilion.sh --- cn/kejilion.sh | 91 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dacfc75d9..848921704 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="true" ENABLE_STATS="true" @@ -9804,34 +9804,90 @@ moltbot_menu() { while read -r model_id; do [[ $first == false ]] && models_array+="," first=false + + # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) - # 根据模型名称推断上下文窗口 local context_window=131072 local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 + *opus*4.6*|*opus*4.5*|*sonnet*4.6*|*sonnet*4.5*|*sonnet-4*) + context_window=1000000 + max_tokens=128000 + input_cost=3.00 + output_cost=15.00 + ;; + *opus-4*|*opus*4.1*) + context_window=200000 + max_tokens=32000 + input_cost=15.00 + output_cost=75.00 + ;; + *haiku*4.5*|*haiku*) + context_window=200000 + max_tokens=64000 + input_cost=0.80 + output_cost=4.00 + ;; + *gpt-5.3*|*gpt-5.2*) + context_window=400000 + max_tokens=128000 + input_cost=1.75 + output_cost=14.00 + ;; + *gpt-5.1*|*gpt-5*codex*|*gpt-5|*gpt-5-*) + context_window=400000 + max_tokens=128000 + input_cost=1.25 + output_cost=10.00 + ;; + *gpt-5*mini*) + context_window=400000 + max_tokens=128000 + input_cost=0.25 + output_cost=2.00 + ;; + *gpt-5*nano*) + context_window=400000 + max_tokens=128000 + input_cost=0.05 + output_cost=0.40 + ;; + *gemini*3.1*pro*|*gemini*3*pro*) + context_window=1048576 + max_tokens=65536 + input_cost=2.00 + output_cost=12.00 + ;; + *gemini*3*flash*|*gemini*2.5*flash) + context_window=1048576 + max_tokens=65535 input_cost=0.30 - output_cost=0.60 + output_cost=2.50 ;; - *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 + *gemini*2.5*pro*) + context_window=1048576 + max_tokens=65536 + input_cost=1.25 + output_cost=10.00 + ;; + *flash*lite*|*lite*) + context_window=1048576 + max_tokens=65535 + input_cost=0.10 output_cost=0.40 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*image*|*image*) + context_window=65536 + max_tokens=32768 + input_cost=0.25 + output_cost=1.50 ;; esac + models_array+=$(cat </dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id From 91a0b39946d55325ceea65078a200f874535898a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:07:56 +0800 Subject: [PATCH 0846/1285] Change default parameter value to 'CN' --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 848921704..98e152bc9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="true" ENABLE_STATS="true" From 67fab9a707cceccbd0de10a629ecff993987a644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:08:25 +0800 Subject: [PATCH 0847/1285] Adjust model parameters in kejilion.sh Updated model parameters for cost and context window based on model ID. --- kejilion.sh | 89 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f807e26cb..848921704 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9804,34 +9804,90 @@ moltbot_menu() { while read -r model_id; do [[ $first == false ]] && models_array+="," first=false + + # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) - # 根据模型名称推断上下文窗口 local context_window=131072 local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 + *opus*4.6*|*opus*4.5*|*sonnet*4.6*|*sonnet*4.5*|*sonnet-4*) + context_window=1000000 + max_tokens=128000 + input_cost=3.00 + output_cost=15.00 + ;; + *opus-4*|*opus*4.1*) + context_window=200000 + max_tokens=32000 + input_cost=15.00 + output_cost=75.00 + ;; + *haiku*4.5*|*haiku*) + context_window=200000 + max_tokens=64000 + input_cost=0.80 + output_cost=4.00 + ;; + *gpt-5.3*|*gpt-5.2*) + context_window=400000 + max_tokens=128000 + input_cost=1.75 + output_cost=14.00 + ;; + *gpt-5.1*|*gpt-5*codex*|*gpt-5|*gpt-5-*) + context_window=400000 + max_tokens=128000 + input_cost=1.25 + output_cost=10.00 + ;; + *gpt-5*mini*) + context_window=400000 + max_tokens=128000 + input_cost=0.25 + output_cost=2.00 + ;; + *gpt-5*nano*) + context_window=400000 + max_tokens=128000 + input_cost=0.05 + output_cost=0.40 + ;; + *gemini*3.1*pro*|*gemini*3*pro*) + context_window=1048576 + max_tokens=65536 + input_cost=2.00 + output_cost=12.00 + ;; + *gemini*3*flash*|*gemini*2.5*flash) + context_window=1048576 + max_tokens=65535 input_cost=0.30 - output_cost=0.60 + output_cost=2.50 ;; - *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 + *gemini*2.5*pro*) + context_window=1048576 + max_tokens=65536 + input_cost=1.25 + output_cost=10.00 + ;; + *flash*lite*|*lite*) + context_window=1048576 + max_tokens=65535 + input_cost=0.10 output_cost=0.40 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*image*|*image*) + context_window=65536 + max_tokens=32768 + input_cost=0.25 + output_cost=1.50 ;; esac + models_array+=$(cat </dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id From c4faa13414a878aab1162e797c6200da8252ecd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:34:41 +0800 Subject: [PATCH 0848/1285] Update model parameters and costs in kejilion.sh --- kejilion.sh | 75 ++++++++++++++++------------------------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 848921704..7a12d796b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9806,88 +9806,59 @@ moltbot_menu() { first=false # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) - local context_window=131072 local max_tokens=8192 local input_cost=0.15 local output_cost=0.60 case "$model_id" in - *opus*4.6*|*opus*4.5*|*sonnet*4.6*|*sonnet*4.5*|*sonnet-4*) + + # 旗舰级(opus/pro级别) + *opus*|*-pro|*-pro-*) context_window=1000000 max_tokens=128000 - input_cost=3.00 - output_cost=15.00 - ;; - *opus-4*|*opus*4.1*) - context_window=200000 - max_tokens=32000 - input_cost=15.00 - output_cost=75.00 - ;; - *haiku*4.5*|*haiku*) - context_window=200000 - max_tokens=64000 - input_cost=0.80 - output_cost=4.00 + input_cost=5.00 + output_cost=25.00 ;; - *gpt-5.3*|*gpt-5.2*) + # 标准级(sonnet/codex/主力模型) + *sonnet*|*codex*|gpt-5*|gpt-5.*) context_window=400000 max_tokens=128000 input_cost=1.75 output_cost=14.00 ;; - *gpt-5.1*|*gpt-5*codex*|*gpt-5|*gpt-5-*) - context_window=400000 - max_tokens=128000 - input_cost=1.25 - output_cost=10.00 - ;; - *gpt-5*mini*) - context_window=400000 - max_tokens=128000 + # 轻量级(haiku/mini/nano/lite) + *haiku*|*mini*|*nano*|*lite*) + context_window=200000 + max_tokens=64000 input_cost=0.25 output_cost=2.00 ;; - *gpt-5*nano*) - context_window=400000 - max_tokens=128000 - input_cost=0.05 - output_cost=0.40 - ;; - *gemini*3.1*pro*|*gemini*3*pro*) - context_window=1048576 - max_tokens=65536 - input_cost=2.00 - output_cost=12.00 - ;; - *gemini*3*flash*|*gemini*2.5*flash) + # Flash级(flash系列) + *flash*) context_window=1048576 max_tokens=65535 input_cost=0.30 output_cost=2.50 ;; - *gemini*2.5*pro*) - context_window=1048576 - max_tokens=65536 - input_cost=1.25 - output_cost=10.00 - ;; - *flash*lite*|*lite*) - context_window=1048576 - max_tokens=65535 - input_cost=0.10 - output_cost=0.40 - ;; - *flash*image*|*image*) + # Image 模型(上下文小) + *image*) context_window=65536 max_tokens=32768 input_cost=0.25 output_cost=1.50 ;; + # Thinking 模型(推理增强) + *thinking*|*reason*) + context_window=200000 + max_tokens=64000 + input_cost=1.00 + output_cost=5.00 + ;; esac + models_array+=$(cat < Date: Sun, 1 Mar 2026 12:35:16 +0800 Subject: [PATCH 0849/1285] Refactor model parameter settings in kejilion.sh Updated model parameters for various model types, including input and output costs. --- cn/kejilion.sh | 75 ++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 98e152bc9..a20220b7f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9806,88 +9806,59 @@ moltbot_menu() { first=false # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) - local context_window=131072 local max_tokens=8192 local input_cost=0.15 local output_cost=0.60 case "$model_id" in - *opus*4.6*|*opus*4.5*|*sonnet*4.6*|*sonnet*4.5*|*sonnet-4*) + + # 旗舰级(opus/pro级别) + *opus*|*-pro|*-pro-*) context_window=1000000 max_tokens=128000 - input_cost=3.00 - output_cost=15.00 - ;; - *opus-4*|*opus*4.1*) - context_window=200000 - max_tokens=32000 - input_cost=15.00 - output_cost=75.00 - ;; - *haiku*4.5*|*haiku*) - context_window=200000 - max_tokens=64000 - input_cost=0.80 - output_cost=4.00 + input_cost=5.00 + output_cost=25.00 ;; - *gpt-5.3*|*gpt-5.2*) + # 标准级(sonnet/codex/主力模型) + *sonnet*|*codex*|gpt-5*|gpt-5.*) context_window=400000 max_tokens=128000 input_cost=1.75 output_cost=14.00 ;; - *gpt-5.1*|*gpt-5*codex*|*gpt-5|*gpt-5-*) - context_window=400000 - max_tokens=128000 - input_cost=1.25 - output_cost=10.00 - ;; - *gpt-5*mini*) - context_window=400000 - max_tokens=128000 + # 轻量级(haiku/mini/nano/lite) + *haiku*|*mini*|*nano*|*lite*) + context_window=200000 + max_tokens=64000 input_cost=0.25 output_cost=2.00 ;; - *gpt-5*nano*) - context_window=400000 - max_tokens=128000 - input_cost=0.05 - output_cost=0.40 - ;; - *gemini*3.1*pro*|*gemini*3*pro*) - context_window=1048576 - max_tokens=65536 - input_cost=2.00 - output_cost=12.00 - ;; - *gemini*3*flash*|*gemini*2.5*flash) + # Flash级(flash系列) + *flash*) context_window=1048576 max_tokens=65535 input_cost=0.30 output_cost=2.50 ;; - *gemini*2.5*pro*) - context_window=1048576 - max_tokens=65536 - input_cost=1.25 - output_cost=10.00 - ;; - *flash*lite*|*lite*) - context_window=1048576 - max_tokens=65535 - input_cost=0.10 - output_cost=0.40 - ;; - *flash*image*|*image*) + # Image 模型(上下文小) + *image*) context_window=65536 max_tokens=32768 input_cost=0.25 output_cost=1.50 ;; + # Thinking 模型(推理增强) + *thinking*|*reason*) + context_window=200000 + max_tokens=64000 + input_cost=1.00 + output_cost=5.00 + ;; esac + models_array+=$(cat < Date: Sun, 1 Mar 2026 12:45:35 +0800 Subject: [PATCH 0850/1285] Refactor model parameter inference logic --- cn/kejilion.sh | 54 ++++++++++++++------------------------------------ 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a20220b7f..db5ef860b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9805,60 +9805,36 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) + # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) local context_window=131072 local max_tokens=8192 local input_cost=0.15 local output_cost=0.60 - + case "$model_id" in - - # 旗舰级(opus/pro级别) - *opus*|*-pro|*-pro-*) - context_window=1000000 + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M max_tokens=128000 - input_cost=5.00 - output_cost=25.00 + input_cost=2.00 + output_cost=12.00 ;; - # 标准级(sonnet/codex/主力模型) - *sonnet*|*codex*|gpt-5*|gpt-5.*) - context_window=400000 + *gpt-5*|*codex*) + context_window=400000 # 400K max_tokens=128000 - input_cost=1.75 - output_cost=14.00 - ;; - # 轻量级(haiku/mini/nano/lite) - *haiku*|*mini*|*nano*|*lite*) - context_window=200000 - max_tokens=64000 - input_cost=0.25 - output_cost=2.00 + input_cost=1.25 + output_cost=10.00 ;; - # Flash级(flash系列) - *flash*) - context_window=1048576 + *flash*|*lite*|*haiku*) + context_window=1048576 # 1M max_tokens=65535 - input_cost=0.30 - output_cost=2.50 - ;; - # Image 模型(上下文小) - *image*) - context_window=65536 - max_tokens=32768 - input_cost=0.25 - output_cost=1.50 - ;; - # Thinking 模型(推理增强) - *thinking*|*reason*) - context_window=200000 - max_tokens=64000 - input_cost=1.00 - output_cost=5.00 + input_cost=0.10 + output_cost=0.40 ;; esac + models_array+=$(cat < Date: Sun, 1 Mar 2026 12:46:03 +0800 Subject: [PATCH 0851/1285] Update kejilion.sh --- kejilion.sh | 54 +++++++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7a12d796b..a61e80792 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9805,60 +9805,36 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # 智能推断模型参数(基于 OpenRouter 2026-03 数据校准) + # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) local context_window=131072 local max_tokens=8192 local input_cost=0.15 local output_cost=0.60 - + case "$model_id" in - - # 旗舰级(opus/pro级别) - *opus*|*-pro|*-pro-*) - context_window=1000000 + *preview*|*thinking*|*opus*|*pro*) + context_window=1048576 # 1M max_tokens=128000 - input_cost=5.00 - output_cost=25.00 + input_cost=2.00 + output_cost=12.00 ;; - # 标准级(sonnet/codex/主力模型) - *sonnet*|*codex*|gpt-5*|gpt-5.*) - context_window=400000 + *gpt-5*|*codex*) + context_window=400000 # 400K max_tokens=128000 - input_cost=1.75 - output_cost=14.00 - ;; - # 轻量级(haiku/mini/nano/lite) - *haiku*|*mini*|*nano*|*lite*) - context_window=200000 - max_tokens=64000 - input_cost=0.25 - output_cost=2.00 + input_cost=1.25 + output_cost=10.00 ;; - # Flash级(flash系列) - *flash*) - context_window=1048576 + *flash*|*lite*|*haiku*) + context_window=1048576 # 1M max_tokens=65535 - input_cost=0.30 - output_cost=2.50 - ;; - # Image 模型(上下文小) - *image*) - context_window=65536 - max_tokens=32768 - input_cost=0.25 - output_cost=1.50 - ;; - # Thinking 模型(推理增强) - *thinking*|*reason*) - context_window=200000 - max_tokens=64000 - input_cost=1.00 - output_cost=5.00 + input_cost=0.10 + output_cost=0.40 ;; esac + models_array+=$(cat < Date: Sun, 1 Mar 2026 12:56:06 +0800 Subject: [PATCH 0852/1285] Update model parameters in kejilion.sh --- cn/kejilion.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index db5ef860b..7e2ebaec1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9806,13 +9806,13 @@ moltbot_menu() { first=false # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) - local context_window=131072 - local max_tokens=8192 - local input_cost=0.15 - local output_cost=0.60 + local context_window=1048576 + local max_tokens=128000 + local input_cost=1.00 + local output_cost=6.00 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) + *preview*|*thinking*|*opus*|*pro*|*sonnet*) context_window=1048576 # 1M max_tokens=128000 input_cost=2.00 @@ -9833,8 +9833,6 @@ moltbot_menu() { esac - - models_array+=$(cat < Date: Sun, 1 Mar 2026 12:56:32 +0800 Subject: [PATCH 0853/1285] Update model parameters for context and cost --- kejilion.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a61e80792..a76fd10bc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9806,13 +9806,13 @@ moltbot_menu() { first=false # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) - local context_window=131072 - local max_tokens=8192 - local input_cost=0.15 - local output_cost=0.60 + local context_window=1048576 + local max_tokens=128000 + local input_cost=1.00 + local output_cost=6.00 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) + *preview*|*thinking*|*opus*|*pro*|*sonnet*) context_window=1048576 # 1M max_tokens=128000 input_cost=2.00 @@ -9833,8 +9833,6 @@ moltbot_menu() { esac - - models_array+=$(cat < Date: Sun, 1 Mar 2026 12:58:29 +0800 Subject: [PATCH 0854/1285] Update kejilion.sh --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a76fd10bc..78ee599c2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9808,8 +9808,8 @@ moltbot_menu() { # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) local context_window=1048576 local max_tokens=128000 - local input_cost=1.00 - local output_cost=6.00 + local input_cost=0.10 + local output_cost=0.40 case "$model_id" in *preview*|*thinking*|*opus*|*pro*|*sonnet*) From 6eddd3e2cb79e34f0a772a4c4c0c8e4cf9cca3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:59:03 +0800 Subject: [PATCH 0855/1285] Update input and output costs in kejilion.sh --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7e2ebaec1..2bc9a721b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9808,8 +9808,8 @@ moltbot_menu() { # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) local context_window=1048576 local max_tokens=128000 - local input_cost=1.00 - local output_cost=6.00 + local input_cost=0.10 + local output_cost=0.40 case "$model_id" in *preview*|*thinking*|*opus*|*pro*|*sonnet*) From 7f449d993b36dd0a0fac07d6650d3a255672977c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:06:42 +0800 Subject: [PATCH 0856/1285] Refactor model costs and context window settings Updated input and output costs for various models and adjusted context window settings. --- cn/kejilion.sh | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2bc9a721b..f9260577d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9804,35 +9804,30 @@ moltbot_menu() { while read -r model_id; do [[ $first == false ]] && models_array+="," first=false - - # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) + + # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - local input_cost=0.10 - local output_cost=0.40 - + + # 只有价格需要分级 + local input_cost=0.15 + local output_cost=0.60 + case "$model_id" in - *preview*|*thinking*|*opus*|*pro*|*sonnet*) - context_window=1048576 # 1M - max_tokens=128000 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) input_cost=2.00 output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=400000 # 400K - max_tokens=128000 input_cost=1.25 output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=1048576 # 1M - max_tokens=65535 + *flash*|*lite*|*haiku*|*mini*|*nano*) input_cost=0.10 output_cost=0.40 ;; esac - models_array+=$(cat < Date: Sun, 1 Mar 2026 13:07:10 +0800 Subject: [PATCH 0857/1285] Refactor model cost and context window settings Updated input and output costs for various model IDs and adjusted context window settings. --- kejilion.sh | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 78ee599c2..242a50f95 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9804,35 +9804,30 @@ moltbot_menu() { while read -r model_id; do [[ $first == false ]] && models_array+="," first=false - - # 根据模型名称推断上下文窗口(OpenRouter 2026-03 校准) + + # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - local input_cost=0.10 - local output_cost=0.40 - + + # 只有价格需要分级 + local input_cost=0.15 + local output_cost=0.60 + case "$model_id" in - *preview*|*thinking*|*opus*|*pro*|*sonnet*) - context_window=1048576 # 1M - max_tokens=128000 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) input_cost=2.00 output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=400000 # 400K - max_tokens=128000 input_cost=1.25 output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=1048576 # 1M - max_tokens=65535 + *flash*|*lite*|*haiku*|*mini*|*nano*) input_cost=0.10 output_cost=0.40 ;; esac - models_array+=$(cat < Date: Sun, 1 Mar 2026 18:18:14 +0800 Subject: [PATCH 0858/1285] Add files via upload --- network-optimize.sh | 557 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 557 insertions(+) create mode 100644 network-optimize.sh diff --git a/network-optimize.sh b/network-optimize.sh new file mode 100644 index 000000000..db05e52d5 --- /dev/null +++ b/network-optimize.sh @@ -0,0 +1,557 @@ +#!/bin/bash +# ============================================================================ +# 自动网络性能检测与内核优化脚本 +# 适配:Debian/Ubuntu, CentOS/RHEL/Alma/Rocky, Alpine, Arch, Fedora +# 作者:kejilion +# ============================================================================ + +# ======================== 颜色定义 ======================== +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' + +# ======================== 工具函数 ======================== +info() { echo -e "${CYAN}[检测]${NC} $*"; } +ok() { echo -e "${GREEN}[✓]${NC} $*"; } +warn() { echo -e "${YELLOW}[!]${NC} $*"; } +fail() { echo -e "${RED}[✗]${NC} $*"; } +title() { echo -e "\n${WHITE}━━━ $* ━━━${NC}"; } + +# 获取内核主版本号用于兼容性判断 +kernel_version() { + local ver + ver=$(uname -r | grep -oP '^\d+\.\d+') + echo "$ver" +} + +# 比较版本号: version_ge 5.4 4.9 => true +version_ge() { + printf '%s\n%s' "$2" "$1" | sort -V -C +} + +# 安全读取 sysctl 值 +sysctl_get() { + sysctl -n "$1" 2>/dev/null || echo "N/A" +} + +# 获取发行版 +detect_distro() { + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + debian|ubuntu|linuxmint|pop|kali) echo "debian" ;; + centos|rhel|almalinux|rocky|ol|amzn|fedora) echo "rhel" ;; + alpine) echo "alpine" ;; + arch|manjaro|endeavouros) echo "arch" ;; + opensuse*|sles) echo "suse" ;; + *) echo "unknown" ;; + esac + elif [ -f /etc/debian_version ]; then + echo "debian" + elif [ -f /etc/redhat-release ]; then + echo "rhel" + else + echo "unknown" + fi +} + +# ======================== 网络检测 ======================== + +# 检测网卡速率(Mbps) +detect_link_speed() { + local speed=0 + local iface + + # 获取默认路由网卡 + iface=$(ip route show default 2>/dev/null | awk '/default/{print $5}' | head -1) + [ -z "$iface" ] && iface=$(ls /sys/class/net/ | grep -v lo | head -1) + + if [ -n "$iface" ]; then + # 尝试 ethtool + if command -v ethtool &>/dev/null; then + speed=$(ethtool "$iface" 2>/dev/null | awk '/Speed:/{gsub(/[^0-9]/,"",$2); print $2}') + fi + + # 尝试 sysfs + if [ -z "$speed" ] || [ "$speed" = "0" ]; then + speed=$(cat "/sys/class/net/$iface/speed" 2>/dev/null) + fi + fi + + # VPS 虚拟网卡可能读不到速率,默认 1000 + [ -z "$speed" ] || [ "$speed" -le 0 ] 2>/dev/null && speed=1000 + + echo "$speed" +} + +# 检测网络延迟(ms,ping 多个公共 DNS) +detect_latency() { + local total=0 count=0 avg + local targets=("8.8.8.8" "1.1.1.1" "9.9.9.9" "208.67.222.222") + + for t in "${targets[@]}"; do + local rtt + rtt=$(ping -c 3 -W 2 "$t" 2>/dev/null | awk -F'/' '/avg/{print $5}') + if [ -n "$rtt" ]; then + total=$(awk "BEGIN{print $total + $rtt}") + count=$((count + 1)) + fi + done + + if [ "$count" -gt 0 ]; then + avg=$(awk "BEGIN{printf \"%.1f\", $total / $count}") + else + avg="50" + fi + + echo "$avg" +} + +# 检测丢包率(%) +detect_packet_loss() { + local loss + loss=$(ping -c 10 -W 2 8.8.8.8 2>/dev/null | awk -F',' '/loss/{gsub(/%/,"",$3); gsub(/ packet/,"",$3); print $3+0}') + [ -z "$loss" ] && loss=0 + echo "$loss" +} + +# 获取当前 TCP 拥塞算法 +detect_congestion() { + sysctl_get net.ipv4.tcp_congestion_control +} + +# 检测总物理内存(MB) +detect_memory_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} + +# ======================== 带宽分级 ======================== +# 返回: low / medium / high / ultra +classify_bandwidth() { + local speed=$1 + if [ "$speed" -lt 100 ]; then + echo "low" + elif [ "$speed" -lt 1000 ]; then + echo "medium" + elif [ "$speed" -lt 10000 ]; then + echo "high" + else + echo "ultra" + fi +} + +# ======================== 核心优化函数 ======================== + +auto_optimize_network() { + local CONF="/etc/sysctl.d/99-network-optimize.conf" + local BACKUP="/etc/sysctl.d/99-network-optimize.conf.bak.$(date +%s)" + local KVER + KVER=$(kernel_version) + local DISTRO + DISTRO=$(detect_distro) + + echo -e "${WHITE}" + echo "╔══════════════════════════════════════════════════════════════╗" + echo "║ 自动网络性能检测与内核优化 ║" + echo "╚══════════════════════════════════════════════════════════════╝" + echo -e "${NC}" + + # ── 权限检查 ── + if [ "$(id -u)" -ne 0 ]; then + fail "请以 root 权限运行" + return 1 + fi + + # ── 环境信息 ── + title "环境信息" + info "发行版: $(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || echo "$DISTRO")" + info "内核版本: $(uname -r)" + info "架构: $(uname -m)" + info "内存: $(detect_memory_mb) MB" + + # ── 网络检测 ── + title "网络性能检测" + + local SPEED LATENCY LOSS CONGESTION MEM_MB BW_CLASS + + info "检测网卡速率..." + SPEED=$(detect_link_speed) + ok "链路速率: ${SPEED} Mbps" + + info "检测网络延迟..." + LATENCY=$(detect_latency) + ok "平均延迟: ${LATENCY} ms" + + info "检测丢包率..." + LOSS=$(detect_packet_loss) + ok "丢包率: ${LOSS}%" + + CONGESTION=$(detect_congestion) + ok "当前拥塞算法: ${CONGESTION}" + + MEM_MB=$(detect_memory_mb) + BW_CLASS=$(classify_bandwidth "$SPEED") + + title "检测结论" + case "$BW_CLASS" in + low) info "带宽等级: ${YELLOW}低带宽 (<100M)${NC} → 保守优化" ;; + medium) info "带宽等级: ${CYAN}中带宽 (100M-1G)${NC} → 标准优化" ;; + high) info "带宽等级: ${GREEN}高带宽 (1G-10G)${NC} → 激进优化" ;; + ultra) info "带宽等级: ${WHITE}超高带宽 (>10G)${NC} → 极致优化" ;; + esac + + local HIGH_LATENCY=false + if [ "$(awk "BEGIN{print ($LATENCY > 100)}")" = "1" ]; then + HIGH_LATENCY=true + warn "高延迟网络 (${LATENCY}ms > 100ms),启用额外优化" + fi + + # ── 备份现有配置 ── + title "备份与准备" + if [ -f "$CONF" ]; then + cp "$CONF" "$BACKUP" + ok "已备份: $BACKUP" + else + ok "首次优化,无需备份" + fi + + # ── 根据带宽等级设定参数 ── + local TCP_RMEM_MAX TCP_WMEM_MAX TCP_RMEM TCP_WMEM + local NETDEV_BUDGET NETDEV_BUDGET_USECS + local SOMAXCONN NETDEV_BACKLOG + local CONNTRACK_MAX + + case "$BW_CLASS" in + low) + TCP_RMEM="4096 65536 2097152" + TCP_WMEM="4096 65536 2097152" + TCP_RMEM_MAX=2097152 + TCP_WMEM_MAX=2097152 + SOMAXCONN=1024 + NETDEV_BACKLOG=1000 + NETDEV_BUDGET=300 + NETDEV_BUDGET_USECS=2000 + CONNTRACK_MAX=65536 + ;; + medium) + TCP_RMEM="4096 131072 16777216" + TCP_WMEM="4096 131072 16777216" + TCP_RMEM_MAX=16777216 + TCP_WMEM_MAX=16777216 + SOMAXCONN=4096 + NETDEV_BACKLOG=5000 + NETDEV_BUDGET=600 + NETDEV_BUDGET_USECS=4000 + CONNTRACK_MAX=262144 + ;; + high) + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + TCP_RMEM_MAX=67108864 + TCP_WMEM_MAX=67108864 + SOMAXCONN=8192 + NETDEV_BACKLOG=10000 + NETDEV_BUDGET=1200 + NETDEV_BUDGET_USECS=6000 + CONNTRACK_MAX=524288 + ;; + ultra) + TCP_RMEM="4096 524288 134217728" + TCP_WMEM="4096 524288 134217728" + TCP_RMEM_MAX=134217728 + TCP_WMEM_MAX=134217728 + SOMAXCONN=16384 + NETDEV_BACKLOG=20000 + NETDEV_BUDGET=2400 + NETDEV_BUDGET_USECS=8000 + CONNTRACK_MAX=1048576 + ;; + esac + + # 高延迟追加:加大初始窗口 + local HIGH_LAT_EXTRA="" + if $HIGH_LATENCY; then + # 高延迟网络使用更大的初始拥塞窗口提升吞吐 + HIGH_LAT_EXTRA=" +# ── 高延迟网络额外优化 ── +net.ipv4.tcp_slow_start_after_idle = 0 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # 内存不足时缩小缓冲区 + if [ "$MEM_MB" -lt 512 ]; then + warn "内存不足 512MB,缩小 TCP 缓冲区" + TCP_RMEM="4096 32768 1048576" + TCP_WMEM="4096 32768 1048576" + TCP_RMEM_MAX=1048576 + TCP_WMEM_MAX=1048576 + CONNTRACK_MAX=32768 + fi + + # ── BBR 检测与加载 ── + title "TCP 拥塞算法优化" + local USE_BBR=false + local TARGET_CC="cubic" + + if version_ge "$KVER" "4.9"; then + # 内核 >= 4.9 支持 BBR + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + if lsmod 2>/dev/null | grep -q tcp_bbr; then + ok "BBR 模块已加载" + else + warn "BBR 模块加载失败,使用 cubic" + fi + fi + + if sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + USE_BBR=true + TARGET_CC="bbr" + ok "拥塞算法: cubic → ${GREEN}BBR${NC}" + fi + else + warn "内核 $KVER < 4.9,不支持 BBR,保持 cubic" + fi + + # BBR 配合 fq 队列调度 + local QDISC="fq" + if ! $USE_BBR; then + QDISC="fq_codel" + fi + + # ── 生成优化配置 ── + title "写入优化配置" + + cat > "$CONF" << SYSCTL +# ============================================================================ +# 自动网络优化配置 +# 生成时间: $(date '+%Y-%m-%d %H:%M:%S') +# 带宽等级: $BW_CLASS (${SPEED}Mbps) +# 平均延迟: ${LATENCY}ms | 丢包率: ${LOSS}% +# 内核: $(uname -r) | 发行版: $DISTRO | 内存: ${MEM_MB}MB +# ============================================================================ + +# ── TCP 拥塞控制 ── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $TARGET_CC + +# ── TCP 缓冲区 ── +net.core.rmem_max = $TCP_RMEM_MAX +net.core.wmem_max = $TCP_WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM +net.ipv4.udp_rmem_min = 8192 +net.ipv4.udp_wmem_min = 8192 + +# ── 连接队列 ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $NETDEV_BACKLOG +net.core.netdev_budget = $NETDEV_BUDGET +$(sysctl -n net.core.netdev_budget_usecs &>/dev/null && echo "net.core.netdev_budget_usecs = $NETDEV_BUDGET_USECS" || echo "# netdev_budget_usecs 不支持,跳过") + +# ── TCP 连接优化 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = 15 +net.ipv4.tcp_keepalive_time = 300 +net.ipv4.tcp_keepalive_intvl = 30 +net.ipv4.tcp_keepalive_probes = 5 +net.ipv4.tcp_max_syn_backlog = $SOMAXCONN +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── 内存与端口 ── +net.ipv4.ip_local_port_range = 1024 65535 +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 安全与防护 ── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 + +# ── IPv6 优化 ── +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── 文件描述符 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 连接跟踪 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then + echo "net.netfilter.nf_conntrack_max = $CONNTRACK_MAX" + echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" + echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" + echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" + echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else + echo "# conntrack 未启用,跳过" +fi) +$HIGH_LAT_EXTRA +SYSCTL + + ok "配置已写入: $CONF" + + # ── 应用配置 ── + title "应用优化" + local apply_errors + apply_errors=$(sysctl -p "$CONF" 2>&1 | grep -i "error\|invalid\|cannot" || true) + + if [ -n "$apply_errors" ]; then + warn "部分参数不支持(已跳过):" + echo "$apply_errors" | while read -r line; do + echo -e " ${YELLOW}$line${NC}" + done + fi + ok "sysctl 参数已应用" + + # ── 设置文件描述符限制 ── + if ! grep -q "# network-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' + +# network-optimize - 自动网络优化添加 +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + ok "文件描述符限制已更新" + fi + + # ── 持久化 BBR 模块 ── + if $USE_BBR; then + if [ ! -f /etc/modules-load.d/bbr.conf ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + ok "BBR 模块持久化" + fi + fi + + # ── 优化摘要 ── + title "优化摘要" + echo -e "${WHITE}┌──────────────────────────────────────────────────┐${NC}" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "项目" "值" + echo -e "${WHITE}├──────────────────────────────────────────────────┤${NC}" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "带宽等级" "$BW_CLASS (${SPEED}Mbps)" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "拥塞算法" "$TARGET_CC" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "队列调度" "$QDISC" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "TCP 缓冲区(max)" "$(numfmt --to=iec $TCP_RMEM_MAX 2>/dev/null || echo ${TCP_RMEM_MAX})" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "连接队列" "$SOMAXCONN" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "网络延迟" "${LATENCY}ms" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "高延迟优化" "$(if $HIGH_LATENCY; then echo '已启用'; else echo '未需要'; fi)" + printf "${WHITE}│${NC} %-20s ${WHITE}│${NC} %-25s ${WHITE}│${NC}\n" "配置文件" "$CONF" + echo -e "${WHITE}└──────────────────────────────────────────────────┘${NC}" + + echo -e "\n${GREEN}网络优化完成!${NC}" + echo -e "回滚命令: ${CYAN}restore_network_defaults${NC}" +} + +# ======================== 回滚函数 ======================== + +restore_network_defaults() { + local CONF="/etc/sysctl.d/99-network-optimize.conf" + + title "回滚网络优化" + + if [ "$(id -u)" -ne 0 ]; then + fail "请以 root 权限运行" + return 1 + fi + + # 查找最近的备份 + local latest_bak + latest_bak=$(ls -t /etc/sysctl.d/99-network-optimize.conf.bak.* 2>/dev/null | head -1) + + if [ -n "$latest_bak" ]; then + cp "$latest_bak" "$CONF" + sysctl -p "$CONF" 2>/dev/null + ok "已从备份恢复: $latest_bak" + elif [ -f "$CONF" ]; then + rm -f "$CONF" + sysctl --system 2>/dev/null + ok "已删除优化配置,恢复系统默认" + else + warn "没有优化配置需要回滚" + return 0 + fi + + # 清理 limits.conf 添加的部分 + if grep -q "# network-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# network-optimize/,+4d' /etc/security/limits.conf + ok "文件描述符限制已恢复" + fi + + # 清理 BBR 持久化 + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + + ok "网络配置已回滚" +} + +# ======================== 查看当前状态 ======================== + +show_network_status() { + title "当前网络内核参数" + + local params=( + "net.ipv4.tcp_congestion_control" + "net.core.default_qdisc" + "net.core.rmem_max" + "net.core.wmem_max" + "net.ipv4.tcp_rmem" + "net.ipv4.tcp_wmem" + "net.core.somaxconn" + "net.core.netdev_max_backlog" + "net.ipv4.tcp_fastopen" + "net.ipv4.tcp_tw_reuse" + "net.ipv4.tcp_fin_timeout" + "net.ipv4.ip_local_port_range" + "net.ipv4.tcp_mtu_probing" + "fs.file-max" + ) + + for p in "${params[@]}"; do + local val + val=$(sysctl_get "$p") + printf " %-45s = %s\n" "$p" "$val" + done + + if [ -f /etc/sysctl.d/99-network-optimize.conf ]; then + echo "" + ok "优化配置已安装: /etc/sysctl.d/99-network-optimize.conf" + else + echo "" + warn "未检测到优化配置" + fi +} + +# ======================== 入口 ======================== +# 用法: +# source network-optimize.sh +# auto_optimize_network # 自动检测并优化 +# show_network_status # 查看当前状态 +# restore_network_defaults # 回滚到默认 +# +# 或直接运行: +# bash network-optimize.sh +# ======================== + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + auto_optimize_network +fi From e8c88c315812eb892de8ccfff7dc678c78be4df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 18:22:17 +0800 Subject: [PATCH 0859/1285] Fix condition to run auto_optimize_network --- network-optimize.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network-optimize.sh b/network-optimize.sh index db05e52d5..8e5f1de3c 100644 --- a/network-optimize.sh +++ b/network-optimize.sh @@ -552,6 +552,6 @@ show_network_status() { # bash network-optimize.sh # ======================== -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then +if [[ "${BASH_SOURCE[0]}" == "${0}" ]] || [[ -z "${BASH_SOURCE[0]}" ]]; then auto_optimize_network fi From 74bdd85fe72e2c5ef4a22d3d137558863de0a7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 18:56:05 +0800 Subject: [PATCH 0860/1285] Update version and optimize kernel parameters --- cn/kejilion.sh | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f9260577d..55c32e9c0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -6026,13 +6026,14 @@ Kernel_optimize() { echo "------------------------------------------------" echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" - echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "--------------------" + echo -e "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo -e "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo -e "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo -e "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -6075,8 +6076,17 @@ Kernel_optimize() { cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "还原默认设置" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "内核自动调优" + ;; + *) break ;; @@ -15977,7 +15987,7 @@ EOF echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo -e "12. Linux系统内核参数优化${gl_huang}自动根据网络环境调优${gl_bai}" echo "------------------------------------------------" read -e -p "确定一键保养吗?(Y/N): " choice @@ -16031,7 +16041,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" From e5fdbef18b043521e1bec9b617eb96dbcebb874f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 18:56:39 +0800 Subject: [PATCH 0861/1285] Update version and optimize network settings --- kejilion.sh | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 242a50f95..00824ee01 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -6026,13 +6026,14 @@ Kernel_optimize() { echo "------------------------------------------------" echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" - echo "--------------------" - echo "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" - echo "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" - echo "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "--------------------" + echo -e "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo -e "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" + echo -e "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" + echo -e "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -6075,8 +6076,17 @@ Kernel_optimize() { cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "还原默认设置" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "内核自动调优" + ;; + *) break ;; @@ -15977,7 +15987,7 @@ EOF echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux系统内核参数优化切换到${gl_huang}均衡优化模式${gl_bai}" + echo -e "12. Linux系统内核参数优化${gl_huang}自动根据网络环境调优${gl_bai}" echo "------------------------------------------------" read -e -p "确定一键保养吗?(Y/N): " choice @@ -16031,7 +16041,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" From cbc2795e2273a31c6fb22c5d12dc446c8538198f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 18:59:52 +0800 Subject: [PATCH 0862/1285] Update kejilion_sh_log.txt for version 4.4.1 Added release notes for version 4.4.1, detailing new features and optimizations. --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 555a11057..55211733f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1457,4 +1457,9 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目使用原生启动保活机制,之前原生不稳定。 应用市场对ClawdBot/Moltbot机器人项目日志选项进行优化,看日志同时显示运行状态信息。 ------------------------ +2026-03-01 v4.4.1 +系统工具内核调优功能增加自动内核调优选项,会根据网络智能调整系统参数。 +系统工具一条龙调优原本均衡内核调优现在改为自动内核调优。 +应用市场对ClawdBot/Moltbot机器人项目添加API时对模型的最大输出输入等参数进行优化,让大模型更稳定, +------------------------ From a2c3af8c64becbff00fbc25c8ff5e169addda7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 19:01:55 +0800 Subject: [PATCH 0863/1285] Enhance network optimization script with VM settings Add VM parameters based on memory size and optimize virtual memory and CPU scheduling settings. --- network-optimize.sh | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/network-optimize.sh b/network-optimize.sh index 8e5f1de3c..51fe8caff 100644 --- a/network-optimize.sh +++ b/network-optimize.sh @@ -292,6 +292,26 @@ net.ipv4.tcp_notsent_lowat = 16384" CONNTRACK_MAX=32768 fi + # ── 根据内存大小设定 VM 参数 ── + local SWAPPINESS MIN_FREE_KB + if [ "$MEM_MB" -ge 16384 ]; then + # 16G+ 大内存:激进 + SWAPPINESS=5 + MIN_FREE_KB=131072 + elif [ "$MEM_MB" -ge 4096 ]; then + # 4G-16G:标准 + SWAPPINESS=10 + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + # 1G-4G:保守 + SWAPPINESS=20 + MIN_FREE_KB=32768 + else + # <1G:极度保守 + SWAPPINESS=30 + MIN_FREE_KB=16384 + fi + # ── BBR 检测与加载 ── title "TCP 拥塞算法优化" local USE_BBR=false @@ -391,6 +411,18 @@ net.ipv4.conf.default.send_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 +# ── 虚拟内存优化 ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = 15 +vm.dirty_background_ratio = 5 +vm.overcommit_memory = 1 +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = 50 + +# ── CPU/内核调度优化 ── +kernel.sched_autogroup_enabled = 0 +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = 0" || echo "# numa_balancing 不支持,跳过") + # ── 文件描述符 ── fs.file-max = 1048576 fs.nr_open = 1048576 @@ -423,6 +455,12 @@ SYSCTL fi ok "sysctl 参数已应用" + # ── 禁用透明大页面(减少延迟抖动) ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo never > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null && \ + ok "透明大页面已禁用" || warn "透明大页面禁用失败" + fi + # ── 设置文件描述符限制 ── if ! grep -q "# network-optimize" /etc/security/limits.conf 2>/dev/null; then cat >> /etc/security/limits.conf << 'LIMITS' @@ -553,5 +591,18 @@ show_network_status() { # ======================== if [[ "${BASH_SOURCE[0]}" == "${0}" ]] || [[ -z "${BASH_SOURCE[0]}" ]]; then - auto_optimize_network + # 支持参数: bash xxx.sh restore / bash xxx.sh status + # 支持环境变量: ACTION=restore curl ... | bash + _action="${1:-${ACTION:-optimize}}" + case "$_action" in + restore|rollback|回滚) + restore_network_defaults + ;; + status|状态) + show_network_status + ;; + *) + auto_optimize_network + ;; + esac fi From 9184cdc557c842d8b9fc0e0e559e67789628daa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:38:02 +0800 Subject: [PATCH 0864/1285] Refactor kernel optimization functions for clarity --- cn/kejilion.sh | 470 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 316 insertions(+), 154 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 55c32e9c0..48eb6a20a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5850,169 +5850,330 @@ clamav() { -# 高性能模式优化函数 -optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null +# 获取内存大小(MB) +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} + +# 统一内核调优核心函数 +# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}切换到${mode_name}...${gl_bai}" + + # ── 根据场景设定参数 ── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # 高性能/直播/游戏:激进参数 + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # 网站服务器:高并发优先 + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # 均衡模式:适度优化 + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── 根据内存大小自适应调整 ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # 小内存缩小缓冲区 + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── 直播场景额外:UDP 缓冲区加大 ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# 直播推流 UDP 优化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── 游戏服场景额外:低延迟优先 ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# 游戏服低延迟优化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + + # ── 加载 BBR 模块 ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── 备份已有配置 ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── 写入配置文件(持久化) ── + echo -e "${gl_lv}写入优化配置...${gl_bai}" + cat > "$CONF" << SYSCTL +# kejilion 内核调优配置 +# 模式: $mode_name | 场景: $scene +# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') + +# ── TCP 拥塞控制 ── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCP 缓冲区 ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── 连接队列 ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP 连接优化 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── 端口与内存 ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 虚拟内存 ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ── CPU/内核调度 ── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing 不支持") + +# ── 安全防护 ── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── 文件描述符 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 连接跟踪 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack 未启用" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── 应用配置 ── + echo -e "${gl_lv}应用优化参数...${gl_bai}" + sysctl -p "$CONF" 2>&1 | grep -v "^$\|^net\.\|^vm\.\|^fs\.\|^kernel\." || true + + # ── 透明大页面 ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + # ── 文件描述符限制 ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBR 持久化 ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + + echo -e "${gl_lv}${mode_name} 优化完成!配置已持久化到 ${CONF}${gl_bai}" + echo -e "${gl_lv}内存: ${MEM_MB}MB | 拥塞算法: ${CC} | 队列: ${QDISC}${gl_bai}" } -# 均衡模式优化函数 -optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── 各模式入口函数(保持原有调用接口不变) ── +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} + +optimize_balanced() { + _kernel_optimize_core "均衡优化模式" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "网站搭建优化模式" "web" } -# 还原默认设置函数 +# ── 还原默认设置(完全清理) ── restore_defaults() { echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}还原网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}还原缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}还原CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # 删除优化配置文件 + rm -f "$CONF" + # 清理 sysctl.conf 里可能残留的 bbr 配置 + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # 重新加载系统默认配置 + sysctl --system 2>&1 | tail -1 -# 网站搭建优化函数 -optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null + # 还原透明大页面 + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + + # 清理文件描述符配置 + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + # 清理 BBR 持久化 + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" } @@ -6027,11 +6188,11 @@ Kernel_optimize() { echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo -e "--------------------" - echo -e "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo -e "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo -e "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo -e "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "4. 直播优化模式: 针对直播推流优化,UDP 缓冲区加大,减少延迟。" + echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" @@ -6061,15 +6222,13 @@ Kernel_optimize() { 4) cd ~ clear - local tiaoyou_moshi="直播优化模式" - optimize_high_performance + _kernel_optimize_core "直播优化模式" "stream" send_stats "直播推流优化" ;; 5) cd ~ clear - local tiaoyou_moshi="游戏服优化模式" - optimize_high_performance + _kernel_optimize_core "游戏服优化模式" "game" send_stats "游戏服优化" ;; 6) @@ -6099,6 +6258,9 @@ Kernel_optimize() { + + + update_locale() { local lang=$1 local locale_file=$2 From 4d0cdabd91c96050f43d5893f67bf83682abc1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:38:31 +0800 Subject: [PATCH 0865/1285] Refactor kernel optimization functions and parameters --- kejilion.sh | 470 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 316 insertions(+), 154 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 00824ee01..0fbaa3bb5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5850,169 +5850,330 @@ clamav() { -# 高性能模式优化函数 -optimize_high_performance() { - echo -e "${gl_lv}切换到${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null +# 获取内存大小(MB) +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} + +# 统一内核调优核心函数 +# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}切换到${mode_name}...${gl_bai}" + + # ── 根据场景设定参数 ── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # 高性能/直播/游戏:激进参数 + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # 网站服务器:高并发优先 + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # 均衡模式:适度优化 + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── 根据内存大小自适应调整 ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # 小内存缩小缓冲区 + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── 直播场景额外:UDP 缓冲区加大 ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# 直播推流 UDP 优化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── 游戏服场景额外:低延迟优先 ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# 游戏服低延迟优化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + + # ── 加载 BBR 模块 ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── 备份已有配置 ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── 写入配置文件(持久化) ── + echo -e "${gl_lv}写入优化配置...${gl_bai}" + cat > "$CONF" << SYSCTL +# kejilion 内核调优配置 +# 模式: $mode_name | 场景: $scene +# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') + +# ── TCP 拥塞控制 ── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCP 缓冲区 ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── 连接队列 ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP 连接优化 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── 端口与内存 ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 虚拟内存 ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ── CPU/内核调度 ── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing 不支持") + +# ── 安全防护 ── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── 文件描述符 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 连接跟踪 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack 未启用" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── 应用配置 ── + echo -e "${gl_lv}应用优化参数...${gl_bai}" + sysctl -p "$CONF" 2>&1 | grep -v "^$\|^net\.\|^vm\.\|^fs\.\|^kernel\." || true + + # ── 透明大页面 ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + # ── 文件描述符限制 ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBR 持久化 ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + + echo -e "${gl_lv}${mode_name} 优化完成!配置已持久化到 ${CONF}${gl_bai}" + echo -e "${gl_lv}内存: ${MEM_MB}MB | 拥塞算法: ${CC} | 队列: ${QDISC}${gl_bai}" } -# 均衡模式优化函数 -optimize_balanced() { - echo -e "${gl_lv}切换到均衡模式...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 还原透明大页面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── 各模式入口函数(保持原有调用接口不变) ── +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} + +optimize_balanced() { + _kernel_optimize_core "均衡优化模式" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "网站搭建优化模式" "web" } -# 还原默认设置函数 +# ── 还原默认设置(完全清理) ── restore_defaults() { echo -e "${gl_lv}还原到默认设置...${gl_bai}" - echo -e "${gl_lv}还原文件描述符...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}还原虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}还原网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}还原缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}还原CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}还原其他优化...${gl_bai}" - # 还原透明大页面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 还原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # 删除优化配置文件 + rm -f "$CONF" + # 清理 sysctl.conf 里可能残留的 bbr 配置 + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # 重新加载系统默认配置 + sysctl --system 2>&1 | tail -1 -# 网站搭建优化函数 -optimize_web_server() { - echo -e "${gl_lv}切换到网站搭建优化模式...${gl_bai}" - - echo -e "${gl_lv}优化文件描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}优化虚拟内存...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}优化网络设置...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}优化缓存管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}优化CPU设置...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他优化...${gl_bai}" - # 禁用透明大页面,减少延迟 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null + # 还原透明大页面 + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + + # 清理文件描述符配置 + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + # 清理 BBR 持久化 + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" } @@ -6027,11 +6188,11 @@ Kernel_optimize() { echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo -e "--------------------" - echo -e "1. 高性能优化模式: 最大化系统性能,优化文件描述符、虚拟内存、网络设置、缓存管理和CPU设置。" + echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo -e "3. 网站优化模式: 针对网站服务器进行优化,提高并发连接处理能力、响应速度和整体性能。" - echo -e "4. 直播优化模式: 针对直播推流的特殊需求进行优化,减少延迟,提高传输性能。" - echo -e "5. 游戏服优化模式: 针对游戏服务器进行优化,提高并发处理能力和响应速度。" + echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "4. 直播优化模式: 针对直播推流优化,UDP 缓冲区加大,减少延迟。" + echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" @@ -6061,15 +6222,13 @@ Kernel_optimize() { 4) cd ~ clear - local tiaoyou_moshi="直播优化模式" - optimize_high_performance + _kernel_optimize_core "直播优化模式" "stream" send_stats "直播推流优化" ;; 5) cd ~ clear - local tiaoyou_moshi="游戏服优化模式" - optimize_high_performance + _kernel_optimize_core "游戏服优化模式" "game" send_stats "游戏服优化" ;; 6) @@ -6099,6 +6258,9 @@ Kernel_optimize() { + + + update_locale() { local lang=$1 local locale_file=$2 From 9ca4d1d2df5bf7b037b8eb067797f9af57e7030d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:41:11 +0800 Subject: [PATCH 0866/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 55211733f..dabc1e5f0 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1458,6 +1458,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目日志选项进行优化,看日志同时显示运行状态信息。 ------------------------ 2026-03-01 v4.4.1 +系统工具内核调优功能全面重构,增加持久化机制。 系统工具内核调优功能增加自动内核调优选项,会根据网络智能调整系统参数。 系统工具一条龙调优原本均衡内核调优现在改为自动内核调优。 应用市场对ClawdBot/Moltbot机器人项目添加API时对模型的最大输出输入等参数进行优化,让大模型更稳定, From 7b11dbc8749fee5f92db09775582be8cf5d2f9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:52:51 +0800 Subject: [PATCH 0867/1285] Refactor Linux kernel tuning module for better adaptability Refactor Linux kernel tuning module to unify core functions and support scene-specific parameters. Replace previous optimization functions with a more adaptable approach. --- cn/kejilion.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 48eb6a20a..e1beb9b6f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5848,7 +5848,11 @@ clamav() { } - +# ============================================================================ +# Linux 内核调优模块(重构版) +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ # 获取内存大小(MB) _get_mem_mb() { @@ -6182,7 +6186,13 @@ Kernel_optimize() { while true; do clear send_stats "Linux内核调优管理" + local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" + if [ -n "$current_mode" ]; then + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + else + echo -e "当前模式: ${gl_hui}未优化${gl_bai}" + fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" @@ -6260,7 +6270,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From 516d500ee3b0bbf299794c59bfa7d67968856f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:53:36 +0800 Subject: [PATCH 0868/1285] Refactor Linux kernel tuning module Refactor Linux kernel tuning module with unified core functions and configurable parameters. --- kejilion.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0fbaa3bb5..73db33b8b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5848,7 +5848,11 @@ clamav() { } - +# ============================================================================ +# Linux 内核调优模块(重构版) +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ # 获取内存大小(MB) _get_mem_mb() { @@ -6182,7 +6186,13 @@ Kernel_optimize() { while true; do clear send_stats "Linux内核调优管理" + local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" + if [ -n "$current_mode" ]; then + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + else + echo -e "当前模式: ${gl_hui}未优化${gl_bai}" + fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" @@ -6260,7 +6270,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From 26faaa295d432816237b5245edc9b9804d69ec8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:14:32 +0800 Subject: [PATCH 0869/1285] Refactor Linux kernel tuning script and update output Removed comments related to Linux kernel tuning module and updated echo statements for current mode display. --- cn/kejilion.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e1beb9b6f..4e6574745 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5848,12 +5848,6 @@ clamav() { } -# ============================================================================ -# Linux 内核调优模块(重构版) -# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 -# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults -# ============================================================================ - # 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo @@ -6189,9 +6183,9 @@ Kernel_optimize() { local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_huang}${current_mode}${gl_bai}" else - echo -e "当前模式: ${gl_hui}未优化${gl_bai}" + echo -e "当前模式: ${gl_huang}未优化${gl_bai}" fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -6267,9 +6261,6 @@ Kernel_optimize() { - - - update_locale() { local lang=$1 local locale_file=$2 From e2050506d894af43ff1a9e0df42c09fd2b9002cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:15:00 +0800 Subject: [PATCH 0870/1285] Refactor kernel optimization module and update output Removed legacy comments and updated mode display colors. --- kejilion.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 73db33b8b..2f1219698 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5848,12 +5848,6 @@ clamav() { } -# ============================================================================ -# Linux 内核调优模块(重构版) -# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 -# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults -# ============================================================================ - # 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo @@ -6189,9 +6183,9 @@ Kernel_optimize() { local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_huang}${current_mode}${gl_bai}" else - echo -e "当前模式: ${gl_hui}未优化${gl_bai}" + echo -e "当前模式: ${gl_huang}未优化${gl_bai}" fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -6267,9 +6261,6 @@ Kernel_optimize() { - - - update_locale() { local lang=$1 local locale_file=$2 From 89e15be001245350d9e9e51a1a1c714b1048cf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:19:21 +0800 Subject: [PATCH 0871/1285] Update kejilion.sh --- kejilion.sh | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 2f1219698..5f4ed259b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5848,6 +5848,12 @@ clamav() { } +# ============================================================================ +# Linux 内核调优模块(重构版) +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ + # 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo @@ -6098,9 +6104,20 @@ $STREAM_EXTRA $GAME_EXTRA SYSCTL - # ── 应用配置 ── + # ── 应用配置(逐行,跳过不支持的参数) ── echo -e "${gl_lv}应用优化参数...${gl_bai}" - sysctl -p "$CONF" 2>&1 | grep -v "^$\|^net\.\|^vm\.\|^fs\.\|^kernel\." || true + local applied=0 skipped=0 + while IFS= read -r line; do + # 跳过注释和空行 + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}已应用 ${applied} 项参数${skipped:+,跳过 ${skipped} 项不支持的参数}${gl_bai}" # ── 透明大页面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then @@ -6157,7 +6174,7 @@ restore_defaults() { sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null # 重新加载系统默认配置 - sysctl --system 2>&1 | tail -1 + sysctl --system 2>/dev/null | tail -1 # 还原透明大页面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ @@ -6183,9 +6200,9 @@ Kernel_optimize() { local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_huang}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" else - echo -e "当前模式: ${gl_huang}未优化${gl_bai}" + echo -e "当前模式: ${gl_hui}未优化${gl_bai}" fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -6260,7 +6277,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From dd12c2ec39b4abc075c9da01c568ad4f249172d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:19:59 +0800 Subject: [PATCH 0872/1285] Refactor Linux kernel tuning module for better management Refactor Linux kernel tuning module with unified core functions, scenario-specific parameters, and persistent configuration. Update application configuration handling and improve output messages. --- cn/kejilion.sh | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4e6574745..d369e404d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5848,6 +5848,12 @@ clamav() { } +# ============================================================================ +# Linux 内核调优模块(重构版) +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ + # 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo @@ -6098,9 +6104,20 @@ $STREAM_EXTRA $GAME_EXTRA SYSCTL - # ── 应用配置 ── + # ── 应用配置(逐行,跳过不支持的参数) ── echo -e "${gl_lv}应用优化参数...${gl_bai}" - sysctl -p "$CONF" 2>&1 | grep -v "^$\|^net\.\|^vm\.\|^fs\.\|^kernel\." || true + local applied=0 skipped=0 + while IFS= read -r line; do + # 跳过注释和空行 + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}已应用 ${applied} 项参数${skipped:+,跳过 ${skipped} 项不支持的参数}${gl_bai}" # ── 透明大页面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then @@ -6157,7 +6174,7 @@ restore_defaults() { sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null # 重新加载系统默认配置 - sysctl --system 2>&1 | tail -1 + sysctl --system 2>/dev/null | tail -1 # 还原透明大页面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ @@ -6183,9 +6200,9 @@ Kernel_optimize() { local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_huang}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" else - echo -e "当前模式: ${gl_huang}未优化${gl_bai}" + echo -e "当前模式: ${gl_hui}未优化${gl_bai}" fi echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" @@ -6260,7 +6277,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From 91f19638bc7506ac5a19213207da3da6e90e42c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:44:35 +0800 Subject: [PATCH 0873/1285] Refactor Linux kernel optimization module --- cn/kejilion.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d369e404d..19394758b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5848,6 +5848,7 @@ clamav() { } + # ============================================================================ # Linux 内核调优模块(重构版) # 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 @@ -6198,6 +6199,7 @@ Kernel_optimize() { clear send_stats "Linux内核调优管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" @@ -6277,6 +6279,11 @@ Kernel_optimize() { + + + + + update_locale() { local lang=$1 local locale_file=$2 From 6c5cbb71d87265cf5edb5ee6d953afbc66533a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:45:04 +0800 Subject: [PATCH 0874/1285] Refactor kernel optimization and locale handling Refactor Linux kernel optimization module and update locale function. --- kejilion.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 5f4ed259b..8ae4f843c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5848,6 +5848,7 @@ clamav() { } + # ============================================================================ # Linux 内核调优模块(重构版) # 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 @@ -6198,6 +6199,7 @@ Kernel_optimize() { clear send_stats "Linux内核调优管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" @@ -6277,6 +6279,11 @@ Kernel_optimize() { + + + + + update_locale() { local lang=$1 local locale_file=$2 From 6c81bef18931470ff502d685a05952a04580f398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:51:58 +0800 Subject: [PATCH 0875/1285] Update comments and improve cleanup in kejilion.sh Refactor comments and clean up configuration removal process. --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8ae4f843c..3b53a944b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5848,7 +5848,6 @@ clamav() { } - # ============================================================================ # Linux 内核调优模块(重构版) # 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 @@ -6168,8 +6167,9 @@ restore_defaults() { local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 删除优化配置文件 + # 删除优化配置文件(含外链自动调优配置) rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf # 清理 sysctl.conf 里可能残留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null @@ -6283,7 +6283,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From 90ede70930ee31bf53148d3bd79f8e808ac7db29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:52:59 +0800 Subject: [PATCH 0876/1285] Refactor kernel optimization module and clean up code Refactor kernel optimization module and update comments. --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 19394758b..6a02168a4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5848,7 +5848,6 @@ clamav() { } - # ============================================================================ # Linux 内核调优模块(重构版) # 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 @@ -6168,8 +6167,9 @@ restore_defaults() { local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 删除优化配置文件 + # 删除优化配置文件(含外链自动调优配置) rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf # 清理 sysctl.conf 里可能残留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null @@ -6283,7 +6283,6 @@ Kernel_optimize() { - update_locale() { local lang=$1 local locale_file=$2 From 3de46a548d91964bd625e2f57184a041a5888434 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 1 Mar 2026 15:19:43 +0000 Subject: [PATCH 0877/1285] fix: make bbr_on write to sysctl.d to avoid conflict with kernel optimize module --- cn/kejilion.sh | 14 +++++++++++--- kejilion.sh | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6a02168a4..32a1c9289 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# 统一写入到 sysctl.d 以防与内核调优模块打架 +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# 清理可能导致冲突的旧版 sysctl.conf 残留 +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } diff --git a/kejilion.sh b/kejilion.sh index 3b53a944b..ee1599641 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# 统一写入到 sysctl.d 以防与内核调优模块打架 +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# 清理可能导致冲突的旧版 sysctl.conf 残留 +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } From 493f32de053bf3308a41114b3ea575e1a520f7d3 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 1 Mar 2026 16:35:03 +0000 Subject: [PATCH 0878/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-03-01=2016:35:03?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 687 ++++++++++++++++++++++++++++++----------------- jp/kejilion.sh | 713 +++++++++++++++++++++++++++++++------------------ kr/kejilion.sh | 663 +++++++++++++++++++++++++++++---------------- tw/kejilion.sh | 575 ++++++++++++++++++++++++++------------- 4 files changed, 1717 insertions(+), 921 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 387fca812..7ac7a21d2 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3522,7 +3522,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4312,7 +4312,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4409,7 +4409,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# Unified writing to sysctl.d to prevent conflicts with the kernel tuning module +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# Clean up remnants of old sysctl.conf that may cause conflicts +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } @@ -5848,171 +5856,348 @@ clamav() { } +# ============================================================================ +# Linux kernel tuning module (refactored version) +# Unified core functions + scene differentiation parameters + persistence to configuration files + hardware adaptation +# Replace the original optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ +# Get memory size (MB) +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} -# High performance mode optimization function -optimize_high_performance() { - echo -e "${gl_lv}switch to${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}Optimize network settings...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}Optimize cache management...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable transparent huge pages to reduce latency - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # Disable NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null +# Unified kernel tuning core functions +# Parameters: $1 = mode name, $2 = scene (high/balanced/web/stream/game) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}switch to${mode_name}...${gl_bai}" + + # ──Set parameters according to the scene── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # High Performance/Live Broadcasting/Gaming: Radical Parameters + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # Website server: high concurrency priority + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # Balanced Mode: Moderate Optimization + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── Adaptively adjust according to memory size ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # Small memory shrink buffer + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── Additional live broadcast scenarios: UDP buffer enlarged ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# Live streaming UDP optimization +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── Game server scene extra: low latency priority ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# Game server low latency optimization +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + # ── Load BBR module ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── Back up existing configuration ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── Write configuration file (persistence) ── + echo -e "${gl_lv}Write optimization configuration...${gl_bai}" + cat > "$CONF" << SYSCTL +# kejilion kernel tuning configuration +# Mode: $mode_name | Scene: $scene +# Memory: ${MEM_MB}MB | Generation time: $(date '+%Y-%m-%d %H:%M:%S') + +# ──TCP Congestion Control── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCP buffer ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── Connection queue ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP connection optimization ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── Ports and Memory ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── Virtual memory ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ──CPU/kernel scheduling── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing not supported") + +# ──Safety protection── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── File descriptor ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── Connection tracking ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack is not enabled" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── Apply configuration (line by line, skip unsupported parameters) ── + echo -e "${gl_lv}Apply optimization parameters...${gl_bai}" + local applied=0 skipped=0 + while IFS= read -r line; do + # Skip comments and blank lines + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}Applied${applied}Item parameter ${skipped:+, skip${skipped}Item unsupported parameter}${gl_bai}" + + # ── Transparent large page ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + + # ── File descriptor restrictions ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' + +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBR persistence ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # Clean up the bbr configuration in the old sysctl.conf (to avoid conflicts) + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + echo -e "${gl_lv}${mode_name}Optimization completed! The configuration has been persisted to${CONF}${gl_bai}" + echo -e "${gl_lv}Memory:${MEM_MB}MB | Congestion algorithm:${CC}| Queue:${QDISC}${gl_bai}" } -# Balanced mode optimization function -optimize_balanced() { - echo -e "${gl_lv}Switch to equalization mode...${gl_bai}" - - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}Optimize network settings...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}Optimize cache management...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Restore transparent huge pages - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # Restore NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── Entry functions of each mode (keep the original calling interface unchanged) ── + +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} +optimize_balanced() { + _kernel_optimize_core "Balanced optimization mode" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "Website construction optimization mode" "web" } -# Restore default settings function +# ── Restore default settings (complete clean) ── restore_defaults() { echo -e "${gl_lv}Revert to default settings...${gl_bai}" - echo -e "${gl_lv}Restore file descriptors...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}Restore virtual memory...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}Reset network settings...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}Restore cache management...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}Restore CPU settings...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}Revert other optimizations...${gl_bai}" - # Restore transparent huge pages - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # Restore NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # Delete the optimization configuration file (including external link automatic tuning configuration) + rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf + # Clean up possible remaining bbr configuration in sysctl.conf + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # Reload system default configuration + sysctl --system 2>/dev/null | tail -1 -# Website building optimization function -optimize_web_server() { - echo -e "${gl_lv}Switch to website construction optimization mode...${gl_bai}" - - echo -e "${gl_lv}Optimize file descriptors...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}Optimize virtual memory...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}Optimize network settings...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}Optimize cache management...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}Optimize CPU settings...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}Other optimizations...${gl_bai}" - # Disable transparent huge pages to reduce latency - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # Disable NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null + # Restore transparent huge pages + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + # Clean file descriptor configuration + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + + # Clean up BBR persistence + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}System has been restored to default settings${gl_bai}" } @@ -6021,18 +6206,26 @@ Kernel_optimize() { while true; do clear send_stats "Linux kernel tuning management" + local current_mode=$(grep "^# Mode:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# mode: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="Automatic tuning mode" echo "Linux system kernel parameter optimization" + if [ -n "$current_mode" ]; then + echo -e "Current mode:${gl_lv}${current_mode}${gl_bai}" + else + echo -e "Current mode:${gl_hui}Not optimized${gl_bai}" + fi echo "Video introduction: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "Provides a variety of system parameter tuning modes, and users can choose to switch according to their own usage scenarios." echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in production environment!" - echo "--------------------" - echo "1. High-performance optimization mode: Maximize system performance and optimize file descriptors, virtual memory, network settings, cache management and CPU settings." - echo "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." - echo "3. Website optimization mode: Optimize the website server to improve concurrent connection processing capabilities, response speed and overall performance." - echo "4. Live broadcast optimization mode: Optimize the special needs of live streaming to reduce delays and improve transmission performance." - echo "5. Game server optimization mode: Optimize the game server to improve concurrent processing capabilities and response speed." - echo "6. Restore default settings: Restore system settings to default configuration." + echo -e "--------------------" + echo -e "1. High-performance optimization mode: Maximize system performance, aggressive memory and network parameters." + echo -e "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." + echo -e "3. Website optimization mode: Optimized for website servers, ultra-high concurrent connection queue." + echo -e "4. Live broadcast optimization mode: For live streaming optimization, the UDP buffer is enlarged to reduce delays." + echo -e "5. Game server optimization mode: Optimized for game servers, giving priority to low latency." + echo -e "6. Restore default settings: Restore system settings to default configuration." + echo -e "7. Automatic tuning: Automatically tune kernel parameters based on test data.${gl_huang}★${gl_bai}" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" @@ -6055,28 +6248,35 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ clear - local tiaoyou_moshi="Live broadcast optimization mode" - optimize_high_performance + _kernel_optimize_core "Live broadcast optimization mode" "stream" send_stats "Live streaming optimization" ;; 5) cd ~ clear - local tiaoyou_moshi="Game server optimization mode" - optimize_high_performance + _kernel_optimize_core "Game server optimization mode" "game" send_stats "Game server optimization" ;; 6) cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "Restore default settings" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "Kernel automatic tuning" + ;; + *) break ;; @@ -6089,6 +6289,8 @@ Kernel_optimize() { + + update_locale() { local lang=$1 local locale_file=$2 @@ -6318,9 +6520,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6362,7 +6564,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6505,7 +6707,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6811,7 +7013,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -6881,7 +7083,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding + # If it is the first line or you have already started to enter the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7018,7 +7220,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -7235,7 +7437,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" tools=( @@ -7870,7 +8072,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8237,7 +8439,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9740,8 +9942,8 @@ moltbot_menu() { start_bot() { - echo "Starting OpenClaw..." - send_stats "Starting OpenClaw..." + echo "Start OpenClaw..." + send_stats "Start OpenClaw..." start_gateway break_end } @@ -9805,30 +10007,26 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # Infer context window based on model name - local context_window=131072 - local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + # context and max_tokens are fully loaded, so you are not afraid of the big problem + local context_window=1048576 + local max_tokens=128000 + + # Only price needs to be graded + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 - input_cost=0.30 - output_cost=0.60 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) + input_cost=2.00 + output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 - output_cost=0.40 + input_cost=1.25 + output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*|*lite*|*haiku*|*mini*|*nano*) + input_cost=0.10 + output_cost=0.40 ;; esac @@ -10035,7 +10233,7 @@ EOF echo "----------------------------------------" # Output a list of recommended practical plug-ins for users to copy - echo "Recommended practical plug-ins (you can directly copy the name input):" + echo "Recommended practical plug-ins (you can directly copy the name and enter it):" echo "feishu # Feishu/Lark integration (currently loaded ✓)" echo "telegram # Telegram bot integration (currently loaded ✓)" echo "memory-core # Core memory enhancement: file-based contextual search (currently loaded ✓)" @@ -10074,7 +10272,7 @@ EOF echo "💡 It is detected that the plug-in already exists in the system directory and is being activated directly..." openclaw plugins enable "$plugin_name" else - echo "📥 Downloading and installing plug-ins through official channels..." + echo "📥 Downloading and installing the plug-in through official channels..." # Use openclaw's own install command, which automatically handles spec checking of package.json openclaw plugins install "$plugin_name" @@ -10274,6 +10472,7 @@ EOF send_stats "Update OpenClaw..." install_node_and_tools npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id @@ -10498,7 +10697,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -10972,7 +11171,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -11026,7 +11225,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11124,7 +11323,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -11199,7 +11398,7 @@ while true; do } - local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12010,7 +12209,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12237,7 +12436,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12289,7 +12488,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12330,7 +12529,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12393,7 +12592,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12578,7 +12777,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -12607,7 +12806,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -12634,7 +12833,7 @@ while true; do } - local docker_describe="A password manager that puts you in control of your data" + local docker_describe="A password manager where you can control your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12721,7 +12920,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12942,7 +13141,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -12992,7 +13191,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13128,7 +13327,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13191,7 +13390,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -13355,7 +13554,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13493,7 +13692,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13547,7 +13746,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13780,7 +13979,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13822,7 +14021,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -13851,7 +14050,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -13920,7 +14119,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -14061,7 +14260,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -14131,7 +14330,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -14171,7 +14370,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Since Lucky uses the host network mode, the port here is only for record/explanation reference and is actually controlled by the application itself (default 16601) + # Since Lucky uses the host network mode, the port here is only for record/explanation reference, and is actually controlled by the application itself (default 16601) local docker_port=8112 docker_rum() { @@ -14277,7 +14476,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14339,7 +14538,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -14723,7 +14922,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. View the latest system log (journal)" + echo "1. Check the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -14735,7 +14934,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -15005,7 +15204,7 @@ linux_Settings() { while true; do clear - # send_stats "System Tools" + # send_stats "system tools" echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" @@ -15080,7 +15279,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -15266,8 +15465,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -15757,7 +15956,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -15978,9 +16177,9 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux system kernel parameter optimization switches to${gl_huang}Balanced optimization mode${gl_bai}" + echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" read -e -p "Are you sure you want one-click maintenance? (Y/N):" choice @@ -16026,7 +16225,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -16034,7 +16233,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 11/12. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux system kernel parameter optimization" echo -e "${gl_lv}One-stop system tuning has been completed${gl_bai}" @@ -16388,7 +16587,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16422,7 +16621,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16539,7 +16738,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16778,7 +16977,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 57cdf450d..08a434f2f 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -119,7 +119,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -1099,7 +1099,7 @@ iptables_panel() { echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" - echo "15. 指定した国の IP をブロック 16. 指定した国の IP のみを許可" + echo "15. 指定した国の IP をブロックする 16. 指定した国の IP のみを許可する" echo "17. 指定国における知的財産制限を解除する" echo "------------------------" echo "0. 前のメニューに戻る" @@ -1189,7 +1189,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2234,7 +2234,7 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2614,7 +2614,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2631,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3672,7 +3672,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4073,7 +4073,7 @@ add_forwarding_service() { read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -4335,7 +4335,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# 競合を引き起こす可能性のある古い sysctl.conf の残りをクリーンアップします。 +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } @@ -4750,7 +4758,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5720,7 +5728,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5833,7 +5841,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -5848,171 +5856,348 @@ clamav() { } +# ============================================================================ +# Linuxカーネルチューニングモジュール(リファクタリング版) +# 統合されたコア機能 + シーン区別パラメータ + 設定ファイルの永続性 + ハードウェア適応 +# 元の optimize_high_performance / optimize_balance / optimize_web_server /restore_defaults を置き換えます +# ============================================================================ +# メモリサイズ(MB)を取得 +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} -# ハイパフォーマンスモード最適化機能 -optimize_high_performance() { - echo -e "${gl_lv}に切り替える${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明な巨大ページを無効にして遅延を軽減する - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA バランシングを無効にする - sysctl -w kernel.numa_balancing=0 2>/dev/null +# 統合されたカーネルチューニングのコア機能 +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}に切り替える${mode_name}...${gl_bai}" + + # ──シーンに合わせてパラメータを設定── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # 高性能/ライブブロードキャスト/ゲーム: ラジカルパラメータ + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # Web サイトサーバー: 同時実行の優先度が高い + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # バランスモード: 中程度の最適化 + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── メモリサイズに応じて適応的に調整 ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # 小さいメモリ縮小バッファ + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── ライブブロードキャストシナリオの追加:UDPバッファの拡大 ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# ライブストリーミング UDP の最適化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── ゲームサーバーシーン番外編:低遅延優先 ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# ゲームサーバーの低遅延の最適化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + # ── BBRモジュールのロード ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── 既存の構成をバックアップします ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── 設定ファイルの書き込み(永続化) ── + echo -e "${gl_lv}最適化構成を書き込みます...${gl_bai}" + cat > "$CONF" << SYSCTL +# kejilion カーネルチューニング構成 +# モード: $モード名 |シーン: $scene +# メモリ: ${MEM_MB}MB |生成時間: $(日付 '+%Y-%m-%d %H:%M:%S') + +# ──TCP輻輳制御── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCPバッファ ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── 接続キュー ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP接続の最適化 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── ポートとメモリ ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 仮想メモリ ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ──CPU/カーネルのスケジューリング── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# uma_balancing はサポートされていません") + +# ──安全保護── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── ファイル記述子 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 接続追跡 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack が有効になっていません" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── 設定を適用します (1 行ずつ、サポートされていないパラメータをスキップします) ── + echo -e "${gl_lv}最適化パラメータを適用します...${gl_bai}" + local applied=0 skipped=0 + while IFS= read -r line; do + # コメントと空白行をスキップする + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}適用済み${applied}アイテムパラメータ ${skipped:+、スキップ${skipped}項目がサポートされていないパラメータ}${gl_bai}" + + # ── 透明大判ページ ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + + # ── ファイル記述子の制限事項 ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' + +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBRのこだわり ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # 古い sysctl.conf 内の bbr 設定をクリーンアップします (競合を避けるため)。 + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + echo -e "${gl_lv}${mode_name}最適化が完了しました!構成は永続化されています${CONF}${gl_bai}" + echo -e "${gl_lv}メモリ:${MEM_MB}MB |輻輳アルゴリズム:${CC}|列:${QDISC}${gl_bai}" } -# バランスモード最適化機能 -optimize_balanced() { - echo -e "${gl_lv}イコライゼーションモードに切り替えます...${gl_bai}" - - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明な巨大ページを復元する - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA バランスを復元する - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── 各モードのエントリ機能(元の呼び出しインターフェースはそのまま) ── + +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} +optimize_balanced() { + _kernel_optimize_core "バランスのとれた最適化モード" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "ウェブサイト構築最適化モード" "web" } -# デフォルト設定に戻す機能 +# ── 初期設定に戻す(完全クリーン) ── restore_defaults() { echo -e "${gl_lv}デフォルト設定に戻す...${gl_bai}" - echo -e "${gl_lv}ファイル記述子を復元します...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}仮想メモリを復元します...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}ネットワーク設定をリセットします...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}キャッシュ管理を復元します...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}CPU設定を復元します...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}他の最適化を元に戻します...${gl_bai}" - # 透明な巨大ページを復元する - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA バランスを復元する - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # 最適化設定ファイル(外部リンク自動チューニング設定含む)を削除します。 + rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf + # sysctl.conf に残っている可能性のある bbr 設定をクリーンアップする + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # システムのデフォルト設定をリロードする + sysctl --system 2>/dev/null | tail -1 -# Webサイト構築最適化機能 -optimize_web_server() { - echo -e "${gl_lv}ウェブサイト構築最適化モードに切り替えます...${gl_bai}" - - echo -e "${gl_lv}ファイル記述子を最適化します...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}仮想メモリを最適化します...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}ネットワーク設定を最適化します...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}キャッシュ管理を最適化します...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}CPU設定を最適化します...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}その他の最適化...${gl_bai}" - # 透明な巨大ページを無効にして遅延を軽減する - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA バランシングを無効にする - sysctl -w kernel.numa_balancing=0 2>/dev/null + # 透明な巨大ページを復元する + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + # クリーンなファイル記述子の構成 + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + + # BBR 永続性をクリーンアップする + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}システムがデフォルト設定に復元されました${gl_bai}" } @@ -6021,18 +6206,26 @@ Kernel_optimize() { while true; do clear send_stats "Linuxカーネルチューニング管理" + local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" + if [ -n "$current_mode" ]; then + echo -e "現在のモード:${gl_lv}${current_mode}${gl_bai}" + else + echo -e "現在のモード:${gl_hui}最適化されていない${gl_bai}" + fi echo "ビデオ紹介: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "さまざまなシステムパラメータチューニングモードを提供し、ユーザーは独自の使用シナリオに応じて切り替えることができます。" echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" - echo "--------------------" - echo "1. ハイパフォーマンス最適化モード: システムのパフォーマンスを最大化し、ファイル記述子、仮想メモリ、ネットワーク設定、キャッシュ管理、CPU 設定を最適化します。" - echo "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" - echo "3. Web サイト最適化モード: Web サイトサーバーを最適化して、同時接続処理能力、応答速度、全体的なパフォーマンスを向上させます。" - echo "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの特別なニーズを最適化し、遅延を削減し、送信パフォーマンスを向上させます。" - echo "5. ゲームサーバー最適化モード: ゲームサーバーを最適化して、同時処理能力と応答速度を向上させます。" - echo "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" + echo -e "--------------------" + echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" + echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" + echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" + echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -6055,28 +6248,35 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ clear - local tiaoyou_moshi="ライブブロードキャスト最適化モード" - optimize_high_performance + _kernel_optimize_core "ライブブロードキャスト最適化モード" "stream" send_stats "ライブストリーミングの最適化" ;; 5) cd ~ clear - local tiaoyou_moshi="ゲームサーバー最適化モード" - optimize_high_performance + _kernel_optimize_core "ゲームサーバー最適化モード" "game" send_stats "ゲームサーバーの最適化" ;; 6) cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "デフォルト設定を復元する" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "カーネル自動チューニング" + ;; + *) break ;; @@ -6089,6 +6289,8 @@ Kernel_optimize() { + + update_locale() { local lang=$1 local locale_file=$2 @@ -6145,7 +6347,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6318,9 +6520,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6362,7 +6564,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6450,7 +6652,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6653,7 +6855,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -6699,7 +6901,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -6811,7 +7013,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -6830,7 +7032,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -6859,7 +7061,7 @@ add_task() { read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポートを入力してください (デフォルトは 22):" port + read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port port=${port:-22} echo "認証方法を選択してください:" @@ -7018,7 +7220,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモート ホストにアクセスできますか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7117,7 +7319,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7235,7 +7437,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" tools=( @@ -7359,7 +7561,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7870,7 +8072,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7944,7 +8146,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8087,7 +8289,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8816,7 +9018,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこれほど面倒で問題が多いのか、非常に腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9740,8 +9942,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw を開始しています..." - send_stats "OpenClaw を開始しています..." + echo "OpenClaw を開始します..." + send_stats "OpenClaw を開始します..." start_gateway break_end } @@ -9805,30 +10007,26 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # モデル名に基づいてコンテキスト ウィンドウを推測する - local context_window=131072 - local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + # context と max_tokens は完全にロードされているため、大きな問題を恐れる必要はありません + local context_window=1048576 + local max_tokens=128000 + + # 評価する必要があるのは価格だけです + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 - input_cost=0.30 - output_cost=0.60 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) + input_cost=2.00 + output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 - output_cost=0.40 + input_cost=1.25 + output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*|*lite*|*haiku*|*mini*|*nano*) + input_cost=0.10 + output_cost=0.40 ;; esac @@ -9938,7 +10136,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -10035,7 +10233,7 @@ EOF echo "----------------------------------------" # ユーザーがコピーできる推奨実用プラグインのリストを出力します - echo "推奨される実用的なプラグイン (名前入力を直接コピーできます):" + echo "推奨される実用的なプラグイン (名前を直接コピーして入力できます):" echo "feishu # Feishu/Lark 統合 (現在ロード中 ✓)" echo "telegram # Telegram ボットの統合 (現在ロードされています ✓)" echo "Memory-core # コア メモリの強化: ファイルベースのコンテキスト検索 (現在ロードされています ✓)" @@ -10274,6 +10472,7 @@ EOF send_stats "OpenClaw を更新..." install_node_and_tools npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id @@ -10498,7 +10697,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -10788,7 +10987,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "ネザ監視$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -11199,7 +11398,7 @@ while true; do } - local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12365,7 +12564,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -12578,7 +12777,7 @@ while true; do } - local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" + local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -12634,7 +12833,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12882,7 +13081,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13191,7 +13390,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -13221,7 +13420,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -13822,7 +14021,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14156,7 +14355,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -14277,7 +14476,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリケーションのバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14339,7 +14538,7 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" @@ -14665,7 +14864,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -14675,7 +14874,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -14687,7 +14886,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -14723,7 +14922,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を表示する" + echo "1. 最新のシステムログ(ジャーナル)を確認する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -14735,10 +14934,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -14748,7 +14947,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -14763,7 +14962,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -14851,7 +15050,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -14866,7 +15065,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -14882,7 +15081,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -14893,7 +15092,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集します" + echo "4. ~/.bashrc を編集する" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -15005,7 +15204,7 @@ linux_Settings() { while true; do clear - # send_stats 「システムツール」 + # send_stats「システムツール」 echo -e "システムツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" @@ -15266,8 +15465,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -15489,7 +15688,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -15757,7 +15956,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -15980,7 +16179,7 @@ EOF echo -e "9. DNS アドレスを自動的に最適化する${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" echo -e "10. ネットワークを次のように設定します。${gl_huang}IPv4優先度${gl_bai}" echo -e "11. 基本ツールのインストール${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux システムのカーネル パラメータの最適化は、${gl_huang}バランスのとれた最適化モード${gl_bai}" + echo -e "12. Linuxシステムのカーネルパラメータの最適化${gl_huang}ネットワーク環境に応じて自動チューニング${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスを実行してもよろしいですか? (はい/いいえ):" choice @@ -16034,7 +16233,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}】11/12。基本的なツールをインストールする${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}】12/12。 Linuxシステムのカーネルパラメータの最適化" echo -e "${gl_lv}ワンストップでのシステムチューニングが完了${gl_bai}" @@ -16388,7 +16587,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16417,12 +16616,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16455,7 +16654,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -16539,7 +16738,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16654,7 +16853,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" + echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -16778,7 +16977,7 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -16813,7 +17012,7 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 64804ad6d..5772aef59 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3343,7 +3343,7 @@ ldnmp_web_on() { echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3429,7 +3429,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4335,7 +4335,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# 충돌을 일으킬 수 있는 이전 sysctl.conf의 남은 부분을 정리합니다. +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } @@ -4970,7 +4978,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원본 Authorized_keys 파일이 백업되었습니다." + echo "원래 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5756,7 +5764,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5848,171 +5856,348 @@ clamav() { } +# ============================================================================ +# Linux 커널 조정 모듈(리팩터링 버전) +# 통합 핵심 기능 + 장면 차별화 매개변수 + 구성 파일 지속성 + 하드웨어 적응 +# 원래의optim_high_performance/optim_balanced/optim_web_server/restore_defaults를 교체하십시오. +# ============================================================================ +# 메모리 크기(MB) 가져오기 +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} -# 고성능 모드 최적화 기능 -optimize_high_performance() { - echo -e "${gl_lv}로 전환하다${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}기타 최적화...${gl_bai}" - # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱 비활성화 - sysctl -w kernel.numa_balancing=0 2>/dev/null +# 통합 커널 튜닝 핵심 기능 +# 매개변수: $1 = 모드 이름, $2 = 장면(하이/밸런스/웹/스트림/게임) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" + + # ──장면에 따라 매개변수를 설정하세요── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # 고성능/생방송/게임: 급진적인 매개변수 + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # 웹사이트 서버: 높은 동시성 우선순위 + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # 균형 모드: 보통 최적화 + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── 메모리 크기에 따라 적응적으로 조정 ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # 작은 메모리 축소 버퍼 + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── 추가 라이브 방송 시나리오: UDP 버퍼 확대 ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# 라이브 스트리밍 UDP 최적화 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── 게임 서버 장면 추가: 낮은 대기 시간 우선 ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# 게임 서버 낮은 대기 시간 최적화 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + # ── BBR 모듈 로드 ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── 기존 구성 백업 ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── 구성 파일 쓰기(지속성) ── + echo -e "${gl_lv}최적화 구성 쓰기...${gl_bai}" + cat > "$CONF" << SYSCTL +# 케질리온 커널 튜닝 구성 +# 모드: $mode_name | 장면: $장면 +# 메모리: ${MEM_MB}MB | 생성 시간: $(날짜 '+%Y-%m-%d %H:%M:%S') + +# ──TCP 혼잡 제어── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCP 버퍼 ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── 연결 큐 ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP 연결 최적화 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── 포트와 메모리 ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 가상 메모리 ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ──CPU/커널 스케줄링── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing은 지원되지 않습니다") + +# ──안전 보호── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── 파일 설명자 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 연결 추적 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack이 활성화되어 있지 않습니다" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── 구성 적용(한 줄씩, 지원되지 않는 매개변수 건너뛰기) ── + echo -e "${gl_lv}최적화 매개변수 적용...${gl_bai}" + local applied=0 skipped=0 + while IFS= read -r line; do + # 주석과 빈 줄 건너뛰기 + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}적용된${applied}항목 매개변수 ${skipped:+, 건너뛰기${skipped}지원되지 않는 항목 매개변수}${gl_bai}" + + # ── 투명 대형 페이지 ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + + # ── 파일 설명자 제한 사항 ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' + +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBR 지속성 ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # 이전 sysctl.conf에서 bbr 구성을 정리합니다(충돌을 방지하기 위해). + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + echo -e "${gl_lv}${mode_name}최적화 완료! 구성은 다음과 같이 유지되었습니다.${CONF}${gl_bai}" + echo -e "${gl_lv}메모리:${MEM_MB}MB | 혼잡 알고리즘:${CC}| 대기줄:${QDISC}${gl_bai}" } -# 균형 모드 최적화 기능 -optimize_balanced() { - echo -e "${gl_lv}이퀄라이제이션 모드로 전환...${gl_bai}" - - echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}기타 최적화...${gl_bai}" - # 투명한 대용량 페이지 복원 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱 복원 - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── 각 모드의 진입 기능(원래 호출 인터페이스를 그대로 유지) ── + +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} +optimize_balanced() { + _kernel_optimize_core "균형 잡힌 최적화 모드" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "웹사이트 구축 최적화 모드" "web" } -# 기본 설정 복원 기능 +# ── 기본 설정 복원(완전 청소) ── restore_defaults() { echo -e "${gl_lv}기본 설정으로 되돌리기...${gl_bai}" - echo -e "${gl_lv}파일 설명자를 복원합니다...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}가상 메모리 복원...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}네트워크 설정 재설정...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}캐시 관리 복원...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}CPU 설정 복원...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}다른 최적화 되돌리기...${gl_bai}" - # 투명한 대용량 페이지 복원 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱 복원 - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # 최적화 구성 파일 삭제(외부 링크 자동 튜닝 구성 포함) + rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf + # sysctl.conf에서 가능한 나머지 bbr 구성을 정리합니다. + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # 시스템 기본 구성 다시 로드 + sysctl --system 2>/dev/null | tail -1 -# 웹사이트 구축 최적화 기능 -optimize_web_server() { - echo -e "${gl_lv}웹사이트 구축 최적화 모드로 전환...${gl_bai}" - - echo -e "${gl_lv}파일 설명자 최적화...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}가상 메모리 최적화...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}네트워크 설정 최적화...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}캐시 관리 최적화...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}CPU 설정 최적화...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}기타 최적화...${gl_bai}" - # 대기 시간을 줄이기 위해 투명한 대용량 페이지를 비활성화합니다. - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # NUMA 밸런싱 비활성화 - sysctl -w kernel.numa_balancing=0 2>/dev/null + # 투명한 대용량 페이지 복원 + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + # 파일 설명자 구성 정리 + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + + # BBR 지속성 정리 + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}시스템이 기본 설정으로 복원되었습니다.${gl_bai}" } @@ -6021,18 +6206,26 @@ Kernel_optimize() { while true; do clear send_stats "Linux 커널 튜닝 관리" + local current_mode=$(grep "^# 모드:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 모드: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="자동 튜닝 모드" echo "Linux 시스템 커널 매개변수 최적화" + if [ -n "$current_mode" ]; then + echo -e "현재 모드:${gl_lv}${current_mode}${gl_bai}" + else + echo -e "현재 모드:${gl_hui}최적화되지 않음${gl_bai}" + fi echo "영상 소개: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." echo -e "${gl_huang}힌트:${gl_bai}프로덕션 환경에서는 주의해서 사용해주세요!" - echo "--------------------" - echo "1. 고성능 최적화 모드: 시스템 성능을 최대화하고 파일 설명자, 가상 메모리, 네트워크 설정, 캐시 관리 및 CPU 설정을 최적화합니다." - echo "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." - echo "3. 웹사이트 최적화 모드: 웹사이트 서버를 최적화하여 동시 연결 처리 기능, 응답 속도 및 전반적인 성능을 향상시킵니다." - echo "4. 라이브 방송 최적화 모드: 라이브 스트리밍의 특별한 요구 사항을 최적화하여 지연을 줄이고 전송 성능을 향상시킵니다." - echo "5. 게임 서버 최적화 모드: 게임 서버를 최적화하여 동시 처리 기능과 응답 속도를 향상시킵니다." - echo "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." + echo -e "--------------------" + echo -e "1. 고성능 최적화 모드: 시스템 성능, 적극적인 메모리 및 네트워크 매개변수를 최대화합니다." + echo -e "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." + echo -e "3. 웹사이트 최적화 모드: 웹사이트 서버에 최적화되어 있으며 동시 연결 대기열이 매우 높습니다." + echo -e "4. 라이브 방송 최적화 모드: 라이브 스트리밍 최적화를 위해 UDP 버퍼가 확장되어 지연이 줄어듭니다." + echo -e "5. 게임 서버 최적화 모드: 게임 서버에 최적화되어 낮은 대기 시간을 우선시합니다." + echo -e "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." + echo -e "7. 자동 튜닝: 테스트 데이터를 기반으로 커널 매개변수를 자동으로 튜닝합니다.${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------" @@ -6055,28 +6248,35 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ clear - local tiaoyou_moshi="라이브 방송 최적화 모드" - optimize_high_performance + _kernel_optimize_core "라이브 방송 최적화 모드" "stream" send_stats "라이브 스트리밍 최적화" ;; 5) cd ~ clear - local tiaoyou_moshi="게임 서버 최적화 모드" - optimize_high_performance + _kernel_optimize_core "게임 서버 최적화 모드" "game" send_stats "게임 서버 최적화" ;; 6) cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "기본 설정 복원" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "커널 자동 튜닝" + ;; + *) break ;; @@ -6089,6 +6289,8 @@ Kernel_optimize() { + + update_locale() { local lang=$1 local locale_file=$2 @@ -6262,7 +6464,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -6505,7 +6707,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -6811,7 +7013,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -6881,7 +7083,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7018,7 +7220,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -7629,7 +7831,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -7870,7 +8072,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -7903,7 +8105,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8057,7 +8259,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8418,7 +8620,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9153,7 +9355,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -9740,8 +9942,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw를 시작하는 중..." - send_stats "OpenClaw를 시작하는 중..." + echo "OpenClaw를 시작하세요..." + send_stats "OpenClaw를 시작하세요..." start_gateway break_end } @@ -9805,30 +10007,26 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # 모델명을 기준으로 컨텍스트 창 추론 - local context_window=131072 - local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + # context 및 max_tokens가 완전히 로드되었으므로 큰 문제를 두려워하지 않습니다. + local context_window=1048576 + local max_tokens=128000 + + # 가격만 등급을 매겨야 합니다. + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 - input_cost=0.30 - output_cost=0.60 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) + input_cost=2.00 + output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 - output_cost=0.40 + input_cost=1.25 + output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*|*lite*|*haiku*|*mini*|*nano*) + input_cost=0.10 + output_cost=0.40 ;; esac @@ -10035,7 +10233,7 @@ EOF echo "----------------------------------------" # 사용자가 복사할 수 있는 권장 실무 플러그인 목록 출력 - echo "추천 실용 플러그인(이름 입력을 직접 복사할 수 있음):" + echo "추천 실용 플러그인(이름을 직접 복사하여 입력 가능):" echo "feishu # Feishu/Lark 통합 (현재 로드됨 ✓)" echo "텔레그램 # 텔레그램 봇 통합 (현재 로드됨 ✓)" echo "memory-core # 핵심 메모리 강화: 파일 기반 상황별 검색(현재 로드됨 ✓)" @@ -10164,7 +10362,7 @@ EOF openclaw plugins enable "$plugin_id" else echo "❌ 치명적인 오류: 플러그인을 얻을 수 없습니다. ID가 맞는지, 네트워크 사용이 가능한지 확인해주세요." - # 키: 구성 하드 코딩을 방지하려면 아래 start_gateway를 사용하는 대신 여기로 직접 돌아가거나 계속하세요. + # 키: 구성이 하드 코딩되는 것을 방지하려면 아래 start_gateway를 사용하는 대신 여기로 직접 돌아가거나 계속하세요. break_end continue fi @@ -10274,6 +10472,7 @@ EOF send_stats "오픈클로 업데이트..." install_node_and_tools npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id @@ -10446,7 +10645,7 @@ EOF openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 수리" + 12) send_stats "상태 감지 및 복구" openclaw doctor --fix break_end ;; @@ -10498,7 +10697,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -10558,7 +10757,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -10788,7 +10987,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -11199,7 +11398,7 @@ while true; do } - local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12301,7 +12500,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12578,7 +12777,7 @@ while true; do } - local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -12634,7 +12833,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12882,7 +13081,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13191,7 +13390,7 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -14277,7 +14476,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14339,7 +14538,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -14723,7 +14922,7 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 보기" + echo "1. 최신 시스템 로그(일지)를 확인하세요." echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" @@ -14735,7 +14934,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -15009,10 +15208,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -15266,8 +15465,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -15757,7 +15956,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -15980,7 +16179,7 @@ EOF echo -e "9. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" echo -e "10. 네트워크를 다음으로 설정합니다.${gl_huang}IPv4 우선순위${gl_bai}" echo -e "11. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux 시스템 커널 매개변수 최적화가 다음으로 전환됩니다.${gl_huang}균형 잡힌 최적화 모드${gl_bai}" + echo -e "12. Linux 시스템 커널 매개변수 최적화${gl_huang}네트워크 환경에 따라 자동으로 튜닝${gl_bai}" echo "------------------------------------------------" read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice @@ -16034,7 +16233,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 11/12. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux 시스템 커널 매개변수 최적화" echo -e "${gl_lv}원스톱 시스템 튜닝이 완료되었습니다${gl_bai}" @@ -16380,7 +16579,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 순회하고 명령을 실행합니다. + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -16388,7 +16587,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16422,7 +16621,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16463,7 +16662,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -16539,7 +16738,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16778,7 +16977,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 3d9a1b56c..bcc567c5b 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.0" +sh_v="4.4.1" gl_hui='\e[37m' @@ -1221,7 +1221,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -4699,9 +4699,17 @@ linux_clean() { bbr_on() { -sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf -echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf -sysctl -p +# 統一寫入到 sysctl.d 以防與核心調優模組打架 +local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" +mkdir -p /etc/sysctl.d +echo "net.core.default_qdisc=fq" > "$CONF" +echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" + +# 清理可能導致衝突的舊版 sysctl.conf 殘留 +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null +sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null + +sysctl -p "$CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 } @@ -5848,171 +5856,348 @@ clamav() { } +# ============================================================================ +# Linux 内核调优模块(重构版) +# 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 +# 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# ============================================================================ +# 取得記憶體大小(MB) +_get_mem_mb() { + awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo +} -# 高效能模式最佳化函數 -optimize_high_performance() { - echo -e "${gl_lv}切換到${tiaoyou_moshi}...${gl_bai}" - - echo -e "${gl_lv}優化檔案描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=15 2>/dev/null - sysctl -w vm.dirty_background_ratio=5 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}優化網路設定...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=250000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}優化快取管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}優化CPU設定...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他優化...${gl_bai}" - # 禁用透明大頁面,減少延遲 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null +# 統一內核調優核心函數 +# 參數: $1 = 模式名稱, $2 = 場景 (high/balanced/web/stream/game) +_kernel_optimize_core() { + local mode_name="$1" + local scene="${2:-high}" + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" + local MEM_MB=$(_get_mem_mb) + + echo -e "${gl_lv}切換到${mode_name}...${gl_bai}" + + # ── 根據場景設定參數 ── + local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE + local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM + local SOMAXCONN BACKLOG SYN_BACKLOG + local PORT_RANGE SCHED_AUTOGROUP THP NUMA FIN_TIMEOUT + local KEEPALIVE_TIME KEEPALIVE_INTVL KEEPALIVE_PROBES + + case "$scene" in + high|stream|game) + # 高性能/直播/游戏:激进参数 + SWAPPINESS=10 + DIRTY_RATIO=15 + DIRTY_BG_RATIO=5 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=67108864 + WMEM_MAX=67108864 + TCP_RMEM="4096 262144 67108864" + TCP_WMEM="4096 262144 67108864" + SOMAXCONN=8192 + BACKLOG=250000 + SYN_BACKLOG=8192 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=10 + KEEPALIVE_TIME=300 + KEEPALIVE_INTVL=30 + KEEPALIVE_PROBES=5 + ;; + web) + # 網站伺服器:高並發優先 + SWAPPINESS=10 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=1 + VFS_PRESSURE=50 + RMEM_MAX=33554432 + WMEM_MAX=33554432 + TCP_RMEM="4096 131072 33554432" + TCP_WMEM="4096 131072 33554432" + SOMAXCONN=16384 + BACKLOG=10000 + SYN_BACKLOG=16384 + PORT_RANGE="1024 65535" + SCHED_AUTOGROUP=0 + THP="never" + NUMA=0 + FIN_TIMEOUT=15 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + balanced) + # 均衡模式:適度優化 + SWAPPINESS=30 + DIRTY_RATIO=20 + DIRTY_BG_RATIO=10 + OVERCOMMIT=0 + VFS_PRESSURE=75 + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + SOMAXCONN=4096 + BACKLOG=5000 + SYN_BACKLOG=4096 + PORT_RANGE="1024 49151" + SCHED_AUTOGROUP=1 + THP="always" + NUMA=1 + FIN_TIMEOUT=30 + KEEPALIVE_TIME=600 + KEEPALIVE_INTVL=60 + KEEPALIVE_PROBES=5 + ;; + esac + + # ── 根據記憶體大小自適應調整 ── + if [ "$MEM_MB" -ge 16384 ]; then + MIN_FREE_KB=131072 + [ "$scene" != "balanced" ] && SWAPPINESS=5 + elif [ "$MEM_MB" -ge 4096 ]; then + MIN_FREE_KB=65536 + elif [ "$MEM_MB" -ge 1024 ]; then + MIN_FREE_KB=32768 + # 小記憶體縮小緩衝區 + if [ "$scene" != "balanced" ]; then + RMEM_MAX=16777216 + WMEM_MAX=16777216 + TCP_RMEM="4096 87380 16777216" + TCP_WMEM="4096 65536 16777216" + fi + else + MIN_FREE_KB=16384 + SWAPPINESS=30 + OVERCOMMIT=0 + RMEM_MAX=4194304 + WMEM_MAX=4194304 + TCP_RMEM="4096 32768 4194304" + TCP_WMEM="4096 32768 4194304" + SOMAXCONN=1024 + BACKLOG=1000 + fi + + # ── 直播場景額外:UDP 緩衝區加大 ── + local STREAM_EXTRA="" + if [ "$scene" = "stream" ]; then + STREAM_EXTRA=" +# 直播推流 UDP 優化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384" + fi + + # ── 遊戲服場景額外:低延遲優先 ── + local GAME_EXTRA="" + if [ "$scene" = "game" ]; then + GAME_EXTRA=" +# 遊戲服低延遲優化 +net.ipv4.udp_rmem_min = 16384 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.tcp_notsent_lowat = 16384 +net.ipv4.tcp_slow_start_after_idle = 0" + fi + # ── 載入 BBR 模組 ── + local CC="bbr" + local QDISC="fq" + local KVER + KVER=$(uname -r | grep -oP '^\d+\.\d+') + if printf '%s\n%s' "4.9" "$KVER" | sort -V -C; then + if ! lsmod 2>/dev/null | grep -q tcp_bbr; then + modprobe tcp_bbr 2>/dev/null + fi + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + CC="cubic" + QDISC="fq_codel" + fi + else + CC="cubic" + QDISC="fq_codel" + fi + + # ── 備份已有設定 ── + [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" + + # ── 寫入設定檔(持久化) ── + echo -e "${gl_lv}寫入優化配置...${gl_bai}" + cat > "$CONF" << SYSCTL +# kejilion 核心調優配置 +# 模式: $mode_name | 場景: $scene +# 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') + +# ── TCP 擁塞控制 ── +net.core.default_qdisc = $QDISC +net.ipv4.tcp_congestion_control = $CC + +# ── TCP 緩衝區 ── +net.core.rmem_max = $RMEM_MAX +net.core.wmem_max = $WMEM_MAX +net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') +net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') +net.ipv4.tcp_rmem = $TCP_RMEM +net.ipv4.tcp_wmem = $TCP_WMEM + +# ── 連接隊列 ── +net.core.somaxconn = $SOMAXCONN +net.core.netdev_max_backlog = $BACKLOG +net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG + +# ── TCP 連線最佳化 ── +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT +net.ipv4.tcp_keepalive_time = $KEEPALIVE_TIME +net.ipv4.tcp_keepalive_intvl = $KEEPALIVE_INTVL +net.ipv4.tcp_keepalive_probes = $KEEPALIVE_PROBES +net.ipv4.tcp_max_tw_buckets = 65536 +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_window_scaling = 1 + +# ── 埠與記憶體 ── +net.ipv4.ip_local_port_range = $PORT_RANGE +net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) +net.ipv4.tcp_max_orphans = 32768 + +# ── 虚拟内存 ── +vm.swappiness = $SWAPPINESS +vm.dirty_ratio = $DIRTY_RATIO +vm.dirty_background_ratio = $DIRTY_BG_RATIO +vm.overcommit_memory = $OVERCOMMIT +vm.min_free_kbytes = $MIN_FREE_KB +vm.vfs_cache_pressure = $VFS_PRESSURE + +# ── CPU/核心調度 ── +kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing 不支持") + +# ── 安全防護 ── +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# ── 文件描述符 ── +fs.file-max = 1048576 +fs.nr_open = 1048576 + +# ── 連結追蹤 ── +$(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then +echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" +echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" +echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" +echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" +echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" +else +echo "# conntrack 未啟用" +fi) +$STREAM_EXTRA +$GAME_EXTRA +SYSCTL + + # ── 應用配置(逐行,跳過不支援的參數) ── + echo -e "${gl_lv}应用优化参数...${gl_bai}" + local applied=0 skipped=0 + while IFS= read -r line; do + # 跳過註解和空行 + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// /}" ]] && continue + if sysctl -w "$line" >/dev/null 2>&1; then + applied=$((applied + 1)) + else + skipped=$((skipped + 1)) + fi + done < "$CONF" + echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" + + # ── 透明大页面 ── + if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then + echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + fi + + # ── 文件描述符限制 ── + if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + cat >> /etc/security/limits.conf << 'LIMITS' + +# kejilion-optimize +* soft nofile 1048576 +* hard nofile 1048576 +root soft nofile 1048576 +root hard nofile 1048576 +LIMITS + fi + + # ── BBR 持久化 ── + if [ "$CC" = "bbr" ]; then + echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null + # 清理舊的 sysctl.conf 裡的 bbr 設定(避免衝突) + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + fi + echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC} | 队列: ${QDISC}${gl_bai}" } -# 均衡模式最佳化函數 -optimize_balanced() { - echo -e "${gl_lv}切換到均衡模式...${gl_bai}" - - echo -e "${gl_lv}優化檔案描述符...${gl_bai}" - ulimit -n 32768 - - echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" - sysctl -w vm.swappiness=30 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=32768 2>/dev/null - - echo -e "${gl_lv}優化網路設定...${gl_bai}" - sysctl -w net.core.rmem_max=8388608 2>/dev/null - sysctl -w net.core.wmem_max=8388608 2>/dev/null - sysctl -w net.core.netdev_max_backlog=125000 2>/dev/null - sysctl -w net.core.somaxconn=2048 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 32768 8388608' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=4096 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 49151' 2>/dev/null - - echo -e "${gl_lv}優化快取管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=75 2>/dev/null - - echo -e "${gl_lv}優化CPU設定...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}其他優化...${gl_bai}" - # 還原透明大頁面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 還原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null +# ── 各模式入口函數(保持原有呼叫介面不變) ── + +optimize_high_performance() { + _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" +} +optimize_balanced() { + _kernel_optimize_core "均衡最佳化模式" "balanced" +} +optimize_web_server() { + _kernel_optimize_core "網站建置優化模式" "web" } -# 還原預設設定函數 +# ── 還原預設設定(完全清理) ── restore_defaults() { echo -e "${gl_lv}還原到預設值...${gl_bai}" - echo -e "${gl_lv}還原檔案描述符...${gl_bai}" - ulimit -n 1024 - - echo -e "${gl_lv}還原虛擬記憶體...${gl_bai}" - sysctl -w vm.swappiness=60 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=0 2>/dev/null - sysctl -w vm.min_free_kbytes=16384 2>/dev/null - - echo -e "${gl_lv}還原網路設定...${gl_bai}" - sysctl -w net.core.rmem_max=212992 2>/dev/null - sysctl -w net.core.wmem_max=212992 2>/dev/null - sysctl -w net.core.netdev_max_backlog=1000 2>/dev/null - sysctl -w net.core.somaxconn=128 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=0 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='32768 60999' 2>/dev/null - - echo -e "${gl_lv}還原快取管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=100 2>/dev/null - - echo -e "${gl_lv}還原CPU設定...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=1 2>/dev/null - - echo -e "${gl_lv}還原其他優化...${gl_bai}" - # 還原透明大頁面 - echo always > /sys/kernel/mm/transparent_hugepage/enabled - # 還原 NUMA balancing - sysctl -w kernel.numa_balancing=1 2>/dev/null + local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" -} + # 刪除最佳化設定檔(含外鏈自動調優配置) + rm -f "$CONF" + rm -f /etc/sysctl.d/99-network-optimize.conf + # 清理 sysctl.conf 里可能残留的 bbr 配置 + sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null + # 重新加载系统默认配置 + sysctl --system 2>/dev/null | tail -1 -# 網站建置優化函數 -optimize_web_server() { - echo -e "${gl_lv}切換到網站建置優化模式...${gl_bai}" - - echo -e "${gl_lv}優化檔案描述符...${gl_bai}" - ulimit -n 65535 - - echo -e "${gl_lv}優化虛擬記憶體...${gl_bai}" - sysctl -w vm.swappiness=10 2>/dev/null - sysctl -w vm.dirty_ratio=20 2>/dev/null - sysctl -w vm.dirty_background_ratio=10 2>/dev/null - sysctl -w vm.overcommit_memory=1 2>/dev/null - sysctl -w vm.min_free_kbytes=65536 2>/dev/null - - echo -e "${gl_lv}優化網路設定...${gl_bai}" - sysctl -w net.core.rmem_max=16777216 2>/dev/null - sysctl -w net.core.wmem_max=16777216 2>/dev/null - sysctl -w net.core.netdev_max_backlog=5000 2>/dev/null - sysctl -w net.core.somaxconn=4096 2>/dev/null - sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216' 2>/dev/null - sysctl -w net.ipv4.tcp_congestion_control=bbr 2>/dev/null - sysctl -w net.ipv4.tcp_max_syn_backlog=8192 2>/dev/null - sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null - sysctl -w net.ipv4.ip_local_port_range='1024 65535' 2>/dev/null - - echo -e "${gl_lv}優化快取管理...${gl_bai}" - sysctl -w vm.vfs_cache_pressure=50 2>/dev/null - - echo -e "${gl_lv}優化CPU設定...${gl_bai}" - sysctl -w kernel.sched_autogroup_enabled=0 2>/dev/null - - echo -e "${gl_lv}其他優化...${gl_bai}" - # 禁用透明大頁面,減少延遲 - echo never > /sys/kernel/mm/transparent_hugepage/enabled - # 禁用 NUMA balancing - sysctl -w kernel.numa_balancing=0 2>/dev/null + # 還原透明大頁面 + [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ + echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null + # 清理文件描述符配置 + if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then + sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf + fi + + # 清理 BBR 持久化 + rm -f /etc/modules-load.d/bbr.conf 2>/dev/null + echo -e "${gl_lv}系統已還原到預設設定${gl_bai}" } @@ -6021,18 +6206,26 @@ Kernel_optimize() { while true; do clear send_stats "Linux核心調優管理" + local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" echo "Linux系統核心參數優化" + if [ -n "$current_mode" ]; then + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + else + echo -e "當前模式:${gl_hui}未最佳化${gl_bai}" + fi echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" - echo "--------------------" - echo "1. 高效能最佳化模式: 最大化系統效能,最佳化檔案描述符、虛擬記憶體、網路設定、快取管理和CPU設定。" - echo "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" - echo "3. 網站最佳化模式: 針對網站伺服器進行最佳化,提升並發連線處理能力、回應速度及整體效能。" - echo "4. 直播最佳化模式: 針對直播推流的特殊需求進行最佳化,減少延遲,提升傳輸效能。" - echo "5. 遊戲服最佳化模式: 針對遊戲伺服器進行最佳化,提升並發處理能力與回應速度。" - echo "6. 還原預設設定: 將系統設定還原為預設配置。" + echo -e "--------------------" + echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" + echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" + echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" + echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" + echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" + echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -6060,23 +6253,30 @@ Kernel_optimize() { 4) cd ~ clear - local tiaoyou_moshi="直播優化模式" - optimize_high_performance + _kernel_optimize_core "直播優化模式" "stream" send_stats "直播推流優化" ;; 5) cd ~ clear - local tiaoyou_moshi="遊戲服優化模式" - optimize_high_performance + _kernel_optimize_core "遊戲服優化模式" "game" send_stats "遊戲服優化" ;; 6) cd ~ clear restore_defaults + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults send_stats "還原預設設定" ;; + + 7) + cd ~ + clear + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + send_stats "核心自動調優" + ;; + *) break ;; @@ -6089,6 +6289,8 @@ Kernel_optimize() { + + update_locale() { local lang=$1 local locale_file=$2 @@ -6695,7 +6897,7 @@ mount_partition() { return 1 fi - echo "分割區已成功掛載到$MOUNT_POINT" + echo "分區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -9805,30 +10007,26 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # 根據模型名稱推斷上下文窗口 - local context_window=131072 - local max_tokens=8192 - local input_cost=0.14 - local output_cost=0.28 + # context 和 max_tokens 全拉滿,不怕大 + local context_window=1048576 + local max_tokens=128000 + + # 只有價格需要分級 + local input_cost=0.15 + local output_cost=0.60 case "$model_id" in - *preview*|*thinking*|*opus*|*pro*) - context_window=1048576 # 1M - max_tokens=16384 - input_cost=0.30 - output_cost=0.60 + *opus*|*pro*|*preview*|*thinking*|*sonnet*) + input_cost=2.00 + output_cost=12.00 ;; *gpt-5*|*codex*) - context_window=131072 # 128K - max_tokens=8192 - input_cost=0.20 - output_cost=0.40 + input_cost=1.25 + output_cost=10.00 ;; - *flash*|*lite*|*haiku*) - context_window=131072 - max_tokens=8192 - input_cost=0.07 - output_cost=0.14 + *flash*|*lite*|*haiku*|*mini*|*nano*) + input_cost=0.10 + output_cost=0.40 ;; esac @@ -10030,7 +10228,7 @@ EOF echo "========================================" echo "外掛程式管理 (安裝)" echo "========================================" - echo "當前已安裝插件:" + echo "目前已安裝插件:" openclaw plugins list echo "----------------------------------------" @@ -10274,6 +10472,7 @@ EOF send_stats "更新 OpenClaw..." install_node_and_tools npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id @@ -10343,7 +10542,7 @@ EOF domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15192,7 +15391,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH連接埠修改" + send_stats "退出SSH埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -15980,7 +16179,7 @@ EOF echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux系統核心參數優化切換到${gl_huang}均衡最佳化模式${gl_bai}" + echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" read -e -p "確定一鍵保養嗎? (Y/N):" choice @@ -16034,7 +16233,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - optimize_balanced + curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系統核心參數最佳化" echo -e "${gl_lv}一條龍系統調優已完成${gl_bai}" @@ -16247,7 +16446,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" From 49f14fbe883f51d950d7c1d36176cc6243f70e76 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 2 Mar 2026 03:24:11 +0000 Subject: [PATCH 0879/1285] feat: upgrade openclaw pairing to support both Telegram and Feishu --- cn/kejilion.sh | 52 ++++++++++++++++++++++++++++++++++---------------- kejilion.sh | 52 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 32a1c9289..43c6dfc8e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9883,7 +9883,7 @@ moltbot_menu() { echo "4. 状态日志查看" echo "5. 换模型" echo "6. 加新模型API" - echo "7. TG输入连接码" + echo "7. 机器人连接对接" echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" @@ -10448,22 +10448,42 @@ EOF change_tg_bot_code() { send_stats "机器人对接" - read -e -p "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " code - - # 检查是否输入 0 以退出 - if [ "$code" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi - - # 验证输入是否为空 - if [ -z "$code" ]; then - echo "错误:连接码不能为空。请重试。" - return 1 - fi + while true; do + clear + echo "========================================" + echo " 机器人连接对接 " + echo "========================================" + echo "1. Telegram 机器人对接" + echo "2. 飞书 (Lark) 机器人对接" + echo "----------------------------------------" + echo "0. 返回上一级选单" + echo "----------------------------------------" + read -e -p "请输入你的选择: " bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done } diff --git a/kejilion.sh b/kejilion.sh index ee1599641..fd2ef0b47 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9883,7 +9883,7 @@ moltbot_menu() { echo "4. 状态日志查看" echo "5. 换模型" echo "6. 加新模型API" - echo "7. TG输入连接码" + echo "7. 机器人连接对接" echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" echo "10. 编辑主配置文件" @@ -10448,22 +10448,42 @@ EOF change_tg_bot_code() { send_stats "机器人对接" - read -e -p "请输入TG机器人收到的连接码 (例如 Pairing code: NYA99R2F)(输入 0 退出): " code - - # 检查是否输入 0 以退出 - if [ "$code" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi - - # 验证输入是否为空 - if [ -z "$code" ]; then - echo "错误:连接码不能为空。请重试。" - return 1 - fi + while true; do + clear + echo "========================================" + echo " 机器人连接对接 " + echo "========================================" + echo "1. Telegram 机器人对接" + echo "2. 飞书 (Lark) 机器人对接" + echo "----------------------------------------" + echo "0. 返回上一级选单" + echo "----------------------------------------" + read -e -p "请输入你的选择: " bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done } From bb5f2a180193c6bcc15af524d49cc154b3b29647 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 2 Mar 2026 03:25:21 +0000 Subject: [PATCH 0880/1285] feat: add WhatsApp pairing option to openclaw menu --- cn/kejilion.sh | 8 ++++++++ kejilion.sh | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 43c6dfc8e..51802b1dd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10455,6 +10455,7 @@ EOF echo "========================================" echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" + echo "3. WhatsApp 机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -10475,6 +10476,13 @@ EOF openclaw pairing approve feishu "$code" break_end ;; + 3) + read -e -p "请输入WhatsApp收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; 0) return 0 ;; diff --git a/kejilion.sh b/kejilion.sh index fd2ef0b47..c534db3f4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10455,6 +10455,7 @@ EOF echo "========================================" echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" + echo "3. WhatsApp 机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -10475,6 +10476,13 @@ EOF openclaw pairing approve feishu "$code" break_end ;; + 3) + read -e -p "请输入WhatsApp收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; 0) return 0 ;; From 0e7a9d6fc4e48c9dfd810ad17dfe8416868f1a3b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 2 Mar 2026 03:28:59 +0000 Subject: [PATCH 0881/1285] docs: update changelog for OpenClaw feishu/whatsapp pairing --- kejilion_sh_log.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index dabc1e5f0..6b88730d9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1461,6 +1461,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具内核调优功能全面重构,增加持久化机制。 系统工具内核调优功能增加自动内核调优选项,会根据网络智能调整系统参数。 系统工具一条龙调优原本均衡内核调优现在改为自动内核调优。 -应用市场对ClawdBot/Moltbot机器人项目添加API时对模型的最大输出输入等参数进行优化,让大模型更稳定, +应用市场对ClawdBot/Moltbot机器人项目添加API时对模型的最大输出输入等参数进行优化,让大模型更稳定。 +应用市场对ClawdBot/Moltbot机器人项目新增飞书和WhatsApp机器人扫码对接功能。 ------------------------ From a4c5331a4db76911a5115b5bb2808c48abcfa47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Mar 2026 16:05:42 +0800 Subject: [PATCH 0882/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 51802b1dd..f3d058be8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="CN" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" From 07eb9265199696e16eb6e7452138f6d14755126f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 2 Mar 2026 16:06:34 +0800 Subject: [PATCH 0883/1285] Update permission_granted variable value Change permission_granted from true to false. --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index c534db3f4..89a8faba4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" From ceb8b05b104b2a7bd0df433779e3d054a2f27c41 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 3 Mar 2026 14:54:45 +0800 Subject: [PATCH 0884/1285] feat: auto-inject domain into OpenClaw allowedOrigins in openclaw_domain_webui --- kejilion.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 89a8faba4..8f58da9da 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10598,6 +10598,19 @@ EOF echo "先访问URL触发设备ID,然后回车下一步进行配对。" read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" + # 自动添加域名到 allowedOrigins + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}已将域名 ${yuming} 加入 allowedOrigins 配置${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "请输入 Request_Key: " Request_Key From e1347a5e7ae289e2c19a3981469a580564db50d7 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 3 Mar 2026 15:00:42 +0800 Subject: [PATCH 0885/1285] feat: sync OpenClaw domain inject logic to cn/kejilion.sh --- cn/kejilion.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3d058be8..3adc5efc2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10598,6 +10598,18 @@ EOF echo "先访问URL触发设备ID,然后回车下一步进行配对。" read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" + # 自动添加域名到 allowedOrigins + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}已将域名 ${yuming} 加入 allowedOrigins 配置${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "请输入 Request_Key: " Request_Key From 6f3acb21495ab56fd5c2816f5a3a5d2eda943270 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 3 Mar 2026 15:10:46 +0800 Subject: [PATCH 0886/1285] docs: add v4.4.2 update log for OpenClaw domain automation --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 6b88730d9..1956239b3 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1465,3 +1465,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目新增飞书和WhatsApp机器人扫码对接功能。 ------------------------ +------------------------ +2026-03-03 v4.4.2 +1.OpenClaw管理中,WebUI访问设置功能增加自动注入域名到allowedOrigins逻辑,实现一键配对。 +2.主脚本与CN版脚本同步更新该自动化逻辑,确保国内外环境一致性。 From 2569252d59b94ea178c98113a7679daed41e75af Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 3 Mar 2026 15:14:55 +0800 Subject: [PATCH 0887/1285] chore: bump version to 4.4.2 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3adc5efc2..20b595b43 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.2" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 8f58da9da..6c26d340f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.2" gl_hui='\e[37m' From 19a61017e05ec01e4d82f508a62ffb7aae397352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:15:25 +0800 Subject: [PATCH 0888/1285] Fix device ID issue in OpenClaw WebUI settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复OpenClaw管理WebUI访问设置中绑定域名不出现设备ID的问题,并更新相关文档。 --- kejilion_sh_log.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1956239b3..da6cd583f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1463,9 +1463,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 系统工具一条龙调优原本均衡内核调优现在改为自动内核调优。 应用市场对ClawdBot/Moltbot机器人项目添加API时对模型的最大输出输入等参数进行优化,让大模型更稳定。 应用市场对ClawdBot/Moltbot机器人项目新增飞书和WhatsApp机器人扫码对接功能。 ------------------------- - ------------------------ 2026-03-03 v4.4.2 -1.OpenClaw管理中,WebUI访问设置功能增加自动注入域名到allowedOrigins逻辑,实现一键配对。 -2.主脚本与CN版脚本同步更新该自动化逻辑,确保国内外环境一致性。 +应用市场中OpenClaw管理 WebUI访问设置功能修复绑定域名不出现设备ID的问题。 +------------------------ + From 59583526ab76a19c3a0e98b00aac2d0bdf6033b6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 21:07:52 +0800 Subject: [PATCH 0889/1285] feat: add Windows OpenClaw standalone manager and one-liner installer --- README-Windows-OpenClaw.md | 36 +++ install.ps1 | 25 ++ openclaw-win-distribute.bat | 35 +++ openclaw-win-manager.bat | 33 +++ openclaw-win-manager.ps1 | 507 ++++++++++++++++++++++++++++++++++++ 5 files changed, 636 insertions(+) create mode 100644 README-Windows-OpenClaw.md create mode 100644 install.ps1 create mode 100644 openclaw-win-distribute.bat create mode 100644 openclaw-win-manager.bat create mode 100644 openclaw-win-manager.ps1 diff --git a/README-Windows-OpenClaw.md b/README-Windows-OpenClaw.md new file mode 100644 index 000000000..d4982192a --- /dev/null +++ b/README-Windows-OpenClaw.md @@ -0,0 +1,36 @@ +# OpenClaw Windows 10/11 独立管理脚本(快捷使用) + +## 文件 +- `openclaw-win-manager.ps1`:主脚本 +- `openclaw-win-manager.bat`:一键启动器(推荐) + +## 一键使用(推荐) +1. 右键 `openclaw-win-manager.bat`,选择**以管理员身份运行**。 +2. 进入交互菜单后,按数字操作: + - `1` 安装 OpenClaw + - `2/3/4` 启动/停止/重启 + - `5` 查看状态与日志 + - `6` 切换模型 + +## 首次安装建议顺序 +1. `1` 安装 OpenClaw +2. `12` 配置向导(onboard) +3. `2` 启动 OpenClaw +4. `5` 检查状态日志 + +## 常见问题 +### 1) 提示执行策略限制 +已在 `.bat` 内自动使用: +`-ExecutionPolicy Bypass` + +### 2) 提示找不到 Node.js +脚本会尝试自动用 `winget/choco/scoop` 安装 Node.js。 +如果都没有,请先手动安装 Node.js 20+。 + +### 3) 修改配置后不生效 +在菜单中执行 `4`(重启)或 `2` 启动前先 `3` 停止。 + +## 安全建议 +- 仅在可信机器运行。 +- API Key 建议最小权限。 +- 定期用菜单 `13` 执行 `doctor --fix`。 diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 000000000..7cc069d0e --- /dev/null +++ b/install.ps1 @@ -0,0 +1,25 @@ +# OpenClaw Windows one-liner installer/bootstrap +# Usage: +# iwr -useb https://openclaw.ai/install.ps1 | iex +# or +# irm https://raw.githubusercontent.com/kejilion/sh/main/install.ps1 | iex + +$ErrorActionPreference = 'Stop' +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +$managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/openclaw-win-manager.ps1' +$targetDir = Join-Path $env:ProgramData 'kejilion\openclaw' +$targetFile = Join-Path $targetDir 'openclaw-win-manager.ps1' + +Write-Host '[INFO] Preparing directories...' -ForegroundColor Cyan +New-Item -ItemType Directory -Path $targetDir -Force | Out-Null + +Write-Host '[INFO] Downloading latest manager script...' -ForegroundColor Cyan +Invoke-WebRequest -UseBasicParsing -Uri $managerUrl -OutFile $targetFile + +if ((Get-Item $targetFile).Length -lt 2000) { + throw 'Downloaded file is too small, abort.' +} + +Write-Host '[INFO] Starting OpenClaw Windows Manager...' -ForegroundColor Cyan +powershell -NoProfile -ExecutionPolicy Bypass -File $targetFile diff --git a/openclaw-win-distribute.bat b/openclaw-win-distribute.bat new file mode 100644 index 000000000..dc2638cc6 --- /dev/null +++ b/openclaw-win-distribute.bat @@ -0,0 +1,35 @@ +@echo off +chcp 65001 >nul +setlocal EnableDelayedExpansion + +REM OpenClaw Windows 一键分发版(单文件) +REM 用法:双击即可,自动拉取最新版 openclaw-win-manager.ps1 再启动 + +set "RAW_URL=https://raw.githubusercontent.com/kejilion/sh/main/openclaw-win-manager.ps1" +set "TARGET=%TEMP%\openclaw-win-manager.ps1" + +where powershell >nul 2>nul +if errorlevel 1 ( + echo [ERROR] 未检测到 PowerShell + pause + exit /b 1 +) + +echo [INFO] 正在下载最新版管理脚本... +powershell -NoProfile -ExecutionPolicy Bypass -Command "try { iwr -UseBasicParsing '%RAW_URL%' -OutFile '%TARGET%'; if ((Get-Item '%TARGET%').Length -lt 2000) { throw 'download too small' } } catch { Write-Host '[ERROR] 下载失败:' $_.Exception.Message; exit 1 }" +if errorlevel 1 ( + echo [ERROR] 下载失败,请检查网络或 RAW_URL。 + pause + exit /b 1 +) + +echo [INFO] 启动 OpenClaw Windows Manager... +powershell -NoProfile -ExecutionPolicy Bypass -File "%TARGET%" + +if errorlevel 1 ( + echo. + echo [WARN] 脚本退出代码: %errorlevel% +) + +pause +endlocal diff --git a/openclaw-win-manager.bat b/openclaw-win-manager.bat new file mode 100644 index 000000000..2479ce74d --- /dev/null +++ b/openclaw-win-manager.bat @@ -0,0 +1,33 @@ +@echo off +chcp 65001 >nul +setlocal + +REM OpenClaw Windows Manager 一键启动器 +REM 放在与 openclaw-win-manager.ps1 同目录 + +set "SCRIPT_DIR=%~dp0" +set "PS1=%SCRIPT_DIR%openclaw-win-manager.ps1" + +if not exist "%PS1%" ( + echo [ERROR] 未找到脚本: %PS1% + pause + exit /b 1 +) + +where powershell >nul 2>nul +if errorlevel 1 ( + echo [ERROR] 未检测到 PowerShell + pause + exit /b 1 +) + +echo [INFO] 正在启动 OpenClaw Windows 管理脚本... +powershell -NoProfile -ExecutionPolicy Bypass -File "%PS1%" + +if errorlevel 1 ( + echo. + echo [WARN] 脚本退出代码: %errorlevel% +) + +pause +endlocal diff --git a/openclaw-win-manager.ps1 b/openclaw-win-manager.ps1 new file mode 100644 index 000000000..fc2e3306e --- /dev/null +++ b/openclaw-win-manager.ps1 @@ -0,0 +1,507 @@ +#requires -Version 5.1 +<#! +.SYNOPSIS + OpenClaw Windows 10/11 独立管理脚本 +.DESCRIPTION + 参考 kejilion.sh 中 OpenClaw 管理设计理念,提供 Windows 版交互式管理: + - 安装/启动/停止/状态日志 + - 模型切换/Provider 注入 + - 插件与技能安装 + - 机器人配对 + - 配置文件编辑、健康修复、更新、卸载 + + 推荐在 PowerShell(管理员)运行: + Set-ExecutionPolicy -Scope Process Bypass + .\openclaw-win-manager.ps1 +#> + +[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() +$ErrorActionPreference = 'Stop' + +function Write-Info($msg) { Write-Host "[INFO] $msg" -ForegroundColor Cyan } +function Write-OK($msg) { Write-Host "[ OK ] $msg" -ForegroundColor Green } +function Write-Warn($msg) { Write-Host "[WARN] $msg" -ForegroundColor Yellow } +function Write-Err($msg) { Write-Host "[ERR ] $msg" -ForegroundColor Red } + +function Pause-Return { + Write-Host "" + Read-Host "按回车继续" +} + +function Test-Command($name) { + return [bool](Get-Command $name -ErrorAction SilentlyContinue) +} + +function Invoke-OpenClaw { + param( + [Parameter(Mandatory = $true)] + [string]$Args + ) + try { + Invoke-Expression "openclaw $Args" + } catch { + Write-Err "命令执行失败: openclaw $Args" + Write-Err $_.Exception.Message + } +} + +function Get-ConfigPath { + return Join-Path $env:USERPROFILE ".openclaw\openclaw.json" +} + +function Get-InstallStatus { + if (Test-Command "openclaw") { return "已安装" } + return "未安装" +} + +function Get-RunningStatus { + try { + $out = & openclaw gateway status 2>$null | Out-String + if ($out -match 'running|online|active|运行') { return "运行中" } + } catch {} + return "未运行" +} + +function Get-OpenClawVersion { + try { + $local = (& npm list -g openclaw --depth=0 --no-update-notifier 2>$null | Out-String) + $m = [regex]::Match($local, 'openclaw@([0-9A-Za-z\.-]+)') + if ($m.Success) { return $m.Groups[1].Value } + } catch {} + return $null +} + +function Get-OpenClawLatestVersion { + try { + $remote = (& npm view openclaw version --no-update-notifier 2>$null).Trim() + if ($remote) { return $remote } + } catch {} + return $null +} + +function Show-Banner { + Clear-Host + $install = Get-InstallStatus + $running = Get-RunningStatus + $local = Get-OpenClawVersion + $latest = Get-OpenClawLatestVersion + + $updateMsg = "版本信息未知" + if ($local -and $latest) { + if ($local -ne $latest) { $updateMsg = "检测到新版本: $latest (当前: $local)" } + else { $updateMsg = "当前已是最新: $local" } + } + + Write-Host "===========================================" + Write-Host "ClawdBot > MoltBot > OpenClaw 管理 (Win)" + Write-Host "状态: $install | $running | $updateMsg" + Write-Host "===========================================" + Write-Host "1. 安装 OpenClaw" + Write-Host "2. 启动 OpenClaw" + Write-Host "3. 停止 OpenClaw" + Write-Host "4. 重启 OpenClaw" + Write-Host "---------------------------" + Write-Host "5. 状态与日志" + Write-Host "6. 切换模型" + Write-Host "7. 添加 Provider(自动注入模型)" + Write-Host "8. 机器人连接对接" + Write-Host "9. 安装插件" + Write-Host "10. 安装技能(clawhub)" + Write-Host "11. 编辑主配置 openclaw.json" + Write-Host "12. 配置向导 (onboard)" + Write-Host "13. 健康检测与修复" + Write-Host "14. 查看 WebUI 地址" + Write-Host "---------------------------" + Write-Host "15. 更新 OpenClaw" + Write-Host "16. 卸载 OpenClaw" + Write-Host "0. 退出" + Write-Host "---------------------------" +} + +function Install-NodeIfNeeded { + if (Test-Command "node") { + Write-OK "Node.js 已存在: $(& node -v)" + return + } + + Write-Info "未检测到 Node.js,尝试自动安装..." + if (Test-Command "winget") { + Write-Info "使用 winget 安装 Node.js (LTS)" + & winget install --id OpenJS.NodeJS.LTS -e --accept-package-agreements --accept-source-agreements + return + } + + if (Test-Command "choco") { + Write-Info "使用 Chocolatey 安装 Node.js" + & choco install nodejs-lts -y + return + } + + if (Test-Command "scoop") { + Write-Info "使用 Scoop 安装 Node.js" + & scoop install nodejs-lts + return + } + + throw "未找到 winget/choco/scoop,无法自动安装 Node.js,请先手动安装 Node.js 20+" +} + +function Install-OpenClaw { + try { + Install-NodeIfNeeded + + if (-not (Test-Command "npm")) { + throw "npm 不可用,请确认 Node.js 安装成功。" + } + + Write-Info "安装 OpenClaw..." + & npm install -g openclaw@latest + + Write-Info "运行初始化向导(安装守护进程)..." + Invoke-OpenClaw "onboard --install-daemon" + + Write-Info "启动网关..." + Invoke-OpenClaw "gateway restart" + + Write-OK "安装完成。" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Start-OpenClaw { + Invoke-OpenClaw "gateway start" + Pause-Return +} + +function Stop-OpenClaw { + Invoke-OpenClaw "gateway stop" + Pause-Return +} + +function Restart-OpenClaw { + Invoke-OpenClaw "gateway restart" + Pause-Return +} + +function Show-StatusLogs { + Write-Host "\n===== openclaw status =====" -ForegroundColor Magenta + Invoke-OpenClaw "status" + Write-Host "\n===== gateway status =====" -ForegroundColor Magenta + Invoke-OpenClaw "gateway status" + Write-Host "\n===== openclaw logs =====" -ForegroundColor Magenta + Invoke-OpenClaw "logs" + Pause-Return +} + +function Change-Model { + try { + Write-Host "\n--- 所有可用模型 ---" -ForegroundColor Magenta + Invoke-OpenClaw "models list --all" + Write-Host "\n--- 当前模型 ---" -ForegroundColor Magenta + Invoke-OpenClaw "models list" + + $model = Read-Host "请输入目标模型(示例: provider/model,输入 0 取消)" + if ($model -eq '0' -or [string]::IsNullOrWhiteSpace($model)) { return } + + Invoke-OpenClaw "models set $model" + Write-OK "已切换模型: $model" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Build-ModelCost { + param([string]$modelId) + + $input = 0.15 + $output = 0.60 + + if ($modelId -match 'opus|pro|preview|thinking|sonnet') { + $input = 2.00; $output = 12.00 + } + elseif ($modelId -match 'gpt-5|codex') { + $input = 1.25; $output = 10.00 + } + elseif ($modelId -match 'flash|lite|haiku|mini|nano') { + $input = 0.10; $output = 0.40 + } + + return @{ input = $input; output = $output; cacheRead = 0; cacheWrite = 0 } +} + +function Add-ProviderInteractive { + try { + $provider = Read-Host "请输入 Provider 名称(例如 deepseek)" + if ([string]::IsNullOrWhiteSpace($provider)) { throw "Provider 名称不能为空" } + + $baseUrl = Read-Host "请输入 Base URL(例如 https://api.xxx.com/v1)" + if ([string]::IsNullOrWhiteSpace($baseUrl)) { throw "Base URL 不能为空" } + $baseUrl = $baseUrl.TrimEnd('/') + + $apiKey = Read-Host "请输入 API Key" + if ([string]::IsNullOrWhiteSpace($apiKey)) { throw "API Key 不能为空" } + + Write-Info "正在获取模型列表: $baseUrl/models" + $headers = @{ Authorization = "Bearer $apiKey" } + $resp = Invoke-RestMethod -Uri "$baseUrl/models" -Headers $headers -Method Get -TimeoutSec 30 + + if (-not $resp.data) { throw "未获取到模型列表。" } + + $modelIds = @($resp.data | ForEach-Object { $_.id } | Where-Object { $_ } | Sort-Object -Unique) + if ($modelIds.Count -eq 0) { throw "模型列表为空。" } + + Write-OK "发现 $($modelIds.Count) 个模型:" + for ($i = 0; $i -lt $modelIds.Count; $i++) { + Write-Host "[$($i+1)] $($modelIds[$i])" + } + + $defaultInput = Read-Host "请输入默认模型(序号或ID,留空默认第一个)" + $defaultModel = $modelIds[0] + if (-not [string]::IsNullOrWhiteSpace($defaultInput)) { + if ($defaultInput -match '^\d+$') { + $idx = [int]$defaultInput - 1 + if ($idx -ge 0 -and $idx -lt $modelIds.Count) { $defaultModel = $modelIds[$idx] } + } else { + $defaultModel = $defaultInput + } + } + + $configPath = Get-ConfigPath + if (-not (Test-Path $configPath)) { + throw "配置文件不存在: $configPath,请先执行一次 openclaw onboard --install-daemon" + } + + $backup = "$configPath.bak.$([DateTimeOffset]::Now.ToUnixTimeSeconds())" + Copy-Item $configPath $backup -Force + Write-Info "已备份配置: $backup" + + $json = Get-Content $configPath -Raw | ConvertFrom-Json + + if (-not $json.models) { + $json | Add-Member -MemberType NoteProperty -Name models -Value (@{}) + } + + $json.models.mode = 'merge' + if (-not $json.models.providers) { + $json.models | Add-Member -MemberType NoteProperty -Name providers -Value (@{}) + } + + $models = @() + foreach ($m in $modelIds) { + $models += [PSCustomObject]@{ + id = $m + name = "$provider / $m" + input = @('text', 'image') + contextWindow = 1048576 + maxTokens = 128000 + cost = (Build-ModelCost -modelId $m) + } + } + + $json.models.providers.$provider = [PSCustomObject]@{ + baseUrl = $baseUrl + apiKey = $apiKey + api = 'openai-completions' + models = $models + } + + $json | ConvertTo-Json -Depth 20 | Set-Content -Path $configPath -Encoding UTF8 + Write-OK "Provider [$provider] 已注入,模型数量: $($modelIds.Count)" + + Invoke-OpenClaw "models set $provider/$defaultModel" + Invoke-OpenClaw "gateway restart" + Write-OK "默认模型已设置为: $provider/$defaultModel" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Pairing-Menu { + while ($true) { + Clear-Host + Write-Host "=== 机器人连接对接 ===" + Write-Host "1. Telegram" + Write-Host "2. 飞书 (Feishu/Lark)" + Write-Host "3. WhatsApp" + Write-Host "0. 返回" + $c = Read-Host "请选择" + + switch ($c) { + '1' { + $code = Read-Host "请输入 Telegram 连接码" + if ($code) { Invoke-OpenClaw "pairing approve telegram $code"; Pause-Return } + } + '2' { + $code = Read-Host "请输入 Feishu 连接码" + if ($code) { Invoke-OpenClaw "pairing approve feishu $code"; Pause-Return } + } + '3' { + $code = Read-Host "请输入 WhatsApp 连接码" + if ($code) { Invoke-OpenClaw "pairing approve whatsapp $code"; Pause-Return } + } + '0' { return } + default { Write-Warn "无效选项"; Start-Sleep -Milliseconds 700 } + } + } +} + +function Install-Plugin { + try { + Write-Host "\n--- 当前插件 ---" -ForegroundColor Magenta + Invoke-OpenClaw "plugins list" + $plugin = Read-Host "请输入插件 ID(例如 telegram / feishu / @openclaw/discord,输入0取消)" + if (-not $plugin -or $plugin -eq '0') { return } + + $pluginId = $plugin -replace '^@openclaw/', '' + + Write-Info "尝试直接启用已安装插件: $pluginId" + Invoke-OpenClaw "plugins enable $pluginId" + + Write-Info "若未安装则执行安装: $plugin" + Invoke-OpenClaw "plugins install $plugin" + Invoke-OpenClaw "plugins enable $pluginId" + + Invoke-OpenClaw "gateway restart" + Write-OK "插件处理完成: $plugin" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Install-Skill { + try { + Write-Host "\n--- 当前技能 ---" -ForegroundColor Magenta + Invoke-OpenClaw "skills list" + + $skill = Read-Host "请输入技能名(例如 weather / youtube-transcript,输入0取消)" + if (-not $skill -or $skill -eq '0') { return } + + if (-not (Test-Command "npx")) { throw "npx 不可用,请先安装 Node.js" } + + Write-Info "正在安装技能: $skill" + & npx clawhub install $skill + + Invoke-OpenClaw "gateway restart" + Write-OK "技能安装完成: $skill" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Edit-Config { + $path = Get-ConfigPath + if (-not (Test-Path $path)) { + Write-Warn "配置不存在: $path" + Pause-Return + return + } + notepad $path + Write-Info "若已修改配置,建议重启网关生效。" + Pause-Return +} + +function Run-Onboard { + Invoke-OpenClaw "onboard --install-daemon" + Pause-Return +} + +function Run-Doctor { + Invoke-OpenClaw "doctor --fix" + Pause-Return +} + +function Show-WebUI { + try { + $out = (& openclaw dashboard 2>$null | Out-String) + if (-not $out) { + Write-Warn "未读取到 dashboard 输出,请先确保网关已启动。" + Pause-Return + return + } + + $tokenMatch = [regex]::Match($out, '#token=([a-f0-9]+)') + if ($tokenMatch.Success) { + $token = $tokenMatch.Groups[1].Value + Write-Host "本机访问地址:" -ForegroundColor Green + Write-Host "http://127.0.0.1:18789/#token=$token" + Write-Host "" + Write-Host "若需局域网访问,请自行在防火墙放行 18789 并配置 allowedOrigins。" -ForegroundColor Yellow + } else { + Write-Host $out + } + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Update-OpenClaw { + try { + Install-NodeIfNeeded + & npm install -g openclaw@latest + Invoke-OpenClaw "gateway restart" + Write-OK "更新完成。" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +function Uninstall-OpenClaw { + try { + Invoke-OpenClaw "uninstall" + if (Test-Command "npm") { + & npm uninstall -g openclaw + } + Write-OK "已卸载 OpenClaw。" + } + catch { + Write-Err $_.Exception.Message + } + Pause-Return +} + +while ($true) { + Show-Banner + $choice = Read-Host "请输入选项并回车" + + switch ($choice) { + '1' { Install-OpenClaw } + '2' { Start-OpenClaw } + '3' { Stop-OpenClaw } + '4' { Restart-OpenClaw } + '5' { Show-StatusLogs } + '6' { Change-Model } + '7' { Add-ProviderInteractive } + '8' { Pairing-Menu } + '9' { Install-Plugin } + '10' { Install-Skill } + '11' { Edit-Config } + '12' { Run-Onboard } + '13' { Run-Doctor } + '14' { Show-WebUI } + '15' { Update-OpenClaw } + '16' { Uninstall-OpenClaw } + '0' { + Write-Host "已退出。" -ForegroundColor Green + break + } + default { + Write-Warn "无效选项,请重试。" + Start-Sleep -Milliseconds 600 + } + } +} From f867bb8d1f134204185accfe7bc6d4155c101226 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 21:46:39 +0800 Subject: [PATCH 0890/1285] fix: make windows manager ASCII-safe to avoid powershell encoding parse errors --- openclaw-win-manager.ps1 | 642 ++++++++++++++------------------------- 1 file changed, 231 insertions(+), 411 deletions(-) diff --git a/openclaw-win-manager.ps1 b/openclaw-win-manager.ps1 index fc2e3306e..38f4ec1c9 100644 --- a/openclaw-win-manager.ps1 +++ b/openclaw-win-manager.ps1 @@ -1,507 +1,327 @@ #requires -Version 5.1 -<#! -.SYNOPSIS - OpenClaw Windows 10/11 独立管理脚本 -.DESCRIPTION - 参考 kejilion.sh 中 OpenClaw 管理设计理念,提供 Windows 版交互式管理: - - 安装/启动/停止/状态日志 - - 模型切换/Provider 注入 - - 插件与技能安装 - - 机器人配对 - - 配置文件编辑、健康修复、更新、卸载 - - 推荐在 PowerShell(管理员)运行: - Set-ExecutionPolicy -Scope Process Bypass +<# +OpenClaw Windows 10/11 standalone manager (ASCII-safe for PowerShell 5.1) +Run: + Set-ExecutionPolicy -Scope Process Bypass -Force .\openclaw-win-manager.ps1 #> -[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() $ErrorActionPreference = 'Stop' -function Write-Info($msg) { Write-Host "[INFO] $msg" -ForegroundColor Cyan } -function Write-OK($msg) { Write-Host "[ OK ] $msg" -ForegroundColor Green } -function Write-Warn($msg) { Write-Host "[WARN] $msg" -ForegroundColor Yellow } -function Write-Err($msg) { Write-Host "[ERR ] $msg" -ForegroundColor Red } +function Info($m){ Write-Host "[INFO] $m" -ForegroundColor Cyan } +function OK($m){ Write-Host "[ OK ] $m" -ForegroundColor Green } +function Warn($m){ Write-Host "[WARN] $m" -ForegroundColor Yellow } +function Err($m){ Write-Host "[ERR ] $m" -ForegroundColor Red } +function PauseBack { ""; Read-Host "Press Enter to continue" | Out-Null } -function Pause-Return { - Write-Host "" - Read-Host "按回车继续" +function HasCmd($n){ return [bool](Get-Command $n -ErrorAction SilentlyContinue) } +function OC([string]$args){ + try { Invoke-Expression "openclaw $args" } + catch { Err "openclaw $args failed"; Err $_.Exception.Message } } -function Test-Command($name) { - return [bool](Get-Command $name -ErrorAction SilentlyContinue) -} - -function Invoke-OpenClaw { - param( - [Parameter(Mandatory = $true)] - [string]$Args - ) - try { - Invoke-Expression "openclaw $Args" - } catch { - Write-Err "命令执行失败: openclaw $Args" - Write-Err $_.Exception.Message - } -} - -function Get-ConfigPath { - return Join-Path $env:USERPROFILE ".openclaw\openclaw.json" -} - -function Get-InstallStatus { - if (Test-Command "openclaw") { return "已安装" } - return "未安装" -} +function ConfigPath { Join-Path $env:USERPROFILE ".openclaw\openclaw.json" } -function Get-RunningStatus { +function InstallStatus { if(HasCmd "openclaw"){"Installed"}else{"Not installed"} } +function RunningStatus { try { $out = & openclaw gateway status 2>$null | Out-String - if ($out -match 'running|online|active|运行') { return "运行中" } + if($out -match 'running|online|active'){ return "Running" } } catch {} - return "未运行" + return "Stopped" } -function Get-OpenClawVersion { +function LocalVersion { try { - $local = (& npm list -g openclaw --depth=0 --no-update-notifier 2>$null | Out-String) - $m = [regex]::Match($local, 'openclaw@([0-9A-Za-z\.-]+)') - if ($m.Success) { return $m.Groups[1].Value } + $t = (& npm list -g openclaw --depth=0 --no-update-notifier 2>$null | Out-String) + $m = [regex]::Match($t,'openclaw@([0-9A-Za-z\.-]+)') + if($m.Success){ return $m.Groups[1].Value } } catch {} return $null } -function Get-OpenClawLatestVersion { +function LatestVersion { try { - $remote = (& npm view openclaw version --no-update-notifier 2>$null).Trim() - if ($remote) { return $remote } + $v = (& npm view openclaw version --no-update-notifier 2>$null).Trim() + if($v){ return $v } } catch {} return $null } -function Show-Banner { +function ShowMenu { Clear-Host - $install = Get-InstallStatus - $running = Get-RunningStatus - $local = Get-OpenClawVersion - $latest = Get-OpenClawLatestVersion - - $updateMsg = "版本信息未知" - if ($local -and $latest) { - if ($local -ne $latest) { $updateMsg = "检测到新版本: $latest (当前: $local)" } - else { $updateMsg = "当前已是最新: $local" } + $ins = InstallStatus + $run = RunningStatus + $lv = LocalVersion + $rv = LatestVersion + $verMsg = "Version unknown" + if($lv -and $rv){ + if($lv -ne $rv){ $verMsg = "Update available: $rv (current $lv)" } + else { $verMsg = "Latest: $lv" } } Write-Host "===========================================" - Write-Host "ClawdBot > MoltBot > OpenClaw 管理 (Win)" - Write-Host "状态: $install | $running | $updateMsg" + Write-Host "OpenClaw Windows Manager" + Write-Host "Status: $ins | $run | $verMsg" Write-Host "===========================================" - Write-Host "1. 安装 OpenClaw" - Write-Host "2. 启动 OpenClaw" - Write-Host "3. 停止 OpenClaw" - Write-Host "4. 重启 OpenClaw" - Write-Host "---------------------------" - Write-Host "5. 状态与日志" - Write-Host "6. 切换模型" - Write-Host "7. 添加 Provider(自动注入模型)" - Write-Host "8. 机器人连接对接" - Write-Host "9. 安装插件" - Write-Host "10. 安装技能(clawhub)" - Write-Host "11. 编辑主配置 openclaw.json" - Write-Host "12. 配置向导 (onboard)" - Write-Host "13. 健康检测与修复" - Write-Host "14. 查看 WebUI 地址" - Write-Host "---------------------------" - Write-Host "15. 更新 OpenClaw" - Write-Host "16. 卸载 OpenClaw" - Write-Host "0. 退出" - Write-Host "---------------------------" + Write-Host "1. Install OpenClaw" + Write-Host "2. Start OpenClaw" + Write-Host "3. Stop OpenClaw" + Write-Host "4. Restart OpenClaw" + Write-Host "5. Status + Logs" + Write-Host "6. Switch model" + Write-Host "7. Add provider (auto models import)" + Write-Host "8. Pairing (Telegram/Feishu/WhatsApp)" + Write-Host "9. Install plugin" + Write-Host "10. Install skill (clawhub)" + Write-Host "11. Edit config file" + Write-Host "12. Run onboard" + Write-Host "13. Run doctor --fix" + Write-Host "14. Show WebUI URL" + Write-Host "15. Update OpenClaw" + Write-Host "16. Uninstall OpenClaw" + Write-Host "0. Exit" + Write-Host "-------------------------------------------" } -function Install-NodeIfNeeded { - if (Test-Command "node") { - Write-OK "Node.js 已存在: $(& node -v)" - return - } +function InstallNodeIfNeeded { + if(HasCmd "node"){ OK "Node.js found: $(& node -v)"; return } + Info "Node.js not found, trying auto-install" - Write-Info "未检测到 Node.js,尝试自动安装..." - if (Test-Command "winget") { - Write-Info "使用 winget 安装 Node.js (LTS)" + if(HasCmd "winget"){ & winget install --id OpenJS.NodeJS.LTS -e --accept-package-agreements --accept-source-agreements return } + if(HasCmd "choco"){ & choco install nodejs-lts -y; return } + if(HasCmd "scoop"){ & scoop install nodejs-lts; return } - if (Test-Command "choco") { - Write-Info "使用 Chocolatey 安装 Node.js" - & choco install nodejs-lts -y - return - } - - if (Test-Command "scoop") { - Write-Info "使用 Scoop 安装 Node.js" - & scoop install nodejs-lts - return - } - - throw "未找到 winget/choco/scoop,无法自动安装 Node.js,请先手动安装 Node.js 20+" + throw "No winget/choco/scoop found. Install Node.js 20+ manually first." } -function Install-OpenClaw { +function InstallOpenClaw { try { - Install-NodeIfNeeded - - if (-not (Test-Command "npm")) { - throw "npm 不可用,请确认 Node.js 安装成功。" - } - - Write-Info "安装 OpenClaw..." + InstallNodeIfNeeded + if(-not (HasCmd "npm")){ throw "npm not found after Node install" } + Info "Installing openclaw..." & npm install -g openclaw@latest - - Write-Info "运行初始化向导(安装守护进程)..." - Invoke-OpenClaw "onboard --install-daemon" - - Write-Info "启动网关..." - Invoke-OpenClaw "gateway restart" - - Write-OK "安装完成。" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return -} - -function Start-OpenClaw { - Invoke-OpenClaw "gateway start" - Pause-Return -} - -function Stop-OpenClaw { - Invoke-OpenClaw "gateway stop" - Pause-Return + Info "Running onboard..." + OC "onboard --install-daemon" + OC "gateway restart" + OK "Install done" + } catch { Err $_.Exception.Message } + PauseBack } -function Restart-OpenClaw { - Invoke-OpenClaw "gateway restart" - Pause-Return +function StartOpenClaw { OC "gateway start"; PauseBack } +function StopOpenClaw { OC "gateway stop"; PauseBack } +function RestartOpenClaw { OC "gateway restart"; PauseBack } + +function ShowStatusLogs { + Write-Host "`n=== openclaw status ===" -ForegroundColor Magenta + OC "status" + Write-Host "`n=== gateway status ===" -ForegroundColor Magenta + OC "gateway status" + Write-Host "`n=== openclaw logs ===" -ForegroundColor Magenta + OC "logs" + PauseBack } -function Show-StatusLogs { - Write-Host "\n===== openclaw status =====" -ForegroundColor Magenta - Invoke-OpenClaw "status" - Write-Host "\n===== gateway status =====" -ForegroundColor Magenta - Invoke-OpenClaw "gateway status" - Write-Host "\n===== openclaw logs =====" -ForegroundColor Magenta - Invoke-OpenClaw "logs" - Pause-Return -} - -function Change-Model { +function SwitchModel { try { - Write-Host "\n--- 所有可用模型 ---" -ForegroundColor Magenta - Invoke-OpenClaw "models list --all" - Write-Host "\n--- 当前模型 ---" -ForegroundColor Magenta - Invoke-OpenClaw "models list" - - $model = Read-Host "请输入目标模型(示例: provider/model,输入 0 取消)" - if ($model -eq '0' -or [string]::IsNullOrWhiteSpace($model)) { return } - - Invoke-OpenClaw "models set $model" - Write-OK "已切换模型: $model" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + Write-Host "`n--- all models ---" -ForegroundColor Magenta + OC "models list --all" + Write-Host "`n--- current model ---" -ForegroundColor Magenta + OC "models list" + $m = Read-Host "Target model (provider/model), 0 to cancel" + if(-not $m -or $m -eq '0'){ return } + OC "models set $m" + OK "Model switched: $m" + } catch { Err $_.Exception.Message } + PauseBack } -function Build-ModelCost { - param([string]$modelId) - - $input = 0.15 - $output = 0.60 - - if ($modelId -match 'opus|pro|preview|thinking|sonnet') { - $input = 2.00; $output = 12.00 - } - elseif ($modelId -match 'gpt-5|codex') { - $input = 1.25; $output = 10.00 - } - elseif ($modelId -match 'flash|lite|haiku|mini|nano') { - $input = 0.10; $output = 0.40 - } - - return @{ input = $input; output = $output; cacheRead = 0; cacheWrite = 0 } +function ModelCost([string]$id){ + $in=0.15; $out=0.60 + if($id -match 'opus|pro|preview|thinking|sonnet'){ $in=2.00; $out=12.00 } + elseif($id -match 'gpt-5|codex'){ $in=1.25; $out=10.00 } + elseif($id -match 'flash|lite|haiku|mini|nano'){ $in=0.10; $out=0.40 } + return @{ input=$in; output=$out; cacheRead=0; cacheWrite=0 } } -function Add-ProviderInteractive { +function AddProvider { try { - $provider = Read-Host "请输入 Provider 名称(例如 deepseek)" - if ([string]::IsNullOrWhiteSpace($provider)) { throw "Provider 名称不能为空" } - - $baseUrl = Read-Host "请输入 Base URL(例如 https://api.xxx.com/v1)" - if ([string]::IsNullOrWhiteSpace($baseUrl)) { throw "Base URL 不能为空" } - $baseUrl = $baseUrl.TrimEnd('/') - - $apiKey = Read-Host "请输入 API Key" - if ([string]::IsNullOrWhiteSpace($apiKey)) { throw "API Key 不能为空" } - - Write-Info "正在获取模型列表: $baseUrl/models" - $headers = @{ Authorization = "Bearer $apiKey" } - $resp = Invoke-RestMethod -Uri "$baseUrl/models" -Headers $headers -Method Get -TimeoutSec 30 - - if (-not $resp.data) { throw "未获取到模型列表。" } - - $modelIds = @($resp.data | ForEach-Object { $_.id } | Where-Object { $_ } | Sort-Object -Unique) - if ($modelIds.Count -eq 0) { throw "模型列表为空。" } - - Write-OK "发现 $($modelIds.Count) 个模型:" - for ($i = 0; $i -lt $modelIds.Count; $i++) { - Write-Host "[$($i+1)] $($modelIds[$i])" - } - - $defaultInput = Read-Host "请输入默认模型(序号或ID,留空默认第一个)" - $defaultModel = $modelIds[0] - if (-not [string]::IsNullOrWhiteSpace($defaultInput)) { - if ($defaultInput -match '^\d+$') { - $idx = [int]$defaultInput - 1 - if ($idx -ge 0 -and $idx -lt $modelIds.Count) { $defaultModel = $modelIds[$idx] } - } else { - $defaultModel = $defaultInput - } - } - - $configPath = Get-ConfigPath - if (-not (Test-Path $configPath)) { - throw "配置文件不存在: $configPath,请先执行一次 openclaw onboard --install-daemon" + $provider = Read-Host "Provider name" + if(-not $provider){ throw "Provider name is required" } + $base = Read-Host "Base URL (e.g. https://api.xxx.com/v1)" + if(-not $base){ throw "Base URL is required" } + $base = $base.TrimEnd('/') + $key = Read-Host "API key" + if(-not $key){ throw "API key is required" } + + Info "Fetching models from $base/models ..." + $resp = Invoke-RestMethod -Uri "$base/models" -Headers @{Authorization="Bearer $key"} -TimeoutSec 30 + $ids = @($resp.data | ForEach-Object { $_.id } | Where-Object { $_ } | Sort-Object -Unique) + if($ids.Count -eq 0){ throw "No models found" } + + for($i=0;$i -lt $ids.Count;$i++){ Write-Host "[$($i+1)] $($ids[$i])" } + $pick = Read-Host "Default model (index or id, blank=first)" + $default = $ids[0] + if($pick){ + if($pick -match '^\d+$'){ + $ix=[int]$pick-1 + if($ix -ge 0 -and $ix -lt $ids.Count){ $default=$ids[$ix] } + } else { $default = $pick } } - $backup = "$configPath.bak.$([DateTimeOffset]::Now.ToUnixTimeSeconds())" - Copy-Item $configPath $backup -Force - Write-Info "已备份配置: $backup" - - $json = Get-Content $configPath -Raw | ConvertFrom-Json + $cfg = ConfigPath + if(-not (Test-Path $cfg)){ throw "Config not found: $cfg. Run onboard first." } - if (-not $json.models) { - $json | Add-Member -MemberType NoteProperty -Name models -Value (@{}) - } + Copy-Item $cfg "$cfg.bak.$([DateTimeOffset]::Now.ToUnixTimeSeconds())" -Force + $json = Get-Content $cfg -Raw | ConvertFrom-Json + if(-not $json.models){ $json | Add-Member -NotePropertyName models -NotePropertyValue (@{}) } $json.models.mode = 'merge' - if (-not $json.models.providers) { - $json.models | Add-Member -MemberType NoteProperty -Name providers -Value (@{}) - } + if(-not $json.models.providers){ $json.models | Add-Member -NotePropertyName providers -NotePropertyValue (@{}) } $models = @() - foreach ($m in $modelIds) { - $models += [PSCustomObject]@{ - id = $m - name = "$provider / $m" - input = @('text', 'image') - contextWindow = 1048576 - maxTokens = 128000 - cost = (Build-ModelCost -modelId $m) + foreach($id in $ids){ + $models += [pscustomobject]@{ + id=$id + name="$provider / $id" + input=@('text','image') + contextWindow=1048576 + maxTokens=128000 + cost=(ModelCost $id) } } - $json.models.providers.$provider = [PSCustomObject]@{ - baseUrl = $baseUrl - apiKey = $apiKey - api = 'openai-completions' - models = $models + $json.models.providers.$provider = [pscustomobject]@{ + baseUrl=$base + apiKey=$key + api='openai-completions' + models=$models } - $json | ConvertTo-Json -Depth 20 | Set-Content -Path $configPath -Encoding UTF8 - Write-OK "Provider [$provider] 已注入,模型数量: $($modelIds.Count)" - - Invoke-OpenClaw "models set $provider/$defaultModel" - Invoke-OpenClaw "gateway restart" - Write-OK "默认模型已设置为: $provider/$defaultModel" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + $json | ConvertTo-Json -Depth 20 | Set-Content -Path $cfg -Encoding UTF8 + OC "models set $provider/$default" + OC "gateway restart" + OK "Provider added: $provider, default model: $provider/$default" + } catch { Err $_.Exception.Message } + PauseBack } -function Pairing-Menu { - while ($true) { +function PairingMenu { + while($true){ Clear-Host - Write-Host "=== 机器人连接对接 ===" + Write-Host "=== Pairing ===" Write-Host "1. Telegram" - Write-Host "2. 飞书 (Feishu/Lark)" + Write-Host "2. Feishu/Lark" Write-Host "3. WhatsApp" - Write-Host "0. 返回" - $c = Read-Host "请选择" - - switch ($c) { - '1' { - $code = Read-Host "请输入 Telegram 连接码" - if ($code) { Invoke-OpenClaw "pairing approve telegram $code"; Pause-Return } - } - '2' { - $code = Read-Host "请输入 Feishu 连接码" - if ($code) { Invoke-OpenClaw "pairing approve feishu $code"; Pause-Return } - } - '3' { - $code = Read-Host "请输入 WhatsApp 连接码" - if ($code) { Invoke-OpenClaw "pairing approve whatsapp $code"; Pause-Return } - } + Write-Host "0. Back" + $c = Read-Host "Select" + switch($c){ + '1' { $code=Read-Host "Telegram code"; if($code){ OC "pairing approve telegram $code"; PauseBack } } + '2' { $code=Read-Host "Feishu code"; if($code){ OC "pairing approve feishu $code"; PauseBack } } + '3' { $code=Read-Host "WhatsApp code"; if($code){ OC "pairing approve whatsapp $code"; PauseBack } } '0' { return } - default { Write-Warn "无效选项"; Start-Sleep -Milliseconds 700 } + default { Warn "Invalid"; Start-Sleep -Milliseconds 600 } } } } -function Install-Plugin { +function InstallPlugin { try { - Write-Host "\n--- 当前插件 ---" -ForegroundColor Magenta - Invoke-OpenClaw "plugins list" - $plugin = Read-Host "请输入插件 ID(例如 telegram / feishu / @openclaw/discord,输入0取消)" - if (-not $plugin -or $plugin -eq '0') { return } - - $pluginId = $plugin -replace '^@openclaw/', '' - - Write-Info "尝试直接启用已安装插件: $pluginId" - Invoke-OpenClaw "plugins enable $pluginId" - - Write-Info "若未安装则执行安装: $plugin" - Invoke-OpenClaw "plugins install $plugin" - Invoke-OpenClaw "plugins enable $pluginId" - - Invoke-OpenClaw "gateway restart" - Write-OK "插件处理完成: $plugin" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + OC "plugins list" + $p = Read-Host "Plugin id (e.g. telegram/feishu/@openclaw/discord), 0 cancel" + if(-not $p -or $p -eq '0'){ return } + $id = $p -replace '^@openclaw/','' + OC "plugins enable $id" + OC "plugins install $p" + OC "plugins enable $id" + OC "gateway restart" + OK "Plugin processed: $p" + } catch { Err $_.Exception.Message } + PauseBack } -function Install-Skill { +function InstallSkill { try { - Write-Host "\n--- 当前技能 ---" -ForegroundColor Magenta - Invoke-OpenClaw "skills list" - - $skill = Read-Host "请输入技能名(例如 weather / youtube-transcript,输入0取消)" - if (-not $skill -or $skill -eq '0') { return } - - if (-not (Test-Command "npx")) { throw "npx 不可用,请先安装 Node.js" } - - Write-Info "正在安装技能: $skill" - & npx clawhub install $skill - - Invoke-OpenClaw "gateway restart" - Write-OK "技能安装完成: $skill" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + OC "skills list" + $s = Read-Host "Skill name, 0 cancel" + if(-not $s -or $s -eq '0'){ return } + if(-not (HasCmd "npx")){ throw "npx not found" } + & npx clawhub install $s + OC "gateway restart" + OK "Skill installed: $s" + } catch { Err $_.Exception.Message } + PauseBack } -function Edit-Config { - $path = Get-ConfigPath - if (-not (Test-Path $path)) { - Write-Warn "配置不存在: $path" - Pause-Return - return - } - notepad $path - Write-Info "若已修改配置,建议重启网关生效。" - Pause-Return +function EditConfig { + $p = ConfigPath + if(-not (Test-Path $p)){ Warn "Config not found: $p"; PauseBack; return } + notepad $p + Info "Restart gateway to apply changes" + PauseBack } -function Run-Onboard { - Invoke-OpenClaw "onboard --install-daemon" - Pause-Return -} - -function Run-Doctor { - Invoke-OpenClaw "doctor --fix" - Pause-Return -} +function RunOnboard { OC "onboard --install-daemon"; PauseBack } +function RunDoctor { OC "doctor --fix"; PauseBack } -function Show-WebUI { +function ShowWebUI { try { - $out = (& openclaw dashboard 2>$null | Out-String) - if (-not $out) { - Write-Warn "未读取到 dashboard 输出,请先确保网关已启动。" - Pause-Return - return - } - - $tokenMatch = [regex]::Match($out, '#token=([a-f0-9]+)') - if ($tokenMatch.Success) { - $token = $tokenMatch.Groups[1].Value - Write-Host "本机访问地址:" -ForegroundColor Green - Write-Host "http://127.0.0.1:18789/#token=$token" - Write-Host "" - Write-Host "若需局域网访问,请自行在防火墙放行 18789 并配置 allowedOrigins。" -ForegroundColor Yellow + $o = (& openclaw dashboard 2>$null | Out-String) + $m = [regex]::Match($o,'#token=([a-f0-9]+)') + if($m.Success){ + $t = $m.Groups[1].Value + Write-Host "http://127.0.0.1:18789/#token=$t" -ForegroundColor Green } else { - Write-Host $out + Write-Host $o } - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + } catch { Err $_.Exception.Message } + PauseBack } -function Update-OpenClaw { +function UpdateOpenClaw { try { - Install-NodeIfNeeded + InstallNodeIfNeeded & npm install -g openclaw@latest - Invoke-OpenClaw "gateway restart" - Write-OK "更新完成。" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + OC "gateway restart" + OK "Update done" + } catch { Err $_.Exception.Message } + PauseBack } -function Uninstall-OpenClaw { +function UninstallOpenClaw { try { - Invoke-OpenClaw "uninstall" - if (Test-Command "npm") { - & npm uninstall -g openclaw - } - Write-OK "已卸载 OpenClaw。" - } - catch { - Write-Err $_.Exception.Message - } - Pause-Return + OC "uninstall" + if(HasCmd "npm"){ & npm uninstall -g openclaw } + OK "Uninstalled" + } catch { Err $_.Exception.Message } + PauseBack } -while ($true) { - Show-Banner - $choice = Read-Host "请输入选项并回车" - - switch ($choice) { - '1' { Install-OpenClaw } - '2' { Start-OpenClaw } - '3' { Stop-OpenClaw } - '4' { Restart-OpenClaw } - '5' { Show-StatusLogs } - '6' { Change-Model } - '7' { Add-ProviderInteractive } - '8' { Pairing-Menu } - '9' { Install-Plugin } - '10' { Install-Skill } - '11' { Edit-Config } - '12' { Run-Onboard } - '13' { Run-Doctor } - '14' { Show-WebUI } - '15' { Update-OpenClaw } - '16' { Uninstall-OpenClaw } - '0' { - Write-Host "已退出。" -ForegroundColor Green - break - } - default { - Write-Warn "无效选项,请重试。" - Start-Sleep -Milliseconds 600 - } +while($true){ + ShowMenu + $c = Read-Host "Select" + switch($c){ + '1' { InstallOpenClaw } + '2' { StartOpenClaw } + '3' { StopOpenClaw } + '4' { RestartOpenClaw } + '5' { ShowStatusLogs } + '6' { SwitchModel } + '7' { AddProvider } + '8' { PairingMenu } + '9' { InstallPlugin } + '10' { InstallSkill } + '11' { EditConfig } + '12' { RunOnboard } + '13' { RunDoctor } + '14' { ShowWebUI } + '15' { UpdateOpenClaw } + '16' { UninstallOpenClaw } + '0' { break } + default { Warn "Invalid option"; Start-Sleep -Milliseconds 500 } } } From edcfa69d9790175420881e7ff3d0086077ec77ae Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 21:49:05 +0800 Subject: [PATCH 0891/1285] refactor: move windows openclaw manager files into windows/openclaw-manager --- .github/workflows/windows-openclaw-smoke.yml | 25 +++++++++++ .../README-Windows-OpenClaw.md | 0 .../openclaw-manager/install.ps1 | 4 +- .../openclaw-win-distribute.bat | 2 +- .../openclaw-manager/openclaw-win-manager.bat | 0 .../openclaw-manager/openclaw-win-manager.ps1 | 0 .../openclaw-manager/windows-smoke-test.ps1 | 44 +++++++++++++++++++ 7 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/windows-openclaw-smoke.yml rename README-Windows-OpenClaw.md => windows/openclaw-manager/README-Windows-OpenClaw.md (100%) rename install.ps1 => windows/openclaw-manager/install.ps1 (85%) rename openclaw-win-distribute.bat => windows/openclaw-manager/openclaw-win-distribute.bat (95%) rename openclaw-win-manager.bat => windows/openclaw-manager/openclaw-win-manager.bat (100%) rename openclaw-win-manager.ps1 => windows/openclaw-manager/openclaw-win-manager.ps1 (100%) create mode 100644 windows/openclaw-manager/windows-smoke-test.ps1 diff --git a/.github/workflows/windows-openclaw-smoke.yml b/.github/workflows/windows-openclaw-smoke.yml new file mode 100644 index 000000000..7a28b5bb7 --- /dev/null +++ b/.github/workflows/windows-openclaw-smoke.yml @@ -0,0 +1,25 @@ +name: windows-openclaw-smoke + +on: + workflow_dispatch: + push: + paths: + - 'windows/openclaw-manager/openclaw-win-manager.ps1' + - 'windows/openclaw-manager/openclaw-win-manager.bat' + - 'windows/openclaw-manager/openclaw-win-distribute.bat' + - 'windows/openclaw-manager/install.ps1' + - 'windows/openclaw-manager/windows-smoke-test.ps1' + - '.github/workflows/windows-openclaw-smoke.yml' + +jobs: + smoke: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run Windows smoke test + shell: pwsh + run: | + Set-ExecutionPolicy -Scope Process Bypass -Force + .\windows\openclaw-manager\windows-smoke-test.ps1 diff --git a/README-Windows-OpenClaw.md b/windows/openclaw-manager/README-Windows-OpenClaw.md similarity index 100% rename from README-Windows-OpenClaw.md rename to windows/openclaw-manager/README-Windows-OpenClaw.md diff --git a/install.ps1 b/windows/openclaw-manager/install.ps1 similarity index 85% rename from install.ps1 rename to windows/openclaw-manager/install.ps1 index 7cc069d0e..abd661622 100644 --- a/install.ps1 +++ b/windows/openclaw-manager/install.ps1 @@ -2,12 +2,12 @@ # Usage: # iwr -useb https://openclaw.ai/install.ps1 | iex # or -# irm https://raw.githubusercontent.com/kejilion/sh/main/install.ps1 | iex +# irm https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/install.ps1 | iex $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/openclaw-win-manager.ps1' +$managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1' $targetDir = Join-Path $env:ProgramData 'kejilion\openclaw' $targetFile = Join-Path $targetDir 'openclaw-win-manager.ps1' diff --git a/openclaw-win-distribute.bat b/windows/openclaw-manager/openclaw-win-distribute.bat similarity index 95% rename from openclaw-win-distribute.bat rename to windows/openclaw-manager/openclaw-win-distribute.bat index dc2638cc6..65dc7a259 100644 --- a/openclaw-win-distribute.bat +++ b/windows/openclaw-manager/openclaw-win-distribute.bat @@ -5,7 +5,7 @@ setlocal EnableDelayedExpansion REM OpenClaw Windows 一键分发版(单文件) REM 用法:双击即可,自动拉取最新版 openclaw-win-manager.ps1 再启动 -set "RAW_URL=https://raw.githubusercontent.com/kejilion/sh/main/openclaw-win-manager.ps1" +set "RAW_URL=https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1" set "TARGET=%TEMP%\openclaw-win-manager.ps1" where powershell >nul 2>nul diff --git a/openclaw-win-manager.bat b/windows/openclaw-manager/openclaw-win-manager.bat similarity index 100% rename from openclaw-win-manager.bat rename to windows/openclaw-manager/openclaw-win-manager.bat diff --git a/openclaw-win-manager.ps1 b/windows/openclaw-manager/openclaw-win-manager.ps1 similarity index 100% rename from openclaw-win-manager.ps1 rename to windows/openclaw-manager/openclaw-win-manager.ps1 diff --git a/windows/openclaw-manager/windows-smoke-test.ps1 b/windows/openclaw-manager/windows-smoke-test.ps1 new file mode 100644 index 000000000..321949231 --- /dev/null +++ b/windows/openclaw-manager/windows-smoke-test.ps1 @@ -0,0 +1,44 @@ +# Windows 本机快速冒烟测试(管理员 PowerShell) +$ErrorActionPreference = 'Stop' + +$root = (Split-Path -Parent $MyInvocation.MyCommand.Path) +$files = @( + (Join-Path $root 'openclaw-win-manager.ps1'), + (Join-Path $root 'openclaw-win-manager.bat'), + (Join-Path $root 'openclaw-win-distribute.bat'), + (Join-Path $root 'install.ps1') +) + +Write-Host "[1/4] 检查文件存在..." -ForegroundColor Cyan +foreach ($f in $files) { + if (!(Test-Path $f)) { throw "缺少文件: $f" } + Write-Host " OK $f" +} + +Write-Host "[2/4] 校验 PS1 语法..." -ForegroundColor Cyan +$null = [System.Management.Automation.Language.Parser]::ParseFile( + (Join-Path $root 'openclaw-win-manager.ps1'), + [ref]$null, + [ref]$null +) +Write-Host " OK openclaw-win-manager.ps1 语法通过" + +Write-Host "[3/4] 校验 install.ps1 语法..." -ForegroundColor Cyan +$null = [System.Management.Automation.Language.Parser]::ParseFile( + (Join-Path $root 'install.ps1'), + [ref]$null, + [ref]$null +) +Write-Host " OK install.ps1 语法通过" + +Write-Host "[4/4] 检查关键命令片段..." -ForegroundColor Cyan +$manager = Get-Content (Join-Path $root 'openclaw-win-manager.ps1') -Raw +$install = Get-Content (Join-Path $root 'install.ps1') -Raw + +if ($manager -notmatch 'openclaw gateway start') { throw '缺少 gateway start' } +if ($manager -notmatch 'openclaw gateway stop') { throw '缺少 gateway stop' } +if ($manager -notmatch 'openclaw models set') { throw '缺少 models set' } +if ($install -notmatch 'openclaw-win-manager.ps1') { throw 'install.ps1 未引用主管理脚本' } + +Write-Host " OK 关键命令片段通过" +Write-Host "\n✅ Windows 冒烟测试通过" -ForegroundColor Green From d50ee3d82fab335a5d8243caf252e8c558e7d434 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 21:54:04 +0800 Subject: [PATCH 0892/1285] feat: switch windows manager to Chinese UI with UTF-8 BOM --- windows/openclaw-manager/install.ps1 | 4 +- .../openclaw-manager/openclaw-win-manager.ps1 | 150 +++++++++--------- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/windows/openclaw-manager/install.ps1 b/windows/openclaw-manager/install.ps1 index abd661622..354728600 100644 --- a/windows/openclaw-manager/install.ps1 +++ b/windows/openclaw-manager/install.ps1 @@ -1,10 +1,12 @@ -# OpenClaw Windows one-liner installer/bootstrap +# OpenClaw Windows one-liner installer/bootstrap # Usage: # iwr -useb https://openclaw.ai/install.ps1 | iex # or # irm https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/install.ps1 | iex $ErrorActionPreference = 'Stop' +[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() +$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1' diff --git a/windows/openclaw-manager/openclaw-win-manager.ps1 b/windows/openclaw-manager/openclaw-win-manager.ps1 index 38f4ec1c9..703346083 100644 --- a/windows/openclaw-manager/openclaw-win-manager.ps1 +++ b/windows/openclaw-manager/openclaw-win-manager.ps1 @@ -1,34 +1,34 @@ -#requires -Version 5.1 +#requires -Version 5.1 <# -OpenClaw Windows 10/11 standalone manager (ASCII-safe for PowerShell 5.1) -Run: +OpenClaw Windows 10/11 独立管理脚本(中文版) +运行: Set-ExecutionPolicy -Scope Process Bypass -Force .\openclaw-win-manager.ps1 #> $ErrorActionPreference = 'Stop' -function Info($m){ Write-Host "[INFO] $m" -ForegroundColor Cyan } -function OK($m){ Write-Host "[ OK ] $m" -ForegroundColor Green } -function Warn($m){ Write-Host "[WARN] $m" -ForegroundColor Yellow } -function Err($m){ Write-Host "[ERR ] $m" -ForegroundColor Red } -function PauseBack { ""; Read-Host "Press Enter to continue" | Out-Null } +function Info($m){ Write-Host "[信息] $m" -ForegroundColor Cyan } +function OK($m){ Write-Host "[完成] $m" -ForegroundColor Green } +function Warn($m){ Write-Host "[警告] $m" -ForegroundColor Yellow } +function Err($m){ Write-Host "[错误] $m" -ForegroundColor Red } +function PauseBack { ""; Read-Host "按回车继续" | Out-Null } function HasCmd($n){ return [bool](Get-Command $n -ErrorAction SilentlyContinue) } function OC([string]$args){ try { Invoke-Expression "openclaw $args" } - catch { Err "openclaw $args failed"; Err $_.Exception.Message } + catch { Err "openclaw $args 执行失败"; Err $_.Exception.Message } } function ConfigPath { Join-Path $env:USERPROFILE ".openclaw\openclaw.json" } -function InstallStatus { if(HasCmd "openclaw"){"Installed"}else{"Not installed"} } +function InstallStatus { if(HasCmd "openclaw"){"已安装"}else{"未安装"} } function RunningStatus { try { $out = & openclaw gateway status 2>$null | Out-String - if($out -match 'running|online|active'){ return "Running" } + if($out -match 'running|online|active|运行'){ return "运行中" } } catch {} - return "Stopped" + return "未运行" } function LocalVersion { @@ -54,39 +54,39 @@ function ShowMenu { $run = RunningStatus $lv = LocalVersion $rv = LatestVersion - $verMsg = "Version unknown" + $verMsg = "版本未知" if($lv -and $rv){ - if($lv -ne $rv){ $verMsg = "Update available: $rv (current $lv)" } - else { $verMsg = "Latest: $lv" } + if($lv -ne $rv){ $verMsg = "可更新: $rv (当前 $lv)" } + else { $verMsg = "已是最新: $lv" } } Write-Host "===========================================" - Write-Host "OpenClaw Windows Manager" - Write-Host "Status: $ins | $run | $verMsg" + Write-Host "OpenClaw Windows 管理" + Write-Host "状态: $ins | $run | $verMsg" Write-Host "===========================================" - Write-Host "1. Install OpenClaw" - Write-Host "2. Start OpenClaw" - Write-Host "3. Stop OpenClaw" - Write-Host "4. Restart OpenClaw" - Write-Host "5. Status + Logs" - Write-Host "6. Switch model" - Write-Host "7. Add provider (auto models import)" - Write-Host "8. Pairing (Telegram/Feishu/WhatsApp)" - Write-Host "9. Install plugin" - Write-Host "10. Install skill (clawhub)" - Write-Host "11. Edit config file" - Write-Host "12. Run onboard" - Write-Host "13. Run doctor --fix" - Write-Host "14. Show WebUI URL" - Write-Host "15. Update OpenClaw" - Write-Host "16. Uninstall OpenClaw" - Write-Host "0. Exit" + Write-Host "1. 安装 OpenClaw" + Write-Host "2. 启动 OpenClaw" + Write-Host "3. 停止 OpenClaw" + Write-Host "4. 重启 OpenClaw" + Write-Host "5. 状态与日志" + Write-Host "6. 切换模型" + Write-Host "7. 添加 Provider(自动导入模型)" + Write-Host "8. 机器人配对(Telegram/飞书/WhatsApp)" + Write-Host "9. 安装插件" + Write-Host "10. 安装技能(clawhub)" + Write-Host "11. 编辑配置文件" + Write-Host "12. 执行 onboard" + Write-Host "13. 执行 doctor --fix" + Write-Host "14. 查看 WebUI 地址" + Write-Host "15. 更新 OpenClaw" + Write-Host "16. 卸载 OpenClaw" + Write-Host "0. 退出" Write-Host "-------------------------------------------" } function InstallNodeIfNeeded { - if(HasCmd "node"){ OK "Node.js found: $(& node -v)"; return } - Info "Node.js not found, trying auto-install" + if(HasCmd "node"){ OK "检测到 Node.js: $(& node -v)"; return } + Info "未检测到 Node.js,尝试自动安装" if(HasCmd "winget"){ & winget install --id OpenJS.NodeJS.LTS -e --accept-package-agreements --accept-source-agreements @@ -95,19 +95,19 @@ function InstallNodeIfNeeded { if(HasCmd "choco"){ & choco install nodejs-lts -y; return } if(HasCmd "scoop"){ & scoop install nodejs-lts; return } - throw "No winget/choco/scoop found. Install Node.js 20+ manually first." + throw "未检测到 winget/choco/scoop,请先手动安装 Node.js 20+" } function InstallOpenClaw { try { InstallNodeIfNeeded - if(-not (HasCmd "npm")){ throw "npm not found after Node install" } - Info "Installing openclaw..." + if(-not (HasCmd "npm")){ throw "npm 不可用" } + Info "正在安装 openclaw..." & npm install -g openclaw@latest - Info "Running onboard..." + Info "正在执行 onboard..." OC "onboard --install-daemon" OC "gateway restart" - OK "Install done" + OK "安装完成" } catch { Err $_.Exception.Message } PauseBack } @@ -128,14 +128,14 @@ function ShowStatusLogs { function SwitchModel { try { - Write-Host "`n--- all models ---" -ForegroundColor Magenta + Write-Host "`n--- 所有模型 ---" -ForegroundColor Magenta OC "models list --all" - Write-Host "`n--- current model ---" -ForegroundColor Magenta + Write-Host "`n--- 当前模型 ---" -ForegroundColor Magenta OC "models list" - $m = Read-Host "Target model (provider/model), 0 to cancel" + $m = Read-Host "输入目标模型(provider/model),输入0取消" if(-not $m -or $m -eq '0'){ return } OC "models set $m" - OK "Model switched: $m" + OK "模型已切换: $m" } catch { Err $_.Exception.Message } PauseBack } @@ -150,21 +150,21 @@ function ModelCost([string]$id){ function AddProvider { try { - $provider = Read-Host "Provider name" - if(-not $provider){ throw "Provider name is required" } - $base = Read-Host "Base URL (e.g. https://api.xxx.com/v1)" - if(-not $base){ throw "Base URL is required" } + $provider = Read-Host "输入 Provider 名称" + if(-not $provider){ throw "Provider 不能为空" } + $base = Read-Host "输入 Base URL(如 https://api.xxx.com/v1)" + if(-not $base){ throw "Base URL 不能为空" } $base = $base.TrimEnd('/') - $key = Read-Host "API key" - if(-not $key){ throw "API key is required" } + $key = Read-Host "输入 API Key" + if(-not $key){ throw "API Key 不能为空" } - Info "Fetching models from $base/models ..." + Info "正在获取模型列表: $base/models" $resp = Invoke-RestMethod -Uri "$base/models" -Headers @{Authorization="Bearer $key"} -TimeoutSec 30 $ids = @($resp.data | ForEach-Object { $_.id } | Where-Object { $_ } | Sort-Object -Unique) - if($ids.Count -eq 0){ throw "No models found" } + if($ids.Count -eq 0){ throw "未获取到模型" } for($i=0;$i -lt $ids.Count;$i++){ Write-Host "[$($i+1)] $($ids[$i])" } - $pick = Read-Host "Default model (index or id, blank=first)" + $pick = Read-Host "输入默认模型(序号或ID,留空=第一个)" $default = $ids[0] if($pick){ if($pick -match '^\d+$'){ @@ -174,7 +174,7 @@ function AddProvider { } $cfg = ConfigPath - if(-not (Test-Path $cfg)){ throw "Config not found: $cfg. Run onboard first." } + if(-not (Test-Path $cfg)){ throw "配置不存在: $cfg,请先执行 onboard" } Copy-Item $cfg "$cfg.bak.$([DateTimeOffset]::Now.ToUnixTimeSeconds())" -Force $json = Get-Content $cfg -Raw | ConvertFrom-Json @@ -205,7 +205,7 @@ function AddProvider { $json | ConvertTo-Json -Depth 20 | Set-Content -Path $cfg -Encoding UTF8 OC "models set $provider/$default" OC "gateway restart" - OK "Provider added: $provider, default model: $provider/$default" + OK "Provider 添加完成,默认模型: $provider/$default" } catch { Err $_.Exception.Message } PauseBack } @@ -213,18 +213,18 @@ function AddProvider { function PairingMenu { while($true){ Clear-Host - Write-Host "=== Pairing ===" + Write-Host "=== 机器人配对 ===" Write-Host "1. Telegram" - Write-Host "2. Feishu/Lark" + Write-Host "2. 飞书" Write-Host "3. WhatsApp" - Write-Host "0. Back" - $c = Read-Host "Select" + Write-Host "0. 返回" + $c = Read-Host "请选择" switch($c){ - '1' { $code=Read-Host "Telegram code"; if($code){ OC "pairing approve telegram $code"; PauseBack } } - '2' { $code=Read-Host "Feishu code"; if($code){ OC "pairing approve feishu $code"; PauseBack } } - '3' { $code=Read-Host "WhatsApp code"; if($code){ OC "pairing approve whatsapp $code"; PauseBack } } + '1' { $code=Read-Host "输入 Telegram 连接码"; if($code){ OC "pairing approve telegram $code"; PauseBack } } + '2' { $code=Read-Host "输入飞书连接码"; if($code){ OC "pairing approve feishu $code"; PauseBack } } + '3' { $code=Read-Host "输入 WhatsApp 连接码"; if($code){ OC "pairing approve whatsapp $code"; PauseBack } } '0' { return } - default { Warn "Invalid"; Start-Sleep -Milliseconds 600 } + default { Warn "无效选项"; Start-Sleep -Milliseconds 600 } } } } @@ -232,14 +232,14 @@ function PairingMenu { function InstallPlugin { try { OC "plugins list" - $p = Read-Host "Plugin id (e.g. telegram/feishu/@openclaw/discord), 0 cancel" + $p = Read-Host "输入插件ID(如 telegram/feishu/@openclaw/discord),0取消" if(-not $p -or $p -eq '0'){ return } $id = $p -replace '^@openclaw/','' OC "plugins enable $id" OC "plugins install $p" OC "plugins enable $id" OC "gateway restart" - OK "Plugin processed: $p" + OK "插件处理完成: $p" } catch { Err $_.Exception.Message } PauseBack } @@ -247,21 +247,21 @@ function InstallPlugin { function InstallSkill { try { OC "skills list" - $s = Read-Host "Skill name, 0 cancel" + $s = Read-Host "输入技能名,0取消" if(-not $s -or $s -eq '0'){ return } - if(-not (HasCmd "npx")){ throw "npx not found" } + if(-not (HasCmd "npx")){ throw "npx 不可用" } & npx clawhub install $s OC "gateway restart" - OK "Skill installed: $s" + OK "技能安装完成: $s" } catch { Err $_.Exception.Message } PauseBack } function EditConfig { $p = ConfigPath - if(-not (Test-Path $p)){ Warn "Config not found: $p"; PauseBack; return } + if(-not (Test-Path $p)){ Warn "配置不存在: $p"; PauseBack; return } notepad $p - Info "Restart gateway to apply changes" + Info "如已修改配置,请重启网关生效" PauseBack } @@ -287,7 +287,7 @@ function UpdateOpenClaw { InstallNodeIfNeeded & npm install -g openclaw@latest OC "gateway restart" - OK "Update done" + OK "更新完成" } catch { Err $_.Exception.Message } PauseBack } @@ -296,14 +296,14 @@ function UninstallOpenClaw { try { OC "uninstall" if(HasCmd "npm"){ & npm uninstall -g openclaw } - OK "Uninstalled" + OK "卸载完成" } catch { Err $_.Exception.Message } PauseBack } while($true){ ShowMenu - $c = Read-Host "Select" + $c = Read-Host "请选择" switch($c){ '1' { InstallOpenClaw } '2' { StartOpenClaw } @@ -322,6 +322,6 @@ while($true){ '15' { UpdateOpenClaw } '16' { UninstallOpenClaw } '0' { break } - default { Warn "Invalid option"; Start-Sleep -Milliseconds 500 } + default { Warn "无效选项"; Start-Sleep -Milliseconds 500 } } } From e5de2a7fd87cec428c8f5f093024ca6d4943c849 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 21:56:58 +0800 Subject: [PATCH 0893/1285] fix: force fresh manager download and verify Chinese build in installer --- windows/openclaw-manager/install.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/windows/openclaw-manager/install.ps1 b/windows/openclaw-manager/install.ps1 index 354728600..a4bca9cc5 100644 --- a/windows/openclaw-manager/install.ps1 +++ b/windows/openclaw-manager/install.ps1 @@ -10,6 +10,7 @@ $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1' +$managerUrl = "$managerUrl?ts=$([DateTimeOffset]::Now.ToUnixTimeSeconds())" $targetDir = Join-Path $env:ProgramData 'kejilion\openclaw' $targetFile = Join-Path $targetDir 'openclaw-win-manager.ps1' @@ -23,5 +24,10 @@ if ((Get-Item $targetFile).Length -lt 2000) { throw 'Downloaded file is too small, abort.' } +$raw = Get-Content -Path $targetFile -Raw +if ($raw -notmatch 'OpenClaw Windows 管理') { + throw 'Downloaded manager is not the latest Chinese build, abort.' +} + Write-Host '[INFO] Starting OpenClaw Windows Manager...' -ForegroundColor Cyan powershell -NoProfile -ExecutionPolicy Bypass -File $targetFile From 22717776e0d55d9953af7fa4706ac68839eac4a9 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 3 Mar 2026 22:02:17 +0800 Subject: [PATCH 0894/1285] fix: installer ASCII-safe + node/npm PATH refresh after winget install --- windows/openclaw-manager/install.ps1 | 10 ++----- .../openclaw-manager/openclaw-win-manager.ps1 | 29 +++++++++++++++---- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/windows/openclaw-manager/install.ps1 b/windows/openclaw-manager/install.ps1 index a4bca9cc5..c91b408c2 100644 --- a/windows/openclaw-manager/install.ps1 +++ b/windows/openclaw-manager/install.ps1 @@ -1,12 +1,8 @@ -# OpenClaw Windows one-liner installer/bootstrap +# OpenClaw Windows bootstrap (ASCII-safe) # Usage: -# iwr -useb https://openclaw.ai/install.ps1 | iex -# or -# irm https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/install.ps1 | iex +# Set-ExecutionPolicy -Scope Process Bypass -Force; iwr -useb https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/install.ps1 | iex $ErrorActionPreference = 'Stop' -[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() -$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1' @@ -18,7 +14,7 @@ Write-Host '[INFO] Preparing directories...' -ForegroundColor Cyan New-Item -ItemType Directory -Path $targetDir -Force | Out-Null Write-Host '[INFO] Downloading latest manager script...' -ForegroundColor Cyan -Invoke-WebRequest -UseBasicParsing -Uri $managerUrl -OutFile $targetFile +Invoke-WebRequest -UseBasicParsing -Headers @{ 'Cache-Control'='no-cache' } -Uri $managerUrl -OutFile $targetFile if ((Get-Item $targetFile).Length -lt 2000) { throw 'Downloaded file is too small, abort.' diff --git a/windows/openclaw-manager/openclaw-win-manager.ps1 b/windows/openclaw-manager/openclaw-win-manager.ps1 index 703346083..37da2c8d8 100644 --- a/windows/openclaw-manager/openclaw-win-manager.ps1 +++ b/windows/openclaw-manager/openclaw-win-manager.ps1 @@ -1,4 +1,5 @@ #requires -Version 5.1 +# OPENCLAW_WIN_MANAGER_CN_V2 <# OpenClaw Windows 10/11 独立管理脚本(中文版) 运行: @@ -85,17 +86,33 @@ function ShowMenu { } function InstallNodeIfNeeded { - if(HasCmd "node"){ OK "检测到 Node.js: $(& node -v)"; return } - Info "未检测到 Node.js,尝试自动安装" + if(HasCmd "node" -and HasCmd "npm"){ OK "检测到 Node.js: $(& node -v)"; return } + Info "未检测到 Node.js/npm,尝试自动安装" if(HasCmd "winget"){ & winget install --id OpenJS.NodeJS.LTS -e --accept-package-agreements --accept-source-agreements - return } - if(HasCmd "choco"){ & choco install nodejs-lts -y; return } - if(HasCmd "scoop"){ & scoop install nodejs-lts; return } + elseif(HasCmd "choco"){ & choco install nodejs-lts -y } + elseif(HasCmd "scoop"){ & scoop install nodejs-lts } + else { throw "未检测到 winget/choco/scoop,请先手动安装 Node.js 20+" } + + # 刷新当前会话 PATH(winget 安装后常见 npm 不在当前会话 PATH) + $machinePath = [Environment]::GetEnvironmentVariable('Path','Machine') + $userPath = [Environment]::GetEnvironmentVariable('Path','User') + $env:Path = "$machinePath;$userPath" + + $extra = @('C:\Program Files\nodejs','C:\Program Files (x86)\nodejs') + foreach($e in $extra){ + if((Test-Path $e) -and ($env:Path -notlike "*$e*")) { $env:Path += ";$e" } + } - throw "未检测到 winget/choco/scoop,请先手动安装 Node.js 20+" + if(-not (HasCmd "npm")){ + Warn "已安装 Node.js,但当前会话未找到 npm。将尝试直接使用 npm.cmd。" + $npmCmd = 'C:\Program Files\nodejs\npm.cmd' + if(Test-Path $npmCmd){ + Set-Alias -Name npm -Value $npmCmd -Scope Script + } + } } function InstallOpenClaw { From 0867ec1dfa02f9816f6573e84a9edc3691828fb8 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 4 Mar 2026 11:57:16 +0800 Subject: [PATCH 0895/1285] chore: remove windows/openclaw-manager test folder --- .../README-Windows-OpenClaw.md | 36 -- windows/openclaw-manager/install.ps1 | 29 -- .../openclaw-win-distribute.bat | 35 -- .../openclaw-manager/openclaw-win-manager.bat | 33 -- .../openclaw-manager/openclaw-win-manager.ps1 | 344 ------------------ .../openclaw-manager/windows-smoke-test.ps1 | 44 --- 6 files changed, 521 deletions(-) delete mode 100644 windows/openclaw-manager/README-Windows-OpenClaw.md delete mode 100644 windows/openclaw-manager/install.ps1 delete mode 100644 windows/openclaw-manager/openclaw-win-distribute.bat delete mode 100644 windows/openclaw-manager/openclaw-win-manager.bat delete mode 100644 windows/openclaw-manager/openclaw-win-manager.ps1 delete mode 100644 windows/openclaw-manager/windows-smoke-test.ps1 diff --git a/windows/openclaw-manager/README-Windows-OpenClaw.md b/windows/openclaw-manager/README-Windows-OpenClaw.md deleted file mode 100644 index d4982192a..000000000 --- a/windows/openclaw-manager/README-Windows-OpenClaw.md +++ /dev/null @@ -1,36 +0,0 @@ -# OpenClaw Windows 10/11 独立管理脚本(快捷使用) - -## 文件 -- `openclaw-win-manager.ps1`:主脚本 -- `openclaw-win-manager.bat`:一键启动器(推荐) - -## 一键使用(推荐) -1. 右键 `openclaw-win-manager.bat`,选择**以管理员身份运行**。 -2. 进入交互菜单后,按数字操作: - - `1` 安装 OpenClaw - - `2/3/4` 启动/停止/重启 - - `5` 查看状态与日志 - - `6` 切换模型 - -## 首次安装建议顺序 -1. `1` 安装 OpenClaw -2. `12` 配置向导(onboard) -3. `2` 启动 OpenClaw -4. `5` 检查状态日志 - -## 常见问题 -### 1) 提示执行策略限制 -已在 `.bat` 内自动使用: -`-ExecutionPolicy Bypass` - -### 2) 提示找不到 Node.js -脚本会尝试自动用 `winget/choco/scoop` 安装 Node.js。 -如果都没有,请先手动安装 Node.js 20+。 - -### 3) 修改配置后不生效 -在菜单中执行 `4`(重启)或 `2` 启动前先 `3` 停止。 - -## 安全建议 -- 仅在可信机器运行。 -- API Key 建议最小权限。 -- 定期用菜单 `13` 执行 `doctor --fix`。 diff --git a/windows/openclaw-manager/install.ps1 b/windows/openclaw-manager/install.ps1 deleted file mode 100644 index c91b408c2..000000000 --- a/windows/openclaw-manager/install.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -# OpenClaw Windows bootstrap (ASCII-safe) -# Usage: -# Set-ExecutionPolicy -Scope Process Bypass -Force; iwr -useb https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/install.ps1 | iex - -$ErrorActionPreference = 'Stop' -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - -$managerUrl = 'https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1' -$managerUrl = "$managerUrl?ts=$([DateTimeOffset]::Now.ToUnixTimeSeconds())" -$targetDir = Join-Path $env:ProgramData 'kejilion\openclaw' -$targetFile = Join-Path $targetDir 'openclaw-win-manager.ps1' - -Write-Host '[INFO] Preparing directories...' -ForegroundColor Cyan -New-Item -ItemType Directory -Path $targetDir -Force | Out-Null - -Write-Host '[INFO] Downloading latest manager script...' -ForegroundColor Cyan -Invoke-WebRequest -UseBasicParsing -Headers @{ 'Cache-Control'='no-cache' } -Uri $managerUrl -OutFile $targetFile - -if ((Get-Item $targetFile).Length -lt 2000) { - throw 'Downloaded file is too small, abort.' -} - -$raw = Get-Content -Path $targetFile -Raw -if ($raw -notmatch 'OpenClaw Windows 管理') { - throw 'Downloaded manager is not the latest Chinese build, abort.' -} - -Write-Host '[INFO] Starting OpenClaw Windows Manager...' -ForegroundColor Cyan -powershell -NoProfile -ExecutionPolicy Bypass -File $targetFile diff --git a/windows/openclaw-manager/openclaw-win-distribute.bat b/windows/openclaw-manager/openclaw-win-distribute.bat deleted file mode 100644 index 65dc7a259..000000000 --- a/windows/openclaw-manager/openclaw-win-distribute.bat +++ /dev/null @@ -1,35 +0,0 @@ -@echo off -chcp 65001 >nul -setlocal EnableDelayedExpansion - -REM OpenClaw Windows 一键分发版(单文件) -REM 用法:双击即可,自动拉取最新版 openclaw-win-manager.ps1 再启动 - -set "RAW_URL=https://raw.githubusercontent.com/kejilion/sh/main/windows/openclaw-manager/openclaw-win-manager.ps1" -set "TARGET=%TEMP%\openclaw-win-manager.ps1" - -where powershell >nul 2>nul -if errorlevel 1 ( - echo [ERROR] 未检测到 PowerShell - pause - exit /b 1 -) - -echo [INFO] 正在下载最新版管理脚本... -powershell -NoProfile -ExecutionPolicy Bypass -Command "try { iwr -UseBasicParsing '%RAW_URL%' -OutFile '%TARGET%'; if ((Get-Item '%TARGET%').Length -lt 2000) { throw 'download too small' } } catch { Write-Host '[ERROR] 下载失败:' $_.Exception.Message; exit 1 }" -if errorlevel 1 ( - echo [ERROR] 下载失败,请检查网络或 RAW_URL。 - pause - exit /b 1 -) - -echo [INFO] 启动 OpenClaw Windows Manager... -powershell -NoProfile -ExecutionPolicy Bypass -File "%TARGET%" - -if errorlevel 1 ( - echo. - echo [WARN] 脚本退出代码: %errorlevel% -) - -pause -endlocal diff --git a/windows/openclaw-manager/openclaw-win-manager.bat b/windows/openclaw-manager/openclaw-win-manager.bat deleted file mode 100644 index 2479ce74d..000000000 --- a/windows/openclaw-manager/openclaw-win-manager.bat +++ /dev/null @@ -1,33 +0,0 @@ -@echo off -chcp 65001 >nul -setlocal - -REM OpenClaw Windows Manager 一键启动器 -REM 放在与 openclaw-win-manager.ps1 同目录 - -set "SCRIPT_DIR=%~dp0" -set "PS1=%SCRIPT_DIR%openclaw-win-manager.ps1" - -if not exist "%PS1%" ( - echo [ERROR] 未找到脚本: %PS1% - pause - exit /b 1 -) - -where powershell >nul 2>nul -if errorlevel 1 ( - echo [ERROR] 未检测到 PowerShell - pause - exit /b 1 -) - -echo [INFO] 正在启动 OpenClaw Windows 管理脚本... -powershell -NoProfile -ExecutionPolicy Bypass -File "%PS1%" - -if errorlevel 1 ( - echo. - echo [WARN] 脚本退出代码: %errorlevel% -) - -pause -endlocal diff --git a/windows/openclaw-manager/openclaw-win-manager.ps1 b/windows/openclaw-manager/openclaw-win-manager.ps1 deleted file mode 100644 index 37da2c8d8..000000000 --- a/windows/openclaw-manager/openclaw-win-manager.ps1 +++ /dev/null @@ -1,344 +0,0 @@ -#requires -Version 5.1 -# OPENCLAW_WIN_MANAGER_CN_V2 -<# -OpenClaw Windows 10/11 独立管理脚本(中文版) -运行: - Set-ExecutionPolicy -Scope Process Bypass -Force - .\openclaw-win-manager.ps1 -#> - -$ErrorActionPreference = 'Stop' - -function Info($m){ Write-Host "[信息] $m" -ForegroundColor Cyan } -function OK($m){ Write-Host "[完成] $m" -ForegroundColor Green } -function Warn($m){ Write-Host "[警告] $m" -ForegroundColor Yellow } -function Err($m){ Write-Host "[错误] $m" -ForegroundColor Red } -function PauseBack { ""; Read-Host "按回车继续" | Out-Null } - -function HasCmd($n){ return [bool](Get-Command $n -ErrorAction SilentlyContinue) } -function OC([string]$args){ - try { Invoke-Expression "openclaw $args" } - catch { Err "openclaw $args 执行失败"; Err $_.Exception.Message } -} - -function ConfigPath { Join-Path $env:USERPROFILE ".openclaw\openclaw.json" } - -function InstallStatus { if(HasCmd "openclaw"){"已安装"}else{"未安装"} } -function RunningStatus { - try { - $out = & openclaw gateway status 2>$null | Out-String - if($out -match 'running|online|active|运行'){ return "运行中" } - } catch {} - return "未运行" -} - -function LocalVersion { - try { - $t = (& npm list -g openclaw --depth=0 --no-update-notifier 2>$null | Out-String) - $m = [regex]::Match($t,'openclaw@([0-9A-Za-z\.-]+)') - if($m.Success){ return $m.Groups[1].Value } - } catch {} - return $null -} - -function LatestVersion { - try { - $v = (& npm view openclaw version --no-update-notifier 2>$null).Trim() - if($v){ return $v } - } catch {} - return $null -} - -function ShowMenu { - Clear-Host - $ins = InstallStatus - $run = RunningStatus - $lv = LocalVersion - $rv = LatestVersion - $verMsg = "版本未知" - if($lv -and $rv){ - if($lv -ne $rv){ $verMsg = "可更新: $rv (当前 $lv)" } - else { $verMsg = "已是最新: $lv" } - } - - Write-Host "===========================================" - Write-Host "OpenClaw Windows 管理" - Write-Host "状态: $ins | $run | $verMsg" - Write-Host "===========================================" - Write-Host "1. 安装 OpenClaw" - Write-Host "2. 启动 OpenClaw" - Write-Host "3. 停止 OpenClaw" - Write-Host "4. 重启 OpenClaw" - Write-Host "5. 状态与日志" - Write-Host "6. 切换模型" - Write-Host "7. 添加 Provider(自动导入模型)" - Write-Host "8. 机器人配对(Telegram/飞书/WhatsApp)" - Write-Host "9. 安装插件" - Write-Host "10. 安装技能(clawhub)" - Write-Host "11. 编辑配置文件" - Write-Host "12. 执行 onboard" - Write-Host "13. 执行 doctor --fix" - Write-Host "14. 查看 WebUI 地址" - Write-Host "15. 更新 OpenClaw" - Write-Host "16. 卸载 OpenClaw" - Write-Host "0. 退出" - Write-Host "-------------------------------------------" -} - -function InstallNodeIfNeeded { - if(HasCmd "node" -and HasCmd "npm"){ OK "检测到 Node.js: $(& node -v)"; return } - Info "未检测到 Node.js/npm,尝试自动安装" - - if(HasCmd "winget"){ - & winget install --id OpenJS.NodeJS.LTS -e --accept-package-agreements --accept-source-agreements - } - elseif(HasCmd "choco"){ & choco install nodejs-lts -y } - elseif(HasCmd "scoop"){ & scoop install nodejs-lts } - else { throw "未检测到 winget/choco/scoop,请先手动安装 Node.js 20+" } - - # 刷新当前会话 PATH(winget 安装后常见 npm 不在当前会话 PATH) - $machinePath = [Environment]::GetEnvironmentVariable('Path','Machine') - $userPath = [Environment]::GetEnvironmentVariable('Path','User') - $env:Path = "$machinePath;$userPath" - - $extra = @('C:\Program Files\nodejs','C:\Program Files (x86)\nodejs') - foreach($e in $extra){ - if((Test-Path $e) -and ($env:Path -notlike "*$e*")) { $env:Path += ";$e" } - } - - if(-not (HasCmd "npm")){ - Warn "已安装 Node.js,但当前会话未找到 npm。将尝试直接使用 npm.cmd。" - $npmCmd = 'C:\Program Files\nodejs\npm.cmd' - if(Test-Path $npmCmd){ - Set-Alias -Name npm -Value $npmCmd -Scope Script - } - } -} - -function InstallOpenClaw { - try { - InstallNodeIfNeeded - if(-not (HasCmd "npm")){ throw "npm 不可用" } - Info "正在安装 openclaw..." - & npm install -g openclaw@latest - Info "正在执行 onboard..." - OC "onboard --install-daemon" - OC "gateway restart" - OK "安装完成" - } catch { Err $_.Exception.Message } - PauseBack -} - -function StartOpenClaw { OC "gateway start"; PauseBack } -function StopOpenClaw { OC "gateway stop"; PauseBack } -function RestartOpenClaw { OC "gateway restart"; PauseBack } - -function ShowStatusLogs { - Write-Host "`n=== openclaw status ===" -ForegroundColor Magenta - OC "status" - Write-Host "`n=== gateway status ===" -ForegroundColor Magenta - OC "gateway status" - Write-Host "`n=== openclaw logs ===" -ForegroundColor Magenta - OC "logs" - PauseBack -} - -function SwitchModel { - try { - Write-Host "`n--- 所有模型 ---" -ForegroundColor Magenta - OC "models list --all" - Write-Host "`n--- 当前模型 ---" -ForegroundColor Magenta - OC "models list" - $m = Read-Host "输入目标模型(provider/model),输入0取消" - if(-not $m -or $m -eq '0'){ return } - OC "models set $m" - OK "模型已切换: $m" - } catch { Err $_.Exception.Message } - PauseBack -} - -function ModelCost([string]$id){ - $in=0.15; $out=0.60 - if($id -match 'opus|pro|preview|thinking|sonnet'){ $in=2.00; $out=12.00 } - elseif($id -match 'gpt-5|codex'){ $in=1.25; $out=10.00 } - elseif($id -match 'flash|lite|haiku|mini|nano'){ $in=0.10; $out=0.40 } - return @{ input=$in; output=$out; cacheRead=0; cacheWrite=0 } -} - -function AddProvider { - try { - $provider = Read-Host "输入 Provider 名称" - if(-not $provider){ throw "Provider 不能为空" } - $base = Read-Host "输入 Base URL(如 https://api.xxx.com/v1)" - if(-not $base){ throw "Base URL 不能为空" } - $base = $base.TrimEnd('/') - $key = Read-Host "输入 API Key" - if(-not $key){ throw "API Key 不能为空" } - - Info "正在获取模型列表: $base/models" - $resp = Invoke-RestMethod -Uri "$base/models" -Headers @{Authorization="Bearer $key"} -TimeoutSec 30 - $ids = @($resp.data | ForEach-Object { $_.id } | Where-Object { $_ } | Sort-Object -Unique) - if($ids.Count -eq 0){ throw "未获取到模型" } - - for($i=0;$i -lt $ids.Count;$i++){ Write-Host "[$($i+1)] $($ids[$i])" } - $pick = Read-Host "输入默认模型(序号或ID,留空=第一个)" - $default = $ids[0] - if($pick){ - if($pick -match '^\d+$'){ - $ix=[int]$pick-1 - if($ix -ge 0 -and $ix -lt $ids.Count){ $default=$ids[$ix] } - } else { $default = $pick } - } - - $cfg = ConfigPath - if(-not (Test-Path $cfg)){ throw "配置不存在: $cfg,请先执行 onboard" } - - Copy-Item $cfg "$cfg.bak.$([DateTimeOffset]::Now.ToUnixTimeSeconds())" -Force - $json = Get-Content $cfg -Raw | ConvertFrom-Json - - if(-not $json.models){ $json | Add-Member -NotePropertyName models -NotePropertyValue (@{}) } - $json.models.mode = 'merge' - if(-not $json.models.providers){ $json.models | Add-Member -NotePropertyName providers -NotePropertyValue (@{}) } - - $models = @() - foreach($id in $ids){ - $models += [pscustomobject]@{ - id=$id - name="$provider / $id" - input=@('text','image') - contextWindow=1048576 - maxTokens=128000 - cost=(ModelCost $id) - } - } - - $json.models.providers.$provider = [pscustomobject]@{ - baseUrl=$base - apiKey=$key - api='openai-completions' - models=$models - } - - $json | ConvertTo-Json -Depth 20 | Set-Content -Path $cfg -Encoding UTF8 - OC "models set $provider/$default" - OC "gateway restart" - OK "Provider 添加完成,默认模型: $provider/$default" - } catch { Err $_.Exception.Message } - PauseBack -} - -function PairingMenu { - while($true){ - Clear-Host - Write-Host "=== 机器人配对 ===" - Write-Host "1. Telegram" - Write-Host "2. 飞书" - Write-Host "3. WhatsApp" - Write-Host "0. 返回" - $c = Read-Host "请选择" - switch($c){ - '1' { $code=Read-Host "输入 Telegram 连接码"; if($code){ OC "pairing approve telegram $code"; PauseBack } } - '2' { $code=Read-Host "输入飞书连接码"; if($code){ OC "pairing approve feishu $code"; PauseBack } } - '3' { $code=Read-Host "输入 WhatsApp 连接码"; if($code){ OC "pairing approve whatsapp $code"; PauseBack } } - '0' { return } - default { Warn "无效选项"; Start-Sleep -Milliseconds 600 } - } - } -} - -function InstallPlugin { - try { - OC "plugins list" - $p = Read-Host "输入插件ID(如 telegram/feishu/@openclaw/discord),0取消" - if(-not $p -or $p -eq '0'){ return } - $id = $p -replace '^@openclaw/','' - OC "plugins enable $id" - OC "plugins install $p" - OC "plugins enable $id" - OC "gateway restart" - OK "插件处理完成: $p" - } catch { Err $_.Exception.Message } - PauseBack -} - -function InstallSkill { - try { - OC "skills list" - $s = Read-Host "输入技能名,0取消" - if(-not $s -or $s -eq '0'){ return } - if(-not (HasCmd "npx")){ throw "npx 不可用" } - & npx clawhub install $s - OC "gateway restart" - OK "技能安装完成: $s" - } catch { Err $_.Exception.Message } - PauseBack -} - -function EditConfig { - $p = ConfigPath - if(-not (Test-Path $p)){ Warn "配置不存在: $p"; PauseBack; return } - notepad $p - Info "如已修改配置,请重启网关生效" - PauseBack -} - -function RunOnboard { OC "onboard --install-daemon"; PauseBack } -function RunDoctor { OC "doctor --fix"; PauseBack } - -function ShowWebUI { - try { - $o = (& openclaw dashboard 2>$null | Out-String) - $m = [regex]::Match($o,'#token=([a-f0-9]+)') - if($m.Success){ - $t = $m.Groups[1].Value - Write-Host "http://127.0.0.1:18789/#token=$t" -ForegroundColor Green - } else { - Write-Host $o - } - } catch { Err $_.Exception.Message } - PauseBack -} - -function UpdateOpenClaw { - try { - InstallNodeIfNeeded - & npm install -g openclaw@latest - OC "gateway restart" - OK "更新完成" - } catch { Err $_.Exception.Message } - PauseBack -} - -function UninstallOpenClaw { - try { - OC "uninstall" - if(HasCmd "npm"){ & npm uninstall -g openclaw } - OK "卸载完成" - } catch { Err $_.Exception.Message } - PauseBack -} - -while($true){ - ShowMenu - $c = Read-Host "请选择" - switch($c){ - '1' { InstallOpenClaw } - '2' { StartOpenClaw } - '3' { StopOpenClaw } - '4' { RestartOpenClaw } - '5' { ShowStatusLogs } - '6' { SwitchModel } - '7' { AddProvider } - '8' { PairingMenu } - '9' { InstallPlugin } - '10' { InstallSkill } - '11' { EditConfig } - '12' { RunOnboard } - '13' { RunDoctor } - '14' { ShowWebUI } - '15' { UpdateOpenClaw } - '16' { UninstallOpenClaw } - '0' { break } - default { Warn "无效选项"; Start-Sleep -Milliseconds 500 } - } -} diff --git a/windows/openclaw-manager/windows-smoke-test.ps1 b/windows/openclaw-manager/windows-smoke-test.ps1 deleted file mode 100644 index 321949231..000000000 --- a/windows/openclaw-manager/windows-smoke-test.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -# Windows 本机快速冒烟测试(管理员 PowerShell) -$ErrorActionPreference = 'Stop' - -$root = (Split-Path -Parent $MyInvocation.MyCommand.Path) -$files = @( - (Join-Path $root 'openclaw-win-manager.ps1'), - (Join-Path $root 'openclaw-win-manager.bat'), - (Join-Path $root 'openclaw-win-distribute.bat'), - (Join-Path $root 'install.ps1') -) - -Write-Host "[1/4] 检查文件存在..." -ForegroundColor Cyan -foreach ($f in $files) { - if (!(Test-Path $f)) { throw "缺少文件: $f" } - Write-Host " OK $f" -} - -Write-Host "[2/4] 校验 PS1 语法..." -ForegroundColor Cyan -$null = [System.Management.Automation.Language.Parser]::ParseFile( - (Join-Path $root 'openclaw-win-manager.ps1'), - [ref]$null, - [ref]$null -) -Write-Host " OK openclaw-win-manager.ps1 语法通过" - -Write-Host "[3/4] 校验 install.ps1 语法..." -ForegroundColor Cyan -$null = [System.Management.Automation.Language.Parser]::ParseFile( - (Join-Path $root 'install.ps1'), - [ref]$null, - [ref]$null -) -Write-Host " OK install.ps1 语法通过" - -Write-Host "[4/4] 检查关键命令片段..." -ForegroundColor Cyan -$manager = Get-Content (Join-Path $root 'openclaw-win-manager.ps1') -Raw -$install = Get-Content (Join-Path $root 'install.ps1') -Raw - -if ($manager -notmatch 'openclaw gateway start') { throw '缺少 gateway start' } -if ($manager -notmatch 'openclaw gateway stop') { throw '缺少 gateway stop' } -if ($manager -notmatch 'openclaw models set') { throw '缺少 models set' } -if ($install -notmatch 'openclaw-win-manager.ps1') { throw 'install.ps1 未引用主管理脚本' } - -Write-Host " OK 关键命令片段通过" -Write-Host "\n✅ Windows 冒烟测试通过" -ForegroundColor Green From ce0f53544d4f5172256ad014413e89825a8b6858 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 4 Mar 2026 11:57:25 +0800 Subject: [PATCH 0896/1285] chore: remove obsolete windows openclaw smoke workflow --- .github/workflows/windows-openclaw-smoke.yml | 25 -------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/windows-openclaw-smoke.yml diff --git a/.github/workflows/windows-openclaw-smoke.yml b/.github/workflows/windows-openclaw-smoke.yml deleted file mode 100644 index 7a28b5bb7..000000000 --- a/.github/workflows/windows-openclaw-smoke.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: windows-openclaw-smoke - -on: - workflow_dispatch: - push: - paths: - - 'windows/openclaw-manager/openclaw-win-manager.ps1' - - 'windows/openclaw-manager/openclaw-win-manager.bat' - - 'windows/openclaw-manager/openclaw-win-distribute.bat' - - 'windows/openclaw-manager/install.ps1' - - 'windows/openclaw-manager/windows-smoke-test.ps1' - - '.github/workflows/windows-openclaw-smoke.yml' - -jobs: - smoke: - runs-on: windows-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Run Windows smoke test - shell: pwsh - run: | - Set-ExecutionPolicy -Scope Process Bypass -Force - .\windows\openclaw-manager\windows-smoke-test.ps1 From 93c8bca8c779119b751a758f37161146b257eb80 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 4 Mar 2026 12:15:11 +0800 Subject: [PATCH 0897/1285] feat: add OpenClaw version-aware update with selectable recent releases --- cn/kejilion.sh | 153 +++++++++++++++++++++++++++++++++++++++++-------- kejilion.sh | 153 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 260 insertions(+), 46 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 20b595b43..284d22f39 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9820,31 +9820,87 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" - check_openclaw_update() { + get_openclaw_current_version() { + local version="" + + if command -v openclaw >/dev/null 2>&1; then + version=$(openclaw --version 2>/dev/null | head -n 1 | sed -E 's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)?).*/\1/') + fi + + if [ -z "$version" ] && command -v npm >/dev/null 2>&1; then + version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep "openclaw@" | tail -n 1 | sed 's/^.*openclaw@//') + fi + + echo "$version" + } + + get_openclaw_latest_and_recent_versions() { + OPENCLAW_LATEST_VERSION="" + OPENCLAW_RECENT_VERSIONS="" + OPENCLAW_VERSION_QUERY_ERROR="" + if ! command -v npm >/dev/null 2>&1; then + OPENCLAW_VERSION_QUERY_ERROR="未检测到 npm,无法查询 OpenClaw 版本" return 1 fi - # 加上 --no-update-notifier,并确保错误重定向位置正确 - local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + local latest_version versions_json recent_versions - if [ -z "$local_version" ]; then - return 1 + latest_version=$(npm view openclaw version --no-update-notifier 2>/dev/null | tr -d '\r') + if [ -n "$latest_version" ]; then + OPENCLAW_LATEST_VERSION="$latest_version" fi - remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + versions_json=$(npm view openclaw versions --json --no-update-notifier 2>/dev/null) + recent_versions=$(echo "$versions_json" | tr -d '[]" ' | tr ',' '\n' | sed '/^$/d' | tail -n 10 | awk '{a[NR]=$0} END{for(i=NR;i>=1;i--) print a[i]}') - if [ -z "$remote_version" ]; then + if [ -z "$recent_versions" ] && [ -n "$latest_version" ]; then + recent_versions="$latest_version" + OPENCLAW_VERSION_QUERY_ERROR="最近 10 个版本获取失败,已仅提供最新版本,请稍后重试" + elif [ -z "$recent_versions" ]; then + OPENCLAW_VERSION_QUERY_ERROR="版本信息获取失败,请稍后重试" return 1 fi - if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" + OPENCLAW_RECENT_VERSIONS="$recent_versions" + return 0 + } + + check_openclaw_update() { + local current_version latest_version + current_version=$(get_openclaw_current_version) + get_openclaw_latest_and_recent_versions >/dev/null 2>&1 + latest_version="$OPENCLAW_LATEST_VERSION" + + [ -z "$current_version" ] && current_version="未安装" + [ -z "$latest_version" ] && latest_version="未知" + + if [ "$current_version" = "$latest_version" ] && [ "$current_version" != "未安装" ] && [ "$current_version" != "未知" ]; then + echo "${gl_lv}当前版本:$current_version | 最新版本:$latest_version (已最新)${gl_bai}" + return 0 + fi + + if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then + echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version (${OPENCLAW_VERSION_QUERY_ERROR})${gl_bai}" else - echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" + echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version${gl_bai}" fi } + install_openclaw_version() { + local target_version="$1" + [ -z "$target_version" ] && target_version="latest" + + if ! npm install -g "openclaw@${target_version}"; then + return 1 + fi + + openclaw onboard --install-daemon + start_gateway + hash -r + return 0 + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then @@ -9932,14 +9988,16 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi - npm install -g openclaw@latest - openclaw onboard --install-daemon - start_gateway - add_app_id - break_end - } + if install_openclaw_version "latest"; then + add_app_id + echo "安装完成" + else + echo "安装失败,请检查网络或 npm 环境后重试" + fi + break_end + } start_bot() { echo "启动 OpenClaw..." @@ -10499,16 +10557,65 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - npm install -g openclaw@latest - crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - start_gateway - hash -r - add_app_id - echo "更新完成" + + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + npm config set registry https://registry.npmmirror.com + fi + + local current_version selected_version latest_version pick + current_version=$(get_openclaw_current_version) + [ -z "$current_version" ] && current_version="未安装" + + get_openclaw_latest_and_recent_versions + latest_version="$OPENCLAW_LATEST_VERSION" + [ -z "$latest_version" ] && latest_version="latest" + + echo "当前版本: $current_version" + echo "最新版本: $latest_version" + echo "----------------------------------------" + echo "最近 10 个版本(输入编号安装/降级,留空默认最新):" + + declare -A openclaw_version_map + local i=1 + if [ -n "$OPENCLAW_RECENT_VERSIONS" ]; then + while read -r v; do + [ -z "$v" ] && continue + echo "$i) $v" + openclaw_version_map[$i]="$v" + i=$((i + 1)) + done <<< "$OPENCLAW_RECENT_VERSIONS" + else + echo "1) $latest_version" + openclaw_version_map[1]="$latest_version" + fi + + if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then + echo "⚠️ $OPENCLAW_VERSION_QUERY_ERROR" + fi + + read -erp "请输入编号(1-10,直接回车=最新):" pick + if [[ -n "$pick" && "$pick" =~ ^[0-9]+$ && -n "${openclaw_version_map[$pick]}" ]]; then + selected_version="${openclaw_version_map[$pick]}" + elif [ -n "$pick" ]; then + echo "输入无效,已按最新版本处理。" + selected_version="$latest_version" + else + selected_version="$latest_version" + fi + + echo "即将安装版本: $selected_version" + if install_openclaw_version "$selected_version"; then + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + add_app_id + echo "更新完成" + else + echo "更新失败,请检查网络或 npm 环境后重试" + fi + break_end } - uninstall_moltbot() { echo "卸载 OpenClaw..." send_stats "卸载 OpenClaw..." diff --git a/kejilion.sh b/kejilion.sh index 6c26d340f..0a43b13f6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9820,31 +9820,87 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" - check_openclaw_update() { + get_openclaw_current_version() { + local version="" + + if command -v openclaw >/dev/null 2>&1; then + version=$(openclaw --version 2>/dev/null | head -n 1 | sed -E 's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)?).*/\1/') + fi + + if [ -z "$version" ] && command -v npm >/dev/null 2>&1; then + version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep "openclaw@" | tail -n 1 | sed 's/^.*openclaw@//') + fi + + echo "$version" + } + + get_openclaw_latest_and_recent_versions() { + OPENCLAW_LATEST_VERSION="" + OPENCLAW_RECENT_VERSIONS="" + OPENCLAW_VERSION_QUERY_ERROR="" + if ! command -v npm >/dev/null 2>&1; then + OPENCLAW_VERSION_QUERY_ERROR="未检测到 npm,无法查询 OpenClaw 版本" return 1 fi - # 加上 --no-update-notifier,并确保错误重定向位置正确 - local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') + local latest_version versions_json recent_versions - if [ -z "$local_version" ]; then - return 1 + latest_version=$(npm view openclaw version --no-update-notifier 2>/dev/null | tr -d '\r') + if [ -n "$latest_version" ]; then + OPENCLAW_LATEST_VERSION="$latest_version" fi - remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) + versions_json=$(npm view openclaw versions --json --no-update-notifier 2>/dev/null) + recent_versions=$(echo "$versions_json" | tr -d '[]" ' | tr ',' '\n' | sed '/^$/d' | tail -n 10 | awk '{a[NR]=$0} END{for(i=NR;i>=1;i--) print a[i]}') - if [ -z "$remote_version" ]; then + if [ -z "$recent_versions" ] && [ -n "$latest_version" ]; then + recent_versions="$latest_version" + OPENCLAW_VERSION_QUERY_ERROR="最近 10 个版本获取失败,已仅提供最新版本,请稍后重试" + elif [ -z "$recent_versions" ]; then + OPENCLAW_VERSION_QUERY_ERROR="版本信息获取失败,请稍后重试" return 1 fi - if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" + OPENCLAW_RECENT_VERSIONS="$recent_versions" + return 0 + } + + check_openclaw_update() { + local current_version latest_version + current_version=$(get_openclaw_current_version) + get_openclaw_latest_and_recent_versions >/dev/null 2>&1 + latest_version="$OPENCLAW_LATEST_VERSION" + + [ -z "$current_version" ] && current_version="未安装" + [ -z "$latest_version" ] && latest_version="未知" + + if [ "$current_version" = "$latest_version" ] && [ "$current_version" != "未安装" ] && [ "$current_version" != "未知" ]; then + echo "${gl_lv}当前版本:$current_version | 最新版本:$latest_version (已最新)${gl_bai}" + return 0 + fi + + if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then + echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version (${OPENCLAW_VERSION_QUERY_ERROR})${gl_bai}" else - echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" + echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version${gl_bai}" fi } + install_openclaw_version() { + local target_version="$1" + [ -z "$target_version" ] && target_version="latest" + + if ! npm install -g "openclaw@${target_version}"; then + return 1 + fi + + openclaw onboard --install-daemon + start_gateway + hash -r + return 0 + } + get_install_status() { if command -v openclaw >/dev/null 2>&1; then @@ -9932,14 +9988,16 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi - npm install -g openclaw@latest - openclaw onboard --install-daemon - start_gateway - add_app_id - break_end - } + if install_openclaw_version "latest"; then + add_app_id + echo "安装完成" + else + echo "安装失败,请检查网络或 npm 环境后重试" + fi + break_end + } start_bot() { echo "启动 OpenClaw..." @@ -10499,16 +10557,65 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - npm install -g openclaw@latest - crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - start_gateway - hash -r - add_app_id - echo "更新完成" + + country=$(curl -s ipinfo.io/country) + if [[ "$country" == "CN" || "$country" == "HK" ]]; then + npm config set registry https://registry.npmmirror.com + fi + + local current_version selected_version latest_version pick + current_version=$(get_openclaw_current_version) + [ -z "$current_version" ] && current_version="未安装" + + get_openclaw_latest_and_recent_versions + latest_version="$OPENCLAW_LATEST_VERSION" + [ -z "$latest_version" ] && latest_version="latest" + + echo "当前版本: $current_version" + echo "最新版本: $latest_version" + echo "----------------------------------------" + echo "最近 10 个版本(输入编号安装/降级,留空默认最新):" + + declare -A openclaw_version_map + local i=1 + if [ -n "$OPENCLAW_RECENT_VERSIONS" ]; then + while read -r v; do + [ -z "$v" ] && continue + echo "$i) $v" + openclaw_version_map[$i]="$v" + i=$((i + 1)) + done <<< "$OPENCLAW_RECENT_VERSIONS" + else + echo "1) $latest_version" + openclaw_version_map[1]="$latest_version" + fi + + if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then + echo "⚠️ $OPENCLAW_VERSION_QUERY_ERROR" + fi + + read -erp "请输入编号(1-10,直接回车=最新):" pick + if [[ -n "$pick" && "$pick" =~ ^[0-9]+$ && -n "${openclaw_version_map[$pick]}" ]]; then + selected_version="${openclaw_version_map[$pick]}" + elif [ -n "$pick" ]; then + echo "输入无效,已按最新版本处理。" + selected_version="$latest_version" + else + selected_version="$latest_version" + fi + + echo "即将安装版本: $selected_version" + if install_openclaw_version "$selected_version"; then + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + add_app_id + echo "更新完成" + else + echo "更新失败,请检查网络或 npm 环境后重试" + fi + break_end } - uninstall_moltbot() { echo "卸载 OpenClaw..." send_stats "卸载 OpenClaw..." From b91b001f6e4351a6643f243c699ba17cb5842a1f Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 4 Mar 2026 12:23:22 +0800 Subject: [PATCH 0898/1285] Revert "feat: add OpenClaw version-aware update with selectable recent releases" This reverts commit 93c8bca8c779119b751a758f37161146b257eb80. --- cn/kejilion.sh | 153 ++++++++----------------------------------------- kejilion.sh | 153 ++++++++----------------------------------------- 2 files changed, 46 insertions(+), 260 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 284d22f39..20b595b43 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9820,87 +9820,31 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" - get_openclaw_current_version() { - local version="" - - if command -v openclaw >/dev/null 2>&1; then - version=$(openclaw --version 2>/dev/null | head -n 1 | sed -E 's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)?).*/\1/') - fi - - if [ -z "$version" ] && command -v npm >/dev/null 2>&1; then - version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep "openclaw@" | tail -n 1 | sed 's/^.*openclaw@//') - fi - - echo "$version" - } - - get_openclaw_latest_and_recent_versions() { - OPENCLAW_LATEST_VERSION="" - OPENCLAW_RECENT_VERSIONS="" - OPENCLAW_VERSION_QUERY_ERROR="" - + check_openclaw_update() { if ! command -v npm >/dev/null 2>&1; then - OPENCLAW_VERSION_QUERY_ERROR="未检测到 npm,无法查询 OpenClaw 版本" return 1 fi - local latest_version versions_json recent_versions - - latest_version=$(npm view openclaw version --no-update-notifier 2>/dev/null | tr -d '\r') - if [ -n "$latest_version" ]; then - OPENCLAW_LATEST_VERSION="$latest_version" - fi - - versions_json=$(npm view openclaw versions --json --no-update-notifier 2>/dev/null) - recent_versions=$(echo "$versions_json" | tr -d '[]" ' | tr ',' '\n' | sed '/^$/d' | tail -n 10 | awk '{a[NR]=$0} END{for(i=NR;i>=1;i--) print a[i]}') + # 加上 --no-update-notifier,并确保错误重定向位置正确 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') - if [ -z "$recent_versions" ] && [ -n "$latest_version" ]; then - recent_versions="$latest_version" - OPENCLAW_VERSION_QUERY_ERROR="最近 10 个版本获取失败,已仅提供最新版本,请稍后重试" - elif [ -z "$recent_versions" ]; then - OPENCLAW_VERSION_QUERY_ERROR="版本信息获取失败,请稍后重试" + if [ -z "$local_version" ]; then return 1 fi - OPENCLAW_RECENT_VERSIONS="$recent_versions" - return 0 - } + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) - check_openclaw_update() { - local current_version latest_version - current_version=$(get_openclaw_current_version) - get_openclaw_latest_and_recent_versions >/dev/null 2>&1 - latest_version="$OPENCLAW_LATEST_VERSION" - - [ -z "$current_version" ] && current_version="未安装" - [ -z "$latest_version" ] && latest_version="未知" - - if [ "$current_version" = "$latest_version" ] && [ "$current_version" != "未安装" ] && [ "$current_version" != "未知" ]; then - echo "${gl_lv}当前版本:$current_version | 最新版本:$latest_version (已最新)${gl_bai}" - return 0 + if [ -z "$remote_version" ]; then + return 1 fi - if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then - echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version (${OPENCLAW_VERSION_QUERY_ERROR})${gl_bai}" + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } - install_openclaw_version() { - local target_version="$1" - [ -z "$target_version" ] && target_version="latest" - - if ! npm install -g "openclaw@${target_version}"; then - return 1 - fi - - openclaw onboard --install-daemon - start_gateway - hash -r - return 0 - } - get_install_status() { if command -v openclaw >/dev/null 2>&1; then @@ -9988,17 +9932,15 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi - - if install_openclaw_version "latest"; then - add_app_id - echo "安装完成" - else - echo "安装失败,请检查网络或 npm 环境后重试" - fi - + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway + add_app_id break_end + } + start_bot() { echo "启动 OpenClaw..." send_stats "启动 OpenClaw..." @@ -10557,65 +10499,16 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - - country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" || "$country" == "HK" ]]; then - npm config set registry https://registry.npmmirror.com - fi - - local current_version selected_version latest_version pick - current_version=$(get_openclaw_current_version) - [ -z "$current_version" ] && current_version="未安装" - - get_openclaw_latest_and_recent_versions - latest_version="$OPENCLAW_LATEST_VERSION" - [ -z "$latest_version" ] && latest_version="latest" - - echo "当前版本: $current_version" - echo "最新版本: $latest_version" - echo "----------------------------------------" - echo "最近 10 个版本(输入编号安装/降级,留空默认最新):" - - declare -A openclaw_version_map - local i=1 - if [ -n "$OPENCLAW_RECENT_VERSIONS" ]; then - while read -r v; do - [ -z "$v" ] && continue - echo "$i) $v" - openclaw_version_map[$i]="$v" - i=$((i + 1)) - done <<< "$OPENCLAW_RECENT_VERSIONS" - else - echo "1) $latest_version" - openclaw_version_map[1]="$latest_version" - fi - - if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then - echo "⚠️ $OPENCLAW_VERSION_QUERY_ERROR" - fi - - read -erp "请输入编号(1-10,直接回车=最新):" pick - if [[ -n "$pick" && "$pick" =~ ^[0-9]+$ && -n "${openclaw_version_map[$pick]}" ]]; then - selected_version="${openclaw_version_map[$pick]}" - elif [ -n "$pick" ]; then - echo "输入无效,已按最新版本处理。" - selected_version="$latest_version" - else - selected_version="$latest_version" - fi - - echo "即将安装版本: $selected_version" - if install_openclaw_version "$selected_version"; then - crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - add_app_id - echo "更新完成" - else - echo "更新失败,请检查网络或 npm 环境后重试" - fi - + npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + start_gateway + hash -r + add_app_id + echo "更新完成" break_end } + uninstall_moltbot() { echo "卸载 OpenClaw..." send_stats "卸载 OpenClaw..." diff --git a/kejilion.sh b/kejilion.sh index 0a43b13f6..6c26d340f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9820,87 +9820,31 @@ moltbot_menu() { send_stats "clawdbot/moltbot管理" - get_openclaw_current_version() { - local version="" - - if command -v openclaw >/dev/null 2>&1; then - version=$(openclaw --version 2>/dev/null | head -n 1 | sed -E 's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)?).*/\1/') - fi - - if [ -z "$version" ] && command -v npm >/dev/null 2>&1; then - version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep "openclaw@" | tail -n 1 | sed 's/^.*openclaw@//') - fi - - echo "$version" - } - - get_openclaw_latest_and_recent_versions() { - OPENCLAW_LATEST_VERSION="" - OPENCLAW_RECENT_VERSIONS="" - OPENCLAW_VERSION_QUERY_ERROR="" - + check_openclaw_update() { if ! command -v npm >/dev/null 2>&1; then - OPENCLAW_VERSION_QUERY_ERROR="未检测到 npm,无法查询 OpenClaw 版本" return 1 fi - local latest_version versions_json recent_versions - - latest_version=$(npm view openclaw version --no-update-notifier 2>/dev/null | tr -d '\r') - if [ -n "$latest_version" ]; then - OPENCLAW_LATEST_VERSION="$latest_version" - fi - - versions_json=$(npm view openclaw versions --json --no-update-notifier 2>/dev/null) - recent_versions=$(echo "$versions_json" | tr -d '[]" ' | tr ',' '\n' | sed '/^$/d' | tail -n 10 | awk '{a[NR]=$0} END{for(i=NR;i>=1;i--) print a[i]}') + # 加上 --no-update-notifier,并确保错误重定向位置正确 + local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') - if [ -z "$recent_versions" ] && [ -n "$latest_version" ]; then - recent_versions="$latest_version" - OPENCLAW_VERSION_QUERY_ERROR="最近 10 个版本获取失败,已仅提供最新版本,请稍后重试" - elif [ -z "$recent_versions" ]; then - OPENCLAW_VERSION_QUERY_ERROR="版本信息获取失败,请稍后重试" + if [ -z "$local_version" ]; then return 1 fi - OPENCLAW_RECENT_VERSIONS="$recent_versions" - return 0 - } + remote_version=$(npm view openclaw version --no-update-notifier 2>/dev/null) - check_openclaw_update() { - local current_version latest_version - current_version=$(get_openclaw_current_version) - get_openclaw_latest_and_recent_versions >/dev/null 2>&1 - latest_version="$OPENCLAW_LATEST_VERSION" - - [ -z "$current_version" ] && current_version="未安装" - [ -z "$latest_version" ] && latest_version="未知" - - if [ "$current_version" = "$latest_version" ] && [ "$current_version" != "未安装" ] && [ "$current_version" != "未知" ]; then - echo "${gl_lv}当前版本:$current_version | 最新版本:$latest_version (已最新)${gl_bai}" - return 0 + if [ -z "$remote_version" ]; then + return 1 fi - if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then - echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version (${OPENCLAW_VERSION_QUERY_ERROR})${gl_bai}" + if [ "$local_version" != "$remote_version" ]; then + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_huang}当前版本:$current_version | 最新版本:$latest_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } - install_openclaw_version() { - local target_version="$1" - [ -z "$target_version" ] && target_version="latest" - - if ! npm install -g "openclaw@${target_version}"; then - return 1 - fi - - openclaw onboard --install-daemon - start_gateway - hash -r - return 0 - } - get_install_status() { if command -v openclaw >/dev/null 2>&1; then @@ -9988,17 +9932,15 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi - - if install_openclaw_version "latest"; then - add_app_id - echo "安装完成" - else - echo "安装失败,请检查网络或 npm 环境后重试" - fi - + npm install -g openclaw@latest + openclaw onboard --install-daemon + start_gateway + add_app_id break_end + } + start_bot() { echo "启动 OpenClaw..." send_stats "启动 OpenClaw..." @@ -10557,65 +10499,16 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - - country=$(curl -s ipinfo.io/country) - if [[ "$country" == "CN" || "$country" == "HK" ]]; then - npm config set registry https://registry.npmmirror.com - fi - - local current_version selected_version latest_version pick - current_version=$(get_openclaw_current_version) - [ -z "$current_version" ] && current_version="未安装" - - get_openclaw_latest_and_recent_versions - latest_version="$OPENCLAW_LATEST_VERSION" - [ -z "$latest_version" ] && latest_version="latest" - - echo "当前版本: $current_version" - echo "最新版本: $latest_version" - echo "----------------------------------------" - echo "最近 10 个版本(输入编号安装/降级,留空默认最新):" - - declare -A openclaw_version_map - local i=1 - if [ -n "$OPENCLAW_RECENT_VERSIONS" ]; then - while read -r v; do - [ -z "$v" ] && continue - echo "$i) $v" - openclaw_version_map[$i]="$v" - i=$((i + 1)) - done <<< "$OPENCLAW_RECENT_VERSIONS" - else - echo "1) $latest_version" - openclaw_version_map[1]="$latest_version" - fi - - if [ -n "$OPENCLAW_VERSION_QUERY_ERROR" ]; then - echo "⚠️ $OPENCLAW_VERSION_QUERY_ERROR" - fi - - read -erp "请输入编号(1-10,直接回车=最新):" pick - if [[ -n "$pick" && "$pick" =~ ^[0-9]+$ && -n "${openclaw_version_map[$pick]}" ]]; then - selected_version="${openclaw_version_map[$pick]}" - elif [ -n "$pick" ]; then - echo "输入无效,已按最新版本处理。" - selected_version="$latest_version" - else - selected_version="$latest_version" - fi - - echo "即将安装版本: $selected_version" - if install_openclaw_version "$selected_version"; then - crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - add_app_id - echo "更新完成" - else - echo "更新失败,请检查网络或 npm 环境后重试" - fi - + npm install -g openclaw@latest + crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + start_gateway + hash -r + add_app_id + echo "更新完成" break_end } + uninstall_moltbot() { echo "卸载 OpenClaw..." send_stats "卸载 OpenClaw..." From 2a4d4d5d8a55184812d778775f83359838f99e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:11:04 +0800 Subject: [PATCH 0899/1285] Update npm registry and modify allowedOrigins logic --- cn/kejilion.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 20b595b43..4570443e9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9932,6 +9932,9 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global --unset url."git@github.com:".insteadOf + npm install -g openclaw@latest openclaw onboard --install-daemon start_gateway @@ -10602,6 +10605,7 @@ EOF config_file="$HOME/.openclaw/openclaw.json" if [ -f "$config_file" ]; then new_origin="https://${yuming}" + # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" From 587639e145a407393f59ed45ac310e6bd7eb5575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:12:21 +0800 Subject: [PATCH 0900/1285] Remove git config setting for GitHub URL --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 6c26d340f..ceb4df09e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9932,6 +9932,9 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global --unset url."git@github.com:".insteadOf + npm install -g openclaw@latest openclaw onboard --install-daemon start_gateway From fabc51f504108b503e4e1e4cecb5c7e4721af304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:13:50 +0800 Subject: [PATCH 0901/1285] Improve compatibility for domestic installation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化国内环境安装时的兼容性。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index da6cd583f..125d96a6d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1466,5 +1466,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 ------------------------ 2026-03-03 v4.4.2 应用市场中OpenClaw管理 WebUI访问设置功能修复绑定域名不出现设备ID的问题。 +应用市场中OpenClaw管理 优化国内环境安装时的兼容性。 ------------------------ From 685f214f77323fcf56d4d8a04eed01e92ac04a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:14:49 +0800 Subject: [PATCH 0902/1285] Fix and optimize OpenClaw management WebUI settings --- kejilion_sh_log.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 125d96a6d..afc97a755 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1465,7 +1465,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场对ClawdBot/Moltbot机器人项目新增飞书和WhatsApp机器人扫码对接功能。 ------------------------ 2026-03-03 v4.4.2 -应用市场中OpenClaw管理 WebUI访问设置功能修复绑定域名不出现设备ID的问题。 -应用市场中OpenClaw管理 优化国内环境安装时的兼容性。 +应用市场中OpenClaw管理,WebUI访问设置功能修复绑定域名不出现设备ID的问题。 +应用市场中OpenClaw管理,优化国内环境安装时的兼容性。 ------------------------ From 131da440e0fdf35fd58ab980a68d0b9068b02f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:59:38 +0800 Subject: [PATCH 0903/1285] Uninstall OpenClaw and remove related files Remove OpenClaw files and clean up related configurations. --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4570443e9..6051ca348 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10518,6 +10518,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" From 6ba022b8ad9be5475c9ab43bf037033bdfda72ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:00:12 +0800 Subject: [PATCH 0904/1285] Add removal of OpenClaw directory on uninstall Remove OpenClaw files during uninstallation process. --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index ceb4df09e..7b3db4b66 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10518,6 +10518,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" From 9c5ca7769877850c31814c17f0de6650fd1474cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:01:43 +0800 Subject: [PATCH 0905/1285] Fix uninstallation issues in OpenClaw management Fix issue with residual configuration directory after uninstallation. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index afc97a755..2d5af2321 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1467,5 +1467,6 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-03-03 v4.4.2 应用市场中OpenClaw管理,WebUI访问设置功能修复绑定域名不出现设备ID的问题。 应用市场中OpenClaw管理,优化国内环境安装时的兼容性。 +应用市场中OpenClaw管理,修复卸载后配置目录残留的问题,卸载不彻底的问题。 ------------------------ From 53201e797a12344d5b16523e6e113860aeee6780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:23:08 +0800 Subject: [PATCH 0906/1285] Update version to 4.4.3 and adjust menu options --- cn/kejilion.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6051ca348..8c849f8af 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.2" +sh_v="4.4.3" gl_hui='\e[37m' @@ -9890,9 +9890,10 @@ moltbot_menu() { echo "11. 配置向导" echo "12. 健康检测与修复" echo "13. WebUI访问与设置" + echo "14. TUI命令行对话窗口" echo "--------------------" - echo "14. 更新" - echo "15. 卸载" + echo "15. 更新" + echo "16. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10695,6 +10696,10 @@ EOF break_end ;; 13) openclaw_webui_menu ;; + 12) send_stats "TUI命令行对话" + openclaw tui + break_end + ;; 14) update_moltbot ;; 15) uninstall_moltbot ;; *) break ;; From 4337cd57518c34b5b20314cdf19530908d5ce822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:23:57 +0800 Subject: [PATCH 0907/1285] Update version and menu options in kejilion.sh --- kejilion.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7b3db4b66..7d06cdbad 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.2" +sh_v="4.4.3" gl_hui='\e[37m' @@ -9890,9 +9890,10 @@ moltbot_menu() { echo "11. 配置向导" echo "12. 健康检测与修复" echo "13. WebUI访问与设置" + echo "14. TUI命令行对话窗口" echo "--------------------" - echo "14. 更新" - echo "15. 卸载" + echo "15. 更新" + echo "16. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10695,6 +10696,10 @@ EOF break_end ;; 13) openclaw_webui_menu ;; + 12) send_stats "TUI命令行对话" + openclaw tui + break_end + ;; 14) update_moltbot ;; 15) uninstall_moltbot ;; *) break ;; From f9e4ff0f4832fef42562413a0b80e2613e829f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:24:37 +0800 Subject: [PATCH 0908/1285] Fix command numbering and update flow control --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 7d06cdbad..146c27b61 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10696,12 +10696,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 12) send_stats "TUI命令行对话" + 14) send_stats "TUI命令行对话" openclaw tui break_end ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done From ca52b493f6c0a668742e3ccbf04bcf96c6aa758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:25:19 +0800 Subject: [PATCH 0909/1285] Reorder case statements and fix conditional block --- cn/kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8c849f8af..9a1215899 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10696,12 +10696,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 12) send_stats "TUI命令行对话" + 14) send_stats "TUI命令行对话" openclaw tui break_end ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done From e59120905ee1ce7aa5c553feac150446e758403b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:27:05 +0800 Subject: [PATCH 0910/1285] Add TUI terminal command line chat window Added a new TUI terminal command line chat window for debugging tasks in OpenClaw management. --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2d5af2321..b527537af 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1469,4 +1469,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场中OpenClaw管理,优化国内环境安装时的兼容性。 应用市场中OpenClaw管理,修复卸载后配置目录残留的问题,卸载不彻底的问题。 ------------------------ +2026-03-06 v4.4.3 +应用市场中OpenClaw管理,新增TUI终端命令行聊天窗口,临时调试任务执行更方面。 +------------------------ + From dabb0c5502c532e06de00d1f024fd9516e5b8d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:59:58 +0800 Subject: [PATCH 0911/1285] Update git config for GitHub HTTPS URLs --- cn/kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9a1215899..37f44166a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9934,10 +9934,12 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi - git config --global --unset url."git@github.com:".insteadOf + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end From 61b05fc6c6cba5f62b66e70e6ab1d1ba0197beef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:00:21 +0800 Subject: [PATCH 0912/1285] Update git config commands and modify openclaw profile --- kejilion.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 146c27b61..608f96ce0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9934,10 +9934,12 @@ moltbot_menu() { npm config set registry https://registry.npmmirror.com fi - git config --global --unset url."git@github.com:".insteadOf + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end From 1ca7125d0c10dea9a9e4a684df7be267c5c65b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:01:51 +0800 Subject: [PATCH 0913/1285] Enhance OpenClaw with automatic permission adjustment Added automatic permission adjustment for OpenClaw after installation. --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index b527537af..5f9bc1318 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1471,6 +1471,7 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 ------------------------ 2026-03-06 v4.4.3 应用市场中OpenClaw管理,新增TUI终端命令行聊天窗口,临时调试任务执行更方面。 +应用市场中OpenClaw管理,安装后自动调整权限为full,可以调用内部程序自动化。 ------------------------ From 3c114d7fdff3eb2c0f0a04b163ad176f76a446d5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 18:35:09 +0800 Subject: [PATCH 0914/1285] feat(fail2ban): add basic bantime/findtime/maxretry config + nano edit option --- cn/kejilion.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ kejilion.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 37f44166a..a342757d6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3213,6 +3213,67 @@ f2b_sshd() { fi } +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) +# 说明: +# - 优先写入 /etc/fail2ban/jail.d/sshd.local(覆盖默认 jail 配置,升级不易丢) +# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}未检测到 fail2ban-client,请先安装 fail2ban。${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -q 'Alpine' /etc/issue 2>/dev/null; then + jail_name="alpine-sshd" + fi + + echo "即将配置 SSH jail:$jail_name" + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime + read -e -p "时间窗口 findtime (秒/分钟/小时,如 600 或 10m) [默认 10m]: " findtime + read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local </dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# 直接打开主配置/覆盖配置编辑(nano) +# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}已保存${gl_bai},正在 reload fail2ban..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -14838,6 +14899,9 @@ fail2ban_panel() { echo "2. 查看SSH拦截记录" echo "3. 日志实时监控" echo "------------------------" + echo "4. 基础参数配置(封禁时长/时间窗口/重试次数)" + echo "5. 编辑配置文件(nano)" + echo "------------------------" echo "9. 卸载防御程序" echo "------------------------" echo "0. 返回上一级选单" @@ -14860,6 +14924,14 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + f2b_basic_config + break_end + ;; + 5) + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban diff --git a/kejilion.sh b/kejilion.sh index 608f96ce0..7ddefd39e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3213,6 +3213,67 @@ f2b_sshd() { fi } +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) +# 说明: +# - 优先写入 /etc/fail2ban/jail.d/sshd.local(覆盖默认 jail 配置,升级不易丢) +# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}未检测到 fail2ban-client,请先安装 fail2ban。${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -q 'Alpine' /etc/issue 2>/dev/null; then + jail_name="alpine-sshd" + fi + + echo "即将配置 SSH jail:$jail_name" + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime + read -e -p "时间窗口 findtime (秒/分钟/小时,如 600 或 10m) [默认 10m]: " findtime + read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local </dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# 直接打开主配置/覆盖配置编辑(nano) +# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}已保存${gl_bai},正在 reload fail2ban..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -14838,6 +14899,9 @@ fail2ban_panel() { echo "2. 查看SSH拦截记录" echo "3. 日志实时监控" echo "------------------------" + echo "4. 基础参数配置(封禁时长/时间窗口/重试次数)" + echo "5. 编辑配置文件(nano)" + echo "------------------------" echo "9. 卸载防御程序" echo "------------------------" echo "0. 返回上一级选单" @@ -14860,6 +14924,14 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + f2b_basic_config + break_end + ;; + 5) + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban From 7689c53e71eef229250810c39bca0923e9c49464 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 18:52:51 +0800 Subject: [PATCH 0915/1285] fix(fail2ban): enable sshd jail in generated sshd.local --- cn/kejilion.sh | 2 ++ kejilion.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a342757d6..335aa8688 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3244,6 +3244,8 @@ f2b_basic_config() { cat > /etc/fail2ban/jail.d/sshd.local < /etc/fail2ban/jail.d/sshd.local < Date: Sat, 7 Mar 2026 18:55:17 +0800 Subject: [PATCH 0916/1285] fix(fail2ban): improve Alpine jail detection; add auth.log logpath for Debian/Ubuntu --- cn/kejilion.sh | 15 +++++++++++++-- kejilion.sh | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 335aa8688..f03b72e09 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3227,8 +3227,11 @@ f2b_basic_config() { fi local jail_name="sshd" - if grep -q 'Alpine' /etc/issue 2>/dev/null; then - jail_name="alpine-sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi fi echo "即将配置 SSH jail:$jail_name" @@ -3251,6 +3254,14 @@ findtime = $findtime maxretry = $maxretry EOF + # Ensure a logfile exists for sshd jail on Debian/Ubuntu minimal images + # (without it, fail2ban-server may refuse to start) + if [ "$jail_name" = "sshd" ]; then + if [ -f /etc/fail2ban/jail.d/sshd.local ]; then + grep -qE '^\s*logpath\s*=' /etc/fail2ban/jail.d/sshd.local || echo 'logpath = /var/log/auth.log' >> /etc/fail2ban/jail.d/sshd.local + fi + fi + echo -e "${gl_lv}已写入配置${gl_bai}: /etc/fail2ban/jail.d/sshd.local" fail2ban-client reload >/dev/null 2>&1 || true sleep 2 diff --git a/kejilion.sh b/kejilion.sh index 856e08729..8e3d56885 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3227,8 +3227,11 @@ f2b_basic_config() { fi local jail_name="sshd" - if grep -q 'Alpine' /etc/issue 2>/dev/null; then - jail_name="alpine-sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi fi echo "即将配置 SSH jail:$jail_name" @@ -3251,6 +3254,14 @@ findtime = $findtime maxretry = $maxretry EOF + # Ensure a logfile exists for sshd jail on Debian/Ubuntu minimal images + # (without it, fail2ban-server may refuse to start) + if [ "$jail_name" = "sshd" ]; then + if [ -f /etc/fail2ban/jail.d/sshd.local ]; then + grep -qE '^\s*logpath\s*=' /etc/fail2ban/jail.d/sshd.local || echo 'logpath = /var/log/auth.log' >> /etc/fail2ban/jail.d/sshd.local + fi + fi + echo -e "${gl_lv}已写入配置${gl_bai}: /etc/fail2ban/jail.d/sshd.local" fail2ban-client reload >/dev/null 2>&1 || true sleep 2 From 2ceca0991ed13ebfe39909a650d6dcf006d907ad Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 20:33:53 +0800 Subject: [PATCH 0917/1285] feat(fail2ban): add send_stats for new config options --- cn/kejilion.sh | 2 ++ kejilion.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f03b72e09..acc27fa2c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14938,10 +14938,12 @@ fail2ban_panel() { break ;; 4) + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; 5) + send_stats "SSH防御编辑配置文件" f2b_edit_config break_end ;; diff --git a/kejilion.sh b/kejilion.sh index 8e3d56885..2166f2257 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14938,10 +14938,12 @@ fail2ban_panel() { break ;; 4) + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; 5) + send_stats "SSH防御编辑配置文件" f2b_edit_config break_end ;; From 81617c54fe8e941164cea6603036a33ad8c7c42a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 20:39:56 +0800 Subject: [PATCH 0918/1285] docs: add v4.4.4 changelog for fail2ban features --- kejilion_sh_log.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 5f9bc1318..4850981ba 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1473,5 +1473,11 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 应用市场中OpenClaw管理,新增TUI终端命令行聊天窗口,临时调试任务执行更方面。 应用市场中OpenClaw管理,安装后自动调整权限为full,可以调用内部程序自动化。 ------------------------ +2026-03-07 v4.4.4 +SSH防御菜单新增基础参数配置功能,支持交互式设置封禁时长、时间窗口、重试次数。 +SSH防御菜单新增配置文件编辑功能,使用nano直接编辑jail配置。 +SSH防御优化Alpine系统jail名称检测,默认使用sshd,仅检测到自定义规则时切换alpine-sshd。 +SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜像启动失败。 +------------------------ From 7b96ede50d8adcb75cba3ede7aefea9434ded7ce Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 20:41:56 +0800 Subject: [PATCH 0919/1285] fix: update screenshot image paths to /img/screenshots/ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e33b8f7be..9be65afee 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ bash <(curl -sL kejilion.sh) en ## 🖼️ 效果图预览 (Preview)

- 中文版 - English Version + 中文版 + English Version

From 304e4c9a9e1248c004d411de6da1766a0566f3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 7 Mar 2026 20:42:40 +0800 Subject: [PATCH 0920/1285] Remove changelog for version 4.4.4 Removed version 4.4.4 changelog entries from the log file. --- kejilion_sh_log.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4850981ba..2d3af3c87 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1472,12 +1472,8 @@ SSL申请失败后追加导入已有证书选项,你可以导入域名有效 2026-03-06 v4.4.3 应用市场中OpenClaw管理,新增TUI终端命令行聊天窗口,临时调试任务执行更方面。 应用市场中OpenClaw管理,安装后自动调整权限为full,可以调用内部程序自动化。 ------------------------- -2026-03-07 v4.4.4 SSH防御菜单新增基础参数配置功能,支持交互式设置封禁时长、时间窗口、重试次数。 SSH防御菜单新增配置文件编辑功能,使用nano直接编辑jail配置。 SSH防御优化Alpine系统jail名称检测,默认使用sshd,仅检测到自定义规则时切换alpine-sshd。 SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜像启动失败。 ------------------------ - - From 24d5256f5ca51e18ff086a71429a98405bf056af Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 20:46:41 +0800 Subject: [PATCH 0921/1285] fix: update screenshot image paths in all language READMEs --- README.ja.md | 2 +- README.kr.md | 2 +- README.ru.md | 4 ++-- README.tw.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.ja.md b/README.ja.md index 675d9e886..16a0d59de 100644 --- a/README.ja.md +++ b/README.ja.md @@ -27,7 +27,7 @@ bash <(curl -sL kejilion.sh) jp *** ## 🖼️ 実際のスクリーンショット -日本語版プレビュー +日本語版プレビュー *** diff --git a/README.kr.md b/README.kr.md index c2fa28aa2..38ff36ce5 100644 --- a/README.kr.md +++ b/README.kr.md @@ -28,7 +28,7 @@ bash <(curl -sL kejilion.sh) kr ## 🖼️ 실제 화면 미리보기 (Preview) -한국어 버전 미리보기 +한국어 버전 미리보기 diff --git a/README.ru.md b/README.ru.md index c8d85b241..28f14d5b9 100644 --- a/README.ru.md +++ b/README.ru.md @@ -1,6 +1,6 @@


-логотип +логотип
@@ -90,7 +90,7 @@ bash <(curl -sL kejilion.sh) ru

## 🖼️ Предпросмотр интерфейса -Предпросмотр русской версии +Предпросмотр русской версии diff --git a/README.tw.md b/README.tw.md index 8efdbe335..3f5eaad15 100644 --- a/README.tw.md +++ b/README.tw.md @@ -27,7 +27,7 @@ bash <(curl -sL kejilion.sh) tw ## 🖼️ 실제 화면 미리보기 (Preview) -한국어 버전 미리보기 +한국어 버전 미리보기 From 219f95fe1dd96a81fb01463e144d5757e749790b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 7 Mar 2026 22:13:57 +0800 Subject: [PATCH 0922/1285] fix(openclaw): fix duplicate install_plugin def and add skill detection --- cn/kejilion.sh | 103 ++++++++++++------------------------------------- kejilion.sh | 103 ++++++++++++------------------------------------- 2 files changed, 48 insertions(+), 158 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index acc27fa2c..f5e312ae7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10300,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "安装插件" - while true; do - clear - echo "========================================" - echo " 插件管理 (安装) " - echo "========================================" - echo "当前已安装插件:" - openclaw plugins list - echo "----------------------------------------" - - # 输出推荐的实用插件列表,便于用户复制 - echo "推荐的实用插件(可直接复制名称输入):" - echo "feishu # 飞书/Lark 集成 (当前已加载 ✓)" - echo "telegram # Telegram 机器人集成 (当前已加载 ✓)" - echo "memory-core # 核心记忆增强:基于文件的上下文搜索 (当前已加载 ✓)" - echo "@openclaw/slack # Slack 频道与 DMs 深度连接" - echo "@openclaw/bluebubbles # iMessage 桥接 (macOS 用户首选)" - echo "@openclaw/msteams # Microsoft Teams 企业通讯集成" - echo "@openclaw/voice-call # 语音通话插件 (基于 Twilio 等后端)" - echo "@openclaw/discord # Discord 频道自动化管理" - echo "@openclaw/nostr # Nostr 协议:隐私安全加密聊天" - echo "lobster # 审批工作流:带有人工干预的自动任务" - echo "memory-lancedb # 长期记忆增强:基于向量数据库的精准召回" - echo "copilot-proxy # GitHub Copilot 代理接入增强" - echo "----------------------------------------" - - # 提示用户输入插件名称 - read -e -p "请输入要安装的插件名称(输入 0 退出): " plugin_name - - # 1. 检查是否输入 0 以退出 - if [ "$plugin_name" = "0" ]; then - echo "操作已取消,退出插件安装。" - break - fi - - # 2. 验证输入是否为空 - if [ -z "$plugin_name" ]; then - echo "错误:插件名称不能为空,请重新输入。" - echo "" - continue - fi - - # 1. 彻底清理之前失败的残留(用户目录) - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. 检查系统是否已经预装(防止 duplicate id 冲突) - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 检测到系统目录已存在该插件,正在直接激活..." - openclaw plugins enable "$plugin_name" - else - echo "📥 正在通过官方渠道下载安装插件..." - # 使用 openclaw 自己的 install 命令,它会自动处理 package.json 的规范检查 - openclaw plugins install "$plugin_name" - - # 3. 如果 openclaw install 报错,再尝试作为普通 npm 包安装(最后的备选) - if [ $? -ne 0 ]; then - echo "⚠️ 官方安装失败,尝试通过 npm 全局强制安装..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. 最后统一执行启用 - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "安装插件" while true; do clear @@ -10412,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 正在检查插件状态..." + # 获取当前插件列表用于状态检测 + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10506,14 +10437,29 @@ EOF continue fi - # 3. 执行安装命令 - echo "正在安装技能:$skill_name ..." - npx clawhub install "$skill_name" + # 3. 检查技能是否已安装 + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在用户目录安装。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系统目录安装。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "是否重新安装?(y/N): " reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "跳过安装。" + break_end + continue + fi + fi - # 获取上一条命令的退出状态 - if [ $? -eq 0 ]; then + # 4. 执行安装命令 + echo "正在安装技能:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ 技能 $skill_name 安装成功。" - # 执行重启/启动服务逻辑 start_gateway else echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" @@ -10521,7 +10467,6 @@ EOF break_end done - } diff --git a/kejilion.sh b/kejilion.sh index 2166f2257..b68dac542 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10300,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "安装插件" - while true; do - clear - echo "========================================" - echo " 插件管理 (安装) " - echo "========================================" - echo "当前已安装插件:" - openclaw plugins list - echo "----------------------------------------" - - # 输出推荐的实用插件列表,便于用户复制 - echo "推荐的实用插件(可直接复制名称输入):" - echo "feishu # 飞书/Lark 集成 (当前已加载 ✓)" - echo "telegram # Telegram 机器人集成 (当前已加载 ✓)" - echo "memory-core # 核心记忆增强:基于文件的上下文搜索 (当前已加载 ✓)" - echo "@openclaw/slack # Slack 频道与 DMs 深度连接" - echo "@openclaw/bluebubbles # iMessage 桥接 (macOS 用户首选)" - echo "@openclaw/msteams # Microsoft Teams 企业通讯集成" - echo "@openclaw/voice-call # 语音通话插件 (基于 Twilio 等后端)" - echo "@openclaw/discord # Discord 频道自动化管理" - echo "@openclaw/nostr # Nostr 协议:隐私安全加密聊天" - echo "lobster # 审批工作流:带有人工干预的自动任务" - echo "memory-lancedb # 长期记忆增强:基于向量数据库的精准召回" - echo "copilot-proxy # GitHub Copilot 代理接入增强" - echo "----------------------------------------" - - # 提示用户输入插件名称 - read -e -p "请输入要安装的插件名称(输入 0 退出): " plugin_name - - # 1. 检查是否输入 0 以退出 - if [ "$plugin_name" = "0" ]; then - echo "操作已取消,退出插件安装。" - break - fi - - # 2. 验证输入是否为空 - if [ -z "$plugin_name" ]; then - echo "错误:插件名称不能为空,请重新输入。" - echo "" - continue - fi - - # 1. 彻底清理之前失败的残留(用户目录) - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. 检查系统是否已经预装(防止 duplicate id 冲突) - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 检测到系统目录已存在该插件,正在直接激活..." - openclaw plugins enable "$plugin_name" - else - echo "📥 正在通过官方渠道下载安装插件..." - # 使用 openclaw 自己的 install 命令,它会自动处理 package.json 的规范检查 - openclaw plugins install "$plugin_name" - - # 3. 如果 openclaw install 报错,再尝试作为普通 npm 包安装(最后的备选) - if [ $? -ne 0 ]; then - echo "⚠️ 官方安装失败,尝试通过 npm 全局强制安装..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. 最后统一执行启用 - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "安装插件" while true; do clear @@ -10412,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 正在检查插件状态..." + # 获取当前插件列表用于状态检测 + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10506,14 +10437,29 @@ EOF continue fi - # 3. 执行安装命令 - echo "正在安装技能:$skill_name ..." - npx clawhub install "$skill_name" + # 3. 检查技能是否已安装 + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在用户目录安装。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系统目录安装。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "是否重新安装?(y/N): " reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "跳过安装。" + break_end + continue + fi + fi - # 获取上一条命令的退出状态 - if [ $? -eq 0 ]; then + # 4. 执行安装命令 + echo "正在安装技能:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ 技能 $skill_name 安装成功。" - # 执行重启/启动服务逻辑 start_gateway else echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" @@ -10521,7 +10467,6 @@ EOF break_end done - } From 337b1243ba902ff4dd4e919c8e0d322db08703e6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 8 Mar 2026 04:55:09 +0000 Subject: [PATCH 0923/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-03-08=2004:55:09?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 408 +++++++++++++++++++++++++++++-------------------- jp/kejilion.sh | 388 ++++++++++++++++++++++++++++------------------ kr/kejilion.sh | 362 ++++++++++++++++++++++++++----------------- tw/kejilion.sh | 408 +++++++++++++++++++++++++++++-------------------- 4 files changed, 951 insertions(+), 615 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 7ac7a21d2..e674bad5f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.3" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -2318,7 +2318,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3213,6 +3213,80 @@ f2b_sshd() { fi } +# Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) +# illustrate: +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}fail2ban-client is not detected, please install fail2ban first.${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # Alpine default jail is usually sshd; only switches if custom alpine-sshd rules are detected + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi + fi + + echo "About to configure the SSH jail:$jail_name" + read -e -p "Bantime bantime (seconds/minutes/hours, such as 3600 or 1h) [default 1h]:" bantime + read -e -p "Time window findtime (seconds/minutes/hours, e.g. 600 or 10m) [default 10m]:" findtime + read -e -p "Number of retries maxretry (integer) [default 5]:" maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local <> /etc/fail2ban/jail.d/sshd.local + fi + fi + + echo -e "${gl_lv}Configuration has been written${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + fail2ban-client reload >/dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# Directly open the main configuration/overlay configuration editor (nano) +# Edit /etc/fail2ban/jail.d/sshd.local first (more secure), create it if it does not exist +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban does not exist, please install fail2ban first.${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}saved${gl_bai}, reloading fail2ban..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -3522,7 +3596,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4312,7 +4386,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4409,7 +4483,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -5014,7 +5088,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5450,7 +5524,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6248,7 +6322,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6707,7 +6781,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -7083,7 +7157,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started to enter the key content, continue adding + # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7220,7 +7294,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -7437,7 +7511,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -8072,7 +8146,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8149,7 +8223,7 @@ linux_docker() { echo -e "${gl_kjlan}7. ${gl_bai}Clean up useless docker containers and mirror network data volumes" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Change Docker source" - echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" echo -e "${gl_kjlan}12. ${gl_bai}Turn off Docker-ipv6 access" @@ -8439,7 +8513,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9883,16 +9957,17 @@ moltbot_menu() { echo "4. View status log" echo "5. Change model" echo "6. Add new model API" - echo "7. Enter the connection code in TG" + echo "7. Robot connection and docking" echo "8. Install plug-ins (such as Feishu)" echo "9. Install skills" echo "10. Edit the main configuration file" echo "11. Configuration Wizard" echo "12. Health detection and repair" echo "13. WebUI access and settings" + echo "14. TUI command line dialog window" echo "--------------------" - echo "14. Update" - echo "15. Uninstall" + echo "15. Update" + echo "16. Uninstall" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" @@ -9932,8 +10007,13 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end @@ -9942,8 +10022,8 @@ moltbot_menu() { start_bot() { - echo "Start OpenClaw..." - send_stats "Start OpenClaw..." + echo "Starting OpenClaw..." + send_stats "Starting OpenClaw..." start_gateway break_end } @@ -10220,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "Install plugin" - while true; do - clear - echo "========================================" - echo "Plug-in management (installation)" - echo "========================================" - echo "Currently installed plugins:" - openclaw plugins list - echo "----------------------------------------" - - # Output a list of recommended practical plug-ins for users to copy - echo "Recommended practical plug-ins (you can directly copy the name and enter it):" - echo "feishu # Feishu/Lark integration (currently loaded ✓)" - echo "telegram # Telegram bot integration (currently loaded ✓)" - echo "memory-core # Core memory enhancement: file-based contextual search (currently loaded ✓)" - echo "@openclaw/slack # Deep connections between Slack channels and DMs" - echo "@openclaw/bluebubbles # iMessage bridge (preferred for macOS users)" - echo "@openclaw/msteams #Microsoft Teams Enterprise Communications Integration" - echo "@openclaw/voice-call # Voice call plug-in (based on backends such as Twilio)" - echo "@openclaw/discord # Discord channel automatic management" - echo "@openclaw/nostr # Nostr protocol: private and secure encrypted chat" - echo "lobster # Approval workflow: automated tasks with human intervention" - echo "memory-lancedb # Long-term memory enhancement: precise recall based on vector database" - echo "copilot-proxy # GitHub Copilot proxy access enhancement" - echo "----------------------------------------" - - # Prompt user for plugin name - read -e -p "Please enter the name of the plugin you want to install (enter 0 to exit):" plugin_name - - # 1. Check if you entered 0 to exit - if [ "$plugin_name" = "0" ]; then - echo "The operation has been canceled and the plug-in installation has been exited." - break - fi - - # 2. Verify that the input is empty - if [ -z "$plugin_name" ]; then - echo "Error: The plug-in name cannot be empty, please re-enter it." - echo "" - continue - fi - - # 1. Completely clean up the remnants of previous failures (user directory) - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. Check whether the system has been pre-installed (to prevent duplicate ID conflicts) - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 It is detected that the plug-in already exists in the system directory and is being activated directly..." - openclaw plugins enable "$plugin_name" - else - echo "📥 Downloading and installing the plug-in through official channels..." - # Use openclaw's own install command, which automatically handles spec checking of package.json - openclaw plugins install "$plugin_name" - - # 3. If openclaw install reports an error, try installing it as a normal npm package (last alternative) - if [ $? -ne 0 ]; then - echo "⚠️ The official installation failed, try to force the installation globally through npm..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. Finally, unified execution and activation - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "Install plugin" while true; do clear @@ -10332,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 Checking plugin status..." + # Get the current plug-in list for status detection + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. Check whether it is already in the list and disabled (the most common case) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10426,14 +10437,29 @@ EOF continue fi - # 3. Execute the installation command - echo "Installing skills:$skill_name ..." - npx clawhub install "$skill_name" + # 3. Check whether the skill is installed + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 Skills [$skill_name] is installed in the user directory." + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 Skills [$skill_name] is installed in the system directory." + skill_found=true + fi - # Get the exit status of the previous command - if [ $? -eq 0 ]; then + if [ "$skill_found" = true ]; then + read -e -p "Reinstall? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "Skip installation." + break_end + continue + fi + fi + + # 4. Execute the installation command + echo "Installing skills:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ Skills$skill_nameInstallation successful." - # Execute restart/start service logic start_gateway else echo "❌ Installation failed. Please check whether the skill name is correct, or refer to the documentation for troubleshooting." @@ -10441,29 +10467,56 @@ EOF break_end done - } change_tg_bot_code() { send_stats "Robot docking" - read -e -p "Please enter the connection code received by the TG robot (for example, Pairing code: NYA99R2F) (enter 0 to exit):" code - - # Check if 0 is entered to exit - if [ "$code" = "0" ]; then - echo "The operation has been cancelled." - return 0 # 正常退出函数 - fi - - # Verify input is empty - if [ -z "$code" ]; then - echo "Error: Connection code cannot be empty. Please try again." - return 1 - fi + while true; do + clear + echo "========================================" + echo "Robot connection and docking" + echo "========================================" + echo "1. Telegram robot docking" + echo "2. Feishu (Lark) robot docking" + echo "3. WhatsApp bot docking" + echo "----------------------------------------" + echo "0. Return to the previous menu" + echo "----------------------------------------" + read -e -p "Please enter your choice:" bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "Please enter the connection code received by the TG robot (for example, NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Please enter the connection code received by Feishu Robot (for example, NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "Please enter the connection code received by WhatsApp (for example NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done } @@ -10487,6 +10540,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "Uninstall completed" @@ -10570,6 +10624,19 @@ EOF echo "First access the URL to trigger the device ID, then press Enter to proceed with pairing." read echo -e "${gl_kjlan}Loading device list...${gl_bai}" + # Automatically add domain names to allowedOrigins + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + # Use jq to safely modify JSON to ensure that the structure exists and domain names are not added repeatedly + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}Domain name has been${yuming}Add allowedOrigins configuration${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "Please enter Request_Key:" Request_Key @@ -10650,8 +10717,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 14) send_stats "TUI command line conversation" + openclaw tui + break_end + ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done @@ -11171,7 +11242,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -11225,7 +11296,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11323,7 +11394,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -11398,7 +11469,7 @@ while true; do } - local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12209,7 +12280,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12436,7 +12507,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12488,7 +12559,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12529,7 +12600,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12592,7 +12663,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -12777,7 +12848,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -12806,7 +12877,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -12833,7 +12904,7 @@ while true; do } - local docker_describe="A password manager where you can control your data" + local docker_describe="A password manager that puts you in control of your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -12920,7 +12991,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13141,7 +13212,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13191,7 +13262,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13327,7 +13398,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13390,7 +13461,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -13554,7 +13625,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13692,7 +13763,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13746,7 +13817,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -13979,7 +14050,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14021,7 +14092,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14050,7 +14121,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14119,7 +14190,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14260,7 +14331,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14330,7 +14401,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -14370,7 +14441,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Since Lucky uses the host network mode, the port here is only for record/explanation reference, and is actually controlled by the application itself (default 16601) + # Since Lucky uses the host network mode, the port here is only for record/explanation reference and is actually controlled by the application itself (default 16601) local docker_port=8112 docker_rum() { @@ -14538,7 +14609,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -14728,7 +14799,7 @@ switch_mirror() { local country country=$(curl -s ipinfo.io/country) - echo "Countries detected:$country" + echo "检测到国家:$country" if [ "$country" = "CN" ]; then echo "Use domestic mirror sources..." @@ -14786,6 +14857,9 @@ fail2ban_panel() { echo "2. View SSH interception records" echo "3. Real-time log monitoring" echo "------------------------" + echo "4. Basic parameter configuration (ban duration/time window/number of retries)" + echo "5. Edit configuration file (nano)" + echo "------------------------" echo "9. Uninstall the defense program" echo "------------------------" echo "0. Return to the previous menu" @@ -14808,6 +14882,16 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + send_stats "SSH defense basic parameter configuration" + f2b_basic_config + break_end + ;; + 5) + send_stats "SSH Defense Edit Configuration File" + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban @@ -14922,7 +15006,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. Check the latest system log (journal)" + echo "1. View the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -14934,7 +15018,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -15012,7 +15096,7 @@ env_menu() { show_env_vars() { clear - send_stats "Environment variables currently in effect" + send_stats "Currently in effect environment variables" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -15204,7 +15288,7 @@ linux_Settings() { while true; do clear - # send_stats "system tools" + # send_stats "System Tools" echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" @@ -15279,7 +15363,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -15956,7 +16040,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -15972,7 +16056,7 @@ EOF case "$Limiting" in 1) # Enter new virtual memory size - echo "If the actual server only has 100G traffic, you can set the threshold to 95G and shut down in advance to avoid traffic errors or overflows." + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" read -e -p "Please enter the inbound traffic threshold (unit is G, default is 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb @@ -16177,7 +16261,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" @@ -16225,7 +16309,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -16587,7 +16671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16621,7 +16705,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16738,7 +16822,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16977,7 +17061,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k命令参考用例" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 08a434f2f..7e0d0de5a 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.3" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -119,7 +119,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -1189,7 +1189,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -3213,6 +3213,80 @@ f2b_sshd() { fi } +# 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) +# 例証します: +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}failed2ban-client が検出されません。まず、fail2ban をインストールしてください。${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # Alpine のデフォルトの刑務所は通常 sshd です。カスタム alpine-sshd ルールが検出された場合にのみ切り替えます + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi + fi + + echo "SSH ジェイルを構成しようとしています:$jail_name" + read -e -p "Bantime 禁止時間 (秒/分/時間、3600 または 1 時間など) [デフォルトは 1 時間]:" bantime + read -e -p "タイムウィンドウ findtime (秒/分/時間、例: 600 または 10 分) [デフォルトは 10 分]:" findtime + read -e -p "再試行回数 maxretry (整数) [デフォルト 5]:" maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local <> /etc/fail2ban/jail.d/sshd.local + fi + fi + + echo -e "${gl_lv}設定が書き込まれました${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + fail2ban-client reload >/dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# メイン構成/オーバーレイ構成エディター (nano) を直接開きます。 +# /etc/fail2ban/jail.d/sshd.local を最初に編集し (より安全です)、存在しない場合は作成します +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban が存在しません。まず、fail2ban をインストールしてください。${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -3672,7 +3746,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4073,7 +4147,7 @@ add_forwarding_service() { read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -4699,7 +4773,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4758,7 +4832,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5841,7 +5915,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6220,7 +6294,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" @@ -6248,7 +6322,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6652,7 +6726,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7032,7 +7106,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7220,7 +7294,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモート ホストにアクセスできますか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7319,7 +7393,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7437,7 +7511,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7561,7 +7635,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7863,7 +7937,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8072,7 +8146,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -9883,16 +9957,17 @@ moltbot_menu() { echo "4. ステータスログの表示" echo "5.機種変更" echo "6. 新しいモデル API を追加する" - echo "7. TGに接続コードを入力します" + echo "7. ロボットの接続とドッキング" echo "8. プラグイン(Feishuなど)をインストールする" echo "9. スキルのインストール" echo "10. メイン設定ファイルを編集します" echo "11. 設定ウィザード" echo "12. 健全性の検出と修復" echo "13. WebUI へのアクセスと設定" + echo "14. TUIコマンドラインダイアログウィンドウ" echo "--------------------" - echo "14. アップデート" - echo "15. アンインストール" + echo "15. アップデート" + echo "16. アンインストール" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -9932,8 +10007,13 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end @@ -9942,8 +10022,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw を開始します..." - send_stats "OpenClaw を開始します..." + echo "OpenClaw を開始しています..." + send_stats "OpenClaw を開始しています..." start_gateway break_end } @@ -10136,7 +10216,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -10220,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "プラグインのインストール" - while true; do - clear - echo "========================================" - echo "プラグイン管理(インストール)" - echo "========================================" - echo "現在インストールされているプラ​​グイン:" - openclaw plugins list - echo "----------------------------------------" - - # ユーザーがコピーできる推奨実用プラグインのリストを出力します - echo "推奨される実用的なプラグイン (名前を直接コピーして入力できます):" - echo "feishu # Feishu/Lark 統合 (現在ロード中 ✓)" - echo "telegram # Telegram ボットの統合 (現在ロードされています ✓)" - echo "Memory-core # コア メモリの強化: ファイルベースのコンテキスト検索 (現在ロードされています ✓)" - echo "@openclaw/slack # Slack チャネルと DM 間の深いつながり" - echo "@openclaw/bluebubbles # iMessage ブリッジ (macOS ユーザーに推奨)" - echo "@openclaw/msteams #Microsoft Teams エンタープライズ コミュニケーションの統合" - echo "@openclaw/voice-call # 音声通話プラグイン (Twilio などのバックエンドに基づく)" - echo "@openclaw/discord #Discordチャンネル自動管理" - echo "@openclaw/nostr # Nostr プロトコル: プライベートで安全な暗号化チャット" - echo "lobster # 承認ワークフロー: 人間の介入によるタスクの自動化" - echo "Memory-lancedb # 長期記憶強化: ベクトルデータベースに基づく正確な記憶" - echo "copilot-proxy # GitHub Copilot プロキシ アクセスの強化" - echo "----------------------------------------" - - # ユーザーにプラグイン名の入力を求めるプロンプト - read -e -p "インストールするプラグインの名前を入力してください (終了するには 0 を入力します):" plugin_name - - # 1.終了するには0を入力したかどうかを確認します - if [ "$plugin_name" = "0" ]; then - echo "操作がキャンセルされ、プラグインのインストールが終了しました。" - break - fi - - # 2. 入力が空であることを確認します - if [ -z "$plugin_name" ]; then - echo "エラー: プラグイン名を空にすることはできません。再入力してください。" - echo "" - continue - fi - - # 1. 以前の失敗の残骸 (ユーザー ディレクトリ) を完全にクリーンアップします。 - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. システムがプリインストールされているかどうかを確認します (重複 ID の競合を防ぐため)。 - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 プラグインが既にシステム ディレクトリに存在し、直接アクティブ化されていることが検出されました..." - openclaw plugins enable "$plugin_name" - else - echo "📥 公式チャネルを通じてプラグインをダウンロードしてインストールしています..." - # openclaw 独自の install コマンドを使用して、package.json の仕様チェックを自動的に処理します。 - openclaw plugins install "$plugin_name" - - # 3. openclaw のインストールでエラーが報告された場合は、通常の npm パッケージとしてインストールしてみてください (最後の選択肢) - if [ $? -ne 0 ]; then - echo "⚠️ 公式インストールが失敗しました。npm を介してグローバルにインストールを強制してみてください..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. 最後に、統合された実行とアクティブ化 - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "プラグインのインストール" while true; do clear @@ -10332,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 プラグインのステータスを確認しています..." + # ステータス検出用の現在のプラグイン リストを取得する + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. すでにリストに含まれていて無効になっているかどうかを確認します (最も一般的なケース)。 if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10426,14 +10437,29 @@ EOF continue fi - # 3. インストールコマンドを実行します。 - echo "スキルのインストール:$skill_name ..." - npx clawhub install "$skill_name" + # 3. スキルがインストールされているか確認する + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" + skill_found=true + fi - # 前のコマンドの終了ステータスを取得する - if [ $? -eq 0 ]; then + if [ "$skill_found" = true ]; then + read -e -p "再インストールしますか? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "インストールをスキップします。" + break_end + continue + fi + fi + + # 4. インストールコマンドを実行します。 + echo "スキルのインストール:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ スキル$skill_nameインストールが成功しました。" - # 再起動/サービス開始ロジックの実行 start_gateway else echo "❌ インストールに失敗しました。スキル名が正しいか確認するか、ドキュメントを参照してトラブルシューティングを行ってください。" @@ -10441,29 +10467,56 @@ EOF break_end done - } change_tg_bot_code() { send_stats "ロボットドッキング" - read -e -p "TG ロボットが受信した接続コード (例: ペアリング コード: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code - - # 終了するには0が入力されているかどうかを確認してください - if [ "$code" = "0" ]; then - echo "操作はキャンセルされました。" - return 0 # 正常退出函数 - fi - - # 入力が空であることを確認してください - if [ -z "$code" ]; then - echo "エラー: 接続コードを空にすることはできません。もう一度試してください。" - return 1 - fi + while true; do + clear + echo "========================================" + echo "ロボットの接続とドッキング" + echo "========================================" + echo "1. テレグラムロボットドッキング" + echo "2.フェイシュ(ヒバリ)ロボットドッキング" + echo "3. WhatsApp ボットのドッキング" + echo "----------------------------------------" + echo "0. 前のメニューに戻る" + echo "----------------------------------------" + read -e -p "選択肢を入力してください:" bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "TG ロボットが受信した接続コード (NYA99R2F など) を入力してください (終了するには 0 を入力します)。" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Feishu Robot が受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done } @@ -10487,6 +10540,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アンインストールが完了しました" @@ -10570,6 +10624,19 @@ EOF echo "まず URL にアクセスしてデバイス ID をトリガーし、Enter キーを押してペアリングを続行します。" read echo -e "${gl_kjlan}デバイスリストをロード中...${gl_bai}" + # ドメイン名を allowedOrigins に自動的に追加する + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + # jq を使用して JSON を安全に変更し、構造が存在し、ドメイン名が繰り返し追加されないようにします。 + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}ドメイン名は${yuming}allowedOrigins 構成を追加する${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "Request_Key を入力してください:" Request_Key @@ -10650,8 +10717,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 14) send_stats "TUI コマンドラインでの会話" + openclaw tui + break_end + ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done @@ -10987,7 +11058,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザ監視$check_docker $update_status" + echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -10996,7 +11067,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -11398,7 +11469,7 @@ while true; do } - local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12777,7 +12848,7 @@ while true; do } - local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" + local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -12833,7 +12904,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -13390,7 +13461,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -14021,7 +14092,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14538,7 +14609,7 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" @@ -14786,6 +14857,9 @@ fail2ban_panel() { echo "2. SSH インターセプト記録の表示" echo "3. リアルタイムログ監視" echo "------------------------" + echo "4. 基本パラメータ設定(禁止期間/時間枠/リトライ回数)" + echo "5. 設定ファイル(nano)の編集" + echo "------------------------" echo "9. 防御プログラムをアンインストールする" echo "------------------------" echo "0. 前のメニューに戻る" @@ -14808,6 +14882,16 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + send_stats "SSH防御基本パラメータ設定" + f2b_basic_config + break_end + ;; + 5) + send_stats "SSH 防御構成ファイルの編集" + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban @@ -14864,7 +14948,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -14874,7 +14958,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -14886,7 +14970,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -14912,7 +14996,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記帳の職業】" + echo "【日記ログ職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -14922,7 +15006,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を確認する" + echo "1. 最新のシステムログ(ジャーナル)を表示する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -14934,10 +15018,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -14947,7 +15031,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -14962,7 +15046,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -15050,7 +15134,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -15065,7 +15149,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -15081,7 +15165,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -15204,7 +15288,7 @@ linux_Settings() { while true; do clear - # send_stats「システムツール」 + # send_stats 「システムツール」 echo -e "システムツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" @@ -15956,7 +16040,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -16168,7 +16252,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -16587,7 +16671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16621,7 +16705,7 @@ while true; do echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16738,7 +16822,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16977,7 +17061,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -17012,7 +17096,7 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 5772aef59..87634f982 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.3" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3213,6 +3213,80 @@ f2b_sshd() { fi } +# 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) +# 설명하다: +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). +# - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}FAIL2BAN-클라이언트가 감지되지 않습니다. 먼저 Fail2ban을 설치하십시오.${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # 알파인 기본 감옥은 일반적으로 sshd입니다. 사용자 정의 alpine-sshd 규칙이 감지된 경우에만 전환됩니다. + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi + fi + + echo "SSH 감옥을 구성하려고 합니다:$jail_name" + read -e -p "금지 시간 금지 시간(초/분/시간, 예: 3600 또는 1h) [기본값 1h]:" bantime + read -e -p "시간 창 찾기 시간(초/분/시간, 예: 600 또는 10m) [기본값 10m]:" findtime + read -e -p "재시도 횟수 maxretry(정수) [기본값 5]:" maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local <> /etc/fail2ban/jail.d/sshd.local + fi + fi + + echo -e "${gl_lv}구성이 작성되었습니다.${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + fail2ban-client reload >/dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# 기본 구성/오버레이 구성 편집기(나노)를 직접 엽니다. +# /etc/fail2ban/jail.d/sshd.local을 먼저 편집하고(보다 안전함) 존재하지 않는 경우 생성합니다. +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban이 존재하지 않습니다. 먼저 fall2ban을 설치하십시오.${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}저장됨${gl_bai}, Fail2ban을 다시 로드하는 중..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -3645,7 +3719,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4335,7 +4409,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4978,7 +5052,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원래 Authorized_keys 파일이 백업되었습니다." + echo "원본 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5764,7 +5838,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6248,7 +6322,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6707,7 +6781,7 @@ add_connection() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then local password_or_key+="${line}"$'\n' fi @@ -7083,7 +7157,7 @@ add_task() { if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용을 입력하기 시작했다면 계속해서 추가하세요. + # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then password_or_key+="${line}"$'\n' fi @@ -7220,7 +7294,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -8072,7 +8146,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8259,7 +8333,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8620,7 +8694,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9883,16 +9957,17 @@ moltbot_menu() { echo "4. 상태 로그 보기" echo "5. 모델 변경" echo "6. 새로운 모델 API 추가" - echo "7. TG에 연결 코드를 입력하세요." + echo "7. 로봇 연결 및 도킹" echo "8. 플러그인 설치(예: Feishu)" echo "9. 스킬 설치" echo "10. 기본 구성 파일 편집" echo "11. 구성 마법사" echo "12. 건강 상태 감지 및 복구" echo "13. WebUI 접속 및 설정" + echo "14. TUI 명령줄 대화 상자 창" echo "--------------------" - echo "14. 업데이트" - echo "15. 제거" + echo "15. 업데이트" + echo "16. 제거" echo "--------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------" @@ -9932,8 +10007,13 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end @@ -9942,8 +10022,8 @@ moltbot_menu() { start_bot() { - echo "OpenClaw를 시작하세요..." - send_stats "OpenClaw를 시작하세요..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_gateway break_end } @@ -10220,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "플러그인 설치" - while true; do - clear - echo "========================================" - echo "플러그인 관리(설치)" - echo "========================================" - echo "현재 설치된 플러그인:" - openclaw plugins list - echo "----------------------------------------" - - # 사용자가 복사할 수 있는 권장 실무 플러그인 목록 출력 - echo "추천 실용 플러그인(이름을 직접 복사하여 입력 가능):" - echo "feishu # Feishu/Lark 통합 (현재 로드됨 ✓)" - echo "텔레그램 # 텔레그램 봇 통합 (현재 로드됨 ✓)" - echo "memory-core # 핵심 메모리 강화: 파일 기반 상황별 검색(현재 로드됨 ✓)" - echo "@openclaw/slack # Slack 채널과 DM 간의 깊은 연결" - echo "@openclaw/bluebubbles # iMessage 브리지(macOS 사용자에게 선호됨)" - echo "@openclaw/msteams #Microsoft Teams 엔터프라이즈 커뮤니케이션 통합" - echo "@openclaw/voice-call # 음성 통화 플러그인 (Twilio와 같은 백엔드 기반)" - echo "@openclaw/discord # 디스코드 채널 자동관리" - echo "@openclaw/nostr # Nostr 프로토콜: 비공개적이고 안전한 암호화된 채팅" - echo "랍스터 # 승인 워크플로: 사람의 개입으로 자동화된 작업" - echo "memory-lancedb # 장기 기억력 향상: 벡터 데이터베이스 기반의 정확한 재현" - echo "copilot-proxy # GitHub Copilot 프록시 액세스 향상" - echo "----------------------------------------" - - # 사용자에게 플러그인 이름을 묻는 메시지 표시 - read -e -p "설치하려는 플러그인의 이름을 입력하십시오(종료하려면 0을 입력하십시오):" plugin_name - - # 1. 0을 입력하여 종료했는지 확인하세요. - if [ "$plugin_name" = "0" ]; then - echo "작업이 취소되고 플러그인 설치가 종료되었습니다." - break - fi - - # 2. 입력이 비어 있는지 확인하십시오. - if [ -z "$plugin_name" ]; then - echo "오류: 플러그인 이름은 비워둘 수 없습니다. 다시 입력하세요." - echo "" - continue - fi - - # 1. 이전 실패의 잔재(사용자 디렉터리)를 완전히 정리합니다. - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. 시스템이 사전 설치되어 있는지 확인하세요. (ID 중복 방지를 위해) - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 플러그인이 시스템 디렉터리에 이미 존재하며 직접 활성화되고 있는 것으로 감지되었습니다..." - openclaw plugins enable "$plugin_name" - else - echo "📥 공식 채널을 통해 플러그인 다운로드 및 설치..." - # package.json의 사양 확인을 자동으로 처리하는 openclaw의 자체 설치 명령을 사용합니다. - openclaw plugins install "$plugin_name" - - # 3. openclaw install에서 오류가 보고되면 일반 npm 패키지로 설치해 보세요(마지막 대안). - if [ $? -ne 0 ]; then - echo "⚠️ 공식 설치에 실패했습니다. npm을 통해 전역적으로 강제 설치를 시도해보세요..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. 마지막으로 통합 실행 및 활성화 - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "플러그인 설치" while true; do clear @@ -10332,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 플러그인 상태 확인 중..." + # 상태 감지를 위한 현재 플러그인 목록 가져오기 + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. 이미 목록에 있고 비활성화되어 있는지 확인합니다(가장 일반적인 경우). if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10426,14 +10437,29 @@ EOF continue fi - # 3. 설치 명령을 실행합니다. - echo "기술 설치:$skill_name ..." - npx clawhub install "$skill_name" + # 3. 스킬이 설치되어 있는지 확인하세요 + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 스킬 [$skill_name]는 사용자 디렉토리에 설치됩니다." + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 스킬 [$skill_name]는 시스템 디렉토리에 설치됩니다." + skill_found=true + fi - # 이전 명령의 종료 상태를 가져옵니다. - if [ $? -eq 0 ]; then + if [ "$skill_found" = true ]; then + read -e -p "다시 설치하시겠습니까? (예/아니요):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "설치를 건너뜁니다." + break_end + continue + fi + fi + + # 4. 설치 명령을 실행합니다. + echo "기술 설치:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ 스킬$skill_name설치가 성공했습니다." - # 서비스 재시작/시작 로직 실행 start_gateway else echo "❌ 설치에 실패했습니다. 스킬 이름이 올바른지 확인하시거나, 문제 해결을 위해 문서를 참고하시기 바랍니다." @@ -10441,29 +10467,56 @@ EOF break_end done - } change_tg_bot_code() { send_stats "로봇 도킹" - read -e -p "TG 로봇이 수신한 연결 코드(예: 페어링 코드: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code - - # 0을 입력했는지 확인하여 종료하세요. - if [ "$code" = "0" ]; then - echo "작업이 취소되었습니다." - return 0 # 正常退出函数 - fi - - # 입력이 비어 있는지 확인 - if [ -z "$code" ]; then - echo "오류: 연결 코드는 비워둘 수 없습니다. 다시 시도해 주세요." - return 1 - fi + while true; do + clear + echo "========================================" + echo "로봇 연결 및 도킹" + echo "========================================" + echo "1. 텔레그램 로봇 도킹" + echo "2. Feishu(Lark) 로봇 도킹" + echo "3. WhatsApp 봇 도킹" + echo "----------------------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "----------------------------------------" + read -e -p "선택사항을 입력하세요:" bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Feishu Robot이 수신한 연결 코드(예: NYA99R2F)를 입력하십시오(종료하려면 0을 입력하십시오)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac + done } @@ -10487,6 +10540,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "제거가 완료되었습니다." @@ -10570,6 +10624,19 @@ EOF echo "먼저 URL에 액세스하여 장치 ID를 트리거한 다음 Enter를 눌러 페어링을 진행하세요." read echo -e "${gl_kjlan}기기 목록 로드 중...${gl_bai}" + # allowedOrigins에 도메인 이름을 자동으로 추가합니다. + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + # 구조가 존재하고 도메인 이름이 반복적으로 추가되지 않도록 jq를 사용하여 JSON을 안전하게 수정하세요. + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}도메인 이름이${yuming}allowedOrigins 구성 추가${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "Request_Key를 입력하십시오:" Request_Key @@ -10650,8 +10717,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 14) send_stats "TUI 명령줄 대화" + openclaw tui + break_end + ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done @@ -10987,7 +11058,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -11398,7 +11469,7 @@ while true; do } - local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -12338,7 +12409,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -12500,7 +12571,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -12777,7 +12848,7 @@ while true; do } - local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -12833,7 +12904,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -13390,7 +13461,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -14021,7 +14092,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -14538,7 +14609,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -14786,6 +14857,9 @@ fail2ban_panel() { echo "2. SSH 차단 기록 보기" echo "3. 실시간 로그 모니터링" echo "------------------------" + echo "4. 기본 매개변수 구성(금지 기간/기간/재시도 횟수)" + echo "5. 구성 파일 편집(나노)" + echo "------------------------" echo "9. 방어 프로그램 제거" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" @@ -14808,6 +14882,16 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + send_stats "SSH 방어 기본 매개변수 구성" + f2b_basic_config + break_end + ;; + 5) + send_stats "SSH 방어 편집 구성 파일" + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban @@ -14922,7 +15006,7 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지)를 확인하세요." + echo "1. 최신 시스템 로그(일지) 보기" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" @@ -14934,7 +15018,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -14983,7 +15067,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한합니다." + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -15089,7 +15173,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -15208,7 +15292,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" @@ -15673,7 +15757,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간을 가져옵니다 + # 현재 시스템 시간 가져오기 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -15956,7 +16040,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -16587,7 +16671,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -16621,7 +16705,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -16738,7 +16822,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -16977,7 +17061,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index bcc567c5b..5f6946fa6 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.1" +sh_v="4.4.3" gl_hui='\e[37m' @@ -13,7 +13,7 @@ gl_kjlan='\033[96m' canshu="default" -permission_granted="true" +permission_granted="false" ENABLE_STATS="true" @@ -538,7 +538,7 @@ while true; do [Nn]) ;; *) - echo "無效的選擇,請輸入 Y 或 N。" + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -753,7 +753,7 @@ docker_ipv6_on() { echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq處理設定檔的更新 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # 檢查目前配置是否已經有 ipv6 設定 @@ -1221,7 +1221,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -2192,7 +2192,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防禦程序已卸載" + echo "Fail2Ban防御程序已卸载" break ;; @@ -2232,7 +2232,7 @@ web_security() { 22) send_stats "高負載開啟5秒盾" - echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" @@ -3213,6 +3213,80 @@ f2b_sshd() { fi } +# 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) +# 說明: +# - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) +# - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 +f2b_basic_config() { + root_use + install nano + + if ! command -v fail2ban-client >/dev/null 2>&1; then + echo -e "${gl_hui}未偵測到 fail2ban-client,請先安裝 fail2ban。${gl_bai}" + return + fi + + local jail_name="sshd" + if grep -qi 'Alpine' /etc/issue 2>/dev/null; then + # Alpine 預設 jail 通常為 sshd;僅當偵測到自訂 alpine-sshd 規則時才切換 + if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then + jail_name="alpine-sshd" + fi + fi + + echo "即將配置 SSH jail:$jail_name" + read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime + read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime + read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry + + bantime=${bantime:-1h} + findtime=${findtime:-10m} + maxretry=${maxretry:-5} + + mkdir -p /etc/fail2ban/jail.d + cat > /etc/fail2ban/jail.d/sshd.local <> /etc/fail2ban/jail.d/sshd.local + fi + fi + + echo -e "${gl_lv}已寫入配置${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + fail2ban-client reload >/dev/null 2>&1 || true + sleep 2 + fail2ban-client status $jail_name || true +} + +# 直接開啟主配置/覆蓋配置編輯(nano) +# 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 +f2b_edit_config() { + root_use + install nano + + if [ ! -d /etc/fail2ban ]; then + echo -e "${gl_hui}/etc/fail2ban 不存在,請先安裝 fail2ban。${gl_bai}" + return + fi + + mkdir -p /etc/fail2ban/jail.d + local cfg="/etc/fail2ban/jail.d/sshd.local" + [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" + + nano "$cfg" + echo -e "${gl_lv}已儲存${gl_bai},正在 reload fail2ban..." + fail2ban-client reload >/dev/null 2>&1 || true +} @@ -3810,7 +3884,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3851,7 +3925,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -4026,7 +4100,7 @@ EOF donlond_frp frps - # 輸出產生的信息 + # 输出生成的信息 ip_address echo "------------------------" echo "客戶端部署時所需使用的參數" @@ -4178,7 +4252,7 @@ list_forwarding_services() { } END { - # 列印最後一個服務的訊息 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4196,7 +4270,7 @@ get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 產生訪問地址 +# 生成访问地址 generate_access_urls() { # 首先獲取所有連接埠 get_frp_ports @@ -4275,7 +4349,7 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" @@ -4364,7 +4438,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP客戶端$check_frp $update_status" - echo "與服務端對接,對接後可建立內網穿透服務到網際網路存取" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4898,7 +4972,7 @@ import_sshkey() { fi if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}錯誤:未輸入公鑰內容。${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi @@ -4947,7 +5021,7 @@ fetch_remote_ssh_keys() { # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } @@ -4963,7 +5037,7 @@ fetch_remote_ssh_keys() { return 1 fi - # 檢查內容是否有效 + # 检查内容是否有效 if [[ ! -s "${temp_file}" ]]; then echo "錯誤:下載到的檔案為空,URL 可能不包含任何公鑰" >&2 rm -f "${temp_file}" @@ -5857,7 +5931,7 @@ clamav() { # ============================================================================ -# Linux 内核调优模块(重构版) +# Linux 核心調優模組(重構版) # 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 # 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ @@ -5886,7 +5960,7 @@ _kernel_optimize_core() { case "$scene" in high|stream|game) - # 高性能/直播/游戏:激进参数 + # 高效能/直播/遊戲:激進參數 SWAPPINESS=10 DIRTY_RATIO=15 DIRTY_BG_RATIO=5 @@ -6070,7 +6144,7 @@ net.ipv4.ip_local_port_range = $PORT_RANGE net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) net.ipv4.tcp_max_orphans = 32768 -# ── 虚拟内存 ── +# ── 虛擬記憶體 ── vm.swappiness = $SWAPPINESS vm.dirty_ratio = $DIRTY_RATIO vm.dirty_background_ratio = $DIRTY_BG_RATIO @@ -6113,7 +6187,7 @@ $GAME_EXTRA SYSCTL # ── 應用配置(逐行,跳過不支援的參數) ── - echo -e "${gl_lv}应用优化参数...${gl_bai}" + echo -e "${gl_lv}應用優化參數...${gl_bai}" local applied=0 skipped=0 while IFS= read -r line; do # 跳過註解和空行 @@ -6127,7 +6201,7 @@ SYSCTL done < "$CONF" echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" - # ── 透明大页面 ── + # ── 透明大頁面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi @@ -6152,7 +6226,7 @@ LIMITS fi echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" - echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC} | 队列: ${QDISC}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" } # ── 各模式入口函數(保持原有呼叫介面不變) ── @@ -6179,17 +6253,17 @@ restore_defaults() { rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf - # 清理 sysctl.conf 里可能残留的 bbr 配置 + # 清理 sysctl.conf 裡可能殘留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新加载系统默认配置 + # 重新載入系統預設配置 sysctl --system 2>/dev/null | tail -1 # 還原透明大頁面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null - # 清理文件描述符配置 + # 清理檔案描述符配置 if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf fi @@ -6210,7 +6284,7 @@ Kernel_optimize() { [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" echo "Linux系統核心參數優化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" else echo -e "當前模式:${gl_hui}未最佳化${gl_bai}" fi @@ -6219,13 +6293,13 @@ Kernel_optimize() { echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo -e "--------------------" - echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" + echo -e "1. 高效能最佳化模式: 最大化系統效能,激進的記憶體和網路參數。" echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" - echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "3. 網站最佳化模式: 針對網站伺服器最佳化,超高並發連線佇列。" echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" - echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" + echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -6532,7 +6606,7 @@ create_backup() { echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input - # 如果使用者沒有輸入目錄,則使用預設目錄 + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6540,7 +6614,7 @@ create_backup() { "/home" # 用户数据 ) else - # 將使用者輸入的目錄以空格分隔成數組 + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi @@ -6569,7 +6643,7 @@ create_backup() { install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 檢查命令是否成功 + # 检查命令是否成功 if [ $? -eq 0 ]; then echo "備份建立成功:$BACKUP_DIR/$BACKUP_NAME" else @@ -6817,7 +6891,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以透過SSH連接到其他Linux系統上" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -6848,7 +6922,7 @@ ssh_manager() { # 列出可用的硬碟分割區 list_partitions() { - echo "可用的硬碟分割區:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } @@ -7424,7 +7498,7 @@ linux_info() { echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -8425,7 +8499,7 @@ linux_test() { # send_stats "測試腳本集合" echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解鎖狀態偵測" + echo -e "${gl_kjlan}IP及解锁状态检测" echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" echo -e "${gl_kjlan}2. ${gl_bai}Region 串流解鎖測試" echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 串流媒體解鎖偵測" @@ -8508,7 +8582,7 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京電信: 219.141.136.12" + echo "北京电信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" @@ -9453,7 +9527,7 @@ linux_ldnmp() { 30) clear - webname="靜態站點" + webname="静态站点" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -9684,7 +9758,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "請輸入${ldnmp_pods}版本號碼 (如: 8.0 8.3 8.4 9.0)(回車取得最新版):" version + read -e -p "請輸入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -9883,16 +9957,17 @@ moltbot_menu() { echo "4. 狀態日誌查看" echo "5. 換模型" echo "6. 加新模型API" - echo "7. TG輸入連接碼" + echo "7. 機器人連線對接" echo "8. 安裝插件(如:飛書)" echo "9. 安裝技能(skills)" echo "10. 編輯主設定文件" echo "11. 配置精靈" echo "12. 健康檢測與修復" echo "13. WebUI存取與設置" + echo "14. TUI命令列對話窗口" echo "--------------------" - echo "14. 更新" - echo "15. 卸載" + echo "15. 更新" + echo "16. 卸載" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -9932,8 +10007,13 @@ moltbot_menu() { if [[ "$country" == "CN" || "$country" == "HK" ]]; then npm config set registry https://registry.npmmirror.com fi + + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + npm install -g openclaw@latest openclaw onboard --install-daemon + sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json start_gateway add_app_id break_end @@ -10220,78 +10300,7 @@ EOF - install_plugin() { - - send_stats "安裝插件" - while true; do - clear - echo "========================================" - echo "外掛程式管理 (安裝)" - echo "========================================" - echo "目前已安裝插件:" - openclaw plugins list - echo "----------------------------------------" - - # 輸出推薦的實用外掛程式列表,方便用戶複製 - echo "建議的實用外掛程式(可直接複製名稱輸入):" - echo "feishu # 飛書/Lark 整合 (目前已載入 ✓)" - echo "telegram # Telegram 機器人整合 (目前已載入 ✓)" - echo "memory-core # 核心記憶增強:基於檔案的上下文搜尋 (目前已載入 ✓)" - echo "@openclaw/slack # Slack 頻道與 DMs 深度連接" - echo "@openclaw/bluebubbles # iMessage 橋接 (macOS 用戶首選)" - echo "@openclaw/msteams # Microsoft Teams 企業通訊集成" - echo "@openclaw/voice-call # 語音通話外掛程式 (基於 Twilio 等後端)" - echo "@openclaw/discord # Discord 頻道自動化管理" - echo "@openclaw/nostr # Nostr 協定:隱私安全加密聊天" - echo "lobster # 審批工作流程:帶有人工幹預的自動任務" - echo "memory-lancedb # 長期記憶增強:基於向量資料庫的精準召回" - echo "copilot-proxy # GitHub Copilot 代理程式存取增強" - echo "----------------------------------------" - - # 提示使用者輸入外掛名稱 - read -e -p "請輸入要安裝的插件名稱(輸入 0 退出):" plugin_name - - # 1. 檢查是否輸入 0 退出 - if [ "$plugin_name" = "0" ]; then - echo "操作已取消,退出插件安裝。" - break - fi - - # 2. 驗證輸入是否為空 - if [ -z "$plugin_name" ]; then - echo "錯誤:插件名稱不能為空,請重新輸入。" - echo "" - continue - fi - - # 1. 徹底清理之前失敗的殘留(使用者目錄) - rm -rf "/root/.openclaw/extensions/$plugin_name" - - # 2. 檢查系統是否已預先安裝(防止 duplicate id 衝突) - if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_name" ]; then - echo "💡 偵測到系統目錄已存在該插件,正在直接啟動..." - openclaw plugins enable "$plugin_name" - else - echo "📥 正在透過官方管道下載安裝插件..." - # 使用 openclaw 自己的 install 指令,它會自動處理 package.json 的規格檢查 - openclaw plugins install "$plugin_name" - - # 3. 如果 openclaw install 報錯,再嘗試作為普通 npm 套件安裝(最後的備選) - if [ $? -ne 0 ]; then - echo "⚠️ 官方安裝失敗,嘗試透過 npm 全域強制安裝..." - npm install -g "$plugin_name" --unsafe-perm - fi - - # 4. 最後統一執行啟用 - openclaw plugins enable "$plugin_name" - fi - - start_gateway - break_end - done - } - - install_plugin() { + install_plugin() { send_stats "安裝插件" while true; do clear @@ -10319,7 +10328,7 @@ EOF echo "⚙️ 功能擴充:" echo "- [lobster] # 審批流 (附人工確認)" echo "- [voice-call] # 語音通話能力" - echo "- [nostr] # 加密隱私聊天" + echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" read -e -p "請輸入外掛 ID(輸入 0 退出):" raw_input @@ -10332,6 +10341,8 @@ EOF local plugin_full="$raw_input" echo "🔍 正在檢查插件狀態..." + # 取得目前插件清單用於狀態檢測 + local plugin_list=$(openclaw plugins list 2>/dev/null) # 2. 檢查是否已經在 list 中且為 disabled (最常見的情況) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then @@ -10426,14 +10437,29 @@ EOF continue fi - # 3. 執行安裝指令 - echo "正在安裝技能:$skill_name ..." - npx clawhub install "$skill_name" + # 3. 檢查技能是否已安裝 + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在使用者目錄安裝。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系統目錄安裝。" + skill_found=true + fi - # 取得上一條指令的退出狀態 - if [ $? -eq 0 ]; then + if [ "$skill_found" = true ]; then + read -e -p "是否重新安裝? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + echo "跳過安裝。" + break_end + continue + fi + fi + + # 4. 執行安裝指令 + echo "正在安裝技能:$skill_name ..." + if npx clawhub install "$skill_name"; then echo "✅ 技能$skill_name安裝成功。" - # 執行重啟/啟動服務邏輯 start_gateway else echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文件排查。" @@ -10441,29 +10467,56 @@ EOF break_end done - } change_tg_bot_code() { send_stats "機器人對接" - read -e -p "請輸入TG機器人收到的連線碼 (例如 Pairing code: NYA99R2F)(輸入 0 退出):" code - - # 檢查是否輸入 0 退出 - if [ "$code" = "0" ]; then - echo "操作已取消。" - return 0 # 正常退出函数 - fi - - # 驗證輸入是否為空 - if [ -z "$code" ]; then - echo "錯誤:連接碼不能為空。請重試。" - return 1 - fi + while true; do + clear + echo "========================================" + echo "機器人連線對接" + echo "========================================" + echo "1. Telegram 機器人對接" + echo "2. 飛書 (Lark) 機器人對接" + echo "3. WhatsApp 機器人對接" + echo "----------------------------------------" + echo "0. 返回上一級選單" + echo "----------------------------------------" + read -e -p "請輸入你的選擇:" bot_choice - openclaw pairing approve telegram $code - break_end + case $bot_choice in + 1) + read -e -p "請輸入TG機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "請輸入飛書機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done } @@ -10487,6 +10540,7 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - + rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -10542,7 +10596,7 @@ EOF domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -10570,6 +10624,19 @@ EOF echo "先造訪URL觸發設備ID,然後回車下一步進行配對。" read echo -e "${gl_kjlan}正在載入設備列表…${gl_bai}" + # 自動新增網域到 allowedOrigins + config_file="$HOME/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + new_origin="https://${yuming}" + # 使用 jq 安全性修改 JSON,確保結構存在且不重複新增域名 + if command -v jq >/dev/null 2>&1; then + tmp_json=$(mktemp) + jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" + echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" + openclaw gateway restart >/dev/null 2>&1 + fi + fi + openclaw devices list read -e -p "請輸入 Request_Key:" Request_Key @@ -10650,8 +10717,12 @@ EOF break_end ;; 13) openclaw_webui_menu ;; - 14) update_moltbot ;; - 15) uninstall_moltbot ;; + 14) send_stats "TUI命令列對話" + openclaw tui + break_end + ;; + 15) update_moltbot ;; + 16) uninstall_moltbot ;; *) break ;; esac done @@ -10702,7 +10773,7 @@ while true; do echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" @@ -10751,11 +10822,11 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" - echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" + echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" - echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" + echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -11257,8 +11328,8 @@ while true; do local docker_describe="禪道是通用的專案管理軟體" local docker_url="官網介紹: https://www.zentao.net/" - local docker_use="echo \"初始使用者名稱: admin\"" - local docker_passwd="echo \"初始密碼: 123456\"" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" local app_size="2" docker_app @@ -11477,7 +11548,7 @@ while true; do check_docker_app clear echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -11512,7 +11583,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已經更新完成" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -14020,7 +14091,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -14356,7 +14427,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一個功能強大的多格式文件轉換工具(支援文件、圖像、音訊視訊等)強烈建議添加域名訪問" - local docker_url="項目地址:${gh_https_url}github.com/c4illin/ConvertX" + local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -14783,9 +14854,12 @@ fail2ban_panel() { echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" - echo "2. 查看SSH攔截記錄" + echo "2. 查看SSH拦截记录" echo "3. 日誌即時監控" echo "------------------------" + echo "4. 基礎參數配置(封禁時間/時間視窗/重試次數)" + echo "5. 編輯設定檔(nano)" + echo "------------------------" echo "9. 卸載防禦程序" echo "------------------------" echo "0. 返回上一級選單" @@ -14808,6 +14882,16 @@ fail2ban_panel() { tail -f /var/log/fail2ban.log break ;; + 4) + send_stats "SSH防禦基礎參數配置" + f2b_basic_config + break_end + ;; + 5) + send_stats "SSH防禦編輯設定檔" + f2b_edit_config + break_end + ;; 9) remove fail2ban rm -rf /etc/fail2ban @@ -15222,7 +15306,7 @@ linux_Settings() { echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高風險漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux核心升級${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令列美化工具${gl_huang}★${gl_bai}" @@ -15563,7 +15647,7 @@ EOF echo "------------------------" echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" - echo "5. 刪除帳號" + echo "5. 删除账号" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -16174,7 +16258,7 @@ EOF echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo -e "5. 啟動fail2ban防禦SSH暴力破解" echo -e "6. 開放所有端口" - echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" @@ -16210,7 +16294,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 5/12. 啟動fail2ban防禦SSH暴力破解" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 開放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" bbr_on @@ -16373,7 +16457,7 @@ linux_file() { echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" - echo "25. 傳文件至其他伺服器" + echo "25. 传文件至其他服务器" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -16381,7 +16465,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 - read -e -p "請輸入目錄名:" dirname + read -e -p "请输入目录名: " dirname cd "$dirname" 2>/dev/null || echo "無法進入目錄" send_stats "進入目錄" ;; @@ -16429,7 +16513,7 @@ linux_file() { send_stats "修改檔案權限" ;; 14) # 重命名文件 - read -e -p "請輸入目前檔名:" current_name + read -e -p "请输入当前文件名: " current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" @@ -16446,7 +16530,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -16655,7 +16739,7 @@ while true; do 4) clear send_stats "備份叢集" - echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai}檔案下載,完成備份!" + echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai} 文件下载,完成备份!" break_end ;; @@ -16718,7 +16802,7 @@ echo "廣告專欄" echo "------------------------" echo "將為用戶提供更簡單優雅的推廣與購買體驗!" echo "" -echo -e "伺服器優惠" +echo -e "服务器优惠" echo "------------------------" echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活動${gl_bai}" echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" From dc802ea880e327d1dd143bee60dc2f1ba0ada9f3 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 8 Mar 2026 00:56:01 +0800 Subject: [PATCH 0924/1285] test(openclaw): add manager smoke and matrix scripts --- run_openclaw_manager_matrix.sh | 38 +++++++++++++++++ tests_openclaw_manager_smoke.sh | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100755 run_openclaw_manager_matrix.sh create mode 100755 tests_openclaw_manager_smoke.sh diff --git a/run_openclaw_manager_matrix.sh b/run_openclaw_manager_matrix.sh new file mode 100755 index 000000000..95f34521c --- /dev/null +++ b/run_openclaw_manager_matrix.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")" + +IMAGES=( + "debian:12" + "debian:13" + "ubuntu:22.04" + "ubuntu:24.04" + "rockylinux:9" + "almalinux:9" + "fedora:41" +) + +install_cmd() { + case "$1" in + debian:*|ubuntu:*) + echo 'apt-get update -y >/dev/null && DEBIAN_FRONTEND=noninteractive apt-get install -y bash jq grep sed coreutils >/dev/null' + ;; + rockylinux:*|almalinux:*|fedora:*) + echo 'dnf install -y bash jq grep sed coreutils >/dev/null' + ;; + *) + return 1 + ;; + esac +} + +for img in "${IMAGES[@]}"; do + echo "===== $img =====" + cmd=$(install_cmd "$img") + if docker run --rm -v "$PWD":/src -w /src "$img" bash -lc "$cmd && bash -n kejilion.sh && ./tests_openclaw_manager_smoke.sh"; then + echo "RESULT $img OK" + else + echo "RESULT $img FAIL" + fi + echo + done diff --git a/tests_openclaw_manager_smoke.sh b/tests_openclaw_manager_smoke.sh new file mode 100755 index 000000000..851b950f5 --- /dev/null +++ b/tests_openclaw_manager_smoke.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-manager-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" +trap 'rm -rf "$WORKDIR"' EXIT + +cat > "$WORKDIR/harness.sh" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +EOF +sed -n '10053,10162p' "$SCRIPT" >> "$WORKDIR/harness.sh" +printf '\n' >> "$WORKDIR/harness.sh" +sed -n '10562,10610p' "$SCRIPT" >> "$WORKDIR/harness.sh" +printf '\n' >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +cat > "$WORKDIR/bin/curl" <<'EOF' +#!/usr/bin/env bash +if [[ "$*" == *"/models"* ]]; then + cat < "$WORKDIR/bin/openclaw" <<'EOF' +#!/usr/bin/env bash +if [[ "${1:-}" == "dashboard" ]]; then + echo "Dashboard: http://127.0.0.1:18789/#token=deadbeef" +else + echo "mock openclaw $*" +fi +EOF +chmod +x "$WORKDIR/bin/openclaw" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{"models":{"mode":"merge","providers":{}}} +JSON + +mkdir -p /home/web/conf.d +cat > /home/web/conf.d/test-openclaw.conf <<'EOF' +server { + listen 443 ssl; + server_name claw.example.com; + location / { + proxy_pass http://127.0.0.1:18789; + } +} +EOF + +source "$WORKDIR/harness.sh" + +echo '[TEST] add-all-models-from-provider' +add-all-models-from-provider "cli-api" "https://example.com/v1" "dummy-token" >/tmp/add-models.out +jq -e '.models.providers["cli-api"].models | length == 3' "$HOME/.openclaw/openclaw.json" >/dev/null +jq -r '.models.providers["cli-api"].models[].id' "$HOME/.openclaw/openclaw.json" + +echo '[TEST] openclaw_find_webui_domain' +openclaw_find_webui_domain + +echo '[TEST] openclaw_show_webui_addr' +openclaw_show_webui_addr + +echo 'SMOKE_OK' From b3868bc7f37f68ac29febcf8d91dde66310f7f78 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 8 Mar 2026 23:05:54 +0800 Subject: [PATCH 0925/1285] feat(openclaw): apply session continuity policy during install --- kejilion.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index b68dac542..55a5929ae 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9997,6 +9997,36 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -10014,6 +10044,7 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + configure_openclaw_session_policy start_gateway add_app_id break_end From dd04fbacd5a95218a970465ae3b2b8730902545a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 8 Mar 2026 23:10:00 +0800 Subject: [PATCH 0926/1285] docs: note OpenClaw session continuity install default --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 2d3af3c87..0eac001d9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1476,4 +1476,5 @@ SSH防御菜单新增基础参数配置功能,支持交互式设置封禁时 SSH防御菜单新增配置文件编辑功能,使用nano直接编辑jail配置。 SSH防御优化Alpine系统jail名称检测,默认使用sshd,仅检测到自定义规则时切换alpine-sshd。 SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜像启动失败。 +应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊默认7天连续、线程1天、群聊2小时,避免用户将默认 session 重置误判为“记忆失效”。 ------------------------ From ba87f17d1b690cfc1354b5b60c019bf69391386b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 8 Mar 2026 23:13:11 +0800 Subject: [PATCH 0927/1285] fix(openclaw): sync CN installer session continuity policy --- cn/kejilion.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f5e312ae7..ddcb4dcbb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9997,6 +9997,36 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -10014,6 +10044,7 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + configure_openclaw_session_policy start_gateway add_app_id break_end From 14f0b6000a8cc1ab58f103ca543417c34465e356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:15:34 +0800 Subject: [PATCH 0928/1285] Update OpenClaw session continuity policy wording --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 0eac001d9..748c60743 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1476,5 +1476,5 @@ SSH防御菜单新增基础参数配置功能,支持交互式设置封禁时 SSH防御菜单新增配置文件编辑功能,使用nano直接编辑jail配置。 SSH防御优化Alpine系统jail名称检测,默认使用sshd,仅检测到自定义规则时切换alpine-sshd。 SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜像启动失败。 -应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊默认7天连续、线程1天、群聊2小时,避免用户将默认 session 重置误判为“记忆失效”。 +应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊7天连续、线程1天、群聊2小时,避免重置误判为“失忆”。 ------------------------ From b222b7d974838b1061beb0a42fe6ca84ef7293b0 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 11:33:41 +0800 Subject: [PATCH 0929/1285] feat(openclaw): sync provider models after doctor fix with safe fallback --- cn/kejilion.sh | 208 ++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 209 +++++++++++++++++++++++++++++++++++++++++++- kejilion_sh_log.txt | 6 ++ 3 files changed, 421 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ddcb4dcbb..20c26fc97 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.5" gl_hui='\e[37m' @@ -10027,6 +10027,207 @@ with open(path, 'w', encoding='utf-8') as f: PY } + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" <<'PY' +import copy +import json +import sys +import urllib.request + +path = sys.argv[1] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +for name, provider in providers.items(): + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') + continue + + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + + try: + with urllib.request.urlopen(req, timeout=12) as resp: + data = json.loads(resp.read().decode('utf-8', 'ignore')) + except Exception as e: + summary.append(f'⚠️ 跳过 {name}: 探测失败 ({type(e).__name__}: {e})') + continue + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') +else: + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') +PY + } + + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -10745,6 +10946,11 @@ EOF ;; 12) send_stats "健康检测与修复" openclaw doctor --fix + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" + fi break_end ;; 13) openclaw_webui_menu ;; diff --git a/kejilion.sh b/kejilion.sh index 55a5929ae..5e62446f8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.5" gl_hui='\e[37m' @@ -10027,6 +10027,208 @@ with open(path, 'w', encoding='utf-8') as f: PY } + + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" <<'PY' +import copy +import json +import sys +import urllib.request + +path = sys.argv[1] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +for name, provider in providers.items(): + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') + continue + + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + + try: + with urllib.request.urlopen(req, timeout=12) as resp: + data = json.loads(resp.read().decode('utf-8', 'ignore')) + except Exception as e: + summary.append(f'⚠️ 跳过 {name}: 探测失败 ({type(e).__name__}: {e})') + continue + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') +else: + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') +PY + } + + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." @@ -10745,6 +10947,11 @@ EOF ;; 12) send_stats "健康检测与修复" openclaw doctor --fix + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" + fi break_end ;; 13) openclaw_webui_menu ;; diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 748c60743..75f5d4d25 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1478,3 +1478,9 @@ SSH防御优化Alpine系统jail名称检测,默认使用sshd,仅检测到自 SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜像启动失败。 应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊7天连续、线程1天、群聊2小时,避免重置误判为“失忆”。 ------------------------ +2026-03-09 v4.4.5 +应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。 +应用市场中OpenClaw管理,API模型同步只对提供商存在模型进行保留。 +应用市场中OpenClaw管理,API提供商新增的模型将自动添加本地列表。 +应用市场中OpenClaw管理,强制维护本地配置的默认模型与模型回退逻辑。 +应用市场中OpenClaw管理,提供商无可用模型会直接判定失败并中止重启。 From 7e511f736ae67a2bbb2e996460aa28b5516e6755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 9 Mar 2026 11:51:36 +0800 Subject: [PATCH 0930/1285] Refine OpenClaw API model synchronization details Updated OpenClaw management log to reflect changes in API model synchronization and local list handling. --- kejilion_sh_log.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 75f5d4d25..baaf6e8ea 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1479,8 +1479,4 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊7天连续、线程1天、群聊2小时,避免重置误判为“失忆”。 ------------------------ 2026-03-09 v4.4.5 -应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。 -应用市场中OpenClaw管理,API模型同步只对提供商存在模型进行保留。 -应用市场中OpenClaw管理,API提供商新增的模型将自动添加本地列表。 -应用市场中OpenClaw管理,强制维护本地配置的默认模型与模型回退逻辑。 -应用市场中OpenClaw管理,提供商无可用模型会直接判定失败并中止重启。 +应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。上游删除则本地删除、上游新增本地新增。 From cb383150ffe263838b04038ae9c96346cb5b4fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 9 Mar 2026 11:52:01 +0800 Subject: [PATCH 0931/1285] Update OpenClaw management log with new features --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index baaf6e8ea..d13873d76 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1480,3 +1480,4 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 ------------------------ 2026-03-09 v4.4.5 应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。上游删除则本地删除、上游新增本地新增。 + From 9ee0e36228b50268546d07840664e820ee8969f6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 12:13:45 +0800 Subject: [PATCH 0932/1285] feat(openclaw): sync provider fetched models into defaults.models --- cn/kejilion.sh | 18 +++++++++++++++++- kejilion.sh | 18 +++++++++++++++++- kejilion_sh_log.txt | 8 ++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 20c26fc97..809039997 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10365,7 +10365,7 @@ EOF # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型 + # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10381,6 +10381,22 @@ EOF models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then diff --git a/kejilion.sh b/kejilion.sh index 5e62446f8..ad7c694d1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10366,7 +10366,7 @@ EOF # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型 + # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10382,6 +10382,22 @@ EOF models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index d13873d76..c0d49f7fc 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1479,5 +1479,9 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊7天连续、线程1天、群聊2小时,避免重置误判为“失忆”。 ------------------------ 2026-03-09 v4.4.5 -应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。上游删除则本地删除、上游新增本地新增。 - +应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。 +应用市场中OpenClaw管理,API模型同步只对提供商存在模型进行保留。 +应用市场中OpenClaw管理,API提供商新增的模型将自动添加本地列表。 +应用市场中OpenClaw管理,强制维护本地配置的默认模型与模型回退逻辑。 +应用市场中OpenClaw管理,提供商无可用模型会直接判定失败并中止重启。 +应用市场中OpenClaw管理,添加API拉取模型后会同步写入 defaults.models 默认列表。 From e057a8d7dac0511f6ddf71a2c16cffc405b6e252 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 12:27:14 +0800 Subject: [PATCH 0933/1285] feat(openclaw): provider /models fail retry+manual-delete flow with safe default rebinding --- cn/kejilion.sh | 137 +++++++++++++++++++++++++++++++++++++++----- kejilion.sh | 137 +++++++++++++++++++++++++++++++++++++++----- kejilion_sh_log.txt | 7 +++ 3 files changed, 253 insertions(+), 28 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 809039997..9dd83d890 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10038,6 +10038,7 @@ PY import copy import json import sys +import time import urllib.request path = sys.argv[1] @@ -10095,7 +10096,115 @@ def set_primary_ref(defaults_obj, new_ref): defaults_obj['model'] = {'primary': new_ref} -for name, provider in providers.items(): +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): if not isinstance(provider, dict): summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') continue @@ -10113,21 +10222,20 @@ for name, provider in providers.items(): summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') continue - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - - try: - with urllib.request.urlopen(req, timeout=12) as resp: - data = json.loads(resp.read().decode('utf-8', 'ignore')) - except Exception as e: - summary.append(f'⚠️ 跳过 {name}: 探测失败 ({type(e).__name__}: {e})') + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') continue @@ -10228,6 +10336,7 @@ PY } + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." diff --git a/kejilion.sh b/kejilion.sh index ad7c694d1..66c702a7f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10039,6 +10039,7 @@ PY import copy import json import sys +import time import urllib.request path = sys.argv[1] @@ -10096,7 +10097,115 @@ def set_primary_ref(defaults_obj, new_ref): defaults_obj['model'] = {'primary': new_ref} -for name, provider in providers.items(): +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): if not isinstance(provider, dict): summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') continue @@ -10114,21 +10223,20 @@ for name, provider in providers.items(): summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') continue - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - - try: - with urllib.request.urlopen(req, timeout=12) as resp: - data = json.loads(resp.read().decode('utf-8', 'ignore')) - except Exception as e: - summary.append(f'⚠️ 跳过 {name}: 探测失败 ({type(e).__name__}: {e})') + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') continue @@ -10229,6 +10337,7 @@ PY } + install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c0d49f7fc..c11a838fe 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1485,3 +1485,10 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,强制维护本地配置的默认模型与模型回退逻辑。 应用市场中OpenClaw管理,提供商无可用模型会直接判定失败并中止重启。 应用市场中OpenClaw管理,添加API拉取模型后会同步写入 defaults.models 默认列表。 +------------------------ +2026-03-09 v4.4.5 +应用市场中OpenClaw管理,API提供商 /models 探测失败时新增3次自动重试机制,避免偶发网络抖动误判。 +应用市场中OpenClaw管理,连续探测失败后不再自动删除提供商,改为进入人工确认流程。 +应用市场中OpenClaw管理,人工确认删除时将删除 models.providers. 整个节点,并同步清理 defaults.models 下该提供商全部模型引用。 +应用市场中OpenClaw管理,删除前自动检查并切换默认主模型与模型回退项(modelFallback / imageModelFallback)到其他可用提供商模型。 +应用市场中OpenClaw管理,当无可用替代模型时将中止删除流程,防止默认模型链路被破坏。 From 09f7b050a8c8607a3edd5a807b160048c7569430 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:13:26 +0800 Subject: [PATCH 0934/1285] feat(openclaw): add API management submenu with provider listing and safe delete --- cn/kejilion.sh | 252 ++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 252 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 500 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9dd83d890..c838d6a47 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9956,7 +9956,7 @@ moltbot_menu() { echo "--------------------" echo "4. 状态日志查看" echo "5. 换模型" - echo "6. 加新模型API" + echo "6. API管理" echo "7. 机器人连接对接" echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" @@ -10616,6 +10616,254 @@ EOF } + openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + + python3 - "$config_file" <<'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('ℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) +except Exception as e: + print(f'❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + +print('--- 已配置 API 列表 ---') +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + print(f'{idx}. {name} | 地址: - | 模型数: 0 | 延迟: 不可用') + continue + + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + ms = ping_models(base_url, api_key) + latency = f'{ms}ms' + except Exception: + latency = '不可用' + else: + latency = '不可用' + + print(f'{idx}. {name} | 地址: {base_url} | 模型数: {model_count} | 延迟: {latency}') +PY + } + + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要删除的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ 已删除 provider: {name}') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') +PY + local rc=$? + case "$rc" in + 0) + echo "✅ 删除完成" + start_gateway + ;; + 2) + echo "❌ 删除失败:provider 不存在" + ;; + 3) + echo "❌ 删除失败:无可用替代模型,已保持原配置" + ;; + *) + echo "❌ 删除失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "API管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw API 管理" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. 添加API" + echo "2. 删除API" + echo "0. 返回上一级" + echo "---------------------------------------" + read -erp "请输入你的选择: " api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + delete-openclaw-provider-interactive + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + change_model() { send_stats "换模型" @@ -11060,7 +11308,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; diff --git a/kejilion.sh b/kejilion.sh index 66c702a7f..8d93aadb3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9956,7 +9956,7 @@ moltbot_menu() { echo "--------------------" echo "4. 状态日志查看" echo "5. 换模型" - echo "6. 加新模型API" + echo "6. API管理" echo "7. 机器人连接对接" echo "8. 安装插件(如:飞书)" echo "9. 安装技能(skills)" @@ -10617,6 +10617,254 @@ EOF } + openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + + python3 - "$config_file" <<'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('ℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) +except Exception as e: + print(f'❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + +print('--- 已配置 API 列表 ---') +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + print(f'{idx}. {name} | 地址: - | 模型数: 0 | 延迟: 不可用') + continue + + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + ms = ping_models(base_url, api_key) + latency = f'{ms}ms' + except Exception: + latency = '不可用' + else: + latency = '不可用' + + print(f'{idx}. {name} | 地址: {base_url} | 模型数: {model_count} | 延迟: {latency}') +PY + } + + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要删除的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ 已删除 provider: {name}') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') +PY + local rc=$? + case "$rc" in + 0) + echo "✅ 删除完成" + start_gateway + ;; + 2) + echo "❌ 删除失败:provider 不存在" + ;; + 3) + echo "❌ 删除失败:无可用替代模型,已保持原配置" + ;; + *) + echo "❌ 删除失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "API管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw API 管理" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. 添加API" + echo "2. 删除API" + echo "0. 返回上一级" + echo "---------------------------------------" + read -erp "请输入你的选择: " api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + delete-openclaw-provider-interactive + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + change_model() { send_stats "换模型" @@ -11061,7 +11309,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; From 7bd9c3e0434c78def93f1582f0a8ba639763cb17 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:16:25 +0800 Subject: [PATCH 0935/1285] feat(openclaw): add API management submenu --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c11a838fe..903ca088d 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1492,3 +1492,4 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,人工确认删除时将删除 models.providers. 整个节点,并同步清理 defaults.models 下该提供商全部模型引用。 应用市场中OpenClaw管理,删除前自动检查并切换默认主模型与模型回退项(modelFallback / imageModelFallback)到其他可用提供商模型。 应用市场中OpenClaw管理,当无可用替代模型时将中止删除流程,防止默认模型链路被破坏。 +应用市场中OpenClaw管理,主菜单新增API管理二级菜单,可查看列表、添加API与安全删除API。 From cf172236a492a681bc2a1320e0f1fdaa624a8b28 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:31:00 +0800 Subject: [PATCH 0936/1285] feat(openclaw): align API manage list columns with model/latency colors --- cn/kejilion.sh | 125 ++++++++++++++++++++++++++++++++++++++++--------- kejilion.sh | 125 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 206 insertions(+), 44 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c838d6a47..68e1c663b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10619,13 +10619,54 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" - python3 - "$config_file" <<'PY' + python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' import json import sys import time +import unicodedata import urllib.request path = sys.argv[1] +C_YELLOW = sys.argv[2] if len(sys.argv) > 2 else '' +C_GREEN = sys.argv[3] if len(sys.argv) > 3 else '' +C_RED = sys.argv[4] if len(sys.argv) > 4 else '' +C_WHITE = sys.argv[5] if len(sys.argv) > 5 else '' +C_BLUE = sys.argv[6] if len(sys.argv) > 6 and sys.argv[6] else C_WHITE +C_RESET = C_WHITE if C_WHITE else '\033[0m' + + +def colorize(text, color): + return f'{color}{text}{C_RESET}' if color else text + + +def char_width(ch): + return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 + + +def text_width(text): + return sum(char_width(ch) for ch in str(text)) + + +def trim_to_width(text, width): + s = str(text) + if text_width(s) <= width: + return s + reserve = 3 + out = [] + w = 0 + for ch in s: + cw = char_width(ch) + if w + cw > max(width - reserve, 0): + break + out.append(ch) + w += cw + return ''.join(out) + '...' + + +def pad_text(text, width): + s = trim_to_width(text, width) + return s + ' ' * max(width - text_width(s), 0) + try: with open(path, 'r', encoding='utf-8') as f: @@ -10658,31 +10699,71 @@ def ping_models(base_url, api_key): resp.read(2048) return int((time.perf_counter() - start) * 1000) + +def latency_label_and_color(latency): + if latency == '不可用': + return latency, C_RED + if latency == '未检测': + return latency, C_BLUE + if isinstance(latency, int): + if latency < 800: + return f'{latency}ms', C_GREEN + return f'{latency}ms', C_YELLOW + return str(latency), C_BLUE + + +IDX_W = 4 +NAME_W = 18 +URL_W = 44 +MODEL_W = 8 +LAT_W = 12 + print('--- 已配置 API 列表 ---') +header = ( + f"{pad_text('序号', IDX_W)} " + f"{pad_text('名称', NAME_W)} " + f"{pad_text('API地址', URL_W)} " + f"{pad_text('模型数量', MODEL_W)} " + f"{pad_text('延迟/状态', LAT_W)}" +) +print(header) +print('-' * text_width(header)) + for idx, name in enumerate(sorted(providers.keys()), start=1): provider = providers.get(name) if not isinstance(provider, dict): - print(f'{idx}. {name} | 地址: - | 模型数: 0 | 延迟: 不可用') - continue - - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - ms = ping_models(base_url, api_key) - latency = f'{ms}ms' - except Exception: - latency = '不可用' - else: - latency = '不可用' - - print(f'{idx}. {name} | 地址: {base_url} | 模型数: {model_count} | 延迟: {latency}') + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + model_txt = pad_text(str(model_count), MODEL_W) + latency_txt, latency_color = latency_label_and_color(latency_raw) + latency_txt = pad_text(latency_txt, LAT_W) + + row = ( + f"{pad_text(str(idx) + '.', IDX_W)} " + f"{pad_text(name, NAME_W)} " + f"{pad_text(base_url, URL_W)} " + f"{colorize(model_txt, C_YELLOW)} " + f"{colorize(latency_txt, latency_color)}" + ) + print(row) PY } diff --git a/kejilion.sh b/kejilion.sh index 8d93aadb3..f0f7c65ca 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10620,13 +10620,54 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" - python3 - "$config_file" <<'PY' + python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' import json import sys import time +import unicodedata import urllib.request path = sys.argv[1] +C_YELLOW = sys.argv[2] if len(sys.argv) > 2 else '' +C_GREEN = sys.argv[3] if len(sys.argv) > 3 else '' +C_RED = sys.argv[4] if len(sys.argv) > 4 else '' +C_WHITE = sys.argv[5] if len(sys.argv) > 5 else '' +C_BLUE = sys.argv[6] if len(sys.argv) > 6 and sys.argv[6] else C_WHITE +C_RESET = C_WHITE if C_WHITE else '\033[0m' + + +def colorize(text, color): + return f'{color}{text}{C_RESET}' if color else text + + +def char_width(ch): + return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 + + +def text_width(text): + return sum(char_width(ch) for ch in str(text)) + + +def trim_to_width(text, width): + s = str(text) + if text_width(s) <= width: + return s + reserve = 3 + out = [] + w = 0 + for ch in s: + cw = char_width(ch) + if w + cw > max(width - reserve, 0): + break + out.append(ch) + w += cw + return ''.join(out) + '...' + + +def pad_text(text, width): + s = trim_to_width(text, width) + return s + ' ' * max(width - text_width(s), 0) + try: with open(path, 'r', encoding='utf-8') as f: @@ -10659,31 +10700,71 @@ def ping_models(base_url, api_key): resp.read(2048) return int((time.perf_counter() - start) * 1000) + +def latency_label_and_color(latency): + if latency == '不可用': + return latency, C_RED + if latency == '未检测': + return latency, C_BLUE + if isinstance(latency, int): + if latency < 800: + return f'{latency}ms', C_GREEN + return f'{latency}ms', C_YELLOW + return str(latency), C_BLUE + + +IDX_W = 4 +NAME_W = 18 +URL_W = 44 +MODEL_W = 8 +LAT_W = 12 + print('--- 已配置 API 列表 ---') +header = ( + f"{pad_text('序号', IDX_W)} " + f"{pad_text('名称', NAME_W)} " + f"{pad_text('API地址', URL_W)} " + f"{pad_text('模型数量', MODEL_W)} " + f"{pad_text('延迟/状态', LAT_W)}" +) +print(header) +print('-' * text_width(header)) + for idx, name in enumerate(sorted(providers.keys()), start=1): provider = providers.get(name) if not isinstance(provider, dict): - print(f'{idx}. {name} | 地址: - | 模型数: 0 | 延迟: 不可用') - continue - - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - ms = ping_models(base_url, api_key) - latency = f'{ms}ms' - except Exception: - latency = '不可用' - else: - latency = '不可用' - - print(f'{idx}. {name} | 地址: {base_url} | 模型数: {model_count} | 延迟: {latency}') + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + model_txt = pad_text(str(model_count), MODEL_W) + latency_txt, latency_color = latency_label_and_color(latency_raw) + latency_txt = pad_text(latency_txt, LAT_W) + + row = ( + f"{pad_text(str(idx) + '.', IDX_W)} " + f"{pad_text(name, NAME_W)} " + f"{pad_text(base_url, URL_W)} " + f"{colorize(model_txt, C_YELLOW)} " + f"{colorize(latency_txt, latency_color)}" + ) + print(row) PY } From cf27001c80631c03f2a67b499e8cf33a7cc93453 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:36:04 +0800 Subject: [PATCH 0937/1285] feat(openclaw): add API manage send_stats telemetry points --- cn/kejilion.sh | 43 ++++++++++++++++++++++++++++++++++++++++--- kejilion.sh | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 68e1c663b..264df0162 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10034,14 +10034,42 @@ PY install jq curl >/dev/null 2>&1 - python3 - "$config_file" <<'PY' + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' import copy import json +import os +import platform import sys import time import urllib.request +from datetime import datetime, timezone path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -10225,11 +10253,14 @@ for name, provider in list(providers.items()): data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: + send_stat('OpenClaw API删失败Provider-确认') summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') else: + send_stat('OpenClaw API删失败Provider-拒绝') summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue @@ -10519,7 +10550,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "添加API" + send_stats "OpenClaw API添加" echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" # 1. Provider 名称 @@ -10618,6 +10649,7 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API列表" python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' import json @@ -10769,6 +10801,7 @@ PY delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到配置文件: $config_file" @@ -10778,6 +10811,7 @@ PY read -erp "请输入要删除的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then + send_stats "OpenClaw API删除取消" echo "❌ provider 名称不能为空" break_end return 1 @@ -10895,6 +10929,7 @@ PY local rc=$? case "$rc" in 0) + send_stats "OpenClaw API删除确认" echo "✅ 删除完成" start_gateway ;; @@ -10902,6 +10937,7 @@ PY echo "❌ 删除失败:provider 不存在" ;; 3) + send_stats "OpenClaw API删除取消" echo "❌ 删除失败:无可用替代模型,已保持原配置" ;; *) @@ -10913,7 +10949,7 @@ PY } openclaw_api_manage_menu() { - send_stats "API管理" + send_stats "OpenClaw API入口" while true; do clear echo "=======================================" @@ -11400,6 +11436,7 @@ PY ;; 12) send_stats "健康检测与修复" openclaw doctor --fix + send_stats "OpenClaw API同步触发" if sync_openclaw_api_models; then start_gateway else diff --git a/kejilion.sh b/kejilion.sh index f0f7c65ca..6d0b8653d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10035,14 +10035,42 @@ PY install jq curl >/dev/null 2>&1 - python3 - "$config_file" <<'PY' + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' import copy import json +import os +import platform import sys import time import urllib.request +from datetime import datetime, timezone path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -10226,11 +10254,14 @@ for name, provider in list(providers.items()): data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: + send_stat('OpenClaw API删失败Provider-确认') summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') else: + send_stat('OpenClaw API删失败Provider-拒绝') summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue @@ -10520,7 +10551,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "添加API" + send_stats "OpenClaw API添加" echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" # 1. Provider 名称 @@ -10619,6 +10650,7 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API列表" python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' import json @@ -10770,6 +10802,7 @@ PY delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到配置文件: $config_file" @@ -10779,6 +10812,7 @@ PY read -erp "请输入要删除的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then + send_stats "OpenClaw API删除取消" echo "❌ provider 名称不能为空" break_end return 1 @@ -10896,6 +10930,7 @@ PY local rc=$? case "$rc" in 0) + send_stats "OpenClaw API删除确认" echo "✅ 删除完成" start_gateway ;; @@ -10903,6 +10938,7 @@ PY echo "❌ 删除失败:provider 不存在" ;; 3) + send_stats "OpenClaw API删除取消" echo "❌ 删除失败:无可用替代模型,已保持原配置" ;; *) @@ -10914,7 +10950,7 @@ PY } openclaw_api_manage_menu() { - send_stats "API管理" + send_stats "OpenClaw API入口" while true; do clear echo "=======================================" @@ -11401,6 +11437,7 @@ PY ;; 12) send_stats "健康检测与修复" openclaw doctor --fix + send_stats "OpenClaw API同步触发" if sync_openclaw_api_models; then start_gateway else From 0c39f98dc440c812e0958732af36d12322fbf330 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:44:02 +0800 Subject: [PATCH 0938/1285] =?UTF-8?q?feat(openclaw):=20API=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E6=98=8E=E6=96=87=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=B8=8E=E6=A8=A1=E5=9E=8B=E6=A0=87=E7=AD=BE=E5=85=9C=E5=BA=95?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 10 +++++----- kejilion.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 264df0162..718738d06 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10734,13 +10734,13 @@ def ping_models(base_url, api_key): def latency_label_and_color(latency): if latency == '不可用': - return latency, C_RED + return '不可用', C_RED if latency == '未检测': - return latency, C_BLUE + return '未检测', C_BLUE if isinstance(latency, int): if latency < 800: - return f'{latency}ms', C_GREEN - return f'{latency}ms', C_YELLOW + return f'低 {latency}ms', C_GREEN + return f'中 {latency}ms', C_YELLOW return str(latency), C_BLUE @@ -10784,7 +10784,7 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): else: latency_raw = '不可用' - model_txt = pad_text(str(model_count), MODEL_W) + model_txt = pad_text(f'模型{model_count}', MODEL_W) latency_txt, latency_color = latency_label_and_color(latency_raw) latency_txt = pad_text(latency_txt, LAT_W) diff --git a/kejilion.sh b/kejilion.sh index 6d0b8653d..19e7b0fb0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10735,13 +10735,13 @@ def ping_models(base_url, api_key): def latency_label_and_color(latency): if latency == '不可用': - return latency, C_RED + return '不可用', C_RED if latency == '未检测': - return latency, C_BLUE + return '未检测', C_BLUE if isinstance(latency, int): if latency < 800: - return f'{latency}ms', C_GREEN - return f'{latency}ms', C_YELLOW + return f'低 {latency}ms', C_GREEN + return f'中 {latency}ms', C_YELLOW return str(latency), C_BLUE @@ -10785,7 +10785,7 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): else: latency_raw = '不可用' - model_txt = pad_text(str(model_count), MODEL_W) + model_txt = pad_text(f'模型{model_count}', MODEL_W) latency_txt, latency_color = latency_label_and_color(latency_raw) latency_txt = pad_text(latency_txt, LAT_W) From b7339bf0e807bdab245eb8a6c2e21eed9cea901e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:48:11 +0800 Subject: [PATCH 0939/1285] revert openclaw api list to plain text status/model display --- cn/kejilion.sh | 21 +++++++++------------ kejilion.sh | 21 +++++++++------------ 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 718738d06..86747a1be 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10732,16 +10732,14 @@ def ping_models(base_url, api_key): return int((time.perf_counter() - start) * 1000) -def latency_label_and_color(latency): +def format_latency(latency): if latency == '不可用': - return '不可用', C_RED + return '不可用' if latency == '未检测': - return '未检测', C_BLUE + return '未检测' if isinstance(latency, int): - if latency < 800: - return f'低 {latency}ms', C_GREEN - return f'中 {latency}ms', C_YELLOW - return str(latency), C_BLUE + return f'{latency}ms' + return str(latency) IDX_W = 4 @@ -10784,16 +10782,15 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): else: latency_raw = '不可用' - model_txt = pad_text(f'模型{model_count}', MODEL_W) - latency_txt, latency_color = latency_label_and_color(latency_raw) - latency_txt = pad_text(latency_txt, LAT_W) + model_txt = pad_text(str(model_count), MODEL_W) + latency_txt = pad_text(format_latency(latency_raw), LAT_W) row = ( f"{pad_text(str(idx) + '.', IDX_W)} " f"{pad_text(name, NAME_W)} " f"{pad_text(base_url, URL_W)} " - f"{colorize(model_txt, C_YELLOW)} " - f"{colorize(latency_txt, latency_color)}" + f"{model_txt} " + f"{latency_txt}" ) print(row) PY diff --git a/kejilion.sh b/kejilion.sh index 19e7b0fb0..1b685091b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10733,16 +10733,14 @@ def ping_models(base_url, api_key): return int((time.perf_counter() - start) * 1000) -def latency_label_and_color(latency): +def format_latency(latency): if latency == '不可用': - return '不可用', C_RED + return '不可用' if latency == '未检测': - return '未检测', C_BLUE + return '未检测' if isinstance(latency, int): - if latency < 800: - return f'低 {latency}ms', C_GREEN - return f'中 {latency}ms', C_YELLOW - return str(latency), C_BLUE + return f'{latency}ms' + return str(latency) IDX_W = 4 @@ -10785,16 +10783,15 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): else: latency_raw = '不可用' - model_txt = pad_text(f'模型{model_count}', MODEL_W) - latency_txt, latency_color = latency_label_and_color(latency_raw) - latency_txt = pad_text(latency_txt, LAT_W) + model_txt = pad_text(str(model_count), MODEL_W) + latency_txt = pad_text(format_latency(latency_raw), LAT_W) row = ( f"{pad_text(str(idx) + '.', IDX_W)} " f"{pad_text(name, NAME_W)} " f"{pad_text(base_url, URL_W)} " - f"{colorize(model_txt, C_YELLOW)} " - f"{colorize(latency_txt, latency_color)}" + f"{model_txt} " + f"{latency_txt}" ) print(row) PY From 72a152a3c5e2edd0e7a209331dab5ac0a96a4a59 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 13:56:21 +0800 Subject: [PATCH 0940/1285] refactor(openclaw): shell-side API list coloring and aligned output --- cn/kejilion.sh | 310 ++++++++++++++------------ kejilion.sh | 310 ++++++++++++++------------ tests_openclaw_api_color_align_min.sh | 40 ++++ 3 files changed, 370 insertions(+), 290 deletions(-) create mode 100755 tests_openclaw_api_color_align_min.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 86747a1be..56590572e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10650,152 +10650,172 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" - - python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' -import json -import sys -import time -import unicodedata -import urllib.request - -path = sys.argv[1] -C_YELLOW = sys.argv[2] if len(sys.argv) > 2 else '' -C_GREEN = sys.argv[3] if len(sys.argv) > 3 else '' -C_RED = sys.argv[4] if len(sys.argv) > 4 else '' -C_WHITE = sys.argv[5] if len(sys.argv) > 5 else '' -C_BLUE = sys.argv[6] if len(sys.argv) > 6 and sys.argv[6] else C_WHITE -C_RESET = C_WHITE if C_WHITE else '\033[0m' - - -def colorize(text, color): - return f'{color}{text}{C_RESET}' if color else text - - -def char_width(ch): - return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 - - -def text_width(text): - return sum(char_width(ch) for ch in str(text)) - - -def trim_to_width(text, width): - s = str(text) - if text_width(s) <= width: - return s - reserve = 3 - out = [] - w = 0 - for ch in s: - cw = char_width(ch) - if w + cw > max(width - reserve, 0): - break - out.append(ch) - w += cw - return ''.join(out) + '...' - - -def pad_text(text, width): - s = trim_to_width(text, width) - return s + ' ' * max(width - text_width(s), 0) - - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('ℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) -except Exception as e: - print(f'❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) - -providers = ((obj.get('models') or {}).get('providers') or {}) -if not isinstance(providers, dict) or not providers: - print('ℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) - -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} - - -def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) - - -def format_latency(latency): - if latency == '不可用': - return '不可用' - if latency == '未检测': - return '未检测' - if isinstance(latency, int): - return f'{latency}ms' - return str(latency) - - -IDX_W = 4 -NAME_W = 18 -URL_W = 44 -MODEL_W = 8 -LAT_W = 12 - -print('--- 已配置 API 列表 ---') -header = ( - f"{pad_text('序号', IDX_W)} " - f"{pad_text('名称', NAME_W)} " - f"{pad_text('API地址', URL_W)} " - f"{pad_text('模型数量', MODEL_W)} " - f"{pad_text('延迟/状态', LAT_W)}" -) -print(header) -print('-' * text_width(header)) - -for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - model_txt = pad_text(str(model_count), MODEL_W) - latency_txt = pad_text(format_latency(latency_raw), LAT_W) - - row = ( - f"{pad_text(str(idx) + '.', IDX_W)} " - f"{pad_text(name, NAME_W)} " - f"{pad_text(base_url, URL_W)} " - f"{model_txt} " - f"{latency_txt}" - ) - print(row) -PY + + while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + HEADER) + printf "%s\n" "$idx" + ;; + SEP) + printf "%s\n" "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf "%s %-4s %-18s %-44s %s%-8s%s %s%-12s%s\n" \ + "" "$idx" "$name" "$base_url" \ + "$gl_huang" "$model_count" "$gl_bai" \ + "$latency_color" "$latency_txt" "$gl_bai" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' + import json + import sys + import time + import unicodedata + import urllib.request + + path = sys.argv[1] + SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + + def char_width(ch): + return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 + + + def text_width(text): + return sum(char_width(ch) for ch in str(text)) + + + def trim_to_width(text, width): + s = str(text) + if text_width(s) <= width: + return s + reserve = 3 + out = [] + w = 0 + for ch in s: + cw = char_width(ch) + if w + cw > max(width - reserve, 0): + break + out.append(ch) + w += cw + return ''.join(out) + '...' + + + def pad_text(text, width): + s = trim_to_width(text, width) + return s + ' ' * max(width - text_width(s), 0) + + + def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + + def classify_latency(latency): + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + + IDX_W = 4 + NAME_W = 18 + URL_W = 44 + MODEL_W = 8 + LAT_W = 12 + + try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + except FileNotFoundError: + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) + except Exception as e: + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + + providers = ((obj.get('models') or {}).get('providers') or {}) + if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + + print('MSG\t--- 已配置 API 列表 ---') + header = ( + f"{pad_text('序号', IDX_W)} " + f"{pad_text('名称', NAME_W)} " + f"{pad_text('API地址', URL_W)} " + f"{pad_text('模型数量', MODEL_W)} " + f"{pad_text('延迟/状态', LAT_W)}" + ) + print(f'HEADER\t{header}') + print(f'SEP\t{"-" * text_width(header)}') + + for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + print( + 'ROW\t' + '\t'.join([ + pad_text(str(idx) + '.', IDX_W), + pad_text(name, NAME_W), + pad_text(base_url, URL_W), + pad_text(str(model_count), MODEL_W), + pad_text(latency_text, LAT_W), + latency_level, + ]) + ) + PY + ) } - delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" diff --git a/kejilion.sh b/kejilion.sh index 1b685091b..f67b493d3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10651,152 +10651,172 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" - - python3 - "$config_file" "${gl_huang}" "${gl_lv}" "${gl_hong}" "${gl_bai}" "${gl_kjlan}" <<'PY' -import json -import sys -import time -import unicodedata -import urllib.request - -path = sys.argv[1] -C_YELLOW = sys.argv[2] if len(sys.argv) > 2 else '' -C_GREEN = sys.argv[3] if len(sys.argv) > 3 else '' -C_RED = sys.argv[4] if len(sys.argv) > 4 else '' -C_WHITE = sys.argv[5] if len(sys.argv) > 5 else '' -C_BLUE = sys.argv[6] if len(sys.argv) > 6 and sys.argv[6] else C_WHITE -C_RESET = C_WHITE if C_WHITE else '\033[0m' - - -def colorize(text, color): - return f'{color}{text}{C_RESET}' if color else text - - -def char_width(ch): - return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 - - -def text_width(text): - return sum(char_width(ch) for ch in str(text)) - - -def trim_to_width(text, width): - s = str(text) - if text_width(s) <= width: - return s - reserve = 3 - out = [] - w = 0 - for ch in s: - cw = char_width(ch) - if w + cw > max(width - reserve, 0): - break - out.append(ch) - w += cw - return ''.join(out) + '...' - - -def pad_text(text, width): - s = trim_to_width(text, width) - return s + ' ' * max(width - text_width(s), 0) - - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('ℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) -except Exception as e: - print(f'❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) - -providers = ((obj.get('models') or {}).get('providers') or {}) -if not isinstance(providers, dict) or not providers: - print('ℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) - -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} - - -def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) - - -def format_latency(latency): - if latency == '不可用': - return '不可用' - if latency == '未检测': - return '未检测' - if isinstance(latency, int): - return f'{latency}ms' - return str(latency) - - -IDX_W = 4 -NAME_W = 18 -URL_W = 44 -MODEL_W = 8 -LAT_W = 12 - -print('--- 已配置 API 列表 ---') -header = ( - f"{pad_text('序号', IDX_W)} " - f"{pad_text('名称', NAME_W)} " - f"{pad_text('API地址', URL_W)} " - f"{pad_text('模型数量', MODEL_W)} " - f"{pad_text('延迟/状态', LAT_W)}" -) -print(header) -print('-' * text_width(header)) - -for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - model_txt = pad_text(str(model_count), MODEL_W) - latency_txt = pad_text(format_latency(latency_raw), LAT_W) - - row = ( - f"{pad_text(str(idx) + '.', IDX_W)} " - f"{pad_text(name, NAME_W)} " - f"{pad_text(base_url, URL_W)} " - f"{model_txt} " - f"{latency_txt}" - ) - print(row) -PY + + while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + HEADER) + printf "%s\n" "$idx" + ;; + SEP) + printf "%s\n" "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf "%s %-4s %-18s %-44s %s%-8s%s %s%-12s%s\n" \ + "" "$idx" "$name" "$base_url" \ + "$gl_huang" "$model_count" "$gl_bai" \ + "$latency_color" "$latency_txt" "$gl_bai" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' + import json + import sys + import time + import unicodedata + import urllib.request + + path = sys.argv[1] + SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + + def char_width(ch): + return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 + + + def text_width(text): + return sum(char_width(ch) for ch in str(text)) + + + def trim_to_width(text, width): + s = str(text) + if text_width(s) <= width: + return s + reserve = 3 + out = [] + w = 0 + for ch in s: + cw = char_width(ch) + if w + cw > max(width - reserve, 0): + break + out.append(ch) + w += cw + return ''.join(out) + '...' + + + def pad_text(text, width): + s = trim_to_width(text, width) + return s + ' ' * max(width - text_width(s), 0) + + + def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + + def classify_latency(latency): + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + + IDX_W = 4 + NAME_W = 18 + URL_W = 44 + MODEL_W = 8 + LAT_W = 12 + + try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + except FileNotFoundError: + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) + except Exception as e: + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + + providers = ((obj.get('models') or {}).get('providers') or {}) + if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + + print('MSG\t--- 已配置 API 列表 ---') + header = ( + f"{pad_text('序号', IDX_W)} " + f"{pad_text('名称', NAME_W)} " + f"{pad_text('API地址', URL_W)} " + f"{pad_text('模型数量', MODEL_W)} " + f"{pad_text('延迟/状态', LAT_W)}" + ) + print(f'HEADER\t{header}') + print(f'SEP\t{"-" * text_width(header)}') + + for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + print( + 'ROW\t' + '\t'.join([ + pad_text(str(idx) + '.', IDX_W), + pad_text(name, NAME_W), + pad_text(base_url, URL_W), + pad_text(str(model_count), MODEL_W), + pad_text(latency_text, LAT_W), + latency_level, + ]) + ) + PY + ) } - delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" diff --git a/tests_openclaw_api_color_align_min.sh b/tests_openclaw_api_color_align_min.sh new file mode 100755 index 000000000..5005d0927 --- /dev/null +++ b/tests_openclaw_api_color_align_min.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 模拟脚本原生颜色变量 +# shellcheck disable=SC2034 +gl_hong='\033[31m' +# shellcheck disable=SC2034 +gl_lv='\033[32m' +# shellcheck disable=SC2034 +gl_huang='\033[33m' +# shellcheck disable=SC2034 +gl_bai='\033[0m' + +printf '%s\n' '--- OpenClaw API 列表(最小颜色/对齐验证) ---' +printf '%-4s %-18s %-44s %-8s %-12s\n' '序号' '名称' 'API地址' '模型数量' '延迟/状态' +printf '%s\n' '----------------------------------------------------------------------------------------------' + +# 模拟 Python 计算后的字段(纯数据,不含颜色码) +while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + [[ "$rec_type" == "ROW" ]] || continue + + latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + # 颜色在 Shell 层拼接并输出 + printf '%-4s %-18s %-44s %b%-8s%b %b%-12s%b\n' \ + "$idx" "$name" "$base_url" \ + "$gl_huang" "$model_count" "$gl_bai" \ + "$latency_color" "$latency_txt" "$gl_bai" +done <<'EOF' +ROW 1. alpha-openai https://api.alpha.example/v1 128 120ms low +ROW 2. beta-proxy https://api.beta.example/v1 64 1300ms medium +ROW 3. gamma-down https://api.gamma.example/v1 0 不可用 unavailable +ROW 4. delta-custom - 12 未检测 unchecked +EOF From 9356b076b1e02267e46e1d6110c1b9682f9bb98e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 14:03:41 +0800 Subject: [PATCH 0941/1285] feat(openclaw-api): add provider-scoped model sync in API manage menu --- cn/kejilion.sh | 238 ++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 238 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 472 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 56590572e..db2c9a517 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10816,6 +10816,236 @@ EOF PY ) } + +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API按Provider同步" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要同步的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') + raise SystemExit(3) + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') +if changed: + print('✅ 指定 provider 模型一致性同步完成并已写入配置') +else: + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ 同步执行完成" + start_gateway + ;; + 2) + echo "❌ 同步失败:provider 不存在或未配置" + ;; + 3) + echo "❌ 同步失败:provider 配置不完整或类型不支持" + ;; + 4) + echo "❌ 同步失败:上游 /models 请求失败" + ;; + 5) + echo "❌ 同步失败:上游模型为空或同步后无可用模型" + ;; + *) + echo "❌ 同步失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end +} + delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" @@ -10975,8 +11205,9 @@ PY openclaw_api_manage_list echo "---------------------------------------" echo "1. 添加API" - echo "2. 删除API" - echo "0. 返回上一级" + echo "2. 同步API供应商模型列表" + echo "3. 删除API" + echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -10985,6 +11216,9 @@ PY add-openclaw-provider-interactive ;; 2) + sync-openclaw-provider-interactive + ;; + 3) delete-openclaw-provider-interactive ;; 0) diff --git a/kejilion.sh b/kejilion.sh index f67b493d3..0f36ee144 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10817,6 +10817,236 @@ EOF PY ) } + +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API按Provider同步" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要同步的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') + raise SystemExit(3) + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') +if changed: + print('✅ 指定 provider 模型一致性同步完成并已写入配置') +else: + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ 同步执行完成" + start_gateway + ;; + 2) + echo "❌ 同步失败:provider 不存在或未配置" + ;; + 3) + echo "❌ 同步失败:provider 配置不完整或类型不支持" + ;; + 4) + echo "❌ 同步失败:上游 /models 请求失败" + ;; + 5) + echo "❌ 同步失败:上游模型为空或同步后无可用模型" + ;; + *) + echo "❌ 同步失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end +} + delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" @@ -10976,8 +11206,9 @@ PY openclaw_api_manage_list echo "---------------------------------------" echo "1. 添加API" - echo "2. 删除API" - echo "0. 返回上一级" + echo "2. 同步API供应商模型列表" + echo "3. 删除API" + echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -10986,6 +11217,9 @@ PY add-openclaw-provider-interactive ;; 2) + sync-openclaw-provider-interactive + ;; + 3) delete-openclaw-provider-interactive ;; 0) From ddd9294b4c95729af372dde472eebc3b0afc37cc Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 14:19:20 +0800 Subject: [PATCH 0942/1285] refactor(openclaw): switch API list to line-based colored output --- cn/kejilion.sh | 282 ++++++++++++++++++++----------------------------- kejilion.sh | 282 ++++++++++++++++++++----------------------------- 2 files changed, 228 insertions(+), 336 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index db2c9a517..372e1e024 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10647,176 +10647,122 @@ EOF } - openclaw_api_manage_list() { - local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API列表" - - while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do - case "$rec_type" in - MSG) - echo "$idx" - ;; - HEADER) - printf "%s\n" "$idx" - ;; - SEP) - printf "%s\n" "$idx" - ;; - ROW) - local latency_color="$gl_bai" - case "$latency_level" in - low) latency_color="$gl_lv" ;; - medium) latency_color="$gl_huang" ;; - high|unavailable) latency_color="$gl_hong" ;; - unchecked) latency_color="$gl_bai" ;; - esac - - printf "%s %-4s %-18s %-44s %s%-8s%s %s%-12s%s\n" \ - "" "$idx" "$name" "$base_url" \ - "$gl_huang" "$model_count" "$gl_bai" \ - "$latency_color" "$latency_txt" "$gl_bai" - ;; - esac - done < <(python3 - "$config_file" <<-'PY' - import json - import sys - import time - import unicodedata - import urllib.request - - path = sys.argv[1] - SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} - - - def char_width(ch): - return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 - - - def text_width(text): - return sum(char_width(ch) for ch in str(text)) - - - def trim_to_width(text, width): - s = str(text) - if text_width(s) <= width: - return s - reserve = 3 - out = [] - w = 0 - for ch in s: - cw = char_width(ch) - if w + cw > max(width - reserve, 0): - break - out.append(ch) - w += cw - return ''.join(out) + '...' - - def pad_text(text, width): - s = trim_to_width(text, width) - return s + ' ' * max(width - text_width(s), 0) - - - def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) - - - def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' - - - IDX_W = 4 - NAME_W = 18 - URL_W = 44 - MODEL_W = 8 - LAT_W = 12 - - try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) - except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) - - providers = ((obj.get('models') or {}).get('providers') or {}) - if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) - - print('MSG\t--- 已配置 API 列表 ---') - header = ( - f"{pad_text('序号', IDX_W)} " - f"{pad_text('名称', NAME_W)} " - f"{pad_text('API地址', URL_W)} " - f"{pad_text('模型数量', MODEL_W)} " - f"{pad_text('延迟/状态', LAT_W)}" - ) - print(f'HEADER\t{header}') - print(f'SEP\t{"-" * text_width(header)}') - - for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - print( - 'ROW\t' + '\t'.join([ - pad_text(str(idx) + '.', IDX_W), - pad_text(name, NAME_W), - pad_text(base_url, URL_W), - pad_text(str(model_count), MODEL_W), - pad_text(latency_text, LAT_W), - latency_level, - ]) - ) - PY - ) - } +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API列表" + while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf '%b\n' "[$idx] ${name} | API: ${base_url} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + +print('MSG\t--- 已配置 API 列表 ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API按Provider同步" diff --git a/kejilion.sh b/kejilion.sh index 0f36ee144..81714f0e4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10648,176 +10648,122 @@ EOF } - openclaw_api_manage_list() { - local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API列表" - - while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do - case "$rec_type" in - MSG) - echo "$idx" - ;; - HEADER) - printf "%s\n" "$idx" - ;; - SEP) - printf "%s\n" "$idx" - ;; - ROW) - local latency_color="$gl_bai" - case "$latency_level" in - low) latency_color="$gl_lv" ;; - medium) latency_color="$gl_huang" ;; - high|unavailable) latency_color="$gl_hong" ;; - unchecked) latency_color="$gl_bai" ;; - esac - - printf "%s %-4s %-18s %-44s %s%-8s%s %s%-12s%s\n" \ - "" "$idx" "$name" "$base_url" \ - "$gl_huang" "$model_count" "$gl_bai" \ - "$latency_color" "$latency_txt" "$gl_bai" - ;; - esac - done < <(python3 - "$config_file" <<-'PY' - import json - import sys - import time - import unicodedata - import urllib.request - - path = sys.argv[1] - SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} - - - def char_width(ch): - return 2 if unicodedata.east_asian_width(ch) in ('W', 'F') else 1 - - - def text_width(text): - return sum(char_width(ch) for ch in str(text)) - - - def trim_to_width(text, width): - s = str(text) - if text_width(s) <= width: - return s - reserve = 3 - out = [] - w = 0 - for ch in s: - cw = char_width(ch) - if w + cw > max(width - reserve, 0): - break - out.append(ch) - w += cw - return ''.join(out) + '...' - - def pad_text(text, width): - s = trim_to_width(text, width) - return s + ' ' * max(width - text_width(s), 0) - - - def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) - - - def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' - - - IDX_W = 4 - NAME_W = 18 - URL_W = 44 - MODEL_W = 8 - LAT_W = 12 - - try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) - except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) - - providers = ((obj.get('models') or {}).get('providers') or {}) - if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) - - print('MSG\t--- 已配置 API 列表 ---') - header = ( - f"{pad_text('序号', IDX_W)} " - f"{pad_text('名称', NAME_W)} " - f"{pad_text('API地址', URL_W)} " - f"{pad_text('模型数量', MODEL_W)} " - f"{pad_text('延迟/状态', LAT_W)}" - ) - print(f'HEADER\t{header}') - print(f'SEP\t{"-" * text_width(header)}') - - for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - print( - 'ROW\t' + '\t'.join([ - pad_text(str(idx) + '.', IDX_W), - pad_text(name, NAME_W), - pad_text(base_url, URL_W), - pad_text(str(model_count), MODEL_W), - pad_text(latency_text, LAT_W), - latency_level, - ]) - ) - PY - ) - } +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API列表" + while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf '%b\n' "[$idx] ${name} | API: ${base_url} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) + +print('MSG\t--- 已配置 API 列表 ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API按Provider同步" From 5ec309a3d52aa95c7b292c77aabdd47dc21a0f54 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 14:30:25 +0800 Subject: [PATCH 0943/1285] chore(log): condense v4.4.5 changelog wording --- kejilion_sh_log.txt | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 903ca088d..8c957d15e 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1479,17 +1479,6 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,安装流程新增会话连续性策略配置:私聊7天连续、线程1天、群聊2小时,避免重置误判为“失忆”。 ------------------------ 2026-03-09 v4.4.5 -应用市场中OpenClaw管理,健康检测后将自动进行API模型同步。 -应用市场中OpenClaw管理,API模型同步只对提供商存在模型进行保留。 -应用市场中OpenClaw管理,API提供商新增的模型将自动添加本地列表。 -应用市场中OpenClaw管理,强制维护本地配置的默认模型与模型回退逻辑。 -应用市场中OpenClaw管理,提供商无可用模型会直接判定失败并中止重启。 -应用市场中OpenClaw管理,添加API拉取模型后会同步写入 defaults.models 默认列表。 ------------------------- -2026-03-09 v4.4.5 -应用市场中OpenClaw管理,API提供商 /models 探测失败时新增3次自动重试机制,避免偶发网络抖动误判。 -应用市场中OpenClaw管理,连续探测失败后不再自动删除提供商,改为进入人工确认流程。 -应用市场中OpenClaw管理,人工确认删除时将删除 models.providers. 整个节点,并同步清理 defaults.models 下该提供商全部模型引用。 -应用市场中OpenClaw管理,删除前自动检查并切换默认主模型与模型回退项(modelFallback / imageModelFallback)到其他可用提供商模型。 -应用市场中OpenClaw管理,当无可用替代模型时将中止删除流程,防止默认模型链路被破坏。 -应用市场中OpenClaw管理,主菜单新增API管理二级菜单,可查看列表、添加API与安全删除API。 +应用市场中OpenClaw管理,健康检测后支持API模型自动一致性同步,新增模型自动写入defaults.models,并维护默认模型与回退链路安全切换。 +应用市场中OpenClaw管理,API管理菜单支持查看列表、按提供商同步模型、删除API,且对/models探测失败增加3次重试与人工确认删除机制。 + From 757e54e0e83a2b8fe80a41ed72f97ba473cd5a38 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 14:44:06 +0800 Subject: [PATCH 0944/1285] chore(menu): rename OpenClaw app market entry --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 372e1e024..e02291045 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11758,7 +11758,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" diff --git a/kejilion.sh b/kejilion.sh index 81714f0e4..290c63b58 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11759,7 +11759,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}ClawdBot/Moltbot机器人${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" From 6fef98f0cf922b41677ea5383b626019502f6278 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 21:15:49 +0800 Subject: [PATCH 0945/1285] feat(openclaw): add lightweight local bot connection status block --- cn/kejilion.sh | 188 +++++++++++++++++++++++++++++++++++++++++++++++++ kejilion.sh | 188 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e02291045..d686a2f78 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11390,6 +11390,192 @@ PY + openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "异常" + elif [ "$enabled" != "true" ]; then + echo "未启用" + elif [ "$connected" = "true" ]; then + echo "已连接" + elif [ "$configured" = "true" ]; then + echo "已配置" + else + echo "未配置" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "本地状态(仅本机配置/缓存,不做网络探测):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + change_tg_bot_code() { send_stats "机器人对接" while true; do @@ -11397,6 +11583,8 @@ PY echo "========================================" echo " 机器人连接对接 " echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" diff --git a/kejilion.sh b/kejilion.sh index 290c63b58..80feda8fa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11391,6 +11391,192 @@ PY + openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "异常" + elif [ "$enabled" != "true" ]; then + echo "未启用" + elif [ "$connected" = "true" ]; then + echo "已连接" + elif [ "$configured" = "true" ]; then + echo "已配置" + else + echo "未配置" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "本地状态(仅本机配置/缓存,不做网络探测):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + change_tg_bot_code() { send_stats "机器人对接" while true; do @@ -11398,6 +11584,8 @@ PY echo "========================================" echo " 机器人连接对接 " echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" From 5f8fb84c6823325bdffb6deb28b58daaf7a7c235 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 9 Mar 2026 23:37:25 +0800 Subject: [PATCH 0946/1285] feat(openclaw): auto-sync plugins.allow after plugin install --- cn/kejilion.sh | 90 +++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 90 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d686a2f78..d57ee5593 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11217,6 +11217,90 @@ PY } + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + return 0 + fi + fi + + echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" + return 1 + } + + install_plugin() { @@ -11256,7 +11340,7 @@ PY [ -z "$raw_input" ] && continue # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_id=$(resolve_openclaw_plugin_id "$raw_input") local plugin_full="$raw_input" echo "🔍 正在检查插件状态..." @@ -11299,6 +11383,10 @@ PY fi fi + echo "🔐 正在同步 plugins.allow 白名单..." + sync_openclaw_plugin_allowlist "$plugin_id" + + echo "🔄 正在重启 OpenClaw 服务以加载新插件..." start_gateway break_end diff --git a/kejilion.sh b/kejilion.sh index 80feda8fa..94df8c1a4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11218,6 +11218,90 @@ PY } + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + return 0 + fi + fi + + echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" + return 1 + } + + install_plugin() { @@ -11257,7 +11341,7 @@ PY [ -z "$raw_input" ] && continue # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') + local plugin_id=$(resolve_openclaw_plugin_id "$raw_input") local plugin_full="$raw_input" echo "🔍 正在检查插件状态..." @@ -11300,6 +11384,10 @@ PY fi fi + echo "🔐 正在同步 plugins.allow 白名单..." + sync_openclaw_plugin_allowlist "$plugin_id" + + echo "🔄 正在重启 OpenClaw 服务以加载新插件..." start_gateway break_end From 5c4d0ea2ff44e121f3d67b0560e9d4419557e19e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 01:36:39 +0800 Subject: [PATCH 0947/1285] feat(openclaw): add backup & restore submenu with secure import/export --- cn/kejilion.sh | 447 ++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 447 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 886 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d57ee5593..abc207c6e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9966,8 +9966,9 @@ moltbot_menu() { echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" echo "--------------------" - echo "15. 更新" - echo "16. 卸载" + echo "15. 备份与还原" + echo "16. 更新" + echo "17. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -11715,6 +11716,443 @@ PYTHON_EOF } + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null 2>&1 && openclaw_is_interactive_terminal; then + echo "检测到交互终端与 sz,可选快速下载。" + read -e -p "是否使用 sz 发送备份文件?(y/N): " send_by_sz + if [[ "$send_by_sz" =~ ^[Yy]$ ]]; then + sz "$file_path" + return + fi + fi + echo "可使用以下方式下载备份文件:" + echo "- 本地路径: $file_path" + echo "- scp 示例: scp root@你的服务器:$file_path ./" + echo "- 或使用 SFTP 客户端下载" + } + + openclaw_prepare_import_archive() { + local expected_type="$1" + local archive_path="$2" + local unpack_root="$3" + + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } + mkdir -p "$unpack_root" + tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 备份包解压失败"; return 1; } + + local pkg_dir="$unpack_root/package" + if [ -f "$unpack_root/backup.meta" ]; then + pkg_dir="$unpack_root" + fi + + for required in backup.meta manifest.files manifest.sha256 payload; do + [ -e "$pkg_dir/$required" ] || { echo "❌ 备份包缺少必要文件: $required"; return 1; } + done + + local real_type + real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) + if [ "$real_type" != "$expected_type" ]; then + echo "❌ 备份类型不匹配,期望: $expected_type,实际: ${real_type:-未知}" + return 1 + fi + + ( + cd "$pkg_dir/payload" || exit 1 + sha256sum -c ../manifest.sha256 >/dev/null + ) || { echo "❌ sha256 校验失败,拒绝导入"; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw记忆全量导出" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ 未找到 workspace 目录: $workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可导出的记忆文件" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ 记忆备份导出完成: $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ 记忆备份导出失败" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_path + echo "$prompt_text" >&2 + if command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then + echo "提示:检测到 rz,可输入 rz 后回车上传,再输入本机保存路径。" >&2 + fi + read -e -p "请输入备份文件路径: " file_path + if [ "$file_path" = "rz" ] && command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then + rz + read -e -p "上传完成,请输入备份文件路径: " file_path + fi + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw记忆全量导入" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "导入前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ 检测到非法或越权路径: $rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 导入中止:存在不安全路径" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local snapshot_file="$backup_root/pre-import-memory-$(date +%Y%m%d-%H%M%S).tar.gz" + local snapshot_targets=() + while IFS= read -r rel; do + [ -e "$workspace_dir/$rel" ] && snapshot_targets+=("$rel") + done < "$valid_list" + if [ ${#snapshot_targets[@]} -gt 0 ]; then + ( cd "$workspace_dir" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) + echo "🧷 已创建导入前快照: $snapshot_file" + fi + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ 记忆全量导入完成" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw项目导出" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" + break_end + return 1 + fi + + echo "导出模式:" + echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "2. 完整模式(含更多状态,敏感风险更高)" + read -e -p "请选择导出模式(默认 1): " export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + if [ -e "$openclaw_root/$d" ]; then + mkdir -p "$tmp_payload/full-extra" + cp -a "$openclaw_root/$d" "$tmp_payload/full-extra/" + fi + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可导出的 OpenClaw 项目内容" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw 项目导出完成 (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw 项目导出失败" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw项目导入" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ 高风险操作:项目导入会覆盖 OpenClaw 配置与工作区内容。" + echo "⚠️ 导入前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + read -e -p "请输入确认词【我已知晓高风险并继续导入】后继续: " confirm_text + if [ "$confirm_text" != "我已知晓高风险并继续导入" ]; then + echo "❌ 确认词不匹配,已取消导入" + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ 检测到非法或越权路径: $rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 导入中止:存在不安全路径" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local snapshot_file="$backup_root/pre-import-project-$(date +%Y%m%d-%H%M%S).tar.gz" + local snapshot_targets=() + while IFS= read -r rel; do + [ -e "$openclaw_root/$rel" ] && snapshot_targets+=("$rel") + done < "$valid_list" + if [ ${#snapshot_targets[@]} -gt 0 ]; then + ( cd "$openclaw_root" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) + echo "🧷 已创建导入前快照: $snapshot_file" + fi + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ 导入前停止 OpenClaw gateway..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ 导入后启动 OpenClaw gateway..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 gateway 健康检查:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw 项目导入完成" + break_end + } + + openclaw_backup_list_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + echo "备份目录: $backup_root" + ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + break_end + } + + openclaw_backup_restore_menu() { + send_stats "OpenClaw备份与还原" + while true; do + clear + echo "=======================================" + echo "OpenClaw 备份与还原" + echo "=======================================" + echo "1. 导出记忆全量" + echo "2. 导入记忆全量" + echo "3. 导出 OpenClaw 项目(默认安全模式)" + echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "5. 查看备份文件" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_list_files ;; + 0) return 0 ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." @@ -11922,8 +12360,9 @@ PYTHON_EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_backup_restore_menu ;; + 16) update_moltbot ;; + 17) uninstall_moltbot ;; *) break ;; esac done diff --git a/kejilion.sh b/kejilion.sh index 94df8c1a4..fc8993c70 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9966,8 +9966,9 @@ moltbot_menu() { echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" echo "--------------------" - echo "15. 更新" - echo "16. 卸载" + echo "15. 备份与还原" + echo "16. 更新" + echo "17. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -11716,6 +11717,443 @@ PYTHON_EOF } + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null 2>&1 && openclaw_is_interactive_terminal; then + echo "检测到交互终端与 sz,可选快速下载。" + read -e -p "是否使用 sz 发送备份文件?(y/N): " send_by_sz + if [[ "$send_by_sz" =~ ^[Yy]$ ]]; then + sz "$file_path" + return + fi + fi + echo "可使用以下方式下载备份文件:" + echo "- 本地路径: $file_path" + echo "- scp 示例: scp root@你的服务器:$file_path ./" + echo "- 或使用 SFTP 客户端下载" + } + + openclaw_prepare_import_archive() { + local expected_type="$1" + local archive_path="$2" + local unpack_root="$3" + + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } + mkdir -p "$unpack_root" + tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 备份包解压失败"; return 1; } + + local pkg_dir="$unpack_root/package" + if [ -f "$unpack_root/backup.meta" ]; then + pkg_dir="$unpack_root" + fi + + for required in backup.meta manifest.files manifest.sha256 payload; do + [ -e "$pkg_dir/$required" ] || { echo "❌ 备份包缺少必要文件: $required"; return 1; } + done + + local real_type + real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) + if [ "$real_type" != "$expected_type" ]; then + echo "❌ 备份类型不匹配,期望: $expected_type,实际: ${real_type:-未知}" + return 1 + fi + + ( + cd "$pkg_dir/payload" || exit 1 + sha256sum -c ../manifest.sha256 >/dev/null + ) || { echo "❌ sha256 校验失败,拒绝导入"; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw记忆全量导出" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ 未找到 workspace 目录: $workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可导出的记忆文件" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ 记忆备份导出完成: $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ 记忆备份导出失败" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_path + echo "$prompt_text" >&2 + if command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then + echo "提示:检测到 rz,可输入 rz 后回车上传,再输入本机保存路径。" >&2 + fi + read -e -p "请输入备份文件路径: " file_path + if [ "$file_path" = "rz" ] && command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then + rz + read -e -p "上传完成,请输入备份文件路径: " file_path + fi + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw记忆全量导入" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "导入前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ 检测到非法或越权路径: $rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 导入中止:存在不安全路径" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local snapshot_file="$backup_root/pre-import-memory-$(date +%Y%m%d-%H%M%S).tar.gz" + local snapshot_targets=() + while IFS= read -r rel; do + [ -e "$workspace_dir/$rel" ] && snapshot_targets+=("$rel") + done < "$valid_list" + if [ ${#snapshot_targets[@]} -gt 0 ]; then + ( cd "$workspace_dir" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) + echo "🧷 已创建导入前快照: $snapshot_file" + fi + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ 记忆全量导入完成" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw项目导出" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" + break_end + return 1 + fi + + echo "导出模式:" + echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "2. 完整模式(含更多状态,敏感风险更高)" + read -e -p "请选择导出模式(默认 1): " export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + if [ -e "$openclaw_root/$d" ]; then + mkdir -p "$tmp_payload/full-extra" + cp -a "$openclaw_root/$d" "$tmp_payload/full-extra/" + fi + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可导出的 OpenClaw 项目内容" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw 项目导出完成 (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw 项目导出失败" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw项目导入" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ 高风险操作:项目导入会覆盖 OpenClaw 配置与工作区内容。" + echo "⚠️ 导入前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + read -e -p "请输入确认词【我已知晓高风险并继续导入】后继续: " confirm_text + if [ "$confirm_text" != "我已知晓高风险并继续导入" ]; then + echo "❌ 确认词不匹配,已取消导入" + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ 检测到非法或越权路径: $rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 导入中止:存在不安全路径" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local snapshot_file="$backup_root/pre-import-project-$(date +%Y%m%d-%H%M%S).tar.gz" + local snapshot_targets=() + while IFS= read -r rel; do + [ -e "$openclaw_root/$rel" ] && snapshot_targets+=("$rel") + done < "$valid_list" + if [ ${#snapshot_targets[@]} -gt 0 ]; then + ( cd "$openclaw_root" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) + echo "🧷 已创建导入前快照: $snapshot_file" + fi + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ 导入前停止 OpenClaw gateway..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ 导入后启动 OpenClaw gateway..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 gateway 健康检查:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw 项目导入完成" + break_end + } + + openclaw_backup_list_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + echo "备份目录: $backup_root" + ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + break_end + } + + openclaw_backup_restore_menu() { + send_stats "OpenClaw备份与还原" + while true; do + clear + echo "=======================================" + echo "OpenClaw 备份与还原" + echo "=======================================" + echo "1. 导出记忆全量" + echo "2. 导入记忆全量" + echo "3. 导出 OpenClaw 项目(默认安全模式)" + echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "5. 查看备份文件" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_list_files ;; + 0) return 0 ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." @@ -11923,8 +12361,9 @@ PYTHON_EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_backup_restore_menu ;; + 16) update_moltbot ;; + 17) uninstall_moltbot ;; *) break ;; esac done From 8d8965d6f885c395839f3c44b4d8d27db3f6937f Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 07:21:47 +0800 Subject: [PATCH 0948/1285] refactor(openclaw): show backup list in restore panel and remove extra menu item --- cn/kejilion.sh | 10 +++++++--- kejilion.sh | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index abc207c6e..71d237d47 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12112,12 +12112,16 @@ EOF break_end } - openclaw_backup_list_files() { + openclaw_backup_render_file_list() { local backup_root backup_root=$(openclaw_backup_root) mkdir -p "$backup_root" echo "备份目录: $backup_root" ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list break_end } @@ -12128,11 +12132,12 @@ EOF echo "=======================================" echo "OpenClaw 备份与还原" echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" echo "1. 导出记忆全量" echo "2. 导入记忆全量" echo "3. 导出 OpenClaw 项目(默认安全模式)" echo "4. 导入 OpenClaw 项目(高级/高风险)" - echo "5. 查看备份文件" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice @@ -12142,7 +12147,6 @@ EOF 2) openclaw_memory_backup_import ;; 3) openclaw_project_backup_export ;; 4) openclaw_project_backup_import ;; - 5) openclaw_backup_list_files ;; 0) return 0 ;; *) echo "无效的选择,请重试。" diff --git a/kejilion.sh b/kejilion.sh index fc8993c70..1bb1b37c5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12113,12 +12113,16 @@ EOF break_end } - openclaw_backup_list_files() { + openclaw_backup_render_file_list() { local backup_root backup_root=$(openclaw_backup_root) mkdir -p "$backup_root" echo "备份目录: $backup_root" ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list break_end } @@ -12129,11 +12133,12 @@ EOF echo "=======================================" echo "OpenClaw 备份与还原" echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" echo "1. 导出记忆全量" echo "2. 导入记忆全量" echo "3. 导出 OpenClaw 项目(默认安全模式)" echo "4. 导入 OpenClaw 项目(高级/高风险)" - echo "5. 查看备份文件" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice @@ -12143,7 +12148,6 @@ EOF 2) openclaw_memory_backup_import ;; 3) openclaw_project_backup_export ;; 4) openclaw_project_backup_import ;; - 5) openclaw_backup_list_files ;; 0) return 0 ;; *) echo "无效的选择,请重试。" From 816d2443e94b5f7613263c54bb16ecc4d57a27d9 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 07:31:28 +0800 Subject: [PATCH 0949/1285] feat(backup): prioritize auto rz/sz transfer with fallback hints --- cn/kejilion.sh | 70 +++++++++++++++++++++++++++++++++++++++++--------- kejilion.sh | 70 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 116 insertions(+), 24 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 71d237d47..f5f7c0457 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11724,6 +11724,34 @@ PYTHON_EOF [ -t 0 ] && [ -t 1 ] } + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + openclaw_try_install_transfer_tool() { + local tool_name="$1" + openclaw_has_command "$tool_name" && return 0 + + echo "未检测到 $tool_name,正在尝试安装 lrzsz(提供 rz/sz)..." + + if ! install lrzsz; then + if openclaw_has_command opkg; then + echo "lrzsz 安装失败,正在尝试安装 rzsz..." + opkg update && opkg install rzsz + else + echo "⚠️ 自动安装 lrzsz 失败。" + fi + fi + + if openclaw_has_command "$tool_name"; then + echo "✅ 已启用 $tool_name" + return 0 + fi + + echo "⚠️ 自动安装完成后仍未找到 $tool_name" + return 1 + } + openclaw_is_safe_relpath() { local rel="$1" [ -z "$rel" ] && return 1 @@ -11800,14 +11828,21 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if command -v sz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - echo "检测到交互终端与 sz,可选快速下载。" - read -e -p "是否使用 sz 发送备份文件?(y/N): " send_by_sz - if [[ "$send_by_sz" =~ ^[Yy]$ ]]; then - sz "$file_path" - return + + if openclaw_is_interactive_terminal; then + if openclaw_try_install_transfer_tool "sz"; then + echo "正在通过 sz 发送备份文件,请在终端客户端确认接收..." + if sz "$file_path"; then + return 0 + fi + echo "⚠️ sz 发送失败,可能是当前终端不支持 ZMODEM,改为路径下载方式。" + else + echo "⚠️ 当前环境未能启用 sz,改为路径下载方式。" fi + else + echo "⚠️ 当前会话不是交互终端,无法直接使用 sz,改为路径下载方式。" fi + echo "可使用以下方式下载备份文件:" echo "- 本地路径: $file_path" echo "- scp 示例: scp root@你的服务器:$file_path ./" @@ -11899,14 +11934,25 @@ EOF local prompt_text="$1" local file_path echo "$prompt_text" >&2 - if command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - echo "提示:检测到 rz,可输入 rz 后回车上传,再输入本机保存路径。" >&2 + + if openclaw_is_interactive_terminal; then + if openclaw_try_install_transfer_tool "rz"; then + echo "正在启用 rz 接收备份文件,请在终端客户端选择上传..." >&2 + if rz; then + echo "✅ rz 接收已结束,请输入上传后的备份文件路径。" >&2 + else + echo "⚠️ rz 接收失败,改为手动输入服务器上的备份文件路径。" >&2 + fi + else + echo "⚠️ 当前环境未能启用 rz,改为手动输入服务器上的备份文件路径。" >&2 + fi + else + echo "⚠️ 当前会话不是交互终端,无法直接使用 rz。" >&2 fi + + echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 + echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 read -e -p "请输入备份文件路径: " file_path - if [ "$file_path" = "rz" ] && command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - rz - read -e -p "上传完成,请输入备份文件路径: " file_path - fi echo "$file_path" } diff --git a/kejilion.sh b/kejilion.sh index 1bb1b37c5..a087d6d36 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11725,6 +11725,34 @@ PYTHON_EOF [ -t 0 ] && [ -t 1 ] } + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + openclaw_try_install_transfer_tool() { + local tool_name="$1" + openclaw_has_command "$tool_name" && return 0 + + echo "未检测到 $tool_name,正在尝试安装 lrzsz(提供 rz/sz)..." + + if ! install lrzsz; then + if openclaw_has_command opkg; then + echo "lrzsz 安装失败,正在尝试安装 rzsz..." + opkg update && opkg install rzsz + else + echo "⚠️ 自动安装 lrzsz 失败。" + fi + fi + + if openclaw_has_command "$tool_name"; then + echo "✅ 已启用 $tool_name" + return 0 + fi + + echo "⚠️ 自动安装完成后仍未找到 $tool_name" + return 1 + } + openclaw_is_safe_relpath() { local rel="$1" [ -z "$rel" ] && return 1 @@ -11801,14 +11829,21 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if command -v sz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - echo "检测到交互终端与 sz,可选快速下载。" - read -e -p "是否使用 sz 发送备份文件?(y/N): " send_by_sz - if [[ "$send_by_sz" =~ ^[Yy]$ ]]; then - sz "$file_path" - return + + if openclaw_is_interactive_terminal; then + if openclaw_try_install_transfer_tool "sz"; then + echo "正在通过 sz 发送备份文件,请在终端客户端确认接收..." + if sz "$file_path"; then + return 0 + fi + echo "⚠️ sz 发送失败,可能是当前终端不支持 ZMODEM,改为路径下载方式。" + else + echo "⚠️ 当前环境未能启用 sz,改为路径下载方式。" fi + else + echo "⚠️ 当前会话不是交互终端,无法直接使用 sz,改为路径下载方式。" fi + echo "可使用以下方式下载备份文件:" echo "- 本地路径: $file_path" echo "- scp 示例: scp root@你的服务器:$file_path ./" @@ -11900,14 +11935,25 @@ EOF local prompt_text="$1" local file_path echo "$prompt_text" >&2 - if command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - echo "提示:检测到 rz,可输入 rz 后回车上传,再输入本机保存路径。" >&2 + + if openclaw_is_interactive_terminal; then + if openclaw_try_install_transfer_tool "rz"; then + echo "正在启用 rz 接收备份文件,请在终端客户端选择上传..." >&2 + if rz; then + echo "✅ rz 接收已结束,请输入上传后的备份文件路径。" >&2 + else + echo "⚠️ rz 接收失败,改为手动输入服务器上的备份文件路径。" >&2 + fi + else + echo "⚠️ 当前环境未能启用 rz,改为手动输入服务器上的备份文件路径。" >&2 + fi + else + echo "⚠️ 当前会话不是交互终端,无法直接使用 rz。" >&2 fi + + echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 + echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 read -e -p "请输入备份文件路径: " file_path - if [ "$file_path" = "rz" ] && command -v rz >/dev/null 2>&1 && openclaw_is_interactive_terminal; then - rz - read -e -p "上传完成,请输入备份文件路径: " file_path - fi echo "$file_path" } From 4615743753068525f030790d4c4d8fdcbade6d93 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 07:47:59 +0800 Subject: [PATCH 0950/1285] fix(backup): clarify apk rz/sz fallback message --- cn/kejilion.sh | 2 ++ kejilion.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f5f7c0457..c9ccfb9c8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11738,6 +11738,8 @@ PYTHON_EOF if openclaw_has_command opkg; then echo "lrzsz 安装失败,正在尝试安装 rzsz..." opkg update && opkg install rzsz + elif openclaw_has_command apk; then + echo "⚠️ 当前系统仓库无可用的 rz/sz(lrzsz/rzsz)包,将直接回退到路径导入/导出。" else echo "⚠️ 自动安装 lrzsz 失败。" fi diff --git a/kejilion.sh b/kejilion.sh index a087d6d36..7ef154249 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11739,6 +11739,8 @@ PYTHON_EOF if openclaw_has_command opkg; then echo "lrzsz 安装失败,正在尝试安装 rzsz..." opkg update && opkg install rzsz + elif openclaw_has_command apk; then + echo "⚠️ 当前系统仓库无可用的 rz/sz(lrzsz/rzsz)包,将直接回退到路径导入/导出。" else echo "⚠️ 自动安装 lrzsz 失败。" fi From 520256f8ac3223c6e7d3eeb293fedecec25fa3c7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 07:51:39 +0800 Subject: [PATCH 0951/1285] feat(openclaw): add backup/snapshot delete option with typed list and double confirm --- cn/kejilion.sh | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-- kejilion.sh | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 170 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c9ccfb9c8..4fa562074 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12160,12 +12160,93 @@ EOF break_end } - openclaw_backup_render_file_list() { + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == pre-import-* ]]; then + echo "回滚快照" + elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then + echo "正式备份" + else + echo "其他文件" + fi + } + + openclaw_backup_collect_files() { local backup_root backup_root=$(openclaw_backup_root) mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + echo "备份目录: $backup_root" - ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "暂无备份文件" + return 0 + fi + + echo "序号 | 类型 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_path="$backup_root/$file_name" + file_type=$(openclaw_backup_detect_type "$file_name") + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. [%-8s] %s | %s | %s\n" "$((i + 1))" "$file_type" "$file_name" "$file_size" "$file_time" + done + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw删除备份或快照" + local backup_root select_idx target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "请输入要删除的序号(0 取消): " select_idx + if [ "$select_idx" = "0" ]; then + echo "已取消删除。" + break_end + return 0 + fi + if ! [[ "$select_idx" =~ ^[0-9]+$ ]] || [ "$select_idx" -lt 1 ] || [ "$select_idx" -gt ${#OPENCLAW_BACKUP_FILES[@]} ]; then + echo "❌ 序号无效。" + break_end + return 1 + fi + + target_file="${OPENCLAW_BACKUP_FILES[$((select_idx - 1))]}" + target_path="$backup_root/$target_file" + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "即将删除: [$target_type] $target_file" + read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消删除。" + break_end + return 0 + fi + read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "已取消删除。" + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ 删除成功: $target_file" + else + echo "❌ 删除失败: $target_file" + fi + break_end } openclaw_backup_list_files() { @@ -12186,6 +12267,7 @@ EOF echo "2. 导入记忆全量" echo "3. 导出 OpenClaw 项目(默认安全模式)" echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "5. 删除备份或快照" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice @@ -12195,6 +12277,7 @@ EOF 2) openclaw_memory_backup_import ;; 3) openclaw_project_backup_export ;; 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; 0) return 0 ;; *) echo "无效的选择,请重试。" diff --git a/kejilion.sh b/kejilion.sh index 7ef154249..5294c2dda 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12161,12 +12161,93 @@ EOF break_end } - openclaw_backup_render_file_list() { + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == pre-import-* ]]; then + echo "回滚快照" + elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then + echo "正式备份" + else + echo "其他文件" + fi + } + + openclaw_backup_collect_files() { local backup_root backup_root=$(openclaw_backup_root) mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + echo "备份目录: $backup_root" - ls -lh "$backup_root"/*.tar.gz 2>/dev/null || echo "暂无备份文件" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "暂无备份文件" + return 0 + fi + + echo "序号 | 类型 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_path="$backup_root/$file_name" + file_type=$(openclaw_backup_detect_type "$file_name") + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. [%-8s] %s | %s | %s\n" "$((i + 1))" "$file_type" "$file_name" "$file_size" "$file_time" + done + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw删除备份或快照" + local backup_root select_idx target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "请输入要删除的序号(0 取消): " select_idx + if [ "$select_idx" = "0" ]; then + echo "已取消删除。" + break_end + return 0 + fi + if ! [[ "$select_idx" =~ ^[0-9]+$ ]] || [ "$select_idx" -lt 1 ] || [ "$select_idx" -gt ${#OPENCLAW_BACKUP_FILES[@]} ]; then + echo "❌ 序号无效。" + break_end + return 1 + fi + + target_file="${OPENCLAW_BACKUP_FILES[$((select_idx - 1))]}" + target_path="$backup_root/$target_file" + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "即将删除: [$target_type] $target_file" + read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消删除。" + break_end + return 0 + fi + read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "已取消删除。" + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ 删除成功: $target_file" + else + echo "❌ 删除失败: $target_file" + fi + break_end } openclaw_backup_list_files() { @@ -12187,6 +12268,7 @@ EOF echo "2. 导入记忆全量" echo "3. 导出 OpenClaw 项目(默认安全模式)" echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "5. 删除备份或快照" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice @@ -12196,6 +12278,7 @@ EOF 2) openclaw_memory_backup_import ;; 3) openclaw_project_backup_export ;; 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; 0) return 0 ;; *) echo "无效的选择,请重试。" From 74006d28425e864fe8eddff4f33355cbf44e880c Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 07:54:44 +0800 Subject: [PATCH 0952/1285] refactor(openclaw): unify backup list titles and grouped rendering --- cn/kejilion.sh | 62 ++++++++++++++++++++++++++++++++++++++++++-------- kejilion.sh | 62 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 104 insertions(+), 20 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4fa562074..eb190c9a4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12163,11 +12163,11 @@ EOF openclaw_backup_detect_type() { local file_name="$1" if [[ "$file_name" == pre-import-* ]]; then - echo "回滚快照" + echo "导入前回滚快照" elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then - echo "正式备份" + echo "正式备份文件" else - echo "其他文件" + echo "其他备份文件" fi } @@ -12180,6 +12180,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time + local has_official=0 has_snapshot=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12189,15 +12190,56 @@ EOF return 0 fi - echo "序号 | 类型 | 文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do - file_name="${OPENCLAW_BACKUP_FILES[$i]}" - file_path="$backup_root/$file_name" - file_type=$(openclaw_backup_detect_type "$file_name") - file_size=$(ls -lh "$file_path" | awk '{print $5}') - file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. [%-8s] %s | %s | %s\n" "$((i + 1))" "$file_type" "$file_name" "$file_size" "$file_time" + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "正式备份文件") has_official=1 ;; + "导入前回滚快照") has_snapshot=1 ;; + "其他备份文件") has_other=1 ;; + esac done + + if [ "$has_official" -eq 1 ]; then + echo "正式备份文件" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "正式备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_snapshot" -eq 1 ]; then + echo "导入前回滚快照" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "导入前回滚快照" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "其他备份文件" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "其他备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi } openclaw_backup_delete_file() { diff --git a/kejilion.sh b/kejilion.sh index 5294c2dda..52d414e52 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12164,11 +12164,11 @@ EOF openclaw_backup_detect_type() { local file_name="$1" if [[ "$file_name" == pre-import-* ]]; then - echo "回滚快照" + echo "导入前回滚快照" elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then - echo "正式备份" + echo "正式备份文件" else - echo "其他文件" + echo "其他备份文件" fi } @@ -12181,6 +12181,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time + local has_official=0 has_snapshot=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12190,15 +12191,56 @@ EOF return 0 fi - echo "序号 | 类型 | 文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do - file_name="${OPENCLAW_BACKUP_FILES[$i]}" - file_path="$backup_root/$file_name" - file_type=$(openclaw_backup_detect_type "$file_name") - file_size=$(ls -lh "$file_path" | awk '{print $5}') - file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. [%-8s] %s | %s | %s\n" "$((i + 1))" "$file_type" "$file_name" "$file_size" "$file_time" + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "正式备份文件") has_official=1 ;; + "导入前回滚快照") has_snapshot=1 ;; + "其他备份文件") has_other=1 ;; + esac done + + if [ "$has_official" -eq 1 ]; then + echo "正式备份文件" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "正式备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_snapshot" -eq 1 ]; then + echo "导入前回滚快照" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "导入前回滚快照" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "其他备份文件" + echo "序号 | 文件名 | 大小 | 修改时间" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "其他备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + done + fi } openclaw_backup_delete_file() { From 602485d57df741cbf2cfe163ff8f40d29626d4c1 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 08:06:48 +0800 Subject: [PATCH 0953/1285] feat(openclaw-backup): switch deletion to filename/path and remove index column --- cn/kejilion.sh | 65 +++++++++++++++++++++++++++++++++++++++----------- kejilion.sh | 65 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index eb190c9a4..e003cf41d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12178,6 +12178,7 @@ EOF mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) } + openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time local has_official=0 has_snapshot=0 has_other=0 @@ -12201,7 +12202,7 @@ EOF if [ "$has_official" -eq 1 ]; then echo "正式备份文件" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12209,13 +12210,13 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi if [ "$has_snapshot" -eq 1 ]; then echo "导入前回滚快照" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12223,13 +12224,13 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi if [ "$has_other" -eq 1 ]; then echo "其他备份文件" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12237,14 +12238,23 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi } + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + openclaw_backup_delete_file() { send_stats "OpenClaw删除备份或快照" - local backup_root select_idx target_file target_path target_type + local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) openclaw_backup_render_file_list @@ -12253,23 +12263,50 @@ EOF return 0 fi - read -e -p "请输入要删除的序号(0 取消): " select_idx - if [ "$select_idx" = "0" ]; then + read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input + if [ "$user_input" = "0" ]; then echo "已取消删除。" break_end return 0 fi - if ! [[ "$select_idx" =~ ^[0-9]+$ ]] || [ "$select_idx" -lt 1 ] || [ "$select_idx" -gt ${#OPENCLAW_BACKUP_FILES[@]} ]; then - echo "❌ 序号无效。" + if [ -z "$user_input" ]; then + echo "❌ 输入不能为空。" + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ 路径越界:仅允许删除备份根目录内的文件。" + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ 目标文件不存在: $target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ 目标文件不在当前备份列表中。" break_end return 1 fi - target_file="${OPENCLAW_BACKUP_FILES[$((select_idx - 1))]}" - target_path="$backup_root/$target_file" target_type=$(openclaw_backup_detect_type "$target_file") - echo "即将删除: [$target_type] $target_file" + echo "即将删除: [$target_type] $target_path" read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消删除。" diff --git a/kejilion.sh b/kejilion.sh index 52d414e52..26073343b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12179,6 +12179,7 @@ EOF mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) } + openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time local has_official=0 has_snapshot=0 has_other=0 @@ -12202,7 +12203,7 @@ EOF if [ "$has_official" -eq 1 ]; then echo "正式备份文件" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12210,13 +12211,13 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi if [ "$has_snapshot" -eq 1 ]; then echo "导入前回滚快照" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12224,13 +12225,13 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi if [ "$has_other" -eq 1 ]; then echo "其他备份文件" - echo "序号 | 文件名 | 大小 | 修改时间" + echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12238,14 +12239,23 @@ EOF file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%2d. %s | %s | %s\n" "$((i + 1))" "$file_name" "$file_size" "$file_time" + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" done fi } + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + openclaw_backup_delete_file() { send_stats "OpenClaw删除备份或快照" - local backup_root select_idx target_file target_path target_type + local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) openclaw_backup_render_file_list @@ -12254,23 +12264,50 @@ EOF return 0 fi - read -e -p "请输入要删除的序号(0 取消): " select_idx - if [ "$select_idx" = "0" ]; then + read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input + if [ "$user_input" = "0" ]; then echo "已取消删除。" break_end return 0 fi - if ! [[ "$select_idx" =~ ^[0-9]+$ ]] || [ "$select_idx" -lt 1 ] || [ "$select_idx" -gt ${#OPENCLAW_BACKUP_FILES[@]} ]; then - echo "❌ 序号无效。" + if [ -z "$user_input" ]; then + echo "❌ 输入不能为空。" + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ 路径越界:仅允许删除备份根目录内的文件。" + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ 目标文件不存在: $target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ 目标文件不在当前备份列表中。" break_end return 1 fi - target_file="${OPENCLAW_BACKUP_FILES[$((select_idx - 1))]}" - target_path="$backup_root/$target_file" target_type=$(openclaw_backup_detect_type "$target_file") - echo "即将删除: [$target_type] $target_file" + echo "即将删除: [$target_type] $target_path" read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消删除。" From 493a01a58a6d5e8276051e883c3b4432da413109 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 08:11:57 +0800 Subject: [PATCH 0954/1285] revert backup rz/sz auto-install and remove backup list headers --- cn/kejilion.sh | 58 +++++--------------------------------------------- kejilion.sh | 58 +++++--------------------------------------------- 2 files changed, 10 insertions(+), 106 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e003cf41d..ebd623939 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11728,31 +11728,6 @@ PYTHON_EOF command -v "$1" >/dev/null 2>&1 } - openclaw_try_install_transfer_tool() { - local tool_name="$1" - openclaw_has_command "$tool_name" && return 0 - - echo "未检测到 $tool_name,正在尝试安装 lrzsz(提供 rz/sz)..." - - if ! install lrzsz; then - if openclaw_has_command opkg; then - echo "lrzsz 安装失败,正在尝试安装 rzsz..." - opkg update && opkg install rzsz - elif openclaw_has_command apk; then - echo "⚠️ 当前系统仓库无可用的 rz/sz(lrzsz/rzsz)包,将直接回退到路径导入/导出。" - else - echo "⚠️ 自动安装 lrzsz 失败。" - fi - fi - - if openclaw_has_command "$tool_name"; then - echo "✅ 已启用 $tool_name" - return 0 - fi - - echo "⚠️ 自动安装完成后仍未找到 $tool_name" - return 1 - } openclaw_is_safe_relpath() { local rel="$1" @@ -11831,18 +11806,9 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if openclaw_is_interactive_terminal; then - if openclaw_try_install_transfer_tool "sz"; then - echo "正在通过 sz 发送备份文件,请在终端客户端确认接收..." - if sz "$file_path"; then - return 0 - fi - echo "⚠️ sz 发送失败,可能是当前终端不支持 ZMODEM,改为路径下载方式。" - else - echo "⚠️ 当前环境未能启用 sz,改为路径下载方式。" - fi - else - echo "⚠️ 当前会话不是交互终端,无法直接使用 sz,改为路径下载方式。" + if openclaw_is_interactive_terminal && openclaw_has_command "sz"; then + echo "检测到 sz,可在当前终端自行执行以下命令下载:" + echo "sz \"$file_path\"" fi echo "可使用以下方式下载备份文件:" @@ -11937,19 +11903,8 @@ EOF local file_path echo "$prompt_text" >&2 - if openclaw_is_interactive_terminal; then - if openclaw_try_install_transfer_tool "rz"; then - echo "正在启用 rz 接收备份文件,请在终端客户端选择上传..." >&2 - if rz; then - echo "✅ rz 接收已结束,请输入上传后的备份文件路径。" >&2 - else - echo "⚠️ rz 接收失败,改为手动输入服务器上的备份文件路径。" >&2 - fi - else - echo "⚠️ 当前环境未能启用 rz,改为手动输入服务器上的备份文件路径。" >&2 - fi - else - echo "⚠️ 当前会话不是交互终端,无法直接使用 rz。" >&2 + if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then + echo "检测到 rz,可在当前终端自行执行 rz 上传备份包;上传完成后再输入服务器上的文件路径。" >&2 fi echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 @@ -12202,7 +12157,6 @@ EOF if [ "$has_official" -eq 1 ]; then echo "正式备份文件" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12216,7 +12170,6 @@ EOF if [ "$has_snapshot" -eq 1 ]; then echo "导入前回滚快照" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12230,7 +12183,6 @@ EOF if [ "$has_other" -eq 1 ]; then echo "其他备份文件" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") diff --git a/kejilion.sh b/kejilion.sh index 26073343b..43cd587b6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11729,31 +11729,6 @@ PYTHON_EOF command -v "$1" >/dev/null 2>&1 } - openclaw_try_install_transfer_tool() { - local tool_name="$1" - openclaw_has_command "$tool_name" && return 0 - - echo "未检测到 $tool_name,正在尝试安装 lrzsz(提供 rz/sz)..." - - if ! install lrzsz; then - if openclaw_has_command opkg; then - echo "lrzsz 安装失败,正在尝试安装 rzsz..." - opkg update && opkg install rzsz - elif openclaw_has_command apk; then - echo "⚠️ 当前系统仓库无可用的 rz/sz(lrzsz/rzsz)包,将直接回退到路径导入/导出。" - else - echo "⚠️ 自动安装 lrzsz 失败。" - fi - fi - - if openclaw_has_command "$tool_name"; then - echo "✅ 已启用 $tool_name" - return 0 - fi - - echo "⚠️ 自动安装完成后仍未找到 $tool_name" - return 1 - } openclaw_is_safe_relpath() { local rel="$1" @@ -11832,18 +11807,9 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if openclaw_is_interactive_terminal; then - if openclaw_try_install_transfer_tool "sz"; then - echo "正在通过 sz 发送备份文件,请在终端客户端确认接收..." - if sz "$file_path"; then - return 0 - fi - echo "⚠️ sz 发送失败,可能是当前终端不支持 ZMODEM,改为路径下载方式。" - else - echo "⚠️ 当前环境未能启用 sz,改为路径下载方式。" - fi - else - echo "⚠️ 当前会话不是交互终端,无法直接使用 sz,改为路径下载方式。" + if openclaw_is_interactive_terminal && openclaw_has_command "sz"; then + echo "检测到 sz,可在当前终端自行执行以下命令下载:" + echo "sz \"$file_path\"" fi echo "可使用以下方式下载备份文件:" @@ -11938,19 +11904,8 @@ EOF local file_path echo "$prompt_text" >&2 - if openclaw_is_interactive_terminal; then - if openclaw_try_install_transfer_tool "rz"; then - echo "正在启用 rz 接收备份文件,请在终端客户端选择上传..." >&2 - if rz; then - echo "✅ rz 接收已结束,请输入上传后的备份文件路径。" >&2 - else - echo "⚠️ rz 接收失败,改为手动输入服务器上的备份文件路径。" >&2 - fi - else - echo "⚠️ 当前环境未能启用 rz,改为手动输入服务器上的备份文件路径。" >&2 - fi - else - echo "⚠️ 当前会话不是交互终端,无法直接使用 rz。" >&2 + if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then + echo "检测到 rz,可在当前终端自行执行 rz 上传备份包;上传完成后再输入服务器上的文件路径。" >&2 fi echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 @@ -12203,7 +12158,6 @@ EOF if [ "$has_official" -eq 1 ]; then echo "正式备份文件" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12217,7 +12171,6 @@ EOF if [ "$has_snapshot" -eq 1 ]; then echo "导入前回滚快照" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") @@ -12231,7 +12184,6 @@ EOF if [ "$has_other" -eq 1 ]; then echo "其他备份文件" - echo "文件名 | 大小 | 修改时间" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") From d4e4bc5fbb48372b29b1dbd364c02a062283b37a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 08:25:02 +0800 Subject: [PATCH 0955/1285] feat(openclaw): unify backup/restore wording and improve restore path resolution --- cn/kejilion.sh | 80 +++++++++++++++++++++++++++++++------------------- kejilion.sh | 80 +++++++++++++++++++++++++++++++------------------- 2 files changed, 98 insertions(+), 62 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ebd623939..84e4990ee 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11845,14 +11845,14 @@ EOF ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 校验失败,拒绝导入"; return 1; } + ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } echo "$pkg_dir" return 0 } openclaw_memory_backup_export() { - send_stats "OpenClaw记忆全量导出" + send_stats "OpenClaw记忆全量备份" local workspace_dir="${HOME}/.openclaw/workspace" local backup_root backup_root=$(openclaw_backup_root) @@ -11881,17 +11881,17 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可导出的记忆文件" + echo "❌ 未找到可备份的记忆文件" rm -rf "$tmp_payload" break_end return 1 fi if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 记忆备份导出完成: $out_file" + echo "✅ 记忆全量备份完成: $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ 记忆备份导出失败" + echo "❌ 记忆全量备份失败" fi rm -rf "$tmp_payload" @@ -11900,7 +11900,7 @@ EOF openclaw_read_import_path() { local prompt_text="$1" - local file_path + local file_input file_path backup_root echo "$prompt_text" >&2 if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then @@ -11909,17 +11909,35 @@ EOF echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 - read -e -p "请输入备份文件路径: " file_path + echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 + read -e -p "请输入备份文件名或路径: " file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ 备份文件不存在: $file_path" >&2 + echo "" + return 1 + fi + echo "$file_path" } openclaw_memory_backup_import() { - send_stats "OpenClaw记忆全量导入" + send_stats "OpenClaw记忆全量还原" local workspace_dir="${HOME}/.openclaw/workspace" mkdir -p "$workspace_dir" local archive_path - archive_path=$(openclaw_read_import_path "导入前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack @@ -11943,7 +11961,7 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 导入中止:存在不安全路径" + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi @@ -11968,12 +11986,12 @@ EOF rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ 记忆全量导入完成" + echo "✅ 记忆全量还原完成" break_end } openclaw_project_backup_export() { - send_stats "OpenClaw项目导出" + send_stats "OpenClaw项目备份" local openclaw_root="${HOME}/.openclaw" if [ ! -d "$openclaw_root" ]; then echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" @@ -11981,10 +11999,10 @@ EOF return 1 fi - echo "导出模式:" + echo "备份模式:" echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多状态,敏感风险更高)" - read -e -p "请选择导出模式(默认 1): " export_mode + read -e -p "请选择备份模式(默认 1): " export_mode [ -z "$export_mode" ] && export_mode="1" local mode_label="safe" @@ -12012,7 +12030,7 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可导出的 OpenClaw 项目内容" + echo "❌ 未找到可备份的 OpenClaw 项目内容" rm -rf "$tmp_payload" break_end return 1 @@ -12024,10 +12042,10 @@ EOF local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then - echo "✅ OpenClaw 项目导出完成 (${mode_label}): $out_file" + echo "✅ OpenClaw 项目备份完成 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 项目导出失败" + echo "❌ OpenClaw 项目备份失败" fi rm -rf "$tmp_payload" @@ -12035,15 +12053,15 @@ EOF } openclaw_project_backup_import() { - send_stats "OpenClaw项目导入" + send_stats "OpenClaw项目还原" local openclaw_root="${HOME}/.openclaw" mkdir -p "$openclaw_root" - echo "⚠️ 高风险操作:项目导入会覆盖 OpenClaw 配置与工作区内容。" - echo "⚠️ 导入前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" - read -e -p "请输入确认词【我已知晓高风险并继续导入】后继续: " confirm_text - if [ "$confirm_text" != "我已知晓高风险并继续导入" ]; then - echo "❌ 确认词不匹配,已取消导入" + echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" + echo "⚠️ 还原前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text + if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then + echo "❌ 确认词不匹配,已取消还原" break_end return 1 fi @@ -12073,7 +12091,7 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 导入中止:存在不安全路径" + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi @@ -12092,7 +12110,7 @@ EOF fi if command -v openclaw >/dev/null 2>&1; then - echo "⏸️ 导入前停止 OpenClaw gateway..." + echo "⏸️ 还原前停止 OpenClaw gateway..." openclaw gateway stop >/dev/null 2>&1 fi @@ -12102,7 +12120,7 @@ EOF done < "$valid_list" if command -v openclaw >/dev/null 2>&1; then - echo "▶️ 导入后启动 OpenClaw gateway..." + echo "▶️ 还原后启动 OpenClaw gateway..." openclaw gateway start >/dev/null 2>&1 sleep 2 echo "🩺 gateway 健康检查:" @@ -12111,7 +12129,7 @@ EOF rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw 项目导入完成" + echo "✅ OpenClaw 项目还原完成" break_end } @@ -12294,10 +12312,10 @@ EOF echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" - echo "1. 导出记忆全量" - echo "2. 导入记忆全量" - echo "3. 导出 OpenClaw 项目(默认安全模式)" - echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "1. 备份记忆全量" + echo "2. 还原记忆全量" + echo "3. 备份 OpenClaw 项目(默认安全模式)" + echo "4. 还原 OpenClaw 项目(高级/高风险)" echo "5. 删除备份或快照" echo "0. 返回上一级" echo "---------------------------------------" diff --git a/kejilion.sh b/kejilion.sh index 43cd587b6..7c7a04c7b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11846,14 +11846,14 @@ EOF ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 校验失败,拒绝导入"; return 1; } + ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } echo "$pkg_dir" return 0 } openclaw_memory_backup_export() { - send_stats "OpenClaw记忆全量导出" + send_stats "OpenClaw记忆全量备份" local workspace_dir="${HOME}/.openclaw/workspace" local backup_root backup_root=$(openclaw_backup_root) @@ -11882,17 +11882,17 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可导出的记忆文件" + echo "❌ 未找到可备份的记忆文件" rm -rf "$tmp_payload" break_end return 1 fi if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 记忆备份导出完成: $out_file" + echo "✅ 记忆全量备份完成: $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ 记忆备份导出失败" + echo "❌ 记忆全量备份失败" fi rm -rf "$tmp_payload" @@ -11901,7 +11901,7 @@ EOF openclaw_read_import_path() { local prompt_text="$1" - local file_path + local file_input file_path backup_root echo "$prompt_text" >&2 if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then @@ -11910,17 +11910,35 @@ EOF echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 - read -e -p "请输入备份文件路径: " file_path + echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 + read -e -p "请输入备份文件名或路径: " file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ 备份文件不存在: $file_path" >&2 + echo "" + return 1 + fi + echo "$file_path" } openclaw_memory_backup_import() { - send_stats "OpenClaw记忆全量导入" + send_stats "OpenClaw记忆全量还原" local workspace_dir="${HOME}/.openclaw/workspace" mkdir -p "$workspace_dir" local archive_path - archive_path=$(openclaw_read_import_path "导入前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack @@ -11944,7 +11962,7 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 导入中止:存在不安全路径" + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi @@ -11969,12 +11987,12 @@ EOF rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ 记忆全量导入完成" + echo "✅ 记忆全量还原完成" break_end } openclaw_project_backup_export() { - send_stats "OpenClaw项目导出" + send_stats "OpenClaw项目备份" local openclaw_root="${HOME}/.openclaw" if [ ! -d "$openclaw_root" ]; then echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" @@ -11982,10 +12000,10 @@ EOF return 1 fi - echo "导出模式:" + echo "备份模式:" echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多状态,敏感风险更高)" - read -e -p "请选择导出模式(默认 1): " export_mode + read -e -p "请选择备份模式(默认 1): " export_mode [ -z "$export_mode" ] && export_mode="1" local mode_label="safe" @@ -12013,7 +12031,7 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可导出的 OpenClaw 项目内容" + echo "❌ 未找到可备份的 OpenClaw 项目内容" rm -rf "$tmp_payload" break_end return 1 @@ -12025,10 +12043,10 @@ EOF local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then - echo "✅ OpenClaw 项目导出完成 (${mode_label}): $out_file" + echo "✅ OpenClaw 项目备份完成 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 项目导出失败" + echo "❌ OpenClaw 项目备份失败" fi rm -rf "$tmp_payload" @@ -12036,15 +12054,15 @@ EOF } openclaw_project_backup_import() { - send_stats "OpenClaw项目导入" + send_stats "OpenClaw项目还原" local openclaw_root="${HOME}/.openclaw" mkdir -p "$openclaw_root" - echo "⚠️ 高风险操作:项目导入会覆盖 OpenClaw 配置与工作区内容。" - echo "⚠️ 导入前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" - read -e -p "请输入确认词【我已知晓高风险并继续导入】后继续: " confirm_text - if [ "$confirm_text" != "我已知晓高风险并继续导入" ]; then - echo "❌ 确认词不匹配,已取消导入" + echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" + echo "⚠️ 还原前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text + if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then + echo "❌ 确认词不匹配,已取消还原" break_end return 1 fi @@ -12074,7 +12092,7 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 导入中止:存在不安全路径" + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi @@ -12093,7 +12111,7 @@ EOF fi if command -v openclaw >/dev/null 2>&1; then - echo "⏸️ 导入前停止 OpenClaw gateway..." + echo "⏸️ 还原前停止 OpenClaw gateway..." openclaw gateway stop >/dev/null 2>&1 fi @@ -12103,7 +12121,7 @@ EOF done < "$valid_list" if command -v openclaw >/dev/null 2>&1; then - echo "▶️ 导入后启动 OpenClaw gateway..." + echo "▶️ 还原后启动 OpenClaw gateway..." openclaw gateway start >/dev/null 2>&1 sleep 2 echo "🩺 gateway 健康检查:" @@ -12112,7 +12130,7 @@ EOF rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw 项目导入完成" + echo "✅ OpenClaw 项目还原完成" break_end } @@ -12295,10 +12313,10 @@ EOF echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" - echo "1. 导出记忆全量" - echo "2. 导入记忆全量" - echo "3. 导出 OpenClaw 项目(默认安全模式)" - echo "4. 导入 OpenClaw 项目(高级/高风险)" + echo "1. 备份记忆全量" + echo "2. 还原记忆全量" + echo "3. 备份 OpenClaw 项目(默认安全模式)" + echo "4. 还原 OpenClaw 项目(高级/高风险)" echo "5. 删除备份或快照" echo "0. 返回上一级" echo "---------------------------------------" From f2cdfc10fbf163d7007f712662a7397e286409cd Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 08:50:48 +0800 Subject: [PATCH 0956/1285] refactor(openclaw-backup): remove pre-import rollback snapshot flow --- cn/kejilion.sh | 52 ++++++-------------------------------------------- kejilion.sh | 52 ++++++-------------------------------------------- 2 files changed, 12 insertions(+), 92 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 84e4990ee..3bce189ee 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11937,7 +11937,7 @@ EOF mkdir -p "$workspace_dir" local archive_path - archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack @@ -11966,18 +11966,6 @@ EOF return 1 fi - local backup_root - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - local snapshot_file="$backup_root/pre-import-memory-$(date +%Y%m%d-%H%M%S).tar.gz" - local snapshot_targets=() - while IFS= read -r rel; do - [ -e "$workspace_dir/$rel" ] && snapshot_targets+=("$rel") - done < "$valid_list" - if [ ${#snapshot_targets[@]} -gt 0 ]; then - ( cd "$workspace_dir" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) - echo "🧷 已创建导入前快照: $snapshot_file" - fi while IFS= read -r rel; do mkdir -p "$workspace_dir/$(dirname "$rel")" @@ -12058,7 +12046,7 @@ EOF mkdir -p "$openclaw_root" echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" - echo "⚠️ 还原前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then echo "❌ 确认词不匹配,已取消还原" @@ -12096,18 +12084,6 @@ EOF return 1 fi - local backup_root - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - local snapshot_file="$backup_root/pre-import-project-$(date +%Y%m%d-%H%M%S).tar.gz" - local snapshot_targets=() - while IFS= read -r rel; do - [ -e "$openclaw_root/$rel" ] && snapshot_targets+=("$rel") - done < "$valid_list" - if [ ${#snapshot_targets[@]} -gt 0 ]; then - ( cd "$openclaw_root" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) - echo "🧷 已创建导入前快照: $snapshot_file" - fi if command -v openclaw >/dev/null 2>&1; then echo "⏸️ 还原前停止 OpenClaw gateway..." @@ -12135,9 +12111,7 @@ EOF openclaw_backup_detect_type() { local file_name="$1" - if [[ "$file_name" == pre-import-* ]]; then - echo "导入前回滚快照" - elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then + if [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then echo "正式备份文件" else echo "其他备份文件" @@ -12154,7 +12128,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time - local has_official=0 has_snapshot=0 has_other=0 + local has_official=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12168,7 +12142,6 @@ EOF file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in "正式备份文件") has_official=1 ;; - "导入前回滚快照") has_snapshot=1 ;; "其他备份文件") has_other=1 ;; esac done @@ -12186,19 +12159,6 @@ EOF done fi - if [ "$has_snapshot" -eq 1 ]; then - echo "导入前回滚快照" - for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do - file_name="${OPENCLAW_BACKUP_FILES[$i]}" - file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "导入前回滚快照" ] && continue - file_path="$backup_root/$file_name" - file_size=$(ls -lh "$file_path" | awk '{print $5}') - file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" - done - fi - if [ "$has_other" -eq 1 ]; then echo "其他备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do @@ -12223,7 +12183,7 @@ EOF } openclaw_backup_delete_file() { - send_stats "OpenClaw删除备份或快照" + send_stats "OpenClaw删除备份文件" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -12316,7 +12276,7 @@ EOF echo "2. 还原记忆全量" echo "3. 备份 OpenClaw 项目(默认安全模式)" echo "4. 还原 OpenClaw 项目(高级/高风险)" - echo "5. 删除备份或快照" + echo "5. 删除备份文件" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice diff --git a/kejilion.sh b/kejilion.sh index 7c7a04c7b..220b39d05 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11938,7 +11938,7 @@ EOF mkdir -p "$workspace_dir" local archive_path - archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验 + 快照") + archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack @@ -11967,18 +11967,6 @@ EOF return 1 fi - local backup_root - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - local snapshot_file="$backup_root/pre-import-memory-$(date +%Y%m%d-%H%M%S).tar.gz" - local snapshot_targets=() - while IFS= read -r rel; do - [ -e "$workspace_dir/$rel" ] && snapshot_targets+=("$rel") - done < "$valid_list" - if [ ${#snapshot_targets[@]} -gt 0 ]; then - ( cd "$workspace_dir" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) - echo "🧷 已创建导入前快照: $snapshot_file" - fi while IFS= read -r rel; do mkdir -p "$workspace_dir/$(dirname "$rel")" @@ -12059,7 +12047,7 @@ EOF mkdir -p "$openclaw_root" echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" - echo "⚠️ 还原前将执行快照、manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then echo "❌ 确认词不匹配,已取消还原" @@ -12097,18 +12085,6 @@ EOF return 1 fi - local backup_root - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - local snapshot_file="$backup_root/pre-import-project-$(date +%Y%m%d-%H%M%S).tar.gz" - local snapshot_targets=() - while IFS= read -r rel; do - [ -e "$openclaw_root/$rel" ] && snapshot_targets+=("$rel") - done < "$valid_list" - if [ ${#snapshot_targets[@]} -gt 0 ]; then - ( cd "$openclaw_root" && tar -czf "$snapshot_file" "${snapshot_targets[@]}" ) - echo "🧷 已创建导入前快照: $snapshot_file" - fi if command -v openclaw >/dev/null 2>&1; then echo "⏸️ 还原前停止 OpenClaw gateway..." @@ -12136,9 +12112,7 @@ EOF openclaw_backup_detect_type() { local file_name="$1" - if [[ "$file_name" == pre-import-* ]]; then - echo "导入前回滚快照" - elif [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then + if [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then echo "正式备份文件" else echo "其他备份文件" @@ -12155,7 +12129,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time - local has_official=0 has_snapshot=0 has_other=0 + local has_official=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12169,7 +12143,6 @@ EOF file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in "正式备份文件") has_official=1 ;; - "导入前回滚快照") has_snapshot=1 ;; "其他备份文件") has_other=1 ;; esac done @@ -12187,19 +12160,6 @@ EOF done fi - if [ "$has_snapshot" -eq 1 ]; then - echo "导入前回滚快照" - for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do - file_name="${OPENCLAW_BACKUP_FILES[$i]}" - file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "导入前回滚快照" ] && continue - file_path="$backup_root/$file_name" - file_size=$(ls -lh "$file_path" | awk '{print $5}') - file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') - printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" - done - fi - if [ "$has_other" -eq 1 ]; then echo "其他备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do @@ -12224,7 +12184,7 @@ EOF } openclaw_backup_delete_file() { - send_stats "OpenClaw删除备份或快照" + send_stats "OpenClaw删除备份文件" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -12317,7 +12277,7 @@ EOF echo "2. 还原记忆全量" echo "3. 备份 OpenClaw 项目(默认安全模式)" echo "4. 还原 OpenClaw 项目(高级/高风险)" - echo "5. 删除备份或快照" + echo "5. 删除备份文件" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " backup_choice From 7f9b5984056ed840e6ba1a212a3fde945df2b075 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 09:04:35 +0800 Subject: [PATCH 0957/1285] refactor(openclaw-backup): remove rz/sz hints from backup restore prompts --- cn/kejilion.sh | 9 --------- kejilion.sh | 9 --------- 2 files changed, 18 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3bce189ee..81e921e3b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11806,11 +11806,6 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if openclaw_is_interactive_terminal && openclaw_has_command "sz"; then - echo "检测到 sz,可在当前终端自行执行以下命令下载:" - echo "sz \"$file_path\"" - fi - echo "可使用以下方式下载备份文件:" echo "- 本地路径: $file_path" echo "- scp 示例: scp root@你的服务器:$file_path ./" @@ -11903,10 +11898,6 @@ EOF local file_input file_path backup_root echo "$prompt_text" >&2 - if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then - echo "检测到 rz,可在当前终端自行执行 rz 上传备份包;上传完成后再输入服务器上的文件路径。" >&2 - fi - echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 diff --git a/kejilion.sh b/kejilion.sh index 220b39d05..affd4d944 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11807,11 +11807,6 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - if openclaw_is_interactive_terminal && openclaw_has_command "sz"; then - echo "检测到 sz,可在当前终端自行执行以下命令下载:" - echo "sz \"$file_path\"" - fi - echo "可使用以下方式下载备份文件:" echo "- 本地路径: $file_path" echo "- scp 示例: scp root@你的服务器:$file_path ./" @@ -11904,10 +11899,6 @@ EOF local file_input file_path backup_root echo "$prompt_text" >&2 - if openclaw_is_interactive_terminal && openclaw_has_command "rz"; then - echo "检测到 rz,可在当前终端自行执行 rz 上传备份包;上传完成后再输入服务器上的文件路径。" >&2 - fi - echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 From 0888612c7f8235e1efa478289a7c28ef1ed7e25a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 09:10:10 +0800 Subject: [PATCH 0958/1285] feat(openclaw): split backup list into memory/project/other categories --- cn/kejilion.sh | 30 +++++++++++++++++++++++------- kejilion.sh | 30 +++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 81e921e3b..7788687d4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12102,8 +12102,10 @@ EOF openclaw_backup_detect_type() { local file_name="$1" - if [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then - echo "正式备份文件" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "记忆备份文件" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "项目备份文件" else echo "其他备份文件" fi @@ -12119,7 +12121,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time - local has_official=0 has_other=0 + local has_memory=0 has_project=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12132,17 +12134,31 @@ EOF for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in - "正式备份文件") has_official=1 ;; + "记忆备份文件") has_memory=1 ;; + "项目备份文件") has_project=1 ;; "其他备份文件") has_other=1 ;; esac done - if [ "$has_official" -eq 1 ]; then - echo "正式备份文件" + if [ "$has_memory" -eq 1 ]; then + echo "记忆备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "正式备份文件" ] && continue + [ "$file_type" != "记忆备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "项目备份文件" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "项目备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') diff --git a/kejilion.sh b/kejilion.sh index affd4d944..b20cc1ed0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12103,8 +12103,10 @@ EOF openclaw_backup_detect_type() { local file_name="$1" - if [[ "$file_name" == openclaw-memory-full-* || "$file_name" == openclaw-project-* ]]; then - echo "正式备份文件" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "记忆备份文件" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "项目备份文件" else echo "其他备份文件" fi @@ -12120,7 +12122,7 @@ EOF openclaw_backup_render_file_list() { local backup_root i file_name file_path file_type file_size file_time - local has_official=0 has_other=0 + local has_memory=0 has_project=0 has_other=0 backup_root=$(openclaw_backup_root) openclaw_backup_collect_files @@ -12133,17 +12135,31 @@ EOF for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in - "正式备份文件") has_official=1 ;; + "记忆备份文件") has_memory=1 ;; + "项目备份文件") has_project=1 ;; "其他备份文件") has_other=1 ;; esac done - if [ "$has_official" -eq 1 ]; then - echo "正式备份文件" + if [ "$has_memory" -eq 1 ]; then + echo "记忆备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "正式备份文件" ] && continue + [ "$file_type" != "记忆备份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "项目备份文件" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "项目备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') From 89797aaee7f34a43c492cd2fa4b76435a332d09e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 09:17:17 +0800 Subject: [PATCH 0959/1285] fix(openclaw): close full project backup/restore path loop safely --- cn/kejilion.sh | 7 ++----- kejilion.sh | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7788687d4..be49aadf0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11756,7 +11756,7 @@ PYTHON_EOF ;; project) case "$rel" in - openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*) return 0 ;; + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; *) return 1 ;; esac ;; @@ -11995,10 +11995,7 @@ EOF done [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" for d in telegram feishu whatsapp discord slack qqbot logs; do - if [ -e "$openclaw_root/$d" ]; then - mkdir -p "$tmp_payload/full-extra" - cp -a "$openclaw_root/$d" "$tmp_payload/full-extra/" - fi + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" done else [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" diff --git a/kejilion.sh b/kejilion.sh index b20cc1ed0..68a094eaa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11757,7 +11757,7 @@ PYTHON_EOF ;; project) case "$rel" in - openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*) return 0 ;; + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; *) return 1 ;; esac ;; @@ -11996,10 +11996,7 @@ EOF done [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" for d in telegram feishu whatsapp discord slack qqbot logs; do - if [ -e "$openclaw_root/$d" ]; then - mkdir -p "$tmp_payload/full-extra" - cp -a "$openclaw_root/$d" "$tmp_payload/full-extra/" - fi + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" done else [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" From 3a587b1687f2e2cbe972d1b2173db3051e4dbe36 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 09:46:25 +0800 Subject: [PATCH 0960/1285] refactor(ssh): unify SSH input collection and validation helpers --- cn/kejilion.sh | 293 ++++++++++++++++++++++++++++++------------------- kejilion.sh | 293 ++++++++++++++++++++++++++++++------------------- 2 files changed, 356 insertions(+), 230 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index be49aadf0..04815a27d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6738,30 +6738,95 @@ linux_backup() { -# 显示连接列表 -list_connections() { - echo "已保存的连接:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH 输入标准化函数 +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# 添加新连接 -add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" - echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "错误: 请输入有效的服务器地址。" + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "错误: 用户名格式不正确。" + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "错误: SSH 用户名格式不正确。" + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "错误: SSH 主机地址格式不正确。" + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "请选择身份验证方式:" echo "1. 密码" @@ -6771,37 +6836,79 @@ add_connection() { case $auth_choice in 1) read -s -p "请输入密码: " password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "错误: 密码不能为空。" + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "请粘贴密钥内容 (粘贴完成后按两次回车):" - local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "无效的密钥内容!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "无效的选择!" - return + return 1 ;; esac +} - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "错误: 密码不能为空。" + done +} + +# 显示连接列表 +list_connections() { + echo "已保存的连接:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# 添加新连接 +add_connection() { + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" + echo "------------------------" + read -e -p "请输入连接名称: " name + + kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "请输入端口号 (默认: 22): " "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi + + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "连接已保存!" } @@ -7134,52 +7241,29 @@ add_task() { read -e -p "请输入任务名称: " name read -e -p "请输入本地目录: " local_path read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port - port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + while true; do + read -e -p "请输入远程用户@IP: " remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "请输入密码: " password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" - local password_or_key="" - while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + while true; do + read -e -p "请输入 SSH 端口 (默认 22): " port + port=${port:-22} + if kj_ssh_validate_port "$port"; then + break + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done - # 检查是否是密钥内容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "无效的密钥内容!" - return - fi - ;; - *) - echo "无效的选择!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "请选择同步模式:" echo "1. 标准模式 (-avz)" @@ -7198,6 +7282,7 @@ add_task() { echo "任务已保存!" } + # 删除任务 delete_task() { send_stats "删除同步任务" @@ -8137,10 +8222,10 @@ docker_ssh_migration() { read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - read -e -p "目标服务器IP: " TARGET_IP - read -e -p "目标服务器SSH用户名: " TARGET_USER - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "目标服务器IP: " "目标服务器SSH用户名 [默认root]: " "目标服务器SSH端口 [默认22]: " "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -9604,13 +9689,9 @@ linux_ldnmp() { read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16304,14 +16385,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -18373,26 +18449,13 @@ linux_file() { continue fi - read -e -p "请输入远端服务器IP: " remote_ip - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" - continue - fi - - read -e -p "请输入远端服务器用户名 (默认root): " remote_user - remote_user=${remote_user:-root} - - read -e -p "请输入远端服务器密码: " -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" - continue - fi + kj_ssh_read_host_user_port "请输入远端服务器IP: " "请输入远端服务器用户名 (默认root): " "请输入登录端口 (默认22): " "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "请输入登录端口 (默认22): " remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "请输入远端服务器密码: " + local remote_password="$KJ_SSH_PASSWORD" # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" diff --git a/kejilion.sh b/kejilion.sh index 68a094eaa..8a58d1111 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6738,30 +6738,95 @@ linux_backup() { -# 显示连接列表 -list_connections() { - echo "已保存的连接:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH 输入标准化函数 +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# 添加新连接 -add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" - echo "------------------------" - read -e -p "请输入连接名称: " name - read -e -p "请输入IP地址: " ip - read -e -p "请输入用户名 (默认: root): " user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "请输入端口号 (默认: 22): " port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "错误: 请输入有效的服务器地址。" + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "错误: 用户名格式不正确。" + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "错误: SSH 用户名格式不正确。" + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "错误: SSH 主机地址格式不正确。" + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "请选择身份验证方式:" echo "1. 密码" @@ -6771,37 +6836,79 @@ add_connection() { case $auth_choice in 1) read -s -p "请输入密码: " password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "错误: 密码不能为空。" + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "请粘贴密钥内容 (粘贴完成后按两次回车):" - local password_or_key="" while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # 检查是否是密钥内容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "无效的密钥内容!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "无效的选择!" - return + return 1 ;; esac +} - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "错误: 密码不能为空。" + done +} + +# 显示连接列表 +list_connections() { + echo "已保存的连接:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# 添加新连接 +add_connection() { + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" + echo "------------------------" + read -e -p "请输入连接名称: " name + + kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "请输入端口号 (默认: 22): " "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi + + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "连接已保存!" } @@ -7134,52 +7241,29 @@ add_task() { read -e -p "请输入任务名称: " name read -e -p "请输入本地目录: " local_path read -e -p "请输入远程目录: " remote_path - read -e -p "请输入远程用户@IP: " remote - read -e -p "请输入 SSH 端口 (默认 22): " port - port=${port:-22} - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请选择 (1/2): " auth_choice + while true; do + read -e -p "请输入远程用户@IP: " remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "请输入密码: " password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" - local password_or_key="" - while IFS= read -r line; do - # 如果输入为空行且密钥内容已经包含了开头,则结束输入 - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # 如果是第一行或已经开始输入密钥内容,则继续添加 - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + while true; do + read -e -p "请输入 SSH 端口 (默认 22): " port + port=${port:-22} + if kj_ssh_validate_port "$port"; then + break + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done - # 检查是否是密钥内容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "无效的密钥内容!" - return - fi - ;; - *) - echo "无效的选择!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "请选择同步模式:" echo "1. 标准模式 (-avz)" @@ -7198,6 +7282,7 @@ add_task() { echo "任务已保存!" } + # 删除任务 delete_task() { send_stats "删除同步任务" @@ -8137,10 +8222,10 @@ docker_ssh_migration() { read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - read -e -p "目标服务器IP: " TARGET_IP - read -e -p "目标服务器SSH用户名: " TARGET_USER - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "目标服务器IP: " "目标服务器SSH用户名 [默认root]: " "目标服务器SSH端口 [默认22]: " "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -9604,13 +9689,9 @@ linux_ldnmp() { read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16305,14 +16386,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - read -e -p "请输入远端服务器IP: " remote_ip - read -e -p "目标服务器SSH端口 [默认22]: " TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - continue - fi + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -18374,26 +18450,13 @@ linux_file() { continue fi - read -e -p "请输入远端服务器IP: " remote_ip - if [ -z "$remote_ip" ]; then - echo "错误: 请输入远端服务器IP。" - send_stats "传送文件失败: 未输入远端服务器IP" - continue - fi - - read -e -p "请输入远端服务器用户名 (默认root): " remote_user - remote_user=${remote_user:-root} - - read -e -p "请输入远端服务器密码: " -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "错误: 请输入远端服务器密码。" - send_stats "传送文件失败: 未输入远端服务器密码" - continue - fi + kj_ssh_read_host_user_port "请输入远端服务器IP: " "请输入远端服务器用户名 (默认root): " "请输入登录端口 (默认22): " "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "请输入登录端口 (默认22): " remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "请输入远端服务器密码: " + local remote_password="$KJ_SSH_PASSWORD" # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" From 2e86e467f3e906e6022602658c9f9ebad0da4cae Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 10:42:08 +0800 Subject: [PATCH 0961/1285] refactor(ssh): reuse shared port reader in rsync add_task --- cn/kejilion.sh | 23 +++++++++++++++-------- kejilion.sh | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 04815a27d..9378726f8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6883,6 +6883,19 @@ kj_ssh_read_password() { done } +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done +} + # 显示连接列表 list_connections() { echo "已保存的连接:" @@ -7250,14 +7263,8 @@ add_task() { fi done - while true; do - read -e -p "请输入 SSH 端口 (默认 22): " port - port=${port:-22} - if kj_ssh_validate_port "$port"; then - break - fi - echo "错误: 端口必须是 1-65535 之间的数字。" - done + kj_ssh_read_port "请输入 SSH 端口 (默认 22): " "22" + port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then return diff --git a/kejilion.sh b/kejilion.sh index 8a58d1111..a6354d1ae 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6883,6 +6883,19 @@ kj_ssh_read_password() { done } +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "错误: 端口必须是 1-65535 之间的数字。" + done +} + # 显示连接列表 list_connections() { echo "已保存的连接:" @@ -7250,14 +7263,8 @@ add_task() { fi done - while true; do - read -e -p "请输入 SSH 端口 (默认 22): " port - port=${port:-22} - if kj_ssh_validate_port "$port"; then - break - fi - echo "错误: 端口必须是 1-65535 之间的数字。" - done + kj_ssh_read_port "请输入 SSH 端口 (默认 22): " "22" + port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then return From 9286c2dc469173a6a8fbe19c12e9503d02a0e122 Mon Sep 17 00:00:00 2001 From: Rroqheo <205424156+Rroqheo@users.noreply.github.com> Date: Tue, 10 Mar 2026 05:25:52 -0400 Subject: [PATCH 0962/1285] Update API configuration in client_config --- client_config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client_config b/client_config index 9c041b3db..b447bc14d 100644 --- a/client_config +++ b/client_config @@ -51,4 +51,5 @@ appId=551xxxx7-xxxx-xxxx-xxxx-b9xxxx60cc65 password=T618Q~.LIy_xxxxx~jm~xxxxxx tenant=xxxx3713-xxxx-4cb5-xxxx-3001060xxxxx -azure=end \ No newline at end of file + +azure=end From 06d074bba0c257b7227bd55acdc8b6ab692f9c2b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 18:34:10 +0800 Subject: [PATCH 0963/1285] chore: remove unused client_config template --- client_config | 55 --------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 client_config diff --git a/client_config b/client_config deleted file mode 100644 index b447bc14d..000000000 --- a/client_config +++ /dev/null @@ -1,55 +0,0 @@ -#在oci=begin和oci=end之间放入你的API配置信息 支持多个配置文件 机器人切换profile可更换操作配置 -oci=begin - -[DEFAULT] -user=ocid1.user.oc1..aaaaaaaaxxxxgwlg3xuzwgsaazxtzbozqq -fingerprint=b8:33:6f:xxxx:45:43:33 -tenancy=ocid1.tenancy.oc1..aaaaaaaaxxx7x7h4ya -region=ap-singapore-1 -key_file=写你的API密钥文件路径 - -[DEFAULT2] -user=ocid1.user.oc1..aaaaaaaaxxxxgwlg3xuzwgsaazxtzbozqq -fingerprint=b8:33:6f:xxxx:45:43:33 -tenancy=ocid1.tenancy.oc1..aaaaaaaaxxx7x7h4ya -region=ap-singapore-1 -key_file=写你的API密钥文件路径 - -oci=end - - - -#用户信息 从 https://t.me/radiance_helper_bot 配置(bot可使用/raninfo命令随机生成) -#必传 -username= -#必传 -password= - - -#cloudflare 功能参数 非必传 -#非必传 cloudflare邮箱 -cf_email= -#非必传 cloudflare key 在我的个人资料->API令牌处->API密钥->Global API Key 获取 -cf_account_key= - - -#非必填 本机ip和端口号 (进阶玩家选项 可填写域名) 不写将自动获取本机ip 并使用默认端口号9527 (小白用户建议不填) 如填写 格式为:https://xxx.xx:9527 -local_address= -#非必填 url名称(默认为address 可在bot上修改) -local_url_name= - -#非必填 启动模式 填写local为启动本地无公网IP模式(只要能联网即可) 不填或填其他 则启动端口模式 -model= - - - -#在azure=begin和azure=end之间放入你的azure的API配置信息 支持多个配置文件 机器人切换profile可更换操作配置 上传配置支持使用原格式({"appId":"xxx","password":"xxx"...})上传 -azure=begin - -[az001] -appId=551xxxx7-xxxx-xxxx-xxxx-b9xxxx60cc65 -password=T618Q~.LIy_xxxxx~jm~xxxxxx -tenant=xxxx3713-xxxx-4cb5-xxxx-3001060xxxxx - - -azure=end From ec8dc36d6a80ab9446c85e6ecb3d554dcece00e4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 19:00:34 +0800 Subject: [PATCH 0964/1285] fix(openclaw): use openclaw config set for tools.profile --- cn/kejilion.sh | 3 ++- kejilion.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9378726f8..85646cff6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10473,7 +10473,8 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway add_app_id diff --git a/kejilion.sh b/kejilion.sh index a6354d1ae..668182e8e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10474,7 +10474,8 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway add_app_id From 8da0890745f33e21fdc043cfbd84052937ab7aff Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 10 Mar 2026 22:18:08 +0800 Subject: [PATCH 0965/1285] fix(openclaw): detect openclaw- extension dirs --- cn/kejilion.sh | 10 +++++++++- kejilion.sh | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 85646cff6..051c4c617 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11611,7 +11611,15 @@ PYTHON_EOF if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi - [ -d "${HOME}/.openclaw/extensions/${plugin}" ] || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] + + # 兼容两种常见目录命名: + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] } openclaw_bot_status_text() { diff --git a/kejilion.sh b/kejilion.sh index 668182e8e..2bfb3c866 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11612,7 +11612,15 @@ PYTHON_EOF if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi - [ -d "${HOME}/.openclaw/extensions/${plugin}" ] || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] + + # 兼容两种常见目录命名: + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] } openclaw_bot_status_text() { From ef9cb26263a2d0f7a4021c3bf2ba87ad8e021d21 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 09:33:23 +0800 Subject: [PATCH 0966/1285] chore: append update log entry --- update_log.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/update_log.sh b/update_log.sh index b67131966..0b5656b42 100644 --- a/update_log.sh +++ b/update_log.sh @@ -417,6 +417,7 @@ echo "2024-05-11 v2.5.1" echo "对docker环境检测进行优化,应用部署将会更稳定" echo "对一些提示的文字颜色进行了优化,对一些警示文字进行红色黄色标注" + echo "openclaw的备份还原功能新增" echo "------------------------" From c87231ecdd17fc751cd63c8cecad5bcdf67c7260 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 09:37:52 +0800 Subject: [PATCH 0967/1285] docs(log): note new OpenClaw backup/restore feature --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 8c957d15e..08b1fb386 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1481,4 +1481,5 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 2026-03-09 v4.4.5 应用市场中OpenClaw管理,健康检测后支持API模型自动一致性同步,新增模型自动写入defaults.models,并维护默认模型与回退链路安全切换。 应用市场中OpenClaw管理,API管理菜单支持查看列表、按提供商同步模型、删除API,且对/models探测失败增加3次重试与人工确认删除机制。 +openclaw的备份还原功能新增 From 86b6d9a59a98cf2bc75bd59638a97cdee775f75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 11 Mar 2026 09:47:28 +0800 Subject: [PATCH 0968/1285] Enhance OpenClaw with backup and restore feature Added backup and restore functionality to OpenClaw management. --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 08b1fb386..13e377057 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1481,5 +1481,5 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 2026-03-09 v4.4.5 应用市场中OpenClaw管理,健康检测后支持API模型自动一致性同步,新增模型自动写入defaults.models,并维护默认模型与回退链路安全切换。 应用市场中OpenClaw管理,API管理菜单支持查看列表、按提供商同步模型、删除API,且对/models探测失败增加3次重试与人工确认删除机制。 -openclaw的备份还原功能新增 +应用市场中OpenClaw管理,添加了备份还原功能,包含记忆和完整项目。 From 44984073d56bf9ef85c0a36953b38b6b509cf645 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 14:41:37 +0800 Subject: [PATCH 0969/1285] Restart gateway after model switch --- cn/kejilion.sh | 1 + kejilion.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 051c4c617..c83902f7a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11300,6 +11300,7 @@ PY # 3. 执行切换逻辑 echo "正在切换模型为: $model ..." openclaw models set "$model" + start_gateway break_end done diff --git a/kejilion.sh b/kejilion.sh index 2bfb3c866..cea950fa3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11301,6 +11301,7 @@ PY # 3. 执行切换逻辑 echo "正在切换模型为: $model ..." openclaw models set "$model" + start_gateway break_end done From 2750412e20419e0ecafc002cb59b6bc936f401f5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 14:49:14 +0800 Subject: [PATCH 0970/1285] chore: sync blank line to keep cn script line count --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c83902f7a..b5998b56e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10116,6 +10116,7 @@ with open(path, 'w', encoding='utf-8') as f: PY } + sync_openclaw_api_models() { local config_file="${HOME}/.openclaw/openclaw.json" From a30a48d84b389752a9d0e7c325cd4eb744af5eda Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 19:12:20 +0800 Subject: [PATCH 0971/1285] feat: add OpenClaw memory menu --- cn/kejilion.sh | 173 +++++++++++++++++++++++++++++++++++++++++++++++-- kejilion.sh | 173 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 334 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b5998b56e..5386fde28 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10053,10 +10053,11 @@ moltbot_menu() { echo "12. 健康检测与修复" echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" + echo "15. 记忆/Memory" echo "--------------------" - echo "15. 备份与还原" - echo "16. 更新" - echo "17. 卸载" + echo "16. 备份与还原" + echo "17. 更新" + echo "18. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -12366,6 +12367,165 @@ EOF break_end } + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } + + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "未找到记忆文件。" + return 0 + fi + echo "编号 | 相对路径 | 大小 | 修改时间" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } + + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ 文件不存在: $file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=200 + local start_line count + echo "文件: $file" + echo "总行数: $total_lines" + read -e -p "请输入起始行(默认末尾 $default_lines 行): " start_line + read -e -p "请输入显示行数(默认 $default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 + else + start_line=$((total_lines - count + 1)) + fi + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ 请输入有效的数字。" + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ 行数必须大于 0。" + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(空文件)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" + } + + openclaw_memory_files_menu() { + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆文件" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "请输入文件编号查看(0 返回): " file_choice + if [ "$file_choice" = "0" ]; then + return 0 + fi + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "无效的选择,请重试。" + sleep 1 + continue + fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "未找到记忆文件,按回车返回..." + return 0 + fi + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "无效的编号,请重试。" + sleep 1 + continue + fi + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "按回车返回列表..." + done + } + + openclaw_memory_menu() { + send_stats "OpenClaw记忆管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆管理" + echo "=======================================" + echo "1. 记忆索引状态" + echo "2. 更新记忆索引" + echo "3. 查看记忆文件" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " memory_choice + case "$memory_choice" in + 1) + openclaw memory status + break_end + ;; + 2) + echo "即将更新记忆索引。" + read -e -p "第一次确认:输入 yes 继续: " confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消。" + break_end + continue + fi + read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 + if [ "$confirm_step2" = "force" ]; then + openclaw memory index --force + else + openclaw memory index + fi + break_end + ;; + 3) + openclaw_memory_files_menu + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" while true; do @@ -12607,9 +12767,10 @@ EOF openclaw tui break_end ;; - 15) openclaw_backup_restore_menu ;; - 16) update_moltbot ;; - 17) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done diff --git a/kejilion.sh b/kejilion.sh index cea950fa3..670d8cc1b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10053,10 +10053,11 @@ moltbot_menu() { echo "12. 健康检测与修复" echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" + echo "15. 记忆/Memory" echo "--------------------" - echo "15. 备份与还原" - echo "16. 更新" - echo "17. 卸载" + echo "16. 备份与还原" + echo "17. 更新" + echo "18. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -12366,6 +12367,165 @@ EOF break_end } + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } + + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "未找到记忆文件。" + return 0 + fi + echo "编号 | 相对路径 | 大小 | 修改时间" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } + + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ 文件不存在: $file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=200 + local start_line count + echo "文件: $file" + echo "总行数: $total_lines" + read -e -p "请输入起始行(默认末尾 $default_lines 行): " start_line + read -e -p "请输入显示行数(默认 $default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 + else + start_line=$((total_lines - count + 1)) + fi + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ 请输入有效的数字。" + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ 行数必须大于 0。" + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(空文件)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" + } + + openclaw_memory_files_menu() { + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆文件" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "请输入文件编号查看(0 返回): " file_choice + if [ "$file_choice" = "0" ]; then + return 0 + fi + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "无效的选择,请重试。" + sleep 1 + continue + fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "未找到记忆文件,按回车返回..." + return 0 + fi + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "无效的编号,请重试。" + sleep 1 + continue + fi + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "按回车返回列表..." + done + } + + openclaw_memory_menu() { + send_stats "OpenClaw记忆管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆管理" + echo "=======================================" + echo "1. 记忆索引状态" + echo "2. 更新记忆索引" + echo "3. 查看记忆文件" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " memory_choice + case "$memory_choice" in + 1) + openclaw memory status + break_end + ;; + 2) + echo "即将更新记忆索引。" + read -e -p "第一次确认:输入 yes 继续: " confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消。" + break_end + continue + fi + read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 + if [ "$confirm_step2" = "force" ]; then + openclaw memory index --force + else + openclaw memory index + fi + break_end + ;; + 3) + openclaw_memory_files_menu + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" while true; do @@ -12607,9 +12767,10 @@ EOF openclaw tui break_end ;; - 15) openclaw_backup_restore_menu ;; - 16) update_moltbot ;; - 17) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done From e368c43fa9699c03d875a615eae068cf825a54e4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 19:55:47 +0800 Subject: [PATCH 0972/1285] feat(openclaw): extend memory manager --- cn/kejilion.sh | 322 ++++++++++++++++++++++++- cn/tests_openclaw_memory_menu_smoke.sh | 131 ++++++++++ kejilion.sh | 322 ++++++++++++++++++++++++- tests_openclaw_memory_menu_smoke.sh | 131 ++++++++++ 4 files changed, 898 insertions(+), 8 deletions(-) create mode 100644 cn/tests_openclaw_memory_menu_smoke.sh create mode 100755 tests_openclaw_memory_menu_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5386fde28..9cc1b278a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12367,6 +12367,310 @@ EOF break_end } + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_get_backend() { + local config_file + config_file=$(openclaw_memory_config_file) + [ -s "$config_file" ] || { echo ""; return 0; } + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +try: + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + backend = data.get('memory', {}).get('backend', '') + print(backend if isinstance(backend, str) else '') +except Exception: + print('') +PY + } + + openclaw_memory_get_local_model_path() { + local config_file + config_file=$(openclaw_memory_config_file) + [ -s "$config_file" ] || { echo ""; return 0; } + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +try: + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + obj = data.get('agents', {}).get('defaults', {}).get('memorySearch', {}).get('local', {}) + model_path = obj.get('modelPath', '') if isinstance(obj, dict) else '' + print(model_path if isinstance(model_path, str) else '') +except Exception: + print('') +PY + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + if command -v openclaw >/dev/null 2>&1 && openclaw memory status >/dev/null 2>&1; then + echo "true" + return + fi + if [ -s "${HOME}/.openclaw/openclaw.json" ] && command -v jq >/dev/null 2>&1; then + if jq -e '.memory.backend == "qmd"' "${HOME}/.openclaw/openclaw.json" >/dev/null 2>&1; then + echo "true" + return + fi + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路径: $model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路径") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件不存在或不可用") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可访问") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可达(疑似国内/受限网络)") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + openclaw_memory_apply_scheme() { + local scheme="$1" + local config_file + config_file=$(openclaw_memory_config_file) + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + return 1 + fi + python3 - "$config_file" "$scheme" <<'PY' +import json,sys +path = sys.argv[1] +scheme = sys.argv[2] +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +mem = data.setdefault('memory', {}) +if scheme == 'qmd': + mem['backend'] = 'qmd' + qmd = mem.setdefault('qmd', {}) + qmd.setdefault('command', 'qmd') +elif scheme == 'local': + mem['backend'] = 'local' + agents = data.setdefault('agents', {}) + defaults = agents.setdefault('defaults', {}) + memory_search = defaults.setdefault('memorySearch', {}) + memory_search['provider'] = 'local' +else: + raise SystemExit(2) +with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + echo "✅ 已更新记忆方案配置" + return 0 + } + + openclaw_memory_offer_restart() { + echo "配置已写入,需要重启 OpenClaw 网关后生效。" + read -e -p "是否立即重启 OpenClaw 网关?(Y/n): " restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "已跳过重启,可稍后执行: openclaw gateway restart" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + } + + openclaw_memory_fix_index() { + local config_file + config_file=$(openclaw_memory_config_file) + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" + read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "已取消。" + break_end + return 0 + fi + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +mem = data.setdefault('memory', {}) +qmd = mem.setdefault('qmd', {}) +qmd['includeDefaultMemory'] = False +with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + break_end + return 1 + fi + echo "✅ 已设置 includeDefaultMemory=false" + read -e -p "是否立即执行 openclaw memory index --force?(y/N): " rebuild_choice + if [[ "$rebuild_choice" =~ ^[Yy]$ ]]; then + openclaw memory index --force + fi + break_end + } + + openclaw_memory_scheme_menu() { + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆方案" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + local) current_label="Local" ;; + *) current_label="未配置" ;; + esac + echo "当前方案: $current_label" + echo "" + echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" + echo "Local: 本地向量检索,依赖 embedding 模型文件" + echo "Auto : 自动推荐(基于可用性 + 网络探测)" + echo "---------------------------------------" + echo "1. 自动推荐并应用" + echo "2. 手动选择 QMD" + echo "3. 手动选择 Local" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_recommend + local recommend_label + if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then + recommend_label="QMD" + else + recommend_label="Local" + fi + echo "推荐方案: $recommend_label" + echo "推荐原因:" + for reason in "${OPENCLAW_MEMORY_RECOMMEND_REASON[@]}"; do + echo " - $reason" + done + read -e -p "是否应用该方案?(Y/n): " apply_choice + if [[ "$apply_choice" =~ ^[Nn]$ ]]; then + break_end + continue + fi + openclaw_memory_apply_scheme "$OPENCLAW_MEMORY_RECOMMEND" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 2) + openclaw_memory_apply_scheme "qmd" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 3) + openclaw_memory_apply_scheme "local" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() local base_dir="${HOME}/.openclaw/workspace" @@ -12395,7 +12699,7 @@ EOF rel="${file#$base_dir/}" size=$(ls -lh "$file" | awk '{print $5}') mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') - printf "%s | %s | %s | %s\n" "$((i+1))" "$rel" "$size" "$mtime" + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" done } @@ -12407,12 +12711,12 @@ EOF } local total_lines total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) - local default_lines=200 + local default_lines=120 local start_line count echo "文件: $file" echo "总行数: $total_lines" - read -e -p "请输入起始行(默认末尾 $default_lines 行): " start_line - read -e -p "请输入显示行数(默认 $default_lines): " count + read -e -p "请输入起始行(回车默认末尾 $default_lines 行): " start_line + read -e -p "请输入显示行数(回车默认 $default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -12488,6 +12792,9 @@ EOF echo "1. 记忆索引状态" echo "2. 更新记忆索引" echo "3. 查看记忆文件" + echo "4. 索引修复(Indexed 异常)" + echo "5. 记忆方案(QMD/Local/Auto)" + echo " - Auto 会基于可用性 + 网络探测推荐" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice @@ -12515,6 +12822,12 @@ EOF 3) openclaw_memory_files_menu ;; + 4) + openclaw_memory_fix_index + ;; + 5) + openclaw_memory_scheme_menu + ;; 0) return 0 ;; @@ -12527,6 +12840,7 @@ EOF } openclaw_backup_restore_menu() { + send_stats "OpenClaw备份与还原" while true; do clear diff --git a/cn/tests_openclaw_memory_menu_smoke.sh b/cn/tests_openclaw_memory_menu_smoke.sh new file mode 100644 index 000000000..2166d45df --- /dev/null +++ b/cn/tests_openclaw_memory_menu_smoke.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-menu-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +# 抽取 OpenClaw 记忆菜单实现 +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +cmd="$*" +if [[ "$cmd" == "memory status" ]]; then + cat < "$WORKDIR/bin/qmd" <<'EOF_INNER' +#!/usr/bin/env bash +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/qmd" + +# stub: curl (用于网络探测) +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$*" == *"huggingface.co"* ]]; then + exit 1 +fi +if [[ "$*" == *"hf-mirror.com"* ]]; then + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +# minimal openclaw.json +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "memory": { + "backend": "qmd", + "qmd": {"command": "qmd", "includeDefaultMemory": true} + }, + "agents": { + "defaults": { + "memorySearch": { + "provider": "local", + "local": { + "modelPath": "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" + } + } + } + } +} +JSON + +# mock memory files +cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' +# MEMORY +line1 +line2 +line3 +TXT +cat > "$HOME/.openclaw/workspace/memory/2026-03-11.md" <<'TXT' +# 2026-03-11 +foo +bar +TXT + +source "$WORKDIR/harness.sh" + +run_menu() { + local input="$1" + local title="$2" + echo "[TEST] $title" + printf "%b" "$input" | openclaw_memory_menu >/tmp/memory_menu.out +} + +# 1) 状态 +run_menu "1\n\n0\n" "status" +# 2) 更新索引(增量) +run_menu "2\nyes\n\n\n0\n" "index" +# 3) 查看记忆文件(列表+查看) +run_menu "3\n1\n\n\n\n\n0\n0\n" "files" +# 4) 索引修复(取消) +run_menu "4\n\n0\n" "fix" +# 5) 记忆方案(自动推荐并取消) +run_menu "5\n1\n\nN\n0\n0\n" "scheme" + +echo "SMOKE_OK" diff --git a/kejilion.sh b/kejilion.sh index 670d8cc1b..11097b116 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12367,6 +12367,310 @@ EOF break_end } + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_get_backend() { + local config_file + config_file=$(openclaw_memory_config_file) + [ -s "$config_file" ] || { echo ""; return 0; } + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +try: + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + backend = data.get('memory', {}).get('backend', '') + print(backend if isinstance(backend, str) else '') +except Exception: + print('') +PY + } + + openclaw_memory_get_local_model_path() { + local config_file + config_file=$(openclaw_memory_config_file) + [ -s "$config_file" ] || { echo ""; return 0; } + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +try: + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + obj = data.get('agents', {}).get('defaults', {}).get('memorySearch', {}).get('local', {}) + model_path = obj.get('modelPath', '') if isinstance(obj, dict) else '' + print(model_path if isinstance(model_path, str) else '') +except Exception: + print('') +PY + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + if command -v openclaw >/dev/null 2>&1 && openclaw memory status >/dev/null 2>&1; then + echo "true" + return + fi + if [ -s "${HOME}/.openclaw/openclaw.json" ] && command -v jq >/dev/null 2>&1; then + if jq -e '.memory.backend == "qmd"' "${HOME}/.openclaw/openclaw.json" >/dev/null 2>&1; then + echo "true" + return + fi + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路径: $model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路径") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件不存在或不可用") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可访问") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可达(疑似国内/受限网络)") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + openclaw_memory_apply_scheme() { + local scheme="$1" + local config_file + config_file=$(openclaw_memory_config_file) + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + return 1 + fi + python3 - "$config_file" "$scheme" <<'PY' +import json,sys +path = sys.argv[1] +scheme = sys.argv[2] +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +mem = data.setdefault('memory', {}) +if scheme == 'qmd': + mem['backend'] = 'qmd' + qmd = mem.setdefault('qmd', {}) + qmd.setdefault('command', 'qmd') +elif scheme == 'local': + mem['backend'] = 'local' + agents = data.setdefault('agents', {}) + defaults = agents.setdefault('defaults', {}) + memory_search = defaults.setdefault('memorySearch', {}) + memory_search['provider'] = 'local' +else: + raise SystemExit(2) +with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + echo "✅ 已更新记忆方案配置" + return 0 + } + + openclaw_memory_offer_restart() { + echo "配置已写入,需要重启 OpenClaw 网关后生效。" + read -e -p "是否立即重启 OpenClaw 网关?(Y/n): " restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "已跳过重启,可稍后执行: openclaw gateway restart" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + } + + openclaw_memory_fix_index() { + local config_file + config_file=$(openclaw_memory_config_file) + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" + read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "已取消。" + break_end + return 0 + fi + python3 - "$config_file" <<'PY' +import json,sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +mem = data.setdefault('memory', {}) +qmd = mem.setdefault('qmd', {}) +qmd['includeDefaultMemory'] = False +with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + break_end + return 1 + fi + echo "✅ 已设置 includeDefaultMemory=false" + read -e -p "是否立即执行 openclaw memory index --force?(y/N): " rebuild_choice + if [[ "$rebuild_choice" =~ ^[Yy]$ ]]; then + openclaw memory index --force + fi + break_end + } + + openclaw_memory_scheme_menu() { + while true; do + clear + echo "=======================================" + echo "OpenClaw 记忆方案" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + local) current_label="Local" ;; + *) current_label="未配置" ;; + esac + echo "当前方案: $current_label" + echo "" + echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" + echo "Local: 本地向量检索,依赖 embedding 模型文件" + echo "Auto : 自动推荐(基于可用性 + 网络探测)" + echo "---------------------------------------" + echo "1. 自动推荐并应用" + echo "2. 手动选择 QMD" + echo "3. 手动选择 Local" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_recommend + local recommend_label + if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then + recommend_label="QMD" + else + recommend_label="Local" + fi + echo "推荐方案: $recommend_label" + echo "推荐原因:" + for reason in "${OPENCLAW_MEMORY_RECOMMEND_REASON[@]}"; do + echo " - $reason" + done + read -e -p "是否应用该方案?(Y/n): " apply_choice + if [[ "$apply_choice" =~ ^[Nn]$ ]]; then + break_end + continue + fi + openclaw_memory_apply_scheme "$OPENCLAW_MEMORY_RECOMMEND" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 2) + openclaw_memory_apply_scheme "qmd" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 3) + openclaw_memory_apply_scheme "local" || { break_end; continue; } + openclaw_memory_offer_restart + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() local base_dir="${HOME}/.openclaw/workspace" @@ -12395,7 +12699,7 @@ EOF rel="${file#$base_dir/}" size=$(ls -lh "$file" | awk '{print $5}') mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') - printf "%s | %s | %s | %s\n" "$((i+1))" "$rel" "$size" "$mtime" + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" done } @@ -12407,12 +12711,12 @@ EOF } local total_lines total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) - local default_lines=200 + local default_lines=120 local start_line count echo "文件: $file" echo "总行数: $total_lines" - read -e -p "请输入起始行(默认末尾 $default_lines 行): " start_line - read -e -p "请输入显示行数(默认 $default_lines): " count + read -e -p "请输入起始行(回车默认末尾 $default_lines 行): " start_line + read -e -p "请输入显示行数(回车默认 $default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -12488,6 +12792,9 @@ EOF echo "1. 记忆索引状态" echo "2. 更新记忆索引" echo "3. 查看记忆文件" + echo "4. 索引修复(Indexed 异常)" + echo "5. 记忆方案(QMD/Local/Auto)" + echo " - Auto 会基于可用性 + 网络探测推荐" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice @@ -12515,6 +12822,12 @@ EOF 3) openclaw_memory_files_menu ;; + 4) + openclaw_memory_fix_index + ;; + 5) + openclaw_memory_scheme_menu + ;; 0) return 0 ;; @@ -12527,6 +12840,7 @@ EOF } openclaw_backup_restore_menu() { + send_stats "OpenClaw备份与还原" while true; do clear diff --git a/tests_openclaw_memory_menu_smoke.sh b/tests_openclaw_memory_menu_smoke.sh new file mode 100755 index 000000000..2166d45df --- /dev/null +++ b/tests_openclaw_memory_menu_smoke.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-menu-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +# 抽取 OpenClaw 记忆菜单实现 +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +cmd="$*" +if [[ "$cmd" == "memory status" ]]; then + cat < "$WORKDIR/bin/qmd" <<'EOF_INNER' +#!/usr/bin/env bash +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/qmd" + +# stub: curl (用于网络探测) +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$*" == *"huggingface.co"* ]]; then + exit 1 +fi +if [[ "$*" == *"hf-mirror.com"* ]]; then + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +# minimal openclaw.json +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "memory": { + "backend": "qmd", + "qmd": {"command": "qmd", "includeDefaultMemory": true} + }, + "agents": { + "defaults": { + "memorySearch": { + "provider": "local", + "local": { + "modelPath": "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" + } + } + } + } +} +JSON + +# mock memory files +cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' +# MEMORY +line1 +line2 +line3 +TXT +cat > "$HOME/.openclaw/workspace/memory/2026-03-11.md" <<'TXT' +# 2026-03-11 +foo +bar +TXT + +source "$WORKDIR/harness.sh" + +run_menu() { + local input="$1" + local title="$2" + echo "[TEST] $title" + printf "%b" "$input" | openclaw_memory_menu >/tmp/memory_menu.out +} + +# 1) 状态 +run_menu "1\n\n0\n" "status" +# 2) 更新索引(增量) +run_menu "2\nyes\n\n\n0\n" "index" +# 3) 查看记忆文件(列表+查看) +run_menu "3\n1\n\n\n\n\n0\n0\n" "files" +# 4) 索引修复(取消) +run_menu "4\n\n0\n" "fix" +# 5) 记忆方案(自动推荐并取消) +run_menu "5\n1\n\nN\n0\n0\n" "scheme" + +echo "SMOKE_OK" From 190f2ab31a331438ed91112d72bc58db3bb00398 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 19:56:08 +0800 Subject: [PATCH 0973/1285] refine(openclaw): tidy memory menu text --- cn/kejilion.sh | 1 - kejilion.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9cc1b278a..43c049b8f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12794,7 +12794,6 @@ PY echo "3. 查看记忆文件" echo "4. 索引修复(Indexed 异常)" echo "5. 记忆方案(QMD/Local/Auto)" - echo " - Auto 会基于可用性 + 网络探测推荐" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice diff --git a/kejilion.sh b/kejilion.sh index 11097b116..afdc84148 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12794,7 +12794,6 @@ PY echo "3. 查看记忆文件" echo "4. 索引修复(Indexed 异常)" echo "5. 记忆方案(QMD/Local/Auto)" - echo " - Auto 会基于可用性 + 网络探测推荐" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice From 47fe47e339b7b36cc03083efd3c473e07fd1d7a8 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 22:05:19 +0800 Subject: [PATCH 0974/1285] Update memory menu status display --- cn/kejilion.sh | 30 +++++++++++++++++------------ kejilion.sh | 30 +++++++++++++++++------------ tests_openclaw_memory_menu_smoke.sh | 12 ++++++------ 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 43c049b8f..a3ad782f3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12789,20 +12789,26 @@ PY echo "=======================================" echo "OpenClaw 记忆管理" echo "=======================================" - echo "1. 记忆索引状态" - echo "2. 更新记忆索引" - echo "3. 查看记忆文件" - echo "4. 索引修复(Indexed 异常)" - echo "5. 记忆方案(QMD/Local/Auto)" + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3) + if [ -z "$status_lines" ]; then + echo "未安装/未启动" + else + echo "$status_lines" + fi + fi + echo "1. 更新记忆索引" + echo "2. 查看记忆文件" + echo "3. 索引修复(Indexed 异常)" + echo "4. 记忆方案(QMD/Local/Auto)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice case "$memory_choice" in 1) - openclaw memory status - break_end - ;; - 2) echo "即将更新记忆索引。" read -e -p "第一次确认:输入 yes 继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then @@ -12818,13 +12824,13 @@ PY fi break_end ;; - 3) + 2) openclaw_memory_files_menu ;; - 4) + 3) openclaw_memory_fix_index ;; - 5) + 4) openclaw_memory_scheme_menu ;; 0) diff --git a/kejilion.sh b/kejilion.sh index afdc84148..af7395f4a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12789,20 +12789,26 @@ PY echo "=======================================" echo "OpenClaw 记忆管理" echo "=======================================" - echo "1. 记忆索引状态" - echo "2. 更新记忆索引" - echo "3. 查看记忆文件" - echo "4. 索引修复(Indexed 异常)" - echo "5. 记忆方案(QMD/Local/Auto)" + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3) + if [ -z "$status_lines" ]; then + echo "未安装/未启动" + else + echo "$status_lines" + fi + fi + echo "1. 更新记忆索引" + echo "2. 查看记忆文件" + echo "3. 索引修复(Indexed 异常)" + echo "4. 记忆方案(QMD/Local/Auto)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice case "$memory_choice" in 1) - openclaw memory status - break_end - ;; - 2) echo "即将更新记忆索引。" read -e -p "第一次确认:输入 yes 继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then @@ -12818,13 +12824,13 @@ PY fi break_end ;; - 3) + 2) openclaw_memory_files_menu ;; - 4) + 3) openclaw_memory_fix_index ;; - 5) + 4) openclaw_memory_scheme_menu ;; 0) diff --git a/tests_openclaw_memory_menu_smoke.sh b/tests_openclaw_memory_menu_smoke.sh index 2166d45df..e15cd3866 100755 --- a/tests_openclaw_memory_menu_smoke.sh +++ b/tests_openclaw_memory_menu_smoke.sh @@ -117,15 +117,15 @@ run_menu() { printf "%b" "$input" | openclaw_memory_menu >/tmp/memory_menu.out } -# 1) 状态 -run_menu "1\n\n0\n" "status" +# 1) 状态展示(直接返回) +run_menu "0\n" "status" # 2) 更新索引(增量) -run_menu "2\nyes\n\n\n0\n" "index" +run_menu "1\nyes\n\n\n0\n" "index" # 3) 查看记忆文件(列表+查看) -run_menu "3\n1\n\n\n\n\n0\n0\n" "files" +run_menu "2\n1\n\n\n\n\n0\n0\n" "files" # 4) 索引修复(取消) -run_menu "4\n\n0\n" "fix" +run_menu "3\n\n0\n" "fix" # 5) 记忆方案(自动推荐并取消) -run_menu "5\n1\n\nN\n0\n0\n" "scheme" +run_menu "4\n1\n\nN\n0\n0\n" "scheme" echo "SMOKE_OK" From 6b0a29949b64654c0e4eee84ac3a14a920c18c33 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 22:38:37 +0800 Subject: [PATCH 0975/1285] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=8C=96=E8=AE=B0?= =?UTF-8?q?=E5=BF=86=E7=AE=A1=E7=90=86=E7=8A=B6=E6=80=81=E5=8D=A1=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a3ad782f3..63f092907 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12793,7 +12793,7 @@ PY if [ $? -ne 0 ] || [ -z "$status_output" ]; then echo "获取状态失败" else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3) + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') if [ -z "$status_lines" ]; then echo "未安装/未启动" else diff --git a/kejilion.sh b/kejilion.sh index af7395f4a..a9bade776 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12793,7 +12793,7 @@ PY if [ $? -ne 0 ] || [ -z "$status_output" ]; then echo "获取状态失败" else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3) + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') if [ -z "$status_lines" ]; then echo "未安装/未启动" else From eb91dfbc496cc9b328671cdcfd7353b9a7a5d04b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 22:50:07 +0800 Subject: [PATCH 0976/1285] Update log for v4.4.5 memory console --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 13e377057..47b8d3765 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1482,4 +1482,5 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,健康检测后支持API模型自动一致性同步,新增模型自动写入defaults.models,并维护默认模型与回退链路安全切换。 应用市场中OpenClaw管理,API管理菜单支持查看列表、按提供商同步模型、删除API,且对/models探测失败增加3次重试与人工确认删除机制。 应用市场中OpenClaw管理,添加了备份还原功能,包含记忆和完整项目。 +应用市场中OpenClaw管理,新增独立且中文化的记忆管理控制台,支持方案自动探测、索引状态查看与重复收录一键修复。 From d4e33795e0d660672e966c27bfe0d8f8817523a5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 23:29:37 +0800 Subject: [PATCH 0977/1285] feat: batch plugin/skill management --- cn/kejilion.sh | 324 +++++++++++++------ cn/tests_openclaw_plugin_skill_menu_smoke.sh | 132 ++++++++ kejilion.sh | 322 ++++++++++++------ tests_openclaw_plugin_skill_menu_smoke.sh | 132 ++++++++ 4 files changed, 729 insertions(+), 181 deletions(-) create mode 100644 cn/tests_openclaw_plugin_skill_menu_smoke.sh create mode 100755 tests_openclaw_plugin_skill_menu_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 63f092907..54d69b8ed 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -10046,8 +10046,8 @@ moltbot_menu() { echo "5. 换模型" echo "6. API管理" echo "7. 机器人连接对接" - echo "8. 安装插件(如:飞书)" - echo "9. 安装技能(skills)" + echo "8. 插件管理(安装/删除)" + echo "9. 技能管理(安装/删除)" echo "10. 编辑主配置文件" echo "11. 配置向导" echo "12. 健康检测与修复" @@ -11393,15 +11393,86 @@ PYTHON_EOF return 1 } + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已从 plugins.allow 移除: $plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已从 plugins.allow 移除: $plugin_id" + return 0 + fi + fi + + echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" + return 1 + } + + + install_plugin() { - send_stats "安装插件" + send_stats "插件管理" while true; do clear echo "========================================" - echo " 插件管理 (安装) " + echo " 插件管理 (安装/删除) " echo "========================================" echo "当前插件列表:" openclaw plugins list @@ -11427,77 +11498,110 @@ PYTHON_EOF echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" - read -e -p "请输入插件 ID(输入 0 退出): " raw_input + echo "1) 安装/启用插件" + echo "2) 删除/禁用插件" + echo "0) 返回" + read -e -p "请选择操作:" plugin_action + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue - # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 - local plugin_id=$(resolve_openclaw_plugin_id "$raw_input") - local plugin_full="$raw_input" - - echo "🔍 正在检查插件状态..." - # 获取当前插件列表用于状态检测 - local plugin_list=$(openclaw plugins list 2>/dev/null) - - # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已预装,正在激活..." - openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" - - # 3. 检查系统物理目录是否存在 - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 发现系统内置目录存在该插件,尝试直接启用..." - openclaw plugins enable "$plugin_id" - - else - # 4. 远程安装逻辑 - echo "📥 本地未发现,尝试下载安装..." + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 正在检查插件状态: $plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已预装,正在激活..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi - # 清理旧的失败残留 - rm -rf "/root/.openclaw/extensions/$plugin_id" + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi - # 执行安装,并捕获结果 - if openclaw plugins install "$plugin_full"; then - echo "✅ 下载成功,正在启用..." - openclaw plugins enable "$plugin_id" + echo "📥 本地未发现,尝试下载安装: $plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ 下载成功,正在启用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ 安装失败:$plugin_full" + failed_list="$failed_list $plugin_id" + fi else - echo "⚠️ 官方渠道下载失败,尝试备选方案..." - # 备选 npm 安装 - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm 安装成功,尝试启用..." - openclaw plugins enable "$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ 已卸载: $plugin_id" else - echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" - # 关键:这里直接 return 或 continue,不走下面的 start_gateway,防止写死配置 - break_end - continue + echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true fi - fi - - echo "🔐 正在同步 plugins.allow 白名单..." - sync_openclaw_plugin_allowlist "$plugin_id" + done + echo "" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" - echo "🔄 正在重启 OpenClaw 服务以加载新插件..." - start_gateway + if [ "$changed" = true ]; then + echo "🔄 正在重启 OpenClaw 服务以加载变更..." + start_gateway + fi break_end done } - - - - - install_skill() { - send_stats "安装技能" + send_stats "技能管理" while true; do clear echo "========================================" - echo " 技能管理 (安装) " + echo " 技能管理 (安装/删除) " echo "========================================" echo "当前已安装技能:" openclaw skills list @@ -11521,57 +11625,95 @@ PYTHON_EOF echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" echo "----------------------------------------" - # 提示用户输入技能名称 - read -e -p "请输入要安装的技能名称(输入 0 退出): " skill_name + echo "1) 安装技能" + echo "2) 删除技能" + echo "0) 返回" + read -e -p "请选择操作:" skill_action - # 1. 检查是否输入 0 以退出 - if [ "$skill_name" = "0" ]; then - echo "操作已取消,退出技能安装。" - break - fi + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue - # 2. 验证输入是否为空 - if [ -z "$skill_name" ]; then - echo "错误:技能名称不能为空。请重试。" - echo "" - continue - fi + read -e -p "请输入技能名称(空格分隔,输入 0 退出): " skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue - # 3. 检查技能是否已安装 - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在用户目录安装。" - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系统目录安装。" - skill_found=true - fi + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token - if [ "$skill_found" = true ]; then - read -e -p "是否重新安装?(y/N): " reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "跳过安装。" + if [ "$skill_action" = "2" ]; then + read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续?(y/N): " confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "已取消删除。" break_end continue fi fi - # 4. 执行安装命令 - echo "正在安装技能:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ 技能 $skill_name 安装成功。" + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在用户目录安装。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系统目录安装。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "技能 [$skill_name] 已安装,是否重新安装?(y/N): " reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "正在安装技能:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ 技能 $skill_name 安装成功。" + success_list="$success_list $skill_name" + changed=true + else + echo "❌ 安装失败:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ 正在删除技能: $skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ 已删除用户技能目录: $skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ 未发现用户技能目录: $skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway - else - echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" fi - break_end done } - - - openclaw_json_get_bool() { +openclaw_json_get_bool() { local expr="$1" local config_file="${HOME}/.openclaw/openclaw.json" if [ ! -s "$config_file" ]; then diff --git a/cn/tests_openclaw_plugin_skill_menu_smoke.sh b/cn/tests_openclaw_plugin_skill_menu_smoke.sh new file mode 100644 index 000000000..28adf7806 --- /dev/null +++ b/cn/tests_openclaw_plugin_skill_menu_smoke.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-plugin-skill-menu-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/skills" "$WORKDIR/home/.openclaw" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +start_gateway() { openclaw gateway stop; openclaw gateway start; } +EOF_INNER + +# 抽取插件/技能管理实现 +awk 'BEGIN{p=0} /resolve_openclaw_plugin_id\(\) \{/{p=1} /openclaw_json_get_bool\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +cmd="$*" +if [[ "$cmd" == "plugins list" ]]; then + cat <> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins install"* ]]; then + echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins disable"* ]]; then + echo "disable $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins uninstall"* ]]; then + # 模拟预装卸载失败 + if [[ "$cmd" == *"feishu"* ]]; then + exit 1 + fi + echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "skills list" ]]; then + echo "skill1" + exit 0 +fi +if [[ "$cmd" == "gateway stop" ]]; then + echo "gateway stop" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "gateway start" ]]; then + echo "gateway start" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +echo "mock openclaw $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" +EOF_INNER +chmod +x "$WORKDIR/bin/openclaw" + +# stub: npx +cat > "$WORKDIR/bin/npx" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$*" == *"clawhub uninstall"* ]]; then + echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$*" == *"clawhub install"* ]]; then + echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/npx" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm +export TEST_LOG="$WORKDIR/test.log" + +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{"plugins":{"allow":["telegram","feishu"]}} +JSON + +# 模拟用户技能目录 +mkdir -p "$HOME/.openclaw/workspace/skills/skillA" + +source "$WORKDIR/harness.sh" + +# 插件安装:多输入,确保只重启一次 +printf "1\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_install.out" + +# 插件删除:多输入,确保删除流程与 allowlist 移除 +printf "2\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_delete.out" + +# 技能删除:二次确认 + 多输入,删除目录 +printf "2\nskillA skillB\ny\n0\n" | install_skill > "$WORKDIR/skill_delete.out" + +# 断言:start_gateway 只调用一次/每次菜单 +start_count=$(grep -c "gateway start" "$TEST_LOG" || true) +if [ "$start_count" -ne 3 ]; then + echo "Expected 3 gateway starts (plugin install/delete + skill delete), got $start_count" + exit 1 +fi + +# 断言:用户技能目录已删除 +if [ -d "$HOME/.openclaw/workspace/skills/skillA" ]; then + echo "Skill directory was not removed" + exit 1 +fi + +# 断言:plugins.allow 移除 +if grep -q '"feishu"' "$HOME/.openclaw/openclaw.json"; then + echo "feishu still in plugins.allow" + exit 1 +fi + +# 断言:输出汇总 +grep -q "操作汇总" "$WORKDIR/plugin_install.out" +grep -q "操作汇总" "$WORKDIR/plugin_delete.out" +grep -q "操作汇总" "$WORKDIR/skill_delete.out" + +echo "SMOKE_OK" diff --git a/kejilion.sh b/kejilion.sh index a9bade776..54d69b8ed 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10046,8 +10046,8 @@ moltbot_menu() { echo "5. 换模型" echo "6. API管理" echo "7. 机器人连接对接" - echo "8. 安装插件(如:飞书)" - echo "9. 安装技能(skills)" + echo "8. 插件管理(安装/删除)" + echo "9. 技能管理(安装/删除)" echo "10. 编辑主配置文件" echo "11. 配置向导" echo "12. 健康检测与修复" @@ -11393,15 +11393,86 @@ PYTHON_EOF return 1 } + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已从 plugins.allow 移除: $plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已从 plugins.allow 移除: $plugin_id" + return 0 + fi + fi + + echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" + return 1 + } + + + install_plugin() { - send_stats "安装插件" + send_stats "插件管理" while true; do clear echo "========================================" - echo " 插件管理 (安装) " + echo " 插件管理 (安装/删除) " echo "========================================" echo "当前插件列表:" openclaw plugins list @@ -11427,77 +11498,110 @@ PYTHON_EOF echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" - read -e -p "请输入插件 ID(输入 0 退出): " raw_input + echo "1) 安装/启用插件" + echo "2) 删除/禁用插件" + echo "0) 返回" + read -e -p "请选择操作:" plugin_action + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue - # 1. 自动处理:如果用户输入带 @openclaw/,提取纯 ID 方便路径检查 - local plugin_id=$(resolve_openclaw_plugin_id "$raw_input") - local plugin_full="$raw_input" - - echo "🔍 正在检查插件状态..." - # 获取当前插件列表用于状态检测 - local plugin_list=$(openclaw plugins list 2>/dev/null) - - # 2. 检查是否已经在 list 中且为 disabled (最常见的情况) - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已预装,正在激活..." - openclaw plugins enable "$plugin_id" && echo "✅ 激活成功" || echo "❌ 激活失败" - - # 3. 检查系统物理目录是否存在 - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 发现系统内置目录存在该插件,尝试直接启用..." - openclaw plugins enable "$plugin_id" - - else - # 4. 远程安装逻辑 - echo "📥 本地未发现,尝试下载安装..." + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 正在检查插件状态: $plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已预装,正在激活..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi - # 清理旧的失败残留 - rm -rf "/root/.openclaw/extensions/$plugin_id" + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi - # 执行安装,并捕获结果 - if openclaw plugins install "$plugin_full"; then - echo "✅ 下载成功,正在启用..." - openclaw plugins enable "$plugin_id" + echo "📥 本地未发现,尝试下载安装: $plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ 下载成功,正在启用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ 安装失败:$plugin_full" + failed_list="$failed_list $plugin_id" + fi else - echo "⚠️ 官方渠道下载失败,尝试备选方案..." - # 备选 npm 安装 - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm 安装成功,尝试启用..." - openclaw plugins enable "$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ 已卸载: $plugin_id" else - echo "❌ 严重错误:无法获取该插件。请检查 ID 是否正确或网络是否可用。" - # 关键:这里直接 return 或 continue,不走下面的 start_gateway,防止写死配置 - break_end - continue + echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true fi - fi - - echo "🔐 正在同步 plugins.allow 白名单..." - sync_openclaw_plugin_allowlist "$plugin_id" + done + echo "" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" - echo "🔄 正在重启 OpenClaw 服务以加载新插件..." - start_gateway + if [ "$changed" = true ]; then + echo "🔄 正在重启 OpenClaw 服务以加载变更..." + start_gateway + fi break_end done } - - - - - install_skill() { - send_stats "安装技能" + send_stats "技能管理" while true; do clear echo "========================================" - echo " 技能管理 (安装) " + echo " 技能管理 (安装/删除) " echo "========================================" echo "当前已安装技能:" openclaw skills list @@ -11521,57 +11625,95 @@ PYTHON_EOF echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" echo "----------------------------------------" - # 提示用户输入技能名称 - read -e -p "请输入要安装的技能名称(输入 0 退出): " skill_name + echo "1) 安装技能" + echo "2) 删除技能" + echo "0) 返回" + read -e -p "请选择操作:" skill_action - # 1. 检查是否输入 0 以退出 - if [ "$skill_name" = "0" ]; then - echo "操作已取消,退出技能安装。" - break - fi + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue - # 2. 验证输入是否为空 - if [ -z "$skill_name" ]; then - echo "错误:技能名称不能为空。请重试。" - echo "" - continue - fi + read -e -p "请输入技能名称(空格分隔,输入 0 退出): " skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue - # 3. 检查技能是否已安装 - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在用户目录安装。" - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系统目录安装。" - skill_found=true - fi + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token - if [ "$skill_found" = true ]; then - read -e -p "是否重新安装?(y/N): " reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "跳过安装。" + if [ "$skill_action" = "2" ]; then + read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续?(y/N): " confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "已取消删除。" break_end continue fi fi - # 4. 执行安装命令 - echo "正在安装技能:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ 技能 $skill_name 安装成功。" + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在用户目录安装。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系统目录安装。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "技能 [$skill_name] 已安装,是否重新安装?(y/N): " reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "正在安装技能:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ 技能 $skill_name 安装成功。" + success_list="$success_list $skill_name" + changed=true + else + echo "❌ 安装失败:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ 正在删除技能: $skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ 已删除用户技能目录: $skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ 未发现用户技能目录: $skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway - else - echo "❌ 安装失败。请检查技能名称是否正确,或参考文档排查。" fi - break_end done } - - - openclaw_json_get_bool() { +openclaw_json_get_bool() { local expr="$1" local config_file="${HOME}/.openclaw/openclaw.json" if [ ! -s "$config_file" ]; then diff --git a/tests_openclaw_plugin_skill_menu_smoke.sh b/tests_openclaw_plugin_skill_menu_smoke.sh new file mode 100755 index 000000000..28adf7806 --- /dev/null +++ b/tests_openclaw_plugin_skill_menu_smoke.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-plugin-skill-menu-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/skills" "$WORKDIR/home/.openclaw" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +start_gateway() { openclaw gateway stop; openclaw gateway start; } +EOF_INNER + +# 抽取插件/技能管理实现 +awk 'BEGIN{p=0} /resolve_openclaw_plugin_id\(\) \{/{p=1} /openclaw_json_get_bool\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +cmd="$*" +if [[ "$cmd" == "plugins list" ]]; then + cat <> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins install"* ]]; then + echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins disable"* ]]; then + echo "disable $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "plugins uninstall"* ]]; then + # 模拟预装卸载失败 + if [[ "$cmd" == *"feishu"* ]]; then + exit 1 + fi + echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "skills list" ]]; then + echo "skill1" + exit 0 +fi +if [[ "$cmd" == "gateway stop" ]]; then + echo "gateway stop" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$cmd" == "gateway start" ]]; then + echo "gateway start" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +echo "mock openclaw $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" +EOF_INNER +chmod +x "$WORKDIR/bin/openclaw" + +# stub: npx +cat > "$WORKDIR/bin/npx" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$*" == *"clawhub uninstall"* ]]; then + echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +if [[ "$*" == *"clawhub install"* ]]; then + echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/npx" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm +export TEST_LOG="$WORKDIR/test.log" + +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{"plugins":{"allow":["telegram","feishu"]}} +JSON + +# 模拟用户技能目录 +mkdir -p "$HOME/.openclaw/workspace/skills/skillA" + +source "$WORKDIR/harness.sh" + +# 插件安装:多输入,确保只重启一次 +printf "1\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_install.out" + +# 插件删除:多输入,确保删除流程与 allowlist 移除 +printf "2\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_delete.out" + +# 技能删除:二次确认 + 多输入,删除目录 +printf "2\nskillA skillB\ny\n0\n" | install_skill > "$WORKDIR/skill_delete.out" + +# 断言:start_gateway 只调用一次/每次菜单 +start_count=$(grep -c "gateway start" "$TEST_LOG" || true) +if [ "$start_count" -ne 3 ]; then + echo "Expected 3 gateway starts (plugin install/delete + skill delete), got $start_count" + exit 1 +fi + +# 断言:用户技能目录已删除 +if [ -d "$HOME/.openclaw/workspace/skills/skillA" ]; then + echo "Skill directory was not removed" + exit 1 +fi + +# 断言:plugins.allow 移除 +if grep -q '"feishu"' "$HOME/.openclaw/openclaw.json"; then + echo "feishu still in plugins.allow" + exit 1 +fi + +# 断言:输出汇总 +grep -q "操作汇总" "$WORKDIR/plugin_install.out" +grep -q "操作汇总" "$WORKDIR/plugin_delete.out" +grep -q "操作汇总" "$WORKDIR/skill_delete.out" + +echo "SMOKE_OK" From e80e9daf738a3415aed05bea890767c6592611d7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 11 Mar 2026 23:45:18 +0800 Subject: [PATCH 0978/1285] fix(openclaw): detect active config file for memory menu --- cn/kejilion.sh | 83 +++++++++++++++++++++----- cn/tests_openclaw_memory_menu_smoke.sh | 29 ++++++--- kejilion.sh | 83 +++++++++++++++++++++----- tests_openclaw_memory_menu_smoke.sh | 21 +++++-- 4 files changed, 174 insertions(+), 42 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 54d69b8ed..48fc5c37d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12510,9 +12510,65 @@ EOF } openclaw_memory_config_file() { + local detected expanded + if command -v openclaw >/dev/null 2>&1; then + detected=$(openclaw config file 2>/dev/null | head -n 1 | tr -d '\r') + fi + if [ -n "$detected" ]; then + expanded=$(python3 - "$detected" <<'PY' +import os,sys +path = sys.argv[1] +if not path: + print('') +else: + print(os.path.expandvars(os.path.expanduser(path))) +PY +) + if [ -n "$expanded" ]; then + echo "$expanded" + return 0 + fi + fi echo "${HOME}/.openclaw/openclaw.json" } + openclaw_memory_config_display() { + local path="$1" + local display head tail + if [ -z "$path" ]; then + echo "未知" + return + fi + display="$path" + if [ -n "$HOME" ]; then + display="${display/#$HOME/~}" + fi + if [ ${#display} -gt 48 ]; then + head="${display:0:20}" + tail="${display: -20}" + display="${head}...${tail}" + fi + echo "$display" + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') + if [ -z "$status_lines" ]; then + echo "未安装/未启动" + else + echo "$status_lines" + fi + fi + config_file=$(openclaw_memory_config_file) + config_display=$(openclaw_memory_config_display "$config_file") + echo "配置文件: $config_display" + } + openclaw_memory_get_backend() { local config_file config_file=$(openclaw_memory_config_file) @@ -12574,8 +12630,10 @@ PY echo "true" return fi - if [ -s "${HOME}/.openclaw/openclaw.json" ] && command -v jq >/dev/null 2>&1; then - if jq -e '.memory.backend == "qmd"' "${HOME}/.openclaw/openclaw.json" >/dev/null 2>&1; then + local config_file + config_file=$(openclaw_memory_config_file) + if [ -s "$config_file" ] && command -v jq >/dev/null 2>&1; then + if jq -e '.memory.backend == "qmd"' "$config_file" >/dev/null 2>&1; then echo "true" return fi @@ -12737,9 +12795,14 @@ PY return 1 fi echo "✅ 已设置 includeDefaultMemory=false" - read -e -p "是否立即执行 openclaw memory index --force?(y/N): " rebuild_choice - if [[ "$rebuild_choice" =~ ^[Yy]$ ]]; then + echo "建议立即执行:openclaw memory index --force" + read -e -p "是否立即执行 openclaw memory index --force?(Y/n): " rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then openclaw memory index --force + echo "" + openclaw_memory_render_status + else + echo "可稍后在记忆管理中查看状态。" fi break_end } @@ -12931,17 +12994,7 @@ PY echo "=======================================" echo "OpenClaw 记忆管理" echo "=======================================" - status_output=$(openclaw memory status 2>/dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') - if [ -z "$status_lines" ]; then - echo "未安装/未启动" - else - echo "$status_lines" - fi - fi + openclaw_memory_render_status echo "1. 更新记忆索引" echo "2. 查看记忆文件" echo "3. 索引修复(Indexed 异常)" diff --git a/cn/tests_openclaw_memory_menu_smoke.sh b/cn/tests_openclaw_memory_menu_smoke.sh index 2166d45df..23230b81d 100644 --- a/cn/tests_openclaw_memory_menu_smoke.sh +++ b/cn/tests_openclaw_memory_menu_smoke.sh @@ -31,6 +31,10 @@ Indexed: 5/5 files TXT exit 0 fi +if [[ "$cmd" == "config file" ]]; then + echo "~/.openclaw/custom-openclaw.json" + exit 0 +fi if [[ "$cmd" == "memory index"* ]]; then echo "index ok" exit 0 @@ -76,7 +80,7 @@ export PATH="$WORKDIR/bin:$PATH" export TERM=xterm # minimal openclaw.json -cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +cat > "$HOME/.openclaw/custom-openclaw.json" <<'JSON' { "memory": { "backend": "qmd", @@ -118,14 +122,23 @@ run_menu() { } # 1) 状态 -run_menu "1\n\n0\n" "status" +run_menu "0\n" "status" # 2) 更新索引(增量) -run_menu "2\nyes\n\n\n0\n" "index" +run_menu "1\nyes\n\n\n0\n" "index" # 3) 查看记忆文件(列表+查看) -run_menu "3\n1\n\n\n\n\n0\n0\n" "files" -# 4) 索引修复(取消) -run_menu "4\n\n0\n" "fix" +run_menu "2\n1\n\n\n\n\n0\n0\n" "files" +# 4) 索引修复(执行修复 + 不立即重建) +run_menu "3\ny\n\nN\n0\n" "fix" # 5) 记忆方案(自动推荐并取消) -run_menu "5\n1\n\nN\n0\n0\n" "scheme" +run_menu "4\n1\n\nN\n0\n0\n" "scheme" -echo "SMOKE_OK" +python3 - <<'PY' +import json,os,sys +path = os.path.expanduser('~/.openclaw/custom-openclaw.json') +with open(path,'r',encoding='utf-8') as f: + data = json.load(f) +flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) +if flag is not False: + raise SystemExit('includeDefaultMemory not updated') +print('SMOKE_OK') +PY diff --git a/kejilion.sh b/kejilion.sh index 54d69b8ed..48fc5c37d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12510,9 +12510,65 @@ EOF } openclaw_memory_config_file() { + local detected expanded + if command -v openclaw >/dev/null 2>&1; then + detected=$(openclaw config file 2>/dev/null | head -n 1 | tr -d '\r') + fi + if [ -n "$detected" ]; then + expanded=$(python3 - "$detected" <<'PY' +import os,sys +path = sys.argv[1] +if not path: + print('') +else: + print(os.path.expandvars(os.path.expanduser(path))) +PY +) + if [ -n "$expanded" ]; then + echo "$expanded" + return 0 + fi + fi echo "${HOME}/.openclaw/openclaw.json" } + openclaw_memory_config_display() { + local path="$1" + local display head tail + if [ -z "$path" ]; then + echo "未知" + return + fi + display="$path" + if [ -n "$HOME" ]; then + display="${display/#$HOME/~}" + fi + if [ ${#display} -gt 48 ]; then + head="${display:0:20}" + tail="${display: -20}" + display="${head}...${tail}" + fi + echo "$display" + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') + if [ -z "$status_lines" ]; then + echo "未安装/未启动" + else + echo "$status_lines" + fi + fi + config_file=$(openclaw_memory_config_file) + config_display=$(openclaw_memory_config_display "$config_file") + echo "配置文件: $config_display" + } + openclaw_memory_get_backend() { local config_file config_file=$(openclaw_memory_config_file) @@ -12574,8 +12630,10 @@ PY echo "true" return fi - if [ -s "${HOME}/.openclaw/openclaw.json" ] && command -v jq >/dev/null 2>&1; then - if jq -e '.memory.backend == "qmd"' "${HOME}/.openclaw/openclaw.json" >/dev/null 2>&1; then + local config_file + config_file=$(openclaw_memory_config_file) + if [ -s "$config_file" ] && command -v jq >/dev/null 2>&1; then + if jq -e '.memory.backend == "qmd"' "$config_file" >/dev/null 2>&1; then echo "true" return fi @@ -12737,9 +12795,14 @@ PY return 1 fi echo "✅ 已设置 includeDefaultMemory=false" - read -e -p "是否立即执行 openclaw memory index --force?(y/N): " rebuild_choice - if [[ "$rebuild_choice" =~ ^[Yy]$ ]]; then + echo "建议立即执行:openclaw memory index --force" + read -e -p "是否立即执行 openclaw memory index --force?(Y/n): " rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then openclaw memory index --force + echo "" + openclaw_memory_render_status + else + echo "可稍后在记忆管理中查看状态。" fi break_end } @@ -12931,17 +12994,7 @@ PY echo "=======================================" echo "OpenClaw 记忆管理" echo "=======================================" - status_output=$(openclaw memory status 2>/dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') - if [ -z "$status_lines" ]; then - echo "未安装/未启动" - else - echo "$status_lines" - fi - fi + openclaw_memory_render_status echo "1. 更新记忆索引" echo "2. 查看记忆文件" echo "3. 索引修复(Indexed 异常)" diff --git a/tests_openclaw_memory_menu_smoke.sh b/tests_openclaw_memory_menu_smoke.sh index e15cd3866..bdba703da 100755 --- a/tests_openclaw_memory_menu_smoke.sh +++ b/tests_openclaw_memory_menu_smoke.sh @@ -31,6 +31,10 @@ Indexed: 5/5 files TXT exit 0 fi +if [[ "$cmd" == "config file" ]]; then + echo "~/.openclaw/custom-openclaw.json" + exit 0 +fi if [[ "$cmd" == "memory index"* ]]; then echo "index ok" exit 0 @@ -76,7 +80,7 @@ export PATH="$WORKDIR/bin:$PATH" export TERM=xterm # minimal openclaw.json -cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +cat > "$HOME/.openclaw/custom-openclaw.json" <<'JSON' { "memory": { "backend": "qmd", @@ -123,9 +127,18 @@ run_menu "0\n" "status" run_menu "1\nyes\n\n\n0\n" "index" # 3) 查看记忆文件(列表+查看) run_menu "2\n1\n\n\n\n\n0\n0\n" "files" -# 4) 索引修复(取消) -run_menu "3\n\n0\n" "fix" +# 4) 索引修复(执行修复 + 不立即重建) +run_menu "3\ny\n\nN\n0\n" "fix" # 5) 记忆方案(自动推荐并取消) run_menu "4\n1\n\nN\n0\n0\n" "scheme" -echo "SMOKE_OK" +python3 - <<'PY' +import json,os,sys +path = os.path.expanduser('~/.openclaw/custom-openclaw.json') +with open(path,'r',encoding='utf-8') as f: + data = json.load(f) +flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) +if flag is not False: + raise SystemExit('includeDefaultMemory not updated') +print('SMOKE_OK') +PY From a05f3610fc150d6f372dd48bea612ea3582cb4b2 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 00:17:05 +0800 Subject: [PATCH 0979/1285] Fix OpenClaw API protocol detection and repair --- cn/kejilion.sh | 318 +++++++++++++++++- ...ests_openclaw_api_protocol_detect_smoke.sh | 1 + kejilion.sh | 318 +++++++++++++++++- tests_openclaw_api_protocol_detect_smoke.sh | 90 +++++ 4 files changed, 711 insertions(+), 16 deletions(-) create mode 120000 cn/tests_openclaw_api_protocol_detect_smoke.sh create mode 100644 tests_openclaw_api_protocol_detect_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 48fc5c37d..520410ce8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10139,6 +10139,39 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + + def send_stat(action): if not stats_enabled: return @@ -10301,6 +10334,39 @@ def delete_provider_and_refs(name): return True +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + + def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10341,6 +10407,16 @@ for name, provider in list(providers.items()): summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') continue + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -10513,6 +10589,52 @@ PY + # OpenClaw API 协议探测(优先 responses -> chat/completions -> completions) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + local code_chat="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses & /chat/completions not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + code_chat=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/chat/completions") + if [[ "$code_chat" != "404" && "$code_chat" != "405" && "$code_chat" != "000" ]]; then + DETECTED_API="openai-chat-completions" + DETECTED_REASON="POST /chat/completions -> HTTP $code_chat" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses, /chat/completions=$code_chat -> fallback /completions" + return 0 + } + # 核心函数:获取并添加所有模型 add-all-models-from-provider() { local provider_name="$1" @@ -10522,6 +10644,10 @@ PY echo "🔍 正在获取 $provider_name 的所有可用模型..." + # 自动识别 API 协议 + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # 获取模型列表 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10601,6 +10727,7 @@ EOF jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10609,7 +10736,7 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) @@ -10669,7 +10796,11 @@ EOF echo done - # 4. 获取模型列表 + # 4. 协议探测(无感) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. 获取模型列表 echo "🔍 正在获取可用模型列表..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10684,10 +10815,10 @@ EOF echo "--------------------------------" # 全部显示,带序号 i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10701,8 +10832,8 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 使用第一个模型: $default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 已选择模型: $default_model" else default_model="$input_model" @@ -10733,6 +10864,7 @@ EOF openclaw models set "$provider_name/$default_model" start_gateway echo "✅ 完成!所有 $model_count 个模型已加载" + echo "✅ 已自动识别协议为: $DETECTED_API" fi break_end @@ -10744,7 +10876,7 @@ openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" - while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do case "$rec_type" in MSG) echo "$idx" @@ -10758,7 +10890,7 @@ openclaw_api_manage_list() { unchecked) latency_color="$gl_bai" ;; esac - printf '%b\n' "[$idx] ${name} | API: ${base_url} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" + printf '%b\n' "[$idx] ${name} | API: ${base_url} | 协议: ${api_type} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" ;; esac done < <(python3 - "$config_file" <<-'PY' @@ -10842,12 +10974,14 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): latency_raw = '不可用' latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' print( 'ROW\t' + '\t'.join([ str(idx), str(name), str(base_url), str(model_count), + str(api_label), str(latency_text), str(latency_level), ]) @@ -10885,6 +11019,38 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -10971,6 +11137,16 @@ if api not in SUPPORTED_APIS: print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') raise SystemExit(3) +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -11047,6 +11223,9 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True +if protocol_msg: + print(protocol_msg) + if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) @@ -11084,6 +11263,125 @@ PY2 break_end } +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ 未找到 openclaw.json') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') +PY +} + +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API协议修复" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要修复协议的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅ 协议已检测并更新(如有变更)" + start_gateway + ;; + 2) + echo "❌ 修复失败:provider 不存在或未配置" + ;; + 3) + echo "❌ 修复失败:provider 配置不完整" + ;; + *) + echo "❌ 修复失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end +} + delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" @@ -11245,6 +11543,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" + echo "4. 协议修复/重新探测" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11259,6 +11558,9 @@ PY 3) delete-openclaw-provider-interactive ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; 0) return 0 ;; diff --git a/cn/tests_openclaw_api_protocol_detect_smoke.sh b/cn/tests_openclaw_api_protocol_detect_smoke.sh new file mode 120000 index 000000000..51f6551e0 --- /dev/null +++ b/cn/tests_openclaw_api_protocol_detect_smoke.sh @@ -0,0 +1 @@ +../tests_openclaw_api_protocol_detect_smoke.sh \ No newline at end of file diff --git a/kejilion.sh b/kejilion.sh index 48fc5c37d..520410ce8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10139,6 +10139,39 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + + def send_stat(action): if not stats_enabled: return @@ -10301,6 +10334,39 @@ def delete_provider_and_refs(name): return True +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + + def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10341,6 +10407,16 @@ for name, provider in list(providers.items()): summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') continue + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -10513,6 +10589,52 @@ PY + # OpenClaw API 协议探测(优先 responses -> chat/completions -> completions) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + local code_chat="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses & /chat/completions not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + code_chat=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/chat/completions") + if [[ "$code_chat" != "404" && "$code_chat" != "405" && "$code_chat" != "000" ]]; then + DETECTED_API="openai-chat-completions" + DETECTED_REASON="POST /chat/completions -> HTTP $code_chat" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses, /chat/completions=$code_chat -> fallback /completions" + return 0 + } + # 核心函数:获取并添加所有模型 add-all-models-from-provider() { local provider_name="$1" @@ -10522,6 +10644,10 @@ PY echo "🔍 正在获取 $provider_name 的所有可用模型..." + # 自动识别 API 协议 + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # 获取模型列表 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10601,6 +10727,7 @@ EOF jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10609,7 +10736,7 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) @@ -10669,7 +10796,11 @@ EOF echo done - # 4. 获取模型列表 + # 4. 协议探测(无感) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. 获取模型列表 echo "🔍 正在获取可用模型列表..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10684,10 +10815,10 @@ EOF echo "--------------------------------" # 全部显示,带序号 i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10701,8 +10832,8 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 使用第一个模型: $default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 已选择模型: $default_model" else default_model="$input_model" @@ -10733,6 +10864,7 @@ EOF openclaw models set "$provider_name/$default_model" start_gateway echo "✅ 完成!所有 $model_count 个模型已加载" + echo "✅ 已自动识别协议为: $DETECTED_API" fi break_end @@ -10744,7 +10876,7 @@ openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" - while IFS=$'\t' read -r rec_type idx name base_url model_count latency_txt latency_level; do + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do case "$rec_type" in MSG) echo "$idx" @@ -10758,7 +10890,7 @@ openclaw_api_manage_list() { unchecked) latency_color="$gl_bai" ;; esac - printf '%b\n' "[$idx] ${name} | API: ${base_url} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" + printf '%b\n' "[$idx] ${name} | API: ${base_url} | 协议: ${api_type} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" ;; esac done < <(python3 - "$config_file" <<-'PY' @@ -10842,12 +10974,14 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): latency_raw = '不可用' latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' print( 'ROW\t' + '\t'.join([ str(idx), str(name), str(base_url), str(model_count), + str(api_label), str(latency_text), str(latency_level), ]) @@ -10885,6 +11019,38 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -10971,6 +11137,16 @@ if api not in SUPPORTED_APIS: print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') raise SystemExit(3) +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -11047,6 +11223,9 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True +if protocol_msg: + print(protocol_msg) + if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) @@ -11084,6 +11263,125 @@ PY2 break_end } +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') + if code2 is not None and code2 not in (404, 405): + return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None + if err or err2: + return 'openai-completions', 'fallback: probe failed', err or err2 + return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ 未找到 openclaw.json') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') +PY +} + +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API协议修复" + + if [ ! -f "$config_file" ]; then + echo "❌ 未找到配置文件: $config_file" + break_end + return 1 + fi + + read -erp "请输入要修复协议的 API 名称(provider): " provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名称不能为空" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅ 协议已检测并更新(如有变更)" + start_gateway + ;; + 2) + echo "❌ 修复失败:provider 不存在或未配置" + ;; + 3) + echo "❌ 修复失败:provider 配置不完整" + ;; + *) + echo "❌ 修复失败:请检查配置文件结构或日志输出" + ;; + esac + + break_end +} + delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API删除入口" @@ -11245,6 +11543,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" + echo "4. 协议修复/重新探测" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11259,6 +11558,9 @@ PY 3) delete-openclaw-provider-interactive ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; 0) return 0 ;; diff --git a/tests_openclaw_api_protocol_detect_smoke.sh b/tests_openclaw_api_protocol_detect_smoke.sh new file mode 100644 index 000000000..b1d5f866d --- /dev/null +++ b/tests_openclaw_api_protocol_detect_smoke.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-api-protocol-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +# 抽取 OpenClaw API 添加逻辑 +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +start_gateway() { return 0; } +install() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} + /openclaw_probe_api_endpoint\(\) \{/{p=1} + /openclaw_api_manage_list\(\) \{/{p=0} + p{print} +' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: curl +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +set -e +args="$*" +# write body to stdout when /models +if [[ "$args" == *"/models"* ]]; then + cat <<'JSON' +{"data": [{"id": "gpt-4o"}, {"id": "gpt-4o-mini"}]} +JSON + exit 0 +fi +# emulate POST /responses = 404, /chat/completions = 200 +if [[ "$args" == *"/responses"* ]]; then + printf "404" + exit 0 +fi +if [[ "$args" == *"/chat/completions"* ]]; then + printf "200" + exit 0 +fi +printf "000" +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +# stub: jq (passthrough for system jq) +# rely on system jq if available + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +# minimal openclaw.json +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "models": { + "mode": "merge", + "providers": {} + }, + "agents": { + "defaults": { + "models": {} + } + } +} +JSON + +source "$WORKDIR/harness.sh" + +add-all-models-from-provider "demo" "https://api.example.com/v1" "sk-test" + +python3 - <<'PY' +import json, os, sys +path = os.path.expanduser('~/.openclaw/openclaw.json') +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +prov = data.get('models', {}).get('providers', {}).get('demo', {}) +api = prov.get('api') +if api != 'openai-chat-completions': + raise SystemExit(f'api mismatch: {api}') +print('SMOKE_OK') +PY From e4d34102d4ef33fde38b5f58f567ffb9b8a701f1 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 00:24:23 +0800 Subject: [PATCH 0980/1285] revert: simplify memory config path handling --- cn/kejilion.sh | 41 -------------------------- cn/tests_openclaw_memory_menu_smoke.sh | 8 ++--- kejilion.sh | 41 -------------------------- tests_openclaw_memory_menu_smoke.sh | 8 ++--- 4 files changed, 4 insertions(+), 94 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 520410ce8..1b6237617 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12812,47 +12812,9 @@ EOF } openclaw_memory_config_file() { - local detected expanded - if command -v openclaw >/dev/null 2>&1; then - detected=$(openclaw config file 2>/dev/null | head -n 1 | tr -d '\r') - fi - if [ -n "$detected" ]; then - expanded=$(python3 - "$detected" <<'PY' -import os,sys -path = sys.argv[1] -if not path: - print('') -else: - print(os.path.expandvars(os.path.expanduser(path))) -PY -) - if [ -n "$expanded" ]; then - echo "$expanded" - return 0 - fi - fi echo "${HOME}/.openclaw/openclaw.json" } - openclaw_memory_config_display() { - local path="$1" - local display head tail - if [ -z "$path" ]; then - echo "未知" - return - fi - display="$path" - if [ -n "$HOME" ]; then - display="${display/#$HOME/~}" - fi - if [ ${#display} -gt 48 ]; then - head="${display:0:20}" - tail="${display: -20}" - display="${head}...${tail}" - fi - echo "$display" - } - openclaw_memory_render_status() { local status_output status_lines config_file config_display status_output=$(openclaw memory status 2>/dev/null) @@ -12866,9 +12828,6 @@ PY echo "$status_lines" fi fi - config_file=$(openclaw_memory_config_file) - config_display=$(openclaw_memory_config_display "$config_file") - echo "配置文件: $config_display" } openclaw_memory_get_backend() { diff --git a/cn/tests_openclaw_memory_menu_smoke.sh b/cn/tests_openclaw_memory_menu_smoke.sh index 23230b81d..0fede93db 100644 --- a/cn/tests_openclaw_memory_menu_smoke.sh +++ b/cn/tests_openclaw_memory_menu_smoke.sh @@ -31,10 +31,6 @@ Indexed: 5/5 files TXT exit 0 fi -if [[ "$cmd" == "config file" ]]; then - echo "~/.openclaw/custom-openclaw.json" - exit 0 -fi if [[ "$cmd" == "memory index"* ]]; then echo "index ok" exit 0 @@ -80,7 +76,7 @@ export PATH="$WORKDIR/bin:$PATH" export TERM=xterm # minimal openclaw.json -cat > "$HOME/.openclaw/custom-openclaw.json" <<'JSON' +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' { "memory": { "backend": "qmd", @@ -134,7 +130,7 @@ run_menu "4\n1\n\nN\n0\n0\n" "scheme" python3 - <<'PY' import json,os,sys -path = os.path.expanduser('~/.openclaw/custom-openclaw.json') +path = os.path.expanduser('~/.openclaw/openclaw.json') with open(path,'r',encoding='utf-8') as f: data = json.load(f) flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) diff --git a/kejilion.sh b/kejilion.sh index 520410ce8..1b6237617 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12812,47 +12812,9 @@ EOF } openclaw_memory_config_file() { - local detected expanded - if command -v openclaw >/dev/null 2>&1; then - detected=$(openclaw config file 2>/dev/null | head -n 1 | tr -d '\r') - fi - if [ -n "$detected" ]; then - expanded=$(python3 - "$detected" <<'PY' -import os,sys -path = sys.argv[1] -if not path: - print('') -else: - print(os.path.expandvars(os.path.expanduser(path))) -PY -) - if [ -n "$expanded" ]; then - echo "$expanded" - return 0 - fi - fi echo "${HOME}/.openclaw/openclaw.json" } - openclaw_memory_config_display() { - local path="$1" - local display head tail - if [ -z "$path" ]; then - echo "未知" - return - fi - display="$path" - if [ -n "$HOME" ]; then - display="${display/#$HOME/~}" - fi - if [ ${#display} -gt 48 ]; then - head="${display:0:20}" - tail="${display: -20}" - display="${head}...${tail}" - fi - echo "$display" - } - openclaw_memory_render_status() { local status_output status_lines config_file config_display status_output=$(openclaw memory status 2>/dev/null) @@ -12866,9 +12828,6 @@ PY echo "$status_lines" fi fi - config_file=$(openclaw_memory_config_file) - config_display=$(openclaw_memory_config_display "$config_file") - echo "配置文件: $config_display" } openclaw_memory_get_backend() { diff --git a/tests_openclaw_memory_menu_smoke.sh b/tests_openclaw_memory_menu_smoke.sh index bdba703da..3cdbc07bc 100755 --- a/tests_openclaw_memory_menu_smoke.sh +++ b/tests_openclaw_memory_menu_smoke.sh @@ -31,10 +31,6 @@ Indexed: 5/5 files TXT exit 0 fi -if [[ "$cmd" == "config file" ]]; then - echo "~/.openclaw/custom-openclaw.json" - exit 0 -fi if [[ "$cmd" == "memory index"* ]]; then echo "index ok" exit 0 @@ -80,7 +76,7 @@ export PATH="$WORKDIR/bin:$PATH" export TERM=xterm # minimal openclaw.json -cat > "$HOME/.openclaw/custom-openclaw.json" <<'JSON' +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' { "memory": { "backend": "qmd", @@ -134,7 +130,7 @@ run_menu "4\n1\n\nN\n0\n0\n" "scheme" python3 - <<'PY' import json,os,sys -path = os.path.expanduser('~/.openclaw/custom-openclaw.json') +path = os.path.expanduser('~/.openclaw/openclaw.json') with open(path,'r',encoding='utf-8') as f: data = json.load(f) flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) From 9e504490876999ce408585a804391f3452ba4e05 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 01:04:21 +0800 Subject: [PATCH 0981/1285] feat: print added/removed model ids on api sync --- cn/kejilion.sh | 18 ++++ kejilion.sh | 18 ++++ tests_openclaw_api_sync_diff_smoke.sh | 133 ++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100755 tests_openclaw_api_sync_diff_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1b6237617..0f7925e50 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10463,6 +10463,15 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -11177,6 +11186,15 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: diff --git a/kejilion.sh b/kejilion.sh index 1b6237617..0f7925e50 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10463,6 +10463,15 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -11177,6 +11186,15 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: diff --git a/tests_openclaw_api_sync_diff_smoke.sh b/tests_openclaw_api_sync_diff_smoke.sh new file mode 100755 index 000000000..eed6cd4be --- /dev/null +++ b/tests_openclaw_api_sync_diff_smoke.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$REPO_DIR/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-api-sync-diff-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +start_gateway() { return 0; } +install() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} + /sync_openclaw_api_models\(\) \{/{p=1} + /install_moltbot\(\) \{/{p=0} + p{print} +' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + + +cat > "$WORKDIR/bin/python3" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$1" != "-" ]]; then + exec /usr/bin/python3 "$@" +fi +SCRIPT=$(cat) +export SCRIPT +/usr/bin/python3 - "${@:2}" <<"PY_STDIN" +import io +import json +import os +import urllib.request +import urllib.error + +class _Resp(io.BytesIO): + def __init__(self, data, code=200): + super().__init__(data) + self._code = code + def getcode(self): + return self._code + def __enter__(self): + return self + def __exit__(self, exc_type, exc, tb): + return False + +_real = urllib.request.urlopen + +def urlopen(req, timeout=0): + url = getattr(req, "full_url", "") or getattr(req, "get_full_url", lambda: "")() + if url.endswith("/models"): + data = json.dumps({"data": [{"id": "alpha"}, {"id": "beta"}]}).encode("utf-8") + return _Resp(data, 200) + if url.endswith("/responses") or url.endswith("/chat/completions"): + raise urllib.error.HTTPError(url, 404, "Not Found", {}, None) + return _real(req, timeout=timeout) + +urllib.request.urlopen = urlopen +script = os.environ.get("SCRIPT", "") +exec(compile(script, "", "exec")) +PY_STDIN +exit $? +EOF_INNER +chmod +x "$WORKDIR/bin/python3" + +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +# fake curl for /models, /responses, /chat/completions (for shell probes) +set -e +args="$*" +if [[ "$args" == *"/responses"* ]]; then + printf "404" + exit 0 +fi +if [[ "$args" == *"/chat/completions"* ]]; then + printf "404" + exit 0 +fi +printf "000" +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm +export ENABLE_STATS=false +export sh_v=testing + +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "models": { + "mode": "merge", + "providers": { + "demo": { + "api": "openai-completions", + "baseUrl": "https://api.example.com/v1", + "apiKey": "sk-test", + "models": [ + {"id": "alpha", "name": "demo / alpha"}, + {"id": "gamma", "name": "demo / gamma"} + ] + } + } + }, + "agents": { + "defaults": { + "models": { + "demo/alpha": {}, + "demo/gamma": {} + }, + "model": "demo/alpha" + } + } +} +JSON + +source "$WORKDIR/harness.sh" + +output=$(sync_openclaw_api_models 2>&1 || true) + +printf '%s\n' "$output" | grep -q "➕ 新增模型(1):" +printf '%s\n' "$output" | grep -q "^ + beta$" +printf '%s\n' "$output" | grep -q "➖ 删除模型(1):" +printf '%s\n' "$output" | grep -q "^ - gamma$" + +printf '%s\n' "SMOKE_OK" From da52af9cbd820dc867328d4420fc44a1ebdb83ec Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 06:51:12 +0800 Subject: [PATCH 0982/1285] v4.4.6 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kejilion_sh_log.txt | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0f7925e50..f3a91279d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.5" +sh_v="4.4.6" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 0f7925e50..f3a91279d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.5" +sh_v="4.4.6" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 47b8d3765..043c631bb 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1484,3 +1484,8 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,添加了备份还原功能,包含记忆和完整项目。 应用市场中OpenClaw管理,新增独立且中文化的记忆管理控制台,支持方案自动探测、索引状态查看与重复收录一键修复。 +------------------------ +2026-03-12 v4.4.6 +应用市场中OpenClaw管理,新增记忆管理控制台,支持索引状态、索引更新、文件查看、方案切换与重复索引修复。 +应用市场中OpenClaw管理,API新增自动探测并优先使用/v1/responses协议,避免legacy /v1/chat/completions报错。 +应用市场中OpenClaw管理,API模型同步一致性输出增强,逐行显示新增/删除模型名称。 From 7ceb04358e7bfdc1ed311746ba9d824d8a73adab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 12 Mar 2026 09:51:34 +0800 Subject: [PATCH 0983/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 043c631bb..92773e7fa 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1483,9 +1483,9 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,API管理菜单支持查看列表、按提供商同步模型、删除API,且对/models探测失败增加3次重试与人工确认删除机制。 应用市场中OpenClaw管理,添加了备份还原功能,包含记忆和完整项目。 应用市场中OpenClaw管理,新增独立且中文化的记忆管理控制台,支持方案自动探测、索引状态查看与重复收录一键修复。 - ------------------------ 2026-03-12 v4.4.6 应用市场中OpenClaw管理,新增记忆管理控制台,支持索引状态、索引更新、文件查看、方案切换与重复索引修复。 应用市场中OpenClaw管理,API新增自动探测并优先使用/v1/responses协议,避免legacy /v1/chat/completions报错。 应用市场中OpenClaw管理,API模型同步一致性输出增强,逐行显示新增/删除模型名称。 + From 303871ed662d6cc2b240153f66959c0a30f2c108 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 10:15:22 +0800 Subject: [PATCH 0984/1285] chore: reorganize openclaw test scripts --- ...ests_openclaw_api_protocol_detect_smoke.sh | 1 + .../tests_openclaw_memory_menu_smoke.sh | 1 + .../tests_openclaw_plugin_skill_menu_smoke.sh | 1 + ...ests_openclaw_api_protocol_detect_smoke.sh | 1 - cn/tests_openclaw_memory_menu_smoke.sh | 140 ------------------ tests/openclaw/README.md | 36 +++++ .../tests_openclaw_api_color_align_min.sh | 0 ...ests_openclaw_api_protocol_detect_smoke.sh | 4 +- .../tests_openclaw_api_sync_diff_smoke.sh | 4 +- .../tests_openclaw_memory_menu_smoke.sh | 19 ++- .../tests_openclaw_plugin_skill_menu_smoke.sh | 4 +- tests_openclaw_plugin_skill_menu_smoke.sh | 132 ----------------- 12 files changed, 61 insertions(+), 282 deletions(-) create mode 120000 cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh create mode 120000 cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh create mode 120000 cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh delete mode 120000 cn/tests_openclaw_api_protocol_detect_smoke.sh delete mode 100644 cn/tests_openclaw_memory_menu_smoke.sh create mode 100644 tests/openclaw/README.md rename tests_openclaw_api_color_align_min.sh => tests/openclaw/tests_openclaw_api_color_align_min.sh (100%) rename tests_openclaw_api_protocol_detect_smoke.sh => tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh (96%) rename tests_openclaw_api_sync_diff_smoke.sh => tests/openclaw/tests_openclaw_api_sync_diff_smoke.sh (97%) rename tests_openclaw_memory_menu_smoke.sh => tests/openclaw/tests_openclaw_memory_menu_smoke.sh (84%) rename {cn => tests/openclaw}/tests_openclaw_plugin_skill_menu_smoke.sh (97%) mode change 100644 => 100755 delete mode 100755 tests_openclaw_plugin_skill_menu_smoke.sh diff --git a/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh b/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh new file mode 120000 index 000000000..8fc9ddc81 --- /dev/null +++ b/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh @@ -0,0 +1 @@ +../../../tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh \ No newline at end of file diff --git a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh new file mode 120000 index 000000000..e10523e3a --- /dev/null +++ b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -0,0 +1 @@ +../../../tests/openclaw/tests_openclaw_memory_menu_smoke.sh \ No newline at end of file diff --git a/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh new file mode 120000 index 000000000..c9f8de09b --- /dev/null +++ b/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh @@ -0,0 +1 @@ +../../../tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh \ No newline at end of file diff --git a/cn/tests_openclaw_api_protocol_detect_smoke.sh b/cn/tests_openclaw_api_protocol_detect_smoke.sh deleted file mode 120000 index 51f6551e0..000000000 --- a/cn/tests_openclaw_api_protocol_detect_smoke.sh +++ /dev/null @@ -1 +0,0 @@ -../tests_openclaw_api_protocol_detect_smoke.sh \ No newline at end of file diff --git a/cn/tests_openclaw_memory_menu_smoke.sh b/cn/tests_openclaw_memory_menu_smoke.sh deleted file mode 100644 index 0fede93db..000000000 --- a/cn/tests_openclaw_memory_menu_smoke.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_DIR="$(cd "$(dirname "$0")" && pwd)" -SCRIPT="$REPO_DIR/kejilion.sh" -WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-menu-test-$$" -mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" -KEEP_WORKDIR=${KEEP_WORKDIR:-false} -trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT - -# 抽取 OpenClaw 记忆菜单实现 -cat > "$WORKDIR/harness.sh" <<'EOF_INNER' -#!/usr/bin/env bash -set -euo pipefail -break_end() { return 0; } -send_stats() { return 0; } -EOF_INNER - -awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" -chmod +x "$WORKDIR/harness.sh" - -# stub: openclaw -cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' -#!/usr/bin/env bash -cmd="$*" -if [[ "$cmd" == "memory status" ]]; then - cat < "$WORKDIR/bin/qmd" <<'EOF_INNER' -#!/usr/bin/env bash -exit 0 -EOF_INNER -chmod +x "$WORKDIR/bin/qmd" - -# stub: curl (用于网络探测) -cat > "$WORKDIR/bin/curl" <<'EOF_INNER' -#!/usr/bin/env bash -if [[ "$*" == *"huggingface.co"* ]]; then - exit 1 -fi -if [[ "$*" == *"hf-mirror.com"* ]]; then - exit 0 -fi -exit 0 -EOF_INNER -chmod +x "$WORKDIR/bin/curl" - -export HOME="$WORKDIR/home" -export PATH="$WORKDIR/bin:$PATH" -export TERM=xterm - -# minimal openclaw.json -cat > "$HOME/.openclaw/openclaw.json" <<'JSON' -{ - "memory": { - "backend": "qmd", - "qmd": {"command": "qmd", "includeDefaultMemory": true} - }, - "agents": { - "defaults": { - "memorySearch": { - "provider": "local", - "local": { - "modelPath": "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" - } - } - } - } -} -JSON - -# mock memory files -cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' -# MEMORY -line1 -line2 -line3 -TXT -cat > "$HOME/.openclaw/workspace/memory/2026-03-11.md" <<'TXT' -# 2026-03-11 -foo -bar -TXT - -source "$WORKDIR/harness.sh" - -run_menu() { - local input="$1" - local title="$2" - echo "[TEST] $title" - printf "%b" "$input" | openclaw_memory_menu >/tmp/memory_menu.out -} - -# 1) 状态 -run_menu "0\n" "status" -# 2) 更新索引(增量) -run_menu "1\nyes\n\n\n0\n" "index" -# 3) 查看记忆文件(列表+查看) -run_menu "2\n1\n\n\n\n\n0\n0\n" "files" -# 4) 索引修复(执行修复 + 不立即重建) -run_menu "3\ny\n\nN\n0\n" "fix" -# 5) 记忆方案(自动推荐并取消) -run_menu "4\n1\n\nN\n0\n0\n" "scheme" - -python3 - <<'PY' -import json,os,sys -path = os.path.expanduser('~/.openclaw/openclaw.json') -with open(path,'r',encoding='utf-8') as f: - data = json.load(f) -flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) -if flag is not False: - raise SystemExit('includeDefaultMemory not updated') -print('SMOKE_OK') -PY diff --git a/tests/openclaw/README.md b/tests/openclaw/README.md new file mode 100644 index 000000000..d5f22e511 --- /dev/null +++ b/tests/openclaw/README.md @@ -0,0 +1,36 @@ +# OpenClaw tests + +这里的脚本用于对 `kejilion.sh` 中的 OpenClaw 相关功能做最小回归与冒烟测试,主要覆盖: + +- API 模型同步/协议探测 +- 记忆菜单 +- 插件/技能菜单 +- API 列表颜色/对齐展示(最小验证) + +## 运行方式 + +在仓库根目录执行(推荐): + +```bash +bash tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh +bash tests/openclaw/tests_openclaw_api_sync_diff_smoke.sh +bash tests/openclaw/tests_openclaw_memory_menu_smoke.sh +bash tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh +bash tests/openclaw/tests_openclaw_api_color_align_min.sh +``` + +也可在任意工作目录执行: + +```bash +/path/to/repo/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +``` + +## 安全说明 + +- 脚本会创建临时工作目录与临时 `HOME`(位于 `/tmp`),并在结束后自动清理(除非设置 `KEEP_WORKDIR=true`)。 +- 运行过程使用 stub/模拟命令,不会改动真实 OpenClaw 配置或系统状态。 +- 如需保留临时目录用于排查,请执行: + +```bash +KEEP_WORKDIR=true bash tests/openclaw/tests_openclaw_memory_menu_smoke.sh +``` diff --git a/tests_openclaw_api_color_align_min.sh b/tests/openclaw/tests_openclaw_api_color_align_min.sh similarity index 100% rename from tests_openclaw_api_color_align_min.sh rename to tests/openclaw/tests_openclaw_api_color_align_min.sh diff --git a/tests_openclaw_api_protocol_detect_smoke.sh b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh similarity index 96% rename from tests_openclaw_api_protocol_detect_smoke.sh rename to tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh index b1d5f866d..0e8b14cae 100644 --- a/tests_openclaw_api_protocol_detect_smoke.sh +++ b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -REPO_DIR="$(cd "$(dirname "$0")" && pwd)" -SCRIPT="$REPO_DIR/kejilion.sh" +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" WORKDIR="${TMPDIR:-/tmp}/openclaw-api-protocol-test-$$" mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" KEEP_WORKDIR=${KEEP_WORKDIR:-false} diff --git a/tests_openclaw_api_sync_diff_smoke.sh b/tests/openclaw/tests_openclaw_api_sync_diff_smoke.sh similarity index 97% rename from tests_openclaw_api_sync_diff_smoke.sh rename to tests/openclaw/tests_openclaw_api_sync_diff_smoke.sh index eed6cd4be..327f879bc 100755 --- a/tests_openclaw_api_sync_diff_smoke.sh +++ b/tests/openclaw/tests_openclaw_api_sync_diff_smoke.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -REPO_DIR="$(cd "$(dirname "$0")" && pwd)" -SCRIPT="$REPO_DIR/kejilion.sh" +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" WORKDIR="${TMPDIR:-/tmp}/openclaw-api-sync-diff-test-$$" mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" KEEP_WORKDIR=${KEEP_WORKDIR:-false} diff --git a/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh similarity index 84% rename from tests_openclaw_memory_menu_smoke.sh rename to tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 3cdbc07bc..3c19a6fc9 100755 --- a/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -REPO_DIR="$(cd "$(dirname "$0")" && pwd)" -SCRIPT="$REPO_DIR/kejilion.sh" +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-menu-test-$$" mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" KEEP_WORKDIR=${KEEP_WORKDIR:-false} @@ -14,20 +14,33 @@ cat > "$WORKDIR/harness.sh" <<'EOF_INNER' set -euo pipefail break_end() { return 0; } send_stats() { return 0; } +openclaw_memory_prepare_workspace() { return 0; } EOF_INNER -awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_memory_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +awk 'BEGIN{p=0} /openclaw_memory_menu\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" chmod +x "$WORKDIR/harness.sh" # stub: openclaw cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' #!/usr/bin/env bash cmd="$*" +if [[ "$cmd" == "config get"* ]]; then + exit 0 +fi +if [[ "$cmd" == "config set"* ]]; then + exit 0 +fi +if [[ "$cmd" == "config file" ]]; then + echo "$HOME/.openclaw/openclaw.json" + exit 0 +fi if [[ "$cmd" == "memory status" ]]; then cat < "$WORKDIR/harness.sh" <<'EOF_INNER' -#!/usr/bin/env bash -set -euo pipefail -break_end() { return 0; } -send_stats() { return 0; } -start_gateway() { openclaw gateway stop; openclaw gateway start; } -EOF_INNER - -# 抽取插件/技能管理实现 -awk 'BEGIN{p=0} /resolve_openclaw_plugin_id\(\) \{/{p=1} /openclaw_json_get_bool\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" -chmod +x "$WORKDIR/harness.sh" - -# stub: openclaw -cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' -#!/usr/bin/env bash -cmd="$*" -if [[ "$cmd" == "plugins list" ]]; then - cat <> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$cmd" == "plugins install"* ]]; then - echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$cmd" == "plugins disable"* ]]; then - echo "disable $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$cmd" == "plugins uninstall"* ]]; then - # 模拟预装卸载失败 - if [[ "$cmd" == *"feishu"* ]]; then - exit 1 - fi - echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$cmd" == "skills list" ]]; then - echo "skill1" - exit 0 -fi -if [[ "$cmd" == "gateway stop" ]]; then - echo "gateway stop" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$cmd" == "gateway start" ]]; then - echo "gateway start" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -echo "mock openclaw $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" -EOF_INNER -chmod +x "$WORKDIR/bin/openclaw" - -# stub: npx -cat > "$WORKDIR/bin/npx" <<'EOF_INNER' -#!/usr/bin/env bash -if [[ "$*" == *"clawhub uninstall"* ]]; then - echo "uninstall $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -if [[ "$*" == *"clawhub install"* ]]; then - echo "install $*" >> "${TEST_LOG:-/tmp/openclaw-plugin.log}" - exit 0 -fi -exit 0 -EOF_INNER -chmod +x "$WORKDIR/bin/npx" - -export HOME="$WORKDIR/home" -export PATH="$WORKDIR/bin:$PATH" -export TERM=xterm -export TEST_LOG="$WORKDIR/test.log" - -cat > "$HOME/.openclaw/openclaw.json" <<'JSON' -{"plugins":{"allow":["telegram","feishu"]}} -JSON - -# 模拟用户技能目录 -mkdir -p "$HOME/.openclaw/workspace/skills/skillA" - -source "$WORKDIR/harness.sh" - -# 插件安装:多输入,确保只重启一次 -printf "1\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_install.out" - -# 插件删除:多输入,确保删除流程与 allowlist 移除 -printf "2\nfeishu telegram\n0\n" | install_plugin > "$WORKDIR/plugin_delete.out" - -# 技能删除:二次确认 + 多输入,删除目录 -printf "2\nskillA skillB\ny\n0\n" | install_skill > "$WORKDIR/skill_delete.out" - -# 断言:start_gateway 只调用一次/每次菜单 -start_count=$(grep -c "gateway start" "$TEST_LOG" || true) -if [ "$start_count" -ne 3 ]; then - echo "Expected 3 gateway starts (plugin install/delete + skill delete), got $start_count" - exit 1 -fi - -# 断言:用户技能目录已删除 -if [ -d "$HOME/.openclaw/workspace/skills/skillA" ]; then - echo "Skill directory was not removed" - exit 1 -fi - -# 断言:plugins.allow 移除 -if grep -q '"feishu"' "$HOME/.openclaw/openclaw.json"; then - echo "feishu still in plugins.allow" - exit 1 -fi - -# 断言:输出汇总 -grep -q "操作汇总" "$WORKDIR/plugin_install.out" -grep -q "操作汇总" "$WORKDIR/plugin_delete.out" -grep -q "操作汇总" "$WORKDIR/skill_delete.out" - -echo "SMOKE_OK" From 641a763e043172f691d2be2c00831dfa3944529f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:41:16 +0800 Subject: [PATCH 0985/1285] Delete cn/tests/openclaw directory --- cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh | 1 - cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh | 1 - cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh | 1 - 3 files changed, 3 deletions(-) delete mode 120000 cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh delete mode 120000 cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh delete mode 120000 cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh diff --git a/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh b/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh deleted file mode 120000 index 8fc9ddc81..000000000 --- a/cn/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh +++ /dev/null @@ -1 +0,0 @@ -../../../tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh \ No newline at end of file diff --git a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh deleted file mode 120000 index e10523e3a..000000000 --- a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ /dev/null @@ -1 +0,0 @@ -../../../tests/openclaw/tests_openclaw_memory_menu_smoke.sh \ No newline at end of file diff --git a/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh deleted file mode 120000 index c9f8de09b..000000000 --- a/cn/tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh +++ /dev/null @@ -1 +0,0 @@ -../../../tests/openclaw/tests_openclaw_plugin_skill_menu_smoke.sh \ No newline at end of file From 830911d531d1b229a2625095c133fce33f5ab883 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 10:30:40 +0800 Subject: [PATCH 0986/1285] fix: make memory menu actions effective --- cn/kejilion.sh | 177 +++++++++--------- kejilion.sh | 177 +++++++++--------- .../tests_openclaw_memory_menu_smoke.sh | 56 ++++-- 3 files changed, 214 insertions(+), 196 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3a91279d..739a3a392 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12833,6 +12833,44 @@ EOF echo "${HOME}/.openclaw/openclaw.json" } + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ 未能获取 Workspace 路径,跳过目录修复。" + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 记忆目录不存在,已自动创建: $memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + openclaw_memory_render_status() { local status_output status_lines config_file config_display status_output=$(openclaw memory status 2>/dev/null) @@ -12849,38 +12887,11 @@ EOF } openclaw_memory_get_backend() { - local config_file - config_file=$(openclaw_memory_config_file) - [ -s "$config_file" ] || { echo ""; return 0; } - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -try: - with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) - backend = data.get('memory', {}).get('backend', '') - print(backend if isinstance(backend, str) else '') -except Exception: - print('') -PY + openclaw_memory_config_get "memory.backend" } openclaw_memory_get_local_model_path() { - local config_file - config_file=$(openclaw_memory_config_file) - [ -s "$config_file" ] || { echo ""; return 0; } - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -try: - with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) - obj = data.get('agents', {}).get('defaults', {}).get('memorySearch', {}).get('local', {}) - model_path = obj.get('modelPath', '') if isinstance(obj, dict) else '' - print(model_path if isinstance(model_path, str) else '') -except Exception: - print('') -PY + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" } openclaw_memory_local_model_status() { @@ -12905,18 +12916,12 @@ PY echo "true" return fi - if command -v openclaw >/dev/null 2>&1 && openclaw memory status >/dev/null 2>&1; then + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then echo "true" return fi - local config_file - config_file=$(openclaw_memory_config_file) - if [ -s "$config_file" ] && command -v jq >/dev/null 2>&1; then - if jq -e '.memory.backend == "qmd"' "$config_file" >/dev/null 2>&1; then - echo "true" - return - fi - fi echo "false" } @@ -12990,39 +12995,27 @@ PY openclaw_memory_apply_scheme() { local scheme="$1" - local config_file - config_file=$(openclaw_memory_config_file) - if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" - return 1 - fi - python3 - "$config_file" "$scheme" <<'PY' -import json,sys -path = sys.argv[1] -scheme = sys.argv[2] -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -mem = data.setdefault('memory', {}) -if scheme == 'qmd': - mem['backend'] = 'qmd' - qmd = mem.setdefault('qmd', {}) - qmd.setdefault('command', 'qmd') -elif scheme == 'local': - mem['backend'] = 'local' - agents = data.setdefault('agents', {}) - defaults = agents.setdefault('defaults', {}) - memory_search = defaults.setdefault('memorySearch', {}) - memory_search['provider'] = 'local' -else: - raise SystemExit(2) -with open(path, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" - return 1 - fi + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "local" + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ 未知方案: $scheme" + return 1 + esac echo "✅ 已更新记忆方案配置" return 0 } @@ -13042,12 +13035,11 @@ PY } openclaw_memory_fix_index() { - local config_file - config_file=$(openclaw_memory_config_file) - if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" - break_end - return 1 + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" + echo " 可切换 Local,或安装 bun + qmd 后再试。" fi echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix @@ -13056,27 +13048,29 @@ PY break_end return 0 fi - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -mem = data.setdefault('memory', {}) -qmd = mem.setdefault('qmd', {}) -qmd['includeDefaultMemory'] = False -with open(path, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - f.write('\n') -PY + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false if [ $? -ne 0 ]; then echo "❌ 写入配置失败" break_end return 1 fi echo "✅ 已设置 includeDefaultMemory=false" - echo "建议立即执行:openclaw memory index --force" - read -e -p "是否立即执行 openclaw memory index --force?(Y/n): " rebuild_choice + echo "推荐执行:清理并重建索引" + read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + local store_file ts backup_file + store_file=$(openclaw_memory_status_value "Store") + if [ -n "$store_file" ] && [ -f "$store_file" ]; then + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 已备份索引: $backup_file" + else + echo "⚠️ 索引备份失败,继续重建。" + fi + else + echo "⚠️ 未找到索引库文件,跳过备份。" + fi openclaw memory index --force echo "" openclaw_memory_render_status @@ -13290,6 +13284,7 @@ PY break_end continue fi + openclaw_memory_prepare_workspace read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 if [ "$confirm_step2" = "force" ]; then openclaw memory index --force diff --git a/kejilion.sh b/kejilion.sh index f3a91279d..739a3a392 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12833,6 +12833,44 @@ EOF echo "${HOME}/.openclaw/openclaw.json" } + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ 未能获取 Workspace 路径,跳过目录修复。" + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 记忆目录不存在,已自动创建: $memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + openclaw_memory_render_status() { local status_output status_lines config_file config_display status_output=$(openclaw memory status 2>/dev/null) @@ -12849,38 +12887,11 @@ EOF } openclaw_memory_get_backend() { - local config_file - config_file=$(openclaw_memory_config_file) - [ -s "$config_file" ] || { echo ""; return 0; } - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -try: - with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) - backend = data.get('memory', {}).get('backend', '') - print(backend if isinstance(backend, str) else '') -except Exception: - print('') -PY + openclaw_memory_config_get "memory.backend" } openclaw_memory_get_local_model_path() { - local config_file - config_file=$(openclaw_memory_config_file) - [ -s "$config_file" ] || { echo ""; return 0; } - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -try: - with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) - obj = data.get('agents', {}).get('defaults', {}).get('memorySearch', {}).get('local', {}) - model_path = obj.get('modelPath', '') if isinstance(obj, dict) else '' - print(model_path if isinstance(model_path, str) else '') -except Exception: - print('') -PY + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" } openclaw_memory_local_model_status() { @@ -12905,18 +12916,12 @@ PY echo "true" return fi - if command -v openclaw >/dev/null 2>&1 && openclaw memory status >/dev/null 2>&1; then + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then echo "true" return fi - local config_file - config_file=$(openclaw_memory_config_file) - if [ -s "$config_file" ] && command -v jq >/dev/null 2>&1; then - if jq -e '.memory.backend == "qmd"' "$config_file" >/dev/null 2>&1; then - echo "true" - return - fi - fi echo "false" } @@ -12990,39 +12995,27 @@ PY openclaw_memory_apply_scheme() { local scheme="$1" - local config_file - config_file=$(openclaw_memory_config_file) - if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" - return 1 - fi - python3 - "$config_file" "$scheme" <<'PY' -import json,sys -path = sys.argv[1] -scheme = sys.argv[2] -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -mem = data.setdefault('memory', {}) -if scheme == 'qmd': - mem['backend'] = 'qmd' - qmd = mem.setdefault('qmd', {}) - qmd.setdefault('command', 'qmd') -elif scheme == 'local': - mem['backend'] = 'local' - agents = data.setdefault('agents', {}) - defaults = agents.setdefault('defaults', {}) - memory_search = defaults.setdefault('memorySearch', {}) - memory_search['provider'] = 'local' -else: - raise SystemExit(2) -with open(path, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" - return 1 - fi + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "local" + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ 未知方案: $scheme" + return 1 + esac echo "✅ 已更新记忆方案配置" return 0 } @@ -13042,12 +13035,11 @@ PY } openclaw_memory_fix_index() { - local config_file - config_file=$(openclaw_memory_config_file) - if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" - break_end - return 1 + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" + echo " 可切换 Local,或安装 bun + qmd 后再试。" fi echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix @@ -13056,27 +13048,29 @@ PY break_end return 0 fi - python3 - "$config_file" <<'PY' -import json,sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -mem = data.setdefault('memory', {}) -qmd = mem.setdefault('qmd', {}) -qmd['includeDefaultMemory'] = False -with open(path, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - f.write('\n') -PY + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false if [ $? -ne 0 ]; then echo "❌ 写入配置失败" break_end return 1 fi echo "✅ 已设置 includeDefaultMemory=false" - echo "建议立即执行:openclaw memory index --force" - read -e -p "是否立即执行 openclaw memory index --force?(Y/n): " rebuild_choice + echo "推荐执行:清理并重建索引" + read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + local store_file ts backup_file + store_file=$(openclaw_memory_status_value "Store") + if [ -n "$store_file" ] && [ -f "$store_file" ]; then + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 已备份索引: $backup_file" + else + echo "⚠️ 索引备份失败,继续重建。" + fi + else + echo "⚠️ 未找到索引库文件,跳过备份。" + fi openclaw memory index --force echo "" openclaw_memory_render_status @@ -13290,6 +13284,7 @@ PY break_end continue fi + openclaw_memory_prepare_workspace read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 if [ "$confirm_step2" = "force" ]; then openclaw memory index --force diff --git a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 3c19a6fc9..1fb4d6cf3 100755 --- a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -14,7 +14,6 @@ cat > "$WORKDIR/harness.sh" <<'EOF_INNER' set -euo pipefail break_end() { return 0; } send_stats() { return 0; } -openclaw_memory_prepare_workspace() { return 0; } EOF_INNER awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_memory_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" @@ -26,21 +25,41 @@ cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' #!/usr/bin/env bash cmd="$*" if [[ "$cmd" == "config get"* ]]; then + key="$3" + case "$key" in + memory.backend) echo "qmd" ;; + memory.qmd.includeDefaultMemory) echo "true" ;; + memory.qmd.command) echo "qmd" ;; + agents.defaults.memorySearch.local.modelPath) echo "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" ;; + agents.defaults.memorySearch.provider) echo "local" ;; + *) echo "" ;; + esac exit 0 fi if [[ "$cmd" == "config set"* ]]; then - exit 0 -fi -if [[ "$cmd" == "config file" ]]; then - echo "$HOME/.openclaw/openclaw.json" + key="$3" + val="$4" + if [[ "$key" == "memory.qmd.includeDefaultMemory" ]]; then + echo "$val" > "${HOME}/.openclaw/includeDefaultMemory" + fi + if [[ "$key" == "memory.backend" ]]; then + echo "$val" > "${HOME}/.openclaw/backend" + fi + if [[ "$key" == "memory.qmd.command" ]]; then + echo "$val" > "${HOME}/.openclaw/qmd_command" + fi + if [[ "$key" == "agents.defaults.memorySearch.provider" ]]; then + echo "$val" > "${HOME}/.openclaw/provider" + fi exit 0 fi if [[ "$cmd" == "memory status" ]]; then cat < "$HOME/.openclaw/openclaw.json" <<'JSON' } JSON +# mock index sqlite +mkdir -p "$HOME/.openclaw/workspace/memory" +touch "$HOME/.openclaw/workspace/memory/index.sqlite" + # mock memory files cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' # MEMORY @@ -137,17 +160,22 @@ run_menu "1\nyes\n\n\n0\n" "index" # 3) 查看记忆文件(列表+查看) run_menu "2\n1\n\n\n\n\n0\n0\n" "files" # 4) 索引修复(执行修复 + 不立即重建) -run_menu "3\ny\n\nN\n0\n" "fix" +run_menu "3\ny\n\n\n0\n" "fix" # 5) 记忆方案(自动推荐并取消) run_menu "4\n1\n\nN\n0\n0\n" "scheme" python3 - <<'PY' import json,os,sys -path = os.path.expanduser('~/.openclaw/openclaw.json') -with open(path,'r',encoding='utf-8') as f: - data = json.load(f) -flag = data.get('memory', {}).get('qmd', {}).get('includeDefaultMemory', True) -if flag is not False: +flag_path = os.path.expanduser('~/.openclaw/includeDefaultMemory') +if not os.path.exists(flag_path): + raise SystemExit('includeDefaultMemory not updated') +flag = open(flag_path, 'r', encoding='utf-8').read().strip() +if flag != 'false': raise SystemExit('includeDefaultMemory not updated') +# ensure backup created +import glob +baks = glob.glob(os.path.expanduser('~/.openclaw/workspace/memory/index.sqlite.bak.*')) +if not baks: + raise SystemExit('index sqlite backup not created') print('SMOKE_OK') PY From b44894aaf98a57fab8ebe0829e13124d5931b502 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 11:07:51 +0800 Subject: [PATCH 0987/1285] fix: drop openai-chat-completions protocol --- cn/kejilion.sh | 69 +++++++------------ kejilion.sh | 69 +++++++------------ ...ests_openclaw_api_protocol_detect_smoke.sh | 59 +++++++++++++++- 3 files changed, 108 insertions(+), 89 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 739a3a392..3c1924530 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10164,12 +10164,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): @@ -10216,7 +10213,7 @@ else: defaults_models = {} defaults['models'] = defaults_models -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} changed = False fatal_errors = [] @@ -10359,12 +10356,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): @@ -10404,8 +10398,10 @@ for name, provider in list(providers.items()): continue if api not in SUPPORTED_APIS: - summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') - continue + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True try: detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) @@ -10598,7 +10594,7 @@ PY - # OpenClaw API 协议探测(优先 responses -> chat/completions -> completions) + # OpenClaw API 协议探测(优先 responses -> completions) openclaw_probe_api_endpoint() { local base_url="$1" local api_key="$2" @@ -10620,10 +10616,9 @@ PY local base_url="$1" local api_key="$2" local code_responses="000" - local code_chat="000" DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses & /chat/completions not supported" + DETECTED_REASON="fallback: /responses not supported" code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then @@ -10632,15 +10627,8 @@ PY return 0 fi - code_chat=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/chat/completions") - if [[ "$code_chat" != "404" && "$code_chat" != "405" && "$code_chat" != "000" ]]; then - DETECTED_API="openai-chat-completions" - DETECTED_REASON="POST /chat/completions -> HTTP $code_chat" - return 0 - fi - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses, /chat/completions=$code_chat -> fallback /completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" return 0 } @@ -10909,7 +10897,7 @@ import time import urllib.request path = sys.argv[1] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): @@ -11026,7 +11014,7 @@ import urllib.request path = sys.argv[1] target = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): url = base_url.rstrip('/') + path @@ -11053,12 +11041,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11143,8 +11128,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') - raise SystemExit(3) + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: @@ -11292,7 +11278,7 @@ import urllib.request path = sys.argv[1] name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): url = base_url.rstrip('/') + path @@ -11319,12 +11305,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: with open(path, 'r', encoding='utf-8') as f: diff --git a/kejilion.sh b/kejilion.sh index 739a3a392..3c1924530 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10164,12 +10164,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): @@ -10216,7 +10213,7 @@ else: defaults_models = {} defaults['models'] = defaults_models -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} changed = False fatal_errors = [] @@ -10359,12 +10356,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): @@ -10404,8 +10398,10 @@ for name, provider in list(providers.items()): continue if api not in SUPPORTED_APIS: - summary.append(f'ℹ️ 跳过 {name}: 不支持直接 /models 校验 (api={api})') - continue + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True try: detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) @@ -10598,7 +10594,7 @@ PY - # OpenClaw API 协议探测(优先 responses -> chat/completions -> completions) + # OpenClaw API 协议探测(优先 responses -> completions) openclaw_probe_api_endpoint() { local base_url="$1" local api_key="$2" @@ -10620,10 +10616,9 @@ PY local base_url="$1" local api_key="$2" local code_responses="000" - local code_chat="000" DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses & /chat/completions not supported" + DETECTED_REASON="fallback: /responses not supported" code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then @@ -10632,15 +10627,8 @@ PY return 0 fi - code_chat=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/chat/completions") - if [[ "$code_chat" != "404" && "$code_chat" != "405" && "$code_chat" != "000" ]]; then - DETECTED_API="openai-chat-completions" - DETECTED_REASON="POST /chat/completions -> HTTP $code_chat" - return 0 - fi - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses, /chat/completions=$code_chat -> fallback /completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" return 0 } @@ -10909,7 +10897,7 @@ import time import urllib.request path = sys.argv[1] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): @@ -11026,7 +11014,7 @@ import urllib.request path = sys.argv[1] target = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): url = base_url.rstrip('/') + path @@ -11053,12 +11041,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11143,8 +11128,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'❌ provider {target} 当前 api={api},不支持直接 /models 同步') - raise SystemExit(3) + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: @@ -11292,7 +11278,7 @@ import urllib.request path = sys.argv[1] name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses', 'openai-chat-completions'} +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): url = base_url.rstrip('/') + path @@ -11319,12 +11305,9 @@ def detect_api_protocol(base_url, api_key): code, err = probe_endpoint(base_url, api_key, '/responses') if code is not None and code not in (404, 405): return 'openai-responses', f'POST /responses -> HTTP {code}', None - code2, err2 = probe_endpoint(base_url, api_key, '/chat/completions') - if code2 is not None and code2 not in (404, 405): - return 'openai-chat-completions', f'POST /chat/completions -> HTTP {code2}', None - if err or err2: - return 'openai-completions', 'fallback: probe failed', err or err2 - return 'openai-completions', f'POST /responses={code}, /chat/completions={code2} -> fallback /completions', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: with open(path, 'r', encoding='utf-8') as f: diff --git a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh index 0e8b14cae..e141cef4e 100644 --- a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh +++ b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh @@ -23,6 +23,13 @@ awk 'BEGIN{p=0} /openclaw_api_manage_list\(\) \{/{p=0} p{print} ' "$SCRIPT" >> "$WORKDIR/harness.sh" + +awk 'BEGIN{p=0} + /openclaw_detect_api_protocol_by_provider\(\) \{/{p=1} + /fix-openclaw-provider-protocol-interactive\(\) \{/{p=0} + p{print} +' "$SCRIPT" >> "$WORKDIR/harness.sh" + chmod +x "$WORKDIR/harness.sh" # stub: curl @@ -58,7 +65,7 @@ export HOME="$WORKDIR/home" export PATH="$WORKDIR/bin:$PATH" export TERM=xterm -# minimal openclaw.json +# case 1: responses 不可用但 chat/completions 可用,仍应写 openai-completions cat > "$HOME/.openclaw/openclaw.json" <<'JSON' { "models": { @@ -84,7 +91,53 @@ with open(path, 'r', encoding='utf-8') as f: data = json.load(f) prov = data.get('models', {}).get('providers', {}).get('demo', {}) api = prov.get('api') -if api != 'openai-chat-completions': +if api != 'openai-completions': raise SystemExit(f'api mismatch: {api}') -print('SMOKE_OK') +print('SMOKE_OK: detect fallback to openai-completions') +PY + +# case 2: 已写入 openai-chat-completions 的配置,修复后必须落回合法协议 +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "models": { + "mode": "merge", + "providers": { + "demo": { + "api": "openai-chat-completions", + "baseUrl": "http://127.0.0.1:1", + "apiKey": "sk-test", + "models": [ + { + "id": "gpt-4o", + "name": "demo / gpt-4o", + "input": ["text"], + "contextWindow": 1, + "maxTokens": 1, + "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0} + } + ] + } + } + }, + "agents": { + "defaults": { + "models": { + "demo/gpt-4o": {} + } + } + } +} +JSON + +openclaw_detect_api_protocol_by_provider "$HOME/.openclaw/openclaw.json" "demo" + +python3 - <<'PY' +import json, os, sys +path = os.path.expanduser('~/.openclaw/openclaw.json') +with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) +api = data.get('models', {}).get('providers', {}).get('demo', {}).get('api') +if api not in ('openai-completions', 'openai-responses'): + raise SystemExit(f'protocol fix mismatch: {api}') +print('SMOKE_OK: protocol repair corrected openai-chat-completions') PY From f4af7af5f24e3ac38184ad0a769ede2cb38f96bc Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 11:36:01 +0800 Subject: [PATCH 0988/1285] feat: add safe memory index rebuild helper --- cn/kejilion.sh | 70 ++++-- .../tests_openclaw_memory_menu_smoke.sh | 203 ++++++++++++++++++ kejilion.sh | 70 ++++-- .../tests_openclaw_memory_menu_smoke.sh | 40 +++- 4 files changed, 332 insertions(+), 51 deletions(-) create mode 100755 cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3c1924530..edba242fa 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12839,6 +12839,42 @@ EOF openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' } + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ 未找到索引库文件,可能为空或不存在。" + echo " Store 原始值: ${store_raw:-<空>}" + echo " 仍将执行重建索引。" + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 已备份索引: $backup_file" + else + echo "⚠️ 索引备份失败,继续重建。" + fi + fi + openclaw memory index --force + echo "" + openclaw_memory_render_status + } + openclaw_memory_prepare_workspace() { local workspace memory_dir workspace=$(openclaw_memory_status_value "Workspace") @@ -13041,22 +13077,7 @@ EOF echo "推荐执行:清理并重建索引" read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - local store_file ts backup_file - store_file=$(openclaw_memory_status_value "Store") - if [ -n "$store_file" ] && [ -f "$store_file" ]; then - ts=$(date +%Y%m%d_%H%M%S) - backup_file="${store_file}.bak.${ts}" - if mv "$store_file" "$backup_file"; then - echo "✅ 已备份索引: $backup_file" - else - echo "⚠️ 索引备份失败,继续重建。" - fi - else - echo "⚠️ 未找到索引库文件,跳过备份。" - fi - openclaw memory index --force - echo "" - openclaw_memory_render_status + openclaw_memory_rebuild_index_safe else echo "可稍后在记忆管理中查看状态。" fi @@ -13268,13 +13289,20 @@ EOF continue fi openclaw_memory_prepare_workspace - read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 - if [ "$confirm_step2" = "force" ]; then - openclaw memory index --force + read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ 全量重建更彻底,但耗时更长。" + echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" + read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe else - openclaw memory index + openclaw memory index --force fi - break_end + else + openclaw memory index + fi + break_end ;; 2) openclaw_memory_files_menu diff --git a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh new file mode 100755 index 000000000..d92832d77 --- /dev/null +++ b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-menu-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +# 抽取 OpenClaw 记忆菜单实现 +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_memory_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +awk 'BEGIN{p=0} /openclaw_memory_menu\(\) \{/{p=1} /openclaw_backup_restore_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +cmd="$*" +if [[ "$cmd" == "config get"* ]]; then + key="$3" + case "$key" in + memory.backend) echo "qmd" ;; + memory.qmd.includeDefaultMemory) echo "true" ;; + memory.qmd.command) echo "qmd" ;; + agents.defaults.memorySearch.local.modelPath) echo "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" ;; + agents.defaults.memorySearch.provider) echo "local" ;; + *) echo "" ;; + esac + exit 0 +fi +if [[ "$cmd" == "config set"* ]]; then + key="$3" + val="$4" + if [[ "$key" == "memory.qmd.includeDefaultMemory" ]]; then + echo "$val" > "${HOME}/.openclaw/includeDefaultMemory" + fi + if [[ "$key" == "memory.backend" ]]; then + echo "$val" > "${HOME}/.openclaw/backend" + fi + if [[ "$key" == "memory.qmd.command" ]]; then + echo "$val" > "${HOME}/.openclaw/qmd_command" + fi + if [[ "$key" == "agents.defaults.memorySearch.provider" ]]; then + echo "$val" > "${HOME}/.openclaw/provider" + fi + exit 0 +fi +if [[ "$cmd" == "memory status" ]]; then + cat <> "${HOME}/.openclaw/index_calls" + echo "index ok" + exit 0 +fi +if [[ "$cmd" == "gateway restart" ]]; then + echo "gateway restarted" + exit 0 +fi +if [[ "$cmd" == "gateway stop" ]]; then + echo "gateway stopped" + exit 0 +fi +if [[ "$cmd" == "gateway start" ]]; then + echo "gateway started" + exit 0 +fi +echo "mock openclaw $*" +EOF_INNER +chmod +x "$WORKDIR/bin/openclaw" + +# stub: qmd +cat > "$WORKDIR/bin/qmd" <<'EOF_INNER' +#!/usr/bin/env bash +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/qmd" + +# stub: curl (用于网络探测) +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +if [[ "$*" == *"huggingface.co"* ]]; then + exit 1 +fi +if [[ "$*" == *"hf-mirror.com"* ]]; then + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +# minimal openclaw.json +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "memory": { + "backend": "qmd", + "qmd": {"command": "qmd", "includeDefaultMemory": true} + }, + "agents": { + "defaults": { + "memorySearch": { + "provider": "local", + "local": { + "modelPath": "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf" + } + } + } + } +} +JSON + +# mock index sqlite +mkdir -p "$HOME/.openclaw/workspace/memory" +touch "$HOME/.openclaw/workspace/memory/index.sqlite" + +# mock memory files +cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' +# MEMORY +line1 +line2 +line3 +TXT +cat > "$HOME/.openclaw/workspace/memory/2026-03-11.md" <<'TXT' +# 2026-03-11 +foo +bar +TXT + +source "$WORKDIR/harness.sh" + +run_menu() { + local input="$1" + local title="$2" + local outfile="$3" + echo "[TEST] $title" + printf "%b" "$input" | openclaw_memory_menu >"$outfile" +} + +# 1) 状态展示(直接返回) +run_menu "0\n" "status" "$WORKDIR/out_status.txt" +# 2) 更新索引(增量) +run_menu "1\nyes\n\n\n0\n" "index" "$WORKDIR/out_index.txt" +# 3) 查看记忆文件(列表+查看) +run_menu "2\n1\n\n\n\n\n0\n0\n" "files" "$WORKDIR/out_files.txt" +# 4) 索引修复(执行修复 + 不立即重建) +run_menu "3\ny\n\n\n0\n" "fix" "$WORKDIR/out_fix.txt" +# 5) 记忆方案(自动推荐并取消) +run_menu "4\n1\n\nN\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" + +# 6) Store 缺失时仍执行 rebuild +: > "$HOME/.openclaw/index_calls" +OPENCLAW_STORE="~/.openclaw/workspace/memory/missing.sqlite" \ + openclaw_memory_rebuild_index_safe >"$WORKDIR/out_missing.txt" + +export WORKDIR +python3 - <<'PY' +import glob +import os + +flag_path = os.path.expanduser('~/.openclaw/includeDefaultMemory') +if not os.path.exists(flag_path): + raise SystemExit('includeDefaultMemory not updated') +flag = open(flag_path, 'r', encoding='utf-8').read().strip() +if flag != 'false': + raise SystemExit('includeDefaultMemory not updated') +# ensure backup created +baks = glob.glob(os.path.expanduser('~/.openclaw/workspace/memory/index.sqlite.bak.*')) +if not baks: + raise SystemExit('index sqlite backup not created') +# ensure missing store still triggers force index +calls_path = os.path.expanduser('~/.openclaw/index_calls') +if not os.path.exists(calls_path): + raise SystemExit('index calls not recorded') +with open(calls_path, 'r', encoding='utf-8') as fh: + calls = fh.read() +if 'memory index --force' not in calls: + raise SystemExit('force index not called for missing store') +# ensure warning emitted +with open(os.path.join(os.environ['WORKDIR'], 'out_missing.txt'), 'r', encoding='utf-8') as fh: + out = fh.read() +if 'Store 原始值' not in out: + raise SystemExit('missing store warning not found') +print('SMOKE_OK') +PY diff --git a/kejilion.sh b/kejilion.sh index 3c1924530..edba242fa 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12839,6 +12839,42 @@ EOF openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' } + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ 未找到索引库文件,可能为空或不存在。" + echo " Store 原始值: ${store_raw:-<空>}" + echo " 仍将执行重建索引。" + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 已备份索引: $backup_file" + else + echo "⚠️ 索引备份失败,继续重建。" + fi + fi + openclaw memory index --force + echo "" + openclaw_memory_render_status + } + openclaw_memory_prepare_workspace() { local workspace memory_dir workspace=$(openclaw_memory_status_value "Workspace") @@ -13041,22 +13077,7 @@ EOF echo "推荐执行:清理并重建索引" read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - local store_file ts backup_file - store_file=$(openclaw_memory_status_value "Store") - if [ -n "$store_file" ] && [ -f "$store_file" ]; then - ts=$(date +%Y%m%d_%H%M%S) - backup_file="${store_file}.bak.${ts}" - if mv "$store_file" "$backup_file"; then - echo "✅ 已备份索引: $backup_file" - else - echo "⚠️ 索引备份失败,继续重建。" - fi - else - echo "⚠️ 未找到索引库文件,跳过备份。" - fi - openclaw memory index --force - echo "" - openclaw_memory_render_status + openclaw_memory_rebuild_index_safe else echo "可稍后在记忆管理中查看状态。" fi @@ -13268,13 +13289,20 @@ EOF continue fi openclaw_memory_prepare_workspace - read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 - if [ "$confirm_step2" = "force" ]; then - openclaw memory index --force + read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ 全量重建更彻底,但耗时更长。" + echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" + read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe else - openclaw memory index + openclaw memory index --force fi - break_end + else + openclaw memory index + fi + break_end ;; 2) openclaw_memory_files_menu diff --git a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 1fb4d6cf3..d92832d77 100755 --- a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -59,11 +59,12 @@ Provider: qmd (requested: qmd) Vector: ready Indexed: 23/14 files Workspace: ${HOME}/.openclaw/workspace -Store: ${HOME}/.openclaw/workspace/memory/index.sqlite +Store: ${OPENCLAW_STORE:-~/.openclaw/workspace/memory/index.sqlite} TXT exit 0 fi if [[ "$cmd" == "memory index"* ]]; then + echo "$cmd" >> "${HOME}/.openclaw/index_calls" echo "index ok" exit 0 fi @@ -149,23 +150,32 @@ source "$WORKDIR/harness.sh" run_menu() { local input="$1" local title="$2" + local outfile="$3" echo "[TEST] $title" - printf "%b" "$input" | openclaw_memory_menu >/tmp/memory_menu.out + printf "%b" "$input" | openclaw_memory_menu >"$outfile" } # 1) 状态展示(直接返回) -run_menu "0\n" "status" +run_menu "0\n" "status" "$WORKDIR/out_status.txt" # 2) 更新索引(增量) -run_menu "1\nyes\n\n\n0\n" "index" +run_menu "1\nyes\n\n\n0\n" "index" "$WORKDIR/out_index.txt" # 3) 查看记忆文件(列表+查看) -run_menu "2\n1\n\n\n\n\n0\n0\n" "files" +run_menu "2\n1\n\n\n\n\n0\n0\n" "files" "$WORKDIR/out_files.txt" # 4) 索引修复(执行修复 + 不立即重建) -run_menu "3\ny\n\n\n0\n" "fix" +run_menu "3\ny\n\n\n0\n" "fix" "$WORKDIR/out_fix.txt" # 5) 记忆方案(自动推荐并取消) -run_menu "4\n1\n\nN\n0\n0\n" "scheme" +run_menu "4\n1\n\nN\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" +# 6) Store 缺失时仍执行 rebuild +: > "$HOME/.openclaw/index_calls" +OPENCLAW_STORE="~/.openclaw/workspace/memory/missing.sqlite" \ + openclaw_memory_rebuild_index_safe >"$WORKDIR/out_missing.txt" + +export WORKDIR python3 - <<'PY' -import json,os,sys +import glob +import os + flag_path = os.path.expanduser('~/.openclaw/includeDefaultMemory') if not os.path.exists(flag_path): raise SystemExit('includeDefaultMemory not updated') @@ -173,9 +183,21 @@ flag = open(flag_path, 'r', encoding='utf-8').read().strip() if flag != 'false': raise SystemExit('includeDefaultMemory not updated') # ensure backup created -import glob baks = glob.glob(os.path.expanduser('~/.openclaw/workspace/memory/index.sqlite.bak.*')) if not baks: raise SystemExit('index sqlite backup not created') +# ensure missing store still triggers force index +calls_path = os.path.expanduser('~/.openclaw/index_calls') +if not os.path.exists(calls_path): + raise SystemExit('index calls not recorded') +with open(calls_path, 'r', encoding='utf-8') as fh: + calls = fh.read() +if 'memory index --force' not in calls: + raise SystemExit('force index not called for missing store') +# ensure warning emitted +with open(os.path.join(os.environ['WORKDIR'], 'out_missing.txt'), 'r', encoding='utf-8') as fh: + out = fh.read() +if 'Store 原始值' not in out: + raise SystemExit('missing store warning not found') print('SMOKE_OK') PY From 80a0d4802e1b6779ba88924321affd6e8dd99d43 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 11:58:55 +0800 Subject: [PATCH 0989/1285] feat: auto setup memory backends --- cn/kejilion.sh | 325 +++++++++++++++++- .../tests_openclaw_memory_auto_setup_smoke.sh | 1 + kejilion.sh | 325 +++++++++++++++++- .../tests_openclaw_memory_auto_setup_smoke.sh | 228 ++++++++++++ 4 files changed, 869 insertions(+), 10 deletions(-) create mode 120000 cn/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh create mode 100644 tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index edba242fa..6ffbcca18 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13012,6 +13012,317 @@ EOF fi } + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ 未检测到 curl 或 wget,无法下载。" + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 可用: ${ver:-unknown}" + echo "ℹ️ sqlite 扩展支持无法可靠检测,将继续。" + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 已存在" + return 0 + fi + echo "⬇️ 安装 bun..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌ 未检测到 curl 或 wget,无法安装 bun。" + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 安装完成" + return 0 + fi + echo "❌ bun 安装失败" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd 已存在: $qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ 通过 bun 安装 qmd: $qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd 安装失败" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd 安装完成: $qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ 环境就绪" + echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "模型: $OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "地区: $OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "下载源: $OPENCLAW_MEMORY_HF_BASE" + fi + echo "如需立即生效,请执行: openclaw gateway restart" + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + echo "即将执行自动部署(可能下载模型 / 写入配置 / 安装依赖)" + echo "目标方案: $scheme_label" + echo "检测到地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "huggingface.co: ${OPENCLAW_MEMORY_HF_OK:-unknown}" + echo "hf-mirror.com: ${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + echo "⚠️ 该过程可能产生网络流量与磁盘占用" + read -e -p "输入 yes 确认继续(默认 N): " confirm_step + if [ "$confirm_step" != "yes" ]; then + echo "已取消自动部署。" + return 1 + fi + local preheat_choice + read -e -p "是否预热索引(可能下载模型)?(Y/n): " preheat_choice + if [[ "$preheat_choice" =~ ^[Nn]$ ]]; then + OPENCLAW_MEMORY_PREHEAT="false" + else + OPENCLAW_MEMORY_PREHEAT="true" + fi + return 0 + } + + openclaw_memory_auto_setup_qmd() { + echo "🔍 检测 QMD 环境" + openclaw_memory_check_sqlite || true + openclaw_memory_ensure_qmd || return 1 + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅ memory.backend 已是 qmd" + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅ 已设置 memory.backend=qmd" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ 已写入 memory.qmd.command: $OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅ memory.qmd.command 已正确" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 预热索引(可能下载模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳过预热" + fi + echo "✅ QMD 自动部署完成" + } + + openclaw_memory_auto_setup_local() { + echo "🔍 检测 Local 环境" + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "local" ]; then + echo "✅ memory.backend 已是 local" + else + openclaw_memory_config_set "memory.backend" "local" + echo "✅ 已设置 memory.backend=local" + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅ memorySearch.provider 已是 local" + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ 已设置 agents.defaults.memorySearch.provider=local" + fi + + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ 模型文件已存在: $model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ -f "$model_dest" ]; then + echo "✅ 已发现默认模型文件: $model_dest" + else + echo "⬇️ 下载模型: $model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 模型已下载: $model_dest" + fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ 已写入模型路径" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + fi + echo "🔁 生成索引" + openclaw_memory_prepare_workspace + openclaw memory index --force + echo "✅ Local 自动部署完成" + } + + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) scheme_label="QMD" ;; + local) scheme_label="Local" ;; + *) + echo "❌ 未知方案: $scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + openclaw_memory_render_auto_summary + return 0 + } + + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "记忆方案自动部署" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3. Auto(自动选择)" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_memory_apply_scheme() { local scheme="$1" case "$scheme" in @@ -13103,14 +13414,18 @@ EOF echo "Local: 本地向量检索,依赖 embedding 模型文件" echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" - echo "1. 自动推荐并应用" - echo "2. 手动选择 QMD" - echo "3. 手动选择 Local" + echo "1. 切换并自动部署(推荐)" + echo "2. 自动推荐并应用(仅写配置)" + echo "3. 手动选择 QMD" + echo "4. 手动选择 Local" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " scheme_choice case "$scheme_choice" in 1) + openclaw_memory_auto_setup_menu + ;; + 2) openclaw_memory_recommend local recommend_label if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then @@ -13132,12 +13447,12 @@ EOF openclaw_memory_offer_restart break_end ;; - 2) + 3) openclaw_memory_apply_scheme "qmd" || { break_end; continue; } openclaw_memory_offer_restart break_end ;; - 3) + 4) openclaw_memory_apply_scheme "local" || { break_end; continue; } openclaw_memory_offer_restart break_end diff --git a/cn/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh new file mode 120000 index 000000000..1158d6222 --- /dev/null +++ b/cn/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh @@ -0,0 +1 @@ +../../../tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh \ No newline at end of file diff --git a/kejilion.sh b/kejilion.sh index edba242fa..6ffbcca18 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13012,6 +13012,317 @@ EOF fi } + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ 未检测到 curl 或 wget,无法下载。" + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 可用: ${ver:-unknown}" + echo "ℹ️ sqlite 扩展支持无法可靠检测,将继续。" + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 已存在" + return 0 + fi + echo "⬇️ 安装 bun..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌ 未检测到 curl 或 wget,无法安装 bun。" + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 安装完成" + return 0 + fi + echo "❌ bun 安装失败" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd 已存在: $qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ 通过 bun 安装 qmd: $qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd 安装失败" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd 安装完成: $qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ 环境就绪" + echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "模型: $OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "地区: $OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "下载源: $OPENCLAW_MEMORY_HF_BASE" + fi + echo "如需立即生效,请执行: openclaw gateway restart" + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + echo "即将执行自动部署(可能下载模型 / 写入配置 / 安装依赖)" + echo "目标方案: $scheme_label" + echo "检测到地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "huggingface.co: ${OPENCLAW_MEMORY_HF_OK:-unknown}" + echo "hf-mirror.com: ${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + echo "⚠️ 该过程可能产生网络流量与磁盘占用" + read -e -p "输入 yes 确认继续(默认 N): " confirm_step + if [ "$confirm_step" != "yes" ]; then + echo "已取消自动部署。" + return 1 + fi + local preheat_choice + read -e -p "是否预热索引(可能下载模型)?(Y/n): " preheat_choice + if [[ "$preheat_choice" =~ ^[Nn]$ ]]; then + OPENCLAW_MEMORY_PREHEAT="false" + else + OPENCLAW_MEMORY_PREHEAT="true" + fi + return 0 + } + + openclaw_memory_auto_setup_qmd() { + echo "🔍 检测 QMD 环境" + openclaw_memory_check_sqlite || true + openclaw_memory_ensure_qmd || return 1 + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅ memory.backend 已是 qmd" + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅ 已设置 memory.backend=qmd" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ 已写入 memory.qmd.command: $OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅ memory.qmd.command 已正确" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 预热索引(可能下载模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳过预热" + fi + echo "✅ QMD 自动部署完成" + } + + openclaw_memory_auto_setup_local() { + echo "🔍 检测 Local 环境" + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "local" ]; then + echo "✅ memory.backend 已是 local" + else + openclaw_memory_config_set "memory.backend" "local" + echo "✅ 已设置 memory.backend=local" + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅ memorySearch.provider 已是 local" + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ 已设置 agents.defaults.memorySearch.provider=local" + fi + + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ 模型文件已存在: $model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ -f "$model_dest" ]; then + echo "✅ 已发现默认模型文件: $model_dest" + else + echo "⬇️ 下载模型: $model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 模型已下载: $model_dest" + fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ 已写入模型路径" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + fi + echo "🔁 生成索引" + openclaw_memory_prepare_workspace + openclaw memory index --force + echo "✅ Local 自动部署完成" + } + + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) scheme_label="QMD" ;; + local) scheme_label="Local" ;; + *) + echo "❌ 未知方案: $scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + openclaw_memory_render_auto_summary + return 0 + } + + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "记忆方案自动部署" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3. Auto(自动选择)" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_memory_apply_scheme() { local scheme="$1" case "$scheme" in @@ -13103,14 +13414,18 @@ EOF echo "Local: 本地向量检索,依赖 embedding 模型文件" echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" - echo "1. 自动推荐并应用" - echo "2. 手动选择 QMD" - echo "3. 手动选择 Local" + echo "1. 切换并自动部署(推荐)" + echo "2. 自动推荐并应用(仅写配置)" + echo "3. 手动选择 QMD" + echo "4. 手动选择 Local" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " scheme_choice case "$scheme_choice" in 1) + openclaw_memory_auto_setup_menu + ;; + 2) openclaw_memory_recommend local recommend_label if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then @@ -13132,12 +13447,12 @@ EOF openclaw_memory_offer_restart break_end ;; - 2) + 3) openclaw_memory_apply_scheme "qmd" || { break_end; continue; } openclaw_memory_offer_restart break_end ;; - 3) + 4) openclaw_memory_apply_scheme "local" || { break_end; continue; } openclaw_memory_offer_restart break_end diff --git a/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh new file mode 100644 index 000000000..a8963f1e2 --- /dev/null +++ b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-auto-setup-test-$$" +mkdir -p "$WORKDIR/bin" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +# 抽取 OpenClaw 记忆菜单实现 +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_memory_menu\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +# stub: openclaw +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +cmd="$*" +config_dir="$HOME/.openclaw/config" +mkdir -p "$config_dir" +key_file() { + local key="$1" + echo "$config_dir/${key//./_}" +} +if [[ "$cmd" == "config get"* ]]; then + key="$3" + file=$(key_file "$key") + if [ -f "$file" ]; then + cat "$file" + fi + exit 0 +fi +if [[ "$cmd" == "config set"* ]]; then + key="$3" + val="$4" + file=$(key_file "$key") + echo "$val" > "$file" + exit 0 +fi +if [[ "$cmd" == "memory status" ]]; then + cat <> "${HOME}/.openclaw/index_calls" + echo "index ok" + exit 0 +fi +echo "mock openclaw $*" +EOF_INNER +chmod +x "$WORKDIR/bin/openclaw" + +# stub: curl +cat > "$WORKDIR/bin/curl" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +args=("$@") + +is_head=0 +for arg in "${args[@]}"; do + if [ "$arg" = "-I" ]; then + is_head=1 + fi +done +url="${args[$((${#args[@]}-1))]}" + +for arg in "${args[@]}"; do + if [[ "$arg" == *"ipinfo.io/country"* ]]; then + echo "${FAKE_COUNTRY:-US}" + exit 0 + fi + if [[ "$arg" == *"bun.sh/install"* ]]; then + cat <<'SCRIPT' +mkdir -p "$HOME/.bun/bin" +cat > "$HOME/.bun/bin/bun" <<'BUN' +#!/usr/bin/env bash +set -euo pipefail +if [[ "$1" == "install" && "$2" == "-g" ]]; then + mkdir -p "$HOME/.bun/bin" + cat > "$HOME/.bun/bin/qmd" <<'QMD' +#!/usr/bin/env bash +exit 0 +QMD + chmod +x "$HOME/.bun/bin/qmd" +fi +echo "$*" >> "$HOME/.openclaw/bun_calls" +exit 0 +BUN +chmod +x "$HOME/.bun/bin/bun" +SCRIPT + exit 0 + fi +done + +if [ "$is_head" = "1" ]; then + if [[ "$url" == *"huggingface.co"* ]]; then + exit ${FAKE_HF_OK:-0} + fi + if [[ "$url" == *"hf-mirror.com"* ]]; then + exit ${FAKE_MIRROR_OK:-0} + fi + exit 0 +fi + +dest="" +for ((i=0;i<${#args[@]};i++)); do + if [ "${args[$i]}" = "-o" ] && [ $((i+1)) -lt ${#args[@]} ]; then + dest="${args[$((i+1))]}" + fi +done + +if [ -n "$dest" ] && [[ "$url" == *"embeddinggemma"* ]]; then + mkdir -p "$(dirname "$dest")" + echo "model" > "$dest" + echo "$url" >> "$HOME/.openclaw/download_calls" + exit 0 +fi +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/curl" + +# stub: wget (fallback, not used in test) +cat > "$WORKDIR/bin/wget" <<'EOF_INNER' +#!/usr/bin/env bash +exit 0 +EOF_INNER +chmod +x "$WORKDIR/bin/wget" + +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +source "$WORKDIR/harness.sh" + +make_home() { + local name="$1" + local home="$WORKDIR/$name/home" + mkdir -p "$home/.openclaw/workspace/memory" "$home/.openclaw" + echo "$home" +} + +run_auto() { + local input="$1" + local scheme="$2" + local outfile="$3" + printf "%b" "$input" | openclaw_memory_auto_setup_run "$scheme" >"$outfile" +} + +# Case 1: qmd 不存在 -> 安装 -> 写入绝对路径 -> index +HOME_QMD=$(make_home "qmd") +export HOME="$HOME_QMD" +FAKE_COUNTRY=US FAKE_HF_OK=0 FAKE_MIRROR_OK=1 \ + run_auto "yes\n\n" "qmd" "$WORKDIR/out_qmd.txt" + +# Case 2: local 模型不存在 -> 下载 -> 写入 modelPath -> index (CN) +HOME_LOCAL=$(make_home "local") +export HOME="$HOME_LOCAL" +FAKE_COUNTRY=CN FAKE_HF_OK=1 FAKE_MIRROR_OK=0 \ + run_auto "yes\n\n" "local" "$WORKDIR/out_local.txt" + +# Case 3: 已存在 -> 跳过下载/安装 +HOME_SKIP=$(make_home "skip") +export HOME="$HOME_SKIP" +mkdir -p "$HOME/.openclaw/models/embedding" "$HOME/.openclaw/config" +MODEL_EXIST="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + +echo "local" > "$HOME/.openclaw/config/memory_backend" +echo "local" > "$HOME/.openclaw/config/agents_defaults_memorySearch_provider" +echo "$MODEL_EXIST" > "$HOME/.openclaw/config/agents_defaults_memorySearch_local_modelPath" + +touch "$MODEL_EXIST" + +# 预置 qmd +mkdir -p "$HOME/.bun/bin" +cat > "$HOME/.bun/bin/qmd" <<'QMD' +#!/usr/bin/env bash +exit 0 +QMD +chmod +x "$HOME/.bun/bin/qmd" +export PATH="$HOME/.bun/bin:$PATH" + +FAKE_COUNTRY=US FAKE_HF_OK=0 FAKE_MIRROR_OK=0 \ + run_auto "yes\nN\n" "local" "$WORKDIR/out_skip.txt" + +export WORKDIR +python3 - <<'PY' +import os +from pathlib import Path + +workdir = os.environ['WORKDIR'] + +# Case1: qmd command absolute + index called +home_qmd = Path(workdir) / 'qmd' / 'home' +qmd_cmd = (home_qmd / '.openclaw/config/memory_qmd_command').read_text().strip() +if not qmd_cmd.startswith('/'): + raise SystemExit('qmd command not absolute') +index_calls = (home_qmd / '.openclaw/index_calls').read_text() +if 'memory index --force' not in index_calls: + raise SystemExit('qmd preheat index not called') + +# Case2: local model downloaded + modelPath written +home_local = Path(workdir) / 'local' / 'home' +model_path = (home_local / '.openclaw/config/agents_defaults_memorySearch_local_modelPath').read_text().strip() +if not Path(model_path).exists(): + raise SystemExit('model file not downloaded') +if 'hf-mirror.com' not in (Path(workdir) / 'out_local.txt').read_text(): + raise SystemExit('mirror not used for CN') + +# Case3: skip download +home_skip = Path(workdir) / 'skip' / 'home' +download_calls = home_skip / '.openclaw/download_calls' +if download_calls.exists(): + raise SystemExit('download should be skipped when model exists') +print('SMOKE_OK') +PY From 00de32ec03ecda49d2be2b23d8442136d47f3f75 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 13:53:29 +0800 Subject: [PATCH 0990/1285] refactor memory scheme auto setup menu --- cn/kejilion.sh | 146 +++++++++++------- .../tests_openclaw_memory_menu_smoke.sh | 2 +- kejilion.sh | 146 +++++++++++------- .../tests_openclaw_memory_auto_setup_smoke.sh | 6 +- .../tests_openclaw_memory_menu_smoke.sh | 2 +- 5 files changed, 185 insertions(+), 117 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6ffbcca18..0275a3158 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13140,6 +13140,14 @@ EOF echo "---------------------------------------" echo "✅ 环境就绪" echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "模式: 仅写配置(未安装/未下载)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "预热索引: 已执行" + else + echo "预热索引: 已跳过" + fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" fi @@ -13158,24 +13166,47 @@ EOF openclaw_memory_auto_confirm() { local scheme_label="$1" - echo "即将执行自动部署(可能下载模型 / 写入配置 / 安装依赖)" + OPENCLAW_MEMORY_PREHEAT="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "即将执行自动部署(详细模式)" echo "目标方案: $scheme_label" - echo "检测到地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "huggingface.co: ${OPENCLAW_MEMORY_HF_OK:-unknown}" - echo "hf-mirror.com: ${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" - echo "⚠️ 该过程可能产生网络流量与磁盘占用" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "可能流量/磁盘占用: $OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "可能流量/磁盘占用: 视实际情况而定" + fi + echo "是否预热索引: 默认否(可输入 yes-preheat 开启)" + echo "高级选项: 输入 config 仅写配置(不安装不下载,不预热)" read -e -p "输入 yes 确认继续(默认 N): " confirm_step - if [ "$confirm_step" != "yes" ]; then - echo "已取消自动部署。" - return 1 + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="false" + ;; + yes-preheat|YES-PREHEAT|yes_preheat|YES_PREHEAT|yespreheat|YESPREHEAT) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "已取消自动部署。" + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ 已选择仅写配置,不安装不下载" fi - local preheat_choice - read -e -p "是否预热索引(可能下载模型)?(Y/n): " preheat_choice - if [[ "$preheat_choice" =~ ^[Nn]$ ]]; then - OPENCLAW_MEMORY_PREHEAT="false" + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 已选择预热索引" else - OPENCLAW_MEMORY_PREHEAT="true" + echo "⏭️ 将跳过预热索引" fi return 0 } @@ -13183,7 +13214,15 @@ EOF openclaw_memory_auto_setup_qmd() { echo "🔍 检测 QMD 环境" openclaw_memory_check_sqlite || true - openclaw_memory_ensure_qmd || return 1 + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) + else + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi local backend backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ]; then @@ -13240,20 +13279,29 @@ EOF local model_dir="$HOME/.openclaw/models/embedding" local model_dest="$model_dir/$model_name" local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" - if [ -f "$model_dest" ]; then - echo "✅ 已发现默认模型文件: $model_dest" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ 仅写配置模式:跳过模型下载" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" else - echo "⬇️ 下载模型: $model_url" - openclaw_memory_download_file "$model_url" "$model_dest" || return 1 - echo "✅ 模型已下载: $model_dest" + if [ -f "$model_dest" ]; then + echo "✅ 已发现默认模型文件: $model_dest" + else + echo "⬇️ 下载模型: $model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 模型已下载: $model_dest" + fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" echo "✅ 已写入模型路径" - OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi - echo "🔁 生成索引" - openclaw_memory_prepare_workspace - openclaw memory index --force + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 预热索引(可能下载模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳过预热" + fi echo "✅ Local 自动部署完成" } @@ -13262,6 +13310,8 @@ EOF local scheme_label OPENCLAW_MEMORY_QMD_PATH="" OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" openclaw_memory_detect_region openclaw_memory_select_sources if [ "$scheme" = "auto" ]; then @@ -13269,8 +13319,16 @@ EOF scheme="$OPENCLAW_MEMORY_RECOMMEND" fi case "$scheme" in - qmd) scheme_label="QMD" ;; - local) scheme_label="Local" ;; + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安装目录)" + OPENCLAW_MEMORY_EXPECT_SIZE="约 20-50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="约 350-600MB" + ;; *) echo "❌ 未知方案: $scheme" return 1 @@ -13414,47 +13472,23 @@ EOF echo "Local: 本地向量检索,依赖 embedding 模型文件" echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" - echo "1. 切换并自动部署(推荐)" - echo "2. 自动推荐并应用(仅写配置)" - echo "3. 手动选择 QMD" - echo "4. 手动选择 Local" + echo "1. 切换 QMD(自动部署/已装则跳过)" + echo "2. 切换 Local(自动部署/已装则跳过)" + echo "3. Auto(自动推荐并自动部署)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " scheme_choice case "$scheme_choice" in 1) - openclaw_memory_auto_setup_menu + openclaw_memory_auto_setup_run "qmd" + break_end ;; 2) - openclaw_memory_recommend - local recommend_label - if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then - recommend_label="QMD" - else - recommend_label="Local" - fi - echo "推荐方案: $recommend_label" - echo "推荐原因:" - for reason in "${OPENCLAW_MEMORY_RECOMMEND_REASON[@]}"; do - echo " - $reason" - done - read -e -p "是否应用该方案?(Y/n): " apply_choice - if [[ "$apply_choice" =~ ^[Nn]$ ]]; then - break_end - continue - fi - openclaw_memory_apply_scheme "$OPENCLAW_MEMORY_RECOMMEND" || { break_end; continue; } - openclaw_memory_offer_restart + openclaw_memory_auto_setup_run "local" break_end ;; 3) - openclaw_memory_apply_scheme "qmd" || { break_end; continue; } - openclaw_memory_offer_restart - break_end - ;; - 4) - openclaw_memory_apply_scheme "local" || { break_end; continue; } - openclaw_memory_offer_restart + openclaw_memory_auto_setup_run "auto" break_end ;; 0) diff --git a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index d92832d77..1f6240b51 100755 --- a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -164,7 +164,7 @@ run_menu "2\n1\n\n\n\n\n0\n0\n" "files" "$WORKDIR/out_files.txt" # 4) 索引修复(执行修复 + 不立即重建) run_menu "3\ny\n\n\n0\n" "fix" "$WORKDIR/out_fix.txt" # 5) 记忆方案(自动推荐并取消) -run_menu "4\n1\n\nN\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" +run_menu "4\n1\n\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" # 6) Store 缺失时仍执行 rebuild : > "$HOME/.openclaw/index_calls" diff --git a/kejilion.sh b/kejilion.sh index 6ffbcca18..0275a3158 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13140,6 +13140,14 @@ EOF echo "---------------------------------------" echo "✅ 环境就绪" echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "模式: 仅写配置(未安装/未下载)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "预热索引: 已执行" + else + echo "预热索引: 已跳过" + fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" fi @@ -13158,24 +13166,47 @@ EOF openclaw_memory_auto_confirm() { local scheme_label="$1" - echo "即将执行自动部署(可能下载模型 / 写入配置 / 安装依赖)" + OPENCLAW_MEMORY_PREHEAT="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "即将执行自动部署(详细模式)" echo "目标方案: $scheme_label" - echo "检测到地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "huggingface.co: ${OPENCLAW_MEMORY_HF_OK:-unknown}" - echo "hf-mirror.com: ${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" - echo "⚠️ 该过程可能产生网络流量与磁盘占用" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "可能流量/磁盘占用: $OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "可能流量/磁盘占用: 视实际情况而定" + fi + echo "是否预热索引: 默认否(可输入 yes-preheat 开启)" + echo "高级选项: 输入 config 仅写配置(不安装不下载,不预热)" read -e -p "输入 yes 确认继续(默认 N): " confirm_step - if [ "$confirm_step" != "yes" ]; then - echo "已取消自动部署。" - return 1 + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="false" + ;; + yes-preheat|YES-PREHEAT|yes_preheat|YES_PREHEAT|yespreheat|YESPREHEAT) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "已取消自动部署。" + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ 已选择仅写配置,不安装不下载" fi - local preheat_choice - read -e -p "是否预热索引(可能下载模型)?(Y/n): " preheat_choice - if [[ "$preheat_choice" =~ ^[Nn]$ ]]; then - OPENCLAW_MEMORY_PREHEAT="false" + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 已选择预热索引" else - OPENCLAW_MEMORY_PREHEAT="true" + echo "⏭️ 将跳过预热索引" fi return 0 } @@ -13183,7 +13214,15 @@ EOF openclaw_memory_auto_setup_qmd() { echo "🔍 检测 QMD 环境" openclaw_memory_check_sqlite || true - openclaw_memory_ensure_qmd || return 1 + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) + else + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi local backend backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ]; then @@ -13240,20 +13279,29 @@ EOF local model_dir="$HOME/.openclaw/models/embedding" local model_dest="$model_dir/$model_name" local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" - if [ -f "$model_dest" ]; then - echo "✅ 已发现默认模型文件: $model_dest" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ 仅写配置模式:跳过模型下载" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" else - echo "⬇️ 下载模型: $model_url" - openclaw_memory_download_file "$model_url" "$model_dest" || return 1 - echo "✅ 模型已下载: $model_dest" + if [ -f "$model_dest" ]; then + echo "✅ 已发现默认模型文件: $model_dest" + else + echo "⬇️ 下载模型: $model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 模型已下载: $model_dest" + fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" echo "✅ 已写入模型路径" - OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi - echo "🔁 生成索引" - openclaw_memory_prepare_workspace - openclaw memory index --force + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 预热索引(可能下载模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳过预热" + fi echo "✅ Local 自动部署完成" } @@ -13262,6 +13310,8 @@ EOF local scheme_label OPENCLAW_MEMORY_QMD_PATH="" OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" openclaw_memory_detect_region openclaw_memory_select_sources if [ "$scheme" = "auto" ]; then @@ -13269,8 +13319,16 @@ EOF scheme="$OPENCLAW_MEMORY_RECOMMEND" fi case "$scheme" in - qmd) scheme_label="QMD" ;; - local) scheme_label="Local" ;; + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安装目录)" + OPENCLAW_MEMORY_EXPECT_SIZE="约 20-50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="约 350-600MB" + ;; *) echo "❌ 未知方案: $scheme" return 1 @@ -13414,47 +13472,23 @@ EOF echo "Local: 本地向量检索,依赖 embedding 模型文件" echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" - echo "1. 切换并自动部署(推荐)" - echo "2. 自动推荐并应用(仅写配置)" - echo "3. 手动选择 QMD" - echo "4. 手动选择 Local" + echo "1. 切换 QMD(自动部署/已装则跳过)" + echo "2. 切换 Local(自动部署/已装则跳过)" + echo "3. Auto(自动推荐并自动部署)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " scheme_choice case "$scheme_choice" in 1) - openclaw_memory_auto_setup_menu + openclaw_memory_auto_setup_run "qmd" + break_end ;; 2) - openclaw_memory_recommend - local recommend_label - if [ "$OPENCLAW_MEMORY_RECOMMEND" = "qmd" ]; then - recommend_label="QMD" - else - recommend_label="Local" - fi - echo "推荐方案: $recommend_label" - echo "推荐原因:" - for reason in "${OPENCLAW_MEMORY_RECOMMEND_REASON[@]}"; do - echo " - $reason" - done - read -e -p "是否应用该方案?(Y/n): " apply_choice - if [[ "$apply_choice" =~ ^[Nn]$ ]]; then - break_end - continue - fi - openclaw_memory_apply_scheme "$OPENCLAW_MEMORY_RECOMMEND" || { break_end; continue; } - openclaw_memory_offer_restart + openclaw_memory_auto_setup_run "local" break_end ;; 3) - openclaw_memory_apply_scheme "qmd" || { break_end; continue; } - openclaw_memory_offer_restart - break_end - ;; - 4) - openclaw_memory_apply_scheme "local" || { break_end; continue; } - openclaw_memory_offer_restart + openclaw_memory_auto_setup_run "auto" break_end ;; 0) diff --git a/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh index a8963f1e2..2b1d3d2cc 100644 --- a/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh @@ -163,13 +163,13 @@ run_auto() { HOME_QMD=$(make_home "qmd") export HOME="$HOME_QMD" FAKE_COUNTRY=US FAKE_HF_OK=0 FAKE_MIRROR_OK=1 \ - run_auto "yes\n\n" "qmd" "$WORKDIR/out_qmd.txt" + run_auto "yes-preheat\n" "qmd" "$WORKDIR/out_qmd.txt" # Case 2: local 模型不存在 -> 下载 -> 写入 modelPath -> index (CN) HOME_LOCAL=$(make_home "local") export HOME="$HOME_LOCAL" FAKE_COUNTRY=CN FAKE_HF_OK=1 FAKE_MIRROR_OK=0 \ - run_auto "yes\n\n" "local" "$WORKDIR/out_local.txt" + run_auto "yes-preheat\n" "local" "$WORKDIR/out_local.txt" # Case 3: 已存在 -> 跳过下载/安装 HOME_SKIP=$(make_home "skip") @@ -193,7 +193,7 @@ chmod +x "$HOME/.bun/bin/qmd" export PATH="$HOME/.bun/bin:$PATH" FAKE_COUNTRY=US FAKE_HF_OK=0 FAKE_MIRROR_OK=0 \ - run_auto "yes\nN\n" "local" "$WORKDIR/out_skip.txt" + run_auto "yes\n" "local" "$WORKDIR/out_skip.txt" export WORKDIR python3 - <<'PY' diff --git a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index d92832d77..1f6240b51 100755 --- a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -164,7 +164,7 @@ run_menu "2\n1\n\n\n\n\n0\n0\n" "files" "$WORKDIR/out_files.txt" # 4) 索引修复(执行修复 + 不立即重建) run_menu "3\ny\n\n\n0\n" "fix" "$WORKDIR/out_fix.txt" # 5) 记忆方案(自动推荐并取消) -run_menu "4\n1\n\nN\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" +run_menu "4\n1\n\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" # 6) Store 缺失时仍执行 rebuild : > "$HOME/.openclaw/index_calls" From e99e084f328d2d85118f15467e810dc4951dcd86 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 14:57:21 +0800 Subject: [PATCH 0991/1285] Auto memory scheme setup with builtin backend --- cn/kejilion.sh | 71 +++++++++++++++------ kejilion.sh | 71 +++++++++++++++------ tests_openclaw_manager_smoke.sh | 105 +++++++++++++++++++++++++++++--- 3 files changed, 200 insertions(+), 47 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0275a3158..90de92e4f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12834,6 +12834,15 @@ EOF openclaw config set "$key" "$@" >/dev/null 2>&1 } + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + openclaw_memory_status_value() { local key="$1" openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' @@ -12906,7 +12915,13 @@ EOF } openclaw_memory_get_backend() { - openclaw_memory_config_get "memory.backend" + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi } openclaw_memory_get_local_model_path() { @@ -13144,9 +13159,14 @@ EOF echo "模式: 仅写配置(未安装/未下载)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "预热索引: 已执行" + echo "索引: 已执行" else - echo "预热索引: 已跳过" + echo "索引: 已跳过" + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "重启: 已执行" + else + echo "重启: 已跳过" fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" @@ -13160,13 +13180,15 @@ EOF if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then echo "下载源: $OPENCLAW_MEMORY_HF_BASE" fi - echo "如需立即生效,请执行: openclaw gateway restart" + echo "最终状态:" + openclaw_memory_render_status echo "---------------------------------------" } openclaw_memory_auto_confirm() { local scheme_label="$1" - OPENCLAW_MEMORY_PREHEAT="false" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" echo "即将执行自动部署(详细模式)" echo "目标方案: $scheme_label" @@ -13181,14 +13203,11 @@ EOF else echo "可能流量/磁盘占用: 视实际情况而定" fi - echo "是否预热索引: 默认否(可输入 yes-preheat 开启)" - echo "高级选项: 输入 config 仅写配置(不安装不下载,不预热)" + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" read -e -p "输入 yes 确认继续(默认 N): " confirm_step case "$confirm_step" in yes|YES) - OPENCLAW_MEMORY_PREHEAT="false" - ;; - yes-preheat|YES-PREHEAT|yes_preheat|YES_PREHEAT|yespreheat|YESPREHEAT) OPENCLAW_MEMORY_PREHEAT="true" ;; config|CONFIG) @@ -13202,17 +13221,15 @@ EOF esac if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then echo "⚠️ 已选择仅写配置,不安装不下载" - fi - if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 已选择预热索引" else - echo "⏭️ 将跳过预热索引" + echo "✅ 将自动构建索引并重启网关" fi return 0 } openclaw_memory_auto_setup_qmd() { echo "🔍 检测 QMD 环境" + openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then if command -v qmd >/dev/null 2>&1; then @@ -13251,13 +13268,14 @@ EOF openclaw_memory_auto_setup_local() { echo "🔍 检测 Local 环境" + openclaw_memory_cleanup_legacy_keys local backend provider backend=$(openclaw_memory_get_backend) - if [ "$backend" = "local" ]; then - echo "✅ memory.backend 已是 local" + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅ memory.backend 已是 builtin" else - openclaw_memory_config_set "memory.backend" "local" - echo "✅ 已设置 memory.backend=local" + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅ 已设置 memory.backend=builtin" fi provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") if [ "$provider" = "local" ]; then @@ -13341,6 +13359,18 @@ EOF local) openclaw_memory_auto_setup_local || return 1 ;; *) return 1 ;; esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ 重启 OpenClaw 网关" + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" openclaw_memory_render_auto_summary return 0 } @@ -13383,6 +13413,7 @@ EOF openclaw_memory_apply_scheme() { local scheme="$1" + openclaw_memory_cleanup_legacy_keys case "$scheme" in qmd) openclaw_memory_config_set "memory.backend" "qmd" @@ -13393,7 +13424,7 @@ EOF openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 ;; local) - openclaw_memory_config_set "memory.backend" "local" + openclaw_memory_config_set "memory.backend" "builtin" if [ $? -ne 0 ]; then echo "❌ 写入配置失败" return 1 @@ -13463,7 +13494,7 @@ EOF backend=$(openclaw_memory_get_backend) case "$backend" in qmd) current_label="QMD" ;; - local) current_label="Local" ;; + builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac echo "当前方案: $current_label" diff --git a/kejilion.sh b/kejilion.sh index 0275a3158..90de92e4f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12834,6 +12834,15 @@ EOF openclaw config set "$key" "$@" >/dev/null 2>&1 } + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + openclaw_memory_status_value() { local key="$1" openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' @@ -12906,7 +12915,13 @@ EOF } openclaw_memory_get_backend() { - openclaw_memory_config_get "memory.backend" + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi } openclaw_memory_get_local_model_path() { @@ -13144,9 +13159,14 @@ EOF echo "模式: 仅写配置(未安装/未下载)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "预热索引: 已执行" + echo "索引: 已执行" else - echo "预热索引: 已跳过" + echo "索引: 已跳过" + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "重启: 已执行" + else + echo "重启: 已跳过" fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" @@ -13160,13 +13180,15 @@ EOF if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then echo "下载源: $OPENCLAW_MEMORY_HF_BASE" fi - echo "如需立即生效,请执行: openclaw gateway restart" + echo "最终状态:" + openclaw_memory_render_status echo "---------------------------------------" } openclaw_memory_auto_confirm() { local scheme_label="$1" - OPENCLAW_MEMORY_PREHEAT="false" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" echo "即将执行自动部署(详细模式)" echo "目标方案: $scheme_label" @@ -13181,14 +13203,11 @@ EOF else echo "可能流量/磁盘占用: 视实际情况而定" fi - echo "是否预热索引: 默认否(可输入 yes-preheat 开启)" - echo "高级选项: 输入 config 仅写配置(不安装不下载,不预热)" + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" read -e -p "输入 yes 确认继续(默认 N): " confirm_step case "$confirm_step" in yes|YES) - OPENCLAW_MEMORY_PREHEAT="false" - ;; - yes-preheat|YES-PREHEAT|yes_preheat|YES_PREHEAT|yespreheat|YESPREHEAT) OPENCLAW_MEMORY_PREHEAT="true" ;; config|CONFIG) @@ -13202,17 +13221,15 @@ EOF esac if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then echo "⚠️ 已选择仅写配置,不安装不下载" - fi - if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 已选择预热索引" else - echo "⏭️ 将跳过预热索引" + echo "✅ 将自动构建索引并重启网关" fi return 0 } openclaw_memory_auto_setup_qmd() { echo "🔍 检测 QMD 环境" + openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then if command -v qmd >/dev/null 2>&1; then @@ -13251,13 +13268,14 @@ EOF openclaw_memory_auto_setup_local() { echo "🔍 检测 Local 环境" + openclaw_memory_cleanup_legacy_keys local backend provider backend=$(openclaw_memory_get_backend) - if [ "$backend" = "local" ]; then - echo "✅ memory.backend 已是 local" + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅ memory.backend 已是 builtin" else - openclaw_memory_config_set "memory.backend" "local" - echo "✅ 已设置 memory.backend=local" + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅ 已设置 memory.backend=builtin" fi provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") if [ "$provider" = "local" ]; then @@ -13341,6 +13359,18 @@ EOF local) openclaw_memory_auto_setup_local || return 1 ;; *) return 1 ;; esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ 重启 OpenClaw 网关" + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" openclaw_memory_render_auto_summary return 0 } @@ -13383,6 +13413,7 @@ EOF openclaw_memory_apply_scheme() { local scheme="$1" + openclaw_memory_cleanup_legacy_keys case "$scheme" in qmd) openclaw_memory_config_set "memory.backend" "qmd" @@ -13393,7 +13424,7 @@ EOF openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 ;; local) - openclaw_memory_config_set "memory.backend" "local" + openclaw_memory_config_set "memory.backend" "builtin" if [ $? -ne 0 ]; then echo "❌ 写入配置失败" return 1 @@ -13463,7 +13494,7 @@ EOF backend=$(openclaw_memory_get_backend) case "$backend" in qmd) current_label="QMD" ;; - local) current_label="Local" ;; + builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac echo "当前方案: $current_label" diff --git a/tests_openclaw_manager_smoke.sh b/tests_openclaw_manager_smoke.sh index 851b950f5..f2e5cf046 100755 --- a/tests_openclaw_manager_smoke.sh +++ b/tests_openclaw_manager_smoke.sh @@ -10,15 +10,25 @@ trap 'rm -rf "$WORKDIR"' EXIT cat > "$WORKDIR/harness.sh" <<'EOF' #!/usr/bin/env bash set -euo pipefail +install() { return 0; } +break_end() { :; } +send_stats() { :; } EOF -sed -n '10053,10162p' "$SCRIPT" >> "$WORKDIR/harness.sh" +sed -n '10597,10766p' "$SCRIPT" >> "$WORKDIR/harness.sh" printf '\n' >> "$WORKDIR/harness.sh" -sed -n '10562,10610p' "$SCRIPT" >> "$WORKDIR/harness.sh" +sed -n '12815,13534p' "$SCRIPT" >> "$WORKDIR/harness.sh" +printf '\n' >> "$WORKDIR/harness.sh" +sed -n '13781,13825p' "$SCRIPT" >> "$WORKDIR/harness.sh" printf '\n' >> "$WORKDIR/harness.sh" chmod +x "$WORKDIR/harness.sh" cat > "$WORKDIR/bin/curl" <<'EOF' #!/usr/bin/env bash +for arg in "$@"; do + if [ "$arg" = "-I" ]; then + exit 0 + fi +done if [[ "$*" == *"/models"* ]]; then cat < "$WORKDIR/bin/openclaw" <<'EOF' #!/usr/bin/env bash -if [[ "${1:-}" == "dashboard" ]]; then - echo "Dashboard: http://127.0.0.1:18789/#token=deadbeef" -else - echo "mock openclaw $*" -fi +set -euo pipefail +cmd="${1:-}" +shift || true +log_file="$HOME/.openclaw/mock_openclaw.log" +echo "openclaw $cmd $*" >> "$log_file" +case "$cmd" in + dashboard) + echo "Dashboard: http://127.0.0.1:18789/#token=deadbeef" + ;; + config) + sub="${1:-}" + shift || true + config_file="$HOME/.openclaw/mock_config.env" + touch "$config_file" + case "$sub" in + set) + key="$1" + shift || true + value="$*" + grep -v "^${key}=" "$config_file" > "${config_file}.tmp" || true + echo "${key}=${value}" >> "${config_file}.tmp" + mv "${config_file}.tmp" "$config_file" + ;; + get) + key="$1" + if grep -q "^${key}=" "$config_file"; then + awk -F'=' -v k="$key" '$1==k {print substr($0, index($0, "=")+1); exit}' "$config_file" + fi + ;; + unset) + key="$1" + grep -v "^${key}=" "$config_file" > "${config_file}.tmp" || true + mv "${config_file}.tmp" "$config_file" + ;; + *) + echo "mock openclaw config $sub $*" + ;; + esac + ;; + memory) + sub="${1:-}" + shift || true + case "$sub" in + status) + echo "Provider: builtin" + echo "Vector: ok" + echo "Indexed: 0/0" + echo "Workspace: $HOME/.openclaw/workspace" + ;; + index) + echo "mock memory index $*" + ;; + *) + echo "mock openclaw memory $sub $*" + ;; + esac + ;; + gateway) + sub="${1:-}" + shift || true + if [ "$sub" = "restart" ]; then + echo "mock gateway restart" + else + echo "mock openclaw gateway $sub $*" + fi + ;; + *) + echo "mock openclaw $cmd $*" + ;; +esac EOF chmod +x "$WORKDIR/bin/openclaw" @@ -69,4 +144,20 @@ openclaw_find_webui_domain echo '[TEST] openclaw_show_webui_addr' openclaw_show_webui_addr +echo '[TEST] openclaw_memory_auto_setup_run local' +mkdir -p "$HOME/.openclaw/models/embedding" +touch "$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" +echo "memory.local=legacy" > "$HOME/.openclaw/mock_config.env" +printf "yes\n" | openclaw_memory_auto_setup_run "local" >/tmp/memory-auto.out + +grep -q '^memory.backend=builtin' "$HOME/.openclaw/mock_config.env" +grep -q '^agents.defaults.memorySearch.provider=local' "$HOME/.openclaw/mock_config.env" +if grep -q '^memory.local=' "$HOME/.openclaw/mock_config.env"; then + echo "memory.local should be removed" + exit 1 +fi + +grep -q 'openclaw memory index --force' "$HOME/.openclaw/mock_openclaw.log" +grep -q 'openclaw gateway restart' "$HOME/.openclaw/mock_openclaw.log" + echo 'SMOKE_OK' From 430fc6f43b92c0e2d0e017e7e2b80195ee04d3bd Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 12 Mar 2026 15:16:54 +0800 Subject: [PATCH 0992/1285] feat: auto-restart gateway after memory rebuild --- cn/kejilion.sh | 4 ++++ cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh | 11 +++++++++++ kejilion.sh | 4 ++++ tests/openclaw/tests_openclaw_memory_menu_smoke.sh | 11 +++++++++++ 4 files changed, 30 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 90de92e4f..e5085905c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12880,6 +12880,8 @@ EOF fi fi openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" echo "" openclaw_memory_render_status } @@ -13678,6 +13680,8 @@ EOF openclaw_memory_rebuild_index_safe else openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" fi else openclaw memory index diff --git a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 1f6240b51..3a555d93c 100755 --- a/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/cn/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -69,6 +69,7 @@ if [[ "$cmd" == "memory index"* ]]; then exit 0 fi if [[ "$cmd" == "gateway restart" ]]; then + echo "$cmd" >> "${HOME}/.openclaw/gateway_calls" echo "gateway restarted" exit 0 fi @@ -194,10 +195,20 @@ with open(calls_path, 'r', encoding='utf-8') as fh: calls = fh.read() if 'memory index --force' not in calls: raise SystemExit('force index not called for missing store') +# ensure gateway restart called after rebuild +gw_calls_path = os.path.expanduser('~/.openclaw/gateway_calls') +if not os.path.exists(gw_calls_path): + raise SystemExit('gateway restart not recorded') +with open(gw_calls_path, 'r', encoding='utf-8') as fh: + gw_calls = fh.read() +if 'gateway restart' not in gw_calls: + raise SystemExit('gateway restart not called after rebuild') # ensure warning emitted with open(os.path.join(os.environ['WORKDIR'], 'out_missing.txt'), 'r', encoding='utf-8') as fh: out = fh.read() if 'Store 原始值' not in out: raise SystemExit('missing store warning not found') +if '索引已重建并自动重启网关' not in out: + raise SystemExit('auto restart message not found') print('SMOKE_OK') PY diff --git a/kejilion.sh b/kejilion.sh index 90de92e4f..e5085905c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12880,6 +12880,8 @@ EOF fi fi openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" echo "" openclaw_memory_render_status } @@ -13678,6 +13680,8 @@ EOF openclaw_memory_rebuild_index_safe else openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" fi else openclaw memory index diff --git a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 1f6240b51..3a555d93c 100755 --- a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -69,6 +69,7 @@ if [[ "$cmd" == "memory index"* ]]; then exit 0 fi if [[ "$cmd" == "gateway restart" ]]; then + echo "$cmd" >> "${HOME}/.openclaw/gateway_calls" echo "gateway restarted" exit 0 fi @@ -194,10 +195,20 @@ with open(calls_path, 'r', encoding='utf-8') as fh: calls = fh.read() if 'memory index --force' not in calls: raise SystemExit('force index not called for missing store') +# ensure gateway restart called after rebuild +gw_calls_path = os.path.expanduser('~/.openclaw/gateway_calls') +if not os.path.exists(gw_calls_path): + raise SystemExit('gateway restart not recorded') +with open(gw_calls_path, 'r', encoding='utf-8') as fh: + gw_calls = fh.read() +if 'gateway restart' not in gw_calls: + raise SystemExit('gateway restart not called after rebuild') # ensure warning emitted with open(os.path.join(os.environ['WORKDIR'], 'out_missing.txt'), 'r', encoding='utf-8') as fh: out = fh.read() if 'Store 原始值' not in out: raise SystemExit('missing store warning not found') +if '索引已重建并自动重启网关' not in out: + raise SystemExit('auto restart message not found') print('SMOKE_OK') PY From 90414c8f8fe3e30dc6f80ff13a8fd2319f9c7bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:16:32 +0800 Subject: [PATCH 0993/1285] Update git config to use HTTPS for GitHub --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e5085905c..844013a04 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13747,6 +13747,8 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway From 226c873a1ae8e7f24f57d6c03e498ceebf872a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:17:41 +0800 Subject: [PATCH 0994/1285] Configure Git to use HTTPS instead of SSH --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index e5085905c..844013a04 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13747,6 +13747,8 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway From 3bccf2a3cf28dd7f0b257c785112f39ed4175f3b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 12:30:03 +0800 Subject: [PATCH 0995/1285] feat: change_model use gum filter with searchable configured models --- cn/kejilion.sh | 99 ++++++++++++++++++++++++++++++++++++++------------ kejilion.sh | 99 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 150 insertions(+), 48 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 844013a04..a7071b8fd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11577,39 +11577,90 @@ PY change_model() { send_stats "换模型" + # 仅展示已配置/可用的模型(Auth=yes),并用 gum 交互式选择 + # 需要 gum;若未安装则降级为手动输入 + local orange="#FF8C00" + while true; do - clear - echo "--- 模型管理 ---" - echo "所有模型:" - openclaw models list --all - echo "----------------" - echo "当前模型:" - openclaw models list - echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " model - - # 1. 检查是否输入 0 以退出 - if [ "$model" = "0" ]; then - echo "操作已取消,正在退出..." - break # 跳出 while 循环 + local models_raw models_list default_model model_count selected_model + models_raw=$(openclaw models list 2>/dev/null) + if [ -z "$models_raw" ]; then + echo "获取模型列表失败,请检查 openclaw 是否可用。" + break_end + return 1 fi - # 2. 验证输入是否为空 - if [ -z "$model" ]; then - echo "错误:模型名称不能为空。请重试。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + # 提取 Auth=yes 的模型名(跳过表头) + models_list=$(echo "$models_raw" | awk 'NR>1 && $5=="yes" {print $1}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # 获取默认模型(Tags 含 default) + default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + [ -z "$default_model" ] && default_model="(unknown)" + + # 若 gum 不存在,降级为手动输入(但仍只提示可用模型) + if ! command -v gum >/dev/null 2>&1; then + clear + echo "--- 模型管理 ---" + echo "可用模型(Auth=yes):${model_count}" + echo "当前默认:${default_model}" + echo "----------------" + echo "$models_list" + echo "----------------" + read -e -p "请输入要设置的模型名称(输入 0 退出): " selected_model + if [ "$selected_model" = "0" ]; then + echo "操作已取消,正在退出..." + break + fi + if [ -z "$selected_model" ]; then + echo "错误:模型名称不能为空。请重试。" + echo "" + continue + fi + else + clear + # 顶部信息(橙色) + gum style --foreground "$orange" --bold "模型管理" + gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" + gum style --foreground "$orange" "当前默认:${default_model}" + echo "" + + # 底部提示 + gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" + echo "" + + # gum filter:带搜索;默认选中当前默认模型 + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ + --prompt "选择模型 > " \ + --indicator "➜ " \ + --value "$default_model" \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 20) + + # Esc 退出时返回空 + if [ -z "$selected_model" ]; then + echo "操作已取消,正在退出..." + break + fi fi - # 3. 执行切换逻辑 - echo "正在切换模型为: $model ..." - openclaw models set "$model" + # 执行切换 + echo "正在切换模型为: $selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切换失败:openclaw models set 返回错误。" + break_end + return 1 + fi start_gateway break_end - done - + done } diff --git a/kejilion.sh b/kejilion.sh index 844013a04..a7071b8fd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11577,39 +11577,90 @@ PY change_model() { send_stats "换模型" + # 仅展示已配置/可用的模型(Auth=yes),并用 gum 交互式选择 + # 需要 gum;若未安装则降级为手动输入 + local orange="#FF8C00" + while true; do - clear - echo "--- 模型管理 ---" - echo "所有模型:" - openclaw models list --all - echo "----------------" - echo "当前模型:" - openclaw models list - echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " model - - # 1. 检查是否输入 0 以退出 - if [ "$model" = "0" ]; then - echo "操作已取消,正在退出..." - break # 跳出 while 循环 + local models_raw models_list default_model model_count selected_model + models_raw=$(openclaw models list 2>/dev/null) + if [ -z "$models_raw" ]; then + echo "获取模型列表失败,请检查 openclaw 是否可用。" + break_end + return 1 fi - # 2. 验证输入是否为空 - if [ -z "$model" ]; then - echo "错误:模型名称不能为空。请重试。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + # 提取 Auth=yes 的模型名(跳过表头) + models_list=$(echo "$models_raw" | awk 'NR>1 && $5=="yes" {print $1}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # 获取默认模型(Tags 含 default) + default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + [ -z "$default_model" ] && default_model="(unknown)" + + # 若 gum 不存在,降级为手动输入(但仍只提示可用模型) + if ! command -v gum >/dev/null 2>&1; then + clear + echo "--- 模型管理 ---" + echo "可用模型(Auth=yes):${model_count}" + echo "当前默认:${default_model}" + echo "----------------" + echo "$models_list" + echo "----------------" + read -e -p "请输入要设置的模型名称(输入 0 退出): " selected_model + if [ "$selected_model" = "0" ]; then + echo "操作已取消,正在退出..." + break + fi + if [ -z "$selected_model" ]; then + echo "错误:模型名称不能为空。请重试。" + echo "" + continue + fi + else + clear + # 顶部信息(橙色) + gum style --foreground "$orange" --bold "模型管理" + gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" + gum style --foreground "$orange" "当前默认:${default_model}" + echo "" + + # 底部提示 + gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" + echo "" + + # gum filter:带搜索;默认选中当前默认模型 + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ + --prompt "选择模型 > " \ + --indicator "➜ " \ + --value "$default_model" \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 20) + + # Esc 退出时返回空 + if [ -z "$selected_model" ]; then + echo "操作已取消,正在退出..." + break + fi fi - # 3. 执行切换逻辑 - echo "正在切换模型为: $model ..." - openclaw models set "$model" + # 执行切换 + echo "正在切换模型为: $selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切换失败:openclaw models set 返回错误。" + break_end + return 1 + fi start_gateway break_end - done - + done } From 737061ac0d6a941f42fb7d928cd43920a746959d Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 12:43:04 +0800 Subject: [PATCH 0996/1285] fix: keep change_model fallback identical to original --- cn/kejilion.sh | 21 +++++++++++++-------- kejilion.sh | 21 +++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a7071b8fd..26c45f3bc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11599,24 +11599,29 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" - # 若 gum 不存在,降级为手动输入(但仍只提示可用模型) + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then clear echo "--- 模型管理 ---" - echo "可用模型(Auth=yes):${model_count}" - echo "当前默认:${default_model}" + echo "所有模型:" + openclaw models list --all echo "----------------" - echo "$models_list" + echo "当前模型:" + openclaw models list echo "----------------" - read -e -p "请输入要设置的模型名称(输入 0 退出): " selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + + # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break + break # 跳出 while 循环 fi + + # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then echo "错误:模型名称不能为空。请重试。" - echo "" - continue + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 fi else clear diff --git a/kejilion.sh b/kejilion.sh index a7071b8fd..26c45f3bc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11599,24 +11599,29 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" - # 若 gum 不存在,降级为手动输入(但仍只提示可用模型) + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then clear echo "--- 模型管理 ---" - echo "可用模型(Auth=yes):${model_count}" - echo "当前默认:${default_model}" + echo "所有模型:" + openclaw models list --all echo "----------------" - echo "$models_list" + echo "当前模型:" + openclaw models list echo "----------------" - read -e -p "请输入要设置的模型名称(输入 0 退出): " selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + + # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break + break # 跳出 while 循环 fi + + # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then echo "错误:模型名称不能为空。请重试。" - echo "" - continue + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 fi else clear From 49346ca03d145377eb1f344dbb1dc1593a623923 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 13:11:50 +0800 Subject: [PATCH 0997/1285] fix: gum filter flags compatibility (cursor-text.foreground) --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 26c45f3bc..329d1a779 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11643,7 +11643,7 @@ PY --value "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ - --cursor.foreground "$orange" \ + --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ --height 20) diff --git a/kejilion.sh b/kejilion.sh index 26c45f3bc..329d1a779 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11643,7 +11643,7 @@ PY --value "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ - --cursor.foreground "$orange" \ + --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ --height 20) From 63bc66331e74700279d5c91cf0ca2ffe665959df Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 13:24:36 +0800 Subject: [PATCH 0998/1285] ux: gum filter show full list and increase height --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 329d1a779..c35f28d15 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11640,13 +11640,13 @@ PY --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ --prompt "选择模型 > " \ --indicator "➜ " \ - --value "$default_model" \ + --selected "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 20) + --height 35) # Esc 退出时返回空 if [ -z "$selected_model" ]; then diff --git a/kejilion.sh b/kejilion.sh index 329d1a779..c35f28d15 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11640,13 +11640,13 @@ PY --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ --prompt "选择模型 > " \ --indicator "➜ " \ - --value "$default_model" \ + --selected "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 20) + --height 35) # Esc 退出时返回空 if [ -z "$selected_model" ]; then From 27b72c726e1e9ff9434dec9a8a747cd1c19235d9 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 13:54:24 +0800 Subject: [PATCH 0999/1285] fix: gum filter compatibility and guard against Usage output --- cn/kejilion.sh | 9 ++++----- kejilion.sh | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c35f28d15..d493bf800 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11635,21 +11635,20 @@ PY gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" echo "" - # gum filter:带搜索;默认选中当前默认模型 + # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags selected_model=$(echo "$models_list" | gum filter \ --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ --prompt "选择模型 > " \ --indicator "➜ " \ - --selected "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35) + --height 35 2>/dev/null) - # Esc 退出时返回空 - if [ -z "$selected_model" ]; then + # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then echo "操作已取消,正在退出..." break fi diff --git a/kejilion.sh b/kejilion.sh index c35f28d15..d493bf800 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11635,21 +11635,20 @@ PY gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" echo "" - # gum filter:带搜索;默认选中当前默认模型 + # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags selected_model=$(echo "$models_list" | gum filter \ --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ --prompt "选择模型 > " \ --indicator "➜ " \ - --selected "$default_model" \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35) + --height 35 2>/dev/null) - # Esc 退出时返回空 - if [ -z "$selected_model" ]; then + # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then echo "操作已取消,正在退出..." break fi From 76ccd7c3f18eb190d0c905a9b9fd0eb749e84fc6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 14:01:03 +0800 Subject: [PATCH 1000/1285] fix: don't silence gum filter stderr --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d493bf800..e6a3d7c67 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11645,7 +11645,7 @@ PY --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35 2>/dev/null) + --height 35) # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then diff --git a/kejilion.sh b/kejilion.sh index d493bf800..e6a3d7c67 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11645,7 +11645,7 @@ PY --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35 2>/dev/null) + --height 35) # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then From 65cc5f93ba512299763301ad9949e4beb1704a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:13:21 +0800 Subject: [PATCH 1001/1285] Add installation of gum in kejilion.sh Install gum if it is not already installed. --- cn/kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e6a3d7c67..975d77b95 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11599,6 +11599,8 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" + install gum + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then clear From fdbb254557de919fd2fc8eb3878063d05ca1b3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:14:33 +0800 Subject: [PATCH 1002/1285] Install gum if not already present Add installation command for gum before fallback logic. --- kejilion.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index e6a3d7c67..975d77b95 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11599,6 +11599,8 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" + install gum + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then clear From 1999473ed390ca7f2f8e79743ae5a029e15a13b3 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 13 Mar 2026 15:12:22 +0800 Subject: [PATCH 1003/1285] docs: update changelog for gum-based model selector --- kejilion_sh_log.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 92773e7fa..e25ea68c9 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1488,4 +1488,8 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 应用市场中OpenClaw管理,新增记忆管理控制台,支持索引状态、索引更新、文件查看、方案切换与重复索引修复。 应用市场中OpenClaw管理,API新增自动探测并优先使用/v1/responses协议,避免legacy /v1/chat/completions报错。 应用市场中OpenClaw管理,API模型同步一致性输出增强,逐行显示新增/删除模型名称。 +------------------------ +2026-03-13 v4.4.7 +OpenClaw模型管理新增gum交互式换模型(可搜索/橙色主题/显示可用模型数与当前默认)。 +未安装gum时保持原手动输入流程;并增加兼容性保护避免gum报错文本误写入默认模型。 From 21b287e40d9d66dc42ffa9eab9098be96fdea587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:15:20 +0800 Subject: [PATCH 1004/1285] Update gum model interaction and compatibility handling Ensure compatibility protection to avoid errors when gum is not installed. --- kejilion_sh_log.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index e25ea68c9..b3e4dda4b 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1491,5 +1491,4 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 ------------------------ 2026-03-13 v4.4.7 OpenClaw模型管理新增gum交互式换模型(可搜索/橙色主题/显示可用模型数与当前默认)。 -未安装gum时保持原手动输入流程;并增加兼容性保护避免gum报错文本误写入默认模型。 From fcda60abaebbfed8b243654b3c33f0a3209391ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:16:04 +0800 Subject: [PATCH 1005/1285] Update shell version from 4.4.6 to 4.4.7 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 975d77b95..6341115ba 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.6" +sh_v="4.4.7" gl_hui='\e[37m' From 5ef7702fa13c4182f8ce942d2ada8d8a3b2c48e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:16:42 +0800 Subject: [PATCH 1006/1285] Update shell version from 4.4.6 to 4.4.7 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 975d77b95..6341115ba 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.6" +sh_v="4.4.7" gl_hui='\e[37m' From 39c3f43043b52a9bac300bc8fa08ca85a6fbdbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 22:54:28 +0800 Subject: [PATCH 1007/1285] Implement gum installation function for Debian Added function to install 'gum' if not already installed, specifically for Debian-based systems. --- cn/kejilion.sh | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6341115ba..dbcd339d0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -11574,6 +11574,22 @@ PY } + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi + } + + + change_model() { send_stats "换模型" @@ -11599,6 +11615,8 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" + + install_gum install gum # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) From 4cbe6cd31348cfcaa477f76713a06a8f20be2bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 22:55:12 +0800 Subject: [PATCH 1008/1285] Add gum installation function to kejilion.sh --- kejilion.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 6341115ba..fb907636a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11574,6 +11574,22 @@ PY } + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi + } + + + change_model() { send_stats "换模型" @@ -11599,6 +11615,8 @@ PY default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" + + install_gum install gum # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) From 46c2a9f9799d002fa437dea63bb418b5392f26a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 23:51:35 +0800 Subject: [PATCH 1009/1285] Update print statement from 'Hello' to 'Goodbye' --- cn/kejilion.sh | 1272 ++++++++++++++++++++++++------------------------ 1 file changed, 636 insertions(+), 636 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dbcd339d0..d31641670 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10096,24 +10096,24 @@ moltbot_menu() { import json, sys path = sys.argv[1] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) session = obj.setdefault('session', {}) session['dmScope'] = session.get('dmScope', 'per-channel-peer') session['resetTriggers'] = ['/new', '/reset'] session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 + 'mode': 'idle', + 'idleMinutes': 10080 } session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} } with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') PY } @@ -10140,77 +10140,77 @@ stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): - if not stats_enabled: - return - payload = { - "action": action, - "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - "country": "", - "os_info": platform.platform(), - "cpu_arch": platform.machine(), - "version": script_version, - } - try: - req = urllib.request.Request( - "https://api.kejilion.pro/api/log", - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"}, - method="POST", - ) - with urllib.request.urlopen(req, timeout=3): - pass - except Exception: - pass + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') - raise SystemExit(0) + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models SUPPORTED_APIS = {'openai-completions', 'openai-responses'} @@ -10221,320 +10221,320 @@ summary = [] def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " - try: - ans = input(prompt).strip().lower() - except EOFError: - return False - return ans in ('y', 'yes') + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') def rebind_defaults_before_delete(name): - global changed - - replacement = None - - def get_replacement(): - nonlocal replacement - if replacement is None: - candidates = collect_available_refs(exclude_provider=name) - replacement = candidates[0] if candidates else None - return replacement - - primary_ref = get_primary_ref(defaults) - if ref_provider(primary_ref) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') - return False - set_primary_ref(defaults, repl) - changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') - return False - defaults[fk] = repl - changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') - - return True + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True def delete_provider_and_refs(name): - global changed + global changed - if not rebind_defaults_before_delete(name): - return False + if not rebind_defaults_before_delete(name): + return False - removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] - for r in removed_refs: - defaults_models.pop(r, None) - if removed_refs: - changed = True + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True - if name in providers: - providers.pop(name, None) - changed = True + if name in providers: + providers.pop(name, None) + changed = True - summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') - return True + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - data = json.loads(payload) - return data, None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries for name, provider in list(providers.items()): - if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') - continue - - api = provider.get('api', '') - base_url = provider.get('baseUrl') - api_key = provider.get('apiKey') - model_list = provider.get('models', []) - - if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') - continue - - if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') - provider['api'] = '' - api = '' - changed = True - - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) - if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') - if prompt_delete_provider(name): - deleted = delete_provider_and_refs(name) - if deleted: - send_stat('OpenClaw API删失败Provider-确认') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') - else: - send_stat('OpenClaw API删失败Provider-拒绝') - summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') - continue - - if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') - - if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') - continue - - remote_ids = [] - for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) - remote_set = set(remote_ids) - - if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') - continue - - local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] - local_ids = [str(m['id']) for m in local_models] - local_set = set(local_ids) - - template = None - for m in local_models: - template = copy.deepcopy(m) - break - if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') - continue - - removed_ids = [mid for mid in local_ids if mid not in remote_set] - added_ids = [mid for mid in remote_ids if mid not in local_set] - - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] - new_models = kept_models[:] - - for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{name} / {mid}' - new_models.append(nm) - - if not new_models: - fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') - continue - - expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} - local_refs = {model_ref(name, mid) for mid in local_ids} - - first_ref = model_ref(name, str(new_models[0]['id'])) - - primary_ref = get_primary_ref(defaults) - if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): - set_primary_ref(defaults, first_ref) - changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in (local_refs - expected_refs): - defaults[fk] = first_ref - changed = True - summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') - - stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] - for r in stale_refs: - defaults_models.pop(r, None) - changed = True - - for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True - - if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True - - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API删失败Provider-确认') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + send_stat('OpenClaw API删失败Provider-拒绝') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if fatal_errors: - for line in summary: - print(line) - for err in fatal_errors: - print(err) - print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') - raise SystemExit(2) + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') - for line in summary: - print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: - for line in summary: - print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -10901,88 +10901,88 @@ SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) print('MSG\t--- 已配置 API 列表 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - api_label = api if api in SUPPORTED_APIS else '-' - print( - 'ROW\t' + '\t'.join([ - str(idx), - str(name), - str(base_url), - str(model_count), - str(api_label), - str(latency_text), - str(latency_level), - ]) - ) + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) PY ) } @@ -11017,105 +11017,105 @@ target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') - raise SystemExit(2) + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def fetch_remote_models_with_retry(base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - return json.loads(payload), None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries api = provider.get('api', '') @@ -11124,41 +11124,41 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') - raise SystemExit(3) + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - raise SystemExit(4) + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') - raise SystemExit(4) + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) remote_ids = [] for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') - raise SystemExit(5) + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] local_ids = [str(m['id']) for m in local_models] @@ -11166,33 +11166,33 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') - raise SystemExit(3) + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{target} / {mid}' - new_models.append(nm) + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') - raise SystemExit(5) + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} local_refs = {model_ref(target, mid) for mid in local_ids} @@ -11202,44 +11202,44 @@ first_ref = model_ref(target, str(new_models[0]['id'])) changed = False primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: - set_primary_ref(defaults, first_ref) - changed = True - print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in removed_refs: - defaults[fk] = first_ref - changed = True - print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: - defaults_models.pop(r, None) - changed = True + defaults_models.pop(r, None) + changed = True for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True + if r not in defaults_models: + defaults_models[r] = {} + changed = True if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True + provider['models'] = new_models + changed = True if protocol_msg: - print(protocol_msg) + print(protocol_msg) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in @@ -11281,66 +11281,66 @@ name = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) + print('❌ 未找到 openclaw.json') + raise SystemExit(2) providers = ((obj.get('models') or {}).get('providers') or {}) provider = providers.get(name) if isinstance(providers, dict) else None if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) base_url = provider.get('baseUrl') api_key = provider.get('apiKey') if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) current_api = provider.get('api', '') if current_api not in SUPPORTED_APIS: - current_api = '' + current_api = '' api, reason, err = detect_api_protocol(base_url, api_key) if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') PY } @@ -11410,71 +11410,71 @@ path = sys.argv[1] name = sys.argv[2] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs replacement_candidates = collect_available_refs(exclude_provider=name) @@ -11482,30 +11482,30 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: - if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') - raise SystemExit(3) - set_primary_ref(defaults, replacement) - print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - if not replacement: - print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') - raise SystemExit(3) - defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: - defaults_models.pop(r, None) + defaults_models.pop(r, None) providers.pop(name, None) with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'🗑️ 已删除 provider: {name}') print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') @@ -11576,16 +11576,16 @@ PY install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - - fi + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi } @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,8 @@ PY --header "" \ --height 35) - # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum)'; then echo "操作已取消,正在退出..." break fi @@ -11740,22 +11740,22 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] if plugin_id not in a: - a.append(plugin_id) + a.append(plugin_id) plugins['allow'] = a data['plugins'] = plugins @@ -11811,19 +11811,19 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] a = [x for x in a if x != plugin_id] plugins['allow'] = a From f9564162a1cfaf2ae02cbf9f552c0c20018d7035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 13 Mar 2026 23:52:13 +0800 Subject: [PATCH 1010/1285] Update greeting from 'Hello World' to 'Goodbye World' --- kejilion.sh | 1272 +++++++++++++++++++++++++-------------------------- 1 file changed, 636 insertions(+), 636 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fb907636a..0d0429001 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10096,24 +10096,24 @@ moltbot_menu() { import json, sys path = sys.argv[1] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) session = obj.setdefault('session', {}) session['dmScope'] = session.get('dmScope', 'per-channel-peer') session['resetTriggers'] = ['/new', '/reset'] session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 + 'mode': 'idle', + 'idleMinutes': 10080 } session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} } with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') PY } @@ -10140,77 +10140,77 @@ stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): - if not stats_enabled: - return - payload = { - "action": action, - "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - "country": "", - "os_info": platform.platform(), - "cpu_arch": platform.machine(), - "version": script_version, - } - try: - req = urllib.request.Request( - "https://api.kejilion.pro/api/log", - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"}, - method="POST", - ) - with urllib.request.urlopen(req, timeout=3): - pass - except Exception: - pass + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') - raise SystemExit(0) + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models SUPPORTED_APIS = {'openai-completions', 'openai-responses'} @@ -10221,320 +10221,320 @@ summary = [] def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " - try: - ans = input(prompt).strip().lower() - except EOFError: - return False - return ans in ('y', 'yes') + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') def rebind_defaults_before_delete(name): - global changed - - replacement = None - - def get_replacement(): - nonlocal replacement - if replacement is None: - candidates = collect_available_refs(exclude_provider=name) - replacement = candidates[0] if candidates else None - return replacement - - primary_ref = get_primary_ref(defaults) - if ref_provider(primary_ref) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') - return False - set_primary_ref(defaults, repl) - changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') - return False - defaults[fk] = repl - changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') - - return True + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True def delete_provider_and_refs(name): - global changed + global changed - if not rebind_defaults_before_delete(name): - return False + if not rebind_defaults_before_delete(name): + return False - removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] - for r in removed_refs: - defaults_models.pop(r, None) - if removed_refs: - changed = True + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True - if name in providers: - providers.pop(name, None) - changed = True + if name in providers: + providers.pop(name, None) + changed = True - summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') - return True + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - data = json.loads(payload) - return data, None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries for name, provider in list(providers.items()): - if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') - continue - - api = provider.get('api', '') - base_url = provider.get('baseUrl') - api_key = provider.get('apiKey') - model_list = provider.get('models', []) - - if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') - continue - - if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') - provider['api'] = '' - api = '' - changed = True - - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) - if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') - if prompt_delete_provider(name): - deleted = delete_provider_and_refs(name) - if deleted: - send_stat('OpenClaw API删失败Provider-确认') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') - else: - send_stat('OpenClaw API删失败Provider-拒绝') - summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') - continue - - if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') - - if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') - continue - - remote_ids = [] - for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) - remote_set = set(remote_ids) - - if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') - continue - - local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] - local_ids = [str(m['id']) for m in local_models] - local_set = set(local_ids) - - template = None - for m in local_models: - template = copy.deepcopy(m) - break - if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') - continue - - removed_ids = [mid for mid in local_ids if mid not in remote_set] - added_ids = [mid for mid in remote_ids if mid not in local_set] - - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] - new_models = kept_models[:] - - for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{name} / {mid}' - new_models.append(nm) - - if not new_models: - fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') - continue - - expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} - local_refs = {model_ref(name, mid) for mid in local_ids} - - first_ref = model_ref(name, str(new_models[0]['id'])) - - primary_ref = get_primary_ref(defaults) - if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): - set_primary_ref(defaults, first_ref) - changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in (local_refs - expected_refs): - defaults[fk] = first_ref - changed = True - summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') - - stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] - for r in stale_refs: - defaults_models.pop(r, None) - changed = True - - for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True - - if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True - - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API删失败Provider-确认') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + send_stat('OpenClaw API删失败Provider-拒绝') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if fatal_errors: - for line in summary: - print(line) - for err in fatal_errors: - print(err) - print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') - raise SystemExit(2) + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') - for line in summary: - print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: - for line in summary: - print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -10901,88 +10901,88 @@ SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) print('MSG\t--- 已配置 API 列表 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - api_label = api if api in SUPPORTED_APIS else '-' - print( - 'ROW\t' + '\t'.join([ - str(idx), - str(name), - str(base_url), - str(model_count), - str(api_label), - str(latency_text), - str(latency_level), - ]) - ) + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) PY ) } @@ -11017,105 +11017,105 @@ target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') - raise SystemExit(2) + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def fetch_remote_models_with_retry(base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - return json.loads(payload), None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries api = provider.get('api', '') @@ -11124,41 +11124,41 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') - raise SystemExit(3) + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - raise SystemExit(4) + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') - raise SystemExit(4) + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) remote_ids = [] for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') - raise SystemExit(5) + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] local_ids = [str(m['id']) for m in local_models] @@ -11166,33 +11166,33 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') - raise SystemExit(3) + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{target} / {mid}' - new_models.append(nm) + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') - raise SystemExit(5) + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} local_refs = {model_ref(target, mid) for mid in local_ids} @@ -11202,44 +11202,44 @@ first_ref = model_ref(target, str(new_models[0]['id'])) changed = False primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: - set_primary_ref(defaults, first_ref) - changed = True - print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in removed_refs: - defaults[fk] = first_ref - changed = True - print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: - defaults_models.pop(r, None) - changed = True + defaults_models.pop(r, None) + changed = True for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True + if r not in defaults_models: + defaults_models[r] = {} + changed = True if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True + provider['models'] = new_models + changed = True if protocol_msg: - print(protocol_msg) + print(protocol_msg) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in @@ -11281,66 +11281,66 @@ name = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) + print('❌ 未找到 openclaw.json') + raise SystemExit(2) providers = ((obj.get('models') or {}).get('providers') or {}) provider = providers.get(name) if isinstance(providers, dict) else None if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) base_url = provider.get('baseUrl') api_key = provider.get('apiKey') if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) current_api = provider.get('api', '') if current_api not in SUPPORTED_APIS: - current_api = '' + current_api = '' api, reason, err = detect_api_protocol(base_url, api_key) if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') PY } @@ -11410,71 +11410,71 @@ path = sys.argv[1] name = sys.argv[2] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs replacement_candidates = collect_available_refs(exclude_provider=name) @@ -11482,30 +11482,30 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: - if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') - raise SystemExit(3) - set_primary_ref(defaults, replacement) - print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - if not replacement: - print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') - raise SystemExit(3) - defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: - defaults_models.pop(r, None) + defaults_models.pop(r, None) providers.pop(name, None) with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'🗑️ 已删除 provider: {name}') print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') @@ -11576,16 +11576,16 @@ PY install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - - fi + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi } @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,8 @@ PY --header "" \ --height 35) - # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum)'; then echo "操作已取消,正在退出..." break fi @@ -11740,22 +11740,22 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] if plugin_id not in a: - a.append(plugin_id) + a.append(plugin_id) plugins['allow'] = a data['plugins'] = plugins @@ -11811,19 +11811,19 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] a = [x for x in a if x != plugin_id] plugins['allow'] = a From 58af8ef3ed353f86da44e945a1c015d72576bad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 00:10:55 +0800 Subject: [PATCH 1011/1285] Update kejilion.sh --- cn/kejilion.sh | 1272 ++++++++++++++++++++++++------------------------ 1 file changed, 636 insertions(+), 636 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d31641670..dbcd339d0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10096,24 +10096,24 @@ moltbot_menu() { import json, sys path = sys.argv[1] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) session = obj.setdefault('session', {}) session['dmScope'] = session.get('dmScope', 'per-channel-peer') session['resetTriggers'] = ['/new', '/reset'] session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 + 'mode': 'idle', + 'idleMinutes': 10080 } session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} } with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') PY } @@ -10140,77 +10140,77 @@ stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): - if not stats_enabled: - return - payload = { - "action": action, - "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - "country": "", - "os_info": platform.platform(), - "cpu_arch": platform.machine(), - "version": script_version, - } - try: - req = urllib.request.Request( - "https://api.kejilion.pro/api/log", - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"}, - method="POST", - ) - with urllib.request.urlopen(req, timeout=3): - pass - except Exception: - pass + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') - raise SystemExit(0) + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models SUPPORTED_APIS = {'openai-completions', 'openai-responses'} @@ -10221,320 +10221,320 @@ summary = [] def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " - try: - ans = input(prompt).strip().lower() - except EOFError: - return False - return ans in ('y', 'yes') + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') def rebind_defaults_before_delete(name): - global changed - - replacement = None - - def get_replacement(): - nonlocal replacement - if replacement is None: - candidates = collect_available_refs(exclude_provider=name) - replacement = candidates[0] if candidates else None - return replacement - - primary_ref = get_primary_ref(defaults) - if ref_provider(primary_ref) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') - return False - set_primary_ref(defaults, repl) - changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') - return False - defaults[fk] = repl - changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') - - return True + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True def delete_provider_and_refs(name): - global changed + global changed - if not rebind_defaults_before_delete(name): - return False + if not rebind_defaults_before_delete(name): + return False - removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] - for r in removed_refs: - defaults_models.pop(r, None) - if removed_refs: - changed = True + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True - if name in providers: - providers.pop(name, None) - changed = True + if name in providers: + providers.pop(name, None) + changed = True - summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') - return True + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - data = json.loads(payload) - return data, None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries for name, provider in list(providers.items()): - if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') - continue - - api = provider.get('api', '') - base_url = provider.get('baseUrl') - api_key = provider.get('apiKey') - model_list = provider.get('models', []) - - if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') - continue - - if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') - provider['api'] = '' - api = '' - changed = True - - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) - if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') - if prompt_delete_provider(name): - deleted = delete_provider_and_refs(name) - if deleted: - send_stat('OpenClaw API删失败Provider-确认') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') - else: - send_stat('OpenClaw API删失败Provider-拒绝') - summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') - continue - - if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') - - if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') - continue - - remote_ids = [] - for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) - remote_set = set(remote_ids) - - if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') - continue - - local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] - local_ids = [str(m['id']) for m in local_models] - local_set = set(local_ids) - - template = None - for m in local_models: - template = copy.deepcopy(m) - break - if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') - continue - - removed_ids = [mid for mid in local_ids if mid not in remote_set] - added_ids = [mid for mid in remote_ids if mid not in local_set] - - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] - new_models = kept_models[:] - - for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{name} / {mid}' - new_models.append(nm) - - if not new_models: - fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') - continue - - expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} - local_refs = {model_ref(name, mid) for mid in local_ids} - - first_ref = model_ref(name, str(new_models[0]['id'])) - - primary_ref = get_primary_ref(defaults) - if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): - set_primary_ref(defaults, first_ref) - changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in (local_refs - expected_refs): - defaults[fk] = first_ref - changed = True - summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') - - stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] - for r in stale_refs: - defaults_models.pop(r, None) - changed = True - - for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True - - if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True - - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API删失败Provider-确认') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + send_stat('OpenClaw API删失败Provider-拒绝') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if fatal_errors: - for line in summary: - print(line) - for err in fatal_errors: - print(err) - print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') - raise SystemExit(2) + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') - for line in summary: - print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: - for line in summary: - print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -10901,88 +10901,88 @@ SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) print('MSG\t--- 已配置 API 列表 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - api_label = api if api in SUPPORTED_APIS else '-' - print( - 'ROW\t' + '\t'.join([ - str(idx), - str(name), - str(base_url), - str(model_count), - str(api_label), - str(latency_text), - str(latency_level), - ]) - ) + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) PY ) } @@ -11017,105 +11017,105 @@ target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') - raise SystemExit(2) + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def fetch_remote_models_with_retry(base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - return json.loads(payload), None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries api = provider.get('api', '') @@ -11124,41 +11124,41 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') - raise SystemExit(3) + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - raise SystemExit(4) + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') - raise SystemExit(4) + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) remote_ids = [] for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') - raise SystemExit(5) + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] local_ids = [str(m['id']) for m in local_models] @@ -11166,33 +11166,33 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') - raise SystemExit(3) + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{target} / {mid}' - new_models.append(nm) + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') - raise SystemExit(5) + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} local_refs = {model_ref(target, mid) for mid in local_ids} @@ -11202,44 +11202,44 @@ first_ref = model_ref(target, str(new_models[0]['id'])) changed = False primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: - set_primary_ref(defaults, first_ref) - changed = True - print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in removed_refs: - defaults[fk] = first_ref - changed = True - print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: - defaults_models.pop(r, None) - changed = True + defaults_models.pop(r, None) + changed = True for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True + if r not in defaults_models: + defaults_models[r] = {} + changed = True if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True + provider['models'] = new_models + changed = True if protocol_msg: - print(protocol_msg) + print(protocol_msg) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in @@ -11281,66 +11281,66 @@ name = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) + print('❌ 未找到 openclaw.json') + raise SystemExit(2) providers = ((obj.get('models') or {}).get('providers') or {}) provider = providers.get(name) if isinstance(providers, dict) else None if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) base_url = provider.get('baseUrl') api_key = provider.get('apiKey') if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) current_api = provider.get('api', '') if current_api not in SUPPORTED_APIS: - current_api = '' + current_api = '' api, reason, err = detect_api_protocol(base_url, api_key) if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') PY } @@ -11410,71 +11410,71 @@ path = sys.argv[1] name = sys.argv[2] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs replacement_candidates = collect_available_refs(exclude_provider=name) @@ -11482,30 +11482,30 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: - if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') - raise SystemExit(3) - set_primary_ref(defaults, replacement) - print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - if not replacement: - print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') - raise SystemExit(3) - defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: - defaults_models.pop(r, None) + defaults_models.pop(r, None) providers.pop(name, None) with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'🗑️ 已删除 provider: {name}') print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') @@ -11576,16 +11576,16 @@ PY install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - - fi + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi } @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + models_raw=$(openclaw models list 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,8 @@ PY --header "" \ --height 35) - - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum)'; then + # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then echo "操作已取消,正在退出..." break fi @@ -11740,22 +11740,22 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] if plugin_id not in a: - a.append(plugin_id) + a.append(plugin_id) plugins['allow'] = a data['plugins'] = plugins @@ -11811,19 +11811,19 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] a = [x for x in a if x != plugin_id] plugins['allow'] = a From 5a7114c610a380dddea6959dbbb4a8accb22104c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:05:46 +0800 Subject: [PATCH 1012/1285] Update print statement from 'Hello' to 'Goodbye' --- kejilion.sh | 1272 +++++++++++++++++++++++++-------------------------- 1 file changed, 636 insertions(+), 636 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0d0429001..fb907636a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10096,24 +10096,24 @@ moltbot_menu() { import json, sys path = sys.argv[1] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) session = obj.setdefault('session', {}) session['dmScope'] = session.get('dmScope', 'per-channel-peer') session['resetTriggers'] = ['/new', '/reset'] session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 + 'mode': 'idle', + 'idleMinutes': 10080 } session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} } with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') PY } @@ -10140,77 +10140,77 @@ stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def send_stat(action): - if not stats_enabled: - return - payload = { - "action": action, - "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - "country": "", - "os_info": platform.platform(), - "cpu_arch": platform.machine(), - "version": script_version, - } - try: - req = urllib.request.Request( - "https://api.kejilion.pro/api/log", - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"}, - method="POST", - ) - with urllib.request.urlopen(req, timeout=3): - pass - except Exception: - pass + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') - raise SystemExit(0) + print('ℹ️ 未检测到 API providers,跳过模型同步') + raise SystemExit(0) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models SUPPORTED_APIS = {'openai-completions', 'openai-responses'} @@ -10221,320 +10221,320 @@ summary = [] def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " - try: - ans = input(prompt).strip().lower() - except EOFError: - return False - return ans in ('y', 'yes') + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') def rebind_defaults_before_delete(name): - global changed - - replacement = None - - def get_replacement(): - nonlocal replacement - if replacement is None: - candidates = collect_available_refs(exclude_provider=name) - replacement = candidates[0] if candidates else None - return replacement - - primary_ref = get_primary_ref(defaults) - if ref_provider(primary_ref) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') - return False - set_primary_ref(defaults, repl) - changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - repl = get_replacement() - if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') - return False - defaults[fk] = repl - changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') - - return True + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + + return True def delete_provider_and_refs(name): - global changed + global changed - if not rebind_defaults_before_delete(name): - return False + if not rebind_defaults_before_delete(name): + return False - removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] - for r in removed_refs: - defaults_models.pop(r, None) - if removed_refs: - changed = True + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True - if name in providers: - providers.pop(name, None) - changed = True + if name in providers: + providers.pop(name, None) + changed = True - summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') - return True + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + return True def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - data = json.loads(payload) - return data, None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries for name, provider in list(providers.items()): - if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') - continue - - api = provider.get('api', '') - base_url = provider.get('baseUrl') - api_key = provider.get('apiKey') - model_list = provider.get('models', []) - - if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') - continue - - if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') - provider['api'] = '' - api = '' - changed = True - - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) - if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') - if prompt_delete_provider(name): - deleted = delete_provider_and_refs(name) - if deleted: - send_stat('OpenClaw API删失败Provider-确认') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') - else: - send_stat('OpenClaw API删失败Provider-拒绝') - summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') - continue - - if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') - - if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') - continue - - remote_ids = [] - for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) - remote_set = set(remote_ids) - - if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') - continue - - local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] - local_ids = [str(m['id']) for m in local_models] - local_set = set(local_ids) - - template = None - for m in local_models: - template = copy.deepcopy(m) - break - if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') - continue - - removed_ids = [mid for mid in local_ids if mid not in remote_set] - added_ids = [mid for mid in remote_ids if mid not in local_set] - - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] - new_models = kept_models[:] - - for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{name} / {mid}' - new_models.append(nm) - - if not new_models: - fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') - continue - - expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} - local_refs = {model_ref(name, mid) for mid in local_ids} - - first_ref = model_ref(name, str(new_models[0]['id'])) - - primary_ref = get_primary_ref(defaults) - if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): - set_primary_ref(defaults, first_ref) - changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') - - for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in (local_refs - expected_refs): - defaults[fk] = first_ref - changed = True - summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') - - stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] - for r in stale_refs: - defaults_models.pop(r, None) - changed = True - - for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True - - if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True - - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API删失败Provider-确认') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + else: + send_stat('OpenClaw API删失败Provider-拒绝') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if fatal_errors: - for line in summary: - print(line) - for err in fatal_errors: - print(err) - print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') - raise SystemExit(2) + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + raise SystemExit(2) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') - for line in summary: - print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: - for line in summary: - print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + for line in summary: + print(line) + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -10901,88 +10901,88 @@ SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def ping_models(base_url, api_key): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - ) - start = time.perf_counter() - with urllib.request.urlopen(req, timeout=4) as resp: - resp.read(2048) - return int((time.perf_counter() - start) * 1000) + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' - if isinstance(latency, int): - if latency <= 800: - level = 'low' - elif latency <= 2000: - level = 'medium' - else: - level = 'high' - return f'{latency}ms', level - return str(latency), 'unchecked' + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') - raise SystemExit(0) + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') - raise SystemExit(0) + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') - raise SystemExit(0) + print('MSG\tℹ️ 当前未配置任何 API provider。') + raise SystemExit(0) print('MSG\t--- 已配置 API 列表 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): - provider = providers.get(name) - if not isinstance(provider, dict): - base_url = '-' - model_count = 0 - latency_raw = '不可用' - else: - base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' - models = provider.get('models') if isinstance(provider.get('models'), list) else [] - model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) - api = provider.get('api', '') - api_key = provider.get('apiKey') - - latency_raw = '未检测' - if api in SUPPORTED_APIS: - if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: - try: - latency_raw = ping_models(base_url, api_key) - except Exception: - latency_raw = '不可用' - else: - latency_raw = '不可用' - - latency_text, latency_level = classify_latency(latency_raw) - api_label = api if api in SUPPORTED_APIS else '-' - print( - 'ROW\t' + '\t'.join([ - str(idx), - str(name), - str(base_url), - str(model_count), - str(api_label), - str(latency_text), - str(latency_level), - ]) - ) + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未检测' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) PY ) } @@ -11017,105 +11017,105 @@ target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') - raise SystemExit(2) + print('❌ 未检测到 API providers,无法同步') + raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def fetch_remote_models_with_retry(base_url, api_key, retries=3): - last_error = None - for attempt in range(1, retries + 1): - req = urllib.request.Request( - base_url.rstrip('/') + '/models', - headers={ - 'Authorization': f'Bearer {api_key}', - 'User-Agent': 'Mozilla/5.0', - }, - ) - try: - with urllib.request.urlopen(req, timeout=12) as resp: - payload = resp.read().decode('utf-8', 'ignore') - return json.loads(payload), None, attempt - except Exception as e: - last_error = e - if attempt < retries: - time.sleep(1) - return None, last_error, retries + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries api = provider.get('api', '') @@ -11124,41 +11124,41 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') - raise SystemExit(3) + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') + provider['api'] = '' + api = '' protocol_msg = None try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' + protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - raise SystemExit(4) + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') - raise SystemExit(4) + print(f'❌ {target}: /models 返回结构不可识别') + raise SystemExit(4) remote_ids = [] for item in data['data']: - if isinstance(item, dict) and item.get('id'): - remote_ids.append(str(item['id'])) + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') - raise SystemExit(5) + print(f'❌ {target}: 上游 /models 为空,已中止同步') + raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] local_ids = [str(m['id']) for m in local_models] @@ -11166,33 +11166,33 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') - raise SystemExit(3) + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: - nm = copy.deepcopy(template) - nm['id'] = mid - if isinstance(nm.get('name'), str): - nm['name'] = f'{target} / {mid}' - new_models.append(nm) + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') - raise SystemExit(5) + print(f'❌ {target}: 同步后无可用模型,已中止写入') + raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} local_refs = {model_ref(target, mid) for mid in local_ids} @@ -11202,44 +11202,44 @@ first_ref = model_ref(target, str(new_models[0]['id'])) changed = False primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: - set_primary_ref(defaults, first_ref) - changed = True - print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if isinstance(val, str) and val in removed_refs: - defaults[fk] = first_ref - changed = True - print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: - defaults_models.pop(r, None) - changed = True + defaults_models.pop(r, None) + changed = True for r in sorted(expected_refs): - if r not in defaults_models: - defaults_models[r] = {} - changed = True + if r not in defaults_models: + defaults_models[r] = {} + changed = True if removed_ids or added_ids or len(local_models) != len(new_models): - provider['models'] = new_models - changed = True + provider['models'] = new_models + changed = True if protocol_msg: - print(protocol_msg) + print(protocol_msg) if changed: - with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in @@ -11281,66 +11281,66 @@ name = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) + print('❌ 未找到 openclaw.json') + raise SystemExit(2) providers = ((obj.get('models') or {}).get('providers') or {}) provider = providers.get(name) if isinstance(providers, dict) else None if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) base_url = provider.get('baseUrl') api_key = provider.get('apiKey') if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) current_api = provider.get('api', '') if current_api not in SUPPORTED_APIS: - current_api = '' + current_api = '' api, reason, err = detect_api_protocol(base_url, api_key) if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') + print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') PY } @@ -11410,71 +11410,71 @@ path = sys.argv[1] name = sys.argv[2] with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) + obj = json.load(f) work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) agents = work.setdefault('agents', {}) defaults = agents.setdefault('defaults', {}) defaults_models_raw = defaults.get('models') if isinstance(defaults_models_raw, dict): - defaults_models = defaults_models_raw + defaults_models = defaults_models_raw elif isinstance(defaults_models_raw, list): - defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} else: - defaults_models = {} + defaults_models = {} defaults['models'] = defaults_models def model_ref(provider_name, model_id): - return f"{provider_name}/{model_id}" + return f"{provider_name}/{model_id}" def ref_provider(ref): - if not isinstance(ref, str) or '/' not in ref: - return None - return ref.split('/', 1)[0] + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] def get_primary_ref(defaults_obj): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - return model_obj - if isinstance(model_obj, dict): - primary = model_obj.get('primary') - if isinstance(primary, str): - return primary - return None + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None def set_primary_ref(defaults_obj, new_ref): - model_obj = defaults_obj.get('model') - if isinstance(model_obj, str): - defaults_obj['model'] = new_ref - elif isinstance(model_obj, dict): - model_obj['primary'] = new_ref - else: - defaults_obj['model'] = {'primary': new_ref} + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} def collect_available_refs(exclude_provider=None): - refs = [] - if not isinstance(providers, dict): - return refs - for pname, p in providers.items(): - if exclude_provider and pname == exclude_provider: - continue - if not isinstance(p, dict): - continue - for m in p.get('models', []) or []: - if isinstance(m, dict) and m.get('id'): - refs.append(model_ref(pname, str(m['id']))) - return refs + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs replacement_candidates = collect_available_refs(exclude_provider=name) @@ -11482,30 +11482,30 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: - if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') - raise SystemExit(3) - set_primary_ref(defaults, replacement) - print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + if not replacement: + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): - val = defaults.get(fk) - if ref_provider(val) == name: - if not replacement: - print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') - raise SystemExit(3) - defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: - defaults_models.pop(r, None) + defaults_models.pop(r, None) providers.pop(name, None) with open(path, 'w', encoding='utf-8') as f: - json.dump(work, f, ensure_ascii=False, indent=2) - f.write('\n') + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') print(f'🗑️ 已删除 provider: {name}') print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') @@ -11576,16 +11576,16 @@ PY install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - - fi + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + + fi } @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + models_raw=$(openclaw models list 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,8 @@ PY --header "" \ --height 35) - - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum)'; then + # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then echo "操作已取消,正在退出..." break fi @@ -11740,22 +11740,22 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] if plugin_id not in a: - a.append(plugin_id) + a.append(plugin_id) plugins['allow'] = a data['plugins'] = plugins @@ -11811,19 +11811,19 @@ config_file = Path(sys.argv[1]) plugin_id = sys.argv[2] try: - data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} - if not isinstance(data, dict): - data = {} + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} except Exception: - data = {} + data = {} plugins = data.get('plugins') if not isinstance(plugins, dict): - plugins = {} + plugins = {} a = plugins.get('allow') if not isinstance(a, list): - a = [] + a = [] a = [x for x in a if x != plugin_id] plugins['allow'] = a From 3845c4e90bf56c442067e0c35bee9f4b73c47df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:13:57 +0800 Subject: [PATCH 1013/1285] Update model list command and error handling --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dbcd339d0..f0d34ed5e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,7 @@ PY --header "" \ --height 35) - # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." break fi From 94b0d9e6e5943214b70e0198b78a1134babb8510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:14:55 +0800 Subject: [PATCH 1014/1285] Update model listing command and error handling --- kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index fb907636a..cbce97710 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11667,8 +11667,7 @@ PY --header "" \ --height 35) - # gum 失败(例如 flags 不兼容)时会输出 Usage/help;避免误写入 openclaw 配置 - if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -qE '^(Usage:|gum: error:)'; then + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." break fi From b46f7c12415dcc39b6b1af598b14ede1464ad6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:24:12 +0800 Subject: [PATCH 1015/1285] Fix command to list models in kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f0d34ed5e..3cba5fa6c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + models_raw=$(openclaw models list 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end From 3b39fce739771831e061b4e2693a606337a695d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:25:41 +0800 Subject: [PATCH 1016/1285] Fix command to list models in kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index cbce97710..ce4a3fc6d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11600,7 +11600,7 @@ PY while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + models_raw=$(openclaw models list 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end From 3f9cd0b915bbf32aded75ee3a6228cd01ef56c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:51:28 +0800 Subject: [PATCH 1017/1285] Update kejilion.sh --- kejilion.sh | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ce4a3fc6d..759d0ea1f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11593,14 +11593,14 @@ PY change_model() { send_stats "换模型" - # 仅展示已配置/可用的模型(Auth=yes),并用 gum 交互式选择 - # 需要 gum;若未安装则降级为手动输入 local orange="#FF8C00" + clear + while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11608,25 +11608,23 @@ PY fi # 提取 Auth=yes 的模型名(跳过表头) - models_list=$(echo "$models_raw" | awk 'NR>1 && $5=="yes" {print $1}') + models_list=$(echo "$models_raw") model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') # 获取默认模型(Tags 含 default) - default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" install_gum install gum + clear + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then - clear echo "--- 模型管理 ---" - echo "所有模型:" - openclaw models list --all - echo "----------------" - echo "当前模型:" + echo "当前可用模型:" openclaw models list echo "----------------" read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model @@ -11644,8 +11642,6 @@ PY continue # 跳过本次循环,重新开始 fi else - clear - # 顶部信息(橙色) gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" From 985cb4c49a9e7c4211abb9700de440e5da587aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 08:52:28 +0800 Subject: [PATCH 1018/1285] Refactor model selection process in kejilion.sh --- cn/kejilion.sh | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3cba5fa6c..3f13f6285 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11593,14 +11593,14 @@ PY change_model() { send_stats "换模型" - # 仅展示已配置/可用的模型(Auth=yes),并用 gum 交互式选择 - # 需要 gum;若未安装则降级为手动输入 local orange="#FF8C00" + clear + while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list 2>/dev/null) + models_raw=$(openclaw models list --plain 2>/dev/null) if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end @@ -11608,25 +11608,23 @@ PY fi # 提取 Auth=yes 的模型名(跳过表头) - models_list=$(echo "$models_raw" | awk 'NR>1 && $5=="yes" {print $1}') + models_list=$(echo "$models_raw") model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') # 获取默认模型(Tags 含 default) - default_model=$(echo "$models_raw" | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') [ -z "$default_model" ] && default_model="(unknown)" install_gum install gum + clear + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then - clear echo "--- 模型管理 ---" - echo "所有模型:" - openclaw models list --all - echo "----------------" - echo "当前模型:" + echo "当前可用模型:" openclaw models list echo "----------------" read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model @@ -11644,8 +11642,6 @@ PY continue # 跳过本次循环,重新开始 fi else - clear - # 顶部信息(橙色) gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" From 99a1e859d3ca931b9df0429bbac759f2dabf5a7b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 16:56:04 +0800 Subject: [PATCH 1019/1285] feat(openclaw): install gum on rpm/zypper distros --- cn/kejilion.sh | 19 ++++++++++++++++++- kejilion.sh | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3f13f6285..0a5c67e4e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11584,7 +11584,24 @@ PY curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null apt update && apt install -y gum - + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum fi } diff --git a/kejilion.sh b/kejilion.sh index 759d0ea1f..849246275 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11584,7 +11584,24 @@ PY curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null apt update && apt install -y gum - + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum fi } From b8c2043dbcdd2686554c6adeaf55a24b314c29aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 17:14:52 +0800 Subject: [PATCH 1020/1285] Increase height parameter from 35 to 45 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0a5c67e4e..db0bbdf30 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11678,7 +11678,7 @@ REPO --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35) + --height 45) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." From 40356991802bf3f0e1c7e5931286a05ac856960f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 14 Mar 2026 17:15:58 +0800 Subject: [PATCH 1021/1285] Increase height parameter in kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 849246275..345f64d89 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11678,7 +11678,7 @@ REPO --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 35) + --height 45) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." From f76207d568253df65976677edf5b24682920bfa6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 17:32:11 +0800 Subject: [PATCH 1022/1285] feat(openclaw): number models in gum selector --- cn/kejilion.sh | 7 +++++-- kejilion.sh | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index db0bbdf30..a4bc717bd 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11624,8 +11624,8 @@ REPO return 1 fi - # 提取 Auth=yes 的模型名(跳过表头) - models_list=$(echo "$models_raw") + # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') # 获取默认模型(Tags 含 default) @@ -11686,6 +11686,9 @@ REPO fi fi + # 去掉编号前缀:"(10) model" -> "model" + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + # 执行切换 echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then diff --git a/kejilion.sh b/kejilion.sh index 345f64d89..97dfb6ee0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11624,8 +11624,8 @@ REPO return 1 fi - # 提取 Auth=yes 的模型名(跳过表头) - models_list=$(echo "$models_raw") + # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') # 获取默认模型(Tags 含 default) @@ -11686,6 +11686,9 @@ REPO fi fi + # 去掉编号前缀:"(10) model" -> "model" + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + # 执行切换 echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then From 8aa5a453f8e34422b6fd44a8b3b276db2949d806 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 18:02:52 +0800 Subject: [PATCH 1023/1285] perf(openclaw): load model list from config first --- cn/kejilion.sh | 10 +++++++++- kejilion.sh | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a4bc717bd..0e269e88d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11617,7 +11617,15 @@ REPO while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + # 优先从配置文件读取模型键(更快),失败再回退到 openclaw models list + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | keys[]?' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + models_raw=$(openclaw models list --plain 2>/dev/null) + fi if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end diff --git a/kejilion.sh b/kejilion.sh index 97dfb6ee0..9c77dfcc0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11617,7 +11617,15 @@ REPO while true; do local models_raw models_list default_model model_count selected_model - models_raw=$(openclaw models list --plain 2>/dev/null) + # 优先从配置文件读取模型键(更快),失败再回退到 openclaw models list + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | keys[]?' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + models_raw=$(openclaw models list --plain 2>/dev/null) + fi if [ -z "$models_raw" ]; then echo "获取模型列表失败,请检查 openclaw 是否可用。" break_end From 6d46771ebfc810870f02a280716dd5bfe4f5f8c3 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 18:41:02 +0800 Subject: [PATCH 1024/1285] fix(openclaw): read models from config keys or array --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0e269e88d..c4e496fb9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11622,7 +11622,7 @@ REPO oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" - models_raw=$(jq -r '.agents.defaults.models | keys[]?' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then models_raw=$(openclaw models list --plain 2>/dev/null) fi diff --git a/kejilion.sh b/kejilion.sh index 9c77dfcc0..6e975cdb6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11622,7 +11622,7 @@ REPO oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" - models_raw=$(jq -r '.agents.defaults.models | keys[]?' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then models_raw=$(openclaw models list --plain 2>/dev/null) fi From b6b9609584171165e325210a8647264eca06aeaa Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 18:45:39 +0800 Subject: [PATCH 1025/1285] perf(openclaw): read default model from config --- cn/kejilion.sh | 7 +++++-- kejilion.sh | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c4e496fb9..e541c9e82 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11636,8 +11636,11 @@ REPO models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # 获取默认模型(Tags 含 default) - default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + if [ -z "$default_model" ]; then + default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + fi [ -z "$default_model" ] && default_model="(unknown)" diff --git a/kejilion.sh b/kejilion.sh index 6e975cdb6..e2e118b26 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11636,8 +11636,11 @@ REPO models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # 获取默认模型(Tags 含 default) - default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + if [ -z "$default_model" ]; then + default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') + fi [ -z "$default_model" ] && default_model="(unknown)" From 14b7ab166ffd9af4d952710b8247bab38cebfa30 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 14 Mar 2026 18:48:33 +0800 Subject: [PATCH 1026/1285] perf(openclaw): model selector reads config only --- cn/kejilion.sh | 12 +++--------- kejilion.sh | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e541c9e82..8516f5d65 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11617,17 +11617,14 @@ REPO while true; do local models_raw models_list default_model model_count selected_model - # 优先从配置文件读取模型键(更快),失败再回退到 openclaw models list + # 从配置文件读取模型键(不调用 openclaw models list) local oc_config oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - models_raw=$(openclaw models list --plain 2>/dev/null) - fi - if [ -z "$models_raw" ]; then - echo "获取模型列表失败,请检查 openclaw 是否可用。" + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi @@ -11638,9 +11635,6 @@ REPO # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) - if [ -z "$default_model" ]; then - default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') - fi [ -z "$default_model" ] && default_model="(unknown)" @@ -11653,7 +11647,7 @@ REPO if ! command -v gum >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" - openclaw models list + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model diff --git a/kejilion.sh b/kejilion.sh index e2e118b26..4893a18cd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11617,17 +11617,14 @@ REPO while true; do local models_raw models_list default_model model_count selected_model - # 优先从配置文件读取模型键(更快),失败再回退到 openclaw models list + # 从配置文件读取模型键(不调用 openclaw models list) local oc_config oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - models_raw=$(openclaw models list --plain 2>/dev/null) - fi - if [ -z "$models_raw" ]; then - echo "获取模型列表失败,请检查 openclaw 是否可用。" + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi @@ -11638,9 +11635,6 @@ REPO # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) - if [ -z "$default_model" ]; then - default_model=$(openclaw models list 2>/dev/null | awk 'NR>1 && $0 ~ /default/ {print $1; exit}') - fi [ -z "$default_model" ] && default_model="(unknown)" @@ -11653,7 +11647,7 @@ REPO if ! command -v gum >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" - openclaw models list + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model From 45a9cea0b01e3a8493053a19a8dc3c622a8219c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:58:11 +0800 Subject: [PATCH 1027/1285] Reduce height parameter from 45 to 35 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8516f5d65..8a54514c0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11683,7 +11683,7 @@ REPO --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 45) + --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." From 694fc7e21862daf8270ff3a51f01310efc6fb0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:59:11 +0800 Subject: [PATCH 1028/1285] Reduce height parameter from 45 to 35 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 4893a18cd..0bbfd5c93 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11683,7 +11683,7 @@ REPO --cursor-text.foreground "$orange" \ --match.foreground "$orange" \ --header "" \ - --height 45) + --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." From 31edfefeeb23ce520caa59bbe18e20fb105e2e30 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 15 Mar 2026 05:21:26 +0000 Subject: [PATCH 1029/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-03-15=2005:21:26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 4120 ++++++++++++++++++++++++++++++++++++++++++----- jp/kejilion.sh | 4138 +++++++++++++++++++++++++++++++++++++++++++----- kr/kejilion.sh | 4138 +++++++++++++++++++++++++++++++++++++++++++----- tw/kejilion.sh | 4064 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 14850 insertions(+), 1610 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index e674bad5f..09d46a098 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.7" gl_hui='\e[37m' @@ -884,7 +884,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -5088,7 +5088,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5524,7 +5524,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6594,9 +6594,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6638,7 +6638,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6738,30 +6738,95 @@ linux_backup() { -# Show connection list -list_connections() { - echo "Saved connections:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH input normalization function +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# Add new connection -add_connection() { - send_stats "Add new connection" - echo "Example of creating a new connection:" - echo "- Connection name: my_server" - echo "- IP address: 192.168.1.100" - echo "- Username: root" - echo "- Port: 22" - echo "------------------------" - read -e -p "Please enter a connection name:" name - read -e -p "Please enter IP address:" ip - read -e -p "Please enter username (default: root):" user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "Please enter the port number (default: 22):" port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "Error: Please enter a valid server address." + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "Error: Port must be a number between 1-65535." + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "Error: Username format is incorrect." + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "Error: SSH username format is incorrect." + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "Error: SSH host address format is incorrect." + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "Please select an authentication method:" echo "1. Password" @@ -6771,37 +6836,92 @@ add_connection() { case $auth_choice in 1) read -s -p "Please enter password:" password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "Error: Password cannot be empty." + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "Please paste the key content (press Enter twice after pasting):" - local password_or_key="" while IFS= read -r line; do - # If the input is a blank line and the key content already contains the beginning, end the input if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # If it is the first line or you have already started entering the key content, continue adding if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # Check if it is the key content - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "Invalid key content!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "Invalid choice!" - return + return 1 ;; esac +} + +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "Error: Password cannot be empty." + done +} + +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "Error: Port must be a number between 1-65535." + done +} + +# Show connection list +list_connections() { + echo "Saved connections:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# Add new connection +add_connection() { + send_stats "Add new connection" + echo "Example of creating a new connection:" + echo "- Connection name: my_server" + echo "- IP address: 192.168.1.100" + echo "- Username: root" + echo "- Port: 22" + echo "------------------------" + read -e -p "Please enter a connection name:" name + + kj_ssh_read_host_user_port "Please enter IP address:" "Please enter username (default: root):" "Please enter the port number (default: 22):" "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "Connection saved!" } @@ -7087,7 +7207,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7134,52 +7254,23 @@ add_task() { read -e -p "Please enter the task name:" name read -e -p "Please enter the local directory:" local_path read -e -p "Please enter the remote directory:" remote_path - read -e -p "Please enter remote user@IP:" remote - read -e -p "Please enter the SSH port (default 22):" port - port=${port:-22} - echo "Please select an authentication method:" - echo "1. Password" - echo "2. Key" - read -e -p "Please select (1/2):" auth_choice + while true; do + read -e -p "Please enter remote user@IP:" remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "Please enter password:" password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "Please paste the key content (press Enter twice after pasting):" - local password_or_key="" - while IFS= read -r line; do - # If the input is a blank line and the key content already contains the beginning, end the input - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # If it is the first line or you have already started entering the key content, continue adding - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + kj_ssh_read_port "Please enter the SSH port (default 22):" "22" + port="$KJ_SSH_PORT" - # Check if it is the key content - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "Invalid key content!" - return - fi - ;; - *) - echo "Invalid choice!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "Please select synchronization mode:" echo "1. Standard mode (-avz)" @@ -7198,6 +7289,7 @@ add_task() { echo "Mission saved!" } + # Delete task delete_task() { send_stats "Delete sync task" @@ -7294,7 +7386,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -8137,10 +8229,10 @@ docker_ssh_migration() { read -e -p "Please enter the backup directory to be migrated:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}The backup directory does not exist${gl_bai}"; return; } - read -e -p "Target server IP:" TARGET_IP - read -e -p "Target server SSH username:" TARGET_USER - read -e -p "Target server SSH port [default 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "Target server IP:" "Target server SSH username [default root]:" "Target server SSH port [default 22]:" "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -8223,7 +8315,7 @@ linux_docker() { echo -e "${gl_kjlan}7. ${gl_bai}Clean up useless docker containers and mirror network data volumes" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Change Docker source" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}9. ${gl_bai}Edit daemon.json file" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Enable Docker-ipv6 access" echo -e "${gl_kjlan}12. ${gl_bai}Turn off Docker-ipv6 access" @@ -9604,13 +9696,9 @@ linux_ldnmp() { read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "Please enter the remote server IP:" remote_ip - read -e -p "Target server SSH port [default 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." - continue - fi + kj_ssh_read_host_port "Please enter the remote server IP:" "Target server SSH port [default 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -9956,22 +10044,24 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. Add new model API" + echo "6. API management" echo "7. Robot connection and docking" - echo "8. Install plug-ins (such as Feishu)" - echo "9. Install skills" + echo "8. Plug-in management (installation/removal)" + echo "9. Skill management (installation/removal)" echo "10. Edit the main configuration file" echo "11. Configuration Wizard" echo "12. Health detection and repair" echo "13. WebUI access and settings" echo "14. TUI command line dialog window" + echo "15. Memory/Memory" echo "--------------------" - echo "15. Update" - echo "16. Uninstall" + echo "16. Backup and restore" + echo "17. Update" + echo "18. Uninstall" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" - printf "Please enter options and press Enter:" + printf "请输入选项并回车: " } @@ -9997,6 +10087,459 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + + + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' +import copy +import json +import os +import platform +import sys +import time +import urllib.request +from datetime import datetime, timezone + +path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ API providers not detected, model synchronization skipped') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models probe failed 3 times in a row. Delete this API provider and all related models? [y/N]:" + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: The default main model points to this provider, but there is no alternative model available, and the deletion has been aborted.') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 The default primary model has been switched before deletion: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} points to the provider, but no alternative model is available, deletion aborted') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 Switched before deletion {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ Provider {name} has been deleted and {len(removed_refs)} model references under defaults.models have been removed') + return True + + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): + if not isinstance(provider, dict): + summary.append(f'ℹ️ Skip {name}: provider structure is illegal') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ Skip {name}: None baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: Illegal protocol {api or "(unset)"} found, will be re-detected') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: The protocol has been automatically corrected to {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: Protocol detection failed, skip correction ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models detection failed, retried {attempts} times ({type(err).__name__}: {err})') + send_stat('OpenClaw API confirmed intervention') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API deletion failed Provider-Confirm') + summary.append(f'✅ {name}: The user has confirmed to delete the provider and all related model references') + else: + send_stat('OpenClaw API deletion failed Provider-rejected') + summary.append(f'ℹ️ {name}: The user has not confirmed the deletion and retains the existing provider configuration.') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models Successful after {attempts} retry') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ Skip {name}: /models return structure is not recognized') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name}’s upstream /models is empty and cannot provide a bottom-up model for this provider.') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ Skip {name}: local models no valid template model') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ Add new model ({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ Delete model ({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} has no available model after synchronization, and the default model/fallback model cannot be guaranteed.') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 The default model has been completely replaced: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} has been completely replaced: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: Delete {len(removed_ids)}, add {len(added_ids)}, current {len(new_models)}') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ Model synchronization failed: There is a provider. After synchronization, there is no available model and writing has been aborted.') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API model consistency synchronization is completed and the configuration has been written') +else: + for line in summary: + print(line) + print('ℹ️ No synchronization required: configuration is already consistent with upstream /models') +PY + } + + + install_moltbot() { echo "Start installing OpenClaw..." send_stats "Start installing OpenClaw..." @@ -10013,7 +10556,9 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # Tip: If you need to modify the configuration to take effect immediately, you can restart the gateway: openclaw gateway restart + configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10049,6 +10594,44 @@ moltbot_menu() { + # OpenClaw API protocol detection (priority responses -> completions) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + return 0 + } + # Core function: get and add all models add-all-models-from-provider() { local provider_name="$1" @@ -10058,6 +10641,10 @@ moltbot_menu() { echo "🔍 Getting$provider_nameAll available models of..." + # Automatically identify API protocols + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # Get model list local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10087,7 +10674,7 @@ moltbot_menu() { [[ $first == false ]] && models_array+="," first=false - # context and max_tokens are fully loaded, so you are not afraid of the big problem + # context and max_tokens are fully loaded, so you are not afraid of big problems local context_window=1048576 local max_tokens=128000 @@ -10133,10 +10720,11 @@ EOF # Backup configuration [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # Inject all models using jq + # Use jq to inject all models and synchronize defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10145,10 +10733,26 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then @@ -10162,7 +10766,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "Add API" + send_stats "OpenClaw API added" echo "=== Interactively add OpenClaw Provider (full model) ===" # 1. Provider name @@ -10189,7 +10793,11 @@ EOF echo done - # 4. Get model list + # 4. Protocol detection (no sense) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. Get model list echo "🔍 Getting list of available models..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10204,10 +10812,10 @@ EOF echo "--------------------------------" # Show all, with serial number i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10221,292 +10829,2968 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 Using the first model:$default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 Selected models:$default_model" else - default_model="$input_model" + default_model="$input_model" + fi + + # 6. Confirm information + echo + echo "====== Confirmation ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "Default model:$default_model" + echo "Total number of models:$model_count" + echo "======================" + + read -erp "Confirm to add all$model_countA model? (y/N):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ Canceled" + return 1 + fi + + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 Set default model and restart gateway..." + openclaw models set "$provider_name/$default_model" + start_gateway + echo "✅ Done! all$model_countmodels loaded" + echo "✅ The agreement has been automatically identified as:$DETECTED_API" + fi + + break_end + } + + + +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API List" + + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf '%b\n' "[$idx] ${name} | API: ${base_url}| Agreement:${api_type}| Number of models:${gl_huang}${model_count}${gl_bai}| Delay/Status:${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == 'Not available': + return 'Not available', 'unavailable' + if latency == 'Not detected': + return 'Not detected', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ openclaw.json not found, please complete the installation/initialization first.') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ Failed to read configuration: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ No API provider is currently configured.') + raise SystemExit(0) + +print('MSG\t--- Configured API list ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = 'Not available' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = 'Not detected' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = 'Not available' + else: + latency_raw = 'Not available' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API synchronization by Provider" + + if [ ! -f "$config_file" ]; then + echo "❌ Configuration file not found:$config_file" + break_end + return 1 + fi + + read -erp "Please enter the API name (provider) to be synchronized:" provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider name cannot be empty" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ API providers not detected, unable to synchronize') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ provider: {target} not found') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ provider {target} is missing baseUrl/apiKey/models and cannot perform synchronization') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'ℹ️ provider {target} current api={api}, will re-detect the protocol and continue') + provider['api'] = '' + api = '' + +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 Auto-corrected protocol: {target} {api} ({detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ Protocol detection failed, skipping correction: {target} ({type(e).__name__}: {e})' + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models detection failed, retried {attempts} times ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models The returned structure is not recognized') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: upstream /models is empty, synchronization aborted') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: Local models do not have a valid template model, and new models cannot be added.') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +if added_ids: + print(f'➕ Add new model ({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ Delete model ({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: No model available after synchronization, writing aborted') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 The default model has been completely replaced: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} has been completely replaced: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if protocol_msg: + print(protocol_msg) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: Remove {len(removed_ids)}, add {len(added_ids)}, current {len(new_models)}') +if changed: + print('✅ The specified provider model consistency synchronization is completed and the configuration has been written') +else: + print('ℹ️ No synchronization required: the provider configuration is already consistent with the upstream /models') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ Synchronous execution completed" + start_gateway + ;; + 2) + echo "❌ Synchronization failed: provider does not exist or is not configured" + ;; + 3) + echo "❌ Synchronization failed: provider configuration is incomplete or type is not supported" + ;; + 4) + echo "❌ Synchronization failed: Upstream /models request failed" + ;; + 5) + echo "❌ Synchronization failed: the upstream model is empty or there is no available model after synchronization" + ;; + *) + echo "❌ Synchronization failed: please check the configuration file structure or log output" + ;; + esac + + break_end +} + +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ openclaw.json not found') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ provider: {name} not found') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ provider {name} is missing baseUrl/apiKey') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ Updated provider {name} protocol: {current_api or "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ No updates required: protocol remains {current_api or api}') +PY +} + +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API protocol fixes" + + if [ ! -f "$config_file" ]; then + echo "❌ Configuration file not found:$config_file" + break_end + return 1 + fi + + read -erp "Please enter the API name (provider) of the protocol to be repaired:" provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider name cannot be empty" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅The agreement has been tested and updated (subject to change)" + start_gateway + ;; + 2) + echo "❌ Repair failed: provider does not exist or is not configured" + ;; + 3) + echo "❌ Repair failed: provider configuration is incomplete" + ;; + *) + echo "❌ Repair failed: please check the configuration file structure or log output" + ;; + esac + + break_end +} + + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API delete entry" + + if [ ! -f "$config_file" ]; then + echo "❌ Configuration file not found:$config_file" + break_end + return 1 + fi + + read -erp "Please enter the API name (provider) to be deleted:" provider_name + if [ -z "$provider_name" ]; then + send_stats "OpenClaw API Delete Cancel" + echo "❌ provider name cannot be empty" + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ provider: {name} not found') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ Deletion aborted: the default main model points to the provider and no alternative model is available') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 Default primary model switching: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ Deletion aborted: {fk} points to the provider and no alternative model is available') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} switch: {val} -> {replacement}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ Deleted provider: {name}') +print(f'🧹 Cleaned {len(removed_refs)} associated model references in defaults.models') +PY + local rc=$? + case "$rc" in + 0) + send_stats "OpenClaw API deletion confirmation" + echo "✅Deletion completed" + start_gateway + ;; + 2) + echo "❌ Deletion failed: provider does not exist" + ;; + 3) + send_stats "OpenClaw API Delete Cancel" + echo "❌ Deletion failed: no replacement model available, original configuration has been maintained" + ;; + *) + echo "❌ Deletion failed: please check the configuration file structure or log output" + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "OpenClaw API entrance" + while true; do + clear + echo "=======================================" + echo "OpenClaw API Management" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. Add API" + echo "2. Synchronize API provider model list" + echo "3. Delete API" + echo "4. Protocol repair/redetection" + echo "0. Exit" + echo "---------------------------------------" + read -erp "Please enter your choice:" api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + sync-openclaw-provider-interactive + ;; + 3) + delete-openclaw-provider-interactive + ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done + } + + + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "Change model" + + local orange="#FF8C00" + + clear + + while true; do + local models_raw models_list default_model model_count selected_model + + # Read model keys from configuration file (without calling openclaw models list) + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + echo "Failed to get list of models: agents.defaults.models not found in configuration file." + break_end + return 1 + fi + + # Number each model to facilitate quick location (for example: "(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # Read default model from configuration file (faster); fallback to openclaw command on failure + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + [ -z "$default_model" ] && default_model="(unknown)" + + + install_gum + install gum + + clear + + # If gum does not exist, downgrade to the original manual input process (remaining exactly the same as before) + if ! command -v gum >/dev/null 2>&1; then + echo "---Model Management ---" + echo "Currently available models:" + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' + echo "----------------" + read -e -p "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" selected_model + + # 1. Check if you entered 0 to exit + if [ "$selected_model" = "0" ]; then + echo "Operation canceled, exiting..." + break # 跳出 while 循环 + fi + + # 2. Verify that the input is empty + if [ -z "$selected_model" ]; then + echo "Error: Model name cannot be empty. Please try again." + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + else + gum style --foreground "$orange" --bold "Model management" + gum style --foreground "$orange" "Available models (Auth=yes):${model_count}" + gum style --foreground "$orange" "Current default:${default_model}" + echo "" + + # Bottom tip + gum style --faint "↑↓ Select / Enter to confirm / Esc to exit" + echo "" + + # gum filter: with search; gum versions vary greatly, only the most compatible flags are used here + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "Search models (such as cli-api/gpt-5.2)" \ + --prompt "Select model >" \ + --indicator "➜ " \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor-text.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 35) + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then + echo "Operation canceled, exiting..." + break + fi + fi + + # Remove the number prefix: "(10) model" -> "model" + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + + # Execute switch + echo "The model being switched is:$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "Switch failed: openclaw models set returned error." + break_end + return 1 + fi + start_gateway + + break_end + done + } + + + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ Synchronized plugins.allow whitelist:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ Synchronized plugins.allow whitelist:$plugin_id" + return 0 + fi + fi + + echo "⚠️ The plugin has been installed, but the synchronization of plugins.allow failed, please check manually:$config_file" + return 1 + } + + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ Removed from plugins.allow:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ Removed from plugins.allow:$plugin_id" + return 0 + fi + fi + + echo "⚠️ plugins.allow removal failed, please check manually:$config_file" + return 1 + } + + + + + + + install_plugin() { + send_stats "Plug-in management" + while true; do + clear + echo "========================================" + echo "Plug-in management (installation/removal)" + echo "========================================" + echo "Current plugin list:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "Recommended commonly used plug-in IDs (just copy the ID in brackets):" + echo "--------------------------------------------------------" + echo "📱 Communication channels:" + echo "- [feishu] # Feishu/Lark integration" + echo "- [telegram] # Telegram bot" + echo "- [slack] #Slack Corporate Communications" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] # Discord community management" + echo "- [whatsapp] #WhatsApp Automation" + echo "" + echo "🧠 Memory and AI:" + echo "- [memory-core] # Basic memory (file retrieval)" + echo "- [memory-lancedb] # Enhanced memory (vector database)" + echo "- [copilot-proxy] # Copilot interface forwarding" + echo "" + echo "⚙️ Function expansion:" + echo "- [lobster] # Approval flow (with manual confirmation)" + echo "- [voice-call] # Voice call capability" + echo "- [nostr] # Encrypted private chat" + echo "--------------------------------------------------------" + + echo "1) Install/enable plugin" + echo "2) Delete/disable plugins" + echo "0) Return" + read -e -p "Please select an action:" plugin_action + + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "Please enter plugin IDs (separated by spaces, enter 0 to exit):" raw_input + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 Checking plugin status:$plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 Plugin [$plugin_id] Pre-installed, activating..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 Found that the plug-in exists in the system's built-in directory, try to enable it directly..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + echo "📥 Not found locally, try to download and install:$plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ Download successful, activating..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ Installation failed:$plugin_full" + failed_list="$failed_list $plugin_id" + fi + else + echo "🗑️ Removing/disabling plugins:$plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ Uninstalled:$plugin_id" + else + echo "⚠️ Uninstallation failed, it may be a pre-installed plug-in, only disable:$plugin_id" + fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true + fi + done + + echo "" + echo "====== Operation Summary ======" + echo "✅ Success:$success_list" + [ -n "$failed_list" ] && echo "❌ Failure:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ Skip:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 Restarting OpenClaw service to load changes..." + start_gateway + fi + break_end + done + } + + + install_skill() { + send_stats "Skill management" + while true; do + clear + echo "========================================" + echo "Skill management (install/remove)" + echo "========================================" + echo "Currently installed skills:" + openclaw skills list + echo "----------------------------------------" + + # Output a list of recommended practical skills + echo "Recommended practical skills (you can directly copy the name and enter it):" + echo "github # Manage GitHub Issues/PR/CI (gh CLI)" + echo "notion # Manipulate Notion pages, databases and blocks" + echo "apple-notes # macOS native note management (create/edit/search)" + echo "apple-reminders # macOS reminder management (to-do list)" + echo "1password # Automate reading and injecting 1Password keys" + echo "gog # Google Workspace (Gmail/cloud disk/documents) all-round assistant" + echo "things-mac # Deep integration of Things 3 task management" + echo "bluebubbles # Send and receive iMessages perfectly with BlueBubbles" + echo "himalaya # Terminal mail management (IMAP/SMTP powerful tool)" + echo "summarize # One-click summary of webpage/podcast/YouTube video content" + echo "openhue # Control Philips Hue smart lighting scenes" + echo "video-frames # Video frame extraction and short clip editing (ffmpeg driver)" + echo "openai-whisper # Convert local audio to text (offline privacy protection)" + echo "coding-agent # Automatically run programming assistants such as Claude Code/Codex" + echo "----------------------------------------" + + echo "1) Installation skills" + echo "2) Delete skills" + echo "0) Return" + read -e -p "Please select an action:" skill_action + + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue + + read -e -p "Please enter skill names (separated by spaces, enter 0 to exit):" skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + if [ "$skill_action" = "2" ]; then + read -e -p "Secondary confirmation: Deletion only affects the user directory ~/.openclaw/workspace/skills. Are you sure to continue? (y/N):" confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "Deletion canceled." + break_end + continue + fi + fi + + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 Skills [$skill_name] is installed in the user directory." + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 Skills [$skill_name] is installed in the system directory." + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "Skill [$skill_name] Already installed, do you want to reinstall? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "Installing skills:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ Skills$skill_nameInstallation successful." + success_list="$success_list $skill_name" + changed=true + else + echo "❌ Installation failed:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ Deleting skills:$skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ User skill directory has been deleted:$skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ User skill directory not found:$skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== Operation Summary ======" + echo "✅ Success:$success_list" + [ -n "$failed_list" ] && echo "❌ Failure:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ Skip:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 Restarting OpenClaw service to load changes..." + start_gateway + fi + break_end + done + } + +openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + + # Compatible with two common directory namings: + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # Avoid brainless substrings, prefer exact matching and openclaw- prefix matching. + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "abnormal" + elif [ "$enabled" != "true" ]; then + echo "Not enabled" + elif [ "$connected" = "true" ]; then + echo "Connected" + elif [ "$configured" = "true" ]; then + echo "configured" + else + echo "Not configured" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "Local status (only local configuration/cache, no network detection):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "Lark" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + + change_tg_bot_code() { + send_stats "Robot docking" + while true; do + clear + echo "========================================" + echo "Robot connection and docking" + echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" + echo "1. Telegram robot docking" + echo "2. Feishu (Lark) robot docking" + echo "3. WhatsApp bot docking" + echo "----------------------------------------" + echo "0. Return to the previous menu" + echo "----------------------------------------" + read -e -p "Please enter your choice:" bot_choice + + case $bot_choice in + 1) + read -e -p "Please enter the connection code received by the TG robot (for example, NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Please enter the connection code received by Feishu Robot (for example, NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "Please enter the connection code received by WhatsApp (for example NYA99R2F) (enter 0 to exit):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done + } + + + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null + ) || { echo "❌ sha256 verification failed and restoration refused"; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw memory full backup" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ workspace directory not found:$workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "Does it come with AGENTS/USER/SOUL/TOOLS files? (y/N):" include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ No backup memory file found" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ Full memory backup completed:$out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ Full memory backup failed" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_input file_path backup_root + echo "$prompt_text" >&2 + + echo "You can first upload the backup package to the server through scp/sftp, and then enter the path." >&2 + echo "scp example: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 + echo "Tip: When entering a file name, it will be searched in the backup directory by default; when entering a path containing /, it will be verified by the full path." >&2 + read -e -p "Please enter the backup file name or path:" file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ The backup file does not exist:$file_path" >&2 + echo "" + return 1 + fi + + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw memory full restoration" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "Before restoration, it will be performed: type verification + sha256 verification + path whitelist verification") + [ -z "$archive_path" ] && { echo "❌ No backup path entered"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ Illegal or unauthorized path detected:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ Restore aborted: Insecure path exists" + break_end + return 1 + fi + + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ Full memory restoration completed" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw project backup" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ OpenClaw root directory not found:$openclaw_root" + break_end + return 1 + fi + + echo "Backup mode:" + echo "1. Safe mode (default, recommended): workspace + openclaw.json + extensions/skills/prompts/tools (if exists)" + echo "2. Complete mode (contains more states, higher sensitivity risk)" + read -e -p "Please select backup mode (default 1):" export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ No backupable OpenClaw project content found" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw project backup completed (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw project backup failed" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw project restore" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ High-risk operation: Project restore will overwrite OpenClaw configuration and workspace content." + echo "⚠️ Manifest/sha256 verification, whitelist restoration, gateway shutdown and health check will be performed before restoration." + read -e -p "Please enter the confirmation word [I am aware of the high risk and continue to restore] to continue:" confirm_text + if [ "$confirm_text" != "I am aware of the high risk and continue to restore" ]; then + echo "❌ The confirmation word does not match and the restore has been cancelled." + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "Please enter the OpenClaw project backup package path") + [ -z "$archive_path" ] && { echo "❌ No backup path entered"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ Illegal or unauthorized path detected:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ Restore aborted: Insecure path exists" + break_end + return 1 + fi + + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ Stop OpenClaw gateway before restoring..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ Start OpenClaw gateway after restoration..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 gateway health check:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw project restoration completed" + break_end + } + + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "memory backup file" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "Project backup file" + else + echo "Other backup files" + fi + } + + openclaw_backup_collect_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + local has_memory=0 has_project=0 has_other=0 + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + + echo "Backup directory:$backup_root" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "No backup file yet" + return 0 + fi + + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "memory backup file") has_memory=1 ;; + "Project backup file") has_project=1 ;; + "Other backup files") has_other=1 ;; + esac + done + + if [ "$has_memory" -eq 1 ]; then + echo "memory backup file" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "memory backup file" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "Project backup file" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "Project backup file" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "Other backup files" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "Other backup files" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + } + + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw delete backup files" + local backup_root backup_root_real user_input target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "Please enter the file name or full path to delete (0 to cancel):" user_input + if [ "$user_input" = "0" ]; then + echo "Deletion canceled." + break_end + return 0 + fi + if [ -z "$user_input" ]; then + echo "❌ The input cannot be empty." + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ Path out of bounds: Only files in the backup root directory are allowed to be deleted." + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ The target file does not exist:$target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ The target file is not in the current backup list." + break_end + return 1 + fi + + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "About to be deleted: [$target_type] $target_path" + read -e -p "First confirmation: Enter yes to confirm and continue:" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "Deletion canceled." + break_end + return 0 + fi + read -e -p "Secondary confirmation: Enter DELETE to delete:" confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "Deletion canceled." + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ Deletion successful:$target_file" + else + echo "❌ Delete failed:$target_file" + fi + break_end + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list + break_end + } + + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } + + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ The index library file was not found, it may be empty or does not exist." + echo "Store raw value: ${store_raw:-}" + echo "Reindexing will still be performed." + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ Index backed up:$backup_file" + else + echo "⚠️ Index backup failed, continue to rebuild." + fi + fi + openclaw memory index --force + openclaw gateway restart + echo "✅ The index has been rebuilt and the gateway has been automatically restarted." + echo "" + openclaw_memory_render_status + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ Failed to obtain Workspace path, skipping directory repair." + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 The memory directory does not exist and has been automatically created:$memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "Failed to get status" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /Underlying solution: /' -e 's/^Vector: /Vector library status: /' -e 's/^Indexed: /Included files: /') + if [ -z "$status_lines" ]; then + echo "Not installed/not started" + else + echo "$status_lines" + fi + fi + } + + openclaw_memory_get_backend() { + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi + } + + openclaw_memory_get_local_model_path() { + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then + echo "true" + return + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD is available") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD not detected") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model path:$model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model path not configured") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model file exists") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("Model comes from HF download source (may be slow/failed in China)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("The local model file does not exist or is unavailable") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co is accessible") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com can be accessed") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com may be unreachable (suspected domestic/restricted network)") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ Curl or wget is not detected and cannot be downloaded." + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ sqlite3 is not detected, QMD may not function properly." + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 available: ${ver:-unknown}" + echo "ℹ️ sqlite extension support cannot be reliably detected and will continue." + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun already exists" + return 0 + fi + echo "⬇️ Install bun..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌ Unable to install bun as curl or wget is not detected." + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun installation completed" + return 0 + fi + echo "❌ bun installation failed" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd already exists:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ Install qmd via bun:$qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd installation failed" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd installation completed:$qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ Environment ready" + echo "Scheme: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "Mode: Write configuration only (not installed/not downloaded)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "Index: Executed" + else + echo "Index: skipped" + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "Restart: executed" + else + echo "Restart: skipped" + fi + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "Model:$OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "area:$OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "Download source:$OPENCLAW_MEMORY_HF_BASE" + fi + echo "Final status:" + openclaw_memory_render_status + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "Automatic deployment is about to be performed (verbose mode)" + echo "Target plan:$scheme_label" + echo "Region: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "Mirror source detection: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "Download source: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "Estimated download path:$OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "Possible traffic/disk usage:$OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "Possible traffic/disk usage: Depends on actual situation" + fi + echo "After confirmation, it will automatically install/download, write configuration, build index and restart the gateway." + echo "Advanced options: Enter config to write configuration only (no installation, no download, no indexing, no restart)" + read -e -p "Enter yes to confirm to continue (default N):" confirm_step + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "Autodeployment canceled." + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ Selected to only write configuration, no installation or download" + else + echo "✅ The index will be automatically built and the gateway will be restarted" + fi + return 0 + } + + openclaw_memory_auto_setup_qmd() { + echo "🔍 Detect QMD environment" + openclaw_memory_cleanup_legacy_keys + openclaw_memory_check_sqlite || true + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) + else + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅ memory.backend is already qmd" + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅ memory.backend=qmd has been set" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ Written to memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅ memory.qmd.command is correct" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 Warm index (possibly download models)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ Preheat skipped" + fi + echo "✅ QMD automatic deployment completed" + } + + openclaw_memory_auto_setup_local() { + echo "🔍 Detect Local environment" + openclaw_memory_cleanup_legacy_keys + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅ memory.backend is already builtin" + else + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅ memory.backend=builtin is set" + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅ memorySearch.provider is already local" + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ agents.defaults.memorySearch.provider=local set" + fi + + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ The model file already exists:$model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ Write-only configuration mode: skip model download" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + else + if [ -f "$model_dest" ]; then + echo "✅ Default model file found:$model_dest" + else + echo "⬇️ Download model:$model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ Model has been downloaded:$model_dest" + fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ The model path has been written" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 Warm index (possibly download models)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ Preheat skipped" + fi + echo "✅ Local automatic deployment is completed" + } + + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd installation directory)" + OPENCLAW_MEMORY_EXPECT_SIZE="About 20-50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="About 350-600MB" + ;; + *) + echo "❌ Unknown solution:$scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ Restart OpenClaw Gateway" + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" + openclaw_memory_render_auto_summary + return 0 + } + + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "Automatic deployment of memory solutions" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3. Auto (automatic selection)" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done + } + + openclaw_memory_apply_scheme() { + local scheme="$1" + openclaw_memory_cleanup_legacy_keys + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ Failed to write configuration" + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "builtin" + if [ $? -ne 0 ]; then + echo "❌ Failed to write configuration" + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ Unknown solution:$scheme" + return 1 + esac + echo "✅ Memory scheme configuration has been updated" + return 0 + } + + openclaw_memory_offer_restart() { + echo "The configuration has been written and needs to be restarted to take effect after the OpenClaw gateway is restarted." + read -e -p "Restart OpenClaw Gateway now? (Y/n):" restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "Restart skipped, can be performed later: openclaw gateway restart" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart fi + } - # 6. Confirm information - echo - echo "====== Confirmation ======" - echo "Provider : $provider_name" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "Default model:$default_model" - echo "Total number of models:$model_count" - echo "======================" - - read -erp "Confirm to add all$model_countA model? (y/N):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ Canceled" + openclaw_memory_fix_index() { + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ The current scheme is detected as QMD, but the qmd command is not installed." + echo "You can switch to Local, or install bun + qmd and try again." + fi + echo "Applicable scenarios: Indexed numerator > denominator (repeated collections lead to abnormal counting)" + read -e -p "Are you sure you set includeDefaultMemory to false? (y/N):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "Canceled." + break_end + return 0 + fi + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false + if [ $? -ne 0 ]; then + echo "❌ Failed to write configuration" + break_end return 1 fi - - install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" - - if [[ $? -eq 0 ]]; then - echo - echo "🔄 Set default model and restart gateway..." - openclaw models set "$provider_name/$default_model" - start_gateway - echo "✅ Done! all$model_countmodels loaded" + echo "✅ includeDefaultMemory=false set" + echo "Recommended execution: Clean and rebuild the index" + read -e -p "Do you want to clean and rebuild the index (recommended)? (Y/n):" rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_safe + else + echo "The status can be viewed later in memory management." fi - break_end } - - - change_model() { - send_stats "Change model" - + openclaw_memory_scheme_menu() { while true; do clear - echo "---Model Management ---" - echo "All models:" - openclaw models list --all - echo "----------------" - echo "Current model:" - openclaw models list - echo "----------------" - read -e -p "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" model - - # 1. Check if you entered 0 to exit - if [ "$model" = "0" ]; then - echo "Operation canceled, exiting..." - break # 跳出 while 循环 - - fi - - # 2. Verify that the input is empty - if [ -z "$model" ]; then - echo "Error: Model name cannot be empty. Please try again." - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 - fi - - # 3. Execute switching logic - echo "The model being switched is:$model ..." - openclaw models set "$model" - - break_end + echo "=======================================" + echo "OpenClaw memory solution" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + builtin|local) current_label="Local" ;; + *) current_label="Not configured" ;; + esac + echo "Current plan:$current_label" + echo "" + echo "QMD: lightweight index, relying on the qmd command (suitable for network constraints)" + echo "Local: local vector retrieval, dependent on embedding model file" + echo "Auto: automatic recommendation (based on availability + network detection)" + echo "---------------------------------------" + echo "1. Switch QMD (automatic deployment/skip if already installed)" + echo "2. Switch to Local (automatic deployment/skip if already installed)" + echo "3. Auto (automatic recommendation and automatic deployment)" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac done - } + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "Memory file not found." + return 0 + fi + echo "number | relative path | size | modification time" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } - - install_plugin() { - send_stats "Install plugin" - while true; do - clear - echo "========================================" - echo "Plug-in management (installation)" - echo "========================================" - echo "Current plugin list:" - openclaw plugins list - echo "--------------------------------------------------------" - echo "Recommended commonly used plug-in IDs (just copy the ID in brackets):" - echo "--------------------------------------------------------" - echo "📱 Communication channels:" - echo "- [feishu] # Feishu/Lark integration" - echo "- [telegram] # Telegram bot" - echo "- [slack] #Slack Corporate Communications" - echo " - [msteams] # Microsoft Teams" - echo "- [discord] # Discord community management" - echo "- [whatsapp] #WhatsApp Automation" - echo "" - echo "🧠 Memory and AI:" - echo "- [memory-core] # Basic memory (file retrieval)" - echo "- [memory-lancedb] # Enhanced memory (vector database)" - echo "- [copilot-proxy] # Copilot interface forwarding" - echo "" - echo "⚙️ Function expansion:" - echo "- [lobster] # Approval flow (with manual confirmation)" - echo "- [voice-call] # Voice call capability" - echo "- [nostr] # Encrypted private chat" - echo "--------------------------------------------------------" - - read -e -p "Please enter the plugin ID (enter 0 to exit):" raw_input - - [ "$raw_input" = "0" ] && break - [ -z "$raw_input" ] && continue - - # 1. Automatic processing: If the user input contains @openclaw/, extract the pure ID to facilitate path checking - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') - local plugin_full="$raw_input" - - echo "🔍 Checking plugin status..." - # Get the current plug-in list for status detection - local plugin_list=$(openclaw plugins list 2>/dev/null) - - # 2. Check whether it is already in the list and disabled (the most common case) - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 Plugin [$plugin_id] Pre-installed, activating..." - openclaw plugins enable "$plugin_id" && echo "✅Activation successful" || echo "❌ Activation failed" - - # 3. Check whether the system physical directory exists - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 Found that the plug-in exists in the system's built-in directory, try to enable it directly..." - openclaw plugins enable "$plugin_id" - + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ File does not exist:$file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=120 + local start_line count + echo "document:$file" + echo "Total number of rows:$total_lines" + read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line + read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 else - # 4. Remote installation logic - echo "📥 Not found locally, try to download and install..." - - # Clean up old failed remnants - rm -rf "/root/.openclaw/extensions/$plugin_id" - - # Perform the installation and capture the results - if openclaw plugins install "$plugin_full"; then - echo "✅ Download successful, activating..." - openclaw plugins enable "$plugin_id" - else - echo "⚠️ Download from official channels failed, try alternatives..." - # Alternative npm installation - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm installed successfully, try to enable..." - openclaw plugins enable "$plugin_id" - else - echo "❌ Fatal error: Unable to obtain the plug-in. Please check if the ID is correct or if the network is available." - # Key: Return or continue directly here instead of using the start_gateway below to prevent hard-coding the configuration. - break_end - continue - fi - fi + start_line=$((total_lines - count + 1)) fi - - echo "🔄 Restarting OpenClaw service to load new plugins..." - start_gateway - break_end - done + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ Please enter a valid number." + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ The number of rows must be greater than 0." + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(empty file)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" } - - - - - - - install_skill() { - send_stats "Installation skills" + openclaw_memory_files_menu() { while true; do clear - echo "========================================" - echo "Skill Management (Installation)" - echo "========================================" - echo "Currently installed skills:" - openclaw skills list - echo "----------------------------------------" - - # Output a list of recommended practical skills - echo "Recommended practical skills (you can directly copy the name and enter it):" - echo "github # Manage GitHub Issues/PR/CI (gh CLI)" - echo "notion # Manipulate Notion pages, databases and blocks" - echo "apple-notes # macOS native note management (create/edit/search)" - echo "apple-reminders # macOS reminder management (to-do list)" - echo "1password # Automate reading and injecting 1Password keys" - echo "gog # Google Workspace (Gmail/cloud disk/documents) all-round assistant" - echo "things-mac # Deep integration of Things 3 task management" - echo "bluebubbles # Send and receive iMessages perfectly with BlueBubbles" - echo "himalaya # Terminal mail management (IMAP/SMTP powerful tool)" - echo "summarize # One-click summary of webpage/podcast/YouTube video content" - echo "openhue # Control Philips Hue smart lighting scenes" - echo "video-frames # Video frame extraction and short clip editing (ffmpeg driver)" - echo "openai-whisper # Convert local audio to text (offline privacy protection)" - echo "coding-agent # Automatically run programming assistants such as Claude Code/Codex" - echo "----------------------------------------" - - # Prompt user to enter skill name - read -e -p "Please enter the name of the skill to be installed (enter 0 to exit):" skill_name - - # 1. Check if you entered 0 to exit - if [ "$skill_name" = "0" ]; then - echo "The operation has been canceled and the skill installation has been exited." - break + echo "=======================================" + echo "OpenClaw memory file" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "Please enter the file number to view (return 0):" file_choice + if [ "$file_choice" = "0" ]; then + return 0 fi - - # 2. Verify that the input is empty - if [ -z "$skill_name" ]; then - echo "Error: Skill name cannot be empty. Please try again." - echo "" + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "Invalid selection, please try again." + sleep 1 continue fi - - # 3. Check whether the skill is installed - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 Skills [$skill_name] is installed in the user directory." - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 Skills [$skill_name] is installed in the system directory." - skill_found=true - fi - - if [ "$skill_found" = true ]; then - read -e -p "Reinstall? (y/N):" reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "Skip installation." - break_end - continue - fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "Memory file not found, press Enter to return..." + return 0 fi - - # 4. Execute the installation command - echo "Installing skills:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ Skills$skill_nameInstallation successful." - start_gateway - else - echo "❌ Installation failed. Please check whether the skill name is correct, or refer to the documentation for troubleshooting." + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "Invalid number, please try again." + sleep 1 + continue fi - - break_end - done + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "Press Enter to return to the list..." + done } - - - change_tg_bot_code() { - send_stats "Robot docking" + openclaw_memory_menu() { + send_stats "OpenClaw memory management" while true; do clear - echo "========================================" - echo "Robot connection and docking" - echo "========================================" - echo "1. Telegram robot docking" - echo "2. Feishu (Lark) robot docking" - echo "3. WhatsApp bot docking" - echo "----------------------------------------" - echo "0. Return to the previous menu" - echo "----------------------------------------" - read -e -p "Please enter your choice:" bot_choice - - case $bot_choice in + echo "=======================================" + echo "OpenClaw memory management" + echo "=======================================" + openclaw_memory_render_status + echo "1. Update memory index" + echo "2. View memory files" + echo "3. Index repair (Indexed exception)" + echo "4. Memory solution (QMD/Local/Auto)" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" memory_choice + case "$memory_choice" in 1) - read -e -p "Please enter the connection code received by the TG robot (for example, NYA99R2F) (enter 0 to exit):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi - openclaw pairing approve telegram "$code" - break_end + echo "The memory index will be updated soon." + read -e -p "First confirmation: Enter yes to continue:" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "Canceled." + break_end + continue + fi + openclaw_memory_prepare_workspace + read -e -p "Secondary confirmation: Enter force to use the full amount (leave blank for increment):" confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ Full reconstruction is more thorough, but takes longer." + echo "Recommendation: Enter rebuild for safe reconstruction (back up the index database first)." + read -e -p "Third confirmation: Enter rebuild to perform a safe rebuild; press Enter to continue with normal force:" confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe + else + openclaw memory index --force + openclaw gateway restart + echo "✅ The index has been rebuilt and the gateway has been automatically restarted." + fi + else + openclaw memory index + fi + break_end ;; 2) - read -e -p "Please enter the connection code received by Feishu Robot (for example, NYA99R2F) (enter 0 to exit):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi - openclaw pairing approve feishu "$code" - break_end + openclaw_memory_files_menu ;; 3) - read -e -p "Please enter the connection code received by WhatsApp (for example NYA99R2F) (enter 0 to exit):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi - openclaw pairing approve whatsapp "$code" - break_end + openclaw_memory_fix_index + ;; + 4) + openclaw_memory_scheme_menu ;; 0) return 0 @@ -10519,11 +13803,47 @@ EOF done } + openclaw_backup_restore_menu() { + + send_stats "OpenClaw backup and restore" + while true; do + clear + echo "=======================================" + echo "OpenClaw Backup and Restore" + echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" + echo "1. Back up the entire memory" + echo "2. Restore the full memory" + echo "3. Back up the OpenClaw project (default safe mode)" + echo "4. Restore OpenClaw Project (Advanced/High Risk)" + echo "5. Delete backup files" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; + 0) return 0 ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done + } + update_moltbot() { echo "Update OpenClaw..." send_stats "Update OpenClaw..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -10703,7 +14023,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; @@ -10714,6 +14034,12 @@ EOF ;; 12) send_stats "Health detection and repair" openclaw doctor --fix + send_stats "OpenClaw API synchronous triggering" + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API model synchronization failed, restarting the gateway has been aborted. Please check provider /models and try again after returning." + fi break_end ;; 13) openclaw_webui_menu ;; @@ -10721,8 +14047,10 @@ EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done @@ -10833,7 +14161,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile online network disk${gl_kjlan}110. ${color110}Karakeep bookmark management" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool${gl_kjlan}112. ${color112}Lucky large intranet penetration tool" - echo -e "${gl_kjlan}113. ${color113}Firefox browser${gl_kjlan}114. ${color114}ClawdBot/Moltbot robot${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox browser${gl_kjlan}114. ${color114}OpenClaw bot management tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}Third-party application list" echo -e "${gl_kjlan}Want your app to appear here? Check out the developer guide:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -13280,7 +16608,7 @@ while true; do docker_rum() { - read -e -p "set up${docker_name}Login key (sk-a combination of letters and numbers starting with) such as: sk-159kejilionyyds163:" app_passwd + read -e -p "set up${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -14516,14 +17844,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "Please enter the remote server IP:" remote_ip - read -e -p "Target server SSH port [default 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." - continue - fi + kj_ssh_read_host_port "Please enter the remote server IP:" "Target server SSH port [default 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -14547,7 +17870,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14620,7 +17943,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -14799,7 +18122,7 @@ switch_mirror() { local country country=$(curl -s ipinfo.io/country) - echo "检测到国家:$country" + echo "Countries detected:$country" if [ "$country" = "CN" ]; then echo "Use domestic mirror sources..." @@ -15018,7 +18341,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -15363,7 +18686,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -15549,8 +18872,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -16056,7 +19379,7 @@ EOF case "$Limiting" in 1) # Enter new virtual memory size - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + echo "If the actual server only has 100G traffic, you can set the threshold to 95G and shut down in advance to avoid traffic errors or overflows." read -e -p "Please enter the inbound traffic threshold (unit is G, default is 100G):" rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "Please enter the outbound traffic threshold (unit is G, default is 100G):" tx_threshold_gb @@ -16585,26 +19908,13 @@ linux_file() { continue fi - read -e -p "Please enter the remote server IP:" remote_ip - if [ -z "$remote_ip" ]; then - echo "Error: Please enter the remote server IP." - send_stats "File transfer failed: Remote server IP not entered" - continue - fi - - read -e -p "Please enter the remote server username (default root):" remote_user - remote_user=${remote_user:-root} - - read -e -p "Please enter the remote server password:" -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "Error: Please enter the remote server password." - send_stats "File transfer failed: Remote server password not entered" - continue - fi + kj_ssh_read_host_user_port "Please enter the remote server IP:" "Please enter the remote server username (default root):" "Please enter the login port (default 22):" "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "Please enter the login port (default 22):" remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "Please enter the remote server password:" + local remote_password="$KJ_SSH_PASSWORD" # Clear old entries for known hosts ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16822,7 +20132,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -17061,7 +20371,7 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 7e0d0de5a..cb5cc4c43 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.7" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -861,12 +861,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1744,7 +1744,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -3284,7 +3284,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3957,7 +3957,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4773,7 +4773,7 @@ linux_clean() { bbr_on() { -# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5802,7 +5802,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6243,7 +6243,7 @@ optimize_web_server() { _kernel_optimize_core "ウェブサイト構築最適化モード" "web" } -# ── 初期設定に戻す(完全クリーン) ── +# ── 还原默认设置(完全清理) ── restore_defaults() { echo -e "${gl_lv}デフォルト設定に戻す...${gl_bai}" @@ -6594,9 +6594,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6638,7 +6638,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6738,30 +6738,95 @@ linux_backup() { -# 接続リストを表示 -list_connections() { - echo "保存された接続:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH入力正規化機能 +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# 新しい接続を追加 -add_connection() { - send_stats "新しい接続を追加" - echo "新しい接続を作成する例:" - echo "- 接続名: my_server" - echo "- IP アドレス: 192.168.1.100" - echo "- ユーザー名: root" - echo "- ポート: 22" - echo "------------------------" - read -e -p "接続名を入力してください:" name - read -e -p "IP アドレスを入力してください:" ip - read -e -p "ユーザー名を入力してください (デフォルト: root):" user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "ポート番号を入力してください (デフォルト: 22):" port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "エラー: 有効なサーバー アドレスを入力してください。" + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "エラー: ポートは 1 ~ 65535 の数値である必要があります。" + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "エラー: ユーザー名の形式が正しくありません。" + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "エラー: SSH ユーザー名の形式が正しくありません。" + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "エラー: SSH ホスト アドレスの形式が正しくありません。" + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "認証方法を選択してください:" echo "1. パスワード" @@ -6771,37 +6836,92 @@ add_connection() { case $auth_choice in 1) read -s -p "パスワードを入力してください:" password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "エラー: パスワードを空にすることはできません。" + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "キーの内容を貼り付けてください (貼り付け後に Enter を 2 回押します)。" - local password_or_key="" while IFS= read -r line; do - # 入力が空行で、キーの内容にすでに先頭が含まれている場合は、入力を終了します if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # それが最初の行である場合、またはすでにキーコンテンツの入力を開始している場合は、追加を続けます。 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # キーコンテンツかどうかを確認する - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "キーの内容が無効です!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "無効な選択です!" - return + return 1 ;; esac +} + +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "エラー: パスワードを空にすることはできません。" + done +} + +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "エラー: ポートは 1 ~ 65535 の数値である必要があります。" + done +} + +# 接続リストを表示 +list_connections() { + echo "保存された接続:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# 新しい接続を追加 +add_connection() { + send_stats "新しい接続を追加" + echo "新しい接続を作成する例:" + echo "- 接続名: my_server" + echo "- IP アドレス: 192.168.1.100" + echo "- ユーザー名: root" + echo "- ポート: 22" + echo "------------------------" + read -e -p "接続名を入力してください:" name + + kj_ssh_read_host_user_port "IP アドレスを入力してください:" "ユーザー名を入力してください (デフォルト: root):" "ポート番号を入力してください (デフォルト: 22):" "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "接続が保存されました!" } @@ -7087,7 +7207,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7134,52 +7254,23 @@ add_task() { read -e -p "タスク名を入力してください:" name read -e -p "ローカル ディレクトリを入力してください:" local_path read -e -p "リモート ディレクトリを入力してください:" remote_path - read -e -p "リモート ユーザー@IP を入力してください:" remote - read -e -p "SSH ポート (デフォルトは 22) を入力してください:" port - port=${port:-22} - echo "認証方法を選択してください:" - echo "1. パスワード" - echo "2. キー" - read -e -p "(1/2) を選択してください:" auth_choice + while true; do + read -e -p "リモート ユーザー@IP を入力してください:" remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "パスワードを入力してください:" password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "キーの内容を貼り付けてください (貼り付け後に Enter を 2 回押します)。" - local password_or_key="" - while IFS= read -r line; do - # 入力が空行で、キーの内容にすでに先頭が含まれている場合は、入力を終了します - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # それが最初の行である場合、またはすでにキーコンテンツの入力を開始している場合は、追加を続けます。 - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" + port="$KJ_SSH_PORT" - # キーコンテンツかどうかを確認する - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "キーの内容が無効です!" - return - fi - ;; - *) - echo "無効な選択です!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "同期モードを選択してください:" echo "1. 標準モード (-avz)" @@ -7198,6 +7289,7 @@ add_task() { echo "ミッションが保存されました!" } + # タスクの削除 delete_task() { send_stats "同期タスクの削除" @@ -7294,7 +7386,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモート ホストにアクセスできますか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7455,7 +7547,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -8137,10 +8229,10 @@ docker_ssh_migration() { read -e -p "移行するバックアップ ディレクトリを入力してください:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } - read -e -p "ターゲットサーバーIP:" TARGET_IP - read -e -p "ターゲットサーバーの SSH ユーザー名:" TARGET_USER - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "ターゲットサーバーIP:" "ターゲットサーバーの SSH ユーザー名 [デフォルトのルート]:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -8363,7 +8455,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9604,13 +9696,9 @@ linux_ldnmp() { read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "エラー: リモート サーバーの IP を入力してください。" - continue - fi + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -9956,18 +10044,20 @@ moltbot_menu() { echo "--------------------" echo "4. ステータスログの表示" echo "5.機種変更" - echo "6. 新しいモデル API を追加する" + echo "6. API管理" echo "7. ロボットの接続とドッキング" - echo "8. プラグイン(Feishuなど)をインストールする" - echo "9. スキルのインストール" + echo "8. プラグイン管理(インストール・削除)" + echo "9. スキル管理(設置・撤去)" echo "10. メイン設定ファイルを編集します" echo "11. 設定ウィザード" echo "12. 健全性の検出と修復" echo "13. WebUI へのアクセスと設定" echo "14. TUIコマンドラインダイアログウィンドウ" + echo "15. 記憶・記憶" echo "--------------------" - echo "15. アップデート" - echo "16. アンインストール" + echo "16. バックアップと復元" + echo "17. アップデート" + echo "18. アンインストール" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -9997,6 +10087,459 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + + + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' +import copy +import json +import os +import platform +import sys +import time +import urllib.request +from datetime import datetime, timezone + +path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ API プロバイダーが検出されず、モデルの同期がスキップされました') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models プローブは 3 回連続で失敗しました。この API プロバイダーとすべての関連モデルを削除しますか? [y/N]:" + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: デフォルトのメイン モデルはこのプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました。') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 デフォルトのプライマリ モデルは削除前に切り替えられています: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 削除前に切り替えられた {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ プロバイダー {name} が削除され、defaults.models の下の {len(removed_refs)} モデル参照が削除されました') + return True + + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): + if not isinstance(provider, dict): + summary.append(f'ℹ️ {name} をスキップ: プロバイダー構造が不正です') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ {name} をスキップ: なしbaseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 不正なプロトコル {api または "(unset)"} が見つかりました。再検出されます') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: プロトコルは自動的に {detected_api} ({detected_reason}) に修正されました') + except Exception as e: + summary.append(f'⚠️ {name}: プロトコルの検出に失敗しました。修正をスキップします ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models の検出に失敗しました。{attempts} 回再試行しました ({type(err).__name__}: {err})') + send_stat('OpenClaw API は介入を確認しました') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + else: + send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') + summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models {attempts} 回の再試行後に成功しました') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ {name} をスキップ: /models 戻り構造が認識されません') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ {name} をスキップ: ローカル モデルに有効なテンプレート モデルがありません') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新しいモデルを追加します ({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ モデルを削除します ({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} には同期後に使用可能なモデルがなく、デフォルト モデル/フォールバック モデルは保証されません。') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 デフォルトのモデルは完全に置き換えられました: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} は完全に置き換えられました: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: {len(removed_ids)} を削除、{len(added_ids)} を追加、現在の {len(new_models)}') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ モデルの同期に失敗しました: プロバイダーがあります。同期後、使用可能なモデルが存在しないため、書き込みは中止されました。') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API モデルの整合性同期が完了し、設定が書き込まれました') +else: + for line in summary: + print(line) + print('ℹ️ 同期は必要ありません: 構成はすでに上流の /models と一致しています') +PY + } + + + install_moltbot() { echo "OpenClaw のインストールを開始します..." send_stats "OpenClaw のインストールを開始します..." @@ -10013,7 +10556,9 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # ヒント: 構成を変更してすぐに有効にする必要がある場合は、ゲートウェイを再起動します: openclaw ゲートウェイの再起動 + configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10049,6 +10594,44 @@ moltbot_menu() { + # OpenClaw API プロトコル検出 (優先応答 -> 完了) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + return 0 + } + # コア機能: すべてのモデルの取得と追加 add-all-models-from-provider() { local provider_name="$1" @@ -10058,6 +10641,10 @@ moltbot_menu() { echo "🔍 取得中$provider_name利用可能なすべてのモデル..." + # API プロトコルを自動的に識別する + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # モデルリストの取得 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10133,10 +10720,11 @@ EOF # バックアップ構成 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # jq を使用してすべてのモデルを注入する + # jq を使用してすべてのモデルを挿入し、defaults.models を同期します。 jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10145,10 +10733,26 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then @@ -10162,7 +10766,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "APIの追加" + send_stats "OpenClaw API が追加されました" echo "=== OpenClaw プロバイダー (フルモデル) を対話的に追加 ===" # 1.プロバイダ名 @@ -10189,7 +10793,11 @@ EOF echo done - # 4. モデルリストの取得 + # 4. プロトコル検出 (無意味) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. モデルリストの取得 echo "🔍 利用可能なモデルのリストを取得中..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10204,10 +10812,10 @@ EOF echo "--------------------------------" # すべて表示 (シリアル番号付き) i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10216,297 +10824,2973 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 最初のモデルの使用:$default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 選択されたモデル:$default_model" else - default_model="$input_model" + default_model="$input_model" + fi + + # 6. 情報の確認 + echo + echo "====== 確認 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "デフォルトのモデル:$default_model" + echo "モデルの総数:$model_count" + echo "======================" + + read -erp "すべて追加することを確認します$model_countA model? (y/N):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ キャンセルされました" + return 1 + fi + + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 设置默认模型并重启网关..." + openclaw models set "$provider_name/$default_model" + start_gateway + echo "✅完了!全て$model_countロードされたモデル" + echo "✅ 契約は次のように自動的に識別されます。$DETECTED_API" + fi + + break_end + } + + + +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API リスト" + + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf '%b\n' "[$idx] ${name} | API: ${base_url}|合意:${api_type}|モデル数:${gl_huang}${model_count}${gl_bai}|遅延/ステータス:${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == '利用不可': + return '利用不可', 'unavailable' + if latency == '検出されませんでした': + return '検出されませんでした', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ openclaw.json が見つかりません。最初にインストール/初期化を完了してください。') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ 構成の読み取りに失敗しました: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 現在構成されている API プロバイダーはありません。') + raise SystemExit(0) + +print('MSG\t--- 構成された API リスト ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '利用不可' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '検出されませんでした' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '利用不可' + else: + latency_raw = '利用不可' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "プロバイダーによる OpenClaw API の同期" + + if [ ! -f "$config_file" ]; then + echo "❌ 設定ファイルが見つかりません:$config_file" + break_end + return 1 + fi + + read -erp "同期する API 名 (プロバイダー) を入力してください:" provider_name + if [ -z "$provider_name" ]; then + echo "❌ プロバイダー名を空にすることはできません" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ API プロバイダーが検出されず、同期できない') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ プロバイダー: {target} が見つかりません') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ プロバイダー {target} にbaseUrl/apiKey/models がないため、同期を実行できません') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'ℹ️ プロバイダー {target} の現在の api={api}、プロトコルを再検出して続行します') + provider['api'] = '' + api = '' + +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 自動修正されたプロトコル: {target} {api} ({detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ プロトコルの検出に失敗しました。修正をスキップしました: {target} ({type(e).__name__}: {e})' + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models の検出に失敗しました。{attempts} 回再試行しました ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models 返された構造は認識されません') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: 上流の /models は空です。同期は中止されました。') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: ローカル モデルには有効なテンプレート モデルがないため、新しいモデルを追加できません。') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +if added_ids: + print(f'➕ 新しいモデルを追加します ({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ モデルを削除します ({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: 同期後に使用可能なモデルがないため、書き込みが中止されました') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 デフォルトのモデルは完全に置き換えられました: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} は完全に置き換えられました: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if protocol_msg: + print(protocol_msg) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: {len(removed_ids)} を削除、{len(added_ids)} を追加、現在の {len(new_models)}') +if changed: + print('✅ 指定されたプロバイダーモデルの整合性同期が完了し、設定が書き込まれました') +else: + print('ℹ️ 同期は必要ありません。プロバイダーの構成はすでにアップストリームの /models と一致しています。') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ 同期実行が完了しました" + start_gateway + ;; + 2) + echo "❌ 同期に失敗しました: プロバイダーが存在しないか、構成されていません" + ;; + 3) + echo "❌ 同期に失敗しました: プロバイダーの構成が不完全であるか、タイプがサポートされていません" + ;; + 4) + echo "❌ 同期に失敗しました: アップストリーム /models リクエストが失敗しました" + ;; + 5) + echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" + ;; + *) + echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + ;; + esac + + break_end +} + +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ openclaw.json が見つかりません') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ プロバイダー: {name} が見つかりません') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ プロバイダー {name} に BaseUrl/apiKey がありません') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ プロバイダー {name} プロトコルを更新しました: {current_api または "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ 更新は必要ありません: プロトコルは {current_api または api} のままです') +PY +} + +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API プロトコルの修正" + + if [ ! -f "$config_file" ]; then + echo "❌ 設定ファイルが見つかりません:$config_file" + break_end + return 1 + fi + + read -erp "修復するプロトコルの API 名 (プロバイダー) を入力してください:" provider_name + if [ -z "$provider_name" ]; then + echo "❌ プロバイダー名を空にすることはできません" + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅契約はテストされ、更新されています(変更される可能性があります)" + start_gateway + ;; + 2) + echo "❌ 修復に失敗しました: プロバイダーが存在しないか、構成されていません" + ;; + 3) + echo "❌ 修復に失敗しました: プロバイダーの構成が不完全です" + ;; + *) + echo "❌ 修復に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + ;; + esac + + break_end +} + + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API エントリの削除" + + if [ ! -f "$config_file" ]; then + echo "❌ 設定ファイルが見つかりません:$config_file" + break_end + return 1 + fi + + read -erp "削除するAPI名(プロバイダー)を入力してください:" provider_name + if [ -z "$provider_name" ]; then + send_stats "OpenClaw API 削除 キャンセル" + echo "❌ プロバイダー名を空にすることはできません" + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ プロバイダー: {name} が見つかりません') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ 削除は中止されました: デフォルトのメイン モデルはプロバイダーを指しており、使用可能な代替モデルはありません') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 デフォルトのプライマリ モデルの切り替え: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 削除は中止されました: {fk} はプロバイダーを指しており、使用可能な代替モデルはありません') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} スイッチ: {val} -> {replacement}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ 削除されたプロバイダー: {name}') +print(f'🧹defaults.models 内の {len(removed_refs)} に関連するモデル参照をクリーンアップしました') +PY + local rc=$? + case "$rc" in + 0) + send_stats "OpenClaw APIの削除確認" + echo "✅削除完了" + start_gateway + ;; + 2) + echo "❌ 削除に失敗しました: プロバイダーが存在しません" + ;; + 3) + send_stats "OpenClaw API 削除 キャンセル" + echo "❌ 削除に失敗しました: 代替モデルはありません。元の構成は維持されています。" + ;; + *) + echo "❌ 削除に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "OpenClaw APIの入口" + while true; do + clear + echo "=======================================" + echo "OpenClaw API 管理" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. APIの追加" + echo "2. APIプロバイダーモデルリストを同期する" + echo "3. APIの削除" + echo "4. プロトコルの修復/再検出" + echo "0.終了" + echo "---------------------------------------" + read -erp "選択肢を入力してください:" api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + sync-openclaw-provider-interactive + ;; + 3) + delete-openclaw-provider-interactive + ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done + } + + + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "機種変更" + + local orange="#FF8C00" + + clear + + while true; do + local models_raw models_list default_model model_count selected_model + + # 構成ファイルからモデル キーを読み取ります (openclaw モデル リストを呼び出すことなく) + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + echo "モデルのリストを取得できませんでした: 構成ファイルに Agents.defaults.models が見つかりません。" + break_end + return 1 + fi + + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # 構成ファイルからデフォルトのモデルを読み取ります (高速)。失敗時に openclaw コマンドにフォールバックする + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + [ -z "$default_model" ] && default_model="(unknown)" + + + install_gum + install gum + + clear + + # ガムが存在しない場合は、元の手動入力プロセスにダウングレードします (以前とまったく同じままです)。 + if ! command -v gum >/dev/null 2>&1; then + echo "---モデル管理---" + echo "現在入手可能なモデル:" + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' + echo "----------------" + read -e -p "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" selected_model + + # 1.終了するには0を入力したかどうかを確認します + if [ "$selected_model" = "0" ]; then + echo "操作がキャンセルされました。終了しています..." + break # 跳出 while 循环 + fi + + # 2. 入力が空であることを確認します + if [ -z "$selected_model" ]; then + echo "エラー: モデル名を空にすることはできません。もう一度試してください。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + else + gum style --foreground "$orange" --bold "モデル管理" + gum style --foreground "$orange" "利用可能なモデル (認証=はい):${model_count}" + gum style --foreground "$orange" "現在のデフォルト:${default_model}" + echo "" + + # ボトムチップ + gum style --faint "↑↓ 選択 / Enter で確認 / Esc で終了" + echo "" + + # ガムフィルター: 検索付き;ガムのバージョンは大きく異なります。ここでは最も互換性のあるフラグのみが使用されます + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "モデルの検索 (cli-api/gpt-5.2 など)" \ + --prompt "モデルを選択 >" \ + --indicator "➜ " \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor-text.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 35) + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then + echo "操作がキャンセルされました。終了しています..." + break + fi + fi + + # 番号の接頭辞を削除します: 「(10) モデル」 -> 「モデル」 + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + + # スイッチの実行 + echo "切り替わる機種は以下の通りです。$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切り替えに失敗しました: openclaw モデル セットがエラーを返しました。" + break_end + return 1 + fi + start_gateway + + break_end + done + } + + + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 同期された plugins.allow ホワイトリスト:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 同期された plugins.allow ホワイトリスト:$plugin_id" + return 0 + fi + fi + + echo "⚠️ プラグインはインストールされましたが、plugins.allow の同期に失敗しました。手動で確認してください:$config_file" + return 1 + } + + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ plugins.allow から削除されました:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ plugins.allow から削除されました:$plugin_id" + return 0 + fi + fi + + echo "⚠️ plugins.allow の削除に失敗しました。手動で確認してください:$config_file" + return 1 + } + + + + + + + install_plugin() { + send_stats "プラグイン管理" + while true; do + clear + echo "========================================" + echo "プラグイン管理(インストール/削除)" + echo "========================================" + echo "現在のプラグインのリスト:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推奨される一般的に使用されるプラグイン ID (括弧内の ID をコピーするだけです):" + echo "--------------------------------------------------------" + echo "📱 コミュニケーションチャネル:" + echo "- [フェイシュ] #フェイシュ/ラーク統合" + echo "- [電報] #電報ボット" + echo "- [slack] #Slack コーポレートコミュニケーション" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] #Discordコミュニティ運営" + echo "- [whatsapp] #WhatsApp オートメーション" + echo "" + echo "🧠 メモリと AI:" + echo "- [memory-core] # 基本メモリ (ファイル取得)" + echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" + echo "- [copilot-proxy] # コパイロットインターフェイスの転送" + echo "" + echo "⚙️機能拡張:" + echo "- [lobster] # 承認フロー(手動確認あり)" + echo "- [voice-call] # 音声通話機能" + echo "- [nostr] # 暗号化されたプライベートチャット" + echo "--------------------------------------------------------" + + echo "1) プラグインのインストール/有効化" + echo "2) プラグインの削除/無効化" + echo "0) 戻る" + read -e -p "アクションを選択してください:" plugin_action + + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "プラグイン ID を入力してください (スペースで区切って、終了するには 0 を入力してください):" raw_input + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 プラグインのステータスを確認する:$plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡プラグイン [$plugin_id] プリインストールされており、アクティベート中..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 プラグインがシステムの組み込みディレクトリに存在することがわかりました。直接有効にしてみてください..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + echo "📥 ローカルに見つかりません。ダウンロードしてインストールしてください:$plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ ダウンロードに成功しました。アクティブ化しています..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ インストールに失敗しました:$plugin_full" + failed_list="$failed_list $plugin_id" + fi + else + echo "🗑️ プラグインの削除/無効化:$plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ アンインストール済み:$plugin_id" + else + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" + fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true + fi + done + + echo "" + echo "====== 操作概要 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + start_gateway + fi + break_end + done + } + + + install_skill() { + send_stats "スキル管理" + while true; do + clear + echo "========================================" + echo "スキル管理(インストール/削除)" + echo "========================================" + echo "現在インストールされているスキル:" + openclaw skills list + echo "----------------------------------------" + + # 推奨実践スキルリストを出力 + echo "推奨される実践スキル (名前を直接コピーして入力できます):" + echo "github # GitHub の問題/PR/CI を管理する (gh CLI)" + echo "notion # Notion のページ、データベース、ブロックを操作する" + echo "apple-notes # macOS ネイティブのノート管理 (作成/編集/検索)" + echo "apple-reminders # macOS リマインダー管理 (ToDo リスト)" + echo "1password # 1Password キーの読み取りと挿入を自動化します" + echo "gog # Google Workspace (Gmail/クラウド ディスク/ドキュメント) 万能アシスタント" + echo "things-mac # Things 3 タスク管理の緊密な統合" + echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" + echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "openhue # Philips Hue スマート照明シーンを制御する" + echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" + echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" + echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" + echo "----------------------------------------" + + echo "1) 取り付けスキル" + echo "2) スキルの削除" + echo "0) 戻る" + read -e -p "アクションを選択してください:" skill_action + + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue + + read -e -p "スキル名を入力してください (スペースで区切って、終了するには 0 を入力してください):" skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + if [ "$skill_action" = "2" ]; then + read -e -p "二次確認: 削除はユーザー ディレクトリ ~/.openclaw/workspace/skills にのみ影響します。続けてもよろしいですか? (y/N):" confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "削除がキャンセルされました。" + break_end + continue + fi + fi + + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "スキル [$skill_name] すでにインストールされていますが、再インストールしますか? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "スキルのインストール:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ スキル$skill_nameインストールが成功しました。" + success_list="$success_list $skill_name" + changed=true + else + echo "❌ インストールに失敗しました:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ スキルの削除:$skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ ユーザースキルディレクトリが削除されました:$skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ ユーザー スキル ディレクトリが見つかりません:$skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== 操作概要 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + start_gateway + fi + break_end + done + } + +openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + + # 2 つの一般的なディレクトリ名と互換性があります。 + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # 無知な部分文字列を避け、完全一致と openclaw プレフィックス一致を優先します。 + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "異常な" + elif [ "$enabled" != "true" ]; then + echo "有効になっていません" + elif [ "$connected" = "true" ]; then + echo "接続済み" + elif [ "$configured" = "true" ]; then + echo "設定済み" + else + echo "未設定" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "ローカル ステータス (ローカル構成/キャッシュのみ、ネットワーク検出なし):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "ヒバリ" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + + change_tg_bot_code() { + send_stats "ロボットドッキング" + while true; do + clear + echo "========================================" + echo "ロボットの接続とドッキング" + echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" + echo "1. テレグラムロボットドッキング" + echo "2.フェイシュ(ヒバリ)ロボットドッキング" + echo "3. WhatsApp ボットのドッキング" + echo "----------------------------------------" + echo "0. 前のメニューに戻る" + echo "----------------------------------------" + read -e -p "選択肢を入力してください:" bot_choice + + case $bot_choice in + 1) + read -e -p "TG ロボットが受信した接続コード (NYA99R2F など) を入力してください (終了するには 0 を入力します)。" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Feishu Robot が受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done + } + + + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null + ) || { echo "❌ sha256 検証が失敗し、復元が拒否されました"; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw メモリの完全バックアップ" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ ワークスペース ディレクトリが見つかりません:$workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "AGENTS/USER/SOUL/TOOLS ファイルは付属していますか? (y/N):" include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ バックアップメモリ​​ファイルが見つかりません" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ メモリ全体のバックアップが完了しました:$out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ フルメモリバックアップに失敗しました" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_input file_path backup_root + echo "$prompt_text" >&2 + + echo "まず scp/sftp 経由でバックアップ パッケージをサーバーにアップロードし、次にパスを入力します。" >&2 + echo "scp の例: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 + echo "ヒント: ファイル名を入力すると、デフォルトではバックアップ ディレクトリ内で検索されます。 / を含むパスを入力すると、フルパスで検証されます。" >&2 + read -e -p "バックアップ ファイル名またはパスを入力してください:" file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ バックアップ ファイルが存在しません:$file_path" >&2 + echo "" + return 1 + fi + + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw メモリ完全復元" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "復元前に、タイプ検証 + sha256 検証 + パス ホワイトリスト検証が実行されます。") + [ -z "$archive_path" ] && { echo "❌ バックアップ パスが入力されていません"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ 違法または無許可のパスが検出されました:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 復元は中止されました: 安全でないパスが存在します" + break_end + return 1 + fi + + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ 完全なメモリ復元が完了しました" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw プロジェクトのバックアップ" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ OpenClaw ルート ディレクトリが見つかりません:$openclaw_root" + break_end + return 1 + fi + + echo "バックアップモード:" + echo "1. セーフ モード (デフォルト、推奨): ワークスペース + openclaw.json + 拡張機能/スキル/プロンプト/ツール (存在する場合)" + echo "2. 完全モード (より多くの状態が含まれ、機密性のリスクが高くなります)" + read -e -p "バックアップ モードを選択してください (デフォルト 1):" export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ バックアップ可能な OpenClaw プロジェクト コンテンツが見つかりません" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw プロジェクトのバックアップが完了しました (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw プロジェクトのバックアップに失敗しました" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw プロジェクトの復元" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ リスクの高い操作: プロジェクトを復元すると、OpenClaw 構成とワークスペースのコンテンツが上書きされます。" + echo "⚠️マニフェスト/sha256の検証、ホワイトリストの復元、ゲートウェイのシャットダウン、ヘルスチェックが復元前に実行されます。" + read -e -p "続行するには、確認の単語 [リスクが高いことを承知しており、復元を続行します] を入力してください:" confirm_text + if [ "$confirm_text" != "高いリスクを認識しており、復旧を続けています" ]; then + echo "❌ 確認ワードが一致しなかったため、リストアはキャンセルされました。" + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "OpenClaw プロジェクトのバックアップ パッケージのパスを入力してください") + [ -z "$archive_path" ] && { echo "❌ バックアップ パスが入力されていません"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ 違法または無許可のパスが検出されました:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 復元は中止されました: 安全でないパスが存在します" + break_end + return 1 + fi + + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ 復元する前に OpenClaw ゲートウェイを停止してください..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ 復元後に OpenClaw ゲートウェイを起動します..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 ゲートウェイのヘルスチェック:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw プロジェクトの復元が完了しました" + break_end + } + + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "メモリバックアップファイル" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "プロジェクトのバックアップファイル" + else + echo "その他のバックアップファイル" + fi + } + + openclaw_backup_collect_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + local has_memory=0 has_project=0 has_other=0 + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + + echo "バックアップディレクトリ:$backup_root" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "まだバックアップファイルがありません" + return 0 + fi + + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "メモリバックアップファイル") has_memory=1 ;; + "プロジェクトのバックアップファイル") has_project=1 ;; + "その他のバックアップファイル") has_other=1 ;; + esac + done + + if [ "$has_memory" -eq 1 ]; then + echo "メモリバックアップファイル" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "メモリバックアップファイル" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "プロジェクトのバックアップファイル" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "プロジェクトのバックアップファイル" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "その他のバックアップファイル" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "その他のバックアップファイル" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + } + + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw はバックアップ ファイルを削除します" + local backup_root backup_root_real user_input target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "削除するファイル名またはフルパスを入力してください (キャンセルするには 0):" user_input + if [ "$user_input" = "0" ]; then + echo "削除がキャンセルされました。" + break_end + return 0 + fi + if [ -z "$user_input" ]; then + echo "❌ 入力を空にすることはできません。" + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ 範囲外のパス: バックアップ ルート ディレクトリ内のファイルのみを削除できます。" + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ 対象のファイルが存在しません:$target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ ターゲットファイルは現在のバックアップリストにありません。" + break_end + return 1 + fi + + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "削除されようとしています: [$target_type] $target_path" + read -e -p "最初の確認: 「yes」と入力して確認し、続行します。" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "削除がキャンセルされました。" + break_end + return 0 + fi + read -e -p "2 番目の確認: 「DELETE」と入力して削除します。" confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "削除がキャンセルされました。" + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ 削除が成功しました:$target_file" + else + echo "❌ 削除に失敗しました:$target_file" + fi + break_end + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list + break_end + } + + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } + + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ インデックス ライブラリ ファイルが見つかりませんでした。空であるか、存在しない可能性があります。" + echo "生の値を保存: ${store_raw:-}" + echo "インデックスの再作成は引き続き実行されます。" + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ インデックスのバックアップ:$backup_file" + else + echo "⚠️ インデックスのバックアップに失敗しました。再構築を続けてください。" + fi + fi + openclaw memory index --force + openclaw gateway restart + echo "✅ インデックスが再構築され、ゲートウェイが自動的に再起動されました。" + echo "" + openclaw_memory_render_status + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ ワークスペースのパスを取得できませんでした。ディレクトリの修復はスキップされました。" + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 メモリ ディレクトリは存在しないため、自動的に作成されます。$memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "ステータスの取得に失敗しました" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^プロバイダ: /基礎となるソリューション: /' -e 's/^Vector: /Vector ライブラリのステータス: /' -e 's/^インデックス付き: /含まれるファイル: /') + if [ -z "$status_lines" ]; then + echo "インストールされていない/起動されていない" + else + echo "$status_lines" + fi + fi + } + + openclaw_memory_get_backend() { + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi + } + + openclaw_memory_get_local_model_path() { + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then + echo "true" + return + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMDが利用可能です") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMDが検出されませんでした") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("ローカル モデル パス:$model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("ローカル モデル パスが構成されていません") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("ローカルモデルファイルが存在します") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("モデルは HF ダウンロード ソースからのものです (中国では遅い/失敗する可能性があります)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("ローカル モデル ファイルが存在しないか、使用できません") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("ハグフェイス.co にアクセスできます") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com にアクセスできます") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com にアクセスできない可能性があります (国内/制限付きネットワークの疑い)") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ Curl または wget が検出されず、ダウンロードできません。" + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ sqlite3 が検出されない場合、QMD が正しく機能しない可能性があります。" + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 が利用可能: ${ver:-unknown}" + echo "ℹ️ sqlite 拡張機能のサポートは確実に検出できないため、継続されます。" + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ パンはすでに存在します" + return 0 + fi + echo "⬇️バンをインストール..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌curl または wget が検出されないため、bun をインストールできません。" + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅パンの取り付けが完了しました" + return 0 + fi + echo "❌ バンのインストールに失敗しました" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd はすでに存在します:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ bun 経由で qmd をインストールします。$qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd のインストールに失敗しました" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd のインストールが完了しました:$qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ 環境準備完了" + echo "スキーム: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "モード: 設定の書き込みのみ (インストールされない/ダウンロードされない)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "インデックス: 実行されました" + else + echo "インデックス: スキップされました" + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "再起動: 実行されました" + else + echo "再起動: スキップされました" + fi + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "モデル:$OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "エリア:$OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "ダウンロードソース:$OPENCLAW_MEMORY_HF_BASE" + fi + echo "最終ステータス:" + openclaw_memory_render_status + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "自動デプロイメントが実行されようとしています (冗長モード)" + echo "対象プラン:$scheme_label" + echo "地域: ${OPENCLAW_MEMORY_COUNTRY:-不明}" + echo "ミラーソース検出:huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "ダウンロード ソース: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "推定ダウンロード パス:$OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "考えられるトラフィック/ディスク使用量:$OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" + fi + echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" + echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "自動デプロイがキャンセルされました。" + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ 構成の書き込みのみを選択し、インストールやダウンロードは行いません" + else + echo "✅ インデックスが自動的に構築され、ゲートウェイが再起動されます。" + fi + return 0 + } + + openclaw_memory_auto_setup_qmd() { + echo "🔍 QMD環境を検出" + openclaw_memory_cleanup_legacy_keys + openclaw_memory_check_sqlite || true + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) + else + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅memory.backendはすでにqmdです" + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅memory.backend=qmdが設定されています" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅memory.qmd.commandに書き込まれます:$OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅memory.qmd.commandは正しいです" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 ウォームインデックス (おそらくダウンロードモデル)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 予熱をスキップしました" + fi + echo "✅ QMD自動展開が完了しました" + } + + openclaw_memory_auto_setup_local() { + echo "🔍 ローカル環境を検出" + openclaw_memory_cleanup_legacy_keys + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅memory.backendはすでに組み込まれています" + else + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅memory.backend=builtinが設定されています" + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅memorySearch.providerはすでにローカルです" + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ Agents.defaults.memorySearch.provider=ローカルセット" + fi + + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ モデルファイルはすでに存在します:$model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ 書き込み専用構成モード: モデルのダウンロードをスキップ" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + else + if [ -f "$model_dest" ]; then + echo "✅ デフォルトのモデルファイルが見つかりました:$model_dest" + else + echo "⬇️ ダウンロードモデル:$model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ モデルがダウンロードされました:$model_dest" + fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ モデルパスが記述されている" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 ウォームインデックス (おそらくダウンロードモデル)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 予熱をスキップしました" + fi + echo "✅ ローカル自動展開が完了しました" + } + + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd インストールディレクトリ)" + OPENCLAW_MEMORY_EXPECT_SIZE="約20~50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="約350~600MB" + ;; + *) + echo "❌ 不明な解決策:$scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ OpenClaw ゲートウェイを再起動します" + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" + openclaw_memory_render_auto_summary + return 0 + } + + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "メモリソリューションの自動導入" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3.オート(自動選択)" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done + } + + openclaw_memory_apply_scheme() { + local scheme="$1" + openclaw_memory_cleanup_legacy_keys + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ 設定の書き込みに失敗しました" + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "builtin" + if [ $? -ne 0 ]; then + echo "❌ 設定の書き込みに失敗しました" + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ 不明な解決策:$scheme" + return 1 + esac + echo "✅ メモリスキーム構成が更新されました" + return 0 + } + + openclaw_memory_offer_restart() { + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart fi + } - # 6. 情報の確認 - echo - echo "====== 確認 ======" - echo "Provider : $provider_name" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "デフォルトのモデル:$default_model" - echo "モデルの総数:$model_count" - echo "======================" - - read -erp "すべて追加することを確認します$model_countモデル? (y/N):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ キャンセルされました" + openclaw_memory_fix_index() { + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ 現在のスキームは QMD として検出されますが、qmd コマンドがインストールされていません。" + echo "ローカルに切り替えるか、bun + qmd をインストールして再試行してください。" + fi + echo "適用可能なシナリオ: インデックス付きの分子 > 分母 (収集を繰り返すと異常なカウントが発生します)" + read -e -p "includeDefaultMemory を false に設定してもよろしいですか? (y/N):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "キャンセル。" + break_end + return 0 + fi + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false + if [ $? -ne 0 ]; then + echo "❌ 設定の書き込みに失敗しました" + break_end return 1 fi - - install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" - - if [[ $? -eq 0 ]]; then - echo - echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." - openclaw models set "$provider_name/$default_model" - start_gateway - echo "✅完了!全て$model_countロードされたモデル" + echo "✅ includeDefaultMemory=false セット" + echo "推奨される実行: インデックスをクリーンアップして再構築する" + read -e -p "インデックスをクリーンして再構築しますか (推奨)? (はい/いいえ):" rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_safe + else + echo "ステータスは後でメモリ管理で確認できます。" fi - break_end } - - - change_model() { - send_stats "機種変更" - + openclaw_memory_scheme_menu() { while true; do clear - echo "---モデル管理---" - echo "すべてのモデル:" - openclaw models list --all - echo "----------------" - echo "現在のモデル:" - openclaw models list - echo "----------------" - read -e -p "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" model - - # 1.終了するには0を入力したかどうかを確認します - if [ "$model" = "0" ]; then - echo "操作がキャンセルされました。終了しています..." - break # 跳出 while 循环 - - fi - - # 2. 入力が空であることを確認します - if [ -z "$model" ]; then - echo "エラー: モデル名を空にすることはできません。もう一度試してください。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 - fi - - # 3. スイッチングロジックの実行 - echo "切り替わる機種は以下の通りです。$model ..." - openclaw models set "$model" - - break_end + echo "=======================================" + echo "OpenClaw メモリ ソリューション" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + builtin|local) current_label="Local" ;; + *) current_label="未設定" ;; + esac + echo "現在の計画:$current_label" + echo "" + echo "QMD: qmd コマンドに依存する軽量インデックス (ネットワーク制約に適しています)" + echo "ローカル: 埋め込みモデル ファイルに依存するローカル ベクトル取得" + echo "自動: 自動推奨 (可用性 + ネットワーク検出に基づく)" + echo "---------------------------------------" + echo "1. QMD の切り替え (自動展開/既にインストールされている場合はスキップ)" + echo "2. ローカルに切り替えます (自動展開/既にインストールされている場合はスキップ)" + echo "3. Auto (自動推奨と自動デプロイ)" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac done - } + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "メモリファイルが見つかりません。" + return 0 + fi + echo "番号 |相対パス |サイズ |修正時間" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } - - install_plugin() { - send_stats "プラグインのインストール" - while true; do - clear - echo "========================================" - echo "プラグイン管理(インストール)" - echo "========================================" - echo "現在のプラグインのリスト:" - openclaw plugins list - echo "--------------------------------------------------------" - echo "推奨される一般的に使用されるプラグイン ID (括弧内の ID をコピーするだけです):" - echo "--------------------------------------------------------" - echo "📱 コミュニケーションチャネル:" - echo "- [フェイシュ] #フェイシュ/ラーク統合" - echo "- [電報] #電報ボット" - echo "- [slack] #Slack コーポレートコミュニケーション" - echo " - [msteams] # Microsoft Teams" - echo "- [discord] #Discordコミュニティ運営" - echo "- [whatsapp] #WhatsApp オートメーション" - echo "" - echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル検索)" - echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" - echo "- [copilot-proxy] # コパイロットインターフェイスの転送" - echo "" - echo "⚙️機能拡張:" - echo "- [lobster] # 承認フロー(手動確認あり)" - echo "- [voice-call] # 音声通話機能" - echo "- [nostr] # 暗号化されたプライベートチャット" - echo "--------------------------------------------------------" - - read -e -p "プラグイン ID を入力してください (終了するには 0 を入力してください):" raw_input - - [ "$raw_input" = "0" ] && break - [ -z "$raw_input" ] && continue - - # 1. 自動処理: ユーザー入力に @openclaw/ が含まれている場合、パスのチェックを容易にするために純粋な ID を抽出します。 - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') - local plugin_full="$raw_input" - - echo "🔍 プラグインのステータスを確認しています..." - # ステータス検出用の現在のプラグイン リストを取得する - local plugin_list=$(openclaw plugins list 2>/dev/null) - - # 2. すでにリストに含まれていて無効になっているかどうかを確認します (最も一般的なケース)。 - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡プラグイン [$plugin_id] プリインストールされており、アクティベート中..." - openclaw plugins enable "$plugin_id" && echo "✅アクティベーション成功" || echo "❌ アクティベーションに失敗しました" - - # 3. システムの物理ディレクトリが存在するかどうかを確認します - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 プラグインがシステムの組み込みディレクトリに存在することがわかりました。直接有効にしてみてください..." - openclaw plugins enable "$plugin_id" - + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ ファイルが存在しません:$file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=120 + local start_line count + echo "書類:$file" + echo "総行数:$total_lines" + read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 else - # 4. リモートインストールロジック - echo "📥 ローカルに見つかりません。ダウンロードしてインストールしてください..." - - # 失敗した古い残骸をクリーンアップする - rm -rf "/root/.openclaw/extensions/$plugin_id" - - # インストールを実行し、結果を取得します - if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードに成功しました。アクティブ化しています..." - openclaw plugins enable "$plugin_id" - else - echo "⚠️ 公式チャネルからのダウンロードに失敗しました。代替手段をお試しください..." - # 代替の npm インストール - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm が正常にインストールされました。有効にしてみてください..." - openclaw plugins enable "$plugin_id" - else - echo "❌ 致命的なエラー: プラグインを取得できません。 IDが正しいか、ネットワークが利用可能か確認してください。" - # 重要: 構成のハードコーディングを防ぐために、以下の start_gateway を使用する代わりに、ここに直接戻るか続行します。 - break_end - continue - fi - fi + start_line=$((total_lines - count + 1)) fi - - echo "🔄 新しいプラグインをロードするために OpenClaw サービスを再起動しています..." - start_gateway - break_end - done + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ 有効な番号を入力してください。" + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ 行数は 0 より大きくなければなりません。" + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(空のファイル)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" } - - - - - - - install_skill() { - send_stats "取り付けスキル" + openclaw_memory_files_menu() { while true; do clear - echo "========================================" - echo "スキル管理(インストール)" - echo "========================================" - echo "現在インストールされているスキル:" - openclaw skills list - echo "----------------------------------------" - - # 推奨実践スキルリストを出力 - echo "推奨される実践スキル (名前を直接コピーして入力できます):" - echo "github # GitHub の問題/PR/CI を管理する (gh CLI)" - echo "notion # Notion のページ、データベース、ブロックを操作する" - echo "apple-notes # macOS ネイティブのノート管理 (作成/編集/検索)" - echo "apple-reminders # macOS リマインダー管理 (ToDo リスト)" - echo "1password # 1Password キーの読み取りと挿入を自動化します" - echo "gog # Google Workspace (Gmail/クラウド ディスク/ドキュメント) 万能アシスタント" - echo "things-mac # Things 3 タスク管理の緊密な統合" - echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" - echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンを制御する" - echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" - echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" - echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" - echo "----------------------------------------" - - # ユーザーにスキル名の入力を求める - read -e -p "インストールするスキルの名前を入力してください (終了するには 0 を入力してください):" skill_name - - # 1.終了するには0を入力したかどうかを確認します - if [ "$skill_name" = "0" ]; then - echo "操作がキャンセルされ、スキルのインストールが終了しました。" - break + echo "=======================================" + echo "OpenClaw メモリ ファイル" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "表示するファイル番号を入力してください (0 を返します):" file_choice + if [ "$file_choice" = "0" ]; then + return 0 fi - - # 2. 入力が空であることを確認します - if [ -z "$skill_name" ]; then - echo "エラー: スキル名を空にすることはできません。もう一度試してください。" - echo "" + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "選択が無効です。もう一度お試しください。" + sleep 1 continue fi - - # 3. スキルがインストールされているか確認する - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" - skill_found=true - fi - - if [ "$skill_found" = true ]; then - read -e -p "再インストールしますか? (y/N):" reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "インストールをスキップします。" - break_end - continue - fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "メモリ ファイルが見つかりません。Enter キーを押して戻ります..." + return 0 fi - - # 4. インストールコマンドを実行します。 - echo "スキルのインストール:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ スキル$skill_nameインストールが成功しました。" - start_gateway - else - echo "❌ インストールに失敗しました。スキル名が正しいか確認するか、ドキュメントを参照してトラブルシューティングを行ってください。" + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "番号が無効です。もう一度お試しください。" + sleep 1 + continue fi - - break_end - done + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "Enter キーを押してリストに戻ります..." + done } - - - change_tg_bot_code() { - send_stats "ロボットドッキング" + openclaw_memory_menu() { + send_stats "OpenClaw のメモリ管理" while true; do clear - echo "========================================" - echo "ロボットの接続とドッキング" - echo "========================================" - echo "1. テレグラムロボットドッキング" - echo "2.フェイシュ(ヒバリ)ロボットドッキング" - echo "3. WhatsApp ボットのドッキング" - echo "----------------------------------------" - echo "0. 前のメニューに戻る" - echo "----------------------------------------" - read -e -p "選択肢を入力してください:" bot_choice - - case $bot_choice in + echo "=======================================" + echo "OpenClaw のメモリ管理" + echo "=======================================" + openclaw_memory_render_status + echo "1. メモリインデックスを更新する" + echo "2. メモリファイルを表示する" + echo "3. インデックス修復(インデックス例外)" + echo "4. メモリ ソリューション (QMD/ローカル/自動)" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" memory_choice + case "$memory_choice" in 1) - read -e -p "TG ロボットが受信した接続コード (NYA99R2F など) を入力してください (終了するには 0 を入力します)。" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi - openclaw pairing approve telegram "$code" - break_end + echo "メモリインデックスは間もなく更新されます。" + read -e -p "最初の確認: 「yes」と入力して続行します:" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "キャンセル。" + break_end + continue + fi + openclaw_memory_prepare_workspace + read -e -p "2 番目の確認: 全額を使用するには、force を入力します (増分の場合は空白のままにします):" confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ 完全な再構築はより徹底的ですが、時間がかかります。" + echo "推奨事項: 安全に再構築するには、再構築を入力してください (最初にインデックス データベースをバックアップします)。" + read -e -p "3 番目の確認: 安全な再構築を実行するには、「再構築」と入力します。 Enter キーを押して通常の力で続行します。" confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe + else + openclaw memory index --force + openclaw gateway restart + echo "✅ インデックスが再構築され、ゲートウェイが自動的に再起動されました。" + fi + else + openclaw memory index + fi + break_end ;; 2) - read -e -p "Feishu Robot が受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" - break_end + openclaw_memory_files_menu ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi - openclaw pairing approve whatsapp "$code" - break_end + openclaw_memory_fix_index + ;; + 4) + openclaw_memory_scheme_menu ;; 0) return 0 @@ -10519,11 +13803,47 @@ EOF done } + openclaw_backup_restore_menu() { + + send_stats "OpenClaw のバックアップと復元" + while true; do + clear + echo "=======================================" + echo "OpenClaw のバックアップと復元" + echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" + echo "1. メモリ全体をバックアップする" + echo "2. メモリ全体を復元する" + echo "3. OpenClaw プロジェクトをバックアップします (デフォルトのセーフ モード)" + echo "4. OpenClaw プロジェクトの復元 (高度/高リスク)" + echo "5. バックアップファイルを削除する" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; + 0) return 0 ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done + } + update_moltbot() { echo "OpenClaw を更新..." send_stats "OpenClaw を更新..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -10548,7 +13868,7 @@ EOF } nano_openclaw_json() { - send_stats "OpenClaw 構成ファイルを編集する" + send_stats "OpenClaw 設定ファイルを編集する" install nano nano ~/.openclaw/openclaw.json start_gateway @@ -10703,7 +14023,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; @@ -10714,6 +14034,12 @@ EOF ;; 12) send_stats "健全性の検出と修復" openclaw doctor --fix + send_stats "OpenClaw API の同期トリガー" + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API モデルの同期に失敗しました。ゲートウェイの再起動は中止されました。プロバイダー/モデルを確認し、戻ってからもう一度お試しください。" + fi break_end ;; 13) openclaw_webui_menu ;; @@ -10721,8 +14047,10 @@ EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done @@ -10833,7 +14161,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール${gl_kjlan}112. ${color112}Lucky 大規模イントラネット侵入ツール" - echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ${gl_kjlan}114. ${color114}ClawdBot/Moltbot ロボット${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ${gl_kjlan}114. ${color114}OpenClaw ボット管理ツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" echo -e "${gl_kjlan}あなたのアプリをここに表示したいですか?開発者ガイドを確認してください。${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -11058,7 +14386,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "ネザ監視$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -11067,7 +14395,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -12003,7 +15331,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -12635,7 +15963,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -14516,14 +17844,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - read -e -p "リモートサーバーのIPを入力してください:" remote_ip - read -e -p "ターゲット サーバーの SSH ポート [デフォルト 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "エラー: リモート サーバーの IP を入力してください。" - continue - fi + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -14547,7 +17870,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリのバックアップ" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14610,7 +17933,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -14620,7 +17943,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -15018,7 +18341,7 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "続行するには Enter キーを押してください..." @@ -15549,8 +18872,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -15772,7 +19095,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -16585,26 +19908,13 @@ linux_file() { continue fi - read -e -p "リモートサーバーのIPを入力してください:" remote_ip - if [ -z "$remote_ip" ]; then - echo "エラー: リモート サーバーの IP を入力してください。" - send_stats "ファイル転送に失敗しました: リモート サーバー IP が入力されていません" - continue - fi - - read -e -p "リモート サーバーのユーザー名 (デフォルトの root) を入力してください:" remote_user - remote_user=${remote_user:-root} - - read -e -p "リモートサーバーのパスワードを入力してください:" -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "エラー: リモート サーバーのパスワードを入力してください。" - send_stats "ファイル転送に失敗しました: リモートサーバーのパスワードが入力されていません" - continue - fi + kj_ssh_read_host_user_port "リモートサーバーのIPを入力してください:" "リモート サーバーのユーザー名 (デフォルトの root) を入力してください:" "ログイン ポートを入力してください (デフォルトは 22):" "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "ログイン ポートを入力してください (デフォルトは 22):" remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "リモートサーバーのパスワードを入力してください:" + local remote_password="$KJ_SSH_PASSWORD" # 既知のホストの古いエントリをクリアする ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16700,7 +20010,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -16738,7 +20048,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -16822,7 +20132,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 87634f982..3338d91e5 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.7" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -502,22 +502,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker restart $dockername ;; 6) @@ -1846,7 +1846,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -4100,7 +4100,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4162,7 +4162,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4773,7 +4773,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4977,7 +4977,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5838,7 +5838,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5951,7 +5951,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정하세요── + # ──장면에 따라 매개변수를 설정합니다── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6738,30 +6738,95 @@ linux_backup() { -# 연결 목록 표시 -list_connections() { - echo "저장된 연결:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH 입력 정규화 기능 +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# 새 연결 추가 -add_connection() { - send_stats "새 연결 추가" - echo "새 연결 생성의 예:" - echo "- 연결 이름: my_server" - echo "- IP 주소: 192.168.1.100" - echo "- 사용자 이름: 루트" - echo "- 포트: 22" - echo "------------------------" - read -e -p "연결 이름을 입력하세요:" name - read -e -p "IP 주소를 입력하세요:" ip - read -e -p "사용자 이름을 입력하십시오(기본값: 루트):" user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "포트 번호를 입력하십시오(기본값: 22):" port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "오류: 유효한 서버 주소를 입력하세요." + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "오류: 사용자 이름 형식이 잘못되었습니다." + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "오류: SSH 사용자 이름 형식이 잘못되었습니다." + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "오류: SSH 호스트 주소 형식이 잘못되었습니다." + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "인증 방법을 선택하세요:" echo "1. 비밀번호" @@ -6771,37 +6836,92 @@ add_connection() { case $auth_choice in 1) read -s -p "비밀번호를 입력하세요:" password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "오류: 비밀번호는 비워둘 수 없습니다." + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." - local password_or_key="" while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # 핵심 내용인지 확인해보세요 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "잘못된 키 콘텐츠입니다!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "잘못된 선택입니다!" - return + return 1 ;; esac +} + +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "오류: 비밀번호는 비워둘 수 없습니다." + done +} + +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." + done +} + +# 연결 목록 표시 +list_connections() { + echo "저장된 연결:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# 새 연결 추가 +add_connection() { + send_stats "새 연결 추가" + echo "새 연결 생성의 예:" + echo "- 연결 이름: my_server" + echo "- IP 주소: 192.168.1.100" + echo "- 사용자 이름: 루트" + echo "- 포트: 22" + echo "------------------------" + read -e -p "연결 이름을 입력하세요:" name + + kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "포트 번호를 입력하십시오(기본값: 22):" "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "연결이 저장되었습니다!" } @@ -7087,7 +7207,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -7134,52 +7254,23 @@ add_task() { read -e -p "작업 이름을 입력하세요:" name read -e -p "로컬 디렉토리를 입력하십시오:" local_path read -e -p "원격 디렉토리를 입력하십시오:" remote_path - read -e -p "원격 user@IP를 입력하십시오:" remote - read -e -p "SSH 포트(기본값 22)를 입력하세요." port - port=${port:-22} - echo "인증 방법을 선택하세요:" - echo "1. 비밀번호" - echo "2. 열쇠" - read -e -p "(1/2)을 선택하세요:" auth_choice + while true; do + read -e -p "원격 user@IP를 입력하십시오:" remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "비밀번호를 입력하세요:" password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." - local password_or_key="" - while IFS= read -r line; do - # 입력이 빈 줄이고 키 내용에 이미 시작 부분이 포함된 경우 입력을 종료합니다. - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # 첫 번째 줄이거나 이미 핵심 내용 입력을 시작했다면 계속해서 추가하세요. - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + kj_ssh_read_port "SSH 포트(기본값 22)를 입력하세요." "22" + port="$KJ_SSH_PORT" - # 핵심 내용인지 확인해보세요 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "잘못된 키 콘텐츠입니다!" - return - fi - ;; - *) - echo "잘못된 선택입니다!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "동기화 모드를 선택하십시오:" echo "1. 표준 모드(-avz)" @@ -7198,6 +7289,7 @@ add_task() { echo "임무가 저장되었습니다!" } + # 할 일 삭제 delete_task() { send_stats "동기화 작업 삭제" @@ -7294,7 +7386,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -8137,10 +8229,10 @@ docker_ssh_migration() { read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } - read -e -p "대상 서버 IP:" TARGET_IP - read -e -p "대상 서버 SSH 사용자 이름:" TARGET_USER - read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "대상 서버 IP:" "대상 서버 SSH 사용자 이름 [기본 루트]:" "대상 서버 SSH 포트 [기본값 22]:" "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -8379,7 +8471,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9604,13 +9696,9 @@ linux_ldnmp() { read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하세요:" remote_ip - read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "오류: 원격 서버 IP를 입력하세요." - continue - fi + kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -9956,18 +10044,20 @@ moltbot_menu() { echo "--------------------" echo "4. 상태 로그 보기" echo "5. 모델 변경" - echo "6. 새로운 모델 API 추가" + echo "6. API 관리" echo "7. 로봇 연결 및 도킹" - echo "8. 플러그인 설치(예: Feishu)" - echo "9. 스킬 설치" + echo "8. 플러그인 관리(설치/제거)" + echo "9. 스킬 관리(설치/제거)" echo "10. 기본 구성 파일 편집" echo "11. 구성 마법사" echo "12. 건강 상태 감지 및 복구" echo "13. WebUI 접속 및 설정" echo "14. TUI 명령줄 대화 상자 창" + echo "15. 기억/기억" echo "--------------------" - echo "15. 업데이트" - echo "16. 제거" + echo "16. 백업 및 복원" + echo "17. 업데이트" + echo "18. 제거" echo "--------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------" @@ -9997,6 +10087,459 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + + + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' +import copy +import json +import os +import platform +import sys +import time +import urllib.request +from datetime import datetime, timezone + +path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ API 제공업체가 감지되지 않음, 모델 동기화 건너뛰기') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models 프로브가 3번 연속 실패했습니다. 이 API 제공업체 및 모든 관련 모델을 삭제하시겠습니까? [예/아니요]:" + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 기본 기본 모델이 이 공급자를 가리키지만 사용 가능한 대체 모델이 없어 삭제가 중단되었습니다.') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 삭제 전에 기본 기본 모델이 전환되었습니다: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk}가 공급자를 가리키지만 대체 모델을 사용할 수 없어 삭제가 중단되었습니다.') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 삭제 전 전환됨 {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ 제공자 {name}이(가) 삭제되었으며 defaults.models 아래의 {len(removed_refs)} 모델 참조가 제거되었습니다.') + return True + + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): + if not isinstance(provider, dict): + summary.append(f'ℹ️ {name} 건너뛰기: 공급자 구조가 불법입니다.') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ {name} 건너뛰기: 없음 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 잘못된 프로토콜 {api 또는 "(unset)"}이 발견되어 다시 감지됩니다.') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 프로토콜이 자동으로 {Detected_api}({Detected_reason})로 수정되었습니다.') + except Exception as e: + summary.append(f'⚠️ {name}: 프로토콜 감지 실패, 수정 건너뛰기 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 감지 실패, {attempts} 번 재시도됨 ({type(err).__name__}: {err})') + send_stat('OpenClaw API 확인 개입') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API 삭제 실패 공급자 확인') + summary.append(f'✅ {name}: 사용자가 공급자 및 모든 관련 모델 참조 삭제를 확인했습니다.') + else: + send_stat('OpenClaw API 삭제 실패 공급자 거부') + summary.append(f'ℹ️ {name}: 사용자가 삭제를 확인하지 않았으며 기존 공급자 구성을 유지합니다.') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models {시도}번 재시도 후 성공') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ {name} 건너뛰기: /models 반환 구조가 인식되지 않습니다.') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name}의 업스트림 /models가 비어 있으며 이 공급자에 대한 상향식 모델을 제공할 수 없습니다.') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ {name} 건너뛰기: 로컬 모델에 유효한 템플릿 모델이 없습니다.') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 새 모델 추가({len(add_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 모델 삭제({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name}은(는) 동기화 후 사용 가능한 모델이 없으며 기본 모델/폴백 모델을 보장할 수 없습니다.') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: {len(removed_ids)} 삭제, {len(add_ids)} 추가, 현재 {len(new_models)}') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 모델 동기화 실패: 공급자가 있습니다. 동기화 후 사용 가능한 모델이 없으며 쓰기가 중단되었습니다.') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') +else: + for line in summary: + print(line) + print('ℹ️ 동기화가 필요하지 않습니다. 구성이 이미 업스트림/모델과 일치합니다.') +PY + } + + + install_moltbot() { echo "OpenClaw 설치를 시작합니다..." send_stats "OpenClaw 설치를 시작합니다..." @@ -10013,7 +10556,9 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # 팁: 즉시 적용되도록 구성을 수정해야 하는 경우 게이트웨이를 다시 시작할 수 있습니다. openclaw Gateway restart + configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10049,6 +10594,44 @@ moltbot_menu() { + # OpenClaw API 프로토콜 감지(우선순위 응답 -> 완료) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + return 0 + } + # 핵심 기능: 모든 모델 가져오기 및 추가 add-all-models-from-provider() { local provider_name="$1" @@ -10058,6 +10641,10 @@ moltbot_menu() { echo "🔍 받기$provider_name사용 가능한 모든 모델..." + # API 프로토콜 자동 식별 + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # 모델 목록 가져오기 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10133,10 +10720,11 @@ EOF # 백업 구성 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # jq를 사용하여 모든 모델 주입 + # jq를 사용하여 모든 모델을 삽입하고 defaults.models를 동기화합니다. jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10145,10 +10733,26 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then @@ -10162,7 +10766,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "API 추가" + send_stats "OpenClaw API가 추가되었습니다." echo "=== 대화식으로 OpenClaw 공급자 추가(전체 모델) ===" # 1. 제공자 이름 @@ -10189,7 +10793,11 @@ EOF echo done - # 4. 모델 목록 가져오기 + # 4. 프로토콜 탐지(의미 없음) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. 모델 목록 가져오기 echo "🔍 사용 가능한 모델 목록을 가져오는 중..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10204,10 +10812,10 @@ EOF echo "--------------------------------" # 일련번호와 함께 모두 표시 i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10221,292 +10829,2968 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 첫 번째 모델 사용:$default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 선택 모델:$default_model" else - default_model="$input_model" + default_model="$input_model" + fi + + # 6. 정보 확인 + echo + echo "====== 확인 ======" + echo "Provider : $provider_name" + echo "Base URL : $base_url" + echo "API Key : ${api_key:0:8}****" + echo "기본 모델:$default_model" + echo "총 모델 수:$model_count" + echo "======================" + + read -erp "모두 추가하려면 확인하세요.$model_count모델? (예/아니요):" confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "❎ 취소됨" + return 1 + fi + + install jq + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + + if [[ $? -eq 0 ]]; then + echo + echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." + openclaw models set "$provider_name/$default_model" + start_gateway + echo "✅ 완료! 모두$model_count로드된 모델" + echo "✅ 계약은 자동으로 다음과 같이 식별되었습니다.$DETECTED_API" + fi + + break_end + } + + + +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API 목록" + + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac + + printf '%b\n' "[$idx] ${name} | API: ${base_url}| 합의:${api_type}| 모델 수:${gl_huang}${model_count}${gl_bai}| 지연/상태:${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == '사용할 수 없음': + return '사용할 수 없음', 'unavailable' + if latency == '감지되지 않음': + return '감지되지 않음', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ openclaw.json을 찾을 수 없습니다. 먼저 설치/초기화를 완료하세요.') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ 구성을 읽지 못했습니다: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 현재 구성된 API 제공업체가 없습니다.') + raise SystemExit(0) + +print('MSG\t--- 구성된 API 목록 ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '사용할 수 없음' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '감지되지 않음' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '사용할 수 없음' + else: + latency_raw = '사용할 수 없음' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "공급자별 OpenClaw API 동기화" + + if [ ! -f "$config_file" ]; then + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + break_end + return 1 + fi + + read -erp "동기화할 API 이름(공급자)을 입력하세요." provider_name + if [ -z "$provider_name" ]; then + echo "❌ 제공업체 이름은 비워둘 수 없습니다." + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ API 제공업체가 감지되지 않아 동기화할 수 없습니다.') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ 제공자: {target}을(를) 찾을 수 없습니다') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ 공급자 {target}에 baseUrl/apiKey/models가 누락되어 동기화를 수행할 수 없습니다.') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'ℹ️ 공급자 {target} 현재 api={api}, 프로토콜을 다시 감지하고 계속합니다.') + provider['api'] = '' + api = '' + +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 자동 수정된 프로토콜: {target} {api} ({Detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ 프로토콜 감지 실패, 수정 건너뛰기: {target} ({type(e).__name__}: {e})' + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models 감지 실패, {attempts}번 재시도됨 ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models 반환된 구조가 인식되지 않습니다.') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: 업스트림 /models가 비어 있고 동기화가 중단되었습니다.') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: 로컬 모델에 유효한 템플릿 모델이 없어 새 모델을 추가할 수 없습니다.') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +if added_ids: + print(f'➕ 새 모델 추가({len(add_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 모델 삭제({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: 동기화 후 사용할 수 있는 모델이 없어 쓰기가 중단되었습니다.') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if protocol_msg: + print(protocol_msg) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: {len(removed_ids)} 제거, {len(add_ids)} 추가, 현재 {len(new_models)}') +if changed: + print('✅ 지정된 공급자 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') +else: + print('ℹ️ 동기화가 필요하지 않습니다. 공급자 구성이 이미 업스트림/모델과 일치합니다.') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ 동기 실행 완료" + start_gateway + ;; + 2) + echo "❌ 동기화 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." + ;; + 3) + echo "❌ 동기화 실패: 공급자 구성이 불완전하거나 유형이 지원되지 않습니다." + ;; + 4) + echo "❌ 동기화 실패: 업스트림 /models 요청 실패" + ;; + 5) + echo "❌ 동기화 실패: 업스트림 모델이 비어 있거나 동기화 후 사용 가능한 모델이 없습니다." + ;; + *) + echo "❌ 동기화 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + ;; + esac + + break_end +} + +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ openclaw.json을 찾을 수 없습니다') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ 공급자 {name}에 baseUrl/apiKey가 없습니다.') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 업데이트된 공급자 {name} 프로토콜: {current_api 또는 "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ 업데이트가 필요하지 않습니다. 프로토콜은 {current_api 또는 api}로 유지됩니다.') +PY +} + +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API 프로토콜 수정" + + if [ ! -f "$config_file" ]; then + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + break_end + return 1 + fi + + read -erp "복구할 프로토콜의 API 이름(공급자)을 입력하세요." provider_name + if [ -z "$provider_name" ]; then + echo "❌ 제공업체 이름은 비워둘 수 없습니다." + break_end + return 1 + fi + + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅본 계약은 테스트 및 업데이트되었습니다(변경될 수 있음)." + start_gateway + ;; + 2) + echo "❌ 복구 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." + ;; + 3) + echo "❌ 복구 실패: 공급자 구성이 불완전합니다." + ;; + *) + echo "❌ 복구 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + ;; + esac + + break_end +} + + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API 삭제 항목" + + if [ ! -f "$config_file" ]; then + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + break_end + return 1 + fi + + read -erp "삭제할 API 이름(공급자)을 입력하세요." provider_name + if [ -z "$provider_name" ]; then + send_stats "OpenClaw API 삭제 취소" + echo "❌ 제공업체 이름은 비워둘 수 없습니다." + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ 삭제가 중단됨: 기본 기본 모델이 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 기본 기본 모델 전환: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 삭제가 중단되었습니다. {fk}가 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 스위치: {val} -> {교체}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ 삭제된 제공자: {name}') +print(f'🧹 defaults.models에서 {len(removed_refs)} 관련 모델 참조를 정리했습니다.') +PY + local rc=$? + case "$rc" in + 0) + send_stats "OpenClaw API 삭제 확인" + echo "✅삭제 완료" + start_gateway + ;; + 2) + echo "❌ 삭제 실패: 공급자가 존재하지 않습니다." + ;; + 3) + send_stats "OpenClaw API 삭제 취소" + echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." + ;; + *) + echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "OpenClaw API 입구" + while true; do + clear + echo "=======================================" + echo "OpenClaw API 관리" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. API 추가" + echo "2. API 제공자 모델 목록 동기화" + echo "3. API 삭제" + echo "4. 프로토콜 복구/재감지" + echo "0. 종료" + echo "---------------------------------------" + read -erp "선택사항을 입력하세요:" api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + sync-openclaw-provider-interactive + ;; + 3) + delete-openclaw-provider-interactive + ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; + 0) + return 0 + ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac + done + } + + + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "모델 변경" + + local orange="#FF8C00" + + clear + + while true; do + local models_raw models_list default_model model_count selected_model + + # 구성 파일에서 모델 키 읽기(openclaw 모델 목록을 호출하지 않고) + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + echo "모델 목록을 가져오지 못했습니다. 구성 파일에서 Agent.defaults.models를 찾을 수 없습니다." + break_end + return 1 + fi + + # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # 구성 파일에서 기본 모델을 읽습니다(더 빠름). 실패 시 openclaw 명령으로 대체 + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + [ -z "$default_model" ] && default_model="(unknown)" + + + install_gum + install gum + + clear + + # 껌이 없을 경우 기존 수동입력 과정으로 다운그레이드 (기존과 동일하게 유지) + if ! command -v gum >/dev/null 2>&1; then + echo "---모델 관리 ---" + echo "현재 사용 가능한 모델:" + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' + echo "----------------" + read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." selected_model + + # 1. 0을 입력하여 종료했는지 확인하세요. + if [ "$selected_model" = "0" ]; then + echo "작업이 취소되었습니다. 종료하는 중..." + break # 跳出 while 循环 + fi + + # 2. 입력이 비어 있는지 확인하십시오. + if [ -z "$selected_model" ]; then + echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + else + gum style --foreground "$orange" --bold "모델 관리" + gum style --foreground "$orange" "사용 가능한 모델(인증=예):${model_count}" + gum style --foreground "$orange" "현재 기본값:${default_model}" + echo "" + + # 하단 팁 + gum style --faint "↑↓ 선택/Enter를 눌러 확인/Esc를 눌러 종료" + echo "" + + # 껌 필터: 검색 포함; 껌 버전은 매우 다양하며 여기서는 가장 호환되는 플래그만 사용됩니다. + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "검색 모델(예: cli-api/gpt-5.2)" \ + --prompt "모델 선택 >" \ + --indicator "➜ " \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor-text.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 35) + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then + echo "작업이 취소되었습니다. 종료하는 중..." + break + fi + fi + + # 숫자 접두사 제거: "(10) model" -> "model" + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + + # 스위치 실행 + echo "전환되는 모델은 다음과 같습니다.$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + break_end + return 1 + fi + start_gateway + + break_end + done + } + + + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" + return 0 + fi + fi + + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + return 1 + } + + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅plugins.allow에서 제거됨:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅plugins.allow에서 제거됨:$plugin_id" + return 0 + fi + fi + + echo "⚠️plugins.allow 제거에 실패했습니다. 수동으로 확인하세요.$config_file" + return 1 + } + + + + + + + install_plugin() { + send_stats "플러그인 관리" + while true; do + clear + echo "========================================" + echo "플러그인 관리(설치/제거)" + echo "========================================" + echo "현재 플러그인 목록:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "--------------------------------------------------------" + echo "📱 커뮤니케이션 채널:" + echo "- [feishu] # 페이슈/종달새 통합" + echo "- [텔레그램] # 텔레그램 봇" + echo "- [slack] #Slack 기업 커뮤니케이션" + echo " - [msteams] # Microsoft Teams" + echo "- [디스코드] # 디스코드 커뮤니티 관리" + echo "- [whatsapp] #WhatsApp 자동화" + echo "" + echo "🧠 메모리와 AI:" + echo "- [memory-core] # 기본 메모리(파일 검색)" + echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" + echo "- [copilot-proxy] # Copilot 인터페이스 전달" + echo "" + echo "⚙️ 기능 확장:" + echo "- [랍스터] # 승인 흐름(수동 확인 포함)" + echo "- [음성통화] # 음성통화 기능" + echo "- [nostr] # 암호화된 비공개 채팅" + echo "--------------------------------------------------------" + + echo "1) 플러그인 설치/활성화" + echo "2) 플러그인 삭제/비활성화" + echo "0) 반품" + read -e -p "작업을 선택하십시오:" plugin_action + + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "플러그인 ID를 입력하십시오(공백으로 구분, 종료하려면 0 입력)." raw_input + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 플러그인 상태 확인 중:$plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요.$plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ 다운로드 성공, 활성화 중..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ 설치 실패:$plugin_full" + failed_list="$failed_list $plugin_id" + fi + else + echo "🗑️ 플러그인 제거/비활성화:$plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ 제거됨:$plugin_id" + else + echo "⚠️ 제거에 실패했습니다. 사전 설치된 플러그인일 수 있습니다. 다음만 비활성화하세요.$plugin_id" + fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true + fi + done + + echo "" + echo "====== 작업 요약 ======" + echo "✅ 성공:$success_list" + [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." + start_gateway + fi + break_end + done + } + + + install_skill() { + send_stats "스킬 관리" + while true; do + clear + echo "========================================" + echo "스킬 관리(설치/제거)" + echo "========================================" + echo "현재 설치된 스킬:" + openclaw skills list + echo "----------------------------------------" + + # 추천 실기 목록 출력 + echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" + echo "github # GitHub 문제/PR/CI 관리(gh CLI)" + echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." + echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" + echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" + echo "1password # 1Password 키 읽기 및 삽입 자동화" + echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" + echo "things-mac # Things 3 작업 관리의 심층 통합" + echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." + echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" + echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" + echo "openhue # Philips Hue 스마트 조명 장면 제어" + echo "video-frames # 비디오 프레임 추출 및 짧은 클립 편집(ffmpeg 드라이버)" + echo "openai-whisper # 로컬 오디오를 텍스트로 변환(오프라인 개인 정보 보호)" + echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." + echo "----------------------------------------" + + echo "1) 설치 기술" + echo "2) 스킬 삭제" + echo "0) 반품" + read -e -p "작업을 선택하십시오:" skill_action + + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue + + read -e -p "스킬 이름을 입력하십시오(공백으로 구분, 종료하려면 0 입력):" skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + if [ "$skill_action" = "2" ]; then + read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. 계속하시겠습니까? (예/아니요):" confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "삭제가 취소되었습니다." + break_end + continue + fi + fi + + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 스킬 [$skill_name]는 사용자 디렉토리에 설치됩니다." + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 스킬 [$skill_name]는 시스템 디렉토리에 설치됩니다." + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "스킬 [$skill_name] 이미 설치되어 있습니다. 다시 설치하시겠습니까? (예/아니요):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "기술 설치:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ 스킬$skill_name설치가 성공했습니다." + success_list="$success_list $skill_name" + changed=true + else + echo "❌ 설치 실패:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ 스킬 삭제:$skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ 사용자 스킬 디렉토리가 삭제되었습니다:$skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ 사용자 스킬 디렉터리를 찾을 수 없습니다:$skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== 작업 요약 ======" + echo "✅ 성공:$success_list" + [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." + start_gateway + fi + break_end + done + } + +openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + + # 두 가지 일반적인 디렉터리 이름과 호환됩니다. + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "이상" + elif [ "$enabled" != "true" ]; then + echo "활성화되지 않음" + elif [ "$connected" = "true" ]; then + echo "연결됨" + elif [ "$configured" = "true" ]; then + echo "구성된" + else + echo "구성되지 않음" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "로컬 상태(로컬 구성/캐시만, 네트워크 감지 없음):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "종달새" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + + change_tg_bot_code() { + send_stats "로봇 도킹" + while true; do + clear + echo "========================================" + echo "로봇 연결 및 도킹" + echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" + echo "1. 텔레그램 로봇 도킹" + echo "2. Feishu(Lark) 로봇 도킹" + echo "3. WhatsApp 봇 도킹" + echo "----------------------------------------" + echo "0. 이전 메뉴로 돌아가기" + echo "----------------------------------------" + read -e -p "선택사항을 입력하세요:" bot_choice + + case $bot_choice in + 1) + read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "Feishu Robot이 수신한 연결 코드(예: NYA99R2F)를 입력하십시오(종료하려면 0을 입력하십시오)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac + done + } + + + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null + ) || { echo "❌ sha256 확인이 실패하고 복원이 거부되었습니다."; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw 메모리 전체 백업" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ 작업공간 디렉터리를 찾을 수 없습니다:$workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "AGENTS/USER/SOUL/TOOLS 파일과 함께 제공됩니까? (예/아니요):" include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 백업 메모리 파일이 없습니다." + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ 전체 메모리 백업 완료:$out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ 전체 메모리 백업 실패" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_input file_path backup_root + echo "$prompt_text" >&2 + + echo "먼저 scp/sftp를 통해 서버에 백업 패키지를 업로드한 후 경로를 입력할 수 있습니다." >&2 + echo "scp 예: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 + echo "팁: 파일 이름을 입력하면 기본적으로 백업 디렉터리에서 검색됩니다. /가 포함된 경로를 입력하면 전체 경로로 확인됩니다." >&2 + read -e -p "백업 파일 이름이나 경로를 입력하십시오:" file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ 백업 파일이 존재하지 않습니다:$file_path" >&2 + echo "" + return 1 + fi + + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw 메모리 전체 복원" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "복원 전 유형 확인 + sha256 확인 + 경로 화이트리스트 확인이 수행됩니다.") + [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + break_end + return 1 + fi + + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ 메모리 전체 복구 완료" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw 프로젝트 백업" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ OpenClaw 루트 디렉터리를 찾을 수 없습니다:$openclaw_root" + break_end + return 1 + fi + + echo "백업 모드:" + echo "1. 안전 모드(기본값, 권장): 작업 공간 + openclaw.json + 확장/기술/프롬프트/도구(존재하는 경우)" + echo "2. 전체 모드(더 많은 상태 포함, 더 높은 민감도 위험)" + read -e -p "백업 모드를 선택하십시오(기본값 1):" export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 백업 가능한 OpenClaw 프로젝트 콘텐츠가 없습니다." + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw 프로젝트 백업 완료 (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw 프로젝트 백업 실패" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw 프로젝트 복원" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ 고위험 작업: 프로젝트 복원은 OpenClaw 구성 및 작업 공간 콘텐츠를 덮어씁니다." + echo "⚠️ 복원 전 매니페스트/sha256 확인, 화이트리스트 복원, 게이트웨이 종료 및 상태 점검이 수행됩니다." + read -e -p "계속하려면 확인 단어 [위험도가 높다는 것을 알고 있으며 복원을 계속합니다]를 입력하십시오." confirm_text + if [ "$confirm_text" != "위험성이 높다는 것을 인지하고 복원을 계속하고 있습니다." ]; then + echo "❌ 확인문자가 일치하지 않아 복원이 취소되었습니다." + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요") + [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + break_end + return 1 + fi + + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ 복원하기 전에 OpenClaw 게이트웨이를 중지하세요..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ 복원 후 OpenClaw 게이트웨이를 시작하세요..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 게이트웨이 상태 점검:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw 프로젝트 복원 완료" + break_end + } + + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "메모리 백업 파일" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "프로젝트 백업 파일" + else + echo "기타 백업 파일" + fi + } + + openclaw_backup_collect_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + local has_memory=0 has_project=0 has_other=0 + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + + echo "백업 디렉터리:$backup_root" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "아직 백업 파일이 없습니다" + return 0 + fi + + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "메모리 백업 파일") has_memory=1 ;; + "프로젝트 백업 파일") has_project=1 ;; + "기타 백업 파일") has_other=1 ;; + esac + done + + if [ "$has_memory" -eq 1 ]; then + echo "메모리 백업 파일" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "메모리 백업 파일" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "프로젝트 백업 파일" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "프로젝트 백업 파일" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "기타 백업 파일" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "기타 백업 파일" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + } + + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw 삭제 백업 파일" + local backup_root backup_root_real user_input target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "삭제할 파일 이름이나 전체 경로를 입력하십시오. (취소하려면 0):" user_input + if [ "$user_input" = "0" ]; then + echo "삭제가 취소되었습니다." + break_end + return 0 + fi + if [ -z "$user_input" ]; then + echo "❌ 입력은 비워둘 수 없습니다." + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ 경로 초과: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ 대상 파일이 존재하지 않습니다:$target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ 현재 백업 목록에 대상 파일이 없습니다." + break_end + return 1 + fi + + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "삭제 예정: [$target_type] $target_path" + read -e -p "첫 번째 확인: 확인하고 계속하려면 yes를 입력하세요." confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "삭제가 취소되었습니다." + break_end + return 0 + fi + read -e -p "보조 확인: 삭제하려면 DELETE를 입력하세요." confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "삭제가 취소되었습니다." + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ 삭제 성공:$target_file" + else + echo "❌ 삭제 실패:$target_file" + fi + break_end + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list + break_end + } + + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } + + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ 인덱스 라이브러리 파일을 찾을 수 없습니다. 비어 있거나 존재하지 않을 수 있습니다." + echo "원시 값 저장: ${store_raw:-}" + echo "재인덱싱은 계속 수행됩니다." + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 백업된 인덱스:$backup_file" + else + echo "⚠️ 인덱스 백업에 실패했습니다. 계속 재구축하세요." + fi + fi + openclaw memory index --force + openclaw gateway restart + echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "" + openclaw_memory_render_status + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ 작업공간 경로를 가져오지 못했습니다. 디렉터리 복구를 건너뜁니다." + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 메모리 디렉터리가 존재하지 않으며 자동으로 생성되었습니다.$memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "상태를 가져오지 못했습니다." + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^공급자: /기본 솔루션: /' -e 's/^벡터: /벡터 라이브러리 상태: /' -e 's/^색인: /포함된 파일: /') + if [ -z "$status_lines" ]; then + echo "설치되지 않음/시작되지 않음" + else + echo "$status_lines" + fi + fi + } + + openclaw_memory_get_backend() { + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi + } + + openclaw_memory_get_local_model_path() { + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then + echo "true" + return + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로:$model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로가 구성되지 않았습니다.") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재합니다.") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("모델은 HF 다운로드 소스에서 제공됩니다(중국에서는 느리거나 실패할 수 있음).") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재하지 않거나 사용할 수 없습니다.") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co에 액세스할 수 있습니다.") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ Curl이나 wget이 감지되지 않아 다운로드할 수 없습니다." + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ sqlite3이 감지되지 않으면 QMD가 제대로 작동하지 않을 수 있습니다." + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 사용 가능: ${ver:-unknown}" + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ 롤빵이 이미 존재합니다" + return 0 + fi + echo "⬇️ 번 설치..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ 번 설치 완료" + return 0 + fi + echo "❌ 번 설치 실패" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd가 이미 존재합니다:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ 롤빵을 통해 qmd를 설치합니다:$qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd 설치 실패" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd 설치 완료:$qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ 환경 준비" + echo "구성표: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "모드: 쓰기 구성만(설치되지 않음/다운로드되지 않음)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "색인: 실행됨" + else + echo "색인: 건너뛰었습니다." + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "다시 시작: 실행됨" + else + echo "다시 시작: 건너뛰었습니다." + fi + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "모델:$OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "영역:$OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "다운로드 소스:$OPENCLAW_MEMORY_HF_BASE" + fi + echo "최종 상태:" + openclaw_memory_render_status + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "자동 배포가 곧 수행됩니다(상세 모드)." + echo "목표 계획:$scheme_label" + echo "지역: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "미러 소스 감지:huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "다운로드 소스: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "예상 다운로드 경로:$OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "가능한 트래픽/디스크 사용량:$OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" + fi + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." + read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "자동 배포가 취소되었습니다." + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ 설치나 다운로드 없이 구성만 작성하도록 선택됨" + else + echo "✅ 인덱스가 자동으로 구축되고 게이트웨이가 다시 시작됩니다." + fi + return 0 + } + + openclaw_memory_auto_setup_qmd() { + echo "🔍 QMD 환경 감지" + openclaw_memory_cleanup_legacy_keys + openclaw_memory_check_sqlite || true + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) + else + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅ memory.backend는 이미 qmd입니다." + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅ memory.backend=qmd가 설정되었습니다" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅ memory.qmd.command가 정확합니다" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 따뜻한 지수(모델 다운로드 가능)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 예열 생략" + fi + echo "✅ QMD 자동 배포 완료" + } + + openclaw_memory_auto_setup_local() { + echo "🔍 로컬 환경 감지" + openclaw_memory_cleanup_legacy_keys + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅ memory.backend는 이미 내장되어 있습니다." + else + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅ memory.backend=builtin이 설정되었습니다." + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅ memorySearch.provider는 이미 로컬입니다." + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ Agents.defaults.memorySearch.provider=로컬 세트" + fi + + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ 모델 파일이 이미 존재합니다:$model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ 쓰기 전용 구성 모드: 모델 다운로드 건너뛰기" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + else + if [ -f "$model_dest" ]; then + echo "✅ 기본 모델 파일이 발견되었습니다:$model_dest" + else + echo "⬇️ 다운로드 모델:$model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 모델이 다운로드되었습니다:$model_dest" + fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ 모델 경로가 작성되었습니다" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 따뜻한 지수(모델 다운로드 가능)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 예열 생략" + fi + echo "✅ 로컬 자동 배포가 완료되었습니다" + } + + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun(qmd 설치 디렉토리)" + OPENCLAW_MEMORY_EXPECT_SIZE="약 20-50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" + ;; + *) + echo "❌ 알 수 없는 해결책:$scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ OpenClaw 게이트웨이 다시 시작" + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" + openclaw_memory_render_auto_summary + return 0 + } + + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "메모리 솔루션 자동 배포" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3. 자동(자동 선택)" + echo "0. 이전 레벨로 돌아갑니다" + echo "---------------------------------------" + read -e -p "선택사항을 입력하세요:" auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac + done + } + + openclaw_memory_apply_scheme() { + local scheme="$1" + openclaw_memory_cleanup_legacy_keys + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ 구성을 쓰지 못했습니다." + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "builtin" + if [ $? -ne 0 ]; then + echo "❌ 구성을 쓰지 못했습니다." + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ 알 수 없는 해결책:$scheme" + return 1 + esac + echo "✅ 메모리 체계 구성이 업데이트되었습니다." + return 0 + } + + openclaw_memory_offer_restart() { + echo "구성이 작성되었으며 OpenClaw 게이트웨이를 다시 시작한 후 적용하려면 다시 시작해야 합니다." + read -e -p "지금 OpenClaw Gateway를 다시 시작하시겠습니까? (예/아니요):" restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "다시 시작을 건너뛰었습니다. 나중에 수행할 수 있습니다. openclaw 게이트웨이 다시 시작" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart fi + } - # 6. 정보 확인 - echo - echo "====== 확인 ======" - echo "Provider : $provider_name" - echo "Base URL : $base_url" - echo "API Key : ${api_key:0:8}****" - echo "기본 모델:$default_model" - echo "총 모델 수:$model_count" - echo "======================" - - read -erp "모두 추가하려면 확인하세요.$model_count모델? (예/아니요):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 취소됨" + openclaw_memory_fix_index() { + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ 현재 구성표는 QMD로 감지되지만 qmd 명령은 설치되지 않습니다." + echo "로컬로 전환하거나 bun + qmd를 설치하고 다시 시도할 수 있습니다." + fi + echo "적용 가능한 시나리오: 인덱스 분자 > 분모(반복된 수집으로 인해 비정상적인 계산이 발생함)" + read -e -p "includeDefaultMemory를 false로 설정하셨나요? (예/아니요):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "취소." + break_end + return 0 + fi + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false + if [ $? -ne 0 ]; then + echo "❌ 구성을 쓰지 못했습니다." + break_end return 1 fi - - install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" - - if [[ $? -eq 0 ]]; then - echo - echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." - openclaw models set "$provider_name/$default_model" - start_gateway - echo "✅ 완료! 모두$model_count로드된 모델" + echo "✅ includeDefaultMemory=false 설정" + echo "권장 실행: 인덱스 정리 및 재구축" + read -e -p "인덱스를 정리하고 다시 작성하시겠습니까(권장)? (예/아니요):" rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_safe + else + echo "상태는 나중에 메모리 관리에서 볼 수 있습니다." fi - break_end } - - - change_model() { - send_stats "모델 변경" - + openclaw_memory_scheme_menu() { while true; do clear - echo "---모델 관리 ---" - echo "모든 모델:" - openclaw models list --all - echo "----------------" - echo "현재 모델:" - openclaw models list - echo "----------------" - read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." model - - # 1. 0을 입력하여 종료했는지 확인하세요. - if [ "$model" = "0" ]; then - echo "작업이 취소되었습니다. 종료하는 중..." - break # 跳出 while 循环 - - fi - - # 2. 입력이 비어 있는지 확인하십시오. - if [ -z "$model" ]; then - echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 - fi - - # 3. 스위칭 로직 실행 - echo "전환되는 모델은 다음과 같습니다.$model ..." - openclaw models set "$model" - - break_end + echo "=======================================" + echo "OpenClaw 메모리 솔루션" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + builtin|local) current_label="Local" ;; + *) current_label="구성되지 않음" ;; + esac + echo "현재 계획:$current_label" + echo "" + echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" + echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" + echo "---------------------------------------" + echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" + echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" + echo "3. 자동(자동 추천 및 자동 배포)" + echo "0. 이전 레벨로 돌아갑니다" + echo "---------------------------------------" + read -e -p "선택사항을 입력하세요:" scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac done - } + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "메모리 파일을 찾을 수 없습니다." + return 0 + fi + echo "번호 | 상대 경로 | 크기 | 수정 시간" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } - - install_plugin() { - send_stats "플러그인 설치" - while true; do - clear - echo "========================================" - echo "플러그인 관리(설치)" - echo "========================================" - echo "현재 플러그인 목록:" - openclaw plugins list - echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" - echo "--------------------------------------------------------" - echo "📱 커뮤니케이션 채널:" - echo "- [feishu] # 페이슈/종달새 통합" - echo "- [텔레그램] # 텔레그램 봇" - echo "- [slack] #Slack 기업 커뮤니케이션" - echo " - [msteams] # Microsoft Teams" - echo "- [디스코드] # 디스코드 커뮤니티 관리" - echo "- [whatsapp] #WhatsApp 자동화" - echo "" - echo "🧠 메모리와 AI:" - echo "- [memory-core] # 기본 메모리(파일 검색)" - echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" - echo "- [copilot-proxy] # Copilot 인터페이스 전달" - echo "" - echo "⚙️ 기능 확장:" - echo "- [랍스터] # 승인 흐름(수동 확인 포함)" - echo "- [음성통화] # 음성통화 기능" - echo "- [nostr] # 암호화된 비공개 채팅" - echo "--------------------------------------------------------" - - read -e -p "플러그인 ID를 입력하십시오(종료하려면 0을 입력하십시오):" raw_input - - [ "$raw_input" = "0" ] && break - [ -z "$raw_input" ] && continue - - # 1. 자동 처리: 사용자 입력에 @openclaw/가 포함된 경우 경로 확인을 용이하게 하기 위해 순수 ID를 추출합니다. - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') - local plugin_full="$raw_input" - - echo "🔍 플러그인 상태 확인 중..." - # 상태 감지를 위한 현재 플러그인 목록 가져오기 - local plugin_list=$(openclaw plugins list 2>/dev/null) - - # 2. 이미 목록에 있고 비활성화되어 있는지 확인합니다(가장 일반적인 경우). - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." - openclaw plugins enable "$plugin_id" && echo "✅활성화 성공" || echo "❌ 활성화 실패" - - # 3. 시스템 물리적 디렉토리가 존재하는지 확인하십시오. - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." - openclaw plugins enable "$plugin_id" - + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ 파일이 존재하지 않습니다:$file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=120 + local start_line count + echo "문서:$file" + echo "총 행 수:$total_lines" + read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line + read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 else - # 4. 원격 설치 논리 - echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요..." - - # 오래되고 실패한 잔재를 정리합니다. - rm -rf "/root/.openclaw/extensions/$plugin_id" - - # 설치 수행 및 결과 캡처 - if openclaw plugins install "$plugin_full"; then - echo "✅ 다운로드 성공, 활성화 중..." - openclaw plugins enable "$plugin_id" - else - echo "⚠️ 공식 채널에서 다운로드하지 못했습니다. 대안을 시도해 보세요..." - # 대체 npm 설치 - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm이 성공적으로 설치되었습니다. 활성화해 보세요..." - openclaw plugins enable "$plugin_id" - else - echo "❌ 치명적인 오류: 플러그인을 얻을 수 없습니다. ID가 맞는지, 네트워크 사용이 가능한지 확인해주세요." - # 키: 구성이 하드 코딩되는 것을 방지하려면 아래 start_gateway를 사용하는 대신 여기로 직접 돌아가거나 계속하세요. - break_end - continue - fi - fi + start_line=$((total_lines - count + 1)) fi - - echo "🔄 새 플러그인을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." - start_gateway - break_end - done + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ 유효한 숫자를 입력하세요." + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ 행 개수는 0보다 커야 합니다." + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(빈 파일)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" } - - - - - - - install_skill() { - send_stats "설치 기술" + openclaw_memory_files_menu() { while true; do clear - echo "========================================" - echo "스킬 관리(설치)" - echo "========================================" - echo "현재 설치된 스킬:" - openclaw skills list - echo "----------------------------------------" - - # 추천 실기 목록 출력 - echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" - echo "github # GitHub 문제/PR/CI 관리(gh CLI)" - echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." - echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" - echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" - echo "1password # 1Password 키 읽기 및 삽입 자동화" - echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" - echo "things-mac # Things 3 작업 관리의 심층 통합" - echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." - echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" - echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" - echo "openhue # Philips Hue 스마트 조명 장면 제어" - echo "video-frames # 비디오 프레임 추출 및 짧은 클립 편집(ffmpeg 드라이버)" - echo "openai-whisper # 로컬 오디오를 텍스트로 변환(오프라인 개인 정보 보호)" - echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." - echo "----------------------------------------" - - # 사용자에게 스킬 이름을 입력하라는 메시지를 표시합니다. - read -e -p "설치할 스킬의 이름을 입력하십시오(종료하려면 0을 입력하십시오):" skill_name - - # 1. 0을 입력하여 종료했는지 확인하세요. - if [ "$skill_name" = "0" ]; then - echo "동작이 취소되어 스킬 설치가 종료되었습니다." - break + echo "=======================================" + echo "OpenClaw 메모리 파일" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "보려는 파일 번호를 입력하십시오(0을 반환)." file_choice + if [ "$file_choice" = "0" ]; then + return 0 fi - - # 2. 입력이 비어 있는지 확인하십시오. - if [ -z "$skill_name" ]; then - echo "오류: 스킬 이름은 비워둘 수 없습니다. 다시 시도해 주세요." - echo "" + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 continue fi - - # 3. 스킬이 설치되어 있는지 확인하세요 - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 스킬 [$skill_name]는 사용자 디렉토리에 설치됩니다." - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 스킬 [$skill_name]는 시스템 디렉토리에 설치됩니다." - skill_found=true - fi - - if [ "$skill_found" = true ]; then - read -e -p "다시 설치하시겠습니까? (예/아니요):" reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "설치를 건너뜁니다." - break_end - continue - fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "메모리 파일을 찾을 수 없습니다. 돌아가려면 Enter를 누르세요..." + return 0 fi - - # 4. 설치 명령을 실행합니다. - echo "기술 설치:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ 스킬$skill_name설치가 성공했습니다." - start_gateway - else - echo "❌ 설치에 실패했습니다. 스킬 이름이 올바른지 확인하시거나, 문제 해결을 위해 문서를 참고하시기 바랍니다." + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "잘못된 번호입니다. 다시 시도해 주세요." + sleep 1 + continue fi - - break_end - done + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "목록으로 돌아가려면 Enter를 누르세요..." + done } - - - change_tg_bot_code() { - send_stats "로봇 도킹" + openclaw_memory_menu() { + send_stats "OpenClaw 메모리 관리" while true; do clear - echo "========================================" - echo "로봇 연결 및 도킹" - echo "========================================" - echo "1. 텔레그램 로봇 도킹" - echo "2. Feishu(Lark) 로봇 도킹" - echo "3. WhatsApp 봇 도킹" - echo "----------------------------------------" - echo "0. 이전 메뉴로 돌아가기" - echo "----------------------------------------" - read -e -p "선택사항을 입력하세요:" bot_choice - - case $bot_choice in + echo "=======================================" + echo "OpenClaw 메모리 관리" + echo "=======================================" + openclaw_memory_render_status + echo "1. 메모리 인덱스 업데이트" + echo "2. 메모리 파일 보기" + echo "3. 인덱스 복구(인덱스 예외)" + echo "4. 메모리 솔루션(QMD/Local/Auto)" + echo "0. 이전 레벨로 돌아갑니다" + echo "---------------------------------------" + read -e -p "선택사항을 입력하세요:" memory_choice + case "$memory_choice" in 1) - read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi - openclaw pairing approve telegram "$code" - break_end + echo "메모리 인덱스는 곧 업데이트될 예정입니다." + read -e -p "첫 번째 확인: 계속하려면 yes를 입력하세요." confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "취소." + break_end + continue + fi + openclaw_memory_prepare_workspace + read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe + else + openclaw memory index --force + openclaw gateway restart + echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + fi + else + openclaw memory index + fi + break_end ;; 2) - read -e -p "Feishu Robot이 수신한 연결 코드(예: NYA99R2F)를 입력하십시오(종료하려면 0을 입력하십시오)." code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi - openclaw pairing approve feishu "$code" - break_end + openclaw_memory_files_menu ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi - openclaw pairing approve whatsapp "$code" - break_end + openclaw_memory_fix_index + ;; + 4) + openclaw_memory_scheme_menu ;; 0) return 0 @@ -10519,11 +13803,47 @@ EOF done } + openclaw_backup_restore_menu() { + + send_stats "OpenClaw 백업 및 복원" + while true; do + clear + echo "=======================================" + echo "OpenClaw 백업 및 복원" + echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" + echo "1. 메모리 전체를 백업하세요" + echo "2. 전체 메모리 복원" + echo "3. OpenClaw 프로젝트 백업(기본 안전 모드)" + echo "4. OpenClaw 프로젝트 복원(고급/고위험)" + echo "5. 백업 파일 삭제" + echo "0. 이전 레벨로 돌아갑니다" + echo "---------------------------------------" + read -e -p "선택사항을 입력하세요:" backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; + 0) return 0 ;; + *) + echo "선택이 잘못되었습니다. 다시 시도해 주세요." + sleep 1 + ;; + esac + done + } + update_moltbot() { echo "오픈클로 업데이트..." send_stats "오픈클로 업데이트..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -10703,7 +14023,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; @@ -10714,6 +14034,12 @@ EOF ;; 12) send_stats "상태 감지 및 복구" openclaw doctor --fix + send_stats "OpenClaw API 동기식 트리거링" + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." + fi break_end ;; 13) openclaw_webui_menu ;; @@ -10721,8 +14047,10 @@ EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done @@ -10833,7 +14161,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" - echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}ClawdBot/Moltbot 로봇${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -11058,7 +14386,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -11170,7 +14498,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -12409,7 +15737,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -13152,7 +16480,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -13520,7 +16848,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -14516,14 +17844,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - read -e -p "원격 서버 IP를 입력하세요:" remote_ip - read -e -p "대상 서버 SSH 포트 [기본값 22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "오류: 원격 서버 IP를 입력하세요." - continue - fi + kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -14547,7 +17870,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -14620,7 +17943,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -15018,7 +18341,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -15173,7 +18496,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -15549,8 +18872,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -15757,7 +19080,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간 가져오기 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -16585,26 +19908,13 @@ linux_file() { continue fi - read -e -p "원격 서버 IP를 입력하세요:" remote_ip - if [ -z "$remote_ip" ]; then - echo "오류: 원격 서버 IP를 입력하세요." - send_stats "파일 전송 실패: 원격 서버 IP가 입력되지 않았습니다." - continue - fi - - read -e -p "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" remote_user - remote_user=${remote_user:-root} - - read -e -p "원격 서버 비밀번호를 입력하세요:" -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "오류: 원격 서버 비밀번호를 입력하세요." - send_stats "파일 전송 실패: 원격 서버 비밀번호가 입력되지 않았습니다." - continue - fi + kj_ssh_read_host_user_port "원격 서버 IP를 입력하세요:" "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" "로그인 포트(기본값 22)를 입력하세요." "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "로그인 포트(기본값 22)를 입력하세요." remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "원격 서버 비밀번호를 입력하세요:" + local remote_password="$KJ_SSH_PASSWORD" # 알려진 호스트에 대한 이전 항목 지우기 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16822,7 +20132,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -17095,7 +20405,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 5f6946fa6..4ca78c571 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.3" +sh_v="4.4.7" gl_hui='\e[37m' @@ -538,7 +538,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "無效的選擇,請輸入 Y 或 N。" ;; esac ;; @@ -753,7 +753,7 @@ docker_ipv6_on() { echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # 使用jq處理設定檔的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # 檢查目前配置是否已經有 ipv6 設定 @@ -2192,7 +2192,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban防禦程序已卸載" break ;; @@ -2232,7 +2232,7 @@ web_security() { 22) send_stats "高負載開啟5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" @@ -4100,7 +4100,7 @@ EOF donlond_frp frps - # 输出生成的信息 + # 輸出產生的信息 ip_address echo "------------------------" echo "客戶端部署時所需使用的參數" @@ -4252,7 +4252,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 列印最後一個服務的訊息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4270,7 +4270,7 @@ get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# 產生訪問地址 generate_access_urls() { # 首先獲取所有連接埠 get_frp_ports @@ -4349,7 +4349,7 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" @@ -4438,7 +4438,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP客戶端$check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "與服務端對接,對接後可建立內網穿透服務到網際網路存取" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4972,7 +4972,7 @@ import_sshkey() { fi if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}錯誤:未輸入公鑰內容。${gl_bai}" return 1 fi @@ -5021,7 +5021,7 @@ fetch_remote_ssh_keys() { # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 + echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 rm -f "${temp_file}" return 1 } @@ -5037,7 +5037,7 @@ fetch_remote_ssh_keys() { return 1 fi - # 检查内容是否有效 + # 檢查內容是否有效 if [[ ! -s "${temp_file}" ]]; then echo "錯誤:下載到的檔案為空,URL 可能不包含任何公鑰" >&2 rm -f "${temp_file}" @@ -6606,7 +6606,7 @@ create_backup() { echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input - # 如果用户没有输入目录,则使用默认目录 + # 如果使用者沒有輸入目錄,則使用預設目錄 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6614,7 +6614,7 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 將使用者輸入的目錄以空格分隔成數組 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi @@ -6643,7 +6643,7 @@ create_backup() { install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # 檢查命令是否成功 if [ $? -eq 0 ]; then echo "備份建立成功:$BACKUP_DIR/$BACKUP_NAME" else @@ -6738,30 +6738,95 @@ linux_backup() { -# 顯示連線清單 -list_connections() { - echo "已儲存的連線:" - echo "------------------------" - cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' - echo "------------------------" +# SSH 輸入標準化函數 +kj_ssh_validate_host() { + local host="$1" + [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] } +kj_ssh_validate_port() { + local port="$1" + [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] +} -# 新增連接 -add_connection() { - send_stats "新增連接" - echo "建立新連接範例:" - echo "- 連線名稱: my_server" - echo "- IP位址: 192.168.1.100" - echo "- 使用者名稱: root" - echo "- 連接埠: 22" - echo "------------------------" - read -e -p "請輸入連線名稱:" name - read -e -p "請輸入IP位址:" ip - read -e -p "請輸入使用者名稱 (預設: root):" user - local user=${user:-root} # 如果用户未输入,则使用默认值 root - read -e -p "請輸入連接埠號碼 (預設: 22):" port - local port=${port:-22} # 如果用户未输入,则使用默认值 22 +kj_ssh_validate_user() { + local user="$1" + [[ -n "$user" && "$user" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]] +} + +kj_ssh_read_host_port() { + local host_prompt="$1" + local port_prompt="$2" + local default_port="${3:-22}" + + while true; do + read -e -p "$host_prompt" KJ_SSH_HOST + if kj_ssh_validate_host "$KJ_SSH_HOST"; then + break + fi + echo "錯誤: 請輸入有效的伺服器位址。" + done + + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + break + fi + echo "錯誤: 連接埠必須是 1-65535 之間的數字。" + done +} + +kj_ssh_read_host_user_port() { + local host_prompt="$1" + local user_prompt="$2" + local port_prompt="$3" + local default_user="${4:-root}" + local default_port="${5:-22}" + + kj_ssh_read_host_port "$host_prompt" "$port_prompt" "$default_port" + + while true; do + read -e -p "$user_prompt" KJ_SSH_USER + KJ_SSH_USER=${KJ_SSH_USER:-$default_user} + if kj_ssh_validate_user "$KJ_SSH_USER"; then + break + fi + echo "錯誤: 使用者名稱格式不正確。" + done +} + +kj_ssh_parse_remote() { + local remote_raw="$1" + local default_user="${2:-root}" + local remote_user remote_host + + if [[ "$remote_raw" == *@* ]]; then + remote_user="${remote_raw%@*}" + remote_host="${remote_raw#*@}" + else + remote_user="$default_user" + remote_host="$remote_raw" + fi + + if ! kj_ssh_validate_user "$remote_user"; then + echo "錯誤: SSH 使用者名稱格式不正確。" + return 1 + fi + + if ! kj_ssh_validate_host "$remote_host"; then + echo "錯誤: SSH 主機位址格式不正確。" + return 1 + fi + + KJ_SSH_USER="$remote_user" + KJ_SSH_HOST="$remote_host" + KJ_SSH_REMOTE="$remote_user@$remote_host" +} + +kj_ssh_read_auth() { + local key_file="$1" + local password_or_key="" echo "請選擇身份驗證方式:" echo "1. 密碼" @@ -6771,37 +6836,92 @@ add_connection() { case $auth_choice in 1) read -s -p "請輸入密碼:" password_or_key - echo # 换行 + echo + if [ -z "$password_or_key" ]; then + echo "錯誤: 密碼不能為空。" + return 1 + fi + KJ_SSH_AUTH_METHOD="password" + KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) echo "請貼上金鑰內容 (貼上完成後按兩次回車):" - local password_or_key="" while IFS= read -r line; do - # 如果輸入為空白行且金鑰內容已經包含了開頭,則結束輸入 if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break fi - # 如果是第一行或已經開始輸入金鑰內容,則繼續新增 if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - local password_or_key+="${line}"$'\n' + password_or_key+="${line}"$'\n' fi done - # 檢查是否為密鑰內容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/$name.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - local password_or_key="$key_file" + if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then + echo "無效的密鑰內容!" + return 1 fi + + mkdir -p "$(dirname "$key_file")" + echo -n "$password_or_key" > "$key_file" + chmod 600 "$key_file" + KJ_SSH_AUTH_METHOD="key" + KJ_SSH_AUTH_SECRET="$key_file" ;; *) echo "無效的選擇!" - return + return 1 ;; esac +} + +kj_ssh_read_password() { + local prompt="${1:-请输入密码: }" + while true; do + read -e -s -p "$prompt" KJ_SSH_PASSWORD + echo + [ -n "$KJ_SSH_PASSWORD" ] && break + echo "錯誤: 密碼不能為空。" + done +} + +kj_ssh_read_port() { + local port_prompt="$1" + local default_port="${2:-22}" + while true; do + read -e -p "$port_prompt" KJ_SSH_PORT + KJ_SSH_PORT=${KJ_SSH_PORT:-$default_port} + if kj_ssh_validate_port "$KJ_SSH_PORT"; then + return 0 + fi + echo "錯誤: 連接埠必須是 1-65535 之間的數字。" + done +} + +# 顯示連線清單 +list_connections() { + echo "已儲存的連線:" + echo "------------------------" + cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' + echo "------------------------" +} + + +# 新增連接 +add_connection() { + send_stats "新增連接" + echo "建立新連接範例:" + echo "- 連線名稱: my_server" + echo "- IP位址: 192.168.1.100" + echo "- 使用者名稱: root" + echo "- 連接埠: 22" + echo "------------------------" + read -e -p "請輸入連線名稱:" name + + kj_ssh_read_host_user_port "請輸入IP位址:" "請輸入使用者名稱 (預設: root):" "請輸入連接埠號碼 (預設: 22):" "root" "22" + if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then + return + fi - echo "$name|$ip|$user|$port|$password_or_key" >> "$CONFIG_FILE" + echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" echo "連線已儲存!" } @@ -6891,7 +7011,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -6922,7 +7042,7 @@ ssh_manager() { # 列出可用的硬碟分割區 list_partitions() { - echo "可用的硬盘分区:" + echo "可用的硬碟分割區:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } @@ -7134,52 +7254,23 @@ add_task() { read -e -p "請輸入任務名稱:" name read -e -p "請輸入本地目錄:" local_path read -e -p "請輸入遠端目錄:" remote_path - read -e -p "請輸入遠端使用者@IP:" remote - read -e -p "請輸入 SSH 連接埠 (預設 22):" port - port=${port:-22} - echo "請選擇身份驗證方式:" - echo "1. 密碼" - echo "2. 密鑰" - read -e -p "請選擇 (1/2):" auth_choice + while true; do + read -e -p "請輸入遠端使用者@IP:" remote + if kj_ssh_parse_remote "$remote" "root"; then + remote="$KJ_SSH_REMOTE" + break + fi + done - case $auth_choice in - 1) - read -s -p "請輸入密碼:" password_or_key - echo # 换行 - auth_method="password" - ;; - 2) - echo "請貼上金鑰內容 (貼上完成後按兩次回車):" - local password_or_key="" - while IFS= read -r line; do - # 如果輸入為空白行且金鑰內容已經包含了開頭,則結束輸入 - if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then - break - fi - # 如果是第一行或已經開始輸入金鑰內容,則繼續新增 - if [[ -n "$line" || "$password_or_key" == *"-----BEGIN"* ]]; then - password_or_key+="${line}"$'\n' - fi - done + kj_ssh_read_port "請輸入 SSH 連接埠 (預設 22):" "22" + port="$KJ_SSH_PORT" - # 檢查是否為密鑰內容 - if [[ "$password_or_key" == *"-----BEGIN"* && "$password_or_key" == *"PRIVATE KEY-----"* ]]; then - local key_file="$KEY_DIR/${name}_sync.key" - echo -n "$password_or_key" > "$key_file" - chmod 600 "$key_file" - password_or_key="$key_file" - auth_method="key" - else - echo "無效的密鑰內容!" - return - fi - ;; - *) - echo "無效的選擇!" - return - ;; - esac + if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then + return + fi + auth_method="$KJ_SSH_AUTH_METHOD" + password_or_key="$KJ_SSH_AUTH_SECRET" echo "請選擇同步模式:" echo "1. 標準模式 (-avz)" @@ -7198,6 +7289,7 @@ add_task() { echo "任務已儲存!" } + # 刪除任務 delete_task() { send_stats "刪除同步任務" @@ -7498,7 +7590,7 @@ linux_info() { echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" echo @@ -7573,7 +7665,7 @@ linux_tools() { echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文字編輯器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI程式設計助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8137,10 +8229,10 @@ docker_ssh_migration() { read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } - read -e -p "目標伺服器IP:" TARGET_IP - read -e -p "目標伺服器SSH用戶名:" TARGET_USER - read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} + kj_ssh_read_host_user_port "目標伺服器IP:" "目標伺服器SSH用戶名 [預設root]:" "目標伺服器SSH連接埠 [預設22]:" "root" "22" + local TARGET_IP="$KJ_SSH_HOST" + local TARGET_USER="$KJ_SSH_USER" + local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" @@ -8499,7 +8591,7 @@ linux_test() { # send_stats "測試腳本集合" echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}IP及解鎖狀態偵測" echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" echo -e "${gl_kjlan}2. ${gl_bai}Region 串流解鎖測試" echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 串流媒體解鎖偵測" @@ -8582,7 +8674,7 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京电信: 219.141.136.12" + echo "北京電信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" @@ -9527,7 +9619,7 @@ linux_ldnmp() { 30) clear - webname="静态站点" + webname="靜態站點" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -9604,13 +9696,9 @@ linux_ldnmp() { read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "請輸入遠端伺服器IP:" remote_ip - read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端伺服器IP。" - continue - fi + kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -9758,7 +9846,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "請輸入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "請輸入${ldnmp_pods}版本號碼 (如: 8.0 8.3 8.4 9.0)(回車取得最新版):" version local version=${version:-latest} cd /home/web/ @@ -9956,18 +10044,20 @@ moltbot_menu() { echo "--------------------" echo "4. 狀態日誌查看" echo "5. 換模型" - echo "6. 加新模型API" + echo "6. API管理" echo "7. 機器人連線對接" - echo "8. 安裝插件(如:飛書)" - echo "9. 安裝技能(skills)" + echo "8. 插件管理(安裝/刪除)" + echo "9. 技能管理(安裝/刪除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" echo "12. 健康檢測與修復" echo "13. WebUI存取與設置" echo "14. TUI命令列對話窗口" + echo "15. 記憶/Memory" echo "--------------------" - echo "15. 更新" - echo "16. 卸載" + echo "16. 備份與還原" + echo "17. 更新" + echo "18. 卸載" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -9997,6 +10087,459 @@ moltbot_menu() { fi } + configure_openclaw_session_policy() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 1 + + python3 - "$config_file" <<'PY' +import json, sys +path = sys.argv[1] +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +session = obj.setdefault('session', {}) +session['dmScope'] = session.get('dmScope', 'per-channel-peer') +session['resetTriggers'] = ['/new', '/reset'] +session['reset'] = { + 'mode': 'idle', + 'idleMinutes': 10080 +} +session['resetByType'] = { + 'direct': {'mode': 'idle', 'idleMinutes': 10080}, + 'thread': {'mode': 'idle', 'idleMinutes': 1440}, + 'group': {'mode': 'idle', 'idleMinutes': 120} +} + +with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') +PY + } + + + sync_openclaw_api_models() { + local config_file="${HOME}/.openclaw/openclaw.json" + + [ ! -f "$config_file" ] && return 0 + + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$ENABLE_STATS" "$sh_v" <<'PY' +import copy +import json +import os +import platform +import sys +import time +import urllib.request +from datetime import datetime, timezone + +path = sys.argv[1] +stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True +script_version = sys.argv[3] if len(sys.argv) > 3 else "" + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def send_stat(action): + if not stats_enabled: + return + payload = { + "action": action, + "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), + "country": "", + "os_info": platform.platform(), + "cpu_arch": platform.machine(), + "version": script_version, + } + try: + req = urllib.request.Request( + "https://api.kejilion.pro/api/log", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(req, timeout=3): + pass + except Exception: + pass + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('ℹ️ 未偵測到 API providers,跳過模型同步') + raise SystemExit(0) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +changed = False +fatal_errors = [] +summary = [] + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +def prompt_delete_provider(name): + prompt = f"⚠️ {name} /models 偵測連續失敗 3 次。是否刪除該 API 供應商及其全部相關模型? [y/N]:" + try: + ans = input(prompt).strip().lower() + except EOFError: + return False + return ans in ('y', 'yes') + + +def rebind_defaults_before_delete(name): + global changed + + replacement = None + + def get_replacement(): + nonlocal replacement + if replacement is None: + candidates = collect_available_refs(exclude_provider=name) + replacement = candidates[0] if candidates else None + return replacement + + primary_ref = get_primary_ref(defaults) + if ref_provider(primary_ref) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: 預設主模型指向該 provider,但無可用替代模型,已中止刪除') + return False + set_primary_ref(defaults, repl) + changed = True + summary.append(f'🔁 刪除前已切換預設主模型: {primary_ref} -> {repl}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + repl = get_replacement() + if not repl: + summary.append(f'❌ {name}: {fk} 指向該 provider,但無可用替代模型,已中止刪除') + return False + defaults[fk] = repl + changed = True + summary.append(f'🔁 刪除前已切換 {fk}: {val} -> {repl}') + + return True + + +def delete_provider_and_refs(name): + global changed + + if not rebind_defaults_before_delete(name): + return False + + removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] + for r in removed_refs: + defaults_models.pop(r, None) + if removed_refs: + changed = True + + if name in providers: + providers.pop(name, None) + changed = True + + summary.append(f'🗑️ 已刪除 provider {name},並移除 defaults.models 下 {len(removed_refs)} 個模型引用') + return True + + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + + +def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + data = json.loads(payload) + return data, None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +for name, provider in list(providers.items()): + if not isinstance(provider, dict): + summary.append(f'ℹ️ 跳過 {name}: provider 結構非法') + continue + + api = provider.get('api', '') + base_url = provider.get('baseUrl') + api_key = provider.get('apiKey') + model_list = provider.get('models', []) + + if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + summary.append(f'ℹ️ 跳過 {name}: 無 baseUrl/apiKey/models') + continue + + if api not in SUPPORTED_APIS: + summary.append(f'🔁 {name}: 發現非法協定 {api or "(unset)"},將重新探測') + provider['api'] = '' + api = '' + changed = True + + try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + changed = True + summary.append(f'🔁 {name}: 已自動修正協定為 {detected_api} ({detected_reason})') + except Exception as e: + summary.append(f'⚠️ {name}: 協定偵測失敗,跳過修正 ({type(e).__name__}: {e})') + + data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) + if err is not None: + summary.append(f'⚠️ {name}: /models 偵測失敗,已重試 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API確認介入') + if prompt_delete_provider(name): + deleted = delete_provider_and_refs(name) + if deleted: + send_stat('OpenClaw API刪失敗Provider-確認') + summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') + else: + send_stat('OpenClaw API刪失敗Provider-拒絕') + summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') + continue + + if attempts > 1: + summary.append(f'🔁 {name}: /models 第 {attempts} 次重試後成功') + + if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + summary.append(f'⚠️ 跳過 {name}: /models 回傳結構不可識別') + continue + + remote_ids = [] + for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) + remote_set = set(remote_ids) + + if not remote_set: + fatal_errors.append(f'❌ {name} 上游 /models 為空,無法為該 provider 提供兜底模型') + continue + + local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] + local_ids = [str(m['id']) for m in local_models] + local_set = set(local_ids) + + template = None + for m in local_models: + template = copy.deepcopy(m) + break + if template is None: + summary.append(f'⚠️ 跳過 {name}: 本地 models 無有效模板模型') + continue + + removed_ids = [mid for mid in local_ids if mid not in remote_set] + added_ids = [mid for mid in remote_ids if mid not in local_set] + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 刪除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] + new_models = kept_models[:] + + for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{name} / {mid}' + new_models.append(nm) + + if not new_models: + fatal_errors.append(f'❌ {name} 同步後無可用模型,無法保障預設模型/回退模型兜底') + continue + + expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} + local_refs = {model_ref(name, mid) for mid in local_ids} + + first_ref = model_ref(name, str(new_models[0]['id'])) + + primary_ref = get_primary_ref(defaults) + if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): + set_primary_ref(defaults, first_ref) + changed = True + summary.append(f'🔁 預設模型已兜底替換: {primary_ref} -> {first_ref}') + + for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in (local_refs - expected_refs): + defaults[fk] = first_ref + changed = True + summary.append(f'🔁 {fk} 已兜底替換: {val} -> {first_ref}') + + stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] + for r in stale_refs: + defaults_models.pop(r, None) + changed = True + + for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + + if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + + summary.append(f'✅ {name}: 刪除 {len(removed_ids)} 個,新增 {len(added_ids)} 個,目前 {len(new_models)} 個') + +if fatal_errors: + for line in summary: + print(line) + for err in fatal_errors: + print(err) + print('❌ 模型同步失敗:存在 provider 同步後無可用模型,已中止寫入') + raise SystemExit(2) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + for line in summary: + print(line) + print('✅ OpenClaw API 模型一致性同步完成並已寫入配置') +else: + for line in summary: + print(line) + print('ℹ️ 無需同步:配置已與上游 /models 保持一致') +PY + } + + + install_moltbot() { echo "開始安裝 OpenClaw..." send_stats "開始安裝 OpenClaw..." @@ -10013,7 +10556,9 @@ moltbot_menu() { npm install -g openclaw@latest openclaw onboard --install-daemon - sed -i 's|"profile": "messaging"|"profile": "full"|g' ~/.openclaw/openclaw.json + openclaw config set tools.profile full + # 提示:修改配置後如需立即生效,可重新啟動 gateway:openclaw gateway restart + configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10049,6 +10594,44 @@ moltbot_menu() { + # OpenClaw API 協定探測(優先 responses -> completions) + openclaw_probe_api_endpoint() { + local base_url="$1" + local api_key="$2" + local path="$3" + local url="${base_url%/}${path}" + local http_code + http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ + -X POST \ + -H "Authorization: Bearer $api_key" \ + -H "Content-Type: application/json" \ + -d '{}' "$url" 2>/dev/null || echo "000") + if [ -z "$http_code" ]; then + http_code="000" + fi + echo "$http_code" + } + + openclaw_detect_api_protocol() { + local base_url="$1" + local api_key="$2" + local code_responses="000" + + DETECTED_API="openai-completions" + DETECTED_REASON="fallback: /responses not supported" + + code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") + if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + DETECTED_API="openai-responses" + DETECTED_REASON="POST /responses -> HTTP $code_responses" + return 0 + fi + + DETECTED_API="openai-completions" + DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + return 0 + } + # 核心函數:取得並加入所有模型 add-all-models-from-provider() { local provider_name="$1" @@ -10058,6 +10641,10 @@ moltbot_menu() { echo "🔍 正在獲取$provider_name的所有可用模型..." + # 自動識別 API 協議 + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + # 取得模型列表 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10133,10 +10720,11 @@ EOF # 備份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型 + # 使用jq注入所有模型,並同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ + --arg api "$DETECTED_API" \ --argjson models "$models_array" \ ' .models |= ( @@ -10145,10 +10733,26 @@ EOF | .providers[$prov] = { baseUrl: $url, apiKey: $key, - api: "openai-completions", + api: $api, models: $models } ) + | .agents |= (. // {}) + | .agents.defaults |= (. // {}) + | .agents.defaults.models |= ( + (if type == "object" then . + elif type == "array" then reduce .[] as $m ({}; if ($m|type) == "string" then .[$m] = {} else . end) + else {} + end) as $existing + | reduce ($models[]? | .id? // empty | tostring) as $mid ( + $existing; + if ($mid | length) > 0 then + .["\($prov)/\($mid)"] //= {} + else + . + end + ) + ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then @@ -10162,7 +10766,7 @@ EOF } add-openclaw-provider-interactive() { - send_stats "新增API" + send_stats "OpenClaw API新增" echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 @@ -10189,7 +10793,11 @@ EOF echo done - # 4. 取得模型列表 + # 4. 協議探測(無感) + install curl >/dev/null 2>&1 + openclaw_detect_api_protocol "$base_url" "$api_key" + + # 5. 取得模型列表 echo "🔍 正在取得可用模型清單..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ @@ -10204,10 +10812,10 @@ EOF echo "--------------------------------" # 全部顯示,附序號 i=1 - declare -A model_map + model_list=() while read -r model; do echo "[$i] $model" - model_map[$i]="$model" + model_list+=("$model") ((i++)) done <<< "$available_models" echo "--------------------------------" @@ -10221,8 +10829,8 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) echo "🎯 使用第一個模型:$default_model" - elif [[ -n "${model_map[$input_model]}" ]]; then - default_model="${model_map[$input_model]}" + elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + default_model="${model_list[$((input_model-1))]}" echo "🎯 已選擇模型:$default_model" else default_model="$input_model" @@ -10253,260 +10861,2936 @@ EOF openclaw models set "$provider_name/$default_model" start_gateway echo "✅ 完成!所有$model_count個模型已載入" + echo "✅ 已自動辨識協定為:$DETECTED_API" fi break_end } + +openclaw_api_manage_list() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API列表" - change_model() { - send_stats "換模型" - - while true; do - clear - echo "--- 模型管理 ---" - echo "所有模型:" - openclaw models list --all - echo "----------------" - echo "當前模型:" - openclaw models list - echo "----------------" - read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" model - - # 1. 檢查是否輸入 0 退出 - if [ "$model" = "0" ]; then - echo "操作已取消,正在退出..." - break # 跳出 while 循环 - - fi + while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do + case "$rec_type" in + MSG) + echo "$idx" + ;; + ROW) + local latency_color="$gl_bai" + case "$latency_level" in + low) latency_color="$gl_lv" ;; + medium) latency_color="$gl_huang" ;; + high|unavailable) latency_color="$gl_hong" ;; + unchecked) latency_color="$gl_bai" ;; + esac - # 2. 驗證輸入是否為空 - if [ -z "$model" ]; then - echo "錯誤:模型名稱不能為空。請重試。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 - fi + printf '%b\n' "[$idx] ${name} | API: ${base_url}| 協議:${api_type}| 模型數量:${gl_huang}${model_count}${gl_bai}| 延遲/狀態:${latency_color}${latency_txt}${gl_bai}" + ;; + esac + done < <(python3 - "$config_file" <<-'PY' +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + + +def ping_models(base_url, api_key): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + ) + start = time.perf_counter() + with urllib.request.urlopen(req, timeout=4) as resp: + resp.read(2048) + return int((time.perf_counter() - start) * 1000) + + +def classify_latency(latency): + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未檢測': + return '未檢測', 'unchecked' + if isinstance(latency, int): + if latency <= 800: + level = 'low' + elif latency <= 2000: + level = 'medium' + else: + level = 'high' + return f'{latency}ms', level + return str(latency), 'unchecked' + + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('MSG\tℹ️ 未找到 openclaw.json,請先完成安裝/初始化。') + raise SystemExit(0) +except Exception as e: + print(f'MSG\t❌ 讀取設定失敗: {type(e).__name__}: {e}') + raise SystemExit(0) + +providers = ((obj.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or not providers: + print('MSG\tℹ️ 目前未配置任何 API provider。') + raise SystemExit(0) + +print('MSG\t--- 已設定 API 清單 ---') + +for idx, name in enumerate(sorted(providers.keys()), start=1): + provider = providers.get(name) + if not isinstance(provider, dict): + base_url = '-' + model_count = 0 + latency_raw = '不可用' + else: + base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' + models = provider.get('models') if isinstance(provider.get('models'), list) else [] + model_count = sum(1 for m in models if isinstance(m, dict) and m.get('id')) + api = provider.get('api', '') + api_key = provider.get('apiKey') + + latency_raw = '未檢測' + if api in SUPPORTED_APIS: + if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: + try: + latency_raw = ping_models(base_url, api_key) + except Exception: + latency_raw = '不可用' + else: + latency_raw = '不可用' + + latency_text, latency_level = classify_latency(latency_raw) + api_label = api if api in SUPPORTED_APIS else '-' + print( + 'ROW\t' + '\t'.join([ + str(idx), + str(name), + str(base_url), + str(model_count), + str(api_label), + str(latency_text), + str(latency_level), + ]) + ) +PY +) +} +sync-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API按Provider同步" - # 3. 執行切換邏輯 - echo "正在切換模型為:$model ..." - openclaw models set "$model" + if [ ! -f "$config_file" ]; then + echo "❌ 未找到設定檔:$config_file" + break_end + return 1 + fi - break_end - done + read -erp "請輸入要同步的 API 名稱(provider):" provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名稱不能為空" + break_end + return 1 + fi - } + install jq curl >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" <<'PY2' +import copy +import json +import sys +import time +import urllib.request + +path = sys.argv[1] +target = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or not providers: + print('❌ 未偵測到 API providers,無法同步') + raise SystemExit(2) + +provider = providers.get(target) +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {target}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def fetch_remote_models_with_retry(base_url, api_key, retries=3): + last_error = None + for attempt in range(1, retries + 1): + req = urllib.request.Request( + base_url.rstrip('/') + '/models', + headers={ + 'Authorization': f'Bearer {api_key}', + 'User-Agent': 'Mozilla/5.0', + }, + ) + try: + with urllib.request.urlopen(req, timeout=12) as resp: + payload = resp.read().decode('utf-8', 'ignore') + return json.loads(payload), None, attempt + except Exception as e: + last_error = e + if attempt < retries: + time.sleep(1) + return None, last_error, retries + + +api = provider.get('api', '') +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +model_list = provider.get('models', []) + +if not base_url or not api_key or not isinstance(model_list, list) or not model_list: + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,無法執行同步') + raise SystemExit(3) + +if api not in SUPPORTED_APIS: + print(f'ℹ️ provider {target} 目前 api={api},重新探測協定後繼續') + provider['api'] = '' + api = '' + +protocol_msg = None +try: + detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) + if detected_api and api != detected_api: + provider['api'] = detected_api + api = detected_api + protocol_msg = f'🔁 已自動修正協定: {target} {api} ({detected_reason})' +except Exception as e: + protocol_msg = f'⚠️ 協定探測失敗,跳過修正: {target} ({type(e).__name__}: {e})' + +data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) +if err is not None: + print(f'❌ {target}: /models 探測失敗,已重試 {attempts} 次 ({type(err).__name__}: {err})') + raise SystemExit(4) + +if not (isinstance(data, dict) and isinstance(data.get('data'), list)): + print(f'❌ {target}: /models 回傳結構不可識別') + raise SystemExit(4) + +remote_ids = [] +for item in data['data']: + if isinstance(item, dict) and item.get('id'): + remote_ids.append(str(item['id'])) +remote_set = set(remote_ids) +if not remote_set: + print(f'❌ {target}: 上游 /models 為空,已中止同步') + raise SystemExit(5) + +local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] +local_ids = [str(m['id']) for m in local_models] +local_set = set(local_ids) + +template = copy.deepcopy(local_models[0]) if local_models else None +if template is None: + print(f'❌ {target}: 本地 models 無有效模板模型,無法補全新增模型') + raise SystemExit(3) + +removed_ids = [mid for mid in local_ids if mid not in remote_set] +added_ids = [mid for mid in remote_ids if mid not in local_set] + +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 刪除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + +kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] +new_models = kept_models[:] +for mid in added_ids: + nm = copy.deepcopy(template) + nm['id'] = mid + if isinstance(nm.get('name'), str): + nm['name'] = f'{target} / {mid}' + new_models.append(nm) + +if not new_models: + print(f'❌ {target}: 同步後無可用模型,已中止寫入') + raise SystemExit(5) + +expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} +local_refs = {model_ref(target, mid) for mid in local_ids} +removed_refs = local_refs - expected_refs +first_ref = model_ref(target, str(new_models[0]['id'])) + +changed = False +primary_ref = get_primary_ref(defaults) +if isinstance(primary_ref, str) and primary_ref in removed_refs: + set_primary_ref(defaults, first_ref) + changed = True + print(f'🔁 預設模型已兜底替換: {primary_ref} -> {first_ref}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if isinstance(val, str) and val in removed_refs: + defaults[fk] = first_ref + changed = True + print(f'🔁 {fk} 已兜底替換: {val} -> {first_ref}') + +stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] +for r in stale_refs: + defaults_models.pop(r, None) + changed = True + +for r in sorted(expected_refs): + if r not in defaults_models: + defaults_models[r] = {} + changed = True + +if removed_ids or added_ids or len(local_models) != len(new_models): + provider['models'] = new_models + changed = True + +if protocol_msg: + print(protocol_msg) + +if changed: + with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ {target}: 刪除 {len(removed_ids)} 個,新增 {len(added_ids)} 個,目前 {len(new_models)} 個') +if changed: + print('✅ 指定 provider 模型一致性同步完成並已寫入配置') +else: + print('ℹ️ 無需同步:此 provider 配置已與上游 /models 保持一致') +PY2 + local rc=$? + case "$rc" in + 0) + echo "✅ 同步執行完成" + start_gateway + ;; + 2) + echo "❌ 同步失敗:provider 不存在或未配置" + ;; + 3) + echo "❌ 同步失敗:provider 配置不完整或類型不支持" + ;; + 4) + echo "❌ 同步失敗:上游 /models 請求失敗" + ;; + 5) + echo "❌ 同步失敗:上游模型為空或同步後無可用模型" + ;; + *) + echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" + ;; + esac + break_end +} +openclaw_detect_api_protocol_by_provider() { + local config_file="$1" + local provider_name="$2" + + python3 - "$config_file" "$provider_name" <<'PY' +import json +import sys +import urllib.request + +path = sys.argv[1] +name = sys.argv[2] +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} + +def probe_endpoint(base_url, api_key, path, timeout=6): + url = base_url.rstrip('/') + path + req = urllib.request.Request( + url, + data=b'{}', + headers={ + 'Authorization': f'Bearer {api_key}', + 'Content-Type': 'application/json', + 'User-Agent': 'OpenClaw-API-Manage/1.0', + }, + method='POST', + ) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.getcode(), None + except urllib.error.HTTPError as e: + return e.code, None + except Exception as e: + return None, e + + +def detect_api_protocol(base_url, api_key): + code, err = probe_endpoint(base_url, api_key, '/responses') + if code is not None and code not in (404, 405): + return 'openai-responses', f'POST /responses -> HTTP {code}', None + if err: + return 'openai-completions', 'fallback: probe failed', err + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + +try: + with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) +except FileNotFoundError: + print('❌ 找不到 openclaw.json') + raise SystemExit(2) + +providers = ((obj.get('models') or {}).get('providers') or {}) +provider = providers.get(name) if isinstance(providers, dict) else None +if not isinstance(provider, dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +base_url = provider.get('baseUrl') +api_key = provider.get('apiKey') +if not base_url or not api_key: + print(f'❌ provider {name} 缺少 baseUrl/apiKey') + raise SystemExit(3) + +current_api = provider.get('api', '') +if current_api not in SUPPORTED_APIS: + current_api = '' + +api, reason, err = detect_api_protocol(base_url, api_key) +if api and api != current_api: + provider['api'] = api + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, ensure_ascii=False, indent=2) + f.write('\n') + print(f'✅ 已更新 provider {name} 協定: {current_api or "(unset)"} -> {api} ({reason})') +else: + print(f'ℹ️ 無需更新:協議保持為 {current_api or api}') +PY +} +fix-openclaw-provider-protocol-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API協定修復" - install_plugin() { - send_stats "安裝插件" - while true; do - clear - echo "========================================" - echo "外掛程式管理 (安裝)" - echo "========================================" - echo "當前插件列表:" - openclaw plugins list - echo "--------------------------------------------------------" - echo "推薦的常用外掛 ID (直接複製括號內的 ID 即可):" - echo "--------------------------------------------------------" - echo "📱 通訊頻道:" - echo "- [feishu] # 飛書/Lark 集成" - echo "- [telegram] # Telegram 機器人" - echo "- [slack] # Slack 企業通訊" - echo " - [msteams] # Microsoft Teams" - echo "- [discord] # Discord 社群管理" - echo "- [whatsapp] # WhatsApp 自動化" - echo "" - echo "🧠 記憶與 AI:" - echo "- [memory-core] # 基礎記憶 (文件檢索)" - echo "- [memory-lancedb] # 增強記憶 (向量資料庫)" - echo "- [copilot-proxy] # Copilot 介面轉發" - echo "" - echo "⚙️ 功能擴充:" - echo "- [lobster] # 審批流 (附人工確認)" - echo "- [voice-call] # 語音通話能力" - echo " - [nostr] # 加密隐私聊天" - echo "--------------------------------------------------------" + if [ ! -f "$config_file" ]; then + echo "❌ 未找到設定檔:$config_file" + break_end + return 1 + fi - read -e -p "請輸入外掛 ID(輸入 0 退出):" raw_input + read -erp "請輸入要修復協定的 API 名稱(provider):" provider_name + if [ -z "$provider_name" ]; then + echo "❌ provider 名稱不能為空" + break_end + return 1 + fi - [ "$raw_input" = "0" ] && break - [ -z "$raw_input" ] && continue + install jq curl >/dev/null 2>&1 + openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + local rc=$? + case "$rc" in + 0) + echo "✅ 協議已檢測並更新(如有變更)" + start_gateway + ;; + 2) + echo "❌ 修復失敗:provider 不存在或未配置" + ;; + 3) + echo "❌ 修復失敗:provider 配置不完整" + ;; + *) + echo "❌ 修復失敗:請檢查設定檔結構或日誌輸出" + ;; + esac - # 1. 自動處理:如果使用者輸入帶 @openclaw/,提取純 ID 方便路徑檢查 - local plugin_id=$(echo "$raw_input" | sed 's|^@openclaw/||') - local plugin_full="$raw_input" + break_end +} - echo "🔍 正在檢查插件狀態..." - # 取得目前插件清單用於狀態檢測 - local plugin_list=$(openclaw plugins list 2>/dev/null) + delete-openclaw-provider-interactive() { + local config_file="${HOME}/.openclaw/openclaw.json" + send_stats "OpenClaw API刪除入口" - # 2. 檢查是否已經在 list 中且為 disabled (最常見的情況) - if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." - openclaw plugins enable "$plugin_id" && echo "✅ 啟動成功" || echo "❌ 啟動失敗" + if [ ! -f "$config_file" ]; then + echo "❌ 未找到設定檔:$config_file" + break_end + return 1 + fi + + read -erp "請輸入要刪除的 API 名稱(provider):" provider_name + if [ -z "$provider_name" ]; then + send_stats "OpenClaw API刪除取消" + echo "❌ provider 名稱不能為空" + break_end + return 1 + fi + + python3 - "$config_file" "$provider_name" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +models_cfg = work.setdefault('models', {}) +providers = models_cfg.get('providers', {}) +if not isinstance(providers, dict) or name not in providers: + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +agents = work.setdefault('agents', {}) +defaults = agents.setdefault('defaults', {}) +defaults_models_raw = defaults.get('models') +if isinstance(defaults_models_raw, dict): + defaults_models = defaults_models_raw +elif isinstance(defaults_models_raw, list): + defaults_models = {str(x): {} for x in defaults_models_raw if isinstance(x, str)} +else: + defaults_models = {} +defaults['models'] = defaults_models + + +def model_ref(provider_name, model_id): + return f"{provider_name}/{model_id}" + + +def ref_provider(ref): + if not isinstance(ref, str) or '/' not in ref: + return None + return ref.split('/', 1)[0] + + +def get_primary_ref(defaults_obj): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + return model_obj + if isinstance(model_obj, dict): + primary = model_obj.get('primary') + if isinstance(primary, str): + return primary + return None + + +def set_primary_ref(defaults_obj, new_ref): + model_obj = defaults_obj.get('model') + if isinstance(model_obj, str): + defaults_obj['model'] = new_ref + elif isinstance(model_obj, dict): + model_obj['primary'] = new_ref + else: + defaults_obj['model'] = {'primary': new_ref} + + +def collect_available_refs(exclude_provider=None): + refs = [] + if not isinstance(providers, dict): + return refs + for pname, p in providers.items(): + if exclude_provider and pname == exclude_provider: + continue + if not isinstance(p, dict): + continue + for m in p.get('models', []) or []: + if isinstance(m, dict) and m.get('id'): + refs.append(model_ref(pname, str(m['id']))) + return refs + + +replacement_candidates = collect_available_refs(exclude_provider=name) +replacement = replacement_candidates[0] if replacement_candidates else None + +primary_ref = get_primary_ref(defaults) +if ref_provider(primary_ref) == name: + if not replacement: + print('❌ 刪除中止:預設主模型指向該 provider,且無可用替代模型') + raise SystemExit(3) + set_primary_ref(defaults, replacement) + print(f'🔁 預設主模型切換: {primary_ref} -> {replacement}') + +for fk in ('modelFallback', 'imageModelFallback'): + val = defaults.get(fk) + if ref_provider(val) == name: + if not replacement: + print(f'❌ 刪除中止:{fk} 指向該 provider,且無可用替代模型') + raise SystemExit(3) + defaults[fk] = replacement + print(f'🔁 {fk} 切換: {val} -> {replacement}') + +removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] +for r in removed_refs: + defaults_models.pop(r, None) + +providers.pop(name, None) + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'🗑️ 已刪除 provider: {name}') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 個關聯模型引用') +PY + local rc=$? + case "$rc" in + 0) + send_stats "OpenClaw API刪除確認" + echo "✅ 刪除完成" + start_gateway + ;; + 2) + echo "❌ 刪除失敗:provider 不存在" + ;; + 3) + send_stats "OpenClaw API刪除取消" + echo "❌ 刪除失敗:無可用替代模型,已保持原始配置" + ;; + *) + echo "❌ 刪除失敗:請檢查設定檔結構或日誌輸出" + ;; + esac + + break_end + } + + openclaw_api_manage_menu() { + send_stats "OpenClaw API入口" + while true; do + clear + echo "=======================================" + echo "OpenClaw API 管理" + echo "=======================================" + openclaw_api_manage_list + echo "---------------------------------------" + echo "1. 新增API" + echo "2. 同步API供應商模型列表" + echo "3. 刪除API" + echo "4. 協議修復/重新探測" + echo "0. 退出" + echo "---------------------------------------" + read -erp "請輸入你的選擇:" api_choice + + case "$api_choice" in + 1) + add-openclaw-provider-interactive + ;; + 2) + sync-openclaw-provider-interactive + ;; + 3) + delete-openclaw-provider-interactive + ;; + 4) + fix-openclaw-provider-protocol-interactive + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } + + + + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + if [ -f /etc/debian_version ]; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "換模型" + + local orange="#FF8C00" + + clear + + while true; do + local models_raw models_list default_model model_count selected_model + + # 從設定檔讀取模型鍵(不呼叫 openclaw models list) + local oc_config + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + + models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') + if [ -z "$models_raw" ]; then + echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" + break_end + return 1 + fi + + # 為每個模型加編號,方便快速定位(例如:"(10) or-api/...:free") + models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') + model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') + + # 從設定檔讀取預設模型(更快);失敗再回退到 openclaw 指令 + default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) + [ -z "$default_model" ] && default_model="(unknown)" + + + install_gum + install gum + + clear + + # 若 gum 不存在,降級為原始手動輸入流程(保持與之前完全一致) + if ! command -v gum >/dev/null 2>&1; then + echo "--- 模型管理 ---" + echo "目前可用模型:" + jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' + echo "----------------" + read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" selected_model + + # 1. 檢查是否輸入 0 退出 + if [ "$selected_model" = "0" ]; then + echo "操作已取消,正在退出..." + break # 跳出 while 循环 + fi + + # 2. 驗證輸入是否為空 + if [ -z "$selected_model" ]; then + echo "錯誤:模型名稱不能為空。請重試。" + echo "" # 换行美化 + continue # 跳过本次循环,重新开始 + fi + else + gum style --foreground "$orange" --bold "模型管理" + gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" + gum style --foreground "$orange" "目前預設:${default_model}" + echo "" + + # 底部提示 + gum style --faint "↑↓ 選擇 / Enter 確認 / Esc 退出" + echo "" + + # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "搜尋模型(如 cli-api/gpt-5.2)" \ + --prompt "選擇模型 >" \ + --indicator "➜ " \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor-text.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 35) + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then + echo "操作已取消,正在退出..." + break + fi + fi + + # 去掉編號前綴:"(10) model" -> "model" + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + + # 執行切換 + echo "正在切換模型為:$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切換失敗:openclaw models set 回傳錯誤。" + break_end + return 1 + fi + start_gateway + + break_end + done + } + + + resolve_openclaw_plugin_id() { + local raw_input="$1" + local plugin_id="$raw_input" + + plugin_id="${plugin_id#@openclaw/}" + if [[ "$plugin_id" == @*/* ]]; then + plugin_id="${plugin_id##*/}" + fi + plugin_id="${plugin_id%%@*}" + echo "$plugin_id" + } + + sync_openclaw_plugin_allowlist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已同步 plugins.allow 白名單:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +if plugin_id not in a: + a.append(plugin_id) + +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已同步 plugins.allow 白名單:$plugin_id" + return 0 + fi + fi + + echo "⚠️ 已安裝插件,但同步 plugins.allow 失敗,請手動檢查:$config_file" + return 1 + } + + sync_openclaw_plugin_denylist() { + local plugin_id="$1" + [ -z "$plugin_id" ] && return 1 + + local home_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + local config_file="$home_config" + if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then + config_file="$root_config" + fi + + mkdir -p "$(dirname "$config_file")" + if [ ! -s "$config_file" ]; then + echo '{}' > "$config_file" + fi + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if jq --arg pid "$plugin_id" ' + .plugins = (if (.plugins | type) == "object" then .plugins else {} end) + | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) + | .plugins.allow = (.plugins.allow | map(select(. != $pid))) + ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then + echo "✅ 已從 plugins.allow 移除:$plugin_id" + return 0 + fi + rm -f "$tmp_json" + fi + + if command -v python3 >/dev/null 2>&1; then + if python3 - "$config_file" "$plugin_id" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path + +config_file = Path(sys.argv[1]) +plugin_id = sys.argv[2] + +try: + data = json.loads(config_file.read_text(encoding='utf-8')) if config_file.exists() else {} + if not isinstance(data, dict): + data = {} +except Exception: + data = {} + +plugins = data.get('plugins') +if not isinstance(plugins, dict): + plugins = {} + +a = plugins.get('allow') +if not isinstance(a, list): + a = [] + +a = [x for x in a if x != plugin_id] +plugins['allow'] = a +data['plugins'] = plugins +config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') +PYTHON_EOF + then + echo "✅ 已從 plugins.allow 移除:$plugin_id" + return 0 + fi + fi + + echo "⚠️ plugins.allow 移除失敗,請手動檢查:$config_file" + return 1 + } + + + + + + + install_plugin() { + send_stats "外掛管理" + while true; do + clear + echo "========================================" + echo "外掛程式管理 (安裝/刪除)" + echo "========================================" + echo "當前插件列表:" + openclaw plugins list + echo "--------------------------------------------------------" + echo "推薦的常用外掛 ID (直接複製括號內的 ID 即可):" + echo "--------------------------------------------------------" + echo "📱 通訊頻道:" + echo "- [feishu] # 飛書/Lark 集成" + echo "- [telegram] # Telegram 機器人" + echo "- [slack] # Slack 企業通訊" + echo " - [msteams] # Microsoft Teams" + echo "- [discord] # Discord 社群管理" + echo "- [whatsapp] # WhatsApp 自動化" + echo "" + echo "🧠 記憶與 AI:" + echo "- [memory-core] # 基礎記憶 (文件檢索)" + echo "- [memory-lancedb] # 增強記憶 (向量資料庫)" + echo "- [copilot-proxy] # Copilot 介面轉發" + echo "" + echo "⚙️ 功能擴充:" + echo "- [lobster] # 審批流 (附人工確認)" + echo "- [voice-call] # 語音通話能力" + echo "- [nostr] # 加密隱私聊天" + echo "--------------------------------------------------------" + + echo "1) 安裝/啟用插件" + echo "2) 刪除/停用插件" + echo "0) 返回" + read -e -p "請選擇操作:" plugin_action + + [ "$plugin_action" = "0" ] && break + [ -z "$plugin_action" ] && continue + + read -e -p "請輸入插件 ID(空格分隔,輸入 0 退出):" raw_input + [ "$raw_input" = "0" ] && break + [ -z "$raw_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + for token in $raw_input; do + local plugin_id + local plugin_full + plugin_id=$(resolve_openclaw_plugin_id "$token") + plugin_full="$token" + [ -z "$plugin_id" ] && continue + + if [ "$plugin_action" = "1" ]; then + echo "🔍 正在檢查插件狀態:$plugin_id" + local plugin_list + plugin_list=$(openclaw plugins list 2>/dev/null) + + if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then + echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then + echo "💡 發現系統內建目錄存在該插件,嘗試直接啟用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + continue + fi + + echo "📥 本機未發現,嘗試下載安裝:$plugin_full" + rm -rf "/root/.openclaw/extensions/$plugin_id" + if openclaw plugins install "$plugin_full"; then + echo "✅ 下載成功,正在啟用..." + if openclaw plugins enable "$plugin_id"; then + sync_openclaw_plugin_allowlist "$plugin_id" + success_list="$success_list $plugin_id" + changed=true + else + failed_list="$failed_list $plugin_id" + fi + else + echo "❌ 安装失败:$plugin_full" + failed_list="$failed_list $plugin_id" + fi + else + echo "🗑️ 正在刪除/停用插件:$plugin_id" + openclaw plugins disable "$plugin_id" >/dev/null 2>&1 + if openclaw plugins uninstall "$plugin_id"; then + echo "✅ 已卸載:$plugin_id" + else + echo "⚠️ 卸載失敗,可能為預先安裝插件,僅停用:$plugin_id" + fi + sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 + success_list="$success_list $plugin_id" + changed=true + fi + done + + echo "" + echo "====== 操作匯總 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 正在重啟 OpenClaw 服務以載入變更..." + start_gateway + fi + break_end + done + } + + + install_skill() { + send_stats "技能管理" + while true; do + clear + echo "========================================" + echo "技能管理 (安裝/刪除)" + echo "========================================" + echo "目前已安裝技能:" + openclaw skills list + echo "----------------------------------------" + + # 輸出建議的實用技能列表 + echo "建議的實用技能(可直接複製名稱輸入):" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 頁面、資料庫和區塊" + echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" + echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" + echo "1password # 自動化讀取和注入 1Password 金鑰" + echo "gog # Google Workspace (Gmail/雲端盤/文件) 全能助手" + echo "things-mac # 深度整合 Things 3 任務管理" + echo "bluebubbles # 透過 BlueBubbles 完美收發 iMessage" + echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" + echo "summarize # 網頁/播客/YouTube 影片內容一鍵總結" + echo "openhue # 控制 Philips Hue 智慧燈光場景" + echo "video-frames # 視訊抽幀與短片剪輯 (ffmpeg 驅動)" + echo "openai-whisper # 本地音訊轉文字 (離線隱私保護)" + echo "coding-agent # 自動運行 Claude Code/Codex 等程式設計助手" + echo "----------------------------------------" + + echo "1) 安裝技能" + echo "2) 刪除技能" + echo "0) 返回" + read -e -p "請選擇操作:" skill_action + + [ "$skill_action" = "0" ] && break + [ -z "$skill_action" ] && continue + + read -e -p "請輸入技能名稱(空格分隔,輸入 0 退出):" skill_input + [ "$skill_input" = "0" ] && break + [ -z "$skill_input" ] && continue + + local success_list="" + local failed_list="" + local skipped_list="" + local changed=false + local token + + if [ "$skill_action" = "2" ]; then + read -e -p "二次確認:刪除僅影響使用者目錄 ~/.openclaw/workspace/skills,確認繼續? (y/N):" confirm_del + if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then + echo "已取消刪除。" + break_end + continue + fi + fi + + for token in $skill_input; do + local skill_name + skill_name="$token" + [ -z "$skill_name" ] && continue + + if [ "$skill_action" = "1" ]; then + local skill_found=false + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在使用者目錄安裝。" + skill_found=true + elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then + echo "💡 技能 [$skill_name] 已在系統目錄安裝。" + skill_found=true + fi + + if [ "$skill_found" = true ]; then + read -e -p "技能 [$skill_name] 已安裝,是否重新安裝? (y/N):" reinstall + if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then + skipped_list="$skipped_list $skill_name" + continue + fi + fi + + echo "正在安裝技能:$skill_name ..." + if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then + echo "✅ 技能$skill_name安裝成功。" + success_list="$success_list $skill_name" + changed=true + else + echo "❌ 安裝失敗:$skill_name" + failed_list="$failed_list $skill_name" + fi + else + echo "🗑️ 正在刪除技能:$skill_name" + npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 + if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then + rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" + echo "✅ 已刪除使用者技能目錄:$skill_name" + success_list="$success_list $skill_name" + changed=true + else + echo "⏭️ 未發現使用者技能目錄:$skill_name" + skipped_list="$skipped_list $skill_name" + fi + fi + done + + echo "" + echo "====== 操作匯總 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" + + if [ "$changed" = true ]; then + echo "🔄 正在重啟 OpenClaw 服務以載入變更..." + start_gateway + fi + break_end + done + } + +openclaw_json_get_bool() { + local expr="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r "$expr" "$config_file" 2>/dev/null || echo "false" + } + + openclaw_channel_has_cfg() { + local channel="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ ! -s "$config_file" ]; then + echo "false" + return + fi + jq -r --arg c "$channel" ' + (.channels[$c] // null) as $v + | if ($v | type) != "object" then + false + else + ([ $v + | to_entries[] + | select((.key == "enabled" or .key == "dmPolicy" or .key == "groupPolicy" or .key == "streaming") | not) + | .value + | select(. != null and . != "" and . != false) + ] | length) > 0 + end + ' "$config_file" 2>/dev/null || echo "false" + } + + openclaw_dir_has_files() { + local dir="$1" + [ -d "$dir" ] && find "$dir" -type f -print -quit 2>/dev/null | grep -q . + } + + openclaw_plugin_local_installed() { + local plugin="$1" + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then + return 0 + fi + + # 相容於兩種常見目錄命名: + # - ~/.openclaw/extensions/qqbot + # - ~/.openclaw/extensions/openclaw-qqbot + # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 + [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ + || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ + || [ -d "/usr/lib/node_modules/openclaw/extensions/openclaw-${plugin}" ] + } + + openclaw_bot_status_text() { + local enabled="$1" + local configured="$2" + local connected="$3" + local abnormal="$4" + if [ "$abnormal" = "true" ]; then + echo "例外" + elif [ "$enabled" != "true" ]; then + echo "未啟用" + elif [ "$connected" = "true" ]; then + echo "已連接" + elif [ "$configured" = "true" ]; then + echo "已配置" + else + echo "未配置" + fi + } + + openclaw_colorize_bot_status() { + local status="$1" + case "$status" in + 已连接) echo -e "${gl_lv}${status}${gl_bai}" ;; + 已配置) echo -e "${gl_huang}${status}${gl_bai}" ;; + 异常) echo -e "${gl_hong}${status}${gl_bai}" ;; + *) echo "$status" ;; + esac + } + + openclaw_print_bot_status_line() { + local label="$1" + local status="$2" + echo -e "- ${label}: $(openclaw_colorize_bot_status "$status")" + } + + openclaw_show_bot_local_status_block() { + local config_file="${HOME}/.openclaw/openclaw.json" + local json_ok="false" + if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then + json_ok="true" + fi + + local tg_enabled tg_cfg tg_connected tg_abnormal tg_status + tg_enabled=$(openclaw_json_get_bool '.channels.telegram.enabled // .plugins.entries.telegram.enabled // false') + tg_cfg=$(openclaw_channel_has_cfg "telegram") + tg_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/telegram"; then + tg_connected="true" + fi + tg_abnormal="false" + if [ "$tg_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + tg_abnormal="true" + fi + tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") + + local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_cfg=$(openclaw_channel_has_cfg "feishu") + feishu_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + feishu_connected="true" + fi + feishu_abnormal="false" + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + feishu_abnormal="true" + fi + if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + feishu_abnormal="true" + fi + feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") + + local wa_enabled wa_cfg wa_connected wa_abnormal wa_status + wa_enabled=$(openclaw_json_get_bool '.plugins.entries.whatsapp.enabled // .channels.whatsapp.enabled // false') + wa_cfg=$(openclaw_channel_has_cfg "whatsapp") + wa_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/whatsapp"; then + wa_connected="true" + fi + wa_abnormal="false" + if [ "$wa_enabled" = "true" ] && ! openclaw_plugin_local_installed "whatsapp"; then + wa_abnormal="true" + fi + if [ "$wa_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wa_abnormal="true" + fi + wa_status=$(openclaw_bot_status_text "$wa_enabled" "$wa_cfg" "$wa_connected" "$wa_abnormal") + + local dc_enabled dc_cfg dc_connected dc_abnormal dc_status + dc_enabled=$(openclaw_json_get_bool '.channels.discord.enabled // .plugins.entries.discord.enabled // false') + dc_cfg=$(openclaw_channel_has_cfg "discord") + dc_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/discord"; then + dc_connected="true" + fi + dc_abnormal="false" + if [ "$dc_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + dc_abnormal="true" + fi + dc_status=$(openclaw_bot_status_text "$dc_enabled" "$dc_cfg" "$dc_connected" "$dc_abnormal") + + local slack_enabled slack_cfg slack_connected slack_abnormal slack_status + slack_enabled=$(openclaw_json_get_bool '.plugins.entries.slack.enabled // .channels.slack.enabled // false') + slack_cfg=$(openclaw_channel_has_cfg "slack") + slack_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/slack"; then + slack_connected="true" + fi + slack_abnormal="false" + if [ "$slack_enabled" = "true" ] && ! openclaw_plugin_local_installed "slack"; then + slack_abnormal="true" + fi + if [ "$slack_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + slack_abnormal="true" + fi + slack_status=$(openclaw_bot_status_text "$slack_enabled" "$slack_cfg" "$slack_connected" "$slack_abnormal") + + local qq_enabled qq_cfg qq_connected qq_abnormal qq_status + qq_enabled=$(openclaw_json_get_bool '.plugins.entries.qqbot.enabled // .channels.qqbot.enabled // false') + qq_cfg=$(openclaw_channel_has_cfg "qqbot") + qq_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/qqbot/sessions" || openclaw_dir_has_files "${HOME}/.openclaw/qqbot/data"; then + qq_connected="true" + fi + qq_abnormal="false" + if [ "$qq_enabled" = "true" ] && ! openclaw_plugin_local_installed "qqbot"; then + qq_abnormal="true" + fi + if [ "$qq_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + qq_abnormal="true" + fi + qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + + echo "本機狀態(僅本機配置/緩存,不做網路探測):" + openclaw_print_bot_status_line "Telegram" "$tg_status" + openclaw_print_bot_status_line "飛書(Lark)" "$feishu_status" + openclaw_print_bot_status_line "WhatsApp" "$wa_status" + openclaw_print_bot_status_line "Discord" "$dc_status" + openclaw_print_bot_status_line "Slack" "$slack_status" + openclaw_print_bot_status_line "QQ Bot" "$qq_status" + } + + change_tg_bot_code() { + send_stats "機器人對接" + while true; do + clear + echo "========================================" + echo "機器人連線對接" + echo "========================================" + openclaw_show_bot_local_status_block + echo "----------------------------------------" + echo "1. Telegram 機器人對接" + echo "2. 飛書 (Lark) 機器人對接" + echo "3. WhatsApp 機器人對接" + echo "----------------------------------------" + echo "0. 返回上一級選單" + echo "----------------------------------------" + read -e -p "請輸入你的選擇:" bot_choice + + case $bot_choice in + 1) + read -e -p "請輸入TG機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve telegram "$code" + break_end + ;; + 2) + read -e -p "請輸入飛書機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve feishu "$code" + break_end + ;; + 3) + read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + if [ "$code" = "0" ]; then continue; fi + if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi + openclaw pairing approve whatsapp "$code" + break_end + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } + + + openclaw_backup_root() { + echo "${HOME}/.openclaw/backups" + } + + openclaw_is_interactive_terminal() { + [ -t 0 ] && [ -t 1 ] + } + + openclaw_has_command() { + command -v "$1" >/dev/null 2>&1 + } + + + openclaw_is_safe_relpath() { + local rel="$1" + [ -z "$rel" ] && return 1 + [[ "$rel" = /* ]] && return 1 + [[ "$rel" == *"//"* ]] && return 1 + [[ "$rel" == *$'\n'* ]] && return 1 + [[ "$rel" == *$'\r'* ]] && return 1 + case "$rel" in + ../*|*/../*|*/..|..) + return 1 + ;; + esac + return 0 + } + + openclaw_restore_path_allowed() { + local mode="$1" + local rel="$2" + case "$mode" in + memory) + case "$rel" in + MEMORY.md|AGENTS.md|USER.md|SOUL.md|TOOLS.md|memory/*) return 0 ;; + *) return 1 ;; + esac + ;; + project) + case "$rel" in + openclaw.json|workspace/*|extensions/*|skills/*|prompts/*|tools/*|telegram/*|feishu/*|whatsapp/*|discord/*|slack/*|qqbot/*|logs/*) return 0 ;; + *) return 1 ;; + esac + ;; + *) + return 1 + ;; + esac + } + + openclaw_pack_backup_archive() { + local backup_type="$1" + local export_mode="$2" + local payload_dir="$3" + local output_file="$4" + + local tmp_root + tmp_root=$(mktemp -d) || return 1 + local pack_dir="$tmp_root/package" + mkdir -p "$pack_dir" + + cp -a "$payload_dir" "$pack_dir/payload" + + ( + cd "$pack_dir/payload" || exit 1 + find . -type f | sed 's|^\./||' | sort > "$pack_dir/manifest.files" + : > "$pack_dir/manifest.sha256" + while IFS= read -r f; do + [ -z "$f" ] && continue + sha256sum "$f" >> "$pack_dir/manifest.sha256" + done < "$pack_dir/manifest.files" + ) || { rm -rf "$tmp_root"; return 1; } + + cat > "$pack_dir/backup.meta" </dev/null + ) || { echo "❌ sha256 校驗失敗,拒絕還原"; return 1; } + + echo "$pkg_dir" + return 0 + } + + openclaw_memory_backup_export() { + send_stats "OpenClaw記憶全量備份" + local workspace_dir="${HOME}/.openclaw/workspace" + local backup_root + backup_root=$(openclaw_backup_root) + local ts + ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" + + mkdir -p "$backup_root" + if [ ! -d "$workspace_dir" ]; then + echo "❌ 未找到 workspace 目录: $workspace_dir" + break_end + return 1 + fi + + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" + [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" + + read -e -p "是否附帶 AGENTS/USER/SOUL/TOOLS 檔案? (y/N):" include_optional + if [[ "$include_optional" =~ ^[Yy]$ ]]; then + for f in AGENTS.md USER.md SOUL.md TOOLS.md; do + [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可備份的記憶文件" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then + echo "✅ 記憶全量備份完成:$out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ 記憶全量備份失敗" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_read_import_path() { + local prompt_text="$1" + local file_input file_path backup_root + echo "$prompt_text" >&2 + + echo "可先透過 scp/sftp 上傳備份包到伺服器,再輸入路徑。" >&2 + echo "scp 範例: scp /本地/備份包.tar.gz root@你的伺服器:/tmp/" >&2 + echo "提示:輸入檔案名稱時預設在備份目錄中尋找;輸入含 / 的路徑時按完整路徑校驗。" >&2 + read -e -p "請輸入備份檔名或路徑:" file_input + [ -z "$file_input" ] && { echo ""; return 0; } + + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + + if [[ "$file_input" == */* ]]; then + file_path="$file_input" + else + file_path="$backup_root/$file_input" + fi + + if [ ! -f "$file_path" ]; then + echo "❌ 備份檔不存在:$file_path" >&2 + echo "" + return 1 + fi + + echo "$file_path" + } + + openclaw_memory_backup_import() { + send_stats "OpenClaw記憶全量還原" + local workspace_dir="${HOME}/.openclaw/workspace" + mkdir -p "$workspace_dir" + + local archive_path + archive_path=$(openclaw_read_import_path "還原前將執行:類型校驗 + sha256 校驗 + 路徑白名單校驗") + [ -z "$archive_path" ] && { echo "❌ 未輸入備份路徑"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then + echo "❌ 偵測到非法或越權路徑:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 還原中止:存在不安全路徑" + break_end + return 1 + fi + + + while IFS= read -r rel; do + mkdir -p "$workspace_dir/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" + done < "$valid_list" + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ 記憶全量還原完成" + break_end + } + + openclaw_project_backup_export() { + send_stats "OpenClaw專案備份" + local openclaw_root="${HOME}/.openclaw" + if [ ! -d "$openclaw_root" ]; then + echo "❌ 未找到 OpenClaw 根目錄:$openclaw_root" + break_end + return 1 + fi + + echo "備份模式:" + echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "2. 完整模式(含更多狀態,敏感風險較高)" + read -e -p "請選擇備份模式(預設 1):" export_mode + [ -z "$export_mode" ] && export_mode="1" + + local mode_label="safe" + local tmp_payload + tmp_payload=$(mktemp -d) || return 1 + + if [ "$export_mode" = "2" ]; then + mode_label="full" + for d in workspace extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in telegram feishu whatsapp discord slack qqbot logs; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + else + [ -d "$openclaw_root/workspace" ] && cp -a "$openclaw_root/workspace" "$tmp_payload/" + [ -f "$openclaw_root/openclaw.json" ] && cp -a "$openclaw_root/openclaw.json" "$tmp_payload/" + for d in extensions skills prompts tools; do + [ -e "$openclaw_root/$d" ] && cp -a "$openclaw_root/$d" "$tmp_payload/" + done + fi + + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 未找到可備份的 OpenClaw 專案內容" + rm -rf "$tmp_payload" + break_end + return 1 + fi + + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" + + if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then + echo "✅ OpenClaw 專案備份完成 (${mode_label}): $out_file" + openclaw_offer_transfer_hint "$out_file" + else + echo "❌ OpenClaw 專案備份失敗" + fi + + rm -rf "$tmp_payload" + break_end + } + + openclaw_project_backup_import() { + send_stats "OpenClaw專案還原" + local openclaw_root="${HOME}/.openclaw" + mkdir -p "$openclaw_root" + + echo "⚠️ 高風險操作:專案還原會涵蓋 OpenClaw 設定與工作區內容。" + echo "⚠️ 還原前將執行 manifest/sha256 校驗、白名單恢復、gateway 停啟與健康檢查。" + read -e -p "請輸入確認詞【我已知高風險並繼續還原】後繼續:" confirm_text + if [ "$confirm_text" != "我已知高風險並持續還原" ]; then + echo "❌ 確認詞不匹配,已取消還原" + break_end + return 1 + fi + + local archive_path + archive_path=$(openclaw_read_import_path "請輸入 OpenClaw 專案備份包路徑") + [ -z "$archive_path" ] && { echo "❌ 未輸入備份路徑"; break_end; return 1; } + + local tmp_unpack + tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir + pkg_dir=$(openclaw_prepare_import_archive "openclaw-project" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + + local invalid=0 + local valid_list + valid_list=$(mktemp) + while IFS= read -r rel; do + [ -z "$rel" ] && continue + if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then + echo "❌ 偵測到非法或越權路徑:$rel" + invalid=1 + break + fi + echo "$rel" >> "$valid_list" + done < "$pkg_dir/manifest.files" + + if [ "$invalid" -ne 0 ]; then + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "❌ 還原中止:存在不安全路徑" + break_end + return 1 + fi + + + if command -v openclaw >/dev/null 2>&1; then + echo "⏸️ 還原前停止 OpenClaw gateway..." + openclaw gateway stop >/dev/null 2>&1 + fi + + while IFS= read -r rel; do + mkdir -p "$openclaw_root/$(dirname "$rel")" + cp -a "$pkg_dir/payload/$rel" "$openclaw_root/$rel" + done < "$valid_list" + + if command -v openclaw >/dev/null 2>&1; then + echo "▶️ 還原後啟動 OpenClaw gateway..." + openclaw gateway start >/dev/null 2>&1 + sleep 2 + echo "🩺 gateway 健康檢查:" + openclaw gateway status || true + fi + + rm -f "$valid_list" + rm -rf "$tmp_unpack" + echo "✅ OpenClaw 專案還原完成" + break_end + } + + openclaw_backup_detect_type() { + local file_name="$1" + if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then + echo "記憶備份文件" + elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then + echo "專案備份文件" + else + echo "其他備份文件" + fi + } + + openclaw_backup_collect_files() { + local backup_root + backup_root=$(openclaw_backup_root) + mkdir -p "$backup_root" + mapfile -t OPENCLAW_BACKUP_FILES < <(find "$backup_root" -maxdepth 1 -type f -name '*.tar.gz' -printf '%f\n' | sort -r) + } + + + openclaw_backup_render_file_list() { + local backup_root i file_name file_path file_type file_size file_time + local has_memory=0 has_project=0 has_other=0 + backup_root=$(openclaw_backup_root) + openclaw_backup_collect_files + + echo "備份目錄:$backup_root" + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + echo "暫無備份文件" + return 0 + fi + + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") + case "$file_type" in + "記憶備份文件") has_memory=1 ;; + "專案備份文件") has_project=1 ;; + "其他備份文件") has_other=1 ;; + esac + done + + if [ "$has_memory" -eq 1 ]; then + echo "記憶備份文件" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "記憶備份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_project" -eq 1 ]; then + echo "專案備份文件" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "專案備份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + + if [ "$has_other" -eq 1 ]; then + echo "其他備份文件" + for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do + file_name="${OPENCLAW_BACKUP_FILES[$i]}" + file_type=$(openclaw_backup_detect_type "$file_name") + [ "$file_type" != "其他備份文件" ] && continue + file_path="$backup_root/$file_name" + file_size=$(ls -lh "$file_path" | awk '{print $5}') + file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') + printf "%s | %s | %s\n" "$file_name" "$file_size" "$file_time" + done + fi + } + + openclaw_backup_file_exists_in_list() { + local target_file="$1" + local item + for item in "${OPENCLAW_BACKUP_FILES[@]}"; do + [ "$item" = "$target_file" ] && return 0 + done + return 1 + } + + openclaw_backup_delete_file() { + send_stats "OpenClaw刪除備份文件" + local backup_root backup_root_real user_input target_file target_path target_type + backup_root=$(openclaw_backup_root) + + openclaw_backup_render_file_list + if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then + break_end + return 0 + fi + + read -e -p "請輸入要刪除的檔案名稱或完整路徑(0 取消):" user_input + if [ "$user_input" = "0" ]; then + echo "已取消刪除。" + break_end + return 0 + fi + if [ -z "$user_input" ]; then + echo "❌ 輸入不能為空。" + break_end + return 1 + fi + + backup_root_real=$(realpath -m "$backup_root") + if [[ "$user_input" == /* ]]; then + target_path=$(realpath -m "$user_input") + case "$target_path" in + "$backup_root_real"/*) ;; + *) + echo "❌ 路徑越界:僅允許刪除備份根目錄內的檔案。" + break_end + return 1 + ;; + esac + target_file=$(basename "$target_path") + else + target_file=$(basename -- "$user_input") + target_path="$backup_root/$target_file" + fi + + if [ ! -f "$target_path" ]; then + echo "❌ 目標檔案不存在:$target_path" + break_end + return 1 + fi + + if ! openclaw_backup_file_exists_in_list "$target_file"; then + echo "❌ 目標檔案不在目前備份清單中。" + break_end + return 1 + fi + + target_type=$(openclaw_backup_detect_type "$target_file") + + echo "即將刪除: [$target_type] $target_path" + read -e -p "第一次確認:輸入 yes 確認繼續:" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消刪除。" + break_end + return 0 + fi + read -e -p "二次確認:輸入 DELETE 執行刪除:" confirm_step2 + if [ "$confirm_step2" != "DELETE" ]; then + echo "已取消刪除。" + break_end + return 0 + fi + + if rm -f -- "$target_path"; then + echo "✅ 刪除成功:$target_file" + else + echo "❌ 刪除失敗:$target_file" + fi + break_end + } + + openclaw_backup_list_files() { + openclaw_backup_render_file_list + break_end + } + + openclaw_memory_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_memory_config_get() { + local key="$1" + local default_value="${2:-}" + local value + value=$(openclaw config get "$key" 2>/dev/null | head -n 1 | sed -e 's/^"//' -e 's/"$//') + if [ -z "$value" ] || [ "$value" = "null" ] || [ "$value" = "undefined" ]; then + echo "$default_value" + return 0 + fi + echo "$value" + } + + openclaw_memory_config_set() { + local key="$1" + shift + openclaw config set "$key" "$@" >/dev/null 2>&1 + } + + openclaw_memory_config_unset() { + local key="$1" + openclaw config unset "$key" >/dev/null 2>&1 + } + + openclaw_memory_cleanup_legacy_keys() { + openclaw_memory_config_unset "memory.local" + } + + openclaw_memory_status_value() { + local key="$1" + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + } - # 3. 檢查系統實體目錄是否存在 - elif [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 發現系統內建目錄存在該插件,嘗試直接啟用..." - openclaw plugins enable "$plugin_id" + openclaw_memory_expand_path() { + local raw_path="$1" + if [ -z "$raw_path" ]; then + echo "" + return 0 + fi + raw_path=$(echo "$raw_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$raw_path" == ~* ]]; then + echo "${raw_path/#\~/$HOME}" + else + echo "$raw_path" + fi + } + + openclaw_memory_rebuild_index_safe() { + local store_raw store_file ts backup_file + store_raw=$(openclaw_memory_status_value "Store") + store_file=$(openclaw_memory_expand_path "$store_raw") + if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then + echo "⚠️ 未找到索引庫文件,可能為空或不存在。" + echo "Store 原始值: ${store_raw:-<空>}" + echo "仍將執行重建索引。" + else + ts=$(date +%Y%m%d_%H%M%S) + backup_file="${store_file}.bak.${ts}" + if mv "$store_file" "$backup_file"; then + echo "✅ 已備份索引:$backup_file" + else + echo "⚠️ 索引備份失敗,繼續重建。" + fi + fi + openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建並自動重新啟動網關" + echo "" + openclaw_memory_render_status + } + + openclaw_memory_prepare_workspace() { + local workspace memory_dir + workspace=$(openclaw_memory_status_value "Workspace") + if [ -z "$workspace" ]; then + echo "⚠️ 未能取得 Workspace 路徑,跳過目錄修復。" + return 1 + fi + memory_dir="$workspace/memory" + if [ ! -d "$memory_dir" ]; then + echo "🔧 記憶目錄不存在,已自動建立:$memory_dir" + mkdir -p "$memory_dir" + fi + return 0 + } + + openclaw_memory_render_status() { + local status_output status_lines config_file config_display + status_output=$(openclaw memory status 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "獲取狀態失敗" + else + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底層方案: /' -e 's/^Vector: /向量庫狀態: /' -e 's/^Indexed: /已收錄文件: /') + if [ -z "$status_lines" ]; then + echo "未安裝/未啟動" + else + echo "$status_lines" + fi + fi + } + + openclaw_memory_get_backend() { + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "local" ]; then + echo "builtin" + else + echo "$backend" + fi + } + + openclaw_memory_get_local_model_path() { + openclaw_memory_config_get "agents.defaults.memorySearch.local.modelPath" + } + + openclaw_memory_local_model_status() { + local model_path="$1" + if [ -z "$model_path" ]; then + echo "missing" + return + fi + if [[ "$model_path" == hf:* ]]; then + echo "hf" + return + fi + if [ -f "$model_path" ]; then + echo "ok" + else + echo "missing" + fi + } + + openclaw_memory_qmd_available() { + if command -v qmd >/dev/null 2>&1; then + echo "true" + return + fi + local backend + backend=$(openclaw_memory_config_get "memory.backend") + if [ "$backend" = "qmd" ]; then + echo "true" + return + fi + echo "false" + } + + openclaw_memory_probe_url() { + local url="$1" + if ! command -v curl >/dev/null 2>&1; then + echo "unknown" + return + fi + if [ -z "$url" ]; then + echo "unknown" + return + fi + if curl -I -m 2 -s "$url" >/dev/null 2>&1; then + echo "ok" + else + echo "fail" + fi + } + + openclaw_memory_recommend() { + local qmd_ok model_path model_status hf_ok mirror_ok + qmd_ok=$(openclaw_memory_qmd_available) + model_path=$(openclaw_memory_get_local_model_path) + model_status=$(openclaw_memory_local_model_status "$model_path") + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + + OPENCLAW_MEMORY_RECOMMEND_REASON=() + if [ "$qmd_ok" = "true" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未檢測到 QMD") + fi + if [ -n "$model_path" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路徑:$model_path") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路徑") + fi + case "$model_status" in + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案存在") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型來自 HF 下載來源(國內可能慢/失敗)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; + esac + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可訪問") + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") + else + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可達(疑似國內/受限網路)") + fi + + if [ "$qmd_ok" = "true" ]; then + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && { [ "$hf_ok" = "ok" ] || [ "$mirror_ok" = "ok" ]; }; then + OPENCLAW_MEMORY_RECOMMEND="local" + elif [ "$model_status" = "hf" ] && [ "$hf_ok" = "fail" ] && [ "$mirror_ok" = "fail" ]; then + OPENCLAW_MEMORY_RECOMMEND="qmd" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + else + if [ "$model_status" = "ok" ]; then + OPENCLAW_MEMORY_RECOMMEND="local" + else + OPENCLAW_MEMORY_RECOMMEND="qmd" + fi + fi + } + + + openclaw_memory_detect_region() { + OPENCLAW_MEMORY_COUNTRY="unknown" + OPENCLAW_MEMORY_USE_MIRROR="false" + if command -v curl >/dev/null 2>&1; then + OPENCLAW_MEMORY_COUNTRY=$(curl -s -m 2 ipinfo.io/country | tr -d ' +' | tr -d ' +') + fi + case "$OPENCLAW_MEMORY_COUNTRY" in + CN|HK) + OPENCLAW_MEMORY_USE_MIRROR="true" + ;; + esac + } + + openclaw_memory_select_sources() { + local hf_ok mirror_ok + hf_ok=$(openclaw_memory_probe_url "https://huggingface.co") + mirror_ok=$(openclaw_memory_probe_url "https://hf-mirror.com") + OPENCLAW_MEMORY_HF_OK="$hf_ok" + OPENCLAW_MEMORY_MIRROR_OK="$mirror_ok" + if [ "$OPENCLAW_MEMORY_USE_MIRROR" = "true" ]; then + if [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + elif [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + else + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + fi + OPENCLAW_MEMORY_GH_PROXY="https://gh.kejilion.pro/" + else + if [ "$hf_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + elif [ "$mirror_ok" = "ok" ]; then + OPENCLAW_MEMORY_HF_BASE="https://hf-mirror.com" + else + OPENCLAW_MEMORY_HF_BASE="https://huggingface.co" + fi + OPENCLAW_MEMORY_GH_PROXY="https://" + fi + } + + openclaw_memory_download_file() { + local url="$1" + local dest="$2" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 2 -o "$dest" "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -O "$dest" "$url" + return $? + fi + echo "❌ 未偵測到 curl 或 wget,無法下載。" + return 1 + } + + openclaw_memory_check_sqlite() { + if ! command -v sqlite3 >/dev/null 2>&1; then + echo "⚠️ 未偵測到 sqlite3,QMD 可能無法正常運作。" + return 1 + fi + local ver + ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') + echo "✅ sqlite3 可用: ${ver:-unknown}" + echo "ℹ️ sqlite 擴充支援無法可靠檢測,將持續。" + return 0 + } + + openclaw_memory_ensure_bun() { + if [ -x "$HOME/.bun/bin/bun" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 已存在" + return 0 + fi + echo "⬇️ 安裝 bun..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://bun.sh/install | bash + else + echo "❌ 未偵測到 curl 或 wget,無法安裝 bun。" + return 1 + fi + if [ -d "$HOME/.bun/bin" ]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + if command -v bun >/dev/null 2>&1; then + echo "✅ bun 安裝完成" + return 0 + fi + echo "❌ bun 安裝失敗" + return 1 + } + + openclaw_memory_ensure_qmd() { + local qmd_path + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -n "$qmd_path" ]; then + echo "✅ qmd 已存在:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + fi + openclaw_memory_ensure_bun || return 1 + local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" + echo "⬇️ 透過 bun 安裝 qmd:$qmd_url" + bun install -g "$qmd_url" + qmd_path=$(command -v qmd 2>/dev/null || true) + if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then + qmd_path="$HOME/.bun/bin/qmd" + fi + if [ -z "$qmd_path" ]; then + echo "❌ qmd 安裝失敗" + return 1 + fi + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + echo "✅ qmd 安裝完成:$qmd_path" + return 0 + } + + openclaw_memory_render_auto_summary() { + echo "---------------------------------------" + echo "✅ 環境就緒" + echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "模式: 僅寫入配置(未安裝/未下載)" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "索引: 已執行" + else + echo "索引: 已跳過" + fi + if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then + echo "重啟: 已執行" + else + echo "重啟: 已跳過" + fi + if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then + echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then + echo "模型:$OPENCLAW_MEMORY_MODEL_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then + echo "地區:$OPENCLAW_MEMORY_COUNTRY" + fi + if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then + echo "下載來源:$OPENCLAW_MEMORY_HF_BASE" + fi + echo "最終狀態:" + openclaw_memory_render_status + echo "---------------------------------------" + } + + openclaw_memory_auto_confirm() { + local scheme_label="$1" + OPENCLAW_MEMORY_PREHEAT="true" + OPENCLAW_MEMORY_RESTARTED="false" + OPENCLAW_MEMORY_CONFIG_ONLY="false" + echo "即將執行自動部署(詳細模式)" + echo "目標方案:$scheme_label" + echo "地區: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "鏡像來源探測: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "下載來源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then + echo "預計下載路徑:$OPENCLAW_MEMORY_EXPECT_PATH" + fi + if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then + echo "可能流量/磁碟佔用:$OPENCLAW_MEMORY_EXPECT_SIZE" + else + echo "可能流量/磁碟佔用: 視實際情況而定" + fi + echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" + echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" + read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step + case "$confirm_step" in + yes|YES) + OPENCLAW_MEMORY_PREHEAT="true" + ;; + config|CONFIG) + OPENCLAW_MEMORY_CONFIG_ONLY="true" + OPENCLAW_MEMORY_PREHEAT="false" + ;; + *) + echo "已取消自動部署。" + return 1 + ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "⚠️ 已選擇僅寫入配置,不安裝不下載" + else + echo "✅ 將自動建立索引並重新啟動網關" + fi + return 0 + } + openclaw_memory_auto_setup_qmd() { + echo "🔍 檢測 QMD 環境" + openclaw_memory_cleanup_legacy_keys + openclaw_memory_check_sqlite || true + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + if command -v qmd >/dev/null 2>&1; then + OPENCLAW_MEMORY_QMD_PATH=$(command -v qmd) else - # 4. 遠端安裝邏輯 - echo "📥 本機未發現,嘗試下載安裝..." + OPENCLAW_MEMORY_QMD_PATH="qmd" + fi + else + openclaw_memory_ensure_qmd || return 1 + fi + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ]; then + echo "✅ memory.backend 已是 qmd" + else + openclaw_memory_config_set "memory.backend" "qmd" + echo "✅ 已設定 memory.backend=qmd" + fi + local qmd_cmd + qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") + if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then + openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" + else + echo "✅ memory.qmd.command 已正確" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 預熱索引(可能下載模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳過預熱" + fi + echo "✅ QMD 自動部署完成" + } - # 清理舊的失敗殘留 - rm -rf "/root/.openclaw/extensions/$plugin_id" + openclaw_memory_auto_setup_local() { + echo "🔍 偵測 Local 環境" + openclaw_memory_cleanup_legacy_keys + local backend provider + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then + echo "✅ memory.backend 已是 builtin" + else + openclaw_memory_config_set "memory.backend" "builtin" + echo "✅ 已設定 memory.backend=builtin" + fi + provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") + if [ "$provider" = "local" ]; then + echo "✅ memorySearch.provider 已是 local" + else + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" + echo "✅ 已設定 agents.defaults.memorySearch.provider=local" + fi - # 執行安裝,並捕獲結果 - if openclaw plugins install "$plugin_full"; then - echo "✅ 下載成功,正在啟用..." - openclaw plugins enable "$plugin_id" + local model_path model_status + model_path=$(openclaw_memory_get_local_model_path) + model_path=$(openclaw_memory_expand_path "$model_path") + model_status=$(openclaw_memory_local_model_status "$model_path") + if [ "$model_status" = "ok" ]; then + echo "✅ 模型檔已存在:$model_path" + OPENCLAW_MEMORY_MODEL_PATH="$model_path" + else + local model_name="embeddinggemma-300M-Q8_0.gguf" + local model_dir="$HOME/.openclaw/models/embedding" + local model_dest="$model_dir/$model_name" + local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + echo "ℹ️ 僅寫入設定模式:跳過模型下載" + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" + else + if [ -f "$model_dest" ]; then + echo "✅ 已發現預設模型檔:$model_dest" else - echo "⚠️ 官方頻道下載失敗,嘗試備選方案..." - # 備選 npm 安裝 - if npm install -g "$plugin_full" --unsafe-perm; then - echo "✅ npm 安裝成功,嘗試啟用..." - openclaw plugins enable "$plugin_id" - else - echo "❌ 嚴重錯誤:無法取得該外掛程式。請檢查 ID 是否正確或網路是否可用。" - # 關鍵:這裡直接 return 或 continue,不走下面的 start_gateway,防止寫死配置 - break_end - continue - fi + echo "⬇️ 下載模型:$model_url" + openclaw_memory_download_file "$model_url" "$model_dest" || return 1 + echo "✅ 模型已下載:$model_dest" fi + OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi + openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" + echo "✅ 已寫入模型路徑" + fi + if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then + echo "🔥 預熱索引(可能下載模型)" + openclaw_memory_prepare_workspace + openclaw memory index --force + else + echo "⏭️ 已跳過預熱" + fi + echo "✅ Local 自動部署完成" + } - echo "🔄 正在重啟 OpenClaw 服務以載入新插件..." + openclaw_memory_auto_setup_run() { + local scheme="$1" + local scheme_label + OPENCLAW_MEMORY_QMD_PATH="" + OPENCLAW_MEMORY_MODEL_PATH="" + OPENCLAW_MEMORY_EXPECT_PATH="" + OPENCLAW_MEMORY_EXPECT_SIZE="" + openclaw_memory_detect_region + openclaw_memory_select_sources + if [ "$scheme" = "auto" ]; then + openclaw_memory_recommend + scheme="$OPENCLAW_MEMORY_RECOMMEND" + fi + case "$scheme" in + qmd) + scheme_label="QMD" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安裝目錄)" + OPENCLAW_MEMORY_EXPECT_SIZE="約 20-50MB" + ;; + local) + scheme_label="Local" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" + OPENCLAW_MEMORY_EXPECT_SIZE="約 350-600MB" + ;; + *) + echo "❌ 未知方案:$scheme" + return 1 + ;; + esac + OPENCLAW_MEMORY_AUTO_SCHEME="$scheme_label" + openclaw_memory_auto_confirm "$scheme_label" || return 0 + case "$scheme" in + qmd) openclaw_memory_auto_setup_qmd || return 1 ;; + local) openclaw_memory_auto_setup_local || return 1 ;; + *) return 1 ;; + esac + if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then + OPENCLAW_MEMORY_RESTARTED="false" + openclaw_memory_render_auto_summary + return 0 + fi + echo "♻️ 重啟 OpenClaw 網關" + if declare -F start_gateway >/dev/null 2>&1; then start_gateway - break_end - done + else + openclaw gateway restart + fi + OPENCLAW_MEMORY_RESTARTED="true" + openclaw_memory_render_auto_summary + return 0 } + openclaw_memory_auto_setup_menu() { + while true; do + clear + echo "=======================================" + echo "記憶方案自動部署" + echo "=======================================" + echo "1. QMD" + echo "2. Local" + echo "3. Auto(自動選擇)" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" auto_choice + case "$auto_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } + openclaw_memory_apply_scheme() { + local scheme="$1" + openclaw_memory_cleanup_legacy_keys + case "$scheme" in + qmd) + openclaw_memory_config_set "memory.backend" "qmd" + if [ $? -ne 0 ]; then + echo "❌ 寫入配置失敗" + return 1 + fi + openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 + ;; + local) + openclaw_memory_config_set "memory.backend" "builtin" + if [ $? -ne 0 ]; then + echo "❌ 寫入配置失敗" + return 1 + fi + openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 + ;; + *) + echo "❌ 未知方案:$scheme" + return 1 + esac + echo "✅ 已更新記憶方案配置" + return 0 + } + openclaw_memory_offer_restart() { + echo "配置已寫入,需要重新啟動 OpenClaw 閘道後生效。" + read -e -p "是否立即重新啟動 OpenClaw 網關? (Y/n):" restart_choice + if [[ "$restart_choice" =~ ^[Nn]$ ]]; then + echo "已跳過重啟,可稍後執行: openclaw gateway restart" + return 0 + fi + if declare -F start_gateway >/dev/null 2>&1; then + start_gateway + else + openclaw gateway restart + fi + } + openclaw_memory_fix_index() { + local backend + backend=$(openclaw_memory_get_backend) + if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then + echo "⚠️ 偵測到目前方案為 QMD,但未安裝 qmd 指令。" + echo "可切換 Local,或安裝 bun + qmd 後再試。" + fi + echo "適用場景:Indexed 分子 > 分母(重複 collection 導致計數異常)" + read -e -p "確認將 includeDefaultMemory 設為 false? (y/N):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then + echo "已取消。" + break_end + return 0 + fi + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false + if [ $? -ne 0 ]; then + echo "❌ 寫入配置失敗" + break_end + return 1 + fi + echo "✅ 已設定 includeDefaultMemory=false" + echo "推薦執行:清理並重建索引" + read -e -p "是否執行清理並重建索引(建議)? (Y/n):" rebuild_choice + if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_safe + else + echo "可稍後在記憶管理中查看狀態。" + fi + break_end + } - - - install_skill() { - send_stats "安裝技能" + openclaw_memory_scheme_menu() { while true; do clear - echo "========================================" - echo "技能管理 (安裝)" - echo "========================================" - echo "目前已安裝技能:" - openclaw skills list - echo "----------------------------------------" + echo "=======================================" + echo "OpenClaw 記憶方案" + echo "=======================================" + local backend current_label + backend=$(openclaw_memory_get_backend) + case "$backend" in + qmd) current_label="QMD" ;; + builtin|local) current_label="Local" ;; + *) current_label="未配置" ;; + esac + echo "當前方案:$current_label" + echo "" + echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" + echo "Local: 本機向量檢索,依賴 embedding 模型文件" + echo "Auto : 自動推薦(基於可用性 + 網路探測)" + echo "---------------------------------------" + echo "1. 切換 QMD(自動部署/已安裝則跳過)" + echo "2. 切換 Local(自動部署/已安裝則跳過)" + echo "3. Auto(自動推薦並自動部署)" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" scheme_choice + case "$scheme_choice" in + 1) + openclaw_memory_auto_setup_run "qmd" + break_end + ;; + 2) + openclaw_memory_auto_setup_run "local" + break_end + ;; + 3) + openclaw_memory_auto_setup_run "auto" + break_end + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } - # 輸出建議的實用技能列表 - echo "建議的實用技能(可直接複製名稱輸入):" - echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 頁面、資料庫和區塊" - echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" - echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" - echo "1password # 自動化讀取和注入 1Password 金鑰" - echo "gog # Google Workspace (Gmail/雲端盤/文件) 全能助手" - echo "things-mac # 深度整合 Things 3 任務管理" - echo "bluebubbles # 透過 BlueBubbles 完美收發 iMessage" - echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" - echo "summarize # 網頁/播客/YouTube 影片內容一鍵總結" - echo "openhue # 控制 Philips Hue 智慧燈光場景" - echo "video-frames # 視訊抽幀與短片剪輯 (ffmpeg 驅動)" - echo "openai-whisper # 本地音訊轉文字 (離線隱私保護)" - echo "coding-agent # 自動運行 Claude Code/Codex 等程式設計助手" - echo "----------------------------------------" + openclaw_memory_file_collect() { + OPENCLAW_MEMORY_FILES=() + local base_dir="${HOME}/.openclaw/workspace" + local memory_dir="$base_dir/memory" + local memory_file="$base_dir/MEMORY.md" + [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + } - # 提示使用者輸入技能名稱 - read -e -p "請輸入要安裝的技能名稱(輸入 0 退出):" skill_name + openclaw_memory_file_render_list() { + local base_dir="${HOME}/.openclaw/workspace" + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + echo "未找到記憶文件。" + return 0 + fi + echo "編號 | 相對路徑 | 大小 | 修改時間" + echo "---------------------------------------" + local i file rel size mtime + for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do + file="${OPENCLAW_MEMORY_FILES[$i]}" + rel="${file#$base_dir/}" + size=$(ls -lh "$file" | awk '{print $5}') + mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') + printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" + done + } - # 1. 檢查是否輸入 0 退出 - if [ "$skill_name" = "0" ]; then - echo "操作已取消,退出技能安裝。" - break + openclaw_memory_view_file() { + local file="$1" + [ -f "$file" ] || { + echo "❌ 文件不存在:$file" + return 1 + } + local total_lines + total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) + local default_lines=120 + local start_line count + echo "文件:$file" + echo "總行數:$total_lines" + read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line + read -e -p "請輸入顯示行數(回車預設$default_lines): " count + [ -z "$count" ] && count=$default_lines + if [ -z "$start_line" ]; then + if [ "$total_lines" -le "$count" ]; then + start_line=1 + else + start_line=$((total_lines - count + 1)) fi + fi + if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then + echo "❌ 請輸入有效的數字。" + return 1 + fi + if [ "$start_line" -lt 1 ]; then + start_line=1 + fi + if [ "$count" -le 0 ]; then + echo "❌ 行數必須大於 0。" + return 1 + fi + local end_line=$((start_line + count - 1)) + if [ "$end_line" -gt "$total_lines" ]; then + end_line=$total_lines + fi + if [ "$total_lines" -eq 0 ]; then + echo "(空白文件)" + return 0 + fi + echo "---------------------------------------" + sed -n "${start_line},${end_line}p" "$file" + echo "---------------------------------------" + } - # 2. 驗證輸入是否為空 - if [ -z "$skill_name" ]; then - echo "錯誤:技能名稱不能為空。請重試。" - echo "" - continue + openclaw_memory_files_menu() { + while true; do + clear + echo "=======================================" + echo "OpenClaw 記憶文件" + echo "=======================================" + openclaw_memory_file_render_list + echo "---------------------------------------" + read -e -p "請輸入文件編號查看(0 返回):" file_choice + if [ "$file_choice" = "0" ]; then + return 0 fi - - # 3. 檢查技能是否已安裝 - local skill_found=false - if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在使用者目錄安裝。" - skill_found=true - elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系統目錄安裝。" - skill_found=true + if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then + echo "無效的選擇,請重試。" + sleep 1 + continue fi - - if [ "$skill_found" = true ]; then - read -e -p "是否重新安裝? (y/N):" reinstall - if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then - echo "跳過安裝。" - break_end - continue - fi + openclaw_memory_file_collect + if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then + read -p "未找到記憶文件,按回車返回..." + return 0 fi - - # 4. 執行安裝指令 - echo "正在安裝技能:$skill_name ..." - if npx clawhub install "$skill_name"; then - echo "✅ 技能$skill_name安裝成功。" - start_gateway - else - echo "❌ 安裝失敗。請檢查技能名稱是否正確,或參考文件排查。" + local idx=$((file_choice-1)) + if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then + echo "無效的編號,請重試。" + sleep 1 + continue fi - - break_end - done + openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" + read -p "按回車返回清單..." + done } - - - change_tg_bot_code() { - send_stats "機器人對接" + openclaw_memory_menu() { + send_stats "OpenClaw記憶管理" while true; do clear - echo "========================================" - echo "機器人連線對接" - echo "========================================" - echo "1. Telegram 機器人對接" - echo "2. 飛書 (Lark) 機器人對接" - echo "3. WhatsApp 機器人對接" - echo "----------------------------------------" - echo "0. 返回上一級選單" - echo "----------------------------------------" - read -e -p "請輸入你的選擇:" bot_choice - - case $bot_choice in + echo "=======================================" + echo "OpenClaw 記憶管理" + echo "=======================================" + openclaw_memory_render_status + echo "1. 更新記憶索引" + echo "2. 檢視記憶文件" + echo "3. 索引修復(Indexed 異常)" + echo "4. 記憶方案(QMD/Local/Auto)" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" memory_choice + case "$memory_choice" in 1) - read -e -p "請輸入TG機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi - openclaw pairing approve telegram "$code" - break_end + echo "即將更新記憶索引。" + read -e -p "第一次確認:輸入 yes 繼續:" confirm_step1 + if [ "$confirm_step1" != "yes" ]; then + echo "已取消。" + break_end + continue + fi + openclaw_memory_prepare_workspace + read -e -p "二次確認:輸入 force 使用全量(留空為增量):" confirm_step2 + if [ "$confirm_step2" = "force" ]; then + echo "⚠️ 全量重建更徹底,但耗時更長。" + echo "建議:輸入 rebuild 進行安全重建(先備份索引庫)。" + read -e -p "第三次確認:輸入 rebuild 執行安全重建;直接回車繼續普通 force:" confirm_step3 + if [ "$confirm_step3" = "rebuild" ]; then + openclaw_memory_rebuild_index_safe + else + openclaw memory index --force + openclaw gateway restart + echo "✅ 索引已重建並自動重新啟動網關" + fi + else + openclaw memory index + fi + break_end ;; 2) - read -e -p "請輸入飛書機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" - break_end + openclaw_memory_files_menu ;; 3) - read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi - openclaw pairing approve whatsapp "$code" - break_end + openclaw_memory_fix_index + ;; + 4) + openclaw_memory_scheme_menu ;; 0) return 0 @@ -10519,11 +13803,47 @@ EOF done } + openclaw_backup_restore_menu() { + + send_stats "OpenClaw備份與還原" + while true; do + clear + echo "=======================================" + echo "OpenClaw 備份與還原" + echo "=======================================" + openclaw_backup_render_file_list + echo "---------------------------------------" + echo "1. 備份記憶全量" + echo "2. 還原記憶全量" + echo "3. 備份 OpenClaw 專案(預設安全模式)" + echo "4. 還原 OpenClaw 專案(進階/高風險)" + echo "5. 刪除備份文件" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" backup_choice + + case "$backup_choice" in + 1) openclaw_memory_backup_export ;; + 2) openclaw_memory_backup_import ;; + 3) openclaw_project_backup_export ;; + 4) openclaw_project_backup_import ;; + 5) openclaw_backup_delete_file ;; + 0) return 0 ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } + update_moltbot() { echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools + git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -10596,7 +13916,7 @@ EOF domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -10703,7 +14023,7 @@ EOF 3) stop_bot ;; 4) view_logs ;; 5) change_model ;; - 6) add-openclaw-provider-interactive ;; + 6) openclaw_api_manage_menu ;; 7) change_tg_bot_code ;; 8) install_plugin ;; 9) install_skill ;; @@ -10714,6 +14034,12 @@ EOF ;; 12) send_stats "健康檢測與修復" openclaw doctor --fix + send_stats "OpenClaw API同步觸發" + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 模型同步失敗,已中止重新啟動網關。請檢查 provider /models 返回後重試。" + fi break_end ;; 13) openclaw_webui_menu ;; @@ -10721,8 +14047,10 @@ EOF openclaw tui break_end ;; - 15) update_moltbot ;; - 16) uninstall_moltbot ;; + 15) openclaw_memory_menu ;; + 16) openclaw_backup_restore_menu ;; + 17) update_moltbot ;; + 18) uninstall_moltbot ;; *) break ;; esac done @@ -10773,7 +14101,7 @@ while true; do echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" + echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" @@ -10822,18 +14150,18 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" - echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" + echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" - echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" + echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" - echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" + echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix开源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}ClawdBot/Moltbot機器人${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -11328,8 +14656,8 @@ while true; do local docker_describe="禪道是通用的專案管理軟體" local docker_url="官網介紹: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_use="echo \"初始使用者名稱: admin\"" + local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -11548,7 +14876,7 @@ while true; do check_docker_app clear echo -e "雷池服務$check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -11583,7 +14911,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已经更新完成" + echo "雷池WAF面板已經更新完成" check_docker_app_ip ;; 3) @@ -14427,7 +17755,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="是一個功能強大的多格式文件轉換工具(支援文件、圖像、音訊視訊等)強烈建議添加域名訪問" - local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" + local docker_url="項目地址:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -14516,14 +17844,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - read -e -p "請輸入遠端伺服器IP:" remote_ip - read -e -p "目標伺服器SSH連接埠 [預設22]:" TARGET_PORT - local TARGET_PORT=${TARGET_PORT:-22} - - if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端伺服器IP。" - continue - fi + kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" + local remote_ip="$KJ_SSH_HOST" + local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) if [ -n "$latest_tar" ]; then ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -14854,7 +18177,7 @@ fail2ban_panel() { echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" - echo "2. 查看SSH拦截记录" + echo "2. 查看SSH攔截記錄" echo "3. 日誌即時監控" echo "------------------------" echo "4. 基礎參數配置(封禁時間/時間視窗/重試次數)" @@ -15056,7 +18379,7 @@ log_menu() { if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -erp "輸入服務名稱:" svc + read -erp "输入服务名: " svc journalctl -u "$svc" -f else echo "無效選擇" @@ -15096,7 +18419,7 @@ env_menu() { show_env_vars() { clear - send_stats "目前已生效環境變數" + send_stats "当前已生效环境变量" echo "========== 目前已生效環境變數(節選) ==========" printf "%-20s %s\n" "變數名" "值" echo "-----------------------------------------------" @@ -15306,7 +18629,7 @@ linux_Settings() { echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高風險漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux核心升級${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令列美化工具${gl_huang}★${gl_bai}" @@ -15647,7 +18970,7 @@ EOF echo "------------------------" echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" - echo "5. 删除账号" + echo "5. 刪除帳號" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -16258,7 +19581,7 @@ EOF echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo -e "5. 啟動fail2ban防禦SSH暴力破解" echo -e "6. 開放所有端口" - echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" @@ -16294,7 +19617,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 5/12. 啟動fail2ban防禦SSH暴力破解" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 開放所有端口" echo "------------------------------------------------" bbr_on @@ -16457,7 +19780,7 @@ linux_file() { echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" - echo "25. 传文件至其他服务器" + echo "25. 傳文件至其他伺服器" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -16465,7 +19788,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname + read -e -p "請輸入目錄名:" dirname cd "$dirname" 2>/dev/null || echo "無法進入目錄" send_stats "進入目錄" ;; @@ -16513,7 +19836,7 @@ linux_file() { send_stats "修改檔案權限" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name + read -e -p "請輸入目前檔名:" current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" @@ -16585,26 +19908,13 @@ linux_file() { continue fi - read -e -p "請輸入遠端伺服器IP:" remote_ip - if [ -z "$remote_ip" ]; then - echo "錯誤: 請輸入遠端伺服器IP。" - send_stats "傳送檔案失敗: 未輸入遠端伺服器IP" - continue - fi - - read -e -p "請輸入遠端伺服器使用者名稱 (預設root):" remote_user - remote_user=${remote_user:-root} - - read -e -p "請輸入遠端伺服器密碼:" -s remote_password - echo - if [ -z "$remote_password" ]; then - echo "錯誤: 請輸入遠端伺服器密碼。" - send_stats "傳送檔案失敗: 未輸入遠端伺服器密碼" - continue - fi + kj_ssh_read_host_user_port "請輸入遠端伺服器IP:" "請輸入遠端伺服器使用者名稱 (預設root):" "請輸入登入連接埠 (預設22):" "root" "22" + local remote_ip="$KJ_SSH_HOST" + local remote_user="$KJ_SSH_USER" + local remote_port="$KJ_SSH_PORT" - read -e -p "請輸入登入連接埠 (預設22):" remote_port - remote_port=${remote_port:-22} + kj_ssh_read_password "請輸入遠端伺服器密碼:" + local remote_password="$KJ_SSH_PASSWORD" # 清除已知主機的舊條目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" @@ -16739,7 +20049,7 @@ while true; do 4) clear send_stats "備份叢集" - echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai} 文件下载,完成备份!" + echo -e "請將${gl_huang}/root/cluster/servers.py${gl_bai}檔案下載,完成備份!" break_end ;; @@ -16802,7 +20112,7 @@ echo "廣告專欄" echo "------------------------" echo "將為用戶提供更簡單優雅的推廣與購買體驗!" echo "" -echo -e "服务器优惠" +echo -e "伺服器優惠" echo "------------------------" echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活動${gl_bai}" echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" From 268881702d93e6fe21cb3f99e81f9b9173e6263b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 10:32:02 +0800 Subject: [PATCH 1030/1285] Add AIClient-2-API project to apps repository --- apps/AIClient-2-API | 1 + 1 file changed, 1 insertion(+) create mode 160000 apps/AIClient-2-API diff --git a/apps/AIClient-2-API b/apps/AIClient-2-API new file mode 160000 index 000000000..90ffd83c7 --- /dev/null +++ b/apps/AIClient-2-API @@ -0,0 +1 @@ +Subproject commit 90ffd83c7869b46e357195c91336f72954162bb0 From 5ac5b33f4b9f633aa8a802c5e4e8a40bbfb3f2e1 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 15:05:02 +0800 Subject: [PATCH 1031/1285] fix(openclaw): gate /responses protocol detection to 2xx only --- kejilion.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0bbfd5c93..48e525526 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10161,12 +10161,17 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: Only consider /responses supported when the probe indicates a valid endpoint. + # Many OpenAI-compatible providers only implement /v1/chat/completions and will respond 400/422 + # to /responses; treating that as "supported" causes mis-routing. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None def send_stat(action): @@ -10621,14 +10626,18 @@ PY DETECTED_REASON="fallback: /responses not supported" code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + # Capability gate: + # Only treat /responses as supported when probe returns a "success" HTTP code. + # Many OpenAI-compatible providers will return 400/422 for /responses even though + # /v1/chat/completions works; routing those providers to openai-responses is wrong. + if [[ "$code_responses" == "200" || "$code_responses" == "201" || "$code_responses" == "202" || "$code_responses" == "204" ]]; then DETECTED_API="openai-responses" DETECTED_REASON="POST /responses -> HTTP $code_responses" return 0 fi DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + DETECTED_REASON="POST /responses=$code_responses -> treated as unsupported -> fallback /completions" return 0 } From 81669ceff6730d3e4f7e66868dd2dfa95513d09d Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 15:28:12 +0800 Subject: [PATCH 1032/1285] chore(sh): sync cn script + remove AIClient-2-API from sh repo --- apps/AIClient-2-API | 1 - cn/kejilion.sh | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) delete mode 160000 apps/AIClient-2-API diff --git a/apps/AIClient-2-API b/apps/AIClient-2-API deleted file mode 160000 index 90ffd83c7..000000000 --- a/apps/AIClient-2-API +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 90ffd83c7869b46e357195c91336f72954162bb0 diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8a54514c0..f59f3a325 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10161,12 +10161,17 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: Only consider /responses supported when the probe indicates a valid endpoint. + # Many OpenAI-compatible providers only implement /v1/chat/completions and will respond 400/422 + # to /responses; treating that as "supported" causes mis-routing. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None def send_stat(action): @@ -10621,14 +10626,18 @@ PY DETECTED_REASON="fallback: /responses not supported" code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then + # Capability gate: + # Only treat /responses as supported when probe returns a "success" HTTP code. + # Many OpenAI-compatible providers will return 400/422 for /responses even though + # /v1/chat/completions works; routing those providers to openai-responses is wrong. + if [[ "$code_responses" == "200" || "$code_responses" == "201" || "$code_responses" == "202" || "$code_responses" == "204" ]]; then DETECTED_API="openai-responses" DETECTED_REASON="POST /responses -> HTTP $code_responses" return 0 fi DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" + DETECTED_REASON="POST /responses=$code_responses -> treated as unsupported -> fallback /completions" return 0 } From 09ad3a2564c2b64879528826dfaa44bb94a6efed Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 15:40:38 +0800 Subject: [PATCH 1033/1285] fix(openclaw): provider sync/repair treat /responses as supported only on 2xx --- cn/kejilion.sh | 16 ++++++++++++---- kejilion.sh | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f59f3a325..2fd462e09 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11047,12 +11047,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11311,12 +11315,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None try: with open(path, 'r', encoding='utf-8') as f: diff --git a/kejilion.sh b/kejilion.sh index 48e525526..c4b8a2778 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11047,12 +11047,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11311,12 +11315,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None try: with open(path, 'r', encoding='utf-8') as f: From cca798bb60b0eebb37e383524c4c77928eafc945 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 15:58:34 +0800 Subject: [PATCH 1034/1285] fix(openclaw): sync/probe treat /responses non-2xx as unsupported --- cn/kejilion.sh | 8 ++++++-- kejilion.sh | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2fd462e09..51b622917 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10358,12 +10358,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): diff --git a/kejilion.sh b/kejilion.sh index c4b8a2778..3201920e4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10358,12 +10358,16 @@ def probe_endpoint(base_url, api_key, path, timeout=6): def detect_api_protocol(base_url, api_key): + # Capability gate: only treat /responses as supported when probe returns a 2xx success code. + # Providers may return 400/422/500 for /responses even if /chat/completions works. code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): + if code is not None and code in (200, 201, 202, 204): return 'openai-responses', f'POST /responses -> HTTP {code}', None + if code is not None and code in (404, 405): + return 'openai-completions', f'POST /responses={code} -> fallback /completions', None if err: return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None + return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): From 920841bb03a9b2efc29b1115f706b0eaae511b10 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 18:19:26 +0800 Subject: [PATCH 1035/1285] refactor(openclaw): remove protocol probing/auto-fix from api manage flows --- cn/kejilion.sh | 261 +----------------- kejilion.sh | 261 +----------------- ...ests_openclaw_api_protocol_detect_smoke.sh | 80 +----- 3 files changed, 30 insertions(+), 572 deletions(-) mode change 100644 => 100755 tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 51b622917..3be40bf62 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10139,41 +10139,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: Only consider /responses supported when the probe indicates a valid endpoint. - # Many OpenAI-compatible providers only implement /v1/chat/completions and will respond 400/422 - # to /responses; treating that as "supported" causes mis-routing. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10336,40 +10301,6 @@ def delete_provider_and_refs(name): return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10412,16 +10343,6 @@ for name, provider in list(providers.items()): api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -10603,47 +10524,8 @@ PY - # OpenClaw API 协议探测(优先 responses -> completions) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" - - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - # Capability gate: - # Only treat /responses as supported when probe returns a "success" HTTP code. - # Many OpenAI-compatible providers will return 400/422 for /responses even though - # /v1/chat/completions works; routing those providers to openai-responses is wrong. - if [[ "$code_responses" == "200" || "$code_responses" == "201" || "$code_responses" == "202" || "$code_responses" == "204" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> treated as unsupported -> fallback /completions" - return 0 - } + # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 + # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 # 核心函数:获取并添加所有模型 add-all-models-from-provider() { @@ -10654,9 +10536,8 @@ PY echo "🔍 正在获取 $provider_name 的所有可用模型..." - # 自动识别 API 协议 - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" # 获取模型列表 local models_json=$(curl -s -m 10 \ @@ -10806,9 +10687,7 @@ EOF echo done - # 4. 协议探测(无感) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. 不再探测/判断 API 类型;协议由用户自行选择与维护 # 5. 获取模型列表 echo "🔍 正在获取可用模型列表..." @@ -11029,39 +10908,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11145,19 +10991,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: @@ -11244,8 +11080,6 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: @@ -11285,84 +11119,10 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') -PY + # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 + # 保留函数以兼容菜单调用,但不做任何改写。 + echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + return 0 } fix-openclaw-provider-protocol-interactive() { @@ -11382,6 +11142,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi + # 不再探测/纠正协议 install jq curl >/dev/null 2>&1 openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" local rc=$? diff --git a/kejilion.sh b/kejilion.sh index 3201920e4..8dea07d27 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10139,41 +10139,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: Only consider /responses supported when the probe indicates a valid endpoint. - # Many OpenAI-compatible providers only implement /v1/chat/completions and will respond 400/422 - # to /responses; treating that as "supported" causes mis-routing. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10336,40 +10301,6 @@ def delete_provider_and_refs(name): return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10412,16 +10343,6 @@ for name, provider in list(providers.items()): api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自动纠正协议为 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 协议探测失败,跳过纠正 ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') @@ -10603,47 +10524,8 @@ PY - # OpenClaw API 协议探测(优先 responses -> completions) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" - - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - # Capability gate: - # Only treat /responses as supported when probe returns a "success" HTTP code. - # Many OpenAI-compatible providers will return 400/422 for /responses even though - # /v1/chat/completions works; routing those providers to openai-responses is wrong. - if [[ "$code_responses" == "200" || "$code_responses" == "201" || "$code_responses" == "202" || "$code_responses" == "204" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> treated as unsupported -> fallback /completions" - return 0 - } + # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 + # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 # 核心函数:获取并添加所有模型 add-all-models-from-provider() { @@ -10654,9 +10536,8 @@ PY echo "🔍 正在获取 $provider_name 的所有可用模型..." - # 自动识别 API 协议 - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" # 获取模型列表 local models_json=$(curl -s -m 10 \ @@ -10806,9 +10687,7 @@ EOF echo done - # 4. 协议探测(无感) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. 不再探测/判断 API 类型;协议由用户自行选择与维护 # 5. 获取模型列表 echo "🔍 正在获取可用模型列表..." @@ -11029,39 +10908,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11145,19 +10991,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},将重新探测协议后继续') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自动纠正协议: {target} {api} ({detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ 协议探测失败,跳过纠正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: @@ -11244,8 +11080,6 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: @@ -11285,84 +11119,10 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - # Capability gate: only treat /responses as supported when probe returns a 2xx success code. - # Providers may return 400/422/500 for /responses even if /chat/completions works. - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code in (200, 201, 202, 204): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if code is not None and code in (404, 405): - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses -> HTTP {code} (treated as unsupported) -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ 未找到 openclaw.json') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 协议: {current_api or "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ 无需更新:协议保持为 {current_api or api}') -PY + # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 + # 保留函数以兼容菜单调用,但不做任何改写。 + echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + return 0 } fix-openclaw-provider-protocol-interactive() { @@ -11382,6 +11142,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi + # 不再探测/纠正协议 install jq curl >/dev/null 2>&1 openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" local rc=$? diff --git a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh old mode 100644 new mode 100755 index e141cef4e..ac869b471 --- a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh +++ b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh @@ -8,7 +8,7 @@ mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw" KEEP_WORKDIR=${KEEP_WORKDIR:-false} trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT -# 抽取 OpenClaw API 添加逻辑 +# 抽取 OpenClaw API 添加逻辑(只验证:不再做协议探测/自动纠正) cat > "$WORKDIR/harness.sh" <<'EOF_INNER' #!/usr/bin/env bash set -euo pipefail @@ -19,7 +19,7 @@ install() { return 0; } EOF_INNER awk 'BEGIN{p=0} - /openclaw_probe_api_endpoint\(\) \{/{p=1} + /add-all-models-from-provider\(\) \{/{p=1} /openclaw_api_manage_list\(\) \{/{p=0} p{print} ' "$SCRIPT" >> "$WORKDIR/harness.sh" @@ -37,35 +37,21 @@ cat > "$WORKDIR/bin/curl" <<'EOF_INNER' #!/usr/bin/env bash set -e args="$*" -# write body to stdout when /models if [[ "$args" == *"/models"* ]]; then cat <<'JSON' {"data": [{"id": "gpt-4o"}, {"id": "gpt-4o-mini"}]} JSON exit 0 fi -# emulate POST /responses = 404, /chat/completions = 200 -if [[ "$args" == *"/responses"* ]]; then - printf "404" - exit 0 -fi -if [[ "$args" == *"/chat/completions"* ]]; then - printf "200" - exit 0 -fi -printf "000" +printf "" exit 0 EOF_INNER chmod +x "$WORKDIR/bin/curl" -# stub: jq (passthrough for system jq) -# rely on system jq if available - export HOME="$WORKDIR/home" export PATH="$WORKDIR/bin:$PATH" export TERM=xterm -# case 1: responses 不可用但 chat/completions 可用,仍应写 openai-completions cat > "$HOME/.openclaw/openclaw.json" <<'JSON' { "models": { @@ -82,62 +68,12 @@ JSON source "$WORKDIR/harness.sh" +# 添加 provider,不应依赖协议探测;若脚本内部仍调用已删除函数会报错 add-all-models-from-provider "demo" "https://api.example.com/v1" "sk-test" -python3 - <<'PY' -import json, os, sys -path = os.path.expanduser('~/.openclaw/openclaw.json') -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -prov = data.get('models', {}).get('providers', {}).get('demo', {}) -api = prov.get('api') -if api != 'openai-completions': - raise SystemExit(f'api mismatch: {api}') -print('SMOKE_OK: detect fallback to openai-completions') -PY - -# case 2: 已写入 openai-chat-completions 的配置,修复后必须落回合法协议 -cat > "$HOME/.openclaw/openclaw.json" <<'JSON' -{ - "models": { - "mode": "merge", - "providers": { - "demo": { - "api": "openai-chat-completions", - "baseUrl": "http://127.0.0.1:1", - "apiKey": "sk-test", - "models": [ - { - "id": "gpt-4o", - "name": "demo / gpt-4o", - "input": ["text"], - "contextWindow": 1, - "maxTokens": 1, - "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0} - } - ] - } - } - }, - "agents": { - "defaults": { - "models": { - "demo/gpt-4o": {} - } - } - } -} -JSON +echo "SMOKE_OK: no protocol probing required during add" -openclaw_detect_api_protocol_by_provider "$HOME/.openclaw/openclaw.json" "demo" +# 协议修复函数现在不再修改配置,只输出提示 +openclaw_detect_api_protocol_by_provider "$HOME/.openclaw/openclaw.json" "demo" >/dev/null 2>&1 || true -python3 - <<'PY' -import json, os, sys -path = os.path.expanduser('~/.openclaw/openclaw.json') -with open(path, 'r', encoding='utf-8') as f: - data = json.load(f) -api = data.get('models', {}).get('providers', {}).get('demo', {}).get('api') -if api not in ('openai-completions', 'openai-responses'): - raise SystemExit(f'protocol fix mismatch: {api}') -print('SMOKE_OK: protocol repair corrected openai-chat-completions') -PY +echo "SMOKE_OK: protocol repair is no-op" From e9a7180878022ff100128e92d892e752292b7c35 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 18:26:09 +0800 Subject: [PATCH 1036/1285] feat(openclaw): api manage option 4 switch provider api type manually --- cn/kejilion.sh | 65 ++++++++++++++++--- kejilion.sh | 65 ++++++++++++++++--- ...ests_openclaw_api_protocol_detect_smoke.sh | 2 +- 3 files changed, 111 insertions(+), 21 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3be40bf62..98b771367 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11127,7 +11127,7 @@ openclaw_detect_api_protocol_by_provider() { fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API协议修复" + send_stats "OpenClaw API协议切换" if [ ! -f "$config_file" ]; then echo "❌ 未找到配置文件: $config_file" @@ -11135,30 +11135,75 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - read -erp "请输入要修复协议的 API 名称(provider): " provider_name + read -erp "请输入要切换协议的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then echo "❌ provider 名称不能为空" break_end return 1 fi - # 不再探测/纠正协议 - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "请选择要设置的 API 类型:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "请输入你的选择 (1/2): " proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ 无效选择" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ 非法协议值') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ 已更新 provider {name} 协议为: {new_api}') +PY local rc=$? case "$rc" in 0) - echo "✅ 协议已检测并更新(如有变更)" start_gateway ;; 2) - echo "❌ 修复失败:provider 不存在或未配置" + echo "❌ 切换失败:provider 不存在或未配置" ;; 3) - echo "❌ 修复失败:provider 配置不完整" + echo "❌ 切换失败:协议值非法" ;; *) - echo "❌ 修复失败:请检查配置文件结构或日志输出" + echo "❌ 切换失败:请检查配置文件结构或日志输出" ;; esac @@ -11326,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 协议修复/重新探测" + echo "4. 切换 API 类型(手动设置协议)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice diff --git a/kejilion.sh b/kejilion.sh index 8dea07d27..7dce7fab5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11127,7 +11127,7 @@ openclaw_detect_api_protocol_by_provider() { fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API协议修复" + send_stats "OpenClaw API协议切换" if [ ! -f "$config_file" ]; then echo "❌ 未找到配置文件: $config_file" @@ -11135,30 +11135,75 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - read -erp "请输入要修复协议的 API 名称(provider): " provider_name + read -erp "请输入要切换协议的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then echo "❌ provider 名称不能为空" break_end return 1 fi - # 不再探测/纠正协议 - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "请选择要设置的 API 类型:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "请输入你的选择 (1/2): " proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ 无效选择" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ 非法协议值') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ 已更新 provider {name} 协议为: {new_api}') +PY local rc=$? case "$rc" in 0) - echo "✅ 协议已检测并更新(如有变更)" start_gateway ;; 2) - echo "❌ 修复失败:provider 不存在或未配置" + echo "❌ 切换失败:provider 不存在或未配置" ;; 3) - echo "❌ 修复失败:provider 配置不完整" + echo "❌ 切换失败:协议值非法" ;; *) - echo "❌ 修复失败:请检查配置文件结构或日志输出" + echo "❌ 切换失败:请检查配置文件结构或日志输出" ;; esac @@ -11326,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 协议修复/重新探测" + echo "4. 切换 API 类型(手动设置协议)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice diff --git a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh index ac869b471..3f615f728 100755 --- a/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh +++ b/tests/openclaw/tests_openclaw_api_protocol_detect_smoke.sh @@ -76,4 +76,4 @@ echo "SMOKE_OK: no protocol probing required during add" # 协议修复函数现在不再修改配置,只输出提示 openclaw_detect_api_protocol_by_provider "$HOME/.openclaw/openclaw.json" "demo" >/dev/null 2>&1 || true -echo "SMOKE_OK: protocol repair is no-op" +echo "SMOKE_OK: protocol switch is available" From 13221611936095adde264e8460b080cd8603646a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 18:38:19 +0800 Subject: [PATCH 1037/1285] chore(openclaw): rename api manage option 4 label --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 98b771367..facf667b8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11371,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 切换 API 类型(手动设置协议)" + echo "4. 切换 API 类型(responses / completions)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice diff --git a/kejilion.sh b/kejilion.sh index 7dce7fab5..a492a2416 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11371,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 切换 API 类型(手动设置协议)" + echo "4. 切换 API 类型(responses / completions)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice From 12751f76fceb4e3fecd2af3e82f5c2c175dcbadf Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 18:38:47 +0800 Subject: [PATCH 1038/1285] chore(openclaw): reorder api type label --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index facf667b8..177b3222f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11371,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 切换 API 类型(responses / completions)" + echo "4. 切换 API 类型(completions / responses)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice diff --git a/kejilion.sh b/kejilion.sh index a492a2416..455066a8d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11371,7 +11371,7 @@ PY echo "1. 添加API" echo "2. 同步API供应商模型列表" echo "3. 删除API" - echo "4. 切换 API 类型(responses / completions)" + echo "4. 切换 API 类型(completions / responses)" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice From c5c469b89b0e3ad9b5584b57ccc4a1d6ea45fff7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 15 Mar 2026 18:44:40 +0800 Subject: [PATCH 1039/1285] chore(openclaw): swap api manage options 3 and 4 --- cn/kejilion.sh | 8 ++++---- kejilion.sh | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 177b3222f..ab63469c8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11370,8 +11370,8 @@ PY echo "---------------------------------------" echo "1. 添加API" echo "2. 同步API供应商模型列表" - echo "3. 删除API" - echo "4. 切换 API 类型(completions / responses)" + echo "3. 切换 API 类型(completions / responses)" + echo "4. 删除API" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11384,10 +11384,10 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive ;; 0) return 0 diff --git a/kejilion.sh b/kejilion.sh index 455066a8d..6c509bf40 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11370,8 +11370,8 @@ PY echo "---------------------------------------" echo "1. 添加API" echo "2. 同步API供应商模型列表" - echo "3. 删除API" - echo "4. 切换 API 类型(completions / responses)" + echo "3. 切换 API 类型(completions / responses)" + echo "4. 删除API" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11384,10 +11384,10 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive ;; 0) return 0 From b24d699133932813eb48811bffca3e0eea2b32c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:07:26 +0800 Subject: [PATCH 1040/1285] Update git config URLs to use proxy settings --- cn/kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ab63469c8..b80dc8c4f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10481,8 +10481,8 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon @@ -13669,8 +13669,8 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway From 7a7a046c4c6637d14b8dd0364306146eb5d930e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:08:42 +0800 Subject: [PATCH 1041/1285] Change git config to use proxy for GitHub URLs --- kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 6c509bf40..1d83bab57 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10481,8 +10481,8 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon @@ -13669,8 +13669,8 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway From ddb1bac0831c01c3cf617a963c7a69cf135e3681 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 17 Mar 2026 10:13:54 +0800 Subject: [PATCH 1042/1285] chore(openclaw): print sync overview before model diff details --- kejilion.sh | 38 +- kr/kejilion.sh | 7465 +++++++++++++++++++++++------------------------- 2 files changed, 3667 insertions(+), 3836 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1d83bab57..596476521 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10389,15 +10389,6 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10446,6 +10437,16 @@ for name, provider in list(providers.items()): summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + if fatal_errors: for line in summary: print(line) @@ -11025,15 +11026,6 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11087,6 +11079,16 @@ if changed: f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 3338d91e5..596476521 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -36,7 +36,7 @@ quanju_canshu -# 명령을 실행하는 함수 정의 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -59,9 +59,9 @@ CheckFirstRun_true() { -# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! -# 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! +# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -114,22 +114,22 @@ CheckFirstRun_false() { fi } -# 사용자에게 약관에 동의하라는 메시지를 표시합니다. +# 提示用户同意条款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" - echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." - echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -e -p "위의 약관에 동의하십니까? (예/아니요):" user_input + read -e -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "라이센스 계약" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "허가가 거부되었습니다" + send_stats "许可拒绝" clear exit fi @@ -173,13 +173,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "패키지 매개변수가 제공되지 않았습니다!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_kjlan}설치 중$package...${gl_bai}" + echo -e "${gl_kjlan}正在安装 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -207,7 +207,7 @@ install() { pkg update pkg install -y "$package" else - echo "알 수 없는 패키지 관리자입니다!" + echo "未知的包管理器!" return 1 fi fi @@ -225,11 +225,11 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}힌트:${gl_bai}디스크 공간이 부족합니다!" - echo "현재 사용 가능한 공간: $((available_space_mb/1024))G" - echo "최소 필요 공간:${required_gb}G" - echo "설치를 계속할 수 없습니다. 디스크 공간을 비운 후 다시 시도하십시오." - send_stats "디스크 공간이 부족합니다." + echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" + echo "当前可用空间: $((available_space_mb/1024))G" + echo "最小需求空间: ${required_gb}G" + echo "无法继续安装,请清理磁盘空间后重试。" + send_stats "磁盘空间不足" break_end kejilion fi @@ -249,12 +249,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "패키지 매개변수가 제공되지 않았습니다!" + echo "未提供软件包参数!" return 1 fi for package in "$@"; do - echo -e "${gl_kjlan}제거 중$package...${gl_bai}" + echo -e "${gl_kjlan}正在卸载 $package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -272,14 +272,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "알 수 없는 패키지 관리자입니다!" + echo "未知的包管理器!" return 1 fi done } -# 다양한 배포판에 적합한 범용 systemctl 기능 +# 通用 systemctl 函数,适用于各种发行版 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -292,43 +292,43 @@ systemctl() { } -# 서비스 다시 시작 +# 重启服务 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 다시 시작되었습니다." + echo "$1 服务已重启。" else - echo "오류: 다시 시작$1서비스가 실패했습니다." + echo "错误:重启 $1 服务失败。" fi } -# 서비스 시작 +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 시작되었습니다." + echo "$1 服务已启动。" else - echo "오류: 시작$1서비스가 실패했습니다." + echo "错误:启动 $1 服务失败。" fi } -# 서비스 중지 +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1서비스가 중지되었습니다." + echo "$1 服务已停止。" else - echo "오류: 중지$1서비스가 실패했습니다." + echo "错误:停止 $1 服务失败。" fi } -# 서비스 상태 확인 +# 查看服务状态 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1서비스 상태가 표시됩니다." + echo "$1 服务状态已显示。" else - echo "오류: 표시할 수 없습니다.$1서비스 상태." + echo "错误:无法显示 $1 服务状态。" fi } @@ -341,14 +341,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME부팅시 자동으로 시작되도록 설정되어 있습니다." + echo "$SERVICE_NAME 已设置为开机自启。" } break_end() { - echo -e "${gl_lv}작업 완료${gl_bai}" - echo "계속하려면 아무 키나 누르세요..." + echo -e "${gl_lv}操作完成${gl_bai}" + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -451,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_kjlan}도커 환경 설치 중...${gl_bai}" + echo -e "${gl_kjlan}正在安装docker环境...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -473,63 +473,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "도커 컨테이너 관리" - echo "도커 컨테이너 목록" + send_stats "Docker容器管理" + echo "Docker容器列表" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "컨테이너 운영" + echo "容器操作" echo "------------------------" - echo "1. 새 컨테이너 생성" + echo "1. 创建新的容器" echo "------------------------" - echo "2. 지정된 컨테이너 시작 6. 모든 컨테이너 시작" - echo "3. 지정된 컨테이너를 중지합니다. 7. 모든 컨테이너를 중지합니다." - echo "4. 지정된 컨테이너 삭제 8. 모든 컨테이너 삭제" - echo "5. 지정된 컨테이너를 다시 시작합니다. 9. 모든 컨테이너를 다시 시작합니다." + echo "2. 启动指定容器 6. 启动所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" + echo "5. 重启指定容器 9. 重启所有容器" echo "------------------------" - echo "11. 지정된 컨테이너를 입력합니다. 12. 컨테이너 로그를 봅니다." - echo "13. 컨테이너 네트워크 확인 14. 컨테이너 점유율 확인" + echo "11. 进入指定容器 12. 查看容器日志" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" - echo "15. 컨테이너 포트 액세스 활성화 16. 컨테이너 포트 액세스 닫기" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "새 컨테이너 만들기" - read -e -p "생성 명령을 입력하십시오:" dockername + send_stats "新建容器" + read -e -p "请输入创建命令: " dockername $dockername ;; 2) - send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) - send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + send_stats "停止指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) - send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + send_stats "删除指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker rm -f $dockername ;; 5) - send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + send_stats "重启指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker restart $dockername ;; 6) - send_stats "모든 컨테이너 시작" + send_stats "启动所有容器" docker start $(docker ps -a -q) ;; 7) - send_stats "모든 컨테이너 중지" + send_stats "停止所有容器" docker stop $(docker ps -q) ;; 8) - send_stats "모든 컨테이너 삭제" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -538,32 +538,32 @@ while true; do [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 9) - send_stats "모든 컨테이너 다시 시작" + send_stats "重启所有容器" docker restart $(docker ps -q) ;; 11) - send_stats "컨테이너를 입력하세요" - read -e -p "컨테이너 이름을 입력하세요:" dockername + send_stats "进入容器" + read -e -p "请输入容器名: " dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "컨테이너 로그 보기" - read -e -p "컨테이너 이름을 입력하세요:" dockername + send_stats "查看容器日志" + read -e -p "请输入容器名: " dockername docker logs $dockername break_end ;; 13) - send_stats "컨테이너 네트워크 보기" + send_stats "查看容器网络" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" + printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -577,14 +577,14 @@ while true; do break_end ;; 14) - send_stats "컨테이너 점유율 보기" + send_stats "查看容器占用" docker stats --no-stream break_end ;; 15) - send_stats "컨테이너 포트 액세스 허용" - read -e -p "컨테이너 이름을 입력하세요:" docker_name + send_stats "允许容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -593,8 +593,8 @@ while true; do ;; 16) - send_stats "컨테이너 포트 접근 차단" - read -e -p "컨테이너 이름을 입력하세요:" docker_name + send_stats "阻止容器端口访问" + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -613,44 +613,44 @@ done docker_image() { while true; do clear - send_stats "도커 이미지 관리" - echo "도커 이미지 목록" + send_stats "Docker镜像管理" + echo "Docker镜像列表" docker image ls echo "" - echo "미러 작동" + echo "镜像操作" echo "------------------------" - echo "1. 지정된 이미지 가져오기 3. 지정된 이미지 삭제" - echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" + echo "1. 获取指定镜像 3. 删除指定镜像" + echo "2. 更新指定镜像 4. 删除所有镜像" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "이미지 가져오기" - read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames + send_stats "拉取镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_kjlan}이미지 가져오기:$name${gl_bai}" + echo -e "${gl_kjlan}正在获取镜像: $name${gl_bai}" docker pull $name done ;; 2) - send_stats "이미지 업데이트" - read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames + send_stats "更新镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do - echo -e "${gl_kjlan}이미지 업데이트 중:$name${gl_bai}" + echo -e "${gl_kjlan}正在更新镜像: $name${gl_bai}" docker pull $name done ;; 3) - send_stats "이미지 삭제" - read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames + send_stats "删除镜像" + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "모든 이미지 삭제" + send_stats "删除所有镜像" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -659,7 +659,7 @@ while true; do [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -727,16 +727,16 @@ install_crontab() { service cron start ;; *) - echo "지원되지 않는 배포판:$ID" + echo "不支持的发行版: $ID" return ;; esac else - echo "운영 체제를 확인할 수 없습니다." + echo "无法确定操作系统。" return fi - echo -e "${gl_lv}crontab이 설치되어 있고 cron 서비스가 실행 중입니다.${gl_bai}" + echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -748,27 +748,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 구성 파일이 있는지 확인하고, 없으면 파일을 생성하고 기본 설정을 씁니다. + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # jq를 사용하여 구성 파일 업데이트 처리 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 현재 구성에 이미 ipv6 설정이 있는지 확인하십시오. + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 구성 업데이트 및 IPv6 활성화 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 원래 구성을 새 구성과 비교 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}현재 IPv6 액세스가 활성화되어 있습니다.${gl_bai}" + echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -783,28 +783,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 구성 파일이 있는지 확인하십시오. + # 检查配置文件是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}구성 파일이 존재하지 않습니다.${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi - # 현재 구성 읽기 + # 读取当前配置 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # jq를 사용하여 구성 파일 업데이트 처리 + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 현재 ipv6 상태 확인 + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 원래 구성을 새 구성과 비교 + # 对比原始配置与新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6 액세스는 현재 폐쇄되었습니다.${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}IPv6 액세스가 성공적으로 종료되었습니다.${gl_bai}" + echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" fi } @@ -843,117 +843,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "포트 번호를 하나 이상 입력하세요." + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 종료 규칙 삭제 + # 删除已存在的关闭规则 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 공개 규칙 추가 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "포트가 열렸습니다.$port" + echo "已打开端口 $port" fi done save_iptables_rules - send_stats "포트가 열렸습니다." + send_stats "已打开端口" } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "포트 번호를 하나 이상 입력하세요." + echo "请提供至少一个端口号" return 1 fi install iptables for port in "${ports[@]}"; do - # 기존 공개 규칙 삭제 + # 删除已存在的打开规则 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 종료 규칙 추가 + # 添加关闭规则 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "항구 폐쇄$port" + echo "已关闭端口 $port" fi done - # 기존 규칙 삭제(있는 경우) + # 删除已存在的规则(如果有) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 첫 번째 규칙에 새 규칙을 삽입합니다. + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "항구 폐쇄" + send_stats "已关闭端口" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 차단 규칙 삭제 + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 허용 규칙 추가 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "공개된 IP$ip" + echo "已放行IP $ip" fi done save_iptables_rules - send_stats "공개된 IP" + send_stats "已放行IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." + echo "请提供至少一个IP地址或IP段" return 1 fi install iptables for ip in "${ips[@]}"; do - # 기존 허용 규칙 삭제 + # 删除已存在的允许规则 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 차단 규칙 추가 + # 添加阻止规则 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IP가 차단됨$ip" + echo "已阻止IP $ip" fi done save_iptables_rules - send_stats "IP가 차단됨" + send_stats "已阻止IP" } @@ -963,7 +963,7 @@ block_ip() { enable_ddos_defense() { - # DDoS 보호 켜기 + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -973,12 +973,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "DDoS 방어 켜기" + send_stats "开启DDoS防御" } -# DDoS 방어 끄기 +# 关闭DDoS防御 disable_ddos_defense() { - # DDoS 보호 끄기 + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -988,14 +988,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "DDoS 방어 끄기" + send_stats "关闭DDoS防御" } -# 국가 IP 규칙을 관리하는 기능 +# 管理国家IP规则的函数 manage_country_rules() { local action="$1" shift # 去掉第一个参数,剩下的全是国家代码 @@ -1013,7 +1013,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류: 다운로드$country_codeIP 영역 파일 실패" + echo "错误:下载 $country_code 的 IP 区域文件失败" continue fi @@ -1023,7 +1023,7 @@ manage_country_rules() { iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - echo "성공적으로 차단되었습니다$country_codeIP 주소" + echo "已成功阻止 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; @@ -1033,7 +1033,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "오류: 다운로드$country_codeIP 영역 파일 실패" + echo "错误:下载 $country_code 的 IP 区域文件失败" continue fi @@ -1046,7 +1046,7 @@ manage_country_rules() { iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - echo "허용되었습니다.$country_codeIP 주소" + echo "已成功允许 $country_code 的 IP 地址" rm "${country_code,,}.zone" ;; @@ -1057,11 +1057,11 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "성공적으로 제거되었습니다$country_codeIP 주소 제한" + echo "已成功解除 $country_code 的 IP 地址限制" ;; *) - echo "사용법: prepare_country_rules {block|allow|unblock} " + echo "用法: manage_country_rules {block|allow|unblock} " ;; esac done @@ -1082,42 +1082,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "고급 방화벽 관리" - send_stats "고급 방화벽 관리" + echo "高级防火墙管理" + send_stats "高级防火墙管理" echo "------------------------" iptables -L INPUT echo "" - echo "방화벽 관리" + echo "防火墙管理" echo "------------------------" - echo "1. 지정 포트 열기 2. 지정 포트 닫기" - echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." + echo "1. 开放指定端口 2. 关闭指定端口" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" - echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "5. IP白名单 6. IP黑名单" + echo "7. 清除指定IP" echo "------------------------" - echo "11. PING 허용 12. PING 비활성화" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" - echo "13. DDOS 방어 시작 14. DDOS 방어 끄기" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" - echo "15. 특정 국가 IP 차단 16. 특정 국가 IP만 허용" - echo "17. 지정된 국가에서 IP 제한을 해제합니다." + echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" + echo "17. 解除指定国家IP限制" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "열려 있는 포트 번호를 입력하세요." o_port + read -e -p "请输入开放的端口号: " o_port open_port $o_port - send_stats "지정된 포트 열기" + send_stats "开放指定端口" ;; 2) - read -e -p "닫힌 포트 번호를 입력하세요:" c_port + read -e -p "请输入关闭的端口号: " c_port close_port $c_port - send_stats "지정된 포트 닫기" + send_stats "关闭指定端口" ;; 3) - # 모든 포트 열기 + # 开放所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1130,10 +1130,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트 열기" + send_stats "开放所有端口" ;; 4) - # 모든 포트를 닫으세요 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1146,40 +1146,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "모든 포트를 닫으세요" + send_stats "关闭所有端口" ;; 5) - # IP 화이트리스트 - read -e -p "허용된 IP 또는 IP 세그먼트를 입력하세요." o_ip + # IP 白名单 + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IP 블랙리스트 - read -e -p "차단된 IP 또는 IP 범위를 입력하세요." c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) - # 지정된 IP 지우기 - read -e -p "삭제된 IP를 입력하세요:" d_ip + # 清除指定 IP + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "지정된 IP 지우기" + send_stats "清除指定IP" ;; 11) - # 핑 허용 + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "핑 허용" + send_stats "允许PING" ;; 12) - # 핑 비활성화 + # 禁用 PING iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "핑 비활성화" + send_stats "禁用PING" ;; 13) enable_ddos_defense @@ -1189,20 +1189,20 @@ iptables_panel() { ;; 15) - read -e -p "차단된 국가 코드를 입력하세요(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "请输入阻止的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules block $country_code - send_stats "국가 허용$country_codeIP" + send_stats "允许国家 $country_code 的IP" ;; 16) - read -e -p "허용되는 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분할 수 있음)." country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code - send_stats "블록 국가$country_codeIP" + send_stats "阻止国家 $country_code 的IP" ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules unblock $country_code - send_stats "명확한 국가$country_codeIP" + send_stats "清除国家 $country_code 的IP" ;; *) @@ -1221,23 +1221,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 현재 시스템의 모든 스왑 파티션을 가져옵니다. + # 获取当前系统中所有的 swap 分区 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 모든 스왑 파티션을 탐색하고 삭제합니다. + # 遍历并删除所有的 swap 分区 for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # /swapfile이 더 이상 사용되지 않는지 확인하세요. + # 确保 /swapfile 不再被使用 swapoff /swapfile - # 이전 /swap 파일 삭제 + # 删除旧的 /swapfile rm -f /swapfile - # 새로운 스왑 파티션 생성 + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1252,7 +1252,7 @@ add_swap() { rc-update add local fi - echo -e "가상 메모리 크기가 다음과 같이 조정되었습니다.${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1278,21 +1278,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # nginx 버전 받기 + # 获取nginx版本 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # mysql 버전 받기 + # 获取mysql版本 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # PHP 버전 받기 + # 获取php版本 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # Redis 버전 받기 + # 获取redis版本 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1305,18 +1305,18 @@ ldnmp_v() { install_ldnmp_conf() { - # 필요한 디렉토리 및 파일 생성 + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf default_server_ssl - # docker-compose.yml 파일을 다운로드하여 교체하세요. + # 下载 docker-compose.yml 文件并进行替换 wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 교체 + # 在 docker-compose.yml 文件中进行替换 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1352,10 +1352,10 @@ update_docker_compose_with_db_creds() { auto_optimize_dns() { - # 국가 코드(예: CN, US 등)를 가져옵니다. + # 获取国家代码(如 CN、US 等) local country=$(curl -s ipinfo.io/country) - # 국가에 따라 DNS 설정 + # 根据国家设置 DNS if [ "$country" = "CN" ]; then local dns1_ipv4="223.5.5.5" local dns2_ipv4="183.60.83.19" @@ -1377,8 +1377,8 @@ auto_optimize_dns() { prefer_ipv4() { grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf -echo "IPv4 우선순위로 전환됨" -send_stats "IPv4 우선순위로 전환됨" +echo "已切换为 IPv4 优先" +send_stats "已切换为 IPv4 优先" } @@ -1396,7 +1396,7 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -1407,7 +1407,7 @@ install_ldnmp() { sleep 2 clear - echo "LDNMP 환경이 설치되었습니다" + echo "LDNMP环境安装完毕" echo "------------------------" ldnmp_v @@ -1424,7 +1424,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "갱신 작업이 업데이트되었습니다." + echo "续签任务已更新" } @@ -1458,15 +1458,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming공개키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" + echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}인증서 저장 경로${gl_bai}" - echo "공개 키: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "개인 키: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}证书存放路径${gl_bai}" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1475,7 +1475,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}SSL 인증서를 빠르게 신청하고 만료되기 전에 자동으로 갱신하세요.${gl_bai}" +echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1491,8 +1491,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}신청한 인증서의 만료 상태${gl_bai}" - echo "사이트 정보 인증서 만료 시간" + echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1531,56 +1531,56 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "도메인 이름 인증서 신청이 성공했습니다." + send_stats "域名证书申请成功" else - send_stats "도메인 이름 인증서 신청 실패" - echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." - echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." - echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." - echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." - echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + send_stats "域名证书申请失败" + echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" - echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" + echo "1. 重新申请 2. 导入已有证书 0. 退出" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "재신청" - echo "다시 배포해 보세요.$webname" + send_stats "重新申请" + echo "请再次尝试部署 $webname" add_yuming install_ssltls certs_status ;; 2) - send_stats "기존 인증서 가져오기" + send_stats "导入已有证书" - # 파일 경로 정의 + # 定义文件路径 local cert_file="/home/web/certs/${yuming}_cert.pem" local key_file="/home/web/certs/${yuming}_key.pem" mkdir -p /home/web/certs - # 1. 인증서를 입력합니다(ECC 및 RSA 인증서 모두 BEGIN CERTIFICATE로 시작함). - echo "인증서(CRT/PEM) 콘텐츠를 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + # 1. 输入证书 (ECC 和 RSA 证书开头都是 BEGIN CERTIFICATE) + echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break cert_content+="${line}"$'\n' done - # 2. 개인 키를 입력하세요. (RSA, ECC, PKCS#8과 호환 가능) - echo "인증서 개인 키(개인 키) 내용을 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break key_content+="${line}"$'\n' done - # 3. 지능형 검증 - # 통과하려면 "BEGIN CERTIFICATE" 및 "PRIVATE KEY"만 포함하면 됩니다. + # 3. 智能校验 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1588,15 +1588,15 @@ certs_status() { chmod 644 "$cert_file" chmod 600 "$key_file" - # 현재 인증서 유형을 식별하고 표시합니다. + # 识别当前证书类型并显示 if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then - echo "ECC 인증서가 성공적으로 저장되었음을 감지했습니다." + echo "检测到 ECC 证书已成功保存。" else - echo "RSA 인증서가 성공적으로 저장되었음을 감지했습니다." + echo "检测到 RSA 证书已成功保存。" fi auth_method="ssl_imported" else - echo "오류: 잘못된 인증서 또는 개인 키 형식입니다!" + echo "错误:无效的证书或私钥格式!" certs_status fi ;; @@ -1611,7 +1611,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "도메인 이름 재사용" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1620,8 +1620,8 @@ fi add_yuming() { ip_address - echo -e "먼저 도메인 이름을 로컬 IP로 확인합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "귀하의 IP 또는 확인된 도메인 이름을 입력하십시오:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1632,7 +1632,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "액세스/수신 포트를 입력하고 Enter를 눌러 기본적으로 80을 사용하십시오." access_port + read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port access_port=${access_port:-80} fi } @@ -1644,13 +1644,13 @@ update_nginx_listen_port() { local access_port="$2" local conf="/home/web/conf.d/${yuming}.conf" - # access_port가 비어 있으면 건너뛰세요. + # 如果 access_port 为空,则跳过 [ -z "$access_port" ] && return 0 - # 모든 청취 라인 제거 + # 删除所有 listen 行 sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" - # 서버 { 뒤에 새 수신 대기 삽입 + # 在 server { 后插入新的 listen sed -i "/server {/a\\ listen ${access_port};\\ listen [::]:${access_port}; @@ -1700,8 +1700,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" } @@ -1720,11 +1720,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "로그인 정보:" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" + echo "登录信息: " + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo - send_stats "시작하다$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1734,29 +1734,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 구성 파일이 있는지 확인하십시오. + # 检查配置文件是否存在 if [ -f "$CONFIG_FILE" ]; then - # 구성 파일에서 API_TOKEN 및 zone_id를 읽습니다. + # 从配置文件读取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ZONE_IDS를 어레이로 변환 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else - # 캐시를 지울지 여부를 사용자에게 묻습니다. - read -e -p "Cloudflare의 캐시를 지워야 합니까? (예/아니요):" answer + # 提示用户是否清理缓存 + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then - echo "CF 정보는 다음 위치에 저장됩니다.$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다." - read -e -p "API_TOKEN을 입력하세요:" API_TOKEN - read -e -p "CF 사용자 이름을 입력하세요:" EMAIL - read -e -p "zone_id를 입력하십시오(여러 개는 공백으로 구분)." -a ZONE_IDS + echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 각 zone_id를 반복하고 캐시 지우기 명령을 실행합니다. + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "zone_id에 대한 캐시 지우기:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1764,13 +1764,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "캐시 삭제 요청이 전송되었습니다." + echo "缓存清除请求已发送完毕。" } web_cache() { - send_stats "사이트 캐시 지우기" + send_stats "清理站点缓存" cf_purge_cache cd /home/web && docker compose restart } @@ -1779,28 +1779,28 @@ web_cache() { web_del() { - send_stats "사이트 데이터 삭제" + send_stats "删除站点数据" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "도메인 이름을 삭제하는 중입니다:$yuming" + echo "正在删除域名: $yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 도메인 이름을 데이터베이스 이름으로 변환 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. - echo "데이터베이스 삭제 중:$dbname" + # 删除数据库前检查是否存在,避免报错 + echo "正在删除数据库: $dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1816,23 +1816,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 모드 매개변수에 따라 WAF를 켤지 끌지 결정합니다. + # 根据 mode 参数来决定开启或关闭 WAF if [ "$mode" == "on" ]; then - # WAF 켜기: 댓글 제거 + # 开启 WAF:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # WAF 끄기: 댓글 추가 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1846,7 +1846,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status=" WAF已开启" else waf_status="" fi @@ -1855,7 +1855,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage="cf 모드가 켜져 있습니다" + CFmessage=" cf模式已开启" else CFmessage="" fi @@ -1879,11 +1879,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 이전 정의 삭제 + # 删除旧定义 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1906,12 +1906,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 이전 정의 삭제 + # 删除旧定义 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1933,17 +1933,17 @@ patch_wp_url() { local TARGET_DIR="/home/web/html" find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do - # 이전 정의 삭제 + # 删除旧定义 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" - # 삽입 콘텐츠 생성 + # 生成插入内容 INSERT=" define('WP_HOME', '$HOME_URL'); define('WP_SITEURL', '$SITE_URL'); " - # '행복한 출판' 앞에 삽입 + # 插入到 “Happy publishing” 之前 awk -v insert="$INSERT" ' /Happy publishing/ { print insert @@ -1971,7 +1971,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # Brotli 켜기: 댓글 제거 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotli 닫기: 댓글 추가 + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2001,11 +2001,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2027,7 +2027,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # Zstd 켜기: 주석 제거 + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2042,7 +2042,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # Zstd 닫기: 설명 추가 + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2058,11 +2058,11 @@ nginx_zstd() { else - echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." + echo "无效的参数:使用 'on' 或 'off'" return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2089,7 +2089,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." + echo "无效的参数:使用 'on' 或 'off'" return 1 fi @@ -2103,31 +2103,31 @@ nginx_gzip() { web_security() { - send_stats "LDNMP 환경 방어" + send_stats "LDNMP环境防御" while true; do check_f2b_status check_waf_status check_cf_mode clear - echo -e "서버 웹사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 방어 프로그램 설치" + echo "1. 安装防御程序" echo "------------------------" - echo "5. SSH 차단 기록 보기 6. 웹사이트 차단 기록 보기" - echo "7. 방어규칙 목록 보기 8. 실시간 모니터링을 위한 로그 보기" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "7. 查看防御规则列表 8. 查看日志实时监控" echo "------------------------" - echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" + echo "11. 配置拦截参数 12. 清除所有拉黑的IP" echo "------------------------" - echo "21. cloudflare 모드 22. 고부하에서 5초 보호 활성화" + echo "21. cloudflare模式 22. 高负载开启5秒盾" echo "------------------------" - echo "31. WAF 켜기 32. WAF 끄기" - echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" + echo "31. 开启WAF 32. 关闭WAF" + echo "33. 开启DDOS防御 34. 关闭DDOS防御" echo "------------------------" - echo "9. 방어 프로그램 제거" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2192,7 +2192,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban 방어 프로그램이 제거되었습니다." + echo "Fail2Ban防御程序已卸载" break ;; @@ -2208,11 +2208,11 @@ web_security() { ;; 21) - send_stats "클라우드플레어 모드" - echo "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고 글로벌 API 키를 받으세요." + send_stats "cloudflare模式" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" - read -e -p "CF의 계좌번호를 입력하세요:" cfuser - read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2227,21 +2227,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "Cloudflare 모드가 구성되었으며, 차단 기록은 cf 백그라운드, site-security-events에서 볼 수 있습니다." + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + send_stats "高负载开启5秒盾" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" - echo "CF 매개변수 가져오기:" - echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" - echo -e "cf 백엔드 도메인 이름 요약 페이지 오른쪽 하단으로 이동하여 가져오세요.${gl_huang}지역 ID${gl_bai}" + echo "获取CF参数: " + echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "CF의 계좌번호를 입력하세요:" cfuser - read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken - read -e -p "CF에 도메인 이름의 영역 ID를 입력하세요." cfzonID + read -e -p "输入CF的账号: " cfuser + read -e -p "输入CF的Global API Key: " cftoken + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2258,23 +2258,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "고부하 자동 쉴드 오픈 스크립트가 추가되었습니다." + echo "高负载自动开盾脚本已添加" else - echo "자동 방패 열기 스크립트가 이미 있으므로 추가할 필요가 없습니다." + echo "自动开盾脚本已存在,无需添加" fi ;; 31) nginx_waf on - echo "사이트 WAF가 활성화되었습니다" - send_stats "사이트 WAF가 활성화되었습니다" + echo "站点WAF已开启" + send_stats "站点WAF已开启" ;; 32) nginx_waf off - echo "사이트 WAF가 다운되었습니다" - send_stats "사이트 WAF가 다운되었습니다" + echo "站点WAF已关闭" + send_stats "站点WAF已关闭" ;; 33) @@ -2300,11 +2300,11 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # MySQL 구성 파일에 4096M이 포함되어 있는지 확인하세요. + # 检查 MySQL 配置文件中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info="고성능 모드" + mode_info=" 高性能模式" else - mode_info="표준 모드" + mode_info=" 标准模式" fi @@ -2316,23 +2316,23 @@ check_nginx_compression() { local CONFIG_FILE="/home/web/nginx.conf" - # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) + # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status=" zstd压缩已开启" else zstd_status="" fi - # brotli가 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status="br압축이 켜져 있습니다" + br_status=" br压缩已开启" else br_status="" fi - # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status="gzip 압축이 켜져 있습니다" + gzip_status=" gzip压缩已开启" else gzip_status="" fi @@ -2346,21 +2346,21 @@ web_optimization() { check_ldnmp_mode check_nginx_compression clear - send_stats "LDNMP 환경 최적화" - echo -e "LDNMP 환경 최적화${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "优化LDNMP环境" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 표준 모드 2. 고성능 모드(2H4G 이상 권장)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" - echo "3. gzip 압축 켜기 4. gzip 압축 끄기" - echo "5. br 압축을 켭니다. 6. br 압축을 끕니다." - echo "7. zstd 압축을 켭니다. 8. zstd 압축을 끕니다." + echo "3. 开启gzip压缩 4. 关闭gzip压缩" + echo "5. 开启br压缩 6. 关闭br压缩" + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "사이트 표준 모드" + send_stats "站点标准模式" local cpu_cores=$(nproc) local connections=$((1024 * ${cpu_cores})) @@ -2368,13 +2368,13 @@ web_optimization() { sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2386,7 +2386,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2397,25 +2397,25 @@ web_optimization() { optimize_balanced - echo "LDNMP 환경이 표준 모드로 설정되었습니다." + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "사이트 고성능 모드" + send_stats "站点高性能模式" - # nginx 튜닝 + # nginx调优 local cpu_cores=$(nproc) local connections=$((2048 * ${cpu_cores})) sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - # PHP 튜닝 + # php调优 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # PHP 튜닝 + # php调优 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2427,7 +2427,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # MySQL 튜닝 + # mysql调优 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2436,7 +2436,7 @@ web_optimization() { optimize_web_server - echo "LDNMP 환경이 고성능 모드로 설정되었습니다." + echo "LDNMP环境已设置成 高性能模式" ;; 3) @@ -2485,9 +2485,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}설치됨${gl_bai}" + check_docker="${gl_lv}已安装${gl_bai}" else - check_docker="${gl_hui}설치되지 않음${gl_bai}" + check_docker="${gl_hui}未安装${gl_bai}" fi } @@ -2496,9 +2496,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." +# check_docker="${gl_lv}已安装${gl_bai}" # else -# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}未安装${gl_bai}" # fi # } @@ -2506,7 +2506,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "방문 주소:" +echo "访问地址:" ip_address @@ -2538,11 +2538,11 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 지역점검 + # 1. 区域检查 local country=$(curl -s --max-time 2 ipinfo.io/country) [[ "$country" == "CN" ]] && return - # 2. 로컬 미러 정보 얻기 + # 2. 获取本地镜像信息 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return @@ -2550,22 +2550,22 @@ check_docker_image_update() { local full_image_name=$(echo "$container_info" | cut -d',' -f2) local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 지능형 라우팅 판단 + # 3. 智能路由判断 if [[ "$full_image_name" == ghcr.io* ]]; then - # --- 시나리오 A: GitHub(ghcr.io)의 미러링 --- - # 웨어하우스 경로를 추출합니다(예: ghcr.io/onexru/oneimg -> onexru/oneimg). + # --- 场景 A: 镜像在 GitHub (ghcr.io) --- + # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 참고: ghcr.io의 API는 비교적 복잡합니다. 일반적으로 가장 빠른 방법은 GitHub Repo 릴리스를 확인하는 것입니다. + # 注意:ghcr.io 的 API 比较复杂,通常最快的方法是查 GitHub Repo 的 Release local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 시나리오 B: 특별 지정(Docker Hub에서도 GitHub 릴리스로 판단하고 싶습니다) --- + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) else - # --- 시나리오 C: 표준 Docker 허브 --- + # --- 场景 C: 标准 Docker Hub --- local image_repo=${full_image_name%%:*} local image_tag=${full_image_name##*:} [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" @@ -2575,11 +2575,11 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) fi - # 4. 타임스탬프 비교 + # 4. 时间戳对比 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) if [[ $container_created_ts -lt $remote_ts ]]; then - update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" + update_status="${gl_huang}发现新版本!${gl_bai}" fi fi } @@ -2594,7 +2594,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소 가져오기 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2604,34 +2604,34 @@ block_container_port() { install iptables - # 다른 모든 IP를 확인하고 차단하세요. + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP 확인 및 해제 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8 확인 및 허용 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 다른 모든 IP를 확인하고 차단하세요. + # 检查并封禁其他所有 IP if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP 확인 및 해제 + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8 확인 및 허용 + # 检查并放行本地网络 127.0.0.0/8 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2641,7 +2641,7 @@ block_container_port() { fi - echo "IP+포트가 서비스 접근을 차단했습니다." + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2652,7 +2652,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 컨테이너의 IP 주소 가져오기 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2662,17 +2662,17 @@ clear_container_rules() { install iptables - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2681,17 +2681,17 @@ clear_container_rules() { - # 다른 모든 IP를 차단하는 명확한 규칙 + # 清除封禁其他所有 IP 的规则 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 清除放行指定 IP 的规则 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. + # 清除放行本地网络 127.0.0.0/8 的规则 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2702,7 +2702,7 @@ clear_container_rules() { fi - echo "IP+포트로 서비스 접속이 허용되었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2716,25 +2716,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." - echo "사용법: block_host_port <포트 번호> <허용 IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP의 접근을 거부 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 지정된 IP에 대한 접근을 허용 + # 允许指定 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스 허용 + # 允许本机访问 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2743,27 +2743,27 @@ block_host_port() { - # 다른 모든 IP의 접근을 거부 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 지정된 IP에 대한 접근을 허용 + # 允许指定 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 로컬 액세스 허용 + # 允许本机访问 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 확립된 관련 연결에 대한 트래픽 허용 + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "IP+포트가 서비스 접근을 차단했습니다." + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2775,47 +2775,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." - echo "사용법:clear_host_port_rules <포트 번호> <허용 IP>" + echo "错误:请提供端口号和允许访问的 IP。" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 로컬 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 로컬 액세스를 허용하는 명확한 규칙 + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 + # 清除允许指定 IP 访问的规则 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "IP+포트로 서비스 접속이 허용되었습니다" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2854,7 +2854,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}관리하다" +send_stats "${docker_name}管理" while true; do clear @@ -2874,25 +2874,25 @@ while true; do fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." - send_stats "애플리케이션 포트가 점유되어 있습니다." + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" else local docker_port=$app_port break @@ -2907,12 +2907,12 @@ while true; do add_app_id clear - echo "$docker_name설치 완료" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "설치하다$docker_name" + send_stats "安装$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2922,12 +2922,12 @@ while true; do add_app_id clear - echo "$docker_name설치 완료" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "고쳐 쓰다$docker_name" + send_stats "更新$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2936,30 +2936,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다." - send_stats "제거$docker_name" + echo "应用已卸载" + send_stats "卸载$docker_name" ;; 5) - echo "${docker_name}도메인 이름 액세스 설정" - send_stats "${docker_name}도메인 이름 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "https://가 없는 도메인 이름 형식 example.com" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 접근 차단${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2996,26 +2996,26 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" - echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." - send_stats "애플리케이션 포트가 점유되어 있습니다." + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" else local docker_port=$app_port break @@ -3028,13 +3028,13 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id - send_stats "$app_name설치하다" + send_stats "$app_name 安装" ;; 2) docker_app_update add_app_id - send_stats "$app_name고쳐 쓰다" + send_stats "$app_name 更新" ;; 3) @@ -3042,27 +3042,27 @@ docker_app_plus() { rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name제거" + send_stats "$app_name 卸载" ;; 5) - echo "${docker_name}도메인 이름 액세스 설정" - send_stats "${docker_name}도메인 이름 액세스 설정" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "https://가 없는 도메인 이름 형식 example.com" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용${docker_name}" + send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "IP 접근 차단${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -3147,17 +3147,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 세션이 존재하는지 확인하는 함수 +# 检查会话是否存在的函数 session_exists() { tmux has-session -t $1 2>/dev/null } -# 존재하지 않는 세션 이름을 찾을 때까지 반복 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 새 tmux 세션 만들기 +# 创建新的 tmux 会话 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3177,9 +3177,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}설치됨${gl_bai}" + check_f2b_status="${gl_lv}已安装${gl_bai}" else - check_f2b_status="${gl_hui}설치되지 않음${gl_bai}" + check_f2b_status="${gl_hui}未安装${gl_bai}" fi } @@ -3213,31 +3213,31 @@ f2b_sshd() { fi } -# 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) -# 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). -# - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) +# 说明: +# - 优先写入 /etc/fail2ban/jail.d/sshd.local(覆盖默认 jail 配置,升级不易丢) +# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 f2b_basic_config() { root_use install nano if ! command -v fail2ban-client >/dev/null 2>&1; then - echo -e "${gl_hui}FAIL2BAN-클라이언트가 감지되지 않습니다. 먼저 Fail2ban을 설치하십시오.${gl_bai}" + echo -e "${gl_hui}未检测到 fail2ban-client,请先安装 fail2ban。${gl_bai}" return fi local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # 알파인 기본 감옥은 일반적으로 sshd입니다. 사용자 정의 alpine-sshd 규칙이 감지된 경우에만 전환됩니다. + # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi fi - echo "SSH 감옥을 구성하려고 합니다:$jail_name" - read -e -p "금지 시간 금지 시간(초/분/시간, 예: 3600 또는 1h) [기본값 1h]:" bantime - read -e -p "시간 창 찾기 시간(초/분/시간, 예: 600 또는 10m) [기본값 10m]:" findtime - read -e -p "재시도 횟수 maxretry(정수) [기본값 5]:" maxretry + echo "即将配置 SSH jail:$jail_name" + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime + read -e -p "时间窗口 findtime (秒/分钟/小时,如 600 或 10m) [默认 10m]: " findtime + read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry bantime=${bantime:-1h} findtime=${findtime:-10m} @@ -3262,20 +3262,20 @@ EOF fi fi - echo -e "${gl_lv}구성이 작성되었습니다.${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + echo -e "${gl_lv}已写入配置${gl_bai}: /etc/fail2ban/jail.d/sshd.local" fail2ban-client reload >/dev/null 2>&1 || true sleep 2 fail2ban-client status $jail_name || true } -# 기본 구성/오버레이 구성 편집기(나노)를 직접 엽니다. -# /etc/fail2ban/jail.d/sshd.local을 먼저 편집하고(보다 안전함) 존재하지 않는 경우 생성합니다. +# 直接打开主配置/覆盖配置编辑(nano) +# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 f2b_edit_config() { root_use install nano if [ ! -d /etc/fail2ban ]; then - echo -e "${gl_hui}/etc/fail2ban이 존재하지 않습니다. 먼저 fall2ban을 설치하십시오.${gl_bai}" + echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" return fi @@ -3284,7 +3284,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}저장됨${gl_bai}, Fail2ban을 다시 로드하는 중..." + echo -e "${gl_lv}已保存${gl_bai},正在 reload fail2ban..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3295,11 +3295,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "다시 시작됨" + echo "已重启" reboot ;; *) - echo "취소" + echo "已取消" ;; esac @@ -3342,8 +3342,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "LDNMP 환경을 다시 설치할 수 없습니다" - echo -e "${gl_huang}힌트:${gl_bai}홈페이지 구축 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" + send_stats "无法再次安装LDNMP环境" + echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -3353,10 +3353,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "LDNMP 환경 설치" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP 환경이 설치되지 않았습니다. LDNMP 환경 설치를 시작합니다...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 /home install_dependency install_docker @@ -3369,10 +3369,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "nginx 환경 설치" +send_stats "安装nginx环境" root_use clear -echo -e "${gl_huang}nginx가 설치되지 않았습니다. nginx 환경 설치를 시작하세요...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" install_dependency install_docker install_certbot @@ -3381,8 +3381,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx가 설치되었습니다" -echo -e "현재 버전:${gl_huang}v$nginx_version${gl_bai}" +echo "nginx已安装完成" +echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3393,7 +3393,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "먼저 LDNMP 환경을 설치해 주세요" + send_stats "请先安装LDNMP环境" ldnmp_install_all fi @@ -3403,7 +3403,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "먼저 nginx 환경을 설치해주세요" + send_stats "请先安装nginx环境" nginx_install_all fi @@ -3414,10 +3414,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "您的 $webname 搭建好了!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname 安装信息如下: " } @@ -3427,7 +3427,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "您的 $webname 搭建好了!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3446,8 +3446,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3489,13 +3489,13 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="역방향 프록시-IP+포트" + webname="反向代理-IP+端口" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3503,12 +3503,12 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then - read -e -p "안티 세대 포트를 입력하십시오:" port + read -e -p "请输入你的反代端口: " port fi nginx_install_status @@ -3531,7 +3531,7 @@ ldnmp_Proxy() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3545,10 +3545,10 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="역방향 프록시-로드 밸런싱" + webname="反向代理-负载均衡" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3556,7 +3556,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "여러 개의 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3578,7 +3578,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3596,34 +3596,34 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "서비스 이름" "통신 유형" "현지 주소" "백엔드 주소" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return fi for conf in "$STREAM_DIR"/*; do - # 서비스 이름은 파일 이름을 사용합니다. + # 服务名取文件名 service_name=$(basename "$conf" .conf) - # 업스트림 블록에서 서버 백엔드 IP:포트 가져오기 + # 获取 upstream 块中的 server 后端 IP:端口 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) - # 청취 포트 가져오기 + # 获取 listen 端口 listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) - # 기본 로컬 IP + # 默认本地 IP ip_address local_ip="$ipv4_address" - # 먼저 파일 이름 접미사 또는 내용으로 판단하여 통신 유형을 가져옵니다. + # 获取通信类型,优先从文件名后缀或内容判断 if grep -qi 'udp;' "$conf"; then proto="udp" else proto="tcp" fi - # 스플라이스 청취 IP:포트 + # 拼接监听 IP:端口 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -3639,7 +3639,7 @@ list_stream_services() { stream_panel() { - send_stats "4계층 프록시 스트리밍" + send_stats "Stream四层代理" local app_id="104" local docker_name="nginx" @@ -3647,42 +3647,42 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "스트림 4계층 프록시 전달 도구$check_docker $update_status" - echo "NGINX 스트림은 고성능 전송 계층 트래픽 전달 및 로드 밸런싱을 달성하는 데 사용되는 NGINX의 TCP/UDP 프록시 모듈입니다." + echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模块,用于实现高性能的 传输层流量转发和负载均衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then list_stream_services fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. 포워딩 서비스 추가 5. 포워딩 서비스 수정 6. 포워딩 서비스 삭제" + echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) nginx_install_status add_app_id - send_stats "Stream 4계층 에이전트 설치" + send_stats "安装Stream四层代理" ;; 2) update_docker_compose_with_db_creds nginx_upgrade add_app_id - send_stats "Stream 4계층 프록시 업데이트" + send_stats "更新Stream四层代理" ;; 3) - read -e -p "nginx 컨테이너를 삭제하시겠습니까? 이는 웹사이트 기능에 영향을 미칠 수 있습니다! (예/아니요):" confirm + read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "Stream 4계층 프록시 업데이트" - echo "nginx 컨테이너가 삭제되었습니다." + send_stats "更新Stream四层代理" + echo "nginx 容器已删除。" else - echo "작업이 취소되었습니다." + echo "操作已取消。" fi ;; @@ -3690,22 +3690,22 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "레이어 4 프록시 추가" + send_stats "添加四层代理" ;; 5) - send_stats "전달 구성 수정" - read -e -p "편집하려는 서비스 이름을 입력하십시오:" stream_name + send_stats "编辑转发配置" + read -e -p "请输入你要编辑的服务名: " stream_name install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "레이어 4 프록시 수정" + send_stats "修改四层代理" ;; 6) - send_stats "전달 구성 삭제" - read -e -p "삭제하려는 서비스 이름을 입력하세요." stream_name + send_stats "删除转发配置" + read -e -p "请输入你要删除的服务名: " stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx - send_stats "레이어 4 프록시 삭제" + send_stats "删除四层代理" ;; *) break @@ -3719,34 +3719,34 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="Stream四层代理-负载均衡" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" - # 에이전트 이름 가져오기 - read -erp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name + # 获取代理名称 + read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name if [ -z "$proxy_name" ]; then - echo "이름은 비워둘 수 없습니다."; return 1 + echo "名称不能为空"; return 1 fi - # 수신 포트 가져오기 - read -erp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port + # 获取监听端口 + read -erp "请输入本机监听端口 (如 3306): " listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then - echo "포트는 숫자여야 합니다."; return 1 + echo "端口必须是数字"; return 1 fi - echo "계약 유형을 선택하십시오:" + echo "请选择协议类型:" echo "1. TCP 2. UDP" - read -erp "일련 번호 [1-2]를 입력하십시오:" proto_choice + read -erp "请输入序号 [1-2]: " proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; 2) proto="udp"; listen_suffix=" udp" ;; - *) echo "잘못된 선택"; return 1 ;; + *) echo "无效选择"; return 1 ;; esac - read -e -p "하나 이상의 백엔드 IP+포트를 공백으로 구분하여 입력하세요(예: 10.13.0.2:3306 10.13.0.3:3306)." reverseproxy_port + read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3763,13 +3763,13 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "您的 $webname 搭建好了!" echo "------------------------" - echo "방문 주소:" + echo "访问地址:" ip_address if [ -n "$ipv4_address" ]; then echo "$ipv4_address:${listen_port}" @@ -3808,12 +3808,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP 사이트 관리" - echo "LDNMP 환경" + send_stats "LDNMP站点管理" + echo "LDNMP环境" echo "------------------------" ldnmp_v - echo -e "대지:${output}인증서 만료 시간" + echo -e "站点: ${output} 证书到期时间" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3845,35 +3845,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "데이터 베이스:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "사이트 디렉토리" + echo "站点目录" echo "------------------------" - echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 도메인 이름 인증서 적용/업데이트 2. 사이트 도메인 이름 복제" - echo "3. 사이트 캐시 지우기 4. 관련 사이트 생성" - echo "5. 접속 로그 보기 6. 오류 로그 보기" - echo "7. 전역 구성 편집 8. 사이트 구성 편집" - echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서 보기" + echo "1. 申请/更新域名证书 2. 克隆站点域名" + echo "3. 清理站点缓存 4. 创建关联站点" + echo "5. 查看访问日志 6. 查看错误日志" + echo "7. 编辑全局配置 8. 编辑站点配置" + echo "9. 管理站点数据库 10. 查看站点分析报告" echo "------------------------" - echo "20. 특정 사이트 데이터 삭제" + echo "20. 删除指定站点数据" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "도메인 이름 인증서 신청" - read -e -p "도메인 이름을 입력하세요:" yuming + send_stats "申请域名证书" + read -e -p "请输入你的域名: " yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3882,9 +3882,9 @@ ldnmp_web_status() { ;; 2) - send_stats "복제 사이트 도메인 이름" - read -e -p "이전 도메인 이름을 입력하세요:" oddyuming - read -e -p "새 도메인 이름을 입력하세요:" yuming + send_stats "克隆站点域名" + read -e -p "请输入旧域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3904,7 +3904,7 @@ ldnmp_web_status() { done done - # 웹사이트 디렉토리 교체 + # 网站目录替换 cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3922,10 +3922,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "연결된 사이트 만들기" - echo -e "액세스하려면 새 도메인 이름을 기존 사이트에 연결하세요." - read -e -p "기존 도메인 이름을 입력하세요:" oddyuming - read -e -p "새 도메인 이름을 입력하세요:" yuming + send_stats "创建关联站点" + echo -e "为现有的站点再关联一个新域名用于访问" + read -e -p "请输入现有的域名: " oddyuming + read -e -p "请输入新域名: " yuming install_certbot install_ssltls certs_status @@ -3939,25 +3939,25 @@ ldnmp_web_status() { ;; 5) - send_stats "접속 로그 보기" + send_stats "查看访问日志" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "오류 로그 보기" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "전역 구성 편집" + send_stats "编辑全局配置" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "사이트 구성 편집" - read -e -p "사이트 구성을 편집하려면 편집하려는 도메인 이름을 입력하십시오:" yuming + send_stats "编辑站点配置" + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3967,7 +3967,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "사이트 데이터 보기" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3989,7 +3989,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}설치됨${gl_bai}" + check_panel="${gl_lv}已安装${gl_bai}" else check_panel="" fi @@ -3998,21 +3998,21 @@ fi install_panel() { -send_stats "${panelname}관리하다" +send_stats "${panelname}管理" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}대중적이고 강력한 운영 및 유지 관리 관리 패널입니다." - echo "공식 웹사이트 소개:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. 설치 2. 관리 3. 제거" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) check_disk_space 1 @@ -4021,20 +4021,20 @@ while true; do panel_app_install add_app_id - send_stats "${panelname}설치하다" + send_stats "${panelname}安装" ;; 2) panel_app_manage add_app_id - send_stats "${panelname}제어" + send_stats "${panelname}控制" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}제거" + send_stats "${panelname}卸载" ;; *) break @@ -4050,9 +4050,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}설치됨${gl_bai}" + check_frp="${gl_lv}已安装${gl_bai}" else - check_frp="${gl_hui}설치되지 않음${gl_bai}" + check_frp="${gl_hui}未安装${gl_bai}" fi } @@ -4078,8 +4078,8 @@ donlond_frp() { generate_frps_config() { - send_stats "FRP 서버 설치" - # 임의의 포트 및 자격 증명 생성 + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -4100,17 +4100,17 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 输出生成的信息 ip_address echo "------------------------" - echo "클라이언트 배포에 필요한 매개변수" - echo "서비스 IP:$ipv4_address" + echo "客户端部署时需要用的参数" + echo "服务IP: $ipv4_address" echo "token: $token" echo - echo "FRP 패널 정보" - echo "FRP 패널 주소: http://$ipv4_address:$dashboard_port" - echo "FRP 패널 사용자 이름:$dashboard_user" - echo "FRP 패널 비밀번호:$dashboard_pwd" + echo "FRP面板信息" + echo "FRP面板地址: http://$ipv4_address:$dashboard_port" + echo "FRP面板用户名: $dashboard_user" + echo "FRP面板密码: $dashboard_pwd" echo open_port 8055 8056 @@ -4120,9 +4120,9 @@ EOF configure_frpc() { - send_stats "FRP 클라이언트 설치" - read -e -p "외부 네트워크 도킹 IP를 입력하세요." server_addr - read -e -p "외부 네트워크 도킹 토큰을 입력하세요." token + send_stats "安装frp客户端" + read -e -p "请输入外网对接IP: " server_addr + read -e -p "请输入外网对接token: " token echo mkdir -p /home/frp @@ -4142,17 +4142,17 @@ EOF } add_forwarding_service() { - send_stats "FRP 인트라넷 서비스 추가" - # 사용자에게 서비스 이름 및 전달 정보를 묻는 메시지를 표시합니다. - read -e -p "서비스 이름을 입력하세요:" service_name - read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type + send_stats "添加frp内网服务" + # 提示用户输入服务名称和转发信息 + read -e -p "请输入服务名称: " service_name + read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip + read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "인트라넷 포트를 입력하십시오:" local_port - read -e -p "외부 네트워크 포트를 입력하세요:" remote_port + read -e -p "请输入内网端口: " local_port + read -e -p "请输入外网端口: " remote_port - # 구성 파일에 사용자 입력 쓰기 + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -4162,8 +4162,8 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 - echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." + # 输出生成的信息 + echo "服务 $service_name 已成功添加到 frpc.toml" docker restart frpc @@ -4174,12 +4174,12 @@ EOF delete_forwarding_service() { - send_stats "FRP 인트라넷 서비스 삭제" - # 삭제해야 하는 서비스 이름을 입력하라는 메시지를 사용자에게 표시합니다. - read -e -p "삭제할 서비스 이름을 입력하세요:" service_name - # sed를 사용하여 서비스 및 관련 구성 삭제 + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "제공하다$service_namefrpc.toml에서 성공적으로 제거되었습니다." + echo "服务 $service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -4189,8 +4189,8 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 헤더 인쇄 - printf "%-20s %-25s %-30s %-10s\n" "서비스 이름" "인트라넷 주소" "외부 네트워크 주소" "규약" + # 打印表头 + printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" awk ' BEGIN { @@ -4210,7 +4210,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 서비스 정보가 이미 존재하는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4219,11 +4219,11 @@ list_forwarding_services() { type } - # 현재 서비스 이름 업데이트 + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 이전 값 지우기 + # 清除之前的值 local_ip="" local_port="" remote_port="" @@ -4252,7 +4252,7 @@ list_forwarding_services() { } END { - # 마지막 서비스에 대한 정보 인쇄 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4265,17 +4265,17 @@ list_forwarding_services() { -# FRP 서버 포트 가져오기 +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 액세스 주소 생성 +# 生成访问地址 generate_access_urls() { - # 먼저 모든 포트를 확보하십시오. + # 首先获取所有端口 get_frp_ports - # 8055/8056 이외의 포트가 있는지 확인하세요. + # 检查是否有非 8055/8056 的端口 local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4284,18 +4284,18 @@ generate_access_urls() { fi done - # 유효한 포트가 있는 경우에만 제목과 내용 표시 + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then - echo "FRP 서비스 외부 액세스 주소:" + echo "FRP服务对外访问地址:" - # IPv4 주소 처리 + # 处理 IPv4 地址 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # IPv6 주소가 있는 경우 처리 + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4304,7 +4304,7 @@ generate_access_urls() { done fi - # HTTPS 구성 처리 + # 处理 HTTPS 配置 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4331,7 +4331,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP 서버" + send_stats "FRP服务端" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -4339,25 +4339,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 서버$check_frp $update_status" - echo "FRP 인트라넷 침투 서비스 환경을 구축하고 공인 IP가 없는 장치를 인터넷에 노출시킵니다." - echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" - echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP服务端 $check_frp $update_status" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "5. 인트라넷 서비스 도메인 이름 접근 6. 도메인 이름 접근 삭제" + echo "5. 内网服务域名访问 6. 删除域名访问" echo "------------------------" - echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" - echo "00. 서비스 상태 새로고침 0. 이전 메뉴로 돌아가기" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -4365,7 +4365,7 @@ frps_panel() { generate_frps_config add_app_id - echo "FRP 서버가 설치되었습니다" + echo "FRP服务端已经安装完成" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -4375,7 +4375,7 @@ frps_panel() { donlond_frp frps add_app_id - echo "FRP 서버가 업데이트되었습니다" + echo "FRP服务端已经更新完成" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -4386,37 +4386,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다." + echo "应用已卸载" ;; 5) - echo "도메인 이름 액세스에 대한 역인트라넷 침투 서비스" - send_stats "FRP 외부 도메인 이름 액세스" + echo "将内网穿透服务反代成域名访问" + send_stats "FRP对外域名访问" add_yuming - read -e -p "인트라넷 침투 서비스 포트를 입력하십시오:" frps_port + read -e -p "请输入你的内网穿透服务端口: " frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "https://가 없는 도메인 이름 형식 example.com" + echo "域名格式 example.com 不带https://" web_del ;; 7) - send_stats "IP 액세스 허용" - read -e -p "해제해야 하는 포트를 입력하세요." frps_port + send_stats "允许IP访问" + read -e -p "请输入需要放行的端口: " frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." - read -e -p "차단할 포트를 입력하세요:" frps_port + send_stats "阻止IP访问" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + read -e -p "请输入需要阻止的端口: " frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "FRP 서비스 상태 새로 고침" - echo "FRP 서비스 상태가 새로 고쳐졌습니다." + send_stats "刷新FRP服务状态" + echo "已经刷新FRP服务状态" ;; *) @@ -4429,7 +4429,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP 클라이언트" + send_stats "FRP客户端" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -4437,10 +4437,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." - echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" - echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP客户端 $check_frp $update_status" + echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" + echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -4448,13 +4448,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 수동 구성" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) install jq grep ss @@ -4462,7 +4462,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP 클라이언트가 설치되었습니다" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4472,7 +4472,7 @@ frpc_panel() { donlond_frp frpc add_app_id - echo "FRP 클라이언트가 업데이트되었습니다." + echo "FRP客户端已经更新完成" ;; 3) @@ -4483,7 +4483,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다." + echo "应用已卸载" ;; 4) @@ -4523,74 +4523,74 @@ yt_menu_pro() { while true; do if [ -x "/usr/local/bin/yt-dlp" ]; then - local YTDLP_STATUS="${gl_lv}설치됨${gl_bai}" + local YTDLP_STATUS="${gl_lv}已安装${gl_bai}" else - local YTDLP_STATUS="${gl_hui}설치되지 않음${gl_bai}" + local YTDLP_STATUS="${gl_hui}未安装${gl_bai}" fi clear - send_stats "yt-dlp 다운로드 도구" + send_stats "yt-dlp 下载工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp는 YouTube, Bilibili, Twitter 등과 같은 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." - echo -e "공식 웹사이트 주소:${gh_https_url}github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "官网地址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "다운로드한 동영상 목록:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" + echo "已下载视频列表:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. 단일 비디오 다운로드 6. 일괄 비디오 다운로드 7. 사용자 정의 매개변수 다운로드" - echo "8. MP3 오디오로 다운로드 9. 비디오 디렉터리 삭제 10. 쿠키 관리(개발 중)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "-------------------------" - read -e -p "옵션 번호를 입력하세요:" choice + read -e -p "请输入选项编号: " choice case $choice in 1) - send_stats "yt-dlp 설치 중..." - echo "yt-dlp 설치 중..." + send_stats "正在安装 yt-dlp..." + echo "正在安装 yt-dlp..." install ffmpeg curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id - echo "설치가 완료되었습니다. 계속하려면 아무 키나 누르세요..." + echo "安装完成。按任意键继续..." read ;; 2) - send_stats "yt-dlp 업데이트 중..." - echo "yt-dlp 업데이트 중..." + send_stats "正在更新 yt-dlp..." + echo "正在更新 yt-dlp..." yt-dlp -U add_app_id - echo "업데이트가 완료되었습니다. 계속하려면 아무 키나 누르세요..." + echo "更新完成。按任意键继续..." read ;; 3) - send_stats "yt-dlp 제거 중..." - echo "yt-dlp 제거 중..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "제거가 완료되었습니다. 계속하려면 아무 키나 누르세요..." + echo "卸载完成。按任意键继续..." read ;; 5) - send_stats "단일 비디오 다운로드" - read -e -p "동영상 링크를 입력하세요:" url + send_stats "单个视频下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "일괄 비디오 다운로드" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 여러 개의 동영상 링크 주소를 입력하세요\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "지금 일괄 다운로드를 시작하세요..." + echo "现在开始批量下载..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4598,31 +4598,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "일괄 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; + read -e -p "批量下载完成,按任意键继续..." ;; 7) - send_stats "맞춤형 비디오 다운로드" - read -e -p "전체 yt-dlp 매개변수를 입력하세요(yt-dlp 제외)." custom + send_stats "自定义视频下载" + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "실행이 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; + read -e -p "执行完成,按任意键继续..." ;; 8) - send_stats "MP3 다운로드" - read -e -p "동영상 링크를 입력하세요:" url + send_stats "MP3下载" + read -e -p "请输入视频链接: " url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "오디오 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) - send_stats "동영상 삭제" - read -e -p "삭제된 동영상의 이름을 입력하세요:" rmdir + send_stats "删除视频" + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4658,7 +4658,7 @@ set_timedate() { -# dpkg 중단 문제 수정 +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4667,7 +4667,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_kjlan}시스템 업데이트 진행 중...${gl_bai}" + echo -e "${gl_kjlan}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4686,7 +4686,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "알 수 없는 패키지 관리자입니다!" + echo "未知的包管理器!" return fi } @@ -4694,7 +4694,7 @@ linux_update() { linux_clean() { - echo -e "${gl_kjlan}시스템 청소 진행 중...${gl_bai}" + echo -e "${gl_kjlan}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4723,13 +4723,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "패키지 관리자 캐시 정리..." + echo "清理包管理器缓存..." apk cache clean - echo "시스템 로그 삭제..." + echo "删除系统日志..." rm -rf /var/log/* - echo "APK 캐시 삭제..." + echo "删除APK缓存..." rm -rf /var/cache/apk/* - echo "임시 파일 삭제..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4747,23 +4747,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "시스템 로그 삭제..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "사용하지 않는 종속성을 정리합니다..." + echo "清理未使用的依赖..." pkg autoremove -y - echo "패키지 관리자 캐시 정리..." + echo "清理包管理器缓存..." pkg clean -y - echo "시스템 로그 삭제..." + echo "删除系统日志..." rm -rf /var/log/* - echo "임시 파일 삭제..." + echo "删除临时文件..." rm -rf /tmp/* else - echo "알 수 없는 패키지 관리자입니다!" + echo "未知的包管理器!" return fi return @@ -4773,13 +4773,13 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 统一写入到 sysctl.d 以防与内核调优模块打架 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 충돌을 일으킬 수 있는 이전 sysctl.conf의 남은 부분을 정리합니다. +# 清理可能导致冲突的旧版 sysctl.conf 残留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4817,26 +4817,26 @@ chattr +i /etc/resolv.conf set_dns_ui() { root_use -send_stats "DNS 최적화" +send_stats "优化DNS" while true; do clear - echo "DNS 주소 최적화" + echo "优化DNS地址" echo "------------------------" - echo "현재 DNS 주소" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 외국 DNS 최적화:" + echo "1. 国外DNS优化: " echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 국내 DNS 최적화:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 구성을 수동으로 편집" + echo "3. 手动编辑DNS配置" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4844,7 +4844,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "외국 DNS 최적화" + send_stats "国外DNS优化" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4852,14 +4852,14 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "국내 DNS 최적화" + send_stats "国内DNS优化" ;; 3) install nano chattr -i /etc/resolv.conf nano /etc/resolv.conf chattr +i /etc/resolv.conf - send_stats "DNS 구성을 수동으로 편집" + send_stats "手动编辑DNS配置" ;; *) break @@ -4913,7 +4913,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 포트가 다음과 같이 수정되었습니다.$new_port" + echo "SSH 端口已修改为: $new_port" sleep 1 @@ -4929,7 +4929,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}사용자 키 로그인 모드가 켜져 있고 비밀번호 로그인 모드가 꺼졌습니다. 다시 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" } @@ -4947,7 +4947,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "개인키 정보가 생성되었습니다. 꼭 복사해서 저장하세요. 다음과 같이 저장될 수 있습니다.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인을 위한 파일" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -4968,21 +4968,21 @@ import_sshkey() { local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then - read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key fi if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}오류: 공개 키 내용이 입력되지 않았습니다.${gl_bai}" + echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" return 1 fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" return 1 fi if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then - echo "공개 키가 이미 존재하므로 다시 추가할 필요가 없습니다." + echo "该公钥已存在,无需重复添加" return 0 fi @@ -5006,40 +5006,40 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - read -e -p "원격 공개 키 URL을 입력하세요:" keys_url + read -e -p "请输入您的远端公钥URL: " keys_url fi - echo "이 스크립트는 원격 URL에서 SSH 공개 키를 가져와서${authorized_keys}" + echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" echo "" - echo "원격 공개 키 주소:" + echo "远程公钥地址:" echo " ${keys_url}" echo "" - # 임시 파일 만들기 + # 创建临时文件 temp_file=$(mktemp) - # 공개 키 다운로드 + # 下载公钥 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } else - echo "오류: 시스템에서 컬 또는 wget을 찾을 수 없어 공개 키를 다운로드할 수 없습니다." >&2 + echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 rm -f "${temp_file}" return 1 fi - # 콘텐츠가 유효한지 확인하세요. + # 检查内容是否有效 if [[ ! -s "${temp_file}" ]]; then - echo "오류: 다운로드한 파일이 비어 있으며 URL에 공개 키가 포함되어 있지 않을 수 있습니다." >&2 + echo "错误:下载到的文件为空,URL 可能不包含任何公钥" >&2 rm -f "${temp_file}" return 1 fi @@ -5049,13 +5049,13 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 원본 인증_키 백업 + # 备份原有 authorized_keys if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원본 Authorized_keys 파일이 백업되었습니다." + echo "已备份原有 authorized_keys 文件" fi - # 공개 키 추가(중복 방지) + # 追加公钥(避免重复) local added=0 while IFS= read -r line; do [[ -z "${line}" || "${line}" =~ ^# ]] && continue @@ -5070,10 +5070,10 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then - echo "성공적으로 추가되었습니다${added}새로운 공개 키가 도착합니다${authorized_keys}" + echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" sshkey_on else - echo "새로운 공개 키를 추가할 필요가 없습니다(모두 이미 존재할 수도 있음)." + echo "没有新的公钥需要添加(可能已全部存在)" fi echo "" @@ -5087,24 +5087,24 @@ fetch_github_ssh_keys() { local username="$1" local base_dir="${2:-$HOME}" - echo "계속하기 전에 SSH 공개 키를 GitHub 계정에 추가했는지 확인하세요." - echo "1. 로그인${gh_https_url}github.com/settings/keys" - echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." - echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" - echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." - echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" + echo " 1. 登录 ${gh_https_url}github.com/settings/keys" + echo " 2. 点击 New SSH key 或 Add SSH key" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo " 5. 点击 Add SSH key 完成添加" echo "" - echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." - echo " ${gh_https_url}github.com/yourusername.keys" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " ${gh_https_url}github.com/您的用户名.keys" echo "" if [[ -z "${username}" ]]; then - read -e -p "GitHub 사용자 이름(@ 없는 사용자 이름)을 입력하세요." username + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username fi if [[ -z "${username}" ]]; then - echo "오류: GitHub 사용자 이름은 비워둘 수 없습니다." >&2 + echo "错误:GitHub 用户名不能为空" >&2 return 1 fi @@ -5117,64 +5117,64 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "사용자 키 로그인" + send_stats "用户密钥登录" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') if [[ "$REAL_STATUS" =~ "yes" ]]; then - IS_KEY_ENABLED="${gl_lv}활성화됨${gl_bai}" + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" else - IS_KEY_ENABLED="${gl_hui}활성화되지 않음${gl_bai}" + IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" fi - echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" - echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" + echo -e "用户密钥登录模式 ${IS_KEY_ENABLED}" + echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" - echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" - echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." - echo "5. 공개 키 파일 편집 6. 로컬 키 보기" + echo "1. 生成新密钥对 2. 手动输入已有公钥" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "5. 编辑公钥文件 6. 查看本机密钥" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - send_stats "새 키 생성" + send_stats "生成新密钥" add_sshkey break_end ;; 2) - send_stats "기존 공개 키 가져오기" + send_stats "导入已有公钥" import_sshkey break_end ;; 3) - send_stats "GitHub 원격 공개 키 가져오기" + send_stats "导入GitHub远端公钥" fetch_github_ssh_keys break_end ;; 4) - send_stats "URL 원격 공개 키 가져오기" - read -e -p "원격 공개 키 URL을 입력하세요:" keys_url + send_stats "导入URL远端公钥" + read -e -p "请输入您的远端公钥URL: " keys_url fetch_remote_ssh_keys "${keys_url}" break_end ;; 5) - send_stats "공개 키 파일 편집" + send_stats "编辑公钥文件" install nano nano ${HOME}/.ssh/authorized_keys break_end ;; 6) - send_stats "로컬 키 보기" + send_stats "查看本机密钥" echo "------------------------" - echo "공개키 정보" + echo "公钥信息" cat ${HOME}/.ssh/authorized_keys echo "------------------------" - echo "개인 키 정보" + echo "私钥信息" cat ${HOME}/.ssh/sshkey echo "------------------------" break_end @@ -5196,22 +5196,22 @@ sshkey_panel() { add_sshpasswd() { root_use - send_stats "비밀번호 로그인 모드 설정" - echo "비밀번호 로그인 모드 설정" + send_stats "设置密码登录模式" + echo "设置密码登录模式" local target_user="$1" - # 매개변수가 전달되지 않으면 대화형으로 입력하세요. + # 如果没有通过参数传入,则交互输入 if [[ -z "$target_user" ]]; then - read -e -p "비밀번호를 변경하려는 사용자 이름을 입력하십시오(기본 루트):" target_user + read -e -p "请输入要修改密码的用户名(默认 root): " target_user fi - # Enter를 누르고 입력하지 마십시오. 기본값은 root입니다. + # 回车不输入,默认 root target_user=${target_user:-root} - # 사용자가 존재하는지 확인 + # 校验用户是否存在 if ! id "$target_user" >/dev/null 2>&1; then - echo "오류: 사용자$target_user존재하지 않는다" + echo "错误:用户 $target_user 不存在" return 1 fi @@ -5226,7 +5226,7 @@ add_sshpasswd() { restart_ssh - echo -e "${gl_lv}비밀번호가 설정되어 비밀번호 로그인 모드로 변경되었습니다!${gl_bai}" + echo -e "${gl_lv}密码设置完毕,已更改为密码登录模式!${gl_bai}" } @@ -5244,7 +5244,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능을 실행하려면 루트 사용자가 필요합니다!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion } @@ -5259,7 +5259,7 @@ clear dd_xitong() { - send_stats "시스템 재설치" + send_stats "重装系统" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -5270,44 +5270,44 @@ dd_xitong() { } dd_xitong_1() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트:${gl_huang}22${gl_bai}" - echo -e "${gl_huang}재설치 후에는 초기 비밀번호를 적시에 변경하여 폭력적인 침입을 방지하시기 바랍니다. 비밀번호를 변경하려면 명령줄에 passwd를 입력하세요.${gl_bai}" - echo -e "계속하려면 아무 키나 누르세요..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令行输入passwd修改密码${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" - echo -e "계속하려면 아무 키나 누르세요..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}22${gl_bai}" - echo -e "계속하려면 아무 키나 누르세요..." + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" - echo -e "계속하려면 아무 키나 누르세요..." + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" + echo -e "按任意键继续..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "시스템 재설치" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." - echo -e "${gl_hui}스크립트 지원을 해주신 bin456789 보스와 leitbogioro 보스에게 감사드립니다!${gl_bai} " - echo -e "${gl_hui}bin456789 프로젝트 주소:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro 프로젝트 주소:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " + echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: ${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5323,21 +5323,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos Feiniu 공개 베타 버전" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "다시 설치하려는 시스템을 선택하십시오:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "데비안 13 재설치" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -5345,49 +5345,49 @@ dd_xitong() { ;; 2) - send_stats "데비안 12 다시 설치" + send_stats "重装debian 12" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "데비안 11 다시 설치" + send_stats "重装debian 11" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "데비안 10 다시 설치" + send_stats "重装debian 10" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "우분투 24.04 다시 설치" + send_stats "重装ubuntu 24.04" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "우분투 22.04 다시 설치" + send_stats "重装ubuntu 22.04" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "우분투 20.04 다시 설치" + send_stats "重装ubuntu 20.04" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "우분투 18.04 다시 설치" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -5396,7 +5396,7 @@ dd_xitong() { 21) - send_stats "rockylinux10 재설치" + send_stats "重装rockylinux10" dd_xitong_3 bash reinstall.sh rocky reboot @@ -5404,7 +5404,7 @@ dd_xitong() { ;; 22) - send_stats "rockylinux9 재설치" + send_stats "重装rockylinux9" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -5412,7 +5412,7 @@ dd_xitong() { ;; 23) - send_stats "alma10 재설치" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5420,7 +5420,7 @@ dd_xitong() { ;; 24) - send_stats "alma9 재설치" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -5428,7 +5428,7 @@ dd_xitong() { ;; 25) - send_stats "oracle10 재설치" + send_stats "重装oracle10" dd_xitong_3 bash reinstall.sh oracle reboot @@ -5436,7 +5436,7 @@ dd_xitong() { ;; 26) - send_stats "oracle9 재설치" + send_stats "重装oracle9" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -5444,7 +5444,7 @@ dd_xitong() { ;; 27) - send_stats "fedora42 재설치" + send_stats "重装fedora42" dd_xitong_3 bash reinstall.sh fedora reboot @@ -5452,7 +5452,7 @@ dd_xitong() { ;; 28) - send_stats "fedora41 재설치" + send_stats "重装fedora41" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -5460,7 +5460,7 @@ dd_xitong() { ;; 29) - send_stats "centos10 재설치" + send_stats "重装centos10" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -5468,7 +5468,7 @@ dd_xitong() { ;; 30) - send_stats "centos9 재설치" + send_stats "重装centos9" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5476,7 +5476,7 @@ dd_xitong() { ;; 31) - send_stats "알파인 재설치" + send_stats "重装alpine" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -5484,7 +5484,7 @@ dd_xitong() { ;; 32) - send_stats "아치 재설치" + send_stats "重装arch" dd_xitong_3 bash reinstall.sh arch reboot @@ -5492,7 +5492,7 @@ dd_xitong() { ;; 33) - send_stats "칼리 재설치" + send_stats "重装kali" dd_xitong_3 bash reinstall.sh kali reboot @@ -5500,7 +5500,7 @@ dd_xitong() { ;; 34) - send_stats "openeuler 다시 설치" + send_stats "重装openeuler" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -5508,7 +5508,7 @@ dd_xitong() { ;; 35) - send_stats "Openuse 다시 설치" + send_stats "重装opensuse" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -5516,7 +5516,7 @@ dd_xitong() { ;; 36) - send_stats "Feiniu 재설치" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -5524,7 +5524,7 @@ dd_xitong() { ;; 41) - send_stats "윈도우 11 재설치" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5533,14 +5533,14 @@ dd_xitong() { 42) dd_xitong_2 - send_stats "윈도우 10 재설치" + send_stats "重装windows10" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "Windows7을 다시 설치하세요." + send_stats "重装windows7" dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -5548,7 +5548,7 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 25를 다시 설치하세요." + send_stats "重装windows server 25" dd_xitong_2 bash InstallNET.sh -windows 2025 -lang "cn" reboot @@ -5556,7 +5556,7 @@ dd_xitong() { ;; 45) - send_stats "윈도우 서버 22 재설치" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -5564,7 +5564,7 @@ dd_xitong() { ;; 46) - send_stats "윈도우 서버 19 재설치" + send_stats "重装windows server 19" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot @@ -5572,7 +5572,7 @@ dd_xitong() { ;; 47) - send_stats "windows11 ARM 재설치" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -5589,7 +5589,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3 관리" + send_stats "bbrv3管理" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -5602,17 +5602,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "xanmod의 BBRv3 커널이 설치되어 있습니다." - echo "현재 커널 버전:$kernel_version" + echo "您已安装xanmod的BBRv3内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. BBRv3 커널 업데이트 2. BBRv3 커널 제거" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) @@ -5622,7 +5622,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3단계: 저장소 추가 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5631,7 +5631,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" + echo "XanMod内核已更新。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5641,7 +5641,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod内核已卸载。重启后生效" server_reboot ;; @@ -5654,13 +5654,13 @@ bbrv3() { else clear - echo "BBR3 가속 설정" - echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "设置BBR3加速" + echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "仅支持Debian/Ubuntu" + echo "请备份数据,将为你升级Linux内核开启BBR3" echo "------------------------------------------------" - read -e -p "계속하시겠습니까? (예/아니요):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -5668,12 +5668,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi else - echo "운영 체제 유형을 확인할 수 없습니다." + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -5684,7 +5684,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 3단계: 저장소 추가 + # 步骤3:添加存储库 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5695,17 +5695,17 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" + echo "XanMod内核安装并BBR3启用成功。重启后生效" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5714,40 +5714,40 @@ bbrv3() { elrepo_install() { - # ELRepo GPG 공개 키 가져오기 - echo "ELRepo GPG 공개 키 가져오기..." + # 导入 ELRepo GPG 公钥 + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 시스템 버전 확인 + # 检测系统版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 지원되는 운영 체제에서 실행되고 있는지 확인하세요. + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "지원되지 않는 운영 체제:$os_name" + echo "不支持的操作系统:$os_name" break_end linux_Settings fi - # 감지된 운영 체제 정보 인쇄 - echo "감지된 운영 체제:$os_name $os_version" - # 시스템 버전에 따라 해당 ELRepo 창고 구성을 설치하십시오. + # 打印检测到的操作系统信息 + echo "检测到的操作系统: $os_name $os_version" + # 根据系统版本安装对应的 ELRepo 仓库配置 if [[ "$os_version" == 8 ]]; then - echo "ELRepo 저장소 구성(버전 8) 설치 중..." + echo "安装 ELRepo 仓库配置 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "ELRepo 저장소 구성(버전 9) 설치 중..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "ELRepo 저장소 구성(버전 10) 설치 중..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "지원되지 않는 시스템 버전:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi - # ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치합니다. - echo "ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치하세요..." + # 启用 ELRepo 内核仓库并安装最新的主线内核 + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "ELRepo 저장소 구성을 설치하고 최신 메인라인 커널로 업데이트했습니다." + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5755,37 +5755,37 @@ elrepo_install() { elrepo() { root_use - send_stats "Red Hat 커널 관리" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "elrepo 커널을 설치했습니다" - echo "현재 커널 버전:$kernel_version" + echo "您已安装elrepo内核" + echo "当前内核版本: $kernel_version" echo "" - echo "커널 관리" + echo "内核管理" echo "------------------------" - echo "1. elrepo 커널 업데이트 2. elrepo 커널 제거" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "Red Hat 커널 업데이트" + send_stats "更新红帽内核" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" - send_stats "Red Hat 커널 제거" + echo "elrepo内核已卸载。重启后生效" + send_stats "卸载红帽内核" server_reboot ;; @@ -5798,26 +5798,26 @@ elrepo() { else clear - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드해 드리겠습니다." - echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "请备份数据,将为你升级Linux内核" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" - read -e -p "계속하시겠습니까? (예/아니요):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "Red Hat 커널 업그레이드" + send_stats "升级红帽内核" server_reboot ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -5828,7 +5828,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_kjlan}바이러스 데이터베이스 업데이트 중...${gl_bai}" + echo -e "${gl_kjlan}正在更新病毒库...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5838,19 +5838,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "请指定要扫描的目录。" return fi - echo -e "${gl_kjlan}$@ 디렉터리를 검색하는 중...${gl_bai}" + echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" - # 마운트 매개변수 빌드 + # 构建 mount 参数 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan 명령 매개변수 빌드 + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5859,7 +5859,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 도커 명령 실행 + # 执行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5869,7 +5869,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}바이러스 있으면 제발${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5881,23 +5881,23 @@ clamav_scan() { clamav() { root_use - send_stats "바이러스 검사 관리" + send_stats "病毒扫描管理" while true; do clear - echo "clamav 바이러스 검사 도구" - echo "영상 소개: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "다양한 유형의 악성 코드를 탐지하고 제거하는 데 주로 사용되는 오픈 소스 바이러스 백신 소프트웨어 도구입니다." - echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어가 포함됩니다." + echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" - echo -e "${gl_lv}1. 전체 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리 스캔${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉터리 검색${gl_bai}" + echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "전체 스캔" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5906,7 +5906,7 @@ clamav() { ;; 2) - send_stats "중요한 디렉토리 스캔" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5914,8 +5914,8 @@ clamav() { break_end ;; 3) - send_stats "사용자 정의 디렉토리 스캔" - read -e -p "스캔할 디렉터리를 공백으로 구분하여 입력하십시오(예: /etc /var /usr /home /root)." directories + send_stats "自定义目录扫描" + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -5931,27 +5931,27 @@ clamav() { # ============================================================================ -# Linux 커널 조정 모듈(리팩터링 버전) -# 통합 핵심 기능 + 장면 차별화 매개변수 + 구성 파일 지속성 + 하드웨어 적응 -# 원래의optim_high_performance/optim_balanced/optim_web_server/restore_defaults를 교체하십시오. +# Linux 内核调优模块(重构版) +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ -# 메모리 크기(MB) 가져오기 +# 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo } -# 통합 커널 튜닝 핵심 기능 -# 매개변수: $1 = 모드 이름, $2 = 장면(하이/밸런스/웹/스트림/게임) +# 统一内核调优核心函数 +# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" local MEM_MB=$(_get_mem_mb) - echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" + echo -e "${gl_lv}切换到${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정합니다── + # ── 根据场景设定参数 ── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -5960,7 +5960,7 @@ _kernel_optimize_core() { case "$scene" in high|stream|game) - # 고성능/생방송/게임: 급진적인 매개변수 + # 高性能/直播/游戏:激进参数 SWAPPINESS=10 DIRTY_RATIO=15 DIRTY_BG_RATIO=5 @@ -5983,7 +5983,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; web) - # 웹사이트 서버: 높은 동시성 우선순위 + # 网站服务器:高并发优先 SWAPPINESS=10 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6006,7 +6006,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; balanced) - # 균형 모드: 보통 최적화 + # 均衡模式:适度优化 SWAPPINESS=30 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6030,7 +6030,7 @@ _kernel_optimize_core() { ;; esac - # ── 메모리 크기에 따라 적응적으로 조정 ── + # ── 根据内存大小自适应调整 ── if [ "$MEM_MB" -ge 16384 ]; then MIN_FREE_KB=131072 [ "$scene" != "balanced" ] && SWAPPINESS=5 @@ -6038,7 +6038,7 @@ _kernel_optimize_core() { MIN_FREE_KB=65536 elif [ "$MEM_MB" -ge 1024 ]; then MIN_FREE_KB=32768 - # 작은 메모리 축소 버퍼 + # 小内存缩小缓冲区 if [ "$scene" != "balanced" ]; then RMEM_MAX=16777216 WMEM_MAX=16777216 @@ -6057,28 +6057,28 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── 추가 라이브 방송 시나리오: UDP 버퍼 확대 ── + # ── 直播场景额外:UDP 缓冲区加大 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" -# 라이브 스트리밍 UDP 최적화 +# 直播推流 UDP 优化 net.ipv4.udp_rmem_min = 16384 net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 게임 서버 장면 추가: 낮은 대기 시간 우선 ── + # ── 游戏服场景额外:低延迟优先 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" -# 게임 서버 낮은 대기 시간 최적화 +# 游戏服低延迟优化 net.ipv4.udp_rmem_min = 16384 net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384 net.ipv4.tcp_slow_start_after_idle = 0" fi - # ── BBR 모듈 로드 ── + # ── 加载 BBR 模块 ── local CC="bbr" local QDISC="fq" local KVER @@ -6096,21 +6096,21 @@ net.ipv4.tcp_slow_start_after_idle = 0" QDISC="fq_codel" fi - # ── 기존 구성 백업 ── + # ── 备份已有配置 ── [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" - # ── 구성 파일 쓰기(지속성) ── - echo -e "${gl_lv}최적화 구성 쓰기...${gl_bai}" + # ── 写入配置文件(持久化) ── + echo -e "${gl_lv}写入优化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# 케질리온 커널 튜닝 구성 -# 모드: $mode_name | 장면: $장면 -# 메모리: ${MEM_MB}MB | 생성 시간: $(날짜 '+%Y-%m-%d %H:%M:%S') +# kejilion 内核调优配置 +# 模式: $mode_name | 场景: $scene +# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') -# ──TCP 혼잡 제어── +# ── TCP 拥塞控制 ── net.core.default_qdisc = $QDISC net.ipv4.tcp_congestion_control = $CC -# ── TCP 버퍼 ── +# ── TCP 缓冲区 ── net.core.rmem_max = $RMEM_MAX net.core.wmem_max = $WMEM_MAX net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') @@ -6118,12 +6118,12 @@ net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') net.ipv4.tcp_rmem = $TCP_RMEM net.ipv4.tcp_wmem = $TCP_WMEM -# ── 연결 큐 ── +# ── 连接队列 ── net.core.somaxconn = $SOMAXCONN net.core.netdev_max_backlog = $BACKLOG net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG -# ── TCP 연결 최적화 ── +# ── TCP 连接优化 ── net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT @@ -6139,12 +6139,12 @@ net.ipv4.tcp_sack = 1 net.ipv4.tcp_timestamps = 1 net.ipv4.tcp_window_scaling = 1 -# ── 포트와 메모리 ── +# ── 端口与内存 ── net.ipv4.ip_local_port_range = $PORT_RANGE net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) net.ipv4.tcp_max_orphans = 32768 -# ── 가상 메모리 ── +# ── 虚拟内存 ── vm.swappiness = $SWAPPINESS vm.dirty_ratio = $DIRTY_RATIO vm.dirty_background_ratio = $DIRTY_BG_RATIO @@ -6152,11 +6152,11 @@ vm.overcommit_memory = $OVERCOMMIT vm.min_free_kbytes = $MIN_FREE_KB vm.vfs_cache_pressure = $VFS_PRESSURE -# ──CPU/커널 스케줄링── +# ── CPU/内核调度 ── kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP -$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing은 지원되지 않습니다") +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing 不支持") -# ──안전 보호── +# ── 安全防护 ── net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 @@ -6168,11 +6168,11 @@ net.ipv4.conf.default.send_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 -# ── 파일 설명자 ── +# ── 文件描述符 ── fs.file-max = 1048576 fs.nr_open = 1048576 -# ── 연결 추적 ── +# ── 连接跟踪 ── $(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" @@ -6180,17 +6180,17 @@ echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" else -echo "# conntrack이 활성화되어 있지 않습니다" +echo "# conntrack 未启用" fi) $STREAM_EXTRA $GAME_EXTRA SYSCTL - # ── 구성 적용(한 줄씩, 지원되지 않는 매개변수 건너뛰기) ── - echo -e "${gl_lv}최적화 매개변수 적용...${gl_bai}" + # ── 应用配置(逐行,跳过不支持的参数) ── + echo -e "${gl_lv}应用优化参数...${gl_bai}" local applied=0 skipped=0 while IFS= read -r line; do - # 주석과 빈 줄 건너뛰기 + # 跳过注释和空行 [[ "$line" =~ ^[[:space:]]*# ]] && continue [[ -z "${line// /}" ]] && continue if sysctl -w "$line" >/dev/null 2>&1; then @@ -6199,14 +6199,14 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}적용된${applied}항목 매개변수 ${skipped:+, 건너뛰기${skipped}지원되지 않는 항목 매개변수}${gl_bai}" + echo -e "${gl_lv}已应用 ${applied} 项参数${skipped:+,跳过 ${skipped} 项不支持的参数}${gl_bai}" - # ── 투명 대형 페이지 ── + # ── 透明大页面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi - # ── 파일 설명자 제한 사항 ── + # ── 文件描述符限制 ── if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then cat >> /etc/security/limits.conf << 'LIMITS' @@ -6218,60 +6218,60 @@ root hard nofile 1048576 LIMITS fi - # ── BBR 지속성 ── + # ── BBR 持久化 ── if [ "$CC" = "bbr" ]; then echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null - # 이전 sysctl.conf에서 bbr 구성을 정리합니다(충돌을 방지하기 위해). + # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name}최적화 완료! 구성은 다음과 같이 유지되었습니다.${CONF}${gl_bai}" - echo -e "${gl_lv}메모리:${MEM_MB}MB | 혼잡 알고리즘:${CC}| 대기줄:${QDISC}${gl_bai}" + echo -e "${gl_lv}${mode_name} 优化完成!配置已持久化到 ${CONF}${gl_bai}" + echo -e "${gl_lv}内存: ${MEM_MB}MB | 拥塞算法: ${CC} | 队列: ${QDISC}${gl_bai}" } -# ── 각 모드의 진입 기능(원래 호출 인터페이스를 그대로 유지) ── +# ── 各模式入口函数(保持原有调用接口不变) ── optimize_high_performance() { _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" } optimize_balanced() { - _kernel_optimize_core "균형 잡힌 최적화 모드" "balanced" + _kernel_optimize_core "均衡优化模式" "balanced" } optimize_web_server() { - _kernel_optimize_core "웹사이트 구축 최적화 모드" "web" + _kernel_optimize_core "网站搭建优化模式" "web" } -# ── 기본 설정 복원(완전 청소) ── +# ── 还原默认设置(完全清理) ── restore_defaults() { - echo -e "${gl_lv}기본 설정으로 되돌리기...${gl_bai}" + echo -e "${gl_lv}还原到默认设置...${gl_bai}" local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 최적화 구성 파일 삭제(외부 링크 자동 튜닝 구성 포함) + # 删除优化配置文件(含外链自动调优配置) rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf - # sysctl.conf에서 가능한 나머지 bbr 구성을 정리합니다. + # 清理 sysctl.conf 里可能残留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 시스템 기본 구성 다시 로드 + # 重新加载系统默认配置 sysctl --system 2>/dev/null | tail -1 - # 투명한 대용량 페이지 복원 + # 还原透明大页面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null - # 파일 설명자 구성 정리 + # 清理文件描述符配置 if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf fi - # BBR 지속성 정리 + # 清理 BBR 持久化 rm -f /etc/modules-load.d/bbr.conf 2>/dev/null - echo -e "${gl_lv}시스템이 기본 설정으로 복원되었습니다.${gl_bai}" + echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" } @@ -6279,76 +6279,76 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux 커널 튜닝 관리" - local current_mode=$(grep "^# 모드:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 모드: //' | awk -F'|' '{print $1}' | xargs) - [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="자동 튜닝 모드" - echo "Linux 시스템 커널 매개변수 최적화" + send_stats "Linux内核调优管理" + local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" + echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "현재 모드:${gl_lv}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" else - echo -e "현재 모드:${gl_hui}최적화되지 않음${gl_bai}" + echo -e "当前模式: ${gl_hui}未优化${gl_bai}" fi - echo "영상 소개: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." - echo -e "${gl_huang}힌트:${gl_bai}프로덕션 환경에서는 주의해서 사용해주세요!" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" echo -e "--------------------" - echo -e "1. 고성능 최적화 모드: 시스템 성능, 적극적인 메모리 및 네트워크 매개변수를 최대화합니다." - echo -e "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." - echo -e "3. 웹사이트 최적화 모드: 웹사이트 서버에 최적화되어 있으며 동시 연결 대기열이 매우 높습니다." - echo -e "4. 라이브 방송 최적화 모드: 라이브 스트리밍 최적화를 위해 UDP 버퍼가 확장되어 지연이 줄어듭니다." - echo -e "5. 게임 서버 최적화 모드: 게임 서버에 최적화되어 낮은 대기 시간을 우선시합니다." - echo -e "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." - echo -e "7. 자동 튜닝: 테스트 데이터를 기반으로 커널 매개변수를 자동으로 튜닝합니다.${gl_huang}★${gl_bai}" + echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" + echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" + echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "4. 直播优化模式: 针对直播推流优化,UDP 缓冲区加大,减少延迟。" + echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" + echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ clear - local tiaoyou_moshi="고성능 최적화 모드" + local tiaoyou_moshi="高性能优化模式" optimize_high_performance - send_stats "고성능 모드 최적화" + send_stats "高性能模式优化" ;; 2) cd ~ clear optimize_balanced - send_stats "균형 모드 최적화" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "网站优化模式" ;; 4) cd ~ clear - _kernel_optimize_core "라이브 방송 최적화 모드" "stream" - send_stats "라이브 스트리밍 최적화" + _kernel_optimize_core "直播优化模式" "stream" + send_stats "直播推流优化" ;; 5) cd ~ clear - _kernel_optimize_core "게임 서버 최적화 모드" "game" - send_stats "게임 서버 최적화" + _kernel_optimize_core "游戏服优化模式" "game" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults - send_stats "기본 설정 복원" + send_stats "还原默认设置" ;; 7) cd ~ clear curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - send_stats "커널 자동 튜닝" + send_stats "内核自动调优" ;; *) @@ -6378,7 +6378,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -6387,17 +6387,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "지원되지 않는 시스템:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "지원되지 않는 시스템, 시스템 유형을 식별할 수 없습니다." + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -6407,29 +6407,29 @@ update_locale() { linux_language() { root_use -send_stats "시스템 언어 전환" +send_stats "切换系统语言" while true; do clear - echo "현재 시스템 언어:$LANG" + echo "当前系统语言: $LANG" echo "------------------------" - echo "1. 영어 2. 중국어 간체 3. 중국어 번체" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "영어로 전환" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "중국어 간체로 전환" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "중국어 번체로 전환" + send_stats "切换到繁体中文" ;; *) break @@ -6451,7 +6451,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 보려면 SSH에 다시 연결하세요!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -6462,10 +6462,10 @@ break_end shell_bianse() { root_use - send_stats "명령줄 미화 도구" + send_stats "命令行美化工具" while true; do clear - echo "명령줄 미화 도구" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -6475,9 +6475,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -6522,7 +6522,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "시스템 휴지통" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -6531,23 +6531,23 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}활성화되지 않음${gl_bai}" + trash_status="${gl_hui}未启用${gl_bai}" else - trash_status="${gl_lv}활성화됨${gl_bai}" + trash_status="${gl_lv}已启用${gl_bai}" fi clear - echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "当前回收站 ${trash_status}" + echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" echo "------------------------" - echo "1. 휴지통 활성화 2. 휴지통 닫기" - echo "3. 콘텐츠 복원 4. 휴지통 비우기" + echo "1. 启用回收站 2. 关闭回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -6555,7 +6555,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "휴지통이 활성화되면 삭제된 파일은 휴지통으로 이동됩니다." + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -6563,23 +6563,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "휴지통이 닫히고 파일이 직접 삭제됩니다." + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) - read -e -p "복원할 파일 이름을 입력하세요:" file_to_restore + read -e -p "输入要还原的文件名: " file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore홈 디렉토리로 복원되었습니다." + echo "$file_to_restore 已还原到主目录。" else - echo "파일이 존재하지 않습니다." + echo "文件不存在。" fi ;; 4) - read -e -p "휴지통을 비우시겠습니까? [예/아니요]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "휴지통이 비워졌습니다." + echo "回收站已清空。" fi ;; *) @@ -6590,23 +6590,23 @@ linux_trash() { } linux_fav() { -send_stats "명령 즐겨찾기" +send_stats "命令收藏夹" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 백업 만들기 +# 创建备份 create_backup() { - send_stats "백업 만들기" + send_stats "创建备份" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 사용자에게 백업 디렉터리를 묻는 메시지 표시 - echo "백업 생성 예:" - echo "- 단일 디렉터리 백업: /var/www" - echo "- 여러 디렉터리 백업: /etc /home /var/log" - echo "- Enter를 눌러 기본 디렉터리(/etc/usr/home)를 사용합니다." - read -e -p "백업할 디렉터리를 입력하십시오(여러 디렉터리를 공백으로 구분하고 Enter를 눌러 기본 디렉터리를 사용하십시오)." input + # 提示用户输入备份目录 + echo "创建备份示例:" + echo " - 备份单个目录: /var/www" + echo " - 备份多个目录: /etc /home /var/log" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input - # 사용자가 디렉터리를 입력하지 않으면 기본 디렉터리가 사용됩니다. + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6614,119 +6614,119 @@ create_backup() { "/home" # 用户数据 ) else - # 사용자가 입력한 디렉토리를 공백으로 배열로 구분합니다. + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 백업 파일 접두사 생성 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 디렉토리 이름 추출 및 슬래시 제거 + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 마지막 밑줄 제거 + # 去除最后一个下划线 local PREFIX=${PREFIX%_} - # 백업 파일 이름 생성 + # 生成备份文件名 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 사용자가 선택한 디렉토리 인쇄 - echo "선택한 백업 디렉터리는 다음과 같습니다." + # 打印用户选择的目录 + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 백업 만들기 - echo "백업 생성$BACKUP_NAME..." + # 创建备份 + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 명령이 성공했는지 확인 + # 检查命令是否成功 if [ $? -eq 0 ]; then - echo "백업이 성공적으로 생성되었습니다:$BACKUP_DIR/$BACKUP_NAME" + echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" else - echo "백업 생성에 실패했습니다!" + echo "备份创建失败!" exit 1 fi } -# 백업 복원 +# 恢复备份 restore_backup() { - send_stats "백업 복원" - # 복원할 백업을 선택하세요 - read -e -p "복원할 백업 파일 이름을 입력하십시오:" BACKUP_NAME + send_stats "恢复备份" + # 选择要恢复的备份 + read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - echo "백업 복원 중$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "백업 및 복원 성공!" + echo "备份恢复成功!" else - echo "백업 복원에 실패했습니다!" + echo "备份恢复失败!" exit 1 fi } -# 백업 나열 +# 列出备份 list_backups() { - echo "사용 가능한 백업:" + echo "可用的备份:" ls -1 "$BACKUP_DIR" } -# 백업 삭제 +# 删除备份 delete_backup() { - send_stats "백업 삭제" + send_stats "删除备份" - read -e -p "삭제할 백업 파일 이름을 입력하십시오:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME - # 백업 파일이 있는지 확인 + # 检查备份文件是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "백업 파일이 존재하지 않습니다!" + echo "备份文件不存在!" exit 1 fi - # 백업 삭제 + # 删除备份 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "백업이 삭제되었습니다!" + echo "备份删除成功!" else - echo "백업 삭제에 실패했습니다!" + echo "备份删除失败!" exit 1 fi } -# 백업 메인 메뉴 +# 备份主菜单 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "시스템 백업 기능" - echo "시스템 백업 기능" + send_stats "系统备份功能" + echo "系统备份功能" echo "------------------------" list_backups echo "------------------------" - echo "1. 백업 생성 2. 백업 복원 3. 백업 삭제" + echo "1. 创建备份 2. 恢复备份 3. 删除备份" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르세요..." + read -e -p "按回车键继续..." done } @@ -6738,7 +6738,7 @@ linux_backup() { -# SSH 입력 정규화 기능 +# SSH 输入标准化函数 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -6764,7 +6764,7 @@ kj_ssh_read_host_port() { if kj_ssh_validate_host "$KJ_SSH_HOST"; then break fi - echo "오류: 유효한 서버 주소를 입력하세요." + echo "错误: 请输入有效的服务器地址。" done while true; do @@ -6773,7 +6773,7 @@ kj_ssh_read_host_port() { if kj_ssh_validate_port "$KJ_SSH_PORT"; then break fi - echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." + echo "错误: 端口必须是 1-65535 之间的数字。" done } @@ -6792,7 +6792,7 @@ kj_ssh_read_host_user_port() { if kj_ssh_validate_user "$KJ_SSH_USER"; then break fi - echo "오류: 사용자 이름 형식이 잘못되었습니다." + echo "错误: 用户名格式不正确。" done } @@ -6810,12 +6810,12 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "오류: SSH 사용자 이름 형식이 잘못되었습니다." + echo "错误: SSH 用户名格式不正确。" return 1 fi if ! kj_ssh_validate_host "$remote_host"; then - echo "오류: SSH 호스트 주소 형식이 잘못되었습니다." + echo "错误: SSH 主机地址格式不正确。" return 1 fi @@ -6828,24 +6828,24 @@ kj_ssh_read_auth() { local key_file="$1" local password_or_key="" - echo "인증 방법을 선택하세요:" - echo "1. 비밀번호" - echo "2. 열쇠" - read -e -p "원하는 항목(1/2)을 입력하세요." auth_choice + echo "请选择身份验证方式:" + echo "1. 密码" + echo "2. 密钥" + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) - read -s -p "비밀번호를 입력하세요:" password_or_key + read -s -p "请输入密码: " password_or_key echo if [ -z "$password_or_key" ]; then - echo "오류: 비밀번호는 비워둘 수 없습니다." + echo "错误: 密码不能为空。" return 1 fi KJ_SSH_AUTH_METHOD="password" KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -6856,7 +6856,7 @@ kj_ssh_read_auth() { done if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then - echo "잘못된 키 콘텐츠입니다!" + echo "无效的密钥内容!" return 1 fi @@ -6867,7 +6867,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$key_file" ;; *) - echo "잘못된 선택입니다!" + echo "无效的选择!" return 1 ;; esac @@ -6879,7 +6879,7 @@ kj_ssh_read_password() { read -e -s -p "$prompt" KJ_SSH_PASSWORD echo [ -n "$KJ_SSH_PASSWORD" ] && break - echo "오류: 비밀번호는 비워둘 수 없습니다." + echo "错误: 密码不能为空。" done } @@ -6892,113 +6892,113 @@ kj_ssh_read_port() { if kj_ssh_validate_port "$KJ_SSH_PORT"; then return 0 fi - echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." + echo "错误: 端口必须是 1-65535 之间的数字。" done } -# 연결 목록 표시 +# 显示连接列表 list_connections() { - echo "저장된 연결:" + echo "已保存的连接:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 새 연결 추가 +# 添加新连接 add_connection() { - send_stats "새 연결 추가" - echo "새 연결 생성의 예:" - echo "- 연결 이름: my_server" - echo "- IP 주소: 192.168.1.100" - echo "- 사용자 이름: 루트" - echo "- 포트: 22" + send_stats "添加新连接" + echo "创建新连接示例:" + echo " - 连接名称: my_server" + echo " - IP地址: 192.168.1.100" + echo " - 用户名: root" + echo " - 端口: 22" echo "------------------------" - read -e -p "연결 이름을 입력하세요:" name + read -e -p "请输入连接名称: " name - kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "포트 번호를 입력하십시오(기본값: 22):" "root" "22" + kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "请输入端口号 (默认: 22): " "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "연결이 저장되었습니다!" + echo "连接已保存!" } -# 연결 삭제 +# 删除连接 delete_connection() { - send_stats "연결 삭제" - read -e -p "삭제할 연결 번호를 입력하세요:" num + send_stats "删除连接" + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류: 해당 연결을 찾을 수 없습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하세요. + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "연결이 삭제되었습니다!" + echo "连接已删除!" } -# 연결 사용 +# 使用连接 use_connection() { - send_stats "연결 사용" - read -e -p "사용할 연결 번호를 입력하세요:" num + send_stats "使用连接" + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "오류: 해당 연결을 찾을 수 없습니다." + echo "错误:未找到对应的连接。" return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "연결 중$name ($ip)..." + echo "正在连接到 $name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 키를 사용하여 연결 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결에 실패했습니다! 다음 사항을 확인하세요." - echo "1. 키파일 경로가 맞나요?$password_or_key" - echo "2. 키 파일 권한이 올바른가요(600이어야 함)." - echo "3. 대상 서버에서 키를 이용한 로그인을 허용하는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" + echo "3. 目标服务器是否允许使用密钥登录。" fi else - # 비밀번호를 사용하여 연결 + # 使用密码连接 if ! command -v sshpass &> /dev/null; then - echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." - echo "설치 방법:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "연결에 실패했습니다! 다음 사항을 확인하세요." - echo "1. 사용자 이름과 비밀번호가 정확합니까?" - echo "2. 대상 서버에서 비밀번호 로그인을 허용하는지 여부." - echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되고 있는지 여부." + echo "连接失败!请检查以下内容:" + echo "1. 用户名和密码是否正确。" + echo "2. 目标服务器是否允许密码登录。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } ssh_manager() { - send_stats "SSH 원격 연결 도구" + send_stats "ssh远程连接工具" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 구성 파일과 키 디렉터리가 있는지 확인하고 없으면 만듭니다. + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -7010,21 +7010,21 @@ ssh_manager() { while true; do clear - echo "SSH 원격 연결 도구" - echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다." + echo "SSH 远程连接工具" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections - echo "1. 새 연결 생성 2. 연결 사용 3. 연결 삭제" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -7040,184 +7040,184 @@ ssh_manager() { -# 사용 가능한 하드 디스크 파티션 나열 +# 列出可用的硬盘分区 list_partitions() { - echo "사용 가능한 하드 드라이브 파티션:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 지속적으로 마운트된 파티션 +# 持久化挂载分区 mount_partition() { - send_stats "마운트 파티션" - read -e -p "마운트할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION + send_stats "挂载分区" + read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" - # 파티션이 존재하는지 확인 + # 检查分区是否存在 if ! lsblk -no NAME | grep -qw "$PARTITION"; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return 1 fi - # 마운트되어 있는지 확인해보세요 + # 检查是否已挂载 if mount | grep -qw "$DEVICE"; then - echo "파티션이 마운트되었습니다!" + echo "分区已经挂载!" return 1 fi - # UUID 가져오기 + # 获取 UUID UUID=$(blkid -s UUID -o value "$DEVICE") if [ -z "$UUID" ]; then - echo "UUID를 얻을 수 없습니다!" + echo "无法获取 UUID!" return 1 fi - # 파일 시스템 유형 가져오기 + # 获取文件系统类型 FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then - echo "파일 시스템 유형을 가져올 수 없습니다!" + echo "无法获取文件系统类型!" return 1 fi - # 마운트 지점 생성 + # 创建挂载点 mkdir -p "$MOUNT_POINT" - # 산 + # 挂载 if ! mount "$DEVICE" "$MOUNT_POINT"; then - echo "파티션 마운트에 실패했습니다!" + echo "分区挂载失败!" rmdir "$MOUNT_POINT" return 1 fi - echo "파티션이 성공적으로 마운트되었습니다.$MOUNT_POINT" + echo "分区已成功挂载到 $MOUNT_POINT" - # /etc/fstab을 확인하여 UUID 또는 마운트 지점이 이미 존재하는지 확인하세요. + # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "파티션 기록이 /etc/fstab에 이미 존재합니다. 쓰기를 건너뛰세요." + echo "/etc/fstab 中已存在该分区记录,跳过写入" return 0 fi - # /etc/fstab에 쓰기 + # 写入 /etc/fstab echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab - echo "지속적인 마운트를 위해 /etc/fstab에 기록" + echo "已写入 /etc/fstab,实现持久化挂载" } -# 파티션 마운트 해제 +# 卸载分区 unmount_partition() { - send_stats "파티션 마운트 해제" - read -e -p "마운트 해제할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION + send_stats "卸载分区" + read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION - # 파티션이 마운트되었는지 확인 + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "파티션이 마운트되지 않았습니다!" + echo "分区未挂载!" return fi - # 파티션 마운트 해제 + # 卸载分区 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션이 성공적으로 제거되었습니다:$MOUNT_POINT" + echo "分区卸载成功: $MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "파티션 제거에 실패했습니다!" + echo "分区卸载失败!" fi } -# 마운트된 파티션 나열 +# 列出已挂载的分区 list_mounted_partitions() { - echo "마운트된 파티션:" + echo "已挂载的分区:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 파티션 포맷 +# 格式化分区 format_partition() { - send_stats "파티션 포맷" - read -e -p "포맷할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION + send_stats "格式化分区" + read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION - # 파티션이 존재하는지 확인 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션이 마운트되었는지 확인 + # 检查分区是否已经挂载 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 마운트되었습니다. 먼저 마운트를 해제하세요!" + echo "分区已经挂载,请先卸载!" return fi - # 파일 시스템 유형 선택 - echo "파일 시스템 유형을 선택하십시오:" + # 选择文件系统类型 + echo "请选择文件系统类型:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "선택사항을 입력하세요:" FS_CHOICE + read -e -p "请输入你的选择: " FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "잘못된 선택입니다!"; return ;; + *) echo "无效的选择!"; return ;; esac - # 포맷 확인 - read -e -p "포맷된 파티션 /dev/ 확인$PARTITION~을 위한$FS_TYPE? (예/아니요):" CONFIRM + # 确认格式化 + read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "작업이 취소되었습니다." + echo "操作已取消。" return fi - # 파티션 포맷 - echo "파티션 /dev/ 포맷 중$PARTITION~을 위한$FS_TYPE ..." + # 格式化分区 + echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "파티션이 성공적으로 포맷되었습니다!" + echo "分区格式化成功!" else - echo "파티션 포맷에 실패했습니다!" + echo "分区格式化失败!" fi } -# 파티션 상태 확인 +# 检查分区状态 check_partition() { - send_stats "파티션 상태 확인" - read -e -p "확인할 파티션 이름을 입력하세요(예: sda1):" PARTITION + send_stats "检查分区状态" + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION - # 파티션이 존재하는지 확인 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "파티션이 존재하지 않습니다!" + echo "分区不存在!" return fi - # 파티션 상태 확인 - echo "파티션 확인 /dev/$PARTITION상태:" + # 检查分区状态 + echo "检查分区 /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } -# 메인 메뉴 +# 主菜单 disk_manager() { - send_stats "하드디스크 관리 기능" + send_stats "硬盘管理功能" while true; do clear - echo "하드 드라이브 파티션 관리" - echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" + echo "硬盘分区管理" + echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 파티션 마운트 2. 파티션 마운트 해제 3. 마운트된 파티션 보기" - echo "4. 파티션 포맷 5. 파티션 상태 확인" + echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -7226,44 +7226,44 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르세요..." + read -e -p "按回车键继续..." done } -# 작업 목록 표시 +# 显示任务列表 list_tasks() { - echo "저장된 동기화 작업:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 새 작업 추가 +# 添加新任务 add_task() { - send_stats "새 동기화 작업 추가" - echo "새 동기화 작업 생성의 예:" - echo "- 작업 이름: backup_www" - echo "- 로컬 디렉터리: /var/www" - echo "- 원격 주소: user@192.168.1.100" - echo "- 원격 디렉터리: /backup/www" - echo "- 포트 번호(기본값 22)" + send_stats "添加新同步任务" + echo "创建新同步任务示例:" + echo " - 任务名称: backup_www" + echo " - 本地目录: /var/www" + echo " - 远程地址: user@192.168.1.100" + echo " - 远程目录: /backup/www" + echo " - 端口号 (默认 22)" echo "---------------------------------" - read -e -p "작업 이름을 입력하세요:" name - read -e -p "로컬 디렉토리를 입력하십시오:" local_path - read -e -p "원격 디렉토리를 입력하십시오:" remote_path + read -e -p "请输入任务名称: " name + read -e -p "请输入本地目录: " local_path + read -e -p "请输入远程目录: " remote_path while true; do - read -e -p "원격 user@IP를 입력하십시오:" remote + read -e -p "请输入远程用户@IP: " remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break fi done - kj_ssh_read_port "SSH 포트(기본값 22)를 입력하세요." "22" + kj_ssh_read_port "请输入 SSH 端口 (默认 22): " "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7272,54 +7272,54 @@ add_task() { auth_method="$KJ_SSH_AUTH_METHOD" password_or_key="$KJ_SSH_AUTH_SECRET" - echo "동기화 모드를 선택하십시오:" - echo "1. 표준 모드(-avz)" - echo "2. 대상 파일 삭제(-avz --delete)" - read -e -p "(1/2)을 선택하세요:" mode + echo "请选择同步模式:" + echo "1. 标准模式 (-avz)" + echo "2. 删除目标文件 (-avz --delete)" + read -e -p "请选择 (1/2): " mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "선택이 잘못되었습니다. 기본값 -avz를 사용하세요."; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "임무가 저장되었습니다!" + echo "任务已保存!" } -# 할 일 삭제 +# 删除任务 delete_task() { - send_stats "동기화 작업 삭제" - read -e -p "삭제할 작업 번호를 입력하세요:" num + send_stats "删除同步任务" + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류: 해당 작업을 찾을 수 없습니다." + echo "错误:未找到对应的任务。" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하세요. + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "작업이 삭제되었습니다!" + echo "任务已删除!" } run_task() { - send_stats "동기화 작업 수행" + send_stats "执行同步任务" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 매개변수 구문 분석 + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -7330,51 +7330,51 @@ run_task() { num="$1" fi - # 작업 번호가 전달되지 않으면 사용자에게 입력하라는 메시지가 표시됩니다. + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then - read -e -p "실행할 작업 번호를 입력하세요:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "오류: 작업을 찾을 수 없습니다!" + echo "错误: 未找到该任务!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 동기화 방향에 따라 소스 및 대상 경로 조정 + # 根据同步方向调整源和目标路径 if [[ "$direction" == "pull" ]]; then - echo "로컬로 가져오기 및 동기화:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "원격 끝에 푸시 및 동기화:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # SSH 연결 공통 매개변수 추가 + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." - echo "설치 방법:" + echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "安装方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 키 파일이 존재하는지, 권한이 올바른지 확인하세요. + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "오류: 키 파일이 존재하지 않습니다:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "경고: 잘못된 키 파일 권한, 수정 중..." + echo "警告:密钥文件权限不正确,正在修复..." chmod 600 "$password_or_key" fi @@ -7382,32 +7382,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "동기화가 완료되었습니다!" + echo "同步完成!" else - echo "동기화에 실패했습니다! 다음 사항을 확인하세요." - echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" - echo "3. 인증정보가 정확합니까?" - echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" + echo "同步失败! 请检查以下内容:" + echo "1. 网络连接是否正常" + echo "2. 远程主机是否可访问" + echo "3. 认证信息是否正确" + echo "4. 本地和远程目录是否有正确的访问权限" fi } -# 예약된 작업 만들기 +# 创建定时任务 schedule_task() { - send_stats "동기화 예약 작업 추가" + send_stats "添加同步定时任务" - read -e -p "정기적으로 동기화할 작업 번호를 입력하세요:" num + read -e -p "请输入要定时同步的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류: 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi - echo "예약된 실행 간격을 선택하십시오." - echo "1) 매 시간마다 한 번씩 실행" - echo "2) 하루에 한 번 실행" - echo "3) 일주일에 한 번 실행" - read -e -p "옵션을 입력하세요(1/2/3):" interval + echo "请选择定时执行间隔:" + echo "1) 每小时执行一次" + echo "2) 每天执行一次" + echo "3) 每周执行一次" + read -e -p "请输入选项 (1/2/3): " interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -7415,66 +7415,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "오류: 유효한 옵션을 입력하십시오!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 동일한 작업이 이미 존재하는지 확인하세요. + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then - echo "오류: 이 작업에 대해 예약된 동기화가 이미 존재합니다!" + echo "错误: 该任务的定时同步已存在!" return fi - # 사용자의 crontab에 생성 + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "예약된 작업이 생성되었습니다:$cron_job" + echo "定时任务已创建: $cron_job" } -# 예약된 작업 보기 +# 查看定时任务 view_tasks() { - echo "현재 예약된 작업:" + echo "当前的定时任务:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 예약된 작업 삭제 +# 删除定时任务 delete_task_schedule() { - send_stats "동기화 예약 작업 삭제" - read -e -p "삭제할 작업 번호를 입력하세요:" num + send_stats "删除同步定时任务" + read -e -p "请输入要删除的任务编号: " num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "오류: 유효한 작업 번호를 입력하십시오!" + echo "错误: 请输入有效的任务编号!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "태스크 번호가 삭제되었습니다.$num예약된 작업" + echo "已删除任务编号 $num 的定时任务" } -# 작업 관리 메인 메뉴 +# 任务管理主菜单 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 원격 동기화 도구" - echo "원격 디렉터리 간의 동기화는 효율적이고 안정적인 증분 동기화를 지원합니다." + echo "Rsync 远程同步工具" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 새 작업 생성 2. 작업 삭제" - echo "3. 원격 사이트에 대한 로컬 동기화 수행 4. 로컬 사이트에 대한 원격 동기화 수행" - echo "5. 예약된 작업 생성 6. 예약된 작업 삭제" + echo "1. 创建新任务 2. 删除任务" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "---------------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -7483,9 +7483,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "계속하려면 Enter를 누르세요..." + read -e -p "按回车键继续..." done } @@ -7502,8 +7502,8 @@ linux_info() { clear - echo -e "${gl_kjlan}시스템 정보를 쿼리하는 중...${gl_bai}" - send_stats "시스템 정보 쿼리" + echo -e "${gl_kjlan}正在查询系统信息……${gl_bai}" + send_stats "系统信息查询" ip_address @@ -7547,7 +7547,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d시간 ", run_hours); printf("%d분\n", run_mins)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') local timezone=$(current_timezone) @@ -7555,42 +7555,42 @@ linux_info() { local udp_count=$(ss -u | wc -l) clear - echo -e "시스템 정보 쿼리" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}호스트 이름:${gl_bai}$hostname" - echo -e "${gl_kjlan}시스템 버전:${gl_bai}$os_info" - echo -e "${gl_kjlan}리눅스 버전:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" + echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 아키텍처:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU 모델:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU 코어 수:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU 주파수:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU 사용량:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" - echo -e "${gl_kjlan}TCP|UDP 연결 수:${gl_bai}$tcp_count|$udp_count" - echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" - echo -e "${gl_kjlan}가상 메모리:${gl_bai}$swap_info" - echo -e "${gl_kjlan}하드 드라이브 사용량:${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" - echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}네트워크 알고리즘:${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 주소:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6 주소:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS 주소:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}위치:${gl_bai}$country $city" - echo -e "${gl_kjlan}시스템 시간:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" + echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" echo @@ -7603,8 +7603,8 @@ linux_tools() { while true; do clear - # send_stats "기본 도구" - echo -e "기본 도구" + # send_stats "基础工具" + echo -e "基础工具" tools=( curl wget sudo socat htop iftop unzip tar tmux ffmpeg @@ -7629,27 +7629,27 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 인식할 수 없는 패키지 관리자" + echo "❌ 未识别的包管理器" exit 1 fi - echo "📦 패키지 관리자를 사용하세요:$PM" + echo "📦 使用包管理器: $PM" echo -e "${gl_kjlan}------------------------${gl_bai}" for ((i=0; i<${#tools[@]}; i+=2)); do - # 왼쪽 열 + # 左列 if command -v "${tools[i]}" >/dev/null 2>&1; then - left=$(printf "✅ %-12s 설치됨" "${tools[i]}") + left=$(printf "✅ %-12s 已安装" "${tools[i]}") else - left=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i]}") + left=$(printf "❌ %-12s 未安装" "${tools[i]}") fi - # 오른쪽 열(배열이 범위를 벗어나는 것을 방지하기 위해) + # 右列(防止数组越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then - right=$(printf "✅ %-12s 설치됨" "${tools[i+1]}") + right=$(printf "✅ %-12s 已安装" "${tools[i+1]}") else - right=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i+1]}") + right=$(printf "❌ %-12s 未安装" "${tools[i+1]}") fi printf "%-42s %s\n" "$left" "$right" else @@ -7658,108 +7658,108 @@ linux_tools() { done echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 다운로드 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 최고 관리 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" - echo -e "${gl_kjlan}5. ${gl_bai}htop 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}iftop 네트워크 트래픽 모니터링 도구" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP 압축 및 압축 풀기 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}레인저 파일 관리 도구" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 디스크 사용량 보기 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" - echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템${gl_kjlan}18. ${gl_bai}오픈코드 AI 프로그래밍 도우미${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统 ${gl_kjlan}18. ${gl_bai}opencode AI编程助手 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 스크린세이버${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" - echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 미니게임" - echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 미니 게임" + echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}모두 설치${gl_kjlan}32. ${gl_bai}모두 설치(화면 보호기 및 게임 제외)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}모두 제거" + echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구 설치${gl_kjlan}42. ${gl_bai}지정된 도구 제거" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear install curl clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" curl --help - send_stats "컬 설치" + send_stats "安装curl" ;; 2) clear install wget clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" wget --help - send_stats "wget 설치" + send_stats "安装wget" ;; 3) clear install sudo clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" sudo --help - send_stats "sudo 설치" + send_stats "安装sudo" ;; 4) clear install socat clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" socat -h - send_stats "socat 설치" + send_stats "安装socat" ;; 5) clear install htop clear htop - send_stats "htop 설치" + send_stats "安装htop" ;; 6) clear install iftop clear iftop - send_stats "iftop 설치" + send_stats "安装iftop" ;; 7) clear install unzip clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" unzip - send_stats "설치압축 해제" + send_stats "安装unzip" ;; 8) clear install tar clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" tar --help - send_stats "타르 설치" + send_stats "安装tar" ;; 9) clear install tmux clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" tmux --help - send_stats "tmux 설치" + send_stats "安装tmux" ;; 10) clear install ffmpeg clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" ffmpeg --help - send_stats "ffmpeg 설치" + send_stats "安装ffmpeg" ;; 11) @@ -7767,7 +7767,7 @@ linux_tools() { install btop clear btop - send_stats "btop 설치" + send_stats "安装btop" ;; 12) clear @@ -7776,7 +7776,7 @@ linux_tools() { clear ranger cd ~ - send_stats "레인저 설치" + send_stats "安装ranger" ;; 13) clear @@ -7785,7 +7785,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncdu 설치" + send_stats "安装ncdu" ;; 14) clear @@ -7794,7 +7794,7 @@ linux_tools() { clear fzf cd ~ - send_stats "fzf 설치" + send_stats "安装fzf" ;; 15) clear @@ -7803,7 +7803,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "vim 설치" + send_stats "安装vim" ;; 16) clear @@ -7812,7 +7812,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "나노 설치" + send_stats "安装nano" ;; @@ -7823,7 +7823,7 @@ linux_tools() { clear git --help cd ~ - send_stats "자식 설치" + send_stats "安装git" ;; 18) @@ -7833,7 +7833,7 @@ linux_tools() { source ~/.bashrc source ~/.profile opencode - send_stats "오픈코드 설치" + send_stats "安装opencode" ;; @@ -7842,28 +7842,28 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "cmatrix 설치" + send_stats "安装cmatrix" ;; 22) clear install sl clear sl - send_stats "sl 설치" + send_stats "安装sl" ;; 26) clear install bastet clear bastet - send_stats "바스테트 설치" + send_stats "安装bastet" ;; 27) clear install nsnake clear nsnake - send_stats "nsnake 설치" + send_stats "安装nsnake" ;; 28) @@ -7871,25 +7871,25 @@ linux_tools() { install ninvaders clear ninvaders - send_stats "닌베이더 설치" + send_stats "安装ninvaders" ;; 31) clear - send_stats "모두 설치" + send_stats "全部安装" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "모두 설치(게임 및 화면 보호기 제외)" + send_stats "全部安装(不含游戏和屏保)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "모두 제거" + send_stats "全部卸载" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git opencode uninstall rm -rf ~/.opencode @@ -7897,15 +7897,15 @@ linux_tools() { 41) clear - read -e -p "설치된 도구 이름을 입력하십시오(wget 컬 sudo htop):" installname + read -e -p "请输入安装的工具名(wget curl sudo htop): " installname install $installname - send_stats "지정된 소프트웨어 설치" + send_stats "安装指定软件" ;; 42) clear - read -e -p "제거된 도구 이름(htop ufw tmux cmatrix)을 입력하십시오." removename + read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename remove $removename - send_stats "지정된 소프트웨어 제거" + send_stats "卸载指定软件" ;; 0) @@ -7913,7 +7913,7 @@ linux_tools() { ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -7927,27 +7927,27 @@ linux_tools() { linux_bbr() { clear - send_stats "BBR 관리" + send_stats "bbr管理" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "현재 TCP 차단 알고리즘:$congestion_algorithm $queue_algorithm" + echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" echo "" - echo "BBR 관리" + echo "BBR管理" echo "------------------------" - echo "1. BBRv3를 켭니다. 2. BBRv3을 끕니다(다시 시작됩니다)." + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) bbr_on - send_stats "알파인이 열립니다 bbr3" + send_stats "alpine开启bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf @@ -7983,21 +7983,21 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${gl_kjlan}현재 백업 목록:${gl_bai}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" + echo -e "${gl_kjlan}当前备份列表:${gl_bai}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" } # ---------------------------- - # 지원 + # 备份 # ---------------------------- backup_docker() { - send_stats "도커 백업" + send_stats "Docker备份" - echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" + echo -e "${gl_kjlan}正在备份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -8010,7 +8010,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}컨테이너를 찾을 수 없습니다.${gl_bai}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}没有找到容器${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -8018,28 +8018,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 자동으로 생성된 복원 스크립트" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # 반복되는 패키징을 피하기 위해 패키징된 Compose 프로젝트 경로를 기록하세요. + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${gl_lv}백업 컨테이너:$c${gl_bai}" + echo -e "${gl_lv}备份容器: $c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}감지됨$c도커 작성 컨테이너입니다${gl_bai}" + echo -e "${gl_kjlan}检测到 $c 是 docker-compose 容器${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "작성 디렉터리가 감지되지 않습니다. 경로를 수동으로 입력하세요." project_dir + read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir fi - # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. + # 如果该 Compose 项目已经打包过,跳过 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${gl_bai}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" continue fi @@ -8047,137 +8047,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 복원:$project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${gl_lv}프로젝트 작성 [$project_name] 포장:${project_dir}${gl_bai}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已打包: ${project_dir}${gl_bai}" else - echo -e "${gl_hong}docker-compose.yml을 찾을 수 없습니다. 이 컨테이너를 건너뛰는 중입니다...${gl_bai}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" fi else - # 일반 컨테이너 백업 볼륨 + # 普通容器备份卷 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "포장량:$path" + echo "打包卷: $path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 포트 + # 端口 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 환경 변수 + # 环境变量 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 볼륨 매핑 + # 卷映射 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 거울 + # 镜像 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 복원 컨테이너:$c" >> "$RESTORE_SCRIPT" + echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then - echo -e "${gl_kjlan}/home/docker 아래의 파일을 백업합니다...${gl_bai}" + echo -e "${gl_kjlan}备份 /home/docker 下的文件...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${gl_lv}백업 완료:${BACKUP_DIR}${gl_bai}" - echo -e "${gl_lv}사용 가능한 복원 스크립트:${RESTORE_SCRIPT}${gl_bai}" + echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}可用还原脚本: ${RESTORE_SCRIPT}${gl_bai}" } # ---------------------------- - # 절감 + # 还原 # ---------------------------- restore_docker() { - send_stats "도커 복원" - read -e -p "복원할 백업 디렉터리를 입력하십시오:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } + send_stats "Docker还原" + read -e -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - echo -e "${gl_kjlan}복원 작업을 시작하는 중...${gl_bai}" + echo -e "${gl_kjlan}开始执行还原操作...${gl_bai}" install tar jq gzip install_docker - # --------- Compose 프로젝트 복원 우선순위 지정 --------- + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -e -p "원래 경로를 찾을 수 없습니다. 복원 디렉터리 경로를 입력하십시오:" original_path + [[ -z "$original_path" ]] && read -e -p "未找到原始路径,请输入还原目录路径: " original_path - # Compose 프로젝트의 컨테이너가 이미 실행 중인지 확인하세요. + # 检查该 compose 项目的容器是否已经在运行 running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${gl_huang}프로젝트 작성 [$project_name] 컨테이너가 이미 실행 중입니다. 복원을 건너뛰세요...${gl_bai}" + echo -e "${gl_huang}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${gl_bai}" continue fi - read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -e -p "새 복원 경로를 입력하십시오." original_path + read -e -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "请输入新的还原路径: " original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已解压到: $original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${gl_lv}프로젝트 작성 [$project_name] 복원 완료!${gl_bai}" + echo -e "${gl_lv}Compose 项目 [$project_name] 还原完成!${gl_bai}" fi done - # --------- 일반 컨테이너를 계속 복원합니다 --------- - echo -e "${gl_kjlan}일반 Docker 컨테이너 확인 및 복원...${gl_bai}" + # --------- 继续还原普通容器 --------- + echo -e "${gl_kjlan}检查并还原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}처리 용기:$container${gl_bai}" + echo -e "${gl_lv}处理容器: $container${gl_bai}" - # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. + # 检查容器是否已经存在且正在运行 if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${gl_bai}" + echo -e "${gl_huang}容器 [$container] 已在运行,跳过还原...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}미러 정보를 찾을 수 없습니다. 건너뛰세요:$container${gl_bai}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } - # 포트 매핑 + # 端口映射 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 환경 변수 + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 볼륨 매핑 + 볼륨 데이터 복구 + # 卷映射 + 卷数据恢复 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -8188,32 +8188,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "볼륨 데이터 복구:$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 기존이지만 실행되지 않는 컨테이너 삭제 + # 删除已存在但未运行的容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${gl_bai}" + echo -e "${gl_huang}容器 [$container] 存在但未运行,删除旧容器...${gl_bai}" docker rm -f "$container" fi - # 컨테이너 시작 - echo "복원 명령을 실행합니다: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 启动容器 + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}공통 컨테이너에 대한 백업 정보가 없습니다.${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" - # /home/docker 아래의 파일 복원 + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${gl_kjlan}/home/docker 아래의 파일을 복원하는 중...${gl_bai}" + echo -e "${gl_kjlan}正在还原 /home/docker 下的文件...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${gl_lv}/home/docker 아래의 파일이 복원되었습니다.${gl_bai}" + echo -e "${gl_lv}/home/docker 下的文件已还原完成${gl_bai}" else - echo -e "${gl_huang}/home/docker 아래의 파일 백업을 찾을 수 없습니다. 건너뛰는 중...${gl_bai}" + echo -e "${gl_huang}未找到 /home/docker 下文件的备份,跳过...${gl_bai}" fi @@ -8221,68 +8221,68 @@ docker_ssh_migration() { # ---------------------------- - # 이주하다 + # 迁移 # ---------------------------- migrate_docker() { - send_stats "도커 마이그레이션" + send_stats "Docker迁移" install jq - read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } + read -e -p "请输入要迁移的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } - kj_ssh_read_host_user_port "대상 서버 IP:" "대상 서버 SSH 사용자 이름 [기본 루트]:" "대상 서버 SSH 포트 [기본값 22]:" "root" "22" + kj_ssh_read_host_user_port "目标服务器IP: " "目标服务器SSH用户名 [默认root]: " "目标服务器SSH端口 [默认22]: " "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" - echo -e "${gl_huang}백업 전송 중...${gl_bai}" + echo -e "${gl_huang}传输备份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 使用密钥登录 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 백업 삭제 + # 删除备份 # ---------------------------- delete_backup() { - send_stats "Docker 백업 파일 삭제" - read -e -p "삭제할 백업 디렉터리를 입력하십시오:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } + send_stats "Docker备份文件删除" + read -e -p "请输入要删除的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${gl_lv}삭제된 백업:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}已删除备份: ${BACKUP_DIR}${gl_bai}" } # ---------------------------- - # 메인 메뉴 + # 主菜单 # ---------------------------- main_menu() { - send_stats "Docker 백업 마이그레이션 복원" + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" - echo -e "Docker 백업/마이그레이션/복원 도구" + echo -e "Docker备份/迁移/还原工具" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 도커 프로젝트 백업" - echo -e "2. 도커 프로젝트 마이그레이션" - echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "1. 备份docker项目" + echo -e "2. 迁移docker项目" + echo -e "3. 还原docker项目" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" - echo -e "0. 이전 메뉴로 돌아가기" + echo -e "0. 返回上一级选单" echo "------------------------" - read -e -p "선택하세요:" choice + read -e -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${gl_hong}잘못된 옵션${gl_bai}" ;; + *) echo -e "${gl_hong}无效选项${gl_bai}" ;; esac break_end done @@ -8299,38 +8299,38 @@ linux_docker() { while true; do clear - # send_stats "도커 관리" - echo -e "도커 관리" + # send_stats "docker管理" + echo -e "Docker管理" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경 설치 및 업데이트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}Docker 전역 상태 보기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" - echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" - echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" + echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너를 정리하고 네트워크 데이터 볼륨을 미러링하세요." + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스 변경" - echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}Docker-ipv6 액세스 활성화" - echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 액세스 끄기" + echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" + echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}Docker 환경 백업/마이그레이션/복원" - echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경 제거" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "도커 환경 설치" + send_stats "安装docker环境" install_add_docker ;; @@ -8341,22 +8341,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "도커 전역 상태" - echo "도커 버전" + send_stats "docker全局状态" + echo "Docker版本" docker -v docker compose version echo "" - echo -e "도커 이미지:${gl_lv}$image_count${gl_bai} " + echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "도커 컨테이너:${gl_lv}$container_count${gl_bai}" + echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker 볼륨:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "도커 네트워크:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8371,15 +8371,15 @@ linux_docker() { 5) while true; do clear - send_stats "도커 네트워크 관리" - echo "도커 네트워크 목록" + send_stats "Docker网络管理" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" + printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -8396,36 +8396,36 @@ linux_docker() { done echo "" - echo "네트워크 운영" + echo "网络操作" echo "------------------------" - echo "1. 네트워크 생성" - echo "2. 네트워크에 가입하세요" - echo "3. 네트워크 종료" - echo "4. 네트워크 삭제" + echo "1. 创建网络" + echo "2. 加入网络" + echo "3. 退出网络" + echo "4. 删除网络" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "네트워크 생성" - read -e -p "새 네트워크 이름 설정:" dockernetwork + send_stats "创建网络" + read -e -p "设置新网络名: " dockernetwork docker network create $dockernetwork ;; 2) - send_stats "네트워크에 가입하세요" - read -e -p "네트워크 이름 추가:" dockernetwork - read -e -p "네트워크에 참여하는 컨테이너(여러 컨테이너 이름을 공백으로 구분하세요):" dockernames + send_stats "加入网络" + read -e -p "加入网络名: " dockernetwork + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "네트워크에 가입하세요" - read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + send_stats "加入网络" + read -e -p "退出网络名: " dockernetwork + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8434,8 +8434,8 @@ linux_docker() { ;; 4) - send_stats "네트워크 삭제" - read -e -p "삭제할 네트워크 이름을 입력하세요:" dockernetwork + send_stats "删除网络" + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -8449,29 +8449,29 @@ linux_docker() { 6) while true; do clear - send_stats "도커 볼륨 관리" - echo "도커 볼륨 목록" + send_stats "Docker卷管理" + echo "Docker卷列表" docker volume ls echo "" - echo "볼륨 작업" + echo "卷操作" echo "------------------------" - echo "1. 새 볼륨 생성" - echo "2. 지정된 볼륨 삭제" - echo "3. 모든 볼륨 삭제" + echo "1. 创建新卷" + echo "2. 删除指定卷" + echo "3. 删除所有卷" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "새 볼륨 생성" - read -e -p "새 볼륨 이름 설정:" dockerjuan + send_stats "新建卷" + read -e -p "设置新卷名: " dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8480,7 +8480,7 @@ linux_docker() { ;; 3) - send_stats "모든 볼륨 삭제" + send_stats "删除所有卷" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8489,7 +8489,7 @@ linux_docker() { [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8502,7 +8502,7 @@ linux_docker() { ;; 7) clear - send_stats "도커 정리" + send_stats "Docker清理" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8511,13 +8511,13 @@ linux_docker() { [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 8) clear - send_stats "도커 소스" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -8533,13 +8533,13 @@ linux_docker() { 11) clear - send_stats "도커 v6 켜짐" + send_stats "Docker v6 开" docker_ipv6_on ;; 12) clear - send_stats "도커 v6 닫기" + send_stats "Docker v6 关" docker_ipv6_off ;; @@ -8550,7 +8550,7 @@ linux_docker() { 20) clear - send_stats "도커 제거" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8562,7 +8562,7 @@ linux_docker() { [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8571,7 +8571,7 @@ linux_docker() { kejilion ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -8588,158 +8588,158 @@ linux_test() { while true; do clear - # send_stats "테스트 스크립트 수집" - echo -e "테스트 스크립트 수집" + # send_stats "测试脚本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 잠금 해제 상태 감지" - echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" - echo -e "${gl_kjlan}3. ${gl_bai}예우 스트리밍 미디어 잠금 해제 감지" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 품질 확인 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP及解锁状态检测" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}네트워크 회선 속도 테스트" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 3 네트워크 백홀 지연 라우팅 테스트" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 삼중 네트워크 백홀 회선 테스트" - echo -e "${gl_kjlan}13. ${gl_bai}초고속 트리플 네트워크 속도 테스트" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 세 개의 네트워크 라인 테스트" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 네트워크 품질 확인 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}网络线路测速" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}하드웨어 성능 테스트" - echo -e "${gl_kjlan}21. ${gl_bai}Yabs 성능 테스트" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU 성능 테스트 스크립트" + echo -e "${gl_kjlan}硬件性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}종합적인 테스트" - echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 퓨전 몬스터 평가${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}Nodequality 융합 몬스터 평가${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪测评 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT 잠금 해제 상태 감지" + send_stats "ChatGPT解锁状态检测" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "지역 스트리밍 미디어 잠금 해제 테스트" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "예우 스트리밍 미디어 잠금 해제 감지" + send_stats "yeahwu流媒体解锁检测" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP 품질 확인 스크립트" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace 삼중 네트워크 백홀 지연 라우팅 테스트" + send_stats "besttrace三网回程延迟路由测试" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace 삼중 네트워크 백홀 회선 테스트" + send_stats "mtr_trace三网回程线路测试" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "초고속 트리플 네트워크 속도 테스트" + send_stats "Superspeed三网测速" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace 빠른 백홀 테스트 스크립트" + send_stats "nxtrace快速回程测试脚本" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." - echo "참조 IP 목록" + send_stats "nxtrace指定IP回程测试脚本" + echo "可参考的IP列表" echo "------------------------" - echo "베이징 통신: 219.141.136.12" - echo "베이징 유니콤: 202.106.50.1" - echo "베이징 모바일: 221.179.155.161" - echo "상하이 통신: 202.96.209.133" - echo "상하이 유니콤: 210.22.97.1" - echo "상하이 모바일: 211.136.112.200" - echo "광저우 통신: 58.60.188.222" - echo "광저우 차이나 유니콤: 210.21.196.6" - echo "광저우 모바일: 120.196.165.24" - echo "청두통신: 61.139.2.69" - echo "청두 차이나 유니콤: 119.6.6.6" - echo "청두 모바일: 211.137.96.205" - echo "후난 통신: 36.111.200.100" - echo "후난 유니콤: 42.48.16.100" - echo "후난 모바일: 39.134.254.6" + echo "北京电信: 219.141.136.12" + echo "北京联通: 202.106.50.1" + echo "北京移动: 221.179.155.161" + echo "上海电信: 202.96.209.133" + echo "上海联通: 210.22.97.1" + echo "上海移动: 211.136.112.200" + echo "广州电信: 58.60.188.222" + echo "广州联通: 210.21.196.6" + echo "广州移动: 120.196.165.24" + echo "成都电信: 61.139.2.69" + echo "成都联通: 119.6.6.6" + echo "成都移动: 211.137.96.205" + echo "湖南电信: 36.111.200.100" + echo "湖南联通: 42.48.16.100" + echo "湖南移动: 39.134.254.6" echo "------------------------" - read -e -p "특정 IP를 입력하세요:" testip + read -e -p "输入一个指定IP: " testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020 세 개의 네트워크 라인 테스트" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc 다기능 속도 테스트 스크립트" + send_stats "i-abc多功能测速脚本" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "네트워크 품질 테스트 스크립트" + send_stats "网络质量测试脚本" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "Yabs 성능 테스트" + send_stats "yabs性能测试" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU 성능 테스트 스크립트" + send_stats "icu/gb5 CPU性能测试脚本" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "벤치 성능 테스트" + send_stats "bench性能测试" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx 퓨전 몬스터 리뷰" + send_stats "spiritysdx融合怪测评" clear curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) - send_stats "Nodequality 융합 몬스터 평가" + send_stats "nodequality融合怪测评" clear bash <(curl -sL https://run.NodeQuality.com) ;; @@ -8751,7 +8751,7 @@ linux_test() { ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -8767,51 +8767,51 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud 스크립트 컬렉션" - echo -e "Oracle Cloud 스크립트 컬렉션" + send_stats "甲骨文云脚本合集" + echo -e "甲骨文云脚本合集" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}유휴 머신 활성 스크립트 설치" - echo -e "${gl_kjlan}2. ${gl_bai}유휴 컴퓨터에서 활성 스크립트 제거" + echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" + echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD 재설치 시스템 스크립트" - echo -e "${gl_kjlan}4. ${gl_bai}R 형사 시작 스크립트" - echo -e "${gl_kjlan}5. ${gl_bai}ROOT 비밀번호 로그인 모드 활성화" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6 복구 도구" + echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) clear - echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + echo "活跃脚本: CPU占用10-20% 内存占用20% " + read -e -p "确定安装吗?(Y/N): " choice case "$choice" in [Yy]) install_docker - # 기본값 설정 + # 设置默认值 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter 키를 누르면 기본값이 사용됩니다. - read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용량 백분율 범위(예: 10-20)를 입력하십시오. [기본값:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "메모리 사용량 비율을 입력하십시오.[기본값:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "속도 테스트 간격 시간(초)을 입력하십시오. [기본값:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Docker 컨테이너 실행 + # 运行Docker容器 docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -8819,14 +8819,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "Oracle Cloud 설치 활성 스크립트" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -8834,20 +8834,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "Oracle Cloud 제거 활성 스크립트" + send_stats "甲骨文云卸载活跃脚本" ;; 3) clear - echo "시스템 재설치" + echo "重装系统" echo "--------------------------------" - echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." - read -e -p "계속하시겠습니까? (예/아니요):" choice + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) while true; do - read -e -p "다시 설치하려는 시스템을 선택하십시오: 1. Debian12 | 2. 우분투20.04:" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -8859,28 +8859,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "선택이 잘못되었습니다. 다시 입력해 주세요." + echo "无效的选择,请重新输入。" ;; esac done - read -e -p "재설치 후 비밀번호를 입력해주세요:" vpspasswd + read -e -p "请输入你重装后的密码: " vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "Oracle Cloud 재설치 시스템 스크립트" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 4) clear - send_stats "R 형사 시작 스크립트" + send_stats "R探长开机脚本" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -8890,15 +8890,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 jhb에서 제공합니다. 감사합니다!" - send_stats "IPv6 수리" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; 0) kejilion ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -8922,7 +8922,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다.${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" fi } @@ -8943,7 +8943,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}대지:$output데이터 베이스:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" fi fi @@ -8971,31 +8971,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP 웹사이트 구축" - echo -e "${gl_huang}LDNMP 웹사이트 구축" + # send_stats "LDNMP建站" + echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경 설치${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼 설치${gl_huang}4. ${gl_bai}Kedao 클라우드 데스크탑 설치" - echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 TV 스테이션 설치${gl_huang}6. ${gl_bai}Unicorn 디지털 카드 네트워크 설치" - echo -e "${gl_huang}7. ${gl_bai}flarum 포럼 웹사이트 설치${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" - echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}맞춤 동적 사이트" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" + echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" - echo -e "${gl_huang}23. ${gl_bai}사이트 역방향 프록시-IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" - echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" - echo -e "${gl_huang}29. ${gl_bai}스트림 4계층 프록시 전달${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" + echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" + echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" - echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터 복원" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" + echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경 보호${gl_huang}36. ${gl_bai}LDNMP 환경 최적화" - echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경 업데이트${gl_huang}38. ${gl_bai}LDNMP 환경 제거" + echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -9009,10 +9009,10 @@ linux_ldnmp() { 3) clear - # 토론 포럼 - webname="토론 포럼" - send_stats "설치하다$webname" - echo "배포 시작$webname" + # Discuz论坛 + webname="Discuz论坛" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9040,21 +9040,21 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사: discuz_" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: discuz_" ;; 4) clear - # Kedao 클라우드 데스크탑 - webname="Kedao 클라우드 데스크탑" - send_stats "설치하다$webname" - echo "배포 시작$webname" + # 可道云桌面 + webname="可道云桌面" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9079,20 +9079,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름:$dbname" - echo "레디스 호스트: 레디스" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" + echo "redis主机: redis" ;; 5) clear - # AppleCMS - webname="AppleCMS" - send_stats "설치하다$webname" - echo "배포 시작$webname" + # 苹果CMS + webname="苹果CMS" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9123,24 +9123,24 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "데이터베이스 포트: 3306" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 접두사: mac_" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库前缀: mac_" echo "------------------------" - echo "설치가 성공적으로 완료되면 백엔드 주소로 로그인하세요." + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; 6) clear - # 한쪽다리 숫자카드 - webname="한쪽다리 숫자카드" - send_stats "설치하다$webname" - echo "배포 시작$webname" + # 独脚数卡 + webname="独脚数卡" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9167,34 +9167,34 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "데이터베이스 포트: 3306" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" echo "" - echo "레디스 주소 : 레디스" - echo "redis 비밀번호: 기본적으로 입력되지 않음" - echo "레디스 포트: 6379" + echo "redis地址: redis" + echo "redis密码: 默认不填写" + echo "redis端口: 6379" echo "" - echo "웹사이트 URL: https://$yuming" - echo "백엔드 로그인 경로: /admin" + echo "网站url: https://$yuming" + echo "后台登录路径: /admin" echo "------------------------" - echo "사용자 이름: 관리자" - echo "비밀번호: 관리자" + echo "用户名: admin" + echo "密码: admin" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." - echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" + echo "登录时右上角如果出现红色error0请使用如下命令: " + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # 플라럼 포럼 - webname="플라럼 포럼" - send_stats "설치하다$webname" - echo "배포 시작$webname" + # flarum论坛 + webname="flarum论坛" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9241,12 +9241,12 @@ linux_ldnmp() { ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사: flarum_" - echo "관리자 정보는 직접 설정 가능" + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: flarum_" + echo "管理员信息自行设置" ;; @@ -9254,8 +9254,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9285,11 +9285,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 접두사: typecho_" - echo "데이터베이스 주소: mysql" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "데이터베이스 이름:$dbname" + echo "数据库前缀: typecho_" + echo "数据库地址: mysql" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "数据库名: $dbname" ;; @@ -9298,8 +9298,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9328,18 +9328,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "데이터베이스 주소: mysql" - echo "데이터베이스 포트: 3306" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" + echo "数据库地址: mysql" + echo "数据库端口: 3306" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" ;; 20) clear - webname="PHP 동적 사이트" - send_stats "설치하다$webname" - echo "배포 시작$webname" + webname="PHP动态站点" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9359,10 +9359,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드 업로드" + echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" echo "-------------" - echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9372,20 +9372,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php가 위치한 경로" + echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/과 유사하게 index.php 경로를 입력하세요.$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택해주세요." + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" - read -e -p "1. PHP 최신 버전 | 2.php7.4:" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -9396,15 +9396,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "선택이 잘못되었습니다. 다시 입력해 주세요." + echo "无效的选择,请重新输入。" ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장 설치" + echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" echo "-------------" - echo "설치된 확장 프로그램" + echo "已经安装的扩展" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -9414,25 +9414,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" + echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" echo "-------------" - echo "계속하려면 아무 키나 누르세요. 의사정적 콘텐츠 등 사이트 구성을 세부적으로 설정할 수 있습니다." + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo ;; 2) - echo "데이터베이스 백업은 .gz로 끝나는 압축 패키지여야 합니다. Pagoda/1panel 백업 데이터 가져오기를 지원하려면 /home/ 디렉토리에 넣으십시오." - read -e -p "다운로드 링크를 입력하여 원격으로 백업 데이터를 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download_db + echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -9442,10 +9442,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "데이터베이스에서 가져온 테이블 데이터" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "데이터베이스 가져오기 완료" + echo "数据库导入完成" ;; *) echo @@ -9457,12 +9457,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "데이터베이스 주소: mysql" - echo "데이터베이스 이름:$dbname" - echo "사용자 이름:$dbuse" - echo "비밀번호:$dbusepasswd" - echo "테이블 접두사:$prefix" - echo "관리자 로그인 정보는 직접 설정합니다." + echo "数据库地址: mysql" + echo "数据库名: $dbname" + echo "用户名: $dbuse" + echo "密码: $dbusepasswd" + echo "表前缀: $prefix" + echo "管理员登录信息自行设置" ;; @@ -9474,11 +9474,11 @@ linux_ldnmp() { 22) clear - webname="사이트 리디렉션" - send_stats "설치하다$webname" - echo "배포 시작$webname" + webname="站点重定向" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - read -e -p "리디렉션 도메인 이름을 입력하세요." reverseproxy + read -e -p "请输入跳转域名: " reverseproxy nginx_install_status @@ -9505,7 +9505,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+포트가 서비스 접근을 차단했습니다." + echo "已阻止IP+端口访问该服务" else ip_address close_port "$port" @@ -9516,12 +9516,12 @@ linux_ldnmp() { 24) clear - webname="역방향 프록시 도메인 이름" - send_stats "설치하다$webname" - echo "배포 시작$webname" + webname="反向代理-域名" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming - echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + echo -e "域名格式: ${gl_huang}google.com${gl_bai}" + read -e -p "请输入你的反代域名: " fandai_yuming nginx_install_status install_ssltls @@ -9545,8 +9545,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming docker run -d \ @@ -9565,8 +9565,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "설치하다$webname" - echo "배포 시작$webname" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 @@ -9578,9 +9578,9 @@ linux_ldnmp() { 27) clear - webname="AI 그림 프롬프트 단어 생성기" - send_stats "설치하다$webname" - echo "배포 시작$webname" + webname="AI绘画提示词生成器" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming nginx_install_status @@ -9619,9 +9619,9 @@ linux_ldnmp() { 30) clear - webname="정적 사이트" - send_stats "설치하다$webname" - echo "배포 시작$webname" + webname="静态站点" + send_stats "安装$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming nginx_install_status @@ -9641,10 +9641,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드 업로드" + echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" echo "-------------" - echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" - read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9654,12 +9654,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html이 위치한 경로" + echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/과 유사하게 index.html 경로를 입력하세요.$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -9684,19 +9684,19 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP 환경 백업" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "생성된 백업 파일: /home/$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice + echo "备份文件已创建: /home/$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -9704,9 +9704,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "파일이 원격 서버 홈 디렉터리로 전송되었습니다." + echo "文件已传送至远程服务器home目录。" else - echo "전송할 파일을 찾을 수 없습니다." + echo "未找到要传送的文件。" fi break ;; @@ -9714,7 +9714,7 @@ linux_ldnmp() { break ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -9722,9 +9722,9 @@ linux_ldnmp() { 33) clear - send_stats "예약된 원격 백업" - read -e -p "원격 서버 IP를 입력하세요." useip - read -e -p "원격 서버 비밀번호를 입력하세요:" usepasswd + send_stats "定时远程备份" + read -e -p "输入远程服务器IP: " useip + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -9734,18 +9734,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 주간 백업 2. 일일 백업" - read -e -p "선택사항을 입력하세요:" dingshi + echo "1. 每周备份 2. 每天备份" + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) check_crontab_installed - read -e -p "주간 백업 요일을 선택합니다(0-6, 0은 일요일을 나타냄)." weekday + read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "일일 백업 시간 선택(시간, 0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -9759,19 +9759,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP 환경 복원" - echo "사용 가능한 사이트 백업" + send_stats "LDNMP环境还原" + echo "可用的站点备份" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -9781,7 +9781,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9789,7 +9789,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "압축된 패키지를 찾을 수 없습니다." + echo "没有找到压缩包。" fi ;; @@ -9807,11 +9807,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "LDNMP 환경 업데이트" - echo "LDNMP 환경 업데이트" + send_stats "更新LDNMP环境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v - echo "새 버전의 구성 요소가 발견되었습니다." + echo "发现新版本的组件" echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -9831,13 +9831,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. nginx 업데이트 2. mysql 업데이트 3. PHP 업데이트 4. redis 업데이트" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" - echo "5. 전체 환경 업데이트" + echo "5. 更新完整环境" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) nginx_upgrade @@ -9846,7 +9846,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 8.0 8.3 8.4 9.0)(최신 버전을 얻으려면 Enter 키를 누르세요):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version local version=${version:-latest} cd /home/web/ @@ -9857,13 +9857,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 3) local ldnmp_pods="php" - read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 7.4 8.0 8.1 8.2 8.3)(최신 버전을 얻으려면 Enter 키를 누르세요):" version + read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -9896,8 +9896,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 4) @@ -9907,15 +9907,15 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "고쳐 쓰다$ldnmp_pods" - echo "고쳐 쓰다${ldnmp_pods}마치다" + send_stats "更新$ldnmp_pods" + echo "更新${ldnmp_pods}完成" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "LDNMP 환경 전체 업데이트" + send_stats "完整更新LDNMP环境" cd /home/web/ docker compose down --rmi all @@ -9940,7 +9940,7 @@ linux_ldnmp() { 38) root_use - send_stats "LDNMP 환경 제거" + send_stats "卸载LDNMP环境" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -9954,7 +9954,7 @@ linux_ldnmp() { ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -9964,7 +9964,7 @@ linux_ldnmp() { ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" esac break_end @@ -9980,14 +9980,14 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "클로드봇/몰트봇 관리" + send_stats "clawdbot/moltbot管理" check_openclaw_update() { if ! command -v npm >/dev/null 2>&1; then return 1 fi - # --no-update-notifier를 추가하고 오류 리디렉션이 올바른 위치에 있는지 확인하세요. + # 加上 --no-update-notifier,并确保错误重定向位置正确 local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10001,26 +10001,26 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}새 버전이 감지되었습니다.$remote_version${gl_bai}" + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}현재 버전이 최신 버전입니다.$local_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } get_install_status() { if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}설치됨${gl_bai}" + echo "${gl_lv}已安装${gl_bai}" else - echo "${gl_hui}설치되지 않음${gl_bai}" + echo "${gl_hui}未安装${gl_bai}" fi } get_running_status() { if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then - echo "${gl_lv}달리기${gl_bai}" + echo "${gl_lv}运行中${gl_bai}" else - echo "${gl_hui}실행되지 않음${gl_bai}" + echo "${gl_hui}未运行${gl_bai}" fi } @@ -10035,33 +10035,33 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 관리" + echo -e "ClawdBot > MoltBot > OpenClaw 管理" echo -e "$install_status $running_status $update_message" echo "=======================================" - echo "1. 설치" - echo "2. 시작" - echo "3. 중지" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" echo "--------------------" - echo "4. 상태 로그 보기" - echo "5. 모델 변경" - echo "6. API 관리" - echo "7. 로봇 연결 및 도킹" - echo "8. 플러그인 관리(설치/제거)" - echo "9. 스킬 관리(설치/제거)" - echo "10. 기본 구성 파일 편집" - echo "11. 구성 마법사" - echo "12. 건강 상태 감지 및 복구" - echo "13. WebUI 접속 및 설정" - echo "14. TUI 명령줄 대화 상자 창" - echo "15. 기억/기억" + echo "4. 状态日志查看" + echo "5. 换模型" + echo "6. API管理" + echo "7. 机器人连接对接" + echo "8. 插件管理(安装/删除)" + echo "9. 技能管理(安装/删除)" + echo "10. 编辑主配置文件" + echo "11. 配置向导" + echo "12. 健康检测与修复" + echo "13. WebUI访问与设置" + echo "14. TUI命令行对话窗口" + echo "15. 记忆/Memory" echo "--------------------" - echo "16. 백업 및 복원" - echo "17. 업데이트" - echo "18. 제거" + echo "16. 备份与还原" + echo "17. 更新" + echo "18. 卸载" echo "--------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "--------------------" - printf "옵션을 입력하고 Enter를 누르십시오." + printf "请输入选项并回车: " } @@ -10139,36 +10139,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10199,7 +10169,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ API 제공업체가 감지되지 않음, 모델 동기화 건너뛰기') + print('ℹ️ 未检测到 API providers,跳过模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10267,7 +10237,7 @@ def collect_available_refs(exclude_provider=None): def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 프로브가 3번 연속 실패했습니다. 이 API 제공업체 및 모든 관련 모델을 삭제하시겠습니까? [예/아니요]:" + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " try: ans = input(prompt).strip().lower() except EOFError: @@ -10291,22 +10261,22 @@ def rebind_defaults_before_delete(name): if ref_provider(primary_ref) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: 기본 기본 모델이 이 공급자를 가리키지만 사용 가능한 대체 모델이 없어 삭제가 중단되었습니다.') + summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') return False set_primary_ref(defaults, repl) changed = True - summary.append(f'🔁 삭제 전에 기본 기본 모델이 전환되었습니다: {primary_ref} -> {repl}') + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk}가 공급자를 가리키지만 대체 모델을 사용할 수 없어 삭제가 중단되었습니다.') + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') return False defaults[fk] = repl changed = True - summary.append(f'🔁 삭제 전 전환됨 {fk}: {val} -> {repl}') + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') return True @@ -10327,40 +10297,10 @@ def delete_provider_and_refs(name): providers.pop(name, None) changed = True - summary.append(f'🗑️ 제공자 {name}이(가) 삭제되었으며 defaults.models 아래의 {len(removed_refs)} 모델 참조가 제거되었습니다.') + summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10385,7 +10325,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ {name} 건너뛰기: 공급자 구조가 불법입니다.') + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') continue api = provider.get('api', '') @@ -10394,44 +10334,34 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ {name} 건너뛰기: 없음 baseUrl/apiKey/models') + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 잘못된 프로토콜 {api 또는 "(unset)"}이 발견되어 다시 감지됩니다.') + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') provider['api'] = '' api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 프로토콜이 자동으로 {Detected_api}({Detected_reason})로 수정되었습니다.') - except Exception as e: - summary.append(f'⚠️ {name}: 프로토콜 감지 실패, 수정 건너뛰기 ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: - summary.append(f'⚠️ {name}: /models 감지 실패, {attempts} 번 재시도됨 ({type(err).__name__}: {err})') - send_stat('OpenClaw API 확인 개입') + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + send_stat('OpenClaw API确认介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: - send_stat('OpenClaw API 삭제 실패 공급자 확인') - summary.append(f'✅ {name}: 사용자가 공급자 및 모든 관련 모델 참조 삭제를 확인했습니다.') + send_stat('OpenClaw API删失败Provider-确认') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') else: - send_stat('OpenClaw API 삭제 실패 공급자 거부') - summary.append(f'ℹ️ {name}: 사용자가 삭제를 확인하지 않았으며 기존 공급자 구성을 유지합니다.') + send_stat('OpenClaw API删失败Provider-拒绝') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue if attempts > 1: - summary.append(f'🔁 {name}: /models {시도}번 재시도 후 성공') + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ {name} 건너뛰기: /models 반환 구조가 인식되지 않습니다.') + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') continue remote_ids = [] @@ -10441,7 +10371,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name}의 업스트림 /models가 비어 있으며 이 공급자에 대한 상향식 모델을 제공할 수 없습니다.') + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10453,21 +10383,12 @@ for name, provider in list(providers.items()): template = copy.deepcopy(m) break if template is None: - summary.append(f'⚠️ {name} 건너뛰기: 로컬 모델에 유효한 템플릿 모델이 없습니다.') + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') continue removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ 새 모델 추가({len(add_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 모델 삭제({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10479,7 +10400,7 @@ for name, provider in list(providers.items()): new_models.append(nm) if not new_models: - fatal_errors.append(f'❌ {name}은(는) 동기화 후 사용 가능한 모델이 없으며 기본 모델/폴백 모델을 보장할 수 없습니다.') + fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') continue expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -10491,14 +10412,14 @@ for name, provider in list(providers.items()): if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): set_primary_ref(defaults, first_ref) changed = True - summary.append(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if isinstance(val, str) and val in (local_refs - expected_refs): defaults[fk] = first_ref changed = True - summary.append(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') + summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] for r in stale_refs: @@ -10514,14 +10435,24 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(removed_ids)} 삭제, {len(add_ids)} 추가, 현재 {len(new_models)}') + summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + if fatal_errors: for line in summary: print(line) for err in fatal_errors: print(err) - print('❌ 모델 동기화 실패: 공급자가 있습니다. 동기화 후 사용 가능한 모델이 없으며 쓰기가 중단되었습니다.') + print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') raise SystemExit(2) if changed: @@ -10530,19 +10461,19 @@ if changed: f.write('\n') for line in summary: print(line) - print('✅ OpenClaw API 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: for line in summary: print(line) - print('ℹ️ 동기화가 필요하지 않습니다. 구성이 이미 업스트림/모델과 일치합니다.') + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } install_moltbot() { - echo "OpenClaw 설치를 시작합니다..." - send_stats "OpenClaw 설치를 시작합니다..." + echo "开始安装 OpenClaw..." + send_stats "开始安装 OpenClaw..." install_node_and_tools @@ -10551,13 +10482,13 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full - # 팁: 즉시 적용되도록 구성을 수정해야 하는 경우 게이트웨이를 다시 시작할 수 있습니다. openclaw Gateway restart + # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway add_app_id @@ -10567,23 +10498,23 @@ PY start_bot() { - echo "OpenClaw를 시작하는 중..." - send_stats "OpenClaw를 시작하는 중..." + echo "启动 OpenClaw..." + send_stats "启动 OpenClaw..." start_gateway break_end } stop_bot() { - echo "OpenClaw를 중지하세요..." - send_stats "OpenClaw를 중지하세요..." + echo "停止 OpenClaw..." + send_stats "停止 OpenClaw..." tmux kill-session -t gateway > /dev/null 2>&1 openclaw gateway stop break_end } view_logs() { - echo "OpenClaw 상태 로그 보기" - send_stats "OpenClaw 로그 보기" + echo "查看 OpenClaw 状态日志" + send_stats "查看 OpenClaw 日志" openclaw status openclaw gateway status openclaw logs @@ -10594,79 +10525,43 @@ PY - # OpenClaw API 프로토콜 감지(우선순위 응답 -> 완료) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" + # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 + # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" - return 0 - } - - # 핵심 기능: 모든 모델 가져오기 및 추가 + # 核心函数:获取并添加所有模型 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" local api_key="$3" local config_file="${HOME}/.openclaw/openclaw.json" - echo "🔍 받기$provider_name사용 가능한 모든 모델..." + echo "🔍 正在获取 $provider_name 的所有可用模型..." - # API 프로토콜 자동 식별 - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" - # 모델 목록 가져오기 + # 获取模型列表 local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ "${base_url}/models") if [[ -z "$models_json" ]]; then - echo "❌ 모델 목록을 가져올 수 없습니다" + echo "❌ 无法获取模型列表" return 1 fi - # 모든 모델 ID 추출 + # 提取所有模型ID local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') if [[ -z "$model_ids" ]]; then - echo "❌ 모델을 찾을 수 없습니다" + echo "❌ 未找到任何模型" return 1 fi local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 발견$model_count모델" + echo "✅ 发现 $model_count 个模型" - # 모델 매개변수의 지능적 추론 + # 智能推断模型参数 local models_array="[" local first=true @@ -10674,11 +10569,11 @@ PY [[ $first == false ]] && models_array+="," first=false - # context 및 max_tokens가 완전히 로드되었으므로 큰 문제를 두려워하지 않습니다. + # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - # 가격만 등급을 매겨야 합니다. + # 只有价格需要分级 local input_cost=0.15 local output_cost=0.60 @@ -10717,10 +10612,10 @@ EOF models_array+="]" - # 백업 구성 + # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # jq를 사용하여 모든 모델을 삽입하고 defaults.models를 동기화합니다. + # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10756,49 +10651,47 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" if [[ $? -eq 0 ]]; then - echo "✅ 성공적으로 추가되었습니다$model_count모델 도착$provider_name" - echo "📦 모델 참조 형식:$provider_name/" + echo "✅ 成功添加 $model_count 个模型到 $provider_name" + echo "📦 模型引用格式: $provider_name/" return 0 else - echo "❌ 구성 삽입 실패" + echo "❌ 配置注入失败" return 1 fi } add-openclaw-provider-interactive() { - send_stats "OpenClaw API가 추가되었습니다." - echo "=== 대화식으로 OpenClaw 공급자 추가(전체 모델) ===" + send_stats "OpenClaw API添加" + echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" - # 1. 제공자 이름 - read -erp "공급자 이름을 입력하십시오(예: deepseek):" provider_name + # 1. Provider 名称 + read -erp "请输入 Provider 名称 (如: deepseek): " provider_name while [[ -z "$provider_name" ]]; do - echo "❌ 제공업체 이름은 비워둘 수 없습니다." - read -erp "제공업체 이름을 입력하세요." provider_name + echo "❌ Provider 名称不能为空" + read -erp "请输入 Provider 名称: " provider_name done # 2. Base URL - read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url + read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url while [[ -z "$base_url" ]]; do - echo "❌ 기본 URL은 비워둘 수 없습니다." - read -erp "기본 URL을 입력하세요:" base_url + echo "❌ Base URL 不能为空" + read -erp "请输入 Base URL: " base_url done base_url="${base_url%/}" # 3. API Key - read -rsp "API 키를 입력하세요(입력은 표시되지 않습니다):" api_key + read -rsp "请输入 API Key (输入不显示): " api_key echo while [[ -z "$api_key" ]]; do - echo "❌ API 키는 비워둘 수 없습니다." - read -rsp "API 키를 입력하세요:" api_key + echo "❌ API Key 不能为空" + read -rsp "请输入 API Key: " api_key echo done - # 4. 프로토콜 탐지(의미 없음) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. 不再探测/判断 API 类型;协议由用户自行选择与维护 - # 5. 모델 목록 가져오기 - echo "🔍 사용 가능한 모델 목록을 가져오는 중..." + # 5. 获取模型列表 + echo "🔍 正在获取可用模型列表..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ "${base_url}/models") @@ -10808,9 +10701,9 @@ EOF if [[ -n "$available_models" ]]; then model_count=$(echo "$available_models" | wc -l) - echo "✅ 발견$model_count사용 가능한 모델:" + echo "✅ 发现 $model_count 个可用模型:" echo "--------------------------------" - # 일련번호와 함께 모두 표시 + # 全部显示,带序号 i=1 model_list=() while read -r model; do @@ -10822,33 +10715,33 @@ EOF fi fi - # 5. 기본 모델을 선택하세요 + # 5. 选择默认模型 echo - read -erp "기본 모델 ID(또는 일련번호, 첫 번째 번호를 사용하려면 비워 두세요)를 입력하세요." input_model + read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) - echo "🎯 첫 번째 모델 사용:$default_model" + echo "🎯 使用第一个模型: $default_model" elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then default_model="${model_list[$((input_model-1))]}" - echo "🎯 선택 모델:$default_model" + echo "🎯 已选择模型: $default_model" else default_model="$input_model" fi - # 6. 정보 확인 + # 6. 确认信息 echo - echo "====== 확인 ======" + echo "====== 确认信息 ======" echo "Provider : $provider_name" echo "Base URL : $base_url" echo "API Key : ${api_key:0:8}****" - echo "기본 모델:$default_model" - echo "총 모델 수:$model_count" + echo "默认模型 : $default_model" + echo "模型总数 : $model_count" echo "======================" - read -erp "모두 추가하려면 확인하세요.$model_count모델? (예/아니요):" confirm + read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 취소됨" + echo "❎ 已取消" return 1 fi @@ -10857,11 +10750,11 @@ EOF if [[ $? -eq 0 ]]; then echo - echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." + echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" start_gateway - echo "✅ 완료! 모두$model_count로드된 모델" - echo "✅ 계약은 자동으로 다음과 같이 식별되었습니다.$DETECTED_API" + echo "✅ 完成!所有 $model_count 个模型已加载" + echo "✅ 已自动识别协议为: $DETECTED_API" fi break_end @@ -10871,7 +10764,7 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API 목록" + send_stats "OpenClaw API列表" while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do case "$rec_type" in @@ -10887,7 +10780,7 @@ openclaw_api_manage_list() { unchecked) latency_color="$gl_bai" ;; esac - printf '%b\n' "[$idx] ${name} | API: ${base_url}| 합의:${api_type}| 모델 수:${gl_huang}${model_count}${gl_bai}| 지연/상태:${latency_color}${latency_txt}${gl_bai}" + printf '%b\n' "[$idx] ${name} | API: ${base_url} | 协议: ${api_type} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" ;; esac done < <(python3 - "$config_file" <<-'PY' @@ -10915,10 +10808,10 @@ def ping_models(base_url, api_key): def classify_latency(latency): - if latency == '사용할 수 없음': - return '사용할 수 없음', 'unavailable' - if latency == '감지되지 않음': - return '감지되지 않음', 'unchecked' + if latency == '不可用': + return '不可用', 'unavailable' + if latency == '未检测': + return '未检测', 'unchecked' if isinstance(latency, int): if latency <= 800: level = 'low' @@ -10934,25 +10827,25 @@ try: with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ openclaw.json을 찾을 수 없습니다. 먼저 설치/초기화를 완료하세요.') + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 구성을 읽지 못했습니다: {type(e).__name__}: {e}') + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 현재 구성된 API 제공업체가 없습니다.') + print('MSG\tℹ️ 当前未配置任何 API provider。') raise SystemExit(0) -print('MSG\t--- 구성된 API 목록 ---') +print('MSG\t--- 已配置 API 列表 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): provider = providers.get(name) if not isinstance(provider, dict): base_url = '-' model_count = 0 - latency_raw = '사용할 수 없음' + latency_raw = '不可用' else: base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' models = provider.get('models') if isinstance(provider.get('models'), list) else [] @@ -10960,15 +10853,15 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): api = provider.get('api', '') api_key = provider.get('apiKey') - latency_raw = '감지되지 않음' + latency_raw = '未检测' if api in SUPPORTED_APIS: if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: try: latency_raw = ping_models(base_url, api_key) except Exception: - latency_raw = '사용할 수 없음' + latency_raw = '不可用' else: - latency_raw = '사용할 수 없음' + latency_raw = '不可用' latency_text, latency_level = classify_latency(latency_raw) api_label = api if api in SUPPORTED_APIS else '-' @@ -10988,17 +10881,17 @@ PY } sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "공급자별 OpenClaw API 동기화" + send_stats "OpenClaw API按Provider同步" if [ ! -f "$config_file" ]; then - echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + echo "❌ 未找到配置文件: $config_file" break_end return 1 fi - read -erp "동기화할 API 이름(공급자)을 입력하세요." provider_name + read -erp "请输入要同步的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then - echo "❌ 제공업체 이름은 비워둘 수 없습니다." + echo "❌ provider 名称不能为空" break_end return 1 fi @@ -11016,35 +10909,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11052,12 +10916,12 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ API 제공업체가 감지되지 않아 동기화할 수 없습니다.') + print('❌ 未检测到 API providers,无法同步') raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 제공자: {target}을(를) 찾을 수 없습니다') + print(f'❌ 未找到 provider: {target}') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11124,31 +10988,21 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ 공급자 {target}에 baseUrl/apiKey/models가 누락되어 동기화를 수행할 수 없습니다.') + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ 공급자 {target} 현재 api={api}, 프로토콜을 다시 감지하고 계속합니다.') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 자동 수정된 프로토콜: {target} {api} ({Detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ 프로토콜 감지 실패, 수정 건너뛰기: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 감지 실패, {attempts}번 재시도됨 ({type(err).__name__}: {err})') + print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 반환된 구조가 인식되지 않습니다.') + print(f'❌ {target}: /models 返回结构不可识别') raise SystemExit(4) remote_ids = [] @@ -11157,7 +11011,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 업스트림 /models가 비어 있고 동기화가 중단되었습니다.') + print(f'❌ {target}: 上游 /models 为空,已中止同步') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11166,21 +11020,12 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 로컬 모델에 유효한 템플릿 모델이 없어 새 모델을 추가할 수 없습니다.') + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ 새 모델 추가({len(add_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ 모델 삭제({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11191,7 +11036,7 @@ for mid in added_ids: new_models.append(nm) if not new_models: - print(f'❌ {target}: 동기화 후 사용할 수 있는 모델이 없어 쓰기가 중단되었습니다.') + print(f'❌ {target}: 同步后无可用模型,已中止写入') raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -11204,14 +11049,14 @@ primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: set_primary_ref(defaults, first_ref) changed = True - print(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') + print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if isinstance(val, str) and val in removed_refs: defaults[fk] = first_ref changed = True - print(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') + print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: @@ -11227,40 +11072,48 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: {len(removed_ids)} 제거, {len(add_ids)} 추가, 현재 {len(new_models)}') +print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: - print('✅ 지정된 공급자 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 동기화가 필요하지 않습니다. 공급자 구성이 이미 업스트림/모델과 일치합니다.') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in 0) - echo "✅ 동기 실행 완료" + echo "✅ 同步执行完成" start_gateway ;; 2) - echo "❌ 동기화 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." + echo "❌ 同步失败:provider 不存在或未配置" ;; 3) - echo "❌ 동기화 실패: 공급자 구성이 불완전하거나 유형이 지원되지 않습니다." + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) - echo "❌ 동기화 실패: 업스트림 /models 요청 실패" + echo "❌ 同步失败:上游 /models 请求失败" ;; 5) - echo "❌ 동기화 실패: 업스트림 모델이 비어 있거나 동기화 후 사용 가능한 모델이 없습니다." + echo "❌ 同步失败:上游模型为空或同步后无可用模型" ;; *) - echo "❌ 동기화 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + echo "❌ 同步失败:请检查配置文件结构或日志输出" ;; esac @@ -11268,115 +11121,91 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ openclaw.json을 찾을 수 없습니다') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ 공급자 {name}에 baseUrl/apiKey가 없습니다.') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 업데이트된 공급자 {name} 프로토콜: {current_api 또는 "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ 업데이트가 필요하지 않습니다. 프로토콜은 {current_api 또는 api}로 유지됩니다.') -PY + # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 + # 保留函数以兼容菜单调用,但不做任何改写。 + echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + return 0 } fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API 프로토콜 수정" + send_stats "OpenClaw API协议切换" if [ ! -f "$config_file" ]; then - echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + echo "❌ 未找到配置文件: $config_file" break_end return 1 fi - read -erp "복구할 프로토콜의 API 이름(공급자)을 입력하세요." provider_name + read -erp "请输入要切换协议的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then - echo "❌ 제공업체 이름은 비워둘 수 없습니다." + echo "❌ provider 名称不能为空" break_end return 1 fi - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "请选择要设置的 API 类型:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "请输入你的选择 (1/2): " proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ 无效选择" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ 非法协议值') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ 已更新 provider {name} 协议为: {new_api}') +PY local rc=$? case "$rc" in 0) - echo "✅본 계약은 테스트 및 업데이트되었습니다(변경될 수 있음)." start_gateway ;; 2) - echo "❌ 복구 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." + echo "❌ 切换失败:provider 不存在或未配置" ;; 3) - echo "❌ 복구 실패: 공급자 구성이 불완전합니다." + echo "❌ 切换失败:协议值非法" ;; *) - echo "❌ 복구 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + echo "❌ 切换失败:请检查配置文件结构或日志输出" ;; esac @@ -11385,18 +11214,18 @@ fix-openclaw-provider-protocol-interactive() { delete-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API 삭제 항목" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then - echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" + echo "❌ 未找到配置文件: $config_file" break_end return 1 fi - read -erp "삭제할 API 이름(공급자)을 입력하세요." provider_name + read -erp "请输入要删除的 API 名称(provider): " provider_name if [ -z "$provider_name" ]; then - send_stats "OpenClaw API 삭제 취소" - echo "❌ 제공업체 이름은 비워둘 수 없습니다." + send_stats "OpenClaw API删除取消" + echo "❌ provider 名称不能为空" break_end return 1 fi @@ -11416,7 +11245,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') + print(f'❌ 未找到 provider: {name}') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11483,19 +11312,19 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 삭제가 중단됨: 기본 기본 모델이 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') raise SystemExit(3) set_primary_ref(defaults, replacement) - print(f'🔁 기본 기본 모델 전환: {primary_ref} -> {replacement}') + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if ref_provider(val) == name: if not replacement: - print(f'❌ 삭제가 중단되었습니다. {fk}가 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') + print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 스위치: {val} -> {교체}') + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11507,25 +11336,25 @@ with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'🗑️ 삭제된 제공자: {name}') -print(f'🧹 defaults.models에서 {len(removed_refs)} 관련 모델 참조를 정리했습니다.') +print(f'🗑️ 已删除 provider: {name}') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') PY local rc=$? case "$rc" in 0) - send_stats "OpenClaw API 삭제 확인" - echo "✅삭제 완료" + send_stats "OpenClaw API删除确认" + echo "✅ 删除完成" start_gateway ;; 2) - echo "❌ 삭제 실패: 공급자가 존재하지 않습니다." + echo "❌ 删除失败:provider 不存在" ;; 3) - send_stats "OpenClaw API 삭제 취소" - echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." + send_stats "OpenClaw API删除取消" + echo "❌ 删除失败:无可用替代模型,已保持原配置" ;; *) - echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + echo "❌ 删除失败:请检查配置文件结构或日志输出" ;; esac @@ -11533,21 +11362,21 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw API 입구" + send_stats "OpenClaw API入口" while true; do clear echo "=======================================" - echo "OpenClaw API 관리" + echo "OpenClaw API 管理" echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. API 추가" - echo "2. API 제공자 모델 목록 동기화" - echo "3. API 삭제" - echo "4. 프로토콜 복구/재감지" - echo "0. 종료" + echo "1. 添加API" + echo "2. 同步API供应商模型列表" + echo "3. 切换 API 类型(completions / responses)" + echo "4. 删除API" + echo "0. 退出" echo "---------------------------------------" - read -erp "선택사항을 입력하세요:" api_choice + read -erp "请输入你的选择: " api_choice case "$api_choice" in 1) @@ -11557,16 +11386,16 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive ;; 0) return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -11608,7 +11437,7 @@ REPO change_model() { - send_stats "모델 변경" + send_stats "换模型" local orange="#FF8C00" @@ -11617,23 +11446,23 @@ REPO while true; do local models_raw models_list default_model model_count selected_model - # 구성 파일에서 모델 키 읽기(openclaw 모델 목록을 호출하지 않고) + # 从配置文件读取模型键(不调用 openclaw models list) local oc_config oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "모델 목록을 가져오지 못했습니다. 구성 파일에서 Agent.defaults.models를 찾을 수 없습니다." + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi - # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # 구성 파일에서 기본 모델을 읽습니다(더 빠름). 실패 시 openclaw 명령으로 대체 + # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" @@ -11643,40 +11472,40 @@ REPO clear - # 껌이 없을 경우 기존 수동입력 과정으로 다운그레이드 (기존과 동일하게 유지) + # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) if ! command -v gum >/dev/null 2>&1; then - echo "---모델 관리 ---" - echo "현재 사용 가능한 모델:" + echo "--- 模型管理 ---" + echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model - # 1. 0을 입력하여 종료했는지 확인하세요. + # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then - echo "작업이 취소되었습니다. 종료하는 중..." + echo "操作已取消,正在退出..." break # 跳出 while 循环 fi - # 2. 입력이 비어 있는지 확인하십시오. + # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then - echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "错误:模型名称不能为空。请重试。" echo "" # 换行美化 continue # 跳过本次循环,重新开始 fi else - gum style --foreground "$orange" --bold "모델 관리" - gum style --foreground "$orange" "사용 가능한 모델(인증=예):${model_count}" - gum style --foreground "$orange" "현재 기본값:${default_model}" + gum style --foreground "$orange" --bold "模型管理" + gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" + gum style --foreground "$orange" "当前默认:${default_model}" echo "" - # 하단 팁 - gum style --faint "↑↓ 선택/Enter를 눌러 확인/Esc를 눌러 종료" + # 底部提示 + gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" echo "" - # 껌 필터: 검색 포함; 껌 버전은 매우 다양하며 여기서는 가장 호환되는 플래그만 사용됩니다. + # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags selected_model=$(echo "$models_list" | gum filter \ - --placeholder "검색 모델(예: cli-api/gpt-5.2)" \ - --prompt "모델 선택 >" \ + --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ + --prompt "选择模型 > " \ --indicator "➜ " \ --prompt.foreground "$orange" \ --indicator.foreground "$orange" \ @@ -11686,18 +11515,18 @@ REPO --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then - echo "작업이 취소되었습니다. 종료하는 중..." + echo "操作已取消,正在退出..." break fi fi - # 숫자 접두사 제거: "(10) model" -> "model" + # 去掉编号前缀:"(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # 스위치 실행 - echo "전환되는 모델은 다음과 같습니다.$selected_model ..." + # 执行切换 + echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "切换失败:openclaw models set 返回错误。" break_end return 1 fi @@ -11744,7 +11573,7 @@ REPO | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then - echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" return 0 fi rm -f "$tmp_json" @@ -11782,12 +11611,12 @@ data['plugins'] = plugins config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') PYTHON_EOF then - echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" return 0 fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" return 1 } @@ -11815,7 +11644,7 @@ PYTHON_EOF | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) | .plugins.allow = (.plugins.allow | map(select(. != $pid))) ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then - echo "✅plugins.allow에서 제거됨:$plugin_id" + echo "✅ 已从 plugins.allow 移除: $plugin_id" return 0 fi rm -f "$tmp_json" @@ -11851,12 +11680,12 @@ data['plugins'] = plugins config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') PYTHON_EOF then - echo "✅plugins.allow에서 제거됨:$plugin_id" + echo "✅ 已从 plugins.allow 移除: $plugin_id" return 0 fi fi - echo "⚠️plugins.allow 제거에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" return 1 } @@ -11866,45 +11695,45 @@ PYTHON_EOF install_plugin() { - send_stats "플러그인 관리" + send_stats "插件管理" while true; do clear echo "========================================" - echo "플러그인 관리(설치/제거)" + echo " 插件管理 (安装/删除) " echo "========================================" - echo "현재 플러그인 목록:" + echo "当前插件列表:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "推荐的常用插件 ID (直接复制括号内的 ID 即可):" echo "--------------------------------------------------------" - echo "📱 커뮤니케이션 채널:" - echo "- [feishu] # 페이슈/종달새 통합" - echo "- [텔레그램] # 텔레그램 봇" - echo "- [slack] #Slack 기업 커뮤니케이션" + echo "📱 通讯渠道:" + echo " - [feishu] # 飞书/Lark 集成" + echo " - [telegram] # Telegram 机器人" + echo " - [slack] # Slack 企业通讯" echo " - [msteams] # Microsoft Teams" - echo "- [디스코드] # 디스코드 커뮤니티 관리" - echo "- [whatsapp] #WhatsApp 자동화" + echo " - [discord] # Discord 社区管理" + echo " - [whatsapp] # WhatsApp 自动化" echo "" - echo "🧠 메모리와 AI:" - echo "- [memory-core] # 기본 메모리(파일 검색)" - echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" - echo "- [copilot-proxy] # Copilot 인터페이스 전달" + echo "🧠 记忆与 AI:" + echo " - [memory-core] # 基础记忆 (文件检索)" + echo " - [memory-lancedb] # 增强记忆 (向量数据库)" + echo " - [copilot-proxy] # Copilot 接口转发" echo "" - echo "⚙️ 기능 확장:" - echo "- [랍스터] # 승인 흐름(수동 확인 포함)" - echo "- [음성통화] # 음성통화 기능" - echo "- [nostr] # 암호화된 비공개 채팅" + echo "⚙️ 功能扩展:" + echo " - [lobster] # 审批流 (带人工确认)" + echo " - [voice-call] # 语音通话能力" + echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" - echo "1) 플러그인 설치/활성화" - echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" - read -e -p "작업을 선택하십시오:" plugin_action + echo "1) 安装/启用插件" + echo "2) 删除/禁用插件" + echo "0) 返回" + read -e -p "请选择操作:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue - read -e -p "플러그인 ID를 입력하십시오(공백으로 구분, 종료하려면 0 입력)." raw_input + read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue @@ -11922,12 +11751,12 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인 중:$plugin_id" + echo "🔍 正在检查插件状态: $plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." + echo "💡 插件 [$plugin_id] 已预装,正在激活..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -11939,7 +11768,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -11950,10 +11779,10 @@ PYTHON_EOF continue fi - echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요.$plugin_full" + echo "📥 本地未发现,尝试下载安装: $plugin_full" rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ 다운로드 성공, 활성화 중..." + echo "✅ 下载成功,正在启用..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -11962,16 +11791,16 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 설치 실패:$plugin_full" + echo "❌ 安装失败:$plugin_full" failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 플러그인 제거/비활성화:$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then - echo "✅ 제거됨:$plugin_id" + echo "✅ 已卸载: $plugin_id" else - echo "⚠️ 제거에 실패했습니다. 사전 설치된 플러그인일 수 있습니다. 다음만 비활성화하세요.$plugin_id" + echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -11980,13 +11809,13 @@ PYTHON_EOF done echo "" - echo "====== 작업 요약 ======" - echo "✅ 성공:$success_list" - [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway fi break_end @@ -11995,43 +11824,43 @@ PYTHON_EOF install_skill() { - send_stats "스킬 관리" + send_stats "技能管理" while true; do clear echo "========================================" - echo "스킬 관리(설치/제거)" + echo " 技能管理 (安装/删除) " echo "========================================" - echo "현재 설치된 스킬:" + echo "当前已安装技能:" openclaw skills list echo "----------------------------------------" - # 추천 실기 목록 출력 - echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" - echo "github # GitHub 문제/PR/CI 관리(gh CLI)" - echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." - echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" - echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" - echo "1password # 1Password 키 읽기 및 삽입 자동화" - echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" - echo "things-mac # Things 3 작업 관리의 심층 통합" - echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." - echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" - echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" - echo "openhue # Philips Hue 스마트 조명 장면 제어" - echo "video-frames # 비디오 프레임 추출 및 짧은 클립 편집(ffmpeg 드라이버)" - echo "openai-whisper # 로컬 오디오를 텍스트로 변환(오프라인 개인 정보 보호)" - echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." + # 输出推荐的实用技能列表 + echo "推荐的实用技能(可直接复制名称输入):" + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 页面、数据库和块" + echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" + echo "apple-reminders # macOS 提醒事项管理 (待办清单)" + echo "1password # 自动化读取和注入 1Password 密钥" + echo "gog # Google Workspace (Gmail/云盘/文档) 全能助手" + echo "things-mac # 深度整合 Things 3 任务管理" + echo "bluebubbles # 通过 BlueBubbles 完美收发 iMessage" + echo "himalaya # 终端邮件管理 (IMAP/SMTP 强力工具)" + echo "summarize # 网页/播客/YouTube 视频内容一键总结" + echo "openhue # 控制 Philips Hue 智能灯光场景" + echo "video-frames # 视频抽帧与短片剪辑 (ffmpeg 驱动)" + echo "openai-whisper # 本地音频转文字 (离线隐私保护)" + echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" echo "----------------------------------------" - echo "1) 설치 기술" - echo "2) 스킬 삭제" - echo "0) 반품" - read -e -p "작업을 선택하십시오:" skill_action + echo "1) 安装技能" + echo "2) 删除技能" + echo "0) 返回" + read -e -p "请选择操作:" skill_action [ "$skill_action" = "0" ] && break [ -z "$skill_action" ] && continue - read -e -p "스킬 이름을 입력하십시오(공백으로 구분, 종료하려면 0 입력):" skill_input + read -e -p "请输入技能名称(空格分隔,输入 0 退出): " skill_input [ "$skill_input" = "0" ] && break [ -z "$skill_input" ] && continue @@ -12042,9 +11871,9 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. 계속하시겠습니까? (예/아니요):" confirm_del + read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续?(y/N): " confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then - echo "삭제가 취소되었습니다." + echo "已取消删除。" break_end continue fi @@ -12058,53 +11887,53 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 스킬 [$skill_name]는 사용자 디렉토리에 설치됩니다." + echo "💡 技能 [$skill_name] 已在用户目录安装。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 스킬 [$skill_name]는 시스템 디렉토리에 설치됩니다." + echo "💡 技能 [$skill_name] 已在系统目录安装。" skill_found=true fi if [ "$skill_found" = true ]; then - read -e -p "스킬 [$skill_name] 이미 설치되어 있습니다. 다시 설치하시겠습니까? (예/아니요):" reinstall + read -e -p "技能 [$skill_name] 已安装,是否重新安装?(y/N): " reinstall if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then skipped_list="$skipped_list $skill_name" continue fi fi - echo "기술 설치:$skill_name ..." + echo "正在安装技能:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then - echo "✅ 스킬$skill_name설치가 성공했습니다." + echo "✅ 技能 $skill_name 安装成功。" success_list="$success_list $skill_name" changed=true else - echo "❌ 설치 실패:$skill_name" + echo "❌ 安装失败:$skill_name" failed_list="$failed_list $skill_name" fi else - echo "🗑️ 스킬 삭제:$skill_name" + echo "🗑️ 正在删除技能: $skill_name" npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" - echo "✅ 사용자 스킬 디렉토리가 삭제되었습니다:$skill_name" + echo "✅ 已删除用户技能目录: $skill_name" success_list="$success_list $skill_name" changed=true else - echo "⏭️ 사용자 스킬 디렉터리를 찾을 수 없습니다:$skill_name" + echo "⏭️ 未发现用户技能目录: $skill_name" skipped_list="$skipped_list $skill_name" fi fi done echo "" - echo "====== 작업 요약 ======" - echo "✅ 성공:$success_list" - [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" + echo "====== 操作汇总 ======" + echo "✅ 成功:$success_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway fi break_end @@ -12155,10 +11984,10 @@ openclaw_json_get_bool() { return 0 fi - # 두 가지 일반적인 디렉터리 이름과 호환됩니다. + # 兼容两种常见目录命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. + # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12171,15 +12000,15 @@ openclaw_json_get_bool() { local connected="$3" local abnormal="$4" if [ "$abnormal" = "true" ]; then - echo "이상" + echo "异常" elif [ "$enabled" != "true" ]; then - echo "활성화되지 않음" + echo "未启用" elif [ "$connected" = "true" ]; then - echo "연결됨" + echo "已连接" elif [ "$configured" = "true" ]; then - echo "구성된" + echo "已配置" else - echo "구성되지 않음" + echo "未配置" fi } @@ -12296,9 +12125,9 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") - echo "로컬 상태(로컬 구성/캐시만, 네트워크 감지 없음):" + echo "本地状态(仅本机配置/缓存,不做网络探测):" openclaw_print_bot_status_line "Telegram" "$tg_status" - openclaw_print_bot_status_line "종달새" "$feishu_status" + openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" openclaw_print_bot_status_line "WhatsApp" "$wa_status" openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" @@ -12306,41 +12135,41 @@ openclaw_json_get_bool() { } change_tg_bot_code() { - send_stats "로봇 도킹" + send_stats "机器人对接" while true; do clear echo "========================================" - echo "로봇 연결 및 도킹" + echo " 机器人连接对接 " echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" - echo "1. 텔레그램 로봇 도킹" - echo "2. Feishu(Lark) 로봇 도킹" - echo "3. WhatsApp 봇 도킹" + echo "1. Telegram 机器人对接" + echo "2. 飞书 (Lark) 机器人对接" + echo "3. WhatsApp 机器人对接" echo "----------------------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "----------------------------------------" - read -e -p "선택사항을 입력하세요:" bot_choice + read -e -p "请输入你的选择: " bot_choice case $bot_choice in 1) - read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi openclaw pairing approve telegram "$code" break_end ;; 2) - read -e -p "Feishu Robot이 수신한 연결 코드(예: NYA99R2F)를 입력하십시오(종료하려면 0을 입력하십시오)." code + read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi openclaw pairing approve feishu "$code" break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "请输入WhatsApp收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" break_end ;; @@ -12348,7 +12177,7 @@ openclaw_json_get_bool() { return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -12446,10 +12275,10 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "백업 파일은 다음 방법을 사용하여 다운로드할 수 있습니다." - echo "- 로컬 경로:$file_path" - echo "- scp 예: scp root@yourserver:$file_path ./" - echo "- 또는 SFTP 클라이언트를 사용하여 다운로드" + echo "可使用以下方式下载备份文件:" + echo "- 本地路径: $file_path" + echo "- scp 示例: scp root@你的服务器:$file_path ./" + echo "- 或使用 SFTP 客户端下载" } openclaw_prepare_import_archive() { @@ -12457,9 +12286,9 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 파일이 존재하지 않습니다:$archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } mkdir -p "$unpack_root" - tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 백업 패키지의 압축을 풀지 못했습니다."; return 1; } + tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 备份包解压失败"; return 1; } local pkg_dir="$unpack_root/package" if [ -f "$unpack_root/backup.meta" ]; then @@ -12467,27 +12296,27 @@ EOF fi for required in backup.meta manifest.files manifest.sha256 payload; do - [ -e "$pkg_dir/$required" ] || { echo "❌ 백업 패키지에 필요한 파일이 없습니다:$required"; return 1; } + [ -e "$pkg_dir/$required" ] || { echo "❌ 备份包缺少必要文件: $required"; return 1; } done local real_type real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) if [ "$real_type" != "$expected_type" ]; then - echo "❌ 백업 유형 불일치 예상:$expected_type, 실제: ${real_type:-unknown}" + echo "❌ 备份类型不匹配,期望: $expected_type,实际: ${real_type:-未知}" return 1 fi ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 확인이 실패하고 복원이 거부되었습니다."; return 1; } + ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } echo "$pkg_dir" return 0 } openclaw_memory_backup_export() { - send_stats "OpenClaw 메모리 전체 백업" + send_stats "OpenClaw记忆全量备份" local workspace_dir="${HOME}/.openclaw/workspace" local backup_root backup_root=$(openclaw_backup_root) @@ -12497,7 +12326,7 @@ EOF mkdir -p "$backup_root" if [ ! -d "$workspace_dir" ]; then - echo "❌ 작업공간 디렉터리를 찾을 수 없습니다:$workspace_dir" + echo "❌ 未找到 workspace 目录: $workspace_dir" break_end return 1 fi @@ -12508,7 +12337,7 @@ EOF [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - read -e -p "AGENTS/USER/SOUL/TOOLS 파일과 함께 제공됩니까? (예/아니요):" include_optional + read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional if [[ "$include_optional" =~ ^[Yy]$ ]]; then for f in AGENTS.md USER.md SOUL.md TOOLS.md; do [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" @@ -12516,17 +12345,17 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 백업 메모리 파일이 없습니다." + echo "❌ 未找到可备份的记忆文件" rm -rf "$tmp_payload" break_end return 1 fi if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 전체 메모리 백업 완료:$out_file" + echo "✅ 记忆全量备份完成: $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ 전체 메모리 백업 실패" + echo "❌ 记忆全量备份失败" fi rm -rf "$tmp_payload" @@ -12538,10 +12367,10 @@ EOF local file_input file_path backup_root echo "$prompt_text" >&2 - echo "먼저 scp/sftp를 통해 서버에 백업 패키지를 업로드한 후 경로를 입력할 수 있습니다." >&2 - echo "scp 예: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 - echo "팁: 파일 이름을 입력하면 기본적으로 백업 디렉터리에서 검색됩니다. /가 포함된 경로를 입력하면 전체 경로로 확인됩니다." >&2 - read -e -p "백업 파일 이름이나 경로를 입력하십시오:" file_input + echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 + echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 + echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 + read -e -p "请输入备份文件名或路径: " file_input [ -z "$file_input" ] && { echo ""; return 0; } backup_root=$(openclaw_backup_root) @@ -12554,7 +12383,7 @@ EOF fi if [ ! -f "$file_path" ]; then - echo "❌ 백업 파일이 존재하지 않습니다:$file_path" >&2 + echo "❌ 备份文件不存在: $file_path" >&2 echo "" return 1 fi @@ -12563,13 +12392,13 @@ EOF } openclaw_memory_backup_import() { - send_stats "OpenClaw 메모리 전체 복원" + send_stats "OpenClaw记忆全量还原" local workspace_dir="${HOME}/.openclaw/workspace" mkdir -p "$workspace_dir" local archive_path - archive_path=$(openclaw_read_import_path "복원 전 유형 확인 + sha256 확인 + 경로 화이트리스트 확인이 수행됩니다.") - [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } + archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack tmp_unpack=$(mktemp -d) || return 1 @@ -12582,7 +12411,7 @@ EOF while IFS= read -r rel; do [ -z "$rel" ] && continue if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" + echo "❌ 检测到非法或越权路径: $rel" invalid=1 break fi @@ -12592,7 +12421,7 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi @@ -12605,23 +12434,23 @@ EOF rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ 메모리 전체 복구 완료" + echo "✅ 记忆全量还原完成" break_end } openclaw_project_backup_export() { - send_stats "OpenClaw 프로젝트 백업" + send_stats "OpenClaw项目备份" local openclaw_root="${HOME}/.openclaw" if [ ! -d "$openclaw_root" ]; then - echo "❌ OpenClaw 루트 디렉터리를 찾을 수 없습니다:$openclaw_root" + echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" break_end return 1 fi - echo "백업 모드:" - echo "1. 안전 모드(기본값, 권장): 작업 공간 + openclaw.json + 확장/기술/프롬프트/도구(존재하는 경우)" - echo "2. 전체 모드(더 많은 상태 포함, 더 높은 민감도 위험)" - read -e -p "백업 모드를 선택하십시오(기본값 1):" export_mode + echo "备份模式:" + echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "2. 完整模式(含更多状态,敏感风险更高)" + read -e -p "请选择备份模式(默认 1): " export_mode [ -z "$export_mode" ] && export_mode="1" local mode_label="safe" @@ -12646,7 +12475,7 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 백업 가능한 OpenClaw 프로젝트 콘텐츠가 없습니다." + echo "❌ 未找到可备份的 OpenClaw 项目内容" rm -rf "$tmp_payload" break_end return 1 @@ -12658,10 +12487,10 @@ EOF local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then - echo "✅ OpenClaw 프로젝트 백업 완료 (${mode_label}): $out_file" + echo "✅ OpenClaw 项目备份完成 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 프로젝트 백업 실패" + echo "❌ OpenClaw 项目备份失败" fi rm -rf "$tmp_payload" @@ -12669,22 +12498,22 @@ EOF } openclaw_project_backup_import() { - send_stats "OpenClaw 프로젝트 복원" + send_stats "OpenClaw项目还原" local openclaw_root="${HOME}/.openclaw" mkdir -p "$openclaw_root" - echo "⚠️ 고위험 작업: 프로젝트 복원은 OpenClaw 구성 및 작업 공간 콘텐츠를 덮어씁니다." - echo "⚠️ 복원 전 매니페스트/sha256 확인, 화이트리스트 복원, 게이트웨이 종료 및 상태 점검이 수행됩니다." - read -e -p "계속하려면 확인 단어 [위험도가 높다는 것을 알고 있으며 복원을 계속합니다]를 입력하십시오." confirm_text - if [ "$confirm_text" != "위험성이 높다는 것을 인지하고 복원을 계속하고 있습니다." ]; then - echo "❌ 확인문자가 일치하지 않아 복원이 취소되었습니다." + echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" + echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text + if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then + echo "❌ 确认词不匹配,已取消还原" break_end return 1 fi local archive_path - archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요") - [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } + archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") + [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } local tmp_unpack tmp_unpack=$(mktemp -d) || return 1 @@ -12697,7 +12526,7 @@ EOF while IFS= read -r rel; do [ -z "$rel" ] && continue if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then - echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" + echo "❌ 检测到非法或越权路径: $rel" invalid=1 break fi @@ -12707,14 +12536,14 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 还原中止:存在不安全路径" break_end return 1 fi if command -v openclaw >/dev/null 2>&1; then - echo "⏸️ 복원하기 전에 OpenClaw 게이트웨이를 중지하세요..." + echo "⏸️ 还原前停止 OpenClaw gateway..." openclaw gateway stop >/dev/null 2>&1 fi @@ -12724,27 +12553,27 @@ EOF done < "$valid_list" if command -v openclaw >/dev/null 2>&1; then - echo "▶️ 복원 후 OpenClaw 게이트웨이를 시작하세요..." + echo "▶️ 还原后启动 OpenClaw gateway..." openclaw gateway start >/dev/null 2>&1 sleep 2 - echo "🩺 게이트웨이 상태 점검:" + echo "🩺 gateway 健康检查:" openclaw gateway status || true fi rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw 프로젝트 복원 완료" + echo "✅ OpenClaw 项目还原完成" break_end } openclaw_backup_detect_type() { local file_name="$1" if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then - echo "메모리 백업 파일" + echo "记忆备份文件" elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then - echo "프로젝트 백업 파일" + echo "项目备份文件" else - echo "기타 백업 파일" + echo "其他备份文件" fi } @@ -12762,27 +12591,27 @@ EOF backup_root=$(openclaw_backup_root) openclaw_backup_collect_files - echo "백업 디렉터리:$backup_root" + echo "备份目录: $backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "아직 백업 파일이 없습니다" + echo "暂无备份文件" return 0 fi for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in - "메모리 백업 파일") has_memory=1 ;; - "프로젝트 백업 파일") has_project=1 ;; - "기타 백업 파일") has_other=1 ;; + "记忆备份文件") has_memory=1 ;; + "项目备份文件") has_project=1 ;; + "其他备份文件") has_other=1 ;; esac done if [ "$has_memory" -eq 1 ]; then - echo "메모리 백업 파일" + echo "记忆备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "메모리 백업 파일" ] && continue + [ "$file_type" != "记忆备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12791,11 +12620,11 @@ EOF fi if [ "$has_project" -eq 1 ]; then - echo "프로젝트 백업 파일" + echo "项目备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "프로젝트 백업 파일" ] && continue + [ "$file_type" != "项目备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12804,11 +12633,11 @@ EOF fi if [ "$has_other" -eq 1 ]; then - echo "기타 백업 파일" + echo "其他备份文件" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "기타 백업 파일" ] && continue + [ "$file_type" != "其他备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12827,7 +12656,7 @@ EOF } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw删除备份文件" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -12837,14 +12666,14 @@ EOF return 0 fi - read -e -p "삭제할 파일 이름이나 전체 경로를 입력하십시오. (취소하려면 0):" user_input + read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input if [ "$user_input" = "0" ]; then - echo "삭제가 취소되었습니다." + echo "已取消删除。" break_end return 0 fi if [ -z "$user_input" ]; then - echo "❌ 입력은 비워둘 수 없습니다." + echo "❌ 输入不能为空。" break_end return 1 fi @@ -12855,7 +12684,7 @@ EOF case "$target_path" in "$backup_root_real"/*) ;; *) - echo "❌ 경로 초과: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." + echo "❌ 路径越界:仅允许删除备份根目录内的文件。" break_end return 1 ;; @@ -12867,37 +12696,37 @@ EOF fi if [ ! -f "$target_path" ]; then - echo "❌ 대상 파일이 존재하지 않습니다:$target_path" + echo "❌ 目标文件不存在: $target_path" break_end return 1 fi if ! openclaw_backup_file_exists_in_list "$target_file"; then - echo "❌ 현재 백업 목록에 대상 파일이 없습니다." + echo "❌ 目标文件不在当前备份列表中。" break_end return 1 fi target_type=$(openclaw_backup_detect_type "$target_file") - echo "삭제 예정: [$target_type] $target_path" - read -e -p "첫 번째 확인: 확인하고 계속하려면 yes를 입력하세요." confirm_step1 + echo "即将删除: [$target_type] $target_path" + read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then - echo "삭제가 취소되었습니다." + echo "已取消删除。" break_end return 0 fi - read -e -p "보조 확인: 삭제하려면 DELETE를 입력하세요." confirm_step2 + read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then - echo "삭제가 취소되었습니다." + echo "已取消删除。" break_end return 0 fi if rm -f -- "$target_path"; then - echo "✅ 삭제 성공:$target_file" + echo "✅ 删除成功: $target_file" else - echo "❌ 삭제 실패:$target_file" + echo "❌ 删除失败: $target_file" fi break_end } @@ -12962,21 +12791,21 @@ EOF store_raw=$(openclaw_memory_status_value "Store") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ 인덱스 라이브러리 파일을 찾을 수 없습니다. 비어 있거나 존재하지 않을 수 있습니다." - echo "원시 값 저장: ${store_raw:-}" - echo "재인덱싱은 계속 수행됩니다." + echo "⚠️ 未找到索引库文件,可能为空或不存在。" + echo " Store 原始值: ${store_raw:-<空>}" + echo " 仍将执行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ 백업된 인덱스:$backup_file" + echo "✅ 已备份索引: $backup_file" else - echo "⚠️ 인덱스 백업에 실패했습니다. 계속 재구축하세요." + echo "⚠️ 索引备份失败,继续重建。" fi fi openclaw memory index --force openclaw gateway restart - echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 索引已重建并自动重启网关" echo "" openclaw_memory_render_status } @@ -12985,12 +12814,12 @@ EOF local workspace memory_dir workspace=$(openclaw_memory_status_value "Workspace") if [ -z "$workspace" ]; then - echo "⚠️ 작업공간 경로를 가져오지 못했습니다. 디렉터리 복구를 건너뜁니다." + echo "⚠️ 未能获取 Workspace 路径,跳过目录修复。" return 1 fi memory_dir="$workspace/memory" if [ ! -d "$memory_dir" ]; then - echo "🔧 메모리 디렉터리가 존재하지 않으며 자동으로 생성되었습니다.$memory_dir" + echo "🔧 记忆目录不存在,已自动创建: $memory_dir" mkdir -p "$memory_dir" fi return 0 @@ -13000,11 +12829,11 @@ EOF local status_output status_lines config_file config_display status_output=$(openclaw memory status 2>/dev/null) if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "상태를 가져오지 못했습니다." + echo "获取状态失败" else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^공급자: /기본 솔루션: /' -e 's/^벡터: /벡터 라이브러리 상태: /' -e 's/^색인: /포함된 파일: /') + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') if [ -z "$status_lines" ]; then - echo "설치되지 않음/시작되지 않음" + echo "未安装/未启动" else echo "$status_lines" fi @@ -13083,26 +12912,26 @@ EOF OPENCLAW_MEMORY_RECOMMEND_REASON=() if [ "$qmd_ok" = "true" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") fi if [ -n "$model_path" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로:$model_path") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路径: $model_path") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로가 구성되지 않았습니다.") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路径") fi case "$model_status" in - ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재합니다.") ;; - hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("모델은 HF 다운로드 소스에서 제공됩니다(중국에서는 느리거나 실패할 수 있음).") ;; - *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재하지 않거나 사용할 수 없습니다.") ;; + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co에 액세스할 수 있습니다.") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") elif [ "$mirror_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可访问") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可达(疑似国内/受限网络)") fi if [ "$qmd_ok" = "true" ]; then @@ -13179,19 +13008,19 @@ EOF wget -O "$dest" "$url" return $? fi - echo "❌ Curl이나 wget이 감지되지 않아 다운로드할 수 없습니다." + echo "❌ 未检测到 curl 或 wget,无法下载。" return 1 } openclaw_memory_check_sqlite() { if ! command -v sqlite3 >/dev/null 2>&1; then - echo "⚠️ sqlite3이 감지되지 않으면 QMD가 제대로 작동하지 않을 수 있습니다." + echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" return 1 fi local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') - echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." + echo "✅ sqlite3 可用: ${ver:-unknown}" + echo "ℹ️ sqlite 扩展支持无法可靠检测,将继续。" return 0 } @@ -13200,26 +13029,26 @@ EOF export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ 롤빵이 이미 존재합니다" + echo "✅ bun 已存在" return 0 fi - echo "⬇️ 번 설치..." + echo "⬇️ 安装 bun..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 未检测到 curl 或 wget,无法安装 bun。" return 1 fi if [ -d "$HOME/.bun/bin" ]; then export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ 번 설치 완료" + echo "✅ bun 安装完成" return 0 fi - echo "❌ 번 설치 실패" + echo "❌ bun 安装失败" return 1 } @@ -13227,57 +13056,57 @@ EOF local qmd_path qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd가 이미 존재합니다:$qmd_path" + echo "✅ qmd 已存在: $qmd_path" OPENCLAW_MEMORY_QMD_PATH="$qmd_path" return 0 fi openclaw_memory_ensure_bun || return 1 local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ 롤빵을 통해 qmd를 설치합니다:$qmd_url" + echo "⬇️ 通过 bun 安装 qmd: $qmd_url" bun install -g "$qmd_url" qmd_path=$(command -v qmd 2>/dev/null || true) if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then qmd_path="$HOME/.bun/bin/qmd" fi if [ -z "$qmd_path" ]; then - echo "❌ qmd 설치 실패" + echo "❌ qmd 安装失败" return 1 fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - echo "✅ qmd 설치 완료:$qmd_path" + echo "✅ qmd 安装完成: $qmd_path" return 0 } openclaw_memory_render_auto_summary() { echo "---------------------------------------" - echo "✅ 환경 준비" - echo "구성표: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + echo "✅ 环境就绪" + echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "모드: 쓰기 구성만(설치되지 않음/다운로드되지 않음)" + echo "模式: 仅写配置(未安装/未下载)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "색인: 실행됨" + echo "索引: 已执行" else - echo "색인: 건너뛰었습니다." + echo "索引: 已跳过" fi if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then - echo "다시 시작: 실행됨" + echo "重启: 已执行" else - echo "다시 시작: 건너뛰었습니다." + echo "重启: 已跳过" fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" fi if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then - echo "모델:$OPENCLAW_MEMORY_MODEL_PATH" + echo "模型: $OPENCLAW_MEMORY_MODEL_PATH" fi if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then - echo "영역:$OPENCLAW_MEMORY_COUNTRY" + echo "地区: $OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then - echo "다운로드 소스:$OPENCLAW_MEMORY_HF_BASE" + echo "下载源: $OPENCLAW_MEMORY_HF_BASE" fi - echo "최종 상태:" + echo "最终状态:" openclaw_memory_render_status echo "---------------------------------------" } @@ -13287,22 +13116,22 @@ EOF OPENCLAW_MEMORY_PREHEAT="true" OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" - echo "자동 배포가 곧 수행됩니다(상세 모드)." - echo "목표 계획:$scheme_label" - echo "지역: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "미러 소스 감지:huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" - echo "다운로드 소스: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + echo "即将执行自动部署(详细模式)" + echo "目标方案: $scheme_label" + echo "地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then - echo "예상 다운로드 경로:$OPENCLAW_MEMORY_EXPECT_PATH" + echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" fi if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then - echo "가능한 트래픽/디스크 사용량:$OPENCLAW_MEMORY_EXPECT_SIZE" + echo "可能流量/磁盘占用: $OPENCLAW_MEMORY_EXPECT_SIZE" else - echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" + echo "可能流量/磁盘占用: 视实际情况而定" fi - echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." - echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." - read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" + read -e -p "输入 yes 确认继续(默认 N): " confirm_step case "$confirm_step" in yes|YES) OPENCLAW_MEMORY_PREHEAT="true" @@ -13312,20 +13141,20 @@ EOF OPENCLAW_MEMORY_PREHEAT="false" ;; *) - echo "자동 배포가 취소되었습니다." + echo "已取消自动部署。" return 1 ;; esac if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "⚠️ 설치나 다운로드 없이 구성만 작성하도록 선택됨" + echo "⚠️ 已选择仅写配置,不安装不下载" else - echo "✅ 인덱스가 자동으로 구축되고 게이트웨이가 다시 시작됩니다." + echo "✅ 将自动构建索引并重启网关" fi return 0 } openclaw_memory_auto_setup_qmd() { - echo "🔍 QMD 환경 감지" + echo "🔍 检测 QMD 环境" openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then @@ -13340,46 +13169,46 @@ EOF local backend backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ]; then - echo "✅ memory.backend는 이미 qmd입니다." + echo "✅ memory.backend 已是 qmd" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ memory.backend=qmd가 설정되었습니다" + echo "✅ 已设置 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" - echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" + echo "✅ 已写入 memory.qmd.command: $OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command 已正确" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 따뜻한 지수(모델 다운로드 가능)" + echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace openclaw memory index --force else - echo "⏭️ 예열 생략" + echo "⏭️ 已跳过预热" fi - echo "✅ QMD 자동 배포 완료" + echo "✅ QMD 自动部署完成" } openclaw_memory_auto_setup_local() { - echo "🔍 로컬 환경 감지" + echo "🔍 检测 Local 环境" openclaw_memory_cleanup_legacy_keys local backend provider backend=$(openclaw_memory_get_backend) if [ "$backend" = "builtin" ] || [ "$backend" = "local" ]; then - echo "✅ memory.backend는 이미 내장되어 있습니다." + echo "✅ memory.backend 已是 builtin" else openclaw_memory_config_set "memory.backend" "builtin" - echo "✅ memory.backend=builtin이 설정되었습니다." + echo "✅ 已设置 memory.backend=builtin" fi provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") if [ "$provider" = "local" ]; then - echo "✅ memorySearch.provider는 이미 로컬입니다." + echo "✅ memorySearch.provider 已是 local" else openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" - echo "✅ Agents.defaults.memorySearch.provider=로컬 세트" + echo "✅ 已设置 agents.defaults.memorySearch.provider=local" fi local model_path model_status @@ -13387,7 +13216,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ 모델 파일이 이미 존재합니다:$model_path" + echo "✅ 模型文件已存在: $model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -13395,29 +13224,29 @@ EOF local model_dest="$model_dir/$model_name" local model_url="${OPENCLAW_MEMORY_HF_BASE}/ggml-org/embeddinggemma-300M-GGUF/resolve/main/$model_name" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "ℹ️ 쓰기 전용 구성 모드: 모델 다운로드 건너뛰기" + echo "ℹ️ 仅写配置模式:跳过模型下载" OPENCLAW_MEMORY_MODEL_PATH="$model_dest" else if [ -f "$model_dest" ]; then - echo "✅ 기본 모델 파일이 발견되었습니다:$model_dest" + echo "✅ 已发现默认模型文件: $model_dest" else - echo "⬇️ 다운로드 모델:$model_url" + echo "⬇️ 下载模型: $model_url" openclaw_memory_download_file "$model_url" "$model_dest" || return 1 - echo "✅ 모델이 다운로드되었습니다:$model_dest" + echo "✅ 模型已下载: $model_dest" fi OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" - echo "✅ 모델 경로가 작성되었습니다" + echo "✅ 已写入模型路径" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 따뜻한 지수(모델 다운로드 가능)" + echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace openclaw memory index --force else - echo "⏭️ 예열 생략" + echo "⏭️ 已跳过预热" fi - echo "✅ 로컬 자동 배포가 완료되었습니다" + echo "✅ Local 自动部署完成" } openclaw_memory_auto_setup_run() { @@ -13436,16 +13265,16 @@ EOF case "$scheme" in qmd) scheme_label="QMD" - OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun(qmd 설치 디렉토리)" - OPENCLAW_MEMORY_EXPECT_SIZE="약 20-50MB" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安装目录)" + OPENCLAW_MEMORY_EXPECT_SIZE="约 20-50MB" ;; local) scheme_label="Local" OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.openclaw/models/embedding/embeddinggemma-300M-Q8_0.gguf" - OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" + OPENCLAW_MEMORY_EXPECT_SIZE="约 350-600MB" ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 未知方案: $scheme" return 1 ;; esac @@ -13461,7 +13290,7 @@ EOF openclaw_memory_render_auto_summary return 0 fi - echo "♻️ OpenClaw 게이트웨이 다시 시작" + echo "♻️ 重启 OpenClaw 网关" if declare -F start_gateway >/dev/null 2>&1; then start_gateway else @@ -13476,14 +13305,14 @@ EOF while true; do clear echo "=======================================" - echo "메모리 솔루션 자동 배포" + echo "记忆方案自动部署" echo "=======================================" echo "1. QMD" echo "2. Local" - echo "3. 자동(자동 선택)" - echo "0. 이전 레벨로 돌아갑니다" + echo "3. Auto(自动选择)" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" auto_choice + read -e -p "请输入你的选择: " auto_choice case "$auto_choice" in 1) openclaw_memory_auto_setup_run "qmd" @@ -13501,7 +13330,7 @@ EOF return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -13515,7 +13344,7 @@ EOF qmd) openclaw_memory_config_set "memory.backend" "qmd" if [ $? -ne 0 ]; then - echo "❌ 구성을 쓰지 못했습니다." + echo "❌ 写入配置失败" return 1 fi openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 @@ -13523,24 +13352,24 @@ EOF local) openclaw_memory_config_set "memory.backend" "builtin" if [ $? -ne 0 ]; then - echo "❌ 구성을 쓰지 못했습니다." + echo "❌ 写入配置失败" return 1 fi openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 未知方案: $scheme" return 1 esac - echo "✅ 메모리 체계 구성이 업데이트되었습니다." + echo "✅ 已更新记忆方案配置" return 0 } openclaw_memory_offer_restart() { - echo "구성이 작성되었으며 OpenClaw 게이트웨이를 다시 시작한 후 적용하려면 다시 시작해야 합니다." - read -e -p "지금 OpenClaw Gateway를 다시 시작하시겠습니까? (예/아니요):" restart_choice + echo "配置已写入,需要重启 OpenClaw 网关后生效。" + read -e -p "是否立即重启 OpenClaw 网关?(Y/n): " restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then - echo "다시 시작을 건너뛰었습니다. 나중에 수행할 수 있습니다. openclaw 게이트웨이 다시 시작" + echo "已跳过重启,可稍后执行: openclaw gateway restart" return 0 fi if declare -F start_gateway >/dev/null 2>&1; then @@ -13554,29 +13383,29 @@ EOF local backend backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then - echo "⚠️ 현재 구성표는 QMD로 감지되지만 qmd 명령은 설치되지 않습니다." - echo "로컬로 전환하거나 bun + qmd를 설치하고 다시 시도할 수 있습니다." + echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" + echo " 可切换 Local,或安装 bun + qmd 后再试。" fi - echo "적용 가능한 시나리오: 인덱스 분자 > 분모(반복된 수집으로 인해 비정상적인 계산이 발생함)" - read -e -p "includeDefaultMemory를 false로 설정하셨나요? (예/아니요):" confirm_fix + echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" + read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "취소." + echo "已取消。" break_end return 0 fi openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false if [ $? -ne 0 ]; then - echo "❌ 구성을 쓰지 못했습니다." + echo "❌ 写入配置失败" break_end return 1 fi - echo "✅ includeDefaultMemory=false 설정" - echo "권장 실행: 인덱스 정리 및 재구축" - read -e -p "인덱스를 정리하고 다시 작성하시겠습니까(권장)? (예/아니요):" rebuild_choice + echo "✅ 已设置 includeDefaultMemory=false" + echo "推荐执行:清理并重建索引" + read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then openclaw_memory_rebuild_index_safe else - echo "상태는 나중에 메모리 관리에서 볼 수 있습니다." + echo "可稍后在记忆管理中查看状态。" fi break_end } @@ -13585,27 +13414,27 @@ EOF while true; do clear echo "=======================================" - echo "OpenClaw 메모리 솔루션" + echo "OpenClaw 记忆方案" echo "=======================================" local backend current_label backend=$(openclaw_memory_get_backend) case "$backend" in qmd) current_label="QMD" ;; builtin|local) current_label="Local" ;; - *) current_label="구성되지 않음" ;; + *) current_label="未配置" ;; esac - echo "현재 계획:$current_label" + echo "当前方案: $current_label" echo "" - echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" - echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" + echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" + echo "Local: 本地向量检索,依赖 embedding 模型文件" + echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" - echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" - echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" - echo "3. 자동(자동 추천 및 자동 배포)" - echo "0. 이전 레벨로 돌아갑니다" + echo "1. 切换 QMD(自动部署/已装则跳过)" + echo "2. 切换 Local(自动部署/已装则跳过)" + echo "3. Auto(自动推荐并自动部署)" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" scheme_choice + read -e -p "请输入你的选择: " scheme_choice case "$scheme_choice" in 1) openclaw_memory_auto_setup_run "qmd" @@ -13623,7 +13452,7 @@ EOF return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -13647,10 +13476,10 @@ EOF local base_dir="${HOME}/.openclaw/workspace" openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then - echo "메모리 파일을 찾을 수 없습니다." + echo "未找到记忆文件。" return 0 fi - echo "번호 | 상대 경로 | 크기 | 수정 시간" + echo "编号 | 相对路径 | 大小 | 修改时间" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do @@ -13665,17 +13494,17 @@ EOF openclaw_memory_view_file() { local file="$1" [ -f "$file" ] || { - echo "❌ 파일이 존재하지 않습니다:$file" + echo "❌ 文件不存在: $file" return 1 } local total_lines total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) local default_lines=120 local start_line count - echo "문서:$file" - echo "총 행 수:$total_lines" - read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + echo "文件: $file" + echo "总行数: $total_lines" + read -e -p "请输入起始行(回车默认末尾 $default_lines 行): " start_line + read -e -p "请输入显示行数(回车默认 $default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -13685,14 +13514,14 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 숫자를 입력하세요." + echo "❌ 请输入有效的数字。" return 1 fi if [ "$start_line" -lt 1 ]; then start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ 행 개수는 0보다 커야 합니다." + echo "❌ 行数必须大于 0。" return 1 fi local end_line=$((start_line + count - 1)) @@ -13700,7 +13529,7 @@ EOF end_line=$total_lines fi if [ "$total_lines" -eq 0 ]; then - echo "(빈 파일)" + echo "(空文件)" return 0 fi echo "---------------------------------------" @@ -13712,71 +13541,71 @@ EOF while true; do clear echo "=======================================" - echo "OpenClaw 메모리 파일" + echo "OpenClaw 记忆文件" echo "=======================================" openclaw_memory_file_render_list echo "---------------------------------------" - read -e -p "보려는 파일 번호를 입력하십시오(0을 반환)." file_choice + read -e -p "请输入文件编号查看(0 返回): " file_choice if [ "$file_choice" = "0" ]; then return 0 fi if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 continue fi openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then - read -p "메모리 파일을 찾을 수 없습니다. 돌아가려면 Enter를 누르세요..." + read -p "未找到记忆文件,按回车返回..." return 0 fi local idx=$((file_choice-1)) if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then - echo "잘못된 번호입니다. 다시 시도해 주세요." + echo "无效的编号,请重试。" sleep 1 continue fi openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" - read -p "목록으로 돌아가려면 Enter를 누르세요..." + read -p "按回车返回列表..." done } openclaw_memory_menu() { - send_stats "OpenClaw 메모리 관리" + send_stats "OpenClaw记忆管理" while true; do clear echo "=======================================" - echo "OpenClaw 메모리 관리" + echo "OpenClaw 记忆管理" echo "=======================================" openclaw_memory_render_status - echo "1. 메모리 인덱스 업데이트" - echo "2. 메모리 파일 보기" - echo "3. 인덱스 복구(인덱스 예외)" - echo "4. 메모리 솔루션(QMD/Local/Auto)" - echo "0. 이전 레벨로 돌아갑니다" + echo "1. 更新记忆索引" + echo "2. 查看记忆文件" + echo "3. 索引修复(Indexed 异常)" + echo "4. 记忆方案(QMD/Local/Auto)" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" memory_choice + read -e -p "请输入你的选择: " memory_choice case "$memory_choice" in 1) - echo "메모리 인덱스는 곧 업데이트될 예정입니다." - read -e -p "첫 번째 확인: 계속하려면 yes를 입력하세요." confirm_step1 + echo "即将更新记忆索引。" + read -e -p "第一次确认:输入 yes 继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then - echo "취소." + echo "已取消。" break_end continue fi openclaw_memory_prepare_workspace - read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 + read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 if [ "$confirm_step2" = "force" ]; then - echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." - read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 + echo "⚠️ 全量重建更彻底,但耗时更长。" + echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" + read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_safe else openclaw memory index --force openclaw gateway restart - echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 索引已重建并自动重启网关" fi else openclaw memory index @@ -13796,7 +13625,7 @@ EOF return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -13805,22 +13634,22 @@ EOF openclaw_backup_restore_menu() { - send_stats "OpenClaw 백업 및 복원" + send_stats "OpenClaw备份与还原" while true; do clear echo "=======================================" - echo "OpenClaw 백업 및 복원" + echo "OpenClaw 备份与还原" echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" - echo "1. 메모리 전체를 백업하세요" - echo "2. 전체 메모리 복원" - echo "3. OpenClaw 프로젝트 백업(기본 안전 모드)" - echo "4. OpenClaw 프로젝트 복원(고급/고위험)" - echo "5. 백업 파일 삭제" - echo "0. 이전 레벨로 돌아갑니다" + echo "1. 备份记忆全量" + echo "2. 还原记忆全量" + echo "3. 备份 OpenClaw 项目(默认安全模式)" + echo "4. 还原 OpenClaw 项目(高级/高风险)" + echo "5. 删除备份文件" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" backup_choice + read -e -p "请输入你的选择: " backup_choice case "$backup_choice" in 1) openclaw_memory_backup_export ;; @@ -13830,7 +13659,7 @@ EOF 5) openclaw_backup_delete_file ;; 0) return 0 ;; *) - echo "선택이 잘못되었습니다. 다시 시도해 주세요." + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -13839,36 +13668,36 @@ EOF update_moltbot() { - echo "오픈클로 업데이트..." - send_stats "오픈클로 업데이트..." + echo "更新 OpenClaw..." + send_stats "更新 OpenClaw..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway hash -r add_app_id - echo "업데이트 완료" + echo "更新完成" break_end } uninstall_moltbot() { - echo "OpenClaw 제거..." - send_stats "OpenClaw 제거..." + echo "卸载 OpenClaw..." + send_stats "卸载 OpenClaw..." openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf /root/.openclaw hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "제거가 완료되었습니다." + echo "卸载完成" break_end } nano_openclaw_json() { - send_stats "OpenClaw 구성 파일 편집" + send_stats "编辑 OpenClaw 配置文件" install nano nano ~/.openclaw/openclaw.json start_gateway @@ -13902,7 +13731,7 @@ EOF local local_ip token domains echo "==================================" - echo "OpenClaw WebUI 접속 주소" + echo "OpenClaw WebUI 访问地址" local_ip="127.0.0.1" token=$( @@ -13911,12 +13740,12 @@ EOF | head -n 1 ) echo - echo "현지 주소:" + echo "本机地址:" echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "도메인 이름 주소:" + echo "域名地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -13927,7 +13756,7 @@ EOF - # 도메인 이름 추가(제공한 기능 호출) + # 添加域名(调用你给的函数) openclaw_domain_webui() { add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 18789 @@ -13939,30 +13768,30 @@ EOF ) clear - echo "방문 주소:" + echo "访问地址:" echo "https://${yuming}/#token=$token" - echo "먼저 URL에 액세스하여 장치 ID를 트리거한 다음 Enter를 눌러 페어링을 진행하세요." + echo "先访问URL触发设备ID,然后回车下一步进行配对。" read - echo -e "${gl_kjlan}기기 목록 로드 중...${gl_bai}" - # allowedOrigins에 도메인 이름을 자동으로 추가합니다. + echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" + # 自动添加域名到 allowedOrigins config_file="$HOME/.openclaw/openclaw.json" if [ -f "$config_file" ]; then new_origin="https://${yuming}" - # 구조가 존재하고 도메인 이름이 반복적으로 추가되지 않도록 jq를 사용하여 JSON을 안전하게 수정하세요. + # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}도메인 이름이${yuming}allowedOrigins 구성 추가${gl_bai}" + echo -e "${gl_kjlan}已将域名 ${yuming} 加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi openclaw devices list - read -e -p "Request_Key를 입력하십시오:" Request_Key + read -e -p "请输入 Request_Key: " Request_Key [ -z "$Request_Key" ] && { - echo "Request_Key는 비워둘 수 없습니다." + echo "Request_Key 不能为空" return 1 } @@ -13970,41 +13799,41 @@ EOF } - # 도메인 이름 삭제 + # 删除域名 openclaw_remove_domain() { - echo "https://가 없는 도메인 이름 형식 example.com" + echo "域名格式 example.com 不带https://" web_del } - # 메인 메뉴 + # 主菜单 openclaw_webui_menu() { - send_stats "WebUI 액세스 및 설정" + send_stats "WebUI访问与设置" while true; do clear openclaw_show_webui_addr echo - echo "1. 도메인 이름 액세스 추가" - echo "2. 도메인 이름 액세스 삭제" - echo "0. 종료" + echo "1. 添加域名访问" + echo "2. 删除域名访问" + echo "0. 退出" echo - read -e -p "선택하세요:" choice + read -e -p "请选择: " choice case "$choice" in 1) openclaw_domain_webui echo - read -p "메뉴로 돌아가려면 Enter를 누르세요..." + read -p "按回车返回菜单..." ;; 2) openclaw_remove_domain - read -p "메뉴로 돌아가려면 Enter를 누르세요..." + read -p "按回车返回菜单..." ;; 0) break ;; *) - echo "잘못된 옵션" + echo "无效选项" sleep 1 ;; esac @@ -14013,7 +13842,7 @@ EOF - # 메인 루프 + # 主循环 while true; do show_menu read choice @@ -14028,22 +13857,22 @@ EOF 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "초기 구성 마법사" + 11) send_stats "初始化配置向导" openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "健康检测与修复" openclaw doctor --fix - send_stats "OpenClaw API 동기식 트리거링" + send_stats "OpenClaw API同步触发" if sync_openclaw_api_models; then start_gateway else - echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" fi break_end ;; 13) openclaw_webui_menu ;; - 14) send_stats "TUI 명령줄 대화" + 14) send_stats "TUI命令行对话" openclaw tui break_end ;; @@ -14067,7 +13896,7 @@ local sub_choice="$1" clear cd ~ install git -echo -e "${gl_kjlan}신청 목록이 업데이트 중입니다. 기다리세요...${gl_bai}" +echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -14080,12 +13909,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "응용 시장" + echo -e "应用市场" echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 루프를 사용하여 색상 설정 + # 用循环设置颜色 for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -14094,91 +13923,91 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" - echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" - echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" - echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" + echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" + echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" + echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 예정된 작업 관리 플랫폼" - echo -e "${gl_kjlan}13. ${color13}Cloudreve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" - echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}Speedtest 속도 테스트 패널" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome은 애드웨어를 제거합니다${gl_kjlan}18. ${color18}onlyoffice온라인 오피스 OFFICE" - echo -e "${gl_kjlan}19. ${color19}Leichi WAF 방화벽 패널${gl_kjlan}20. ${color20}포테이너 컨테이너 관리 패널" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" + echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" - echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" - echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" - echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatAI 채팅 집계 웹사이트" - echo -e "${gl_kjlan}37. ${color37}MyIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist 가족 버킷" - echo -e "${gl_kjlan}39. ${color39}Bililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexterm 원격 연결 도구" - echo -e "${gl_kjlan}43. ${color43}RustDesk 원격 데스크톱(서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}GitHub 가속 스테이션${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로메테우스(호스트 모니터링)" - echo -e "${gl_kjlan}49. ${color49}프로메테우스(컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" + echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPanel 컨테이너 관리 패널" - echo -e "${gl_kjlan}53. ${color53}라마3 채팅 AI 대형 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" - echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투(클라이언트)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek 채팅 AI 대형 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI 대형 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" + echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" + echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" + echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}n8n 자동화된 워크플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" - echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" + echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" + echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" - echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" - echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" - echo -e "${gl_kjlan}79. ${color79}베젤 서버 모니터링${gl_kjlan}80. ${color80}링크워든 북마크 관리" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" + echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" + echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}gpt-load 고성능 AI 투명 프록시" - echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" - echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" - echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" + echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" + echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea 비공개 코드 저장소${gl_kjlan}92. ${color92}FileBrowser 파일 관리자" - echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}Gopeed 고속 다운로드 도구" - echo -e "${gl_kjlan}95. ${color95}종이 없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAuth 자체 호스팅 2단계 인증자" - echo -e "${gl_kjlan}97. ${color97}WireGuard 네트워킹(서버)${gl_kjlan}98. ${color98}WireGuard 네트워킹(클라이언트)" - echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}P2P 파일 동기화 도구 동기화" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" + echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" - echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" - echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" - echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" + echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" + echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" + echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" + echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" - echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}第三方应用列表" + echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) - # 앱 설명 가져오기 + # 获取应用描述 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - # 설치 상태 확인(appno.txt의 ID 일치) - # 여기서는 appno.txt에 기록되는 내용이 base_name(즉, 파일 이름)이라고 가정합니다. + # 检查安装状态 (匹配 appno.txt 中的 ID) + # 这里假设 appno.txt 中记录的是 base_name (即文件名) if echo "$app_numbers" | grep -q "^$base_name$"; then - # 설치된 경우: show base_name - 설명 [설치됨](녹색) - echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[설치됨]${gl_bai}" + # 如果已安装:显示 base_name - 描述 [已安装] (绿色) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" else - # 설치되지 않은 경우: 정상적으로 표시됩니다. + # 如果未安装:正常显示 echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" fi done @@ -14186,18 +14015,18 @@ while true; do echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice fi case $sub_choice in 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="탑 패널" + local panelname="宝塔面板" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -14290,10 +14119,10 @@ while true; do } - local docker_describe="도메인 이름 액세스 추가를 지원하지 않는 Nginx 역방향 프록시 도구 패널." - local docker_url="공식 홈페이지 소개: https://nginxproxymanager.com/" - local docker_use="echo \"초기 사용자 이름: admin@example.com\"" - local docker_passwd="echo \"초기 비밀번호:changeme\"" + local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" + local docker_url="官网介绍: https://nginxproxymanager.com/" + local docker_use="echo \"初始用户名: admin@example.com\"" + local docker_passwd="echo \"初始密码: changeme\"" local app_size="1" docker_app @@ -14325,8 +14154,8 @@ while true; do } - local docker_describe="gin 및 Solidjs로 구동되는 다중 저장소, 웹 브라우징 및 WebDAV를 지원하는 파일 목록 프로그램" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/OpenListTeam/OpenList" + local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" + local docker_url="官网介绍: ${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -14343,8 +14172,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정:" admin - read -e -p "로그인 사용자 비밀번호 설정:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -14366,8 +14195,8 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." - local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -14377,7 +14206,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -14386,20 +14215,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" - echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" - echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" + echo -e "哪吒监控 $check_docker $update_status" + echo "开源、轻量、易用的服务器监控与运维工具" + echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 사용" + echo "1. 使用" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -14446,8 +14275,8 @@ while true; do } - local docker_describe="qbittorrent 오프라인 BT 자기 다운로드 서비스" - local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -14456,7 +14285,7 @@ while true; do ;; 9|mail) - send_stats "우체국을 짓다" + send_stats "搭建邮局" clear install telnet local app_id="9" @@ -14466,44 +14295,44 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" - echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." - echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "邮局服务 $check_docker $update_status" + echo "poste.io 是一个开源的邮件服务器解决方案," + echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "포트 감지" + echo "端口检测" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}포트$port현재 사용 가능${gl_bai}" + echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" else - echo -e "${gl_hong}포트$port현재는 이용할 수 없습니다${gl_bai}" + echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "방문 주소:" + echo "访问地址: " echo "https://$yuming" fi echo "------------------------" - echo "1. 설치 2. 업데이트 3. 제거" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "먼저 이 DNS 레코드를 구문 분석하세요." + echo "先解析这些DNS记录" echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -14513,7 +14342,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "계속하려면 아무 키나 누르세요..." + echo "按任意键继续..." read -n 1 -s -r -p "" install jq @@ -14532,9 +14361,9 @@ while true; do add_app_id clear - echo "poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -14557,9 +14386,9 @@ while true; do add_app_id clear - echo "poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" - echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" ;; @@ -14570,7 +14399,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "앱이 제거되었습니다." + echo "应用已卸载" ;; *) @@ -14586,9 +14415,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat 채팅 시스템" - local app_text="Rocket.Chat은 실시간 채팅, 음성 및 영상 통화, 파일 공유 및 기타 기능을 지원하는 오픈 소스 팀 커뮤니케이션 플랫폼입니다." - local app_url="공식소개 : https://www.rocket.chat/" + local app_name="Rocket.Chat聊天系统" + local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," + local app_url="官方介绍: https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -14604,7 +14433,7 @@ while true; do clear ip_address - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -14614,7 +14443,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chat이 설치되었습니다" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -14624,7 +14453,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -14654,10 +14483,10 @@ while true; do } - local docker_describe="ZenTao는 범용 프로젝트 관리 소프트웨어입니다" - local docker_url="공식 홈페이지 소개 : https://www.zentao.net/" - local docker_use="echo \"초기 사용자 이름: admin\"" - local docker_passwd="echo \"초기 비밀번호: 123456\"" + local docker_describe="禅道是通用的项目管理软件" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" + local docker_passwd="echo \"初始密码: 123456\"" local app_size="2" docker_app @@ -14683,8 +14512,8 @@ while true; do } - local docker_describe="Qinglong Panel은 예약된 작업 관리 플랫폼입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/whyour/qinglong" + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -14694,9 +14523,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="클라우드리브 네트워크 디스크" - local app_text="cloudreve는 여러 클라우드 스토리지를 지원하는 네트워크 디스크 시스템입니다." - local app_url="영상 소개: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="cloudreve网盘" + local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -14708,7 +14537,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -14722,7 +14551,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -14748,8 +14577,8 @@ while true; do } - local docker_describe="심플드로잉베드는 심플드로잉베드 프로그램입니다" - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="简单图床是一个简单的图床程序" + local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -14776,8 +14605,8 @@ while true; do } - local docker_describe="emby는 서버의 비디오 및 오디오를 구성하고 오디오 및 비디오를 클라이언트 장치로 스트리밍하는 데 사용할 수 있는 마스터-슬레이브 아키텍처 미디어 서버 소프트웨어입니다." - local docker_url="공식 홈페이지 소개 : https://emby.media/" + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" + local docker_url="官网介绍: https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -14797,8 +14626,8 @@ while true; do } - local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -14828,8 +14657,8 @@ while true; do } - local docker_describe="AdGuardHome은 미래에 단순한 DNS 서버 이상의 역할을 할 네트워크 전체의 광고 차단 및 추적 방지 소프트웨어입니다." - local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -14857,8 +14686,8 @@ while true; do } - local docker_describe="onlyoffice는 오픈 소스 온라인 오피스 도구로 매우 강력합니다!" - local docker_url="공식 홈페이지 소개 : https://www.onlyoffice.com/" + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" + local docker_url="官网介绍: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -14867,7 +14696,7 @@ while true; do ;; 19|safeline) - send_stats "천둥 웅덩이를 만들어라" + send_stats "搭建雷池" local app_id="19" local docker_name=safeline-mgt @@ -14875,20 +14704,20 @@ while true; do while true; do check_docker_app clear - echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." - echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" + echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -14898,7 +14727,7 @@ while true; do add_app_id clear - echo "Leichi WAF 패널이 설치되었습니다." + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -14911,7 +14740,7 @@ while true; do add_app_id clear - echo "Leichi WAF 패널이 업데이트되었습니다." + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -14922,7 +14751,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "기본 설치 디렉터리에 있다면 이제 프로젝트가 제거된 것입니다. 설치 디렉터리를 사용자 정의하는 경우 설치 디렉터리로 이동하여 직접 실행해야 합니다." + echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -14954,8 +14783,8 @@ while true; do } - local docker_describe="portainer는 경량 도커 컨테이너 관리 패널입니다." - local docker_url="공식 홈페이지 소개 : https://www.portainer.io/" + local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_url="官网介绍: https://www.portainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -14977,8 +14806,8 @@ while true; do } - local docker_describe="VScode는 강력한 온라인 코드 작성 도구입니다" - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode是一款强大的在线代码编写工具" + local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -15005,8 +14834,8 @@ while true; do } - local docker_describe="가동 시간 Kuma 사용하기 쉬운 자체 호스팅 모니터링 도구" - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -15025,8 +14854,8 @@ while true; do } - local docker_describe="Memos는 경량의 자체 호스팅 메모 센터입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -15041,8 +14870,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정:" admin - read -e -p "로그인 사용자 비밀번호 설정:" admin_password + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -15066,8 +14895,8 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." - local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -15087,9 +14916,9 @@ while true; do } - local docker_describe="400,000개 이상 배포된 Nextcloud는 다운로드할 수 있는 가장 인기 있는 로컬 콘텐츠 협업 플랫폼입니다." - local docker_url="공식 홈페이지 소개 : https://nextcloud.com/" - local docker_use="echo \"계정: nextcloud 비밀번호:$rootpasswd\"" + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" + local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -15107,8 +14936,8 @@ while true; do } - local docker_describe="QD-Today는 HTTP 요청 예약 작업 자동 실행 프레임워크입니다." - local docker_url="공식 홈페이지 소개: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -15127,8 +14956,8 @@ while true; do } - local docker_describe="Dockge는 시각적 Docker 작성 컨테이너 관리 패널입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/dockge" + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -15147,8 +14976,8 @@ while true; do } - local docker_describe="librespeed는 즉시 사용할 수 있는 Javascript로 구현된 경량 속도 테스트 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -15172,8 +15001,8 @@ while true; do } - local docker_describe="searxng는 비공개 및 비공개 검색 엔진 사이트입니다." - local docker_url="공식 홈페이지 소개 : https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -15204,9 +15033,9 @@ while true; do } - local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" - local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" + local docker_describe="photoprism非常强大的私有相册系统" + local docker_url="官网介绍: https://www.photoprism.app/" + local docker_use="echo \"账号: admin 密码: $rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -15232,8 +15061,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -15253,8 +15082,8 @@ while true; do } - local docker_describe="이것은 강력한 차트 작성 소프트웨어입니다. 마인드맵, 토폴로지 다이어그램, 흐름도를 그릴 수 있습니다." - local docker_url="공식 홈페이지 소개 : https://www.drawio.com/" + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" + local docker_url="官网介绍: https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -15278,9 +15107,9 @@ while true; do } - local docker_describe="Sun-Panel 서버, NAS 탐색 패널, 홈페이지, 브라우저 홈페이지" - local docker_url="공식 홈페이지 소개: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"계정: admin@sun.cc 비밀번호: 12345678\"" + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -15302,8 +15131,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share는 자체 구축 가능한 파일 공유 플랫폼이자 WeTransfer의 대안입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -15329,9 +15158,9 @@ while true; do } - local docker_describe="미니멀리스트 순간, 높은 모방 WeChat 순간, 멋진 삶을 기록하세요" - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"계정: admin 비밀번호: a123456\"" + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" + local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -15353,8 +15182,8 @@ while true; do lobehub/lobe-chat } - local docker_describe="LobeChat은 시장의 주류 AI 대형 모델인 ChatGPT/Claude/Gemini/Groq/Ollama를 통합합니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/lobehub/lobe-chat" + local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" + local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -15374,8 +15203,8 @@ while true; do } - local docker_describe="자신의 IP 정보와 연결성을 확인하고 웹 패널을 통해 표시할 수 있는 다기능 IP 도구 상자입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" + local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -15383,7 +15212,7 @@ while true; do ;; 38|xiaoya) - send_stats "Xiaoya 가족 버킷" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -15408,8 +15237,8 @@ while true; do } - local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹음 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -15425,8 +15254,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="간단한 온라인 SSH 연결 도구 및 SFTP 도구" - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="简易在线ssh连接工具和sftp工具" + local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -15437,8 +15266,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 오리지널 마우스 패널" - local panelurl="공식 주소:${gh_proxy}github.com/acepanel/panel" + local panelname="AcePanel 原耗子面板" + local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" panel_app_install() { cd ~ @@ -15479,8 +15308,8 @@ while true; do } - local docker_describe="nexterm은 강력한 온라인 SSH/VNC/RDP 연결 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" + local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -15500,10 +15329,10 @@ while true; do } - local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(서버)은 자체 Sunflower 개인 서버와 유사합니다." - local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"원격 데스크톱 클라이언트에서 사용될 IP와 키를 기록하세요. 릴레이를 설치하려면 옵션 44로 이동하세요!\"" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" local app_size="1" docker_app ;; @@ -15520,9 +15349,9 @@ while true; do } - local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(릴레이)은 자체 Sunflower 개인 서버와 유사합니다." - local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" - local docker_use="echo \"원격 데스크톱 클라이언트를 다운로드하려면 공식 웹사이트로 이동하세요: https://rustdesk.com/zh-cn/\"" + local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" + local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -15546,8 +15375,8 @@ while true; do } - local docker_describe="Docker Registry는 Docker 이미지를 저장하고 배포하는 서비스입니다." - local docker_url="공식 홈페이지 소개: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_url="官网介绍: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -15566,8 +15395,8 @@ while true; do } - local docker_describe="Go를 사용하여 구현된 GHProxy는 일부 영역에서 Github 저장소 가져오기를 가속화하는 데 사용됩니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" + local docker_url="官网介绍: ${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -15577,9 +15406,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="프로메테우스 모니터링" - local app_text="Prometheus+Grafana 전사적 모니터링 시스템" - local app_url="공식 홈페이지 소개 : https://prometheus.io" + local app_name="普罗米修斯监控" + local app_text="Prometheus+Grafana企业级监控系统" + local app_url="官网介绍: https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -15588,9 +15417,9 @@ while true; do prometheus_install clear ip_address - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름과 비밀번호는 admin입니다." + echo "初始用户名密码均为: admin" } docker_app_update() { @@ -15608,7 +15437,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -15631,8 +15460,8 @@ while true; do } - local docker_describe="이는 Prometheus 호스트 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/prometheus/node_exporter" + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: ${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -15661,8 +15490,8 @@ while true; do } - local docker_describe="이는 Prometheus 컨테이너 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/google/cadvisor" + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_url="官网介绍: ${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -15684,8 +15513,8 @@ while true; do } - local docker_describe="이는 웹사이트 변경 감지, 보충 모니터링 및 알림을 위한 작은 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/dgtlmoon/changedetection.io" + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_url="官网介绍: ${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -15695,7 +15524,7 @@ while true; do 51|pve) clear - send_stats "PVE 오픈 병아리" + send_stats "PVE开小鸡" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -15717,8 +15546,8 @@ while true; do } - local docker_describe="Docker 시각적 패널 시스템은 완전한 Docker 관리 기능을 제공합니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/donknap/dpanel" + local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" + local docker_url="官网介绍: ${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -15737,8 +15566,8 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -15749,8 +15578,8 @@ while true; do local app_id="54" local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH 패널" - local panelurl="공식 주소 : https://amh.sh/index.htm?amh" + local panelname="AMH面板" + local panelurl="官方地址: https://amh.sh/index.htm?amh" panel_app_install() { cd ~ @@ -15789,8 +15618,8 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 DeepSeek R1 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -15800,9 +15629,9 @@ while true; do 58|dify) local app_id="58" - local app_name="DifyKnowledge Base" - local app_text="오픈 소스 LLM(대형 언어 모델) 애플리케이션 개발 플랫폼입니다. AI 생성을 위한 자체 호스팅 학습 데이터" - local app_url="공식 홈페이지: https://docs.dify.ai/zh-hans" + local app_name="Dify知识库" + local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" + local app_url="官方网站: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -15820,7 +15649,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -15835,7 +15664,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -15845,8 +15674,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="차세대 대형 모델 게이트웨이 및 AI 자산 관리 시스템" - local app_url="공식 웹사이트:${gh_https_url}github.com/Calcium-Ion/new-api" + local app_text="新一代大模型网关与AI资产管理系统" + local app_url="官方网站: ${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -15863,7 +15692,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -15879,7 +15708,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -15887,7 +15716,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -15898,9 +15727,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." - local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" + local app_name="JumpServer开源堡垒机" + local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" + local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -15908,17 +15737,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름: admin" - echo "초기 비밀번호: ChangeMe" + echo "初始用户名: admin" + echo "初始密码: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "앱이 업데이트되었습니다" + echo "应用已更新" } @@ -15928,7 +15757,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -15950,8 +15779,8 @@ while true; do } - local docker_describe="무료 오픈 소스 기계 번역 API, 완전 자체 호스팅 및 번역 엔진은 오픈 소스 Argos Translate 라이브러리에 의해 구동됩니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreTranslate/LibreTranslate" + local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -15962,9 +15791,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow 지식 기반" - local app_text="깊은 문서 이해를 기반으로 한 오픈소스 RAG(Retrieval Augmented Generation) 엔진" - local app_url="공식 웹사이트:${gh_https_url}github.com/infiniflow/ragflow" + local app_name="RAGFlow知识库" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_url="官方网站: ${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -15975,7 +15804,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -15991,7 +15820,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16011,8 +15840,8 @@ while true; do } - local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 단순화 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" + local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -16029,8 +15858,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="개발자와 IT 작업자에게 매우 유용한 도구" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/CorentinTh/it-tools" + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" + local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -16065,8 +15894,8 @@ while true; do } - local docker_describe="강력한 자동화된 워크플로우 플랫폼입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/n8n-io/n8n" + local docker_describe="是一款功能强大的自动化工作流平台" + local docker_url="官网介绍: ${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -16094,8 +15923,8 @@ while true; do } - local docker_describe="동적 도메인 이름 확인을 위해 공용 IP(IPv4/IPv6)를 주요 DNS 서비스 제공업체에 실시간으로 자동 업데이트합니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/jeessy2/ddns-go" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_url="官网介绍: ${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -16112,10 +15941,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="오픈 소스 무료 SSL 인증서 자동화 관리 플랫폼" - local docker_url="공식 홈페이지 소개: https://allinssl.com" - local docker_use="echo \"보안 입구: /allinssl\"" - local docker_passwd="echo \"사용자 이름: allinssl 비밀번호: allinssldocker\"" + local docker_describe="开源免费的 SSL 证书自动化管理平台" + local docker_url="官网介绍: https://allinssl.com" + local docker_use="echo \"安全入口: /allinssl\"" + local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" local app_size="1" docker_app ;; @@ -16144,8 +15973,8 @@ while true; do } - local docker_describe="언제 어디서나 무료 오픈 소스 SFTP FTP WebDAV 파일 전송 도구" - local docker_url="공식 홈페이지 소개 : https://sftpgo.com/" + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" + local docker_url="官网介绍: https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16176,9 +16005,9 @@ while true; do } - local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" - local docker_url="공식 홈페이지 소개: https://astrbot.app/" - local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" + local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" + local docker_url="官网介绍: https://astrbot.app/" + local docker_use="echo \"用户名: astrbot 密码: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -16205,8 +16034,8 @@ while true; do } - local docker_describe="경량, 고성능 음악 스트리밍 서버입니다." - local docker_url="공식 홈페이지 소개 : https://www.navidrome.org/" + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16232,8 +16061,8 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" - local docker_url="공식 홈페이지 소개: https://bitwarden.com/" + local docker_describe="一个你可以控制数据的密码管理器" + local docker_url="官网介绍: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16253,7 +16082,7 @@ while true; do docker_rum() { - read -e -p "LibreTV 로그인 비밀번호 설정:" app_passwd + read -e -p "设置LibreTV的登录密码: " app_passwd docker run -d \ --name libretv \ @@ -16264,8 +16093,8 @@ while true; do } - local docker_describe="무료 온라인 비디오 검색 및 시청 플랫폼" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreSpark/LibreTV" + local docker_describe="免费在线视频搜索与观看平台" + local docker_url="官网介绍: ${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -16279,17 +16108,17 @@ while true; do local app_id="74" - local app_name="Moontv 개인 영화 및 TV" - local app_text="무료 온라인 비디오 검색 및 시청 플랫폼" - local app_url="비디오 소개:${gh_https_url}github.com/MoonTechLab/LunaTV" + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" + local app_url="视频介绍: ${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" docker_app_install() { - read -e -p "로그인 사용자 이름 설정:" admin - read -e -p "로그인 사용자 비밀번호 설정:" admin_password - read -e -p "인증 코드 입력:" shouquanma + read -e -p "设置登录用户名: " admin + read -e -p "设置登录用户密码: " admin_password + read -e -p "输入授权码: " shouquanma mkdir -p /home/docker/moontv @@ -16305,7 +16134,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -16319,7 +16148,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16346,8 +16175,8 @@ while true; do } - local docker_describe="음악을 더 잘 관리할 수 있도록 설계된 음악 마법사입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/foamzou/melody" + local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" + local docker_url="官网介绍: ${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -16373,8 +16202,8 @@ while true; do } - local docker_describe="중국의 DOS 게임 컬렉션 웹사이트입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/rwv/chinese-dos-games" + local docker_describe="是一个中文DOS游戏合集网站" + local docker_url="官网介绍: ${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -16392,8 +16221,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정:" app_use - read -e -p "로그인 비밀번호 설정:" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name xunlei \ @@ -16408,9 +16237,9 @@ while true; do } - local docker_describe="오프라인 고속 BT 자기 다운로드 도구인 Xunlei" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/cnk3x/xunlei" - local docker_use="echo \"휴대폰으로 Xunlei에 로그인하고 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" + local docker_describe="迅雷你的离线高速BT磁力下载工具" + local docker_url="官网介绍: ${gh_https_url}github.com/cnk3x/xunlei" + local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" local docker_passwd="" local app_size="1" docker_app @@ -16423,8 +16252,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki는 AI 대형 모델을 기반으로 하는 오픈 소스 지능형 문서 관리 시스템입니다. 포트 배포를 사용자 정의하지 않는 것이 좋습니다." - local app_url="공식 소개:${gh_https_url}github.com/chaitin/PandaWiki" + local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" + local app_url="官方介绍: ${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -16466,8 +16295,8 @@ while true; do } - local docker_describe="Beszel은 가볍고 사용하기 쉬운 서버 모니터링입니다." - local docker_url="공식 홈페이지 소개: https://beszel.dev/zh/" + local docker_describe="Beszel轻量易用的服务器监控" + local docker_url="官网介绍: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16479,9 +16308,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." - local app_url="공식 홈페이지: https://linkwarden.app/" + local app_name="linkwarden书签管理" + local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" + local app_url="官方网站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -16490,11 +16319,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 공식 docker-compose 및 env 파일 다운로드 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 임의의 키와 비밀번호 생성 + # 生成随机密钥与密码 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -16503,17 +16332,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 관리자 계정 정보 추가 + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 컨테이너 시작 + # 启动容器 docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -16523,7 +16352,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 원래 변수 유지 + # 保留原本的变量 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -16540,7 +16369,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16551,9 +16380,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet 화상 회의" - local app_text="다자간 온라인 회의, 화면 공유, 암호화된 통신을 지원하는 오픈 소스 보안 화상 회의 솔루션입니다." - local app_url="공식 홈페이지: https://jitsi.org/" + local app_name="JitsiMeet视频会议" + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" + local app_url="官方网站: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -16590,7 +16419,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16608,7 +16437,7 @@ while true; do docker_rum() { - read -e -p "설정${docker_name}로그인 키(sk-다음과 같이 시작하는 문자와 숫자의 조합): sk-159kejilionyyds163:" app_passwd + read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -16619,8 +16448,8 @@ while true; do } - local docker_describe="고성능 AI 인터페이스 투명 프록시 서비스" - local docker_url="공식 홈페이지 소개: https://www.gpt-load.com/" + local docker_describe="高性能AI接口透明代理服务" + local docker_url="官网介绍: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16652,9 +16481,9 @@ while true; do } - local docker_describe="경량 자체 호스팅 서버 모니터링 도구" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"기본 계정: admin 기본 비밀번호: 1212156\"" + local docker_describe="轻量级的自托管服务器监控工具" + local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -16683,8 +16512,8 @@ while true; do } - local docker_describe="재무 관리를 위한 오픈 소스 개인 구독 추적기" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/ellite/Wallos" + local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_url="官网介绍: ${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -16695,9 +16524,9 @@ while true; do 85|immich) local app_id="85" - local app_name="이미치 픽처 비디오 매니저" - local app_text="고성능 자체 호스팅 사진 및 비디오 관리 솔루션입니다." - local app_url="공식 웹사이트 소개:${gh_https_url}github.com/immich-app/immich" + local app_name="immich图片视频管理器" + local app_text="高性能自托管照片和视频管理解决方案。" + local app_url="官网介绍: ${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -16713,7 +16542,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -16726,7 +16555,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16761,8 +16590,8 @@ while true; do } - local docker_describe="오픈 소스 미디어 서버 소프트웨어입니다" - local docker_url="공식 홈페이지 소개 : https://jellyfin.org/" + local docker_describe="是一款开源媒体服务器软件" + local docker_url="官网介绍: https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16789,9 +16618,9 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" - local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" + local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" + local docker_url="官网介绍: ${gh_https_url}github.com/synctv-org/synctv" + local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" local docker_passwd="" local app_size="1" docker_app @@ -16819,10 +16648,10 @@ while true; do } - local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" - local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" - local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" + local docker_describe="开源、免费的自建直播平台" + local docker_url="官网介绍: https://owncast.online" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" local app_size="1" docker_app @@ -16848,10 +16677,10 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" - local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" - local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" + local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" + local docker_url="官网介绍: ${gh_https_url}github.com/vastsa/FileCodeBox" + local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" + local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" local app_size="1" docker_app @@ -16887,7 +16716,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "초기 사용자 또는 관리자를 생성합니다. 다음 사용자 이름과 비밀번호를 설정하고 관리자인지 여부를 설정하세요." + echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -16904,8 +16733,8 @@ while true; do } - local docker_describe="Matrix는 분산형 채팅 프로토콜입니다." - local docker_url="공식 홈페이지 소개 : https://matrix.org/" + local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_url="官网介绍: https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16919,9 +16748,9 @@ while true; do local app_id="91" - local app_name="gitea 비공개 코드 저장소" - local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." - local app_url="비디오 소개:${gh_https_url}github.com/go-gitea/gitea" + local app_name="gitea私有代码仓库" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_url="视频介绍: ${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -16939,7 +16768,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -16953,7 +16782,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -16983,8 +16812,8 @@ while true; do } - local docker_describe="웹 기반 파일 관리자입니다" - local docker_url="공식 홈페이지 소개 : https://filebrowser.org/" + local docker_describe="是一个基于Web的文件管理器" + local docker_url="官网介绍: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -17010,8 +16839,8 @@ while true; do } - local docker_describe="미니멀리스트 정적 파일 서버, 업로드 및 다운로드 지원" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/sigoden/dufs" + local docker_describe="极简静态文件服务器,支持上传下载" + local docker_url="官网介绍: ${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -17028,8 +16857,8 @@ while true; do docker_rum() { - read -e -p "로그인 사용자 이름 설정:" app_use - read -e -p "로그인 비밀번호 설정:" app_passwd + read -e -p "设置登录用户名: " app_use + read -e -p "设置登录密码: " app_passwd docker run -d \ --name ${docker_name} \ @@ -17041,8 +16870,8 @@ while true; do } - local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/GopeedLab/gopeed" + local docker_describe="分布式高速下载工具,支持多种协议" + local docker_url="官网介绍: ${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -17056,9 +16885,9 @@ while true; do local app_id="95" - local app_name="종이 없는 문서 관리 플랫폼" - local app_text="오픈 소스 전자 문서 관리 시스템으로, 주요 목적은 종이 문서를 디지털화하고 관리하는 것입니다." - local app_url="영상 소개: https://docs.paperless-ngx.com/" + local app_name="paperless文档管理平台" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -17077,7 +16906,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17091,7 +16920,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17104,9 +16933,9 @@ while true; do local app_id="96" - local app_name="2FAuth 자체 호스팅 2단계 인증자" - local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." - local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" + local app_name="2FAuth自托管二步验证器" + local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" + local app_url="官网: ${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -17131,7 +16960,7 @@ while true; do block_container_port "$docker_name" "$ipv4_address" clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17145,7 +16974,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17163,9 +16992,9 @@ while true; do docker_rum() { - read -e -p "네트워크의 클라이언트 수를 입력하십시오(기본값 5):" COUNT + read -e -p "请输入组网的客户端数量 (默认 5): " COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard 네트워크 세그먼트(기본값 10.13.13.0)를 입력하세요." NETWORK + read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -17235,24 +17064,24 @@ while true; do sleep 2 echo - echo -e "${gl_huang}모든 클라이언트 QR 코드 구성:${gl_bai}" + echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo - echo -e "${gl_huang}모든 클라이언트 구성 코드:${gl_bai}" + echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}각 클라이언트에 대한 모든 출력을 구성합니다. 사용방법은 다음과 같습니다.${gl_bai}" - echo -e "${gl_lv}1. 휴대폰에 wg APP을 다운로드하고 위의 QR 코드를 스캔하면 빠르게 인터넷에 연결됩니다.${gl_bai}" - echo -e "${gl_lv}2. Windows용 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" - echo -e "${gl_lv}3. 스크립트를 사용하여 Linux에 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" - echo -e "${gl_lv}공식 클라이언트 다운로드 방법: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" + echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" break_end } - local docker_describe="최신 고성능 가상 사설망 도구" - local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17274,16 +17103,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 디렉터리가 없으면 생성 + # 创建目录(如果不存在) mkdir -p "$(dirname "$CONFIG_FILE")" - echo "클라이언트 구성을 붙여넣고 Enter를 두 번 눌러 저장하세요." + echo "请粘贴你的客户端配置,连续按两次回车保存:" - # 변수 초기화 + # 初始化变量 input="" empty_line_count=0 - # 사용자 입력을 한 줄씩 읽습니다. + # 逐行读取用户输入 while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -17296,10 +17125,10 @@ while true; do fi done - # 구성 파일 쓰기 + # 写入配置文件 echo "$input" > "$CONFIG_FILE" - echo "클라이언트 구성이 다음에 저장되었습니다.$CONFIG_FILE" + echo "客户端配置已保存到 $CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -17321,8 +17150,8 @@ while true; do } - local docker_describe="최신 고성능 가상 사설망 도구" - local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" + local docker_describe="现代化、高性能的虚拟专用网络工具" + local docker_url="官网介绍: https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17335,19 +17164,19 @@ while true; do local app_id="99" - local app_name="dsm 시놀로지 가상 머신" - local app_text="Docker 컨테이너의 가상 DSM" - local app_url="공식 웹사이트:${gh_https_url}github.com/vdsm/virtual-dsm" + local app_name="dsm群晖虚拟机" + local app_text="Docker容器中的虚拟DSM" + local app_url="官网: ${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" docker_app_install() { - read -e -p "CPU 코어 수를 설정합니다(기본값 2):" CPU_CORES + read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "메모리 크기 설정(기본 4G):" RAM_SIZE + read -e -p "设置内存大小 (默认 4G): " RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -17364,7 +17193,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17378,7 +17207,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17407,8 +17236,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="Dropbox 및 Resilio Sync와 유사하지만 완전히 분산된 오픈 소스 P2P 파일 동기화 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/syncthing/syncthing" + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_url="官网介绍: ${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -17419,9 +17248,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." - local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI视频生成工具" + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" + local app_url="官方网站: ${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -17433,7 +17262,7 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17449,7 +17278,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17475,8 +17304,8 @@ while true; do } - local docker_describe="독립적인 배포를 지원하는 개인용 클라우드 소셜 미디어 채팅 서비스입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/Privoce/vocechat-web" + local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" + local docker_url="官网介绍: ${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -17487,9 +17316,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami 웹사이트 통계 도구" - local app_text="Google Analytics와 유사한 오픈 소스, 가볍고 개인정보 보호 친화적인 웹사이트 분석 도구입니다." - local app_url="공식 웹사이트:${gh_https_url}github.com/umami-software/umami" + local app_name="Umami网站统计工具" + local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" + local app_url="官方网站: ${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -17501,10 +17330,10 @@ while true; do docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip - echo "초기 사용자 이름: admin" - echo "초기 비밀번호 : umami" + echo "初始用户名: admin" + echo "初始密码: umami" } docker_app_update() { @@ -17518,7 +17347,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17539,7 +17368,7 @@ while true; do docker_rum() { - read -e -p "로그인 비밀번호 설정:" app_passwd + read -e -p "设置登录密码: " app_passwd docker run -d \ --name siyuan \ @@ -17554,8 +17383,8 @@ while true; do } - local docker_describe="Siyuan Notes는 개인 정보 보호를 최우선으로 하는 지식 관리 시스템입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/siyuan-note/siyuan" + local docker_describe="思源笔记是一款隐私优先的知识管理系统" + local docker_url="官网介绍: ${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -17581,8 +17410,8 @@ while true; do } - local docker_describe="마인드맵, 플로우차트 등을 통합한 강력한 오픈소스 화이트보드 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/plait-board/drawnix" + local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" + local docker_url="官网介绍: ${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -17616,8 +17445,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou는 고성능 네트워크 디스크 리소스 검색 API 서비스입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/fish2018/pansou" + local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" + local docker_url="官网介绍: ${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -17630,9 +17459,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot 챗봇" - local app_text="오픈 소스 대형 언어 모델 기반 인스턴트 메시징 로봇 개발 플랫폼입니다." - local app_url="공식 웹사이트:${gh_https_url}github.com/langbot-app/LangBot" + local app_name="LangBot聊天机器人" + local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" + local app_url="官方网站: ${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -17644,7 +17473,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17659,7 +17488,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17688,8 +17517,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="개인이나 소규모 팀에 적합한 온라인 네트워크 디스크 프로그램입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/zfile-dev/zfile" + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_url="官网介绍: ${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -17700,9 +17529,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep 북마크 관리" - local app_text="데이터 수집가를 위해 설계된 인공 지능 기능을 갖춘 자체 호스팅 북마크 앱입니다." - local app_url="공식 웹사이트:${gh_https_url}github.com/karakeep-app/karakeep" + local app_name="karakeep书签管理" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_url="官方网站: ${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -17714,7 +17543,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker compose up -d clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip } @@ -17729,7 +17558,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -17754,8 +17583,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="강력한 다중 형식 파일 변환 도구입니다(문서, 이미지, 오디오 및 비디오 등 지원). 도메인 이름 액세스를 추가하는 것이 좋습니다." - local docker_url="프로젝트 주소:${gh_https_url}github.com/c4illin/ConvertX" + local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" + local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -17769,7 +17598,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) local docker_port=8112 docker_rum() { @@ -17780,15 +17609,15 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - echo "Lucky가 초기화되기를 기다리는 중..." + echo "正在等待 Lucky 初始化..." sleep 10 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } - local docker_describe="Lucky는 DDNS, 역방향 프록시, WOL 및 기타 기능을 지원하는 대규모 인트라넷 침투 및 포트 전달 관리 도구입니다." - local docker_url="프로젝트 주소:${gh_https_url}github.com/gdy666/lucky" - local docker_use="echo \"기본 계정 비밀번호: 666\"" + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" + local docker_url="项目地址: ${gh_https_url}github.com/gdy666/lucky" + local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" local app_size="1" docker_app @@ -17805,7 +17634,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_rum() { - read -e -p "로그인 비밀번호 설정:" admin_password + read -e -p "设置登录密码: " admin_password docker run -d --name=${docker_name} --restart=always \ -p ${docker_port}:5800 \ @@ -17816,8 +17645,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="웹 페이지를 통해 데스크톱 브라우저 인터페이스에 대한 직접 액세스를 지원하는 Docker에서 실행되는 Firefox 브라우저입니다." - local docker_url="프로젝트 주소:${gh_https_url}github.com/jlesage/docker-firefox" + local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" + local docker_url="项目地址: ${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -17832,19 +17661,19 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ b) clear - send_stats "모든 애플리케이션 백업" + send_stats "全部应用备份" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "생성된 백업 파일: /$backup_filename" - read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice + echo "备份文件已创建: /$backup_filename" + read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice case "$choice" in [Yy]) - kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -17852,14 +17681,14 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "원격 서버/루트 디렉터리로 파일이 전송되었습니다." + echo "文件已传送至远程服务器/根目录。" else - echo "전송할 파일을 찾을 수 없습니다." + echo "未找到要传送的文件。" fi break ;; *) - echo "참고: 현재 백업에는 docker 프로젝트만 포함되며, Pagoda, 1panel 등 웹사이트 구축 패널의 데이터 백업은 포함되지 않습니다." + echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" break ;; esac @@ -17869,29 +17698,29 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use - send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + send_stats "全部应用还原" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. + # 如果用户没有输入文件名,使用最新的压缩包 if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "애플리케이션 데이터가 복원되었습니다. 현재 해당 애플리케이션을 복원하려면 지정된 애플리케이션 메뉴에 수동으로 진입한 후 애플리케이션을 업데이트하시기 바랍니다." + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else - echo "압축된 패키지를 찾을 수 없습니다." + echo "没有找到压缩包。" fi ;; @@ -17913,7 +17742,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -f "$custom_app" ]; then . "$custom_app" else - echo -e "${gl_hong}오류: 번호가 없습니다.${sub_choice}애플리케이션 구성${gl_bai}" + echo -e "${gl_hong}错误: 未找到编号为 ${sub_choice} 的应用配置${gl_bai}" fi ;; esac @@ -17929,35 +17758,35 @@ linux_work() { while true; do clear - send_stats "백엔드 작업공간" - echo -e "백엔드 작업공간" - echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." - echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" + send_stats "后台工作区" + echo -e "后台工作区" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" - echo "현재 존재하는 작업공간 목록" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}작업 영역 1" - echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" - echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" - echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" - echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" - echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" - echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" + echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" + echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" + echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" + echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" + echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" + echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" - echo -e "${gl_kjlan}23. ${gl_bai}백그라운드 작업 공간에 명령 삽입" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업공간 삭제" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" + echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -17965,7 +17794,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -17973,63 +17802,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; @@ -18037,30 +17866,30 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}켜다${gl_bai}" + local tmux_sshd_status="${gl_lv}开启${gl_bai}" else - local tmux_sshd_status="${gl_hui}폐쇄${gl_bai}" + local tmux_sshd_status="${gl_hui}关闭${gl_bai}" fi - send_stats "SSH 상주 모드" - echo -e "SSH 상주 모드${tmux_sshd_status}" - echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." + send_stats "SSH常驻模式 " + echo -e "SSH常驻模式 ${tmux_sshd_status}" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 开启 2. 关闭" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" gongzuoqu_del + read -e -p "请输入你的选择: " gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "작업공간 시작$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 자동으로 tmux 세션 시작\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "启动工作区$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; 2) - sed -i '/# 자동으로 tmux 세션을 입력합니다/,+4d' ~/.bashrc + sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -18071,29 +17900,29 @@ linux_work() { ;; 22) - read -e -p "1001 kj001 work1과 같이 생성하거나 입력한 작업공간의 이름을 입력하세요." SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run - send_stats "맞춤형 작업공간" + send_stats "自定义工作区" ;; 23) - read -e -p "다음과 같이 백그라운드에서 실행하려는 명령을 입력하십시오. 컬 -fsSL https://get.docker.com | 쉿:" tmuxd + read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd tmux_run_d - send_stats "백그라운드 작업 공간에 명령 삽입" + send_stats "注入命令到后台工作区" ;; 24) - read -e -p "삭제하려는 작업공간의 이름을 입력하세요:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "작업공간 삭제" + send_stats "删除工作区" ;; 0) kejilion ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -18112,20 +17941,20 @@ linux_work() { -# 지능형 스위칭 미러 소스 기능 +# 智能切换镜像源函数 switch_mirror() { - # 선택적 매개변수, 기본값은 false입니다. + # 可选参数,默认为 false local upgrade_software=${1:-false} local clean_cache=${2:-false} - # 사용자 국가 가져오기 + # 获取用户国家 local country country=$(curl -s ipinfo.io/country) - echo "감지된 국가:$country" + echo "检测到国家:$country" if [ "$country" = "CN" ]; then - echo "국내 미러 소스를 사용하세요..." + echo "使用国内镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.huaweicloud.com \ --protocol https \ @@ -18137,7 +17966,7 @@ switch_mirror() { --install-epel false \ --pure-mode else - echo "해외 미러 소스를 활용하세요.." + echo "使用海外镜像源..." if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ @@ -18167,27 +17996,27 @@ switch_mirror() { fail2ban_panel() { root_use - send_stats "SSH 방어" + send_stats "ssh防御" while true; do check_f2b_status - echo -e "SSH 방어 프로그램$check_f2b_status" - echo "fall2ban은 무차별 대입 크래킹을 방지하는 SSH 도구입니다." - echo "공식 웹사이트 소개:${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH防御程序 $check_f2b_status" + echo "fail2ban是一个SSH防止暴力破解工具" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 방어 프로그램 설치" + echo "1. 安装防御程序" echo "------------------------" - echo "2. SSH 차단 기록 보기" - echo "3. 실시간 로그 모니터링" + echo "2. 查看SSH拦截记录" + echo "3. 日志实时监控" echo "------------------------" - echo "4. 기본 매개변수 구성(금지 기간/기간/재시도 횟수)" - echo "5. 구성 파일 편집(나노)" + echo "4. 基础参数配置(封禁时长/时间窗口/重试次数)" + echo "5. 编辑配置文件(nano)" echo "------------------------" - echo "9. 방어 프로그램 제거" + echo "9. 卸载防御程序" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) f2b_install_sshd @@ -18206,19 +18035,19 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH 방어 기본 매개변수 구성" + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; 5) - send_stats "SSH 방어 편집 구성 파일" + send_stats "SSH防御编辑配置文件" f2b_edit_config break_end ;; 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2Ban 방어 프로그램이 제거되었습니다." + echo "Fail2Ban防御程序已卸载" break ;; *) @@ -18235,10 +18064,10 @@ fail2ban_panel() { net_menu() { - send_stats "네트워크 카드 관리 도구" + send_stats "网卡管理工具" show_nics() { - echo "================ 현재 네트워크 카드 정보 =================" - printf "%-18s %-12s %-20s %-26s\n" "네트워크 카드 이름" "상태" "IP 주소" "MAC 주소" + echo "================ 当前网卡信息 ================" + printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -18253,50 +18082,50 @@ net_menu() { clear show_nics echo - echo "=========== 네트워크 카드 관리 메뉴 ===========" - echo "1. 네트워크 카드 활성화" - echo "2. 네트워크 카드 비활성화" - echo "3. 네트워크 카드 세부정보 보기" - echo "4. 네트워크 카드 정보 새로 고침" - echo "0. 이전 메뉴로 돌아가기" + echo "=========== 网卡管理菜单 ===========" + echo "1. 启用网卡" + echo "2. 禁用网卡" + echo "3. 查看网卡详细信息" + echo "4. 刷新网卡信息" + echo "0. 返回上一级选单" echo "====================================" - read -erp "작업을 선택하십시오:" choice + read -erp "请选择操作: " choice case $choice in 1) - send_stats "네트워크 카드 활성화" - read -erp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic + send_stats "启用网卡" + read -erp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" + ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" else - echo "✘ 네트워크 카드가 존재하지 않습니다." + echo "✘ 网卡不存在" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 2) - send_stats "네트워크 카드 비활성화" - read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic + send_stats "禁用网卡" + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" + ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" else - echo "✘ 네트워크 카드가 존재하지 않습니다." + echo "✘ 网卡不存在" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 3) - send_stats "네트워크 카드 세부정보 보기" - read -erp "보려는 네트워크 카드의 이름을 입력하십시오:" nic + send_stats "查看网卡详情" + read -erp "请输入要查看的网卡名: " nic if ip link show "$nic" &>/dev/null; then - echo "========== $nic세부정보 ==========" + echo "========== $nic 详细信息 ==========" ip addr show "$nic" ethtool "$nic" 2>/dev/null | head -n 10 else - echo "✘ 네트워크 카드가 존재하지 않습니다." + echo "✘ 网卡不存在" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 4) - send_stats "네트워크 카드 정보 새로 고침" + send_stats "刷新网卡信息" continue ;; *) @@ -18309,17 +18138,17 @@ net_menu() { log_menu() { - send_stats "시스템 로그 관리 도구" + send_stats "系统日志管理工具" show_log_overview() { - echo "============= 시스템 로그 개요 =============" - echo "호스트 이름: $(호스트 이름)" - echo "시스템 시간: $(날짜)" + echo "============= 系统日志概览 =============" + echo "主机名: $(hostname)" + echo "系统时间: $(date)" echo - echo "[/var/log 디렉토리 직업]" + echo "[ /var/log 目录占用 ]" du -sh /var/log 2>/dev/null echo - echo "[일지 로그 직업]" + echo "[ journal 日志占用 ]" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -18328,77 +18157,77 @@ log_menu() { clear show_log_overview echo - echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 보기" - echo "2. 지정된 서비스 로그 보기" - echo "3. 로그인/보안 로그 보기" - echo "4. 실시간 추적 로그" - echo "5. 오래된 저널 로그 정리" - echo "0. 이전 메뉴로 돌아가기" + echo "=========== 系统日志管理菜单 ===========" + echo "1. 查看最近系统日志(journal)" + echo "2. 查看指定服务日志" + echo "3. 查看登录/安全日志" + echo "4. 实时跟踪日志" + echo "5. 清理旧 journal 日志" + echo "0. 返回上一级选单" echo "=======================================" - read -erp "작업을 선택하십시오:" choice + read -erp "请选择操作: " choice case $choice in 1) - send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + send_stats "查看最近日志" + read -erp "查看最近多少行日志?[默认 100]: " lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 2) - send_stats "지정된 서비스 로그 보기" - read -erp "서비스 이름(예: sshd, nginx)을 입력하세요." svc + send_stats "查看指定服务日志" + read -erp "请输入服务名(如 sshd、nginx): " svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else - echo "✘ 서비스가 존재하지 않거나 로그가 없습니다." + echo "✘ 服务不存在或无日志" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 3) - send_stats "로그인/보안 로그 보기" - echo "====== 최근 로그인 로그 ======" + send_stats "查看登录/安全日志" + echo "====== 最近登录日志 ======" last -n 10 echo - echo "====== 인증 로그 ======" + echo "====== 认证日志 ======" if [ -f /var/log/secure ]; then tail -n 20 /var/log/secure elif [ -f /var/log/auth.log ]; then tail -n 20 /var/log/auth.log else - echo "보안 로그 파일을 찾을 수 없습니다." + echo "未找到安全日志文件" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." ;; 4) - send_stats "실시간 추적 로그" - echo "1) 시스템 로그" - echo "2) 서비스 로그 지정" - read -erp "추적 유형 선택:" t + send_stats "实时跟踪日志" + echo "1) 系统日志" + echo "2) 指定服务日志" + read -erp "选择跟踪类型: " t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -erp "서비스 이름 입력:" svc + read -erp "输入服务名: " svc journalctl -u "$svc" -f else - echo "잘못된 선택" + echo "无效选择" fi ;; 5) - send_stats "오래된 저널 로그 정리" - echo "⚠️ 일지를 청소하세요(안전한 방법)" - echo "1) 최근 7일을 보관" - echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." - read -erp "청소 방법을 선택하세요:" c + send_stats "清理旧 journal 日志" + echo "⚠️ 清理 journal 日志(安全方式)" + echo "1) 保留最近 7 天" + echo "2) 保留最近 3 天" + echo "3) 限制日志最大 500M" + read -erp "请选择清理方式: " c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; 3) journalctl --vacuum-size=500M ;; - *) echo "잘못된 옵션" ;; + *) echo "无效选项" ;; esac - echo "✔ 저널 로그 정리 완료" + echo "✔ journal 日志清理完成" sleep 2 ;; *) @@ -18415,13 +18244,13 @@ env_menu() { BASHRC="$HOME/.bashrc" PROFILE="$HOME/.profile" - send_stats "시스템 변수 관리 도구" + send_stats "系统变量管理工具" show_env_vars() { clear - send_stats "현재 유효한 환경 변수" - echo "========== 현재 적용되는 환경변수(발췌) ==========" - printf "%-20s %s\n" "변수 이름" "값" + send_stats "当前已生效环境变量" + echo "========== 当前已生效环境变量(节选) ==========" + printf "%-20s %s\n" "变量名" "值" echo "-----------------------------------------------" for v in USER HOME SHELL LANG PWD; do printf "%-20s %s\n" "$v" "${!v}" @@ -18432,17 +18261,17 @@ env_menu() { echo "$PATH" | tr ':' '\n' | nl -ba echo - echo "========== 구성 파일에 정의된 변수(파싱) ==========" + echo "========== 配置文件中定义的变量(解析) ==========" parse_file_vars() { local file="$1" [ -f "$file" ] || return echo - echo ">>> 소스 파일:$file" + echo ">>> 来源文件:$file" echo "-----------------------------------------------" - # 내보내기 VAR=xxx 또는 VAR=xxx 추출 + # 提取 export VAR=xxx 或 VAR=xxx grep -Ev '^\s*#|^\s*$' "$file" \ | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ | while read -r line; do @@ -18457,55 +18286,55 @@ env_menu() { echo echo "===============================================" - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." } view_file() { local file="$1" - send_stats "변수 파일 보기$file" + send_stats "查看变量文件 $file" clear if [ -f "$file" ]; then - echo "========== 파일 보기:$file ==========" + echo "========== 查看文件:$file ==========" cat -n "$file" echo "====================================" else - echo "파일이 존재하지 않습니다:$file" + echo "文件不存在:$file" fi - read -erp "계속하려면 Enter를 누르세요..." + read -erp "按回车继续..." } edit_file() { local file="$1" - send_stats "변수 파일 편집$file" + send_stats "编辑变量文件 $file" install nano nano "$file" } source_files() { - echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드 중" + echo "正在重新加载环境变量..." + send_stats "正在重新加载环境变量" source "$BASHRC" source "$PROFILE" - echo "✔ 환경 변수가 다시 로드되었습니다." - read -erp "계속하려면 Enter를 누르세요..." + echo "✔ 环境变量已重新加载" + read -erp "按回车继续..." } while true; do clear - echo "=========== 시스템 환경 변수 관리 ==========" - echo "현재 사용자:$USER" + echo "=========== 系统环境变量管理 ==========" + echo "当前用户:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." - echo "2. ~/.bashrc 보기" - echo "3. ~/.profile 보기" - echo "4. ~/.bashrc 편집" - echo "5. ~/.profile 편집" - echo "6. 환경 변수 다시 로드(출처)" + echo "1. 查看当前常用环境变量" + echo "2. 查看 ~/.bashrc" + echo "3. 查看 ~/.profile" + echo "4. 编辑 ~/.bashrc" + echo "5. 编辑 ~/.profile" + echo "6. 重新加载环境变量(source)" echo "--------------------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "--------------------------------------" - read -erp "작업을 선택하십시오:" choice + read -erp "请选择操作: " choice case "$choice" in 1) @@ -18530,7 +18359,7 @@ env_menu() { break ;; *) - echo "잘못된 옵션" + echo "无效选项" sleep 1 ;; esac @@ -18544,40 +18373,40 @@ create_user_with_sshkey() { local sshkey_vl if [[ -z "$new_username" ]]; then - echo "사용법: create_user_with_sshkey <사용자 이름>" + echo "用法:create_user_with_sshkey <用户名>" return 1 fi - # 사용자 생성 + # 创建用户 useradd -m -s /bin/bash "$new_username" || return 1 - echo "공개 키 가져오기의 예:" + echo "导入公钥范例:" echo " - URL: ${gh_https_url}github.com/torvalds.keys" - echo "- 직접 붙여넣기: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." - read -e -p "수입해주세요${new_username}공개 키:" sshkey_vl + echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl case "$sshkey_vl" in http://*|https://*) - send_stats "URL에서 SSH 공개 키 가져오기" + send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "공개 키를 직접 가져오기" + send_stats "公钥直接导入" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) - echo "오류: 알 수 없는 매개변수 '$sshkey_vl'" + echo "错误:未知参数 '$sshkey_vl'" return 1 ;; esac - # 권한 수정 + # 修正权限 chown -R "$new_username:$new_username" "/home/$new_username/.ssh" install sudo - # sudo 비밀번호가 필요하지 않음 + # sudo 免密 if [[ "$is_sudo" == "true" ]]; then cat >"/etc/sudoers.d/$new_username" </dev/null restart_ssh - echo "사용자$new_username생성 완료" + echo "用户 $new_username 创建完成" } @@ -18611,48 +18440,48 @@ linux_Settings() { while true; do clear - # send_stats "시스템 도구" - echo -e "시스템 도구" + # send_stats "系统工具" + echo -e "系统工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" - echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" - echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" + echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" + echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" + echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" - echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" - echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속 설정" - echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름 수정" - echo -e "${gl_kjlan}19. ${gl_bai}시스템 업데이트 소스 전환${gl_kjlan}20. ${gl_bai}예약된 작업 관리" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" + echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" + echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" - echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" + echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}用户密钥登录模式" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}시스템 언어 전환${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" - echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" - echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}rsync 원격 동기화 도구" - echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}네트워크 카드 관리 도구" + echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" + echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}시스템 로그 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}시스템 변수 관리 도구" + echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系统变量管理工具" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원스톱 시스템 튜닝${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하세요${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" - echo -e "${gl_kjlan}101. ${gl_bai}k 명령의 고급 사용법${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 사자 스크립트 제거" + echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" + echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) while true; do clear - read -e -p "바로가기 키를 입력하십시오(종료하려면 0을 입력하십시오):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -18662,8 +18491,8 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "단축키가 설정되었습니다" - send_stats "스크립트 단축키가 설정되었습니다" + echo "快捷键已设置" + send_stats "脚本快捷键已设置" break_end linux_Settings done @@ -18671,8 +18500,8 @@ linux_Settings() { 2) clear - send_stats "로그인 비밀번호를 설정하세요" - echo "로그인 비밀번호를 설정하세요" + send_stats "设置你的登录密码" + echo "设置你的登录密码" passwd ;; 3) @@ -18682,22 +18511,22 @@ linux_Settings() { 4) root_use - send_stats "py 버전 관리" - echo "파이썬 버전 관리" - echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "py版本管理" + echo "python版本管理" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "권장 버전: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "더 많은 버전 확인: https://www.python.org/downloads/" + echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" - read -e -p "설치하려는 Python 버전 번호를 입력하세요(종료하려면 0 입력)." py_new_v + read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "스크립트 PY 관리" + send_stats "脚本PY管理" break_end linux_Settings fi @@ -18730,7 +18559,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "알 수 없는 패키지 관리자입니다!" + echo "未知的包管理器!" return fi @@ -18759,55 +18588,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 PY 버전 전환" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + send_stats "脚本PY版本切换" ;; 5) root_use - send_stats "열린 포트" + send_stats "开放端口" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "모든 포트가 열려 있습니다." + echo "端口已全部开放" ;; 6) root_use - send_stats "SSH 포트 수정" + send_stats "修改SSH端口" while true; do clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 현재 SSH 포트 번호 읽기 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 현재 SSH 포트 번호 인쇄 - echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" + # 打印当前的 SSH 端口号 + echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "포트 번호 범위는 1~65535입니다. (종료하려면 0을 입력하세요.)" + echo "端口号范围1到65535之间的数字。(输入0退出)" - # 사용자에게 새 SSH 포트 번호를 묻는 메시지 표시 - read -e -p "새 SSH 포트 번호를 입력하세요." new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port - # 포트 번호가 유효한 범위 내에 있는지 확인 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH 포트가 수정되었습니다." + send_stats "SSH端口已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "SSH 포트 수정 종료" + send_stats "退出SSH端口修改" break else - echo "포트 번호가 잘못되었습니다. 1~65535 사이의 숫자를 입력하세요." - send_stats "잘못된 SSH 포트가 입력되었습니다." + echo "端口号无效,请输入1到65535之间的数字。" + send_stats "输入无效SSH端口" break_end fi else - echo "입력이 잘못되었습니다. 숫자를 입력하세요." - send_stats "잘못된 SSH 포트가 입력되었습니다." + echo "输入无效,请输入数字。" + send_stats "输入无效SSH端口" break_end fi done @@ -18826,8 +18655,8 @@ EOF ;; 9) root_use - send_stats "신규 사용자에 대한 루트 비활성화" - read -e -p "새 사용자 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_username + send_stats "新用户禁用root" + read -e -p "请输入新用户名(输入0退出): " new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -18845,26 +18674,26 @@ EOF 10) root_use - send_stats "v4/v6 우선순위 설정" + send_stats "设置v4/v6优先级" while true; do clear - echo "v4/v6 우선순위 설정" + echo "设置v4/v6优先级" echo "------------------------" if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv4${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" else - echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv6${gl_bai}우선 사항" + echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" fi echo "" echo "------------------------" - echo "1. IPv4 우선 2. IPv6 우선 3. IPv6 복구 도구" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선호하는 네트워크를 선택하세요:" choice + read -e -p "选择优先的网络: " choice case $choice in 1) @@ -18872,15 +18701,15 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "已切换为 IPv6 优先" + send_stats "已切换为 IPv6 优先" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "이 기능은 jhb에서 제공합니다. 감사합니다!" - send_stats "IPv6 수리" + echo "该功能由jhb大神提供,感谢他!" + send_stats "ipv6修复" ;; *) @@ -18898,43 +18727,43 @@ EOF 12) root_use - send_stats "가상 메모리 설정" + send_stats "设置虚拟内存" while true; do clear - echo "가상 메모리 설정" + echo "设置虚拟内存" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "현재 가상 메모리:${gl_huang}$swap_info${gl_bai}" + echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 1024M 할당 2. 2048M 할당 3. 4096M 할당 4. 사용자 정의 크기" + echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; 2) - send_stats "2G 가상 메모리가 설정되었습니다" + send_stats "已设置2G虚拟内存" add_swap 2048 ;; 3) - send_stats "4G 가상 메모리가 설정되었습니다." + send_stats "已设置4G虚拟内存" add_swap 4096 ;; 4) - read -e -p "가상 메모리 크기(단위 M)를 입력하세요." new_swap + read -e -p "请输入虚拟内存大小(单位M): " new_swap add_swap "$new_swap" - send_stats "사용자 정의 가상 메모리 세트" + send_stats "已设置自定义虚拟内存" ;; *) @@ -18947,10 +18776,10 @@ EOF 13) while true; do root_use - send_stats "사용자 관리" - echo "사용자 목록" + send_stats "用户管理" + echo "用户列表" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "사용자 이름" "사용자 권한" "사용자 그룹" "sudo 권한" + printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status @@ -18964,34 +18793,34 @@ EOF echo "" - echo "계정 운영" + echo "账户操作" echo "------------------------" - echo "1. 일반 사용자 생성 2. 고급 사용자 생성" + echo "1. 创建普通用户 2. 创建高级用户" echo "------------------------" - echo "3. 가장 높은 권한을 부여합니다. 4. 가장 높은 권한을 제거합니다." + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" - echo "5. 계정 삭제" + echo "5. 删除账号" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - # 사용자에게 새 사용자 이름을 묻는 메시지 표시 - read -e -p "새 사용자 이름을 입력하세요:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username create_user_with_sshkey $new_username false ;; 2) - # 사용자에게 새 사용자 이름을 묻는 메시지 표시 - read -e -p "새 사용자 이름을 입력하세요:" new_username + # 提示用户输入新用户名 + read -e -p "请输入新用户名: " new_username create_user_with_sshkey $new_username true ;; 3) - read -e -p "사용자 이름을 입력하세요:" username + read -e -p "请输入用户名: " username install sudo cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f fi sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "삭제하려는 사용자 이름을 입력하세요:" username + read -e -p "请输入要删除的用户名: " username userdel -r "$username" ;; @@ -19021,50 +18850,50 @@ EOF 14) clear - send_stats "사용자 정보 생성기" - echo "임의의 사용자 이름" + send_stats "用户信息生成器" + echo "随机用户名" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "임의의 사용자 이름$i: $username" + echo "随机用户名 $i: $username" done echo "" - echo "임의의 이름" + echo "随机姓名" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 5개의 무작위 사용자 이름 생성 + # 生成5个随机用户姓名 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "임의의 사용자 이름$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" - echo "무작위 UUID" + echo "随机UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "무작위 UUID$i: $uuid" + echo "随机UUID $i: $uuid" done echo "" - echo "16자리 랜덤 비밀번호" + echo "16位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "임의의 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" - echo "32비트 임의 비밀번호" + echo "32位随机密码" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "임의의 비밀번호$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -19072,46 +18901,46 @@ EOF 15) root_use - send_stats "시간대 변경" + send_stats "换时区" while true; do clear - echo "시스템 시간 정보" + echo "系统时间信息" - # 현재 시스템 시간대 가져오기 + # 获取当前系统时区 local timezone=$(current_timezone) - # 현재 시스템 시간을 가져옵니다 + # 获取当前系统时间 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 시간대 및 시간 표시 - echo "현재 시스템 시간대:$timezone" - echo "현재 시스템 시간:$current_time" + # 显示时区和时间 + echo "当前系统时区:$timezone" + echo "当前系统时间:$current_time" echo "" - echo "시간대 스위치" + echo "时区切换" echo "------------------------" - echo "아시아" - echo "1. 중국 상하이 시간 2. 중국 홍콩 시간" - echo "3. 일본 도쿄 시간 4. 한국 서울 시간" - echo "5. 싱가포르 시간 6. 콜카타, 인도 시간" - echo "7. 아랍에미리트 두바이 시간 8. 호주 시드니 시간" - echo "9. 태국 방콕 시간" + echo "亚洲" + echo "1. 中国上海时间 2. 中国香港时间" + echo "3. 日本东京时间 4. 韩国首尔时间" + echo "5. 新加坡时间 6. 印度加尔各答时间" + echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" + echo "9. 泰国曼谷时间" echo "------------------------" - echo "유럽" - echo "11. 영국 런던 시간 12. 프랑스 파리 시간" - echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "欧洲" + echo "11. 英国伦敦时间 12. 法国巴黎时间" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" - echo "미국" - echo "21. 미국 서부 시간 22. 미국 동부 시간" - echo "23. 캐나다 시간 24. 멕시코 시간" - echo "25. 브라질 시간 26. 아르헨티나 시간" + echo "美洲" + echo "21. 美国西部时间 22. 美国东部时间" + echo "23. 加拿大时间 24. 墨西哥时间" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" - echo "31. UTC 세계 표준시" + echo "31. UTC全球标准时间" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in @@ -19154,21 +18983,21 @@ EOF 18) root_use - send_stats "호스트 이름 수정" + send_stats "修改主机名" while true; do clear local current_hostname=$(uname -n) - echo -e "현재 호스트 이름:${gl_huang}$current_hostname${gl_bai}" + echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "새 호스트 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_hostname + read -e -p "请输入新的主机名(输入0退出): " new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # 其他系统,如 Debian, Ubuntu, CentOS 等 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -19186,11 +19015,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "호스트 이름이 다음으로 변경되었습니다.$new_hostname" - send_stats "호스트 이름이 변경됨" + echo "主机名已更改为: $new_hostname" + send_stats "主机名已更改" sleep 1 else - echo "호스트 이름을 변경하지 않고 종료되었습니다." + echo "已退出,未更改主机名。" break fi done @@ -19198,37 +19027,37 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스 변경" + send_stats "换系统更新源" clear - echo "업데이트 소스 지역 선택" - echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" + echo "选择更新源区域" + echo "接入LinuxMirrors切换系统更新源" echo "------------------------" - echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + read -e -p "输入你的选择: " choice case $choice in 1) - send_stats "중국 본토 기본 소스" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "중국 본토 교육 소스" + send_stats "中国大陆教育源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "해외 소스" + send_stats "海外源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; 4) - send_stats "업데이트 소스의 지능적인 전환" + send_stats "智能切换更新源" switch_mirror false false ;; *) - echo "취소" + echo "已取消" ;; esac @@ -19236,62 +19065,62 @@ EOF ;; 20) - send_stats "예약된 작업 관리" + send_stats "定时任务管理" while true; do clear check_crontab_installed clear - echo "예약된 작업 목록" + echo "定时任务列表" crontab -l echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 예약된 작업 추가 2. 예약된 작업 삭제 3. 예약된 작업 편집" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - read -e -p "새 작업의 실행 명령을 입력하십시오:" newquest + read -e -p "请输入新任务的执行命令: " newquest echo "------------------------" - echo "1. 월간 작업 2. 주간 작업" - echo "3. 일일 작업 4. 시간별 작업" + echo "1. 每月任务 2. 每周任务" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" - read -e -p "선택사항을 입력하세요:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day + read -e -p "选择每月的几号执行任务? (1-30): " day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "작업을 수행할 요일을 선택하시겠습니까? (0-6, 0은 일요일을 나타냄):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "매일 몇 시에 작업을 수행하기로 선택하시나요? (시간, 0-23):" hour + read -e -p "选择每天几点执行任务?(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "작업을 실행해야 하는 시간을 입력하세요. (분, 0-60):" minute + read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "예약된 작업 추가" + send_stats "添加定时任务" ;; 2) - read -e -p "삭제할 작업의 키워드를 입력하세요:" kquest + read -e -p "请输入需要删除任务的关键字: " kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "예약된 작업 삭제" + send_stats "删除定时任务" ;; 3) crontab -e - send_stats "예약된 작업 편집" + send_stats "编辑定时任务" ;; *) break # 跳出循环,退出菜单 @@ -19303,32 +19132,32 @@ EOF 21) root_use - send_stats "로컬 호스트 확인" + send_stats "本地host解析" while true; do clear - echo "기본 호스트 확인 목록" - echo "여기에 파싱 매칭을 추가하면 더 이상 동적 파싱이 사용되지 않습니다." + echo "本机host解析列表" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" - echo "작동하다" + echo "操作" echo "------------------------" - echo "1. 새로운 해상도 추가 2. 해상도 주소 삭제" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) - read -e -p "새로운 구문 분석 기록 형식을 입력하세요: 110.25.5.33 kejilion.pro:" addhost + read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost echo "$addhost" >> /etc/hosts - send_stats "로컬 호스트 해상도가 추가되었습니다." + send_stats "本地host解析新增" ;; 2) - read -e -p "삭제해야 하는 구문 분석된 콘텐츠의 키워드를 입력하세요." delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts - send_stats "로컬 호스트 확인 및 삭제" + send_stats "本地host解析删除" ;; *) break # 跳出循环,退出菜单 @@ -19344,47 +19173,47 @@ EOF 23) root_use - send_stats "전류 제한 차단 기능" + send_stats "限流关机功能" while true; do clear - echo "전류 제한 차단 기능" - echo "영상 소개: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "限流关机功能" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "서버가 다시 시작되면 현재 트래픽 사용량이 지워집니다!" + echo "当前流量使用情况,重启服务器流量计算会清零!" output_status - echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" - echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" + echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" + echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" - # Limiting_Shut_down.sh 파일이 있는지 확인하세요. + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then - # Threshold_gb 값을 가져옵니다. + # 获取 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" fi echo echo "------------------------------------------------" - echo "시스템은 매분마다 실제 트래픽이 임계값에 도달했는지 여부를 감지하고 임계값에 도달한 후 자동으로 서버를 종료합니다!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" - echo "1. 전류 제한 종료 기능을 활성화합니다. 2. 전류 제한 종료 기능을 비활성화합니다." + echo "1. 开启限流关机功能 2. 停用限流关机功能" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) - # 새 가상 메모리 크기 입력 - echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." - read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb + # 输入新的虚拟内存大小 + echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" + read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb + read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일 재설정)." cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -19397,15 +19226,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "전류 제한 종료가 설정되었습니다." - send_stats "전류 제한 종료가 설정되었습니다." + echo "限流关机已设置" + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 차단 기능이 꺼졌습니다." + echo "已关闭限流关机功能" ;; *) break @@ -19421,18 +19250,18 @@ EOF 25) root_use - send_stats "전신 경고" - echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + send_stats "电报预警" + echo "TG-bot监控预警功能" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." - echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." - echo -e "${gl_hui}- 트래픽에 관해서는 서버를 다시 시작하면 다시 계산됩니다 -${gl_bai}" - read -e -p "계속하시겠습니까? (예/아니요):" choice + echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" + echo "到达阈值后会向用户发预警消息" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "텔레그램 경고 활성화됨" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -19454,7 +19283,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # ~/.profile 파일에 추가 + # 添加到 ~/.profile 文件中 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -19465,21 +19294,21 @@ EOF source ~/.profile clear - echo "TG-bot 조기경보 시스템이 활성화되었습니다." - echo -e "${gl_hui}TG-check-notify.sh 경고 파일을 다른 컴퓨터의 루트 디렉터리에 넣고 직접 사용할 수도 있습니다!${gl_bai}" + echo "TG-bot预警系统已启动" + echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; 26) root_use - send_stats "고위험 SSH 취약점 수정" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -19523,7 +19352,7 @@ EOF ;; 37) clear - send_stats "명령줄 기록" + send_stats "命令行历史记录" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -19562,94 +19391,94 @@ EOF 61) clear - send_stats "메시지 보드" - echo "Technology Lion 공식 게시판을 방문해 보세요. 스크립트에 대한 아이디어가 있으시면 교환 메시지를 남겨주세요!" + send_stats "留言板" + echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" echo "https://board.kejilion.pro" - echo "공개 비밀번호: kejilion.sh" + echo "公共密码: kejilion.sh" ;; 66) root_use - send_stats "원스톱 튜닝" - echo "원스톱 시스템 튜닝" + send_stats "一条龙调优" + echo "一条龙系统调优" echo "------------------------------------------------" - echo "다음 콘텐츠가 운영 및 최적화됩니다." - echo "1. 시스템 업데이트 소스를 최적화하고 시스템을 최신 버전으로 업데이트하세요." - echo "2. 시스템 정크 파일 정리" - echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" - echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" - echo -e "5. SSH 무차별 대입 크래킹을 방어하기 위해 fall2ban을 시작하세요." - echo -e "6. 모든 포트를 엽니다" - echo -e "7. 켜다${gl_huang}BBR${gl_bai}가속하다" - echo -e "8. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" - echo -e "9. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" - echo -e "10. 네트워크를 다음으로 설정합니다.${gl_huang}IPv4 우선순위${gl_bai}" - echo -e "11. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux 시스템 커널 매개변수 최적화${gl_huang}네트워크 환경에 따라 자동으로 튜닝${gl_bai}" + echo "将对以下内容进行操作与优化" + echo "1. 优化系统更新源,更新系统到最新" + echo "2. 清理系统垃圾文件" + echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "5. 启动fail2ban防御SSH暴力破解" + echo -e "6. 开放所有端口" + echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" + echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux系统内核参数优化${gl_huang}自动根据网络环境调优${gl_bai}" echo "------------------------------------------------" - read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice + read -e -p "确定一键保养吗?(Y/N): " choice case "$choice" in [Yy]) clear - send_stats "원스톱 튜닝 시작" + send_stats "一条龙调优启动" echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 시스템을 최신으로 업데이트하세요" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 시스템 정크 파일 정리" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 가상 메모리 설정${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 - echo -e "[${gl_lv}OK${gl_bai}] 4/12. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd cd ~ f2b_status - echo -e "[${gl_lv}OK${gl_bai}] 5/12. SSH 무차별 대입 크래킹을 방어하려면 Fail2ban을 시작하세요." + echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 모든 포트 열기" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 7/12. 열려 있는${gl_huang}BBR${gl_bai}가속하다" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 9/12. DNS 주소 자동 최적화${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 네트워크를 다음으로 설정하세요.${gl_huang}IPv4 우선순위${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux 시스템 커널 매개변수 최적화" - echo -e "${gl_lv}원스톱 시스템 튜닝이 완료되었습니다${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" + echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac @@ -19657,7 +19486,7 @@ EOF 99) clear - send_stats "시스템을 다시 시작하세요" + send_stats "重启系统" server_reboot ;; 100) @@ -19666,39 +19495,39 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}데이터 수집${gl_bai}" + local status_message="${gl_lv}正在采集数据${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}컬렉션이 닫혔습니다.${gl_bai}" + local status_message="${gl_hui}采集已关闭${gl_bai}" else - local status_message="불확실한 상태" + local status_message="无法确定的状态" fi - echo "개인 정보 보호 및 보안" - echo "스크립트는 사용자의 기능 사용에 대한 데이터를 수집하고 스크립트 경험을 최적화하며 더 재미 있고 유용한 기능을 만듭니다." - echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 사용된 기능 이름이 수집됩니다." + echo "隐私与安全" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" - echo -e "현재 상태:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" - echo "1. 수집 시작" - echo "2. 수집 종료" + echo "1. 开启采集" + echo "2. 关闭采集" echo "--------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "--------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 시작되었습니다" - send_stats "개인정보 보호 및 보안 수집이 사용 설정되었습니다." + echo "已开启采集" + send_stats "隐私与安全已开启采集" ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "컬렉션이 닫혔습니다." - send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." + echo "已关闭采集" + send_stats "隐私与安全已关闭采集" ;; *) break @@ -19714,11 +19543,11 @@ EOF 102) clear - send_stats "기술 사자 스크립트 제거" - echo "기술 사자 스크립트 제거" + send_stats "卸载科技lion脚本" + echo "卸载科技lion脚本" echo "------------------------------------------------" - echo "kejilion 스크립트는 다른 기능에 영향을 주지 않고 완전히 제거됩니다." - read -e -p "계속하시겠습니까? (예/아니요):" choice + echo "将彻底卸载kejilion脚本,不影响你其他功能" + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -19726,16 +19555,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "스크립트가 제거되었습니다. 안녕!" + echo "脚本已卸载,再见!" break_end clear exit ;; [Nn]) - echo "취소" + echo "已取消" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -19745,7 +19574,7 @@ EOF ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -19763,174 +19592,174 @@ EOF linux_file() { root_use - send_stats "파일 관리자" + send_stats "文件管理器" while true; do clear - echo "파일 관리자" + echo "文件管理器" echo "------------------------" - echo "현재 경로" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉터리 입력 2. 디렉터리 생성 3. 디렉터리 권한 수정 4. 디렉터리 이름 바꾸기" - echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" - echo "11. 파일 생성 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" - echo "15. 파일 삭제" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "15. 删除文件" echo "------------------------" - echo "21. 파일 디렉터리 압축 22. 파일 디렉터리 압축 풀기 23. 파일 디렉터리 이동 24. 파일 디렉터리 복사" - echo "25. 다른 서버로 파일 전송" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "25. 传文件至其他服务器" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" - read -e -p "선택사항을 입력하세요:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "디렉토리 이름을 입력하십시오:" dirname - cd "$dirname" 2>/dev/null || echo "디렉토리에 들어갈 수 없습니다" - send_stats "디렉토리 입력" + read -e -p "请输入目录名: " dirname + cd "$dirname" 2>/dev/null || echo "无法进入目录" + send_stats "进入目录" ;; 2) # 创建目录 - read -e -p "생성할 디렉터리 이름을 입력하세요." dirname - mkdir -p "$dirname" && echo "디렉터리가 생성되었습니다." || echo "생성 실패" - send_stats "디렉터리 생성" + read -e -p "请输入要创建的目录名: " dirname + mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" + send_stats "创建目录" ;; 3) # 修改目录权限 - read -e -p "디렉토리 이름을 입력하십시오:" dirname - read -e -p "권한을 입력하세요(예: 755):" perm - chmod "$perm" "$dirname" && echo "권한이 수정되었습니다." || echo "수정 실패" - send_stats "디렉터리 권한 수정" + read -e -p "请输入目录名: " dirname + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" + send_stats "修改目录权限" ;; 4) # 重命名目录 - read -e -p "현재 디렉터리 이름을 입력하세요." current_name - read -e -p "새 디렉터리 이름을 입력하세요." new_name - mv "$current_name" "$new_name" && echo "디렉터리 이름이 변경되었습니다." || echo "이름 바꾸기 실패" - send_stats "디렉터리 이름 바꾸기" + read -e -p "请输入当前目录名: " current_name + read -e -p "请输入新目录名: " new_name + mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" + send_stats "重命名目录" ;; 5) # 删除目录 - read -e -p "삭제할 디렉터리 이름을 입력하세요:" dirname - rm -rf "$dirname" && echo "디렉터리가 삭제되었습니다." || echo "삭제 실패" - send_stats "디렉토리 삭제" + read -e -p "请输入要删除的目录名: " dirname + rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" + send_stats "删除目录" ;; 6) # 返回上一级选单目录 cd .. - send_stats "이전 메뉴 디렉토리로 돌아가기" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 - read -e -p "생성할 파일 이름을 입력하세요:" filename - touch "$filename" && echo "파일이 생성되었습니다." || echo "생성 실패" - send_stats "파일 생성" + read -e -p "请输入要创建的文件名: " filename + touch "$filename" && echo "文件已创建" || echo "创建失败" + send_stats "创建文件" ;; 12) # 编辑文件 - read -e -p "편집할 파일 이름을 입력하십시오:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" - send_stats "파일 편집" + send_stats "编辑文件" ;; 13) # 修改文件权限 - read -e -p "파일 이름을 입력하세요:" filename - read -e -p "권한을 입력하세요(예: 755):" perm - chmod "$perm" "$filename" && echo "권한이 수정되었습니다." || echo "수정 실패" - send_stats "파일 권한 수정" + read -e -p "请输入文件名: " filename + read -e -p "请输入权限 (如 755): " perm + chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" + send_stats "修改文件权限" ;; 14) # 重命名文件 - read -e -p "현재 파일 이름을 입력하십시오:" current_name - read -e -p "새 파일 이름을 입력하세요:" new_name - mv "$current_name" "$new_name" && echo "파일 이름이 변경되었습니다." || echo "이름 바꾸기 실패" - send_stats "파일 이름 바꾸기" + read -e -p "请输入当前文件名: " current_name + read -e -p "请输入新文件名: " new_name + mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" + send_stats "重命名文件" ;; 15) # 删除文件 - read -e -p "삭제할 파일 이름을 입력하세요:" filename - rm -f "$filename" && echo "파일이 삭제되었습니다." || echo "삭제 실패" - send_stats "파일 삭제" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已删除" || echo "删除失败" + send_stats "删除文件" ;; 21) # 压缩文件/目录 - read -e -p "압축할 파일/디렉터리 이름을 입력하십시오:" name + read -e -p "请输入要压缩的文件/目录名: " name install tar - tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축 실패" - send_stats "압축된 파일/디렉토리" + tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오." filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar - tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "압축 해제 실패" - send_stats "파일/디렉토리 압축 풀기" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" + send_stats "解压文件/目录" ;; 23) # 移动文件或目录 - read -e -p "이동할 파일 또는 디렉터리 경로를 입력하세요." src_path + read -e -p "请输入要移动的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 이동 실패: 파일 또는 디렉터리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류: 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉터리 이동 실패: 대상 경로가 지정되지 않았습니다." + echo "错误: 请输入目标路径。" + send_stats "移动文件或目录失败: 目标路径未指定" continue fi - mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 다음으로 이동되었습니다.$dest_path" || echo "파일 또는 디렉터리를 이동하지 못했습니다." - send_stats "파일 또는 디렉터리 이동" + mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then - echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." + echo "错误: 文件或目录不存在。" + send_stats "复制文件或目录失败: 文件或目录不存在" continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path + read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path if [ -z "$dest_path" ]; then - echo "오류: 대상 경로를 입력하십시오." - send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." + echo "错误: 请输入目标路径。" + send_stats "复制文件或目录失败: 目标路径未指定" continue fi - # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. - cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." - send_stats "파일 또는 디렉터리 복사" + # 使用 -r 选项以递归方式复制目录 + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" + send_stats "复制文件或目录" ;; 25) # 传送文件至远端服务器 - read -e -p "전송할 파일 경로를 입력하십시오:" file_to_transfer + read -e -p "请输入要传送的文件路径: " file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "오류: 파일이 존재하지 않습니다." - send_stats "파일 전송 실패: 파일이 존재하지 않습니다." + echo "错误: 文件不存在。" + send_stats "传送文件失败: 文件不存在" continue fi - kj_ssh_read_host_user_port "원격 서버 IP를 입력하세요:" "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" "로그인 포트(기본값 22)를 입력하세요." "root" "22" + kj_ssh_read_host_user_port "请输入远端服务器IP: " "请输入远端服务器用户名 (默认root): " "请输入登录端口 (默认22): " "root" "22" local remote_ip="$KJ_SSH_HOST" local remote_user="$KJ_SSH_USER" local remote_port="$KJ_SSH_PORT" - kj_ssh_read_password "원격 서버 비밀번호를 입력하세요:" + kj_ssh_read_password "请输入远端服务器密码: " local remote_password="$KJ_SSH_PASSWORD" - # 알려진 호스트에 대한 이전 항목 지우기 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # scp를 사용하여 파일 전송 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}스크립트가 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트가 최신 상태입니다.$sh_v_new" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit @@ -20286,15 +20115,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}자동 업데이트가 켜져 있고 매일 새벽 2시에 스크립트가 자동으로 업데이트됩니다!${gl_bai}" - send_stats "자동 스크립트 업데이트 활성화" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" + send_stats "开启脚本自动更新" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}자동 업데이트가 꺼졌습니다${gl_bai}" - send_stats "자동 스크립트 업데이트 끄기" + echo -e "${gl_lv}自动更新已关闭${gl_bai}" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -20316,40 +20145,40 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "기술 사자 스크립트 도구 상자 v$sh_v" -echo -e "명령줄 입력${gl_huang}k${gl_kjlan}빠른 시작 스크립트${gl_bai}" +echo -e "科技lion脚本工具箱 v$sh_v" +echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" -echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" -echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" -echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" -echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" -echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" -echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" -echo -e "${gl_kjlan}8. ${gl_bai}테스트 스크립트 수집" -echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" -echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹사이트 구축" -echo -e "${gl_kjlan}11. ${gl_bai}응용 시장" -echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업공간" -echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" -echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" -echo -e "${gl_kjlan}15. ${gl_bai}광고 칼럼" -echo -e "${gl_kjlan}16. ${gl_bai}게임 서버 오프닝 스크립트 모음" +echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" +echo -e "${gl_kjlan}2. ${gl_bai}系统更新" +echo -e "${gl_kjlan}3. ${gl_bai}系统清理" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" +echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" +echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" +echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" +echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" +echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" +echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" +echo -e "${gl_kjlan}11. ${gl_bai}应用市场" +echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" +echo -e "${gl_kjlan}13. ${gl_bai}系统工具" +echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" +echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" +echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" +echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" +echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "선택사항을 입력하세요:" choice +read -e -p "请输入你的选择: " choice case $choice in 1) linux_info ;; - 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; - 3) clear ; send_stats "시스템 정리" ; linux_clean ;; + 2) clear ; send_stats "系统更新" ; linux_update ;; + 3) clear ; send_stats "系统清理" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "워프 관리" ; install wget + 7) clear ; send_stats "warp管理" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -20363,7 +20192,7 @@ case $choice in 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "입력이 잘못되었습니다!" ;; + *) echo "无效的输入!" ;; esac break_end done @@ -20371,76 +20200,76 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k命令参考用例" echo "-------------------" -echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "다음은 k 명령의 참조 사용 사례입니다." -echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." -echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" -echo "시스템 k 업데이트 업데이트 | k 업데이트" -echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" -echo "시스템 패널을 다시 설치하십시오. k dd | k 다시 설치하다" -echo "bbr3 제어판 k bbr3 | kbbrv3" -echo "커널 튜닝 패널 k nhyh | k 커널 최적화" -echo "가상 메모리 k 스왑 2048 설정" -echo "가상 시간대 설정 k 시간 아시아/상하이 | k 시간대 아시아/상하이" -echo "시스템 휴지통 k 쓰레기 | khsz | k 휴지통" -echo "시스템 백업 기능 k 백업 | k bf | k 백업" -echo "SSH 원격 연결 도구 k SSH | k 원격 연결" -echo "rsync 원격 동기화 도구 k rsync | k 원격 동기화" -echo "하드 디스크 관리 도구 k 디스크 | k 하드 디스크 관리" -echo "인트라넷 침투(서버) k frps" -echo "인트라넷 침투(클라이언트) k frpc" -echo "소프트웨어 시작 k start sshd | k sshd를 시작하세요" -echo "소프트웨어 중지 k 중지 sshd | k sshd 중지" -echo "소프트웨어 재시작 k 재시작 sshd | k sshd를 다시 시작하세요" -echo "소프트웨어 상태 확인 k status sshd | k 상태 sshd" -echo "k 도커 활성화 | k 자동 시작 도커 | k 소프트웨어를 부팅할 때 도커를 활성화합니다." -echo "도메인 이름 인증서 신청 k SSL" -echo "도메인 이름 인증서 만료 쿼리 k SSL ps" -echo "도커 관리 플레인 k 도커" -echo "docker 환경 설치 k docker 설치 |k docker 설치" -echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" -echo "도커 이미지 관리 k docker img |k 도커 이미지" -echo "LDNMP 사이트 관리 k web" -echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" -echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" -echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" -echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" -echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" -echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" -echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" -echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" -echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" -echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" -echo "Fail2ban 관리 k Fail2ban | 케이 F2B" -echo "시스템 정보 표시 k 정보" -echo "ROOT 키 관리 k sshkey" -echo "SSH 공개 키 가져오기(URL) k sshkey " -echo "SSH 공개 키 가져오기(GitHub) k sshkey github " +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令参考用例:" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" +echo "更新系统 k update | k 更新" +echo "清理系统垃圾 k clean | k 清理" +echo "重装系统面板 k dd | k 重装" +echo "bbr3控制面板 k bbr3 | k bbrv3" +echo "内核调优面板 k nhyh | k 内核优化" +echo "设置虚拟内存 k swap 2048" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" +echo "系统回收站 k trash | k hsz | k 回收站" +echo "系统备份功能 k backup | k bf | k 备份" +echo "ssh远程连接工具 k ssh | k 远程连接" +echo "rsync远程同步工具 k rsync | k 远程同步" +echo "硬盘管理工具 k disk | k 硬盘管理" +echo "内网穿透(服务端) k frps" +echo "内网穿透(客户端) k frpc" +echo "软件启动 k start sshd | k 启动 sshd " +echo "软件停止 k stop sshd | k 停止 sshd " +echo "软件重启 k restart sshd | k 重启 sshd " +echo "软件状态查看 k status sshd | k 状态 sshd " +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "域名证书申请 k ssl" +echo "域名证书到期查询 k ssl ps" +echo "docker管理平面 k docker" +echo "docker环境安装 k docker install |k docker 安装" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "安装L4负载均衡 k stream |k L4负载均衡" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" +echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" +echo "fail2ban管理 k fail2ban | k f2b" +echo "显示系统信息 k info" +echo "ROOT密钥管理 k sshkey" +echo "SSH公钥导入(URL) k sshkey " +echo "SSH公钥导入(GitHub) k sshkey github " } if [ "$#" -eq 0 ]; then - # 인수 없이 대화형 논리를 실행합니다. + # 如果没有参数,运行交互式逻辑 kejilion_sh else - # 매개변수가 있으면 해당 함수를 실행합니다. + # 如果有参数,执行相应函数 case $1 in install|add|安装) shift - send_stats "소프트웨어 설치" + send_stats "安装软件" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "소프트웨어 제거" + send_stats "卸载软件" remove "$@" ;; update|更新) @@ -20474,7 +20303,7 @@ else rsync_run) shift - send_stats "예약된 rsync 동기화" + send_stats "定时rsync同步" run_task "$@" ;; @@ -20493,7 +20322,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "IP+포트가 서비스 접근을 차단했습니다." + echo "已阻止IP+端口访问该服务" else ip_address close_port "$port" @@ -20512,13 +20341,13 @@ else swap) shift - send_stats "가상 메모리를 빠르게 설정하세요" + send_stats "快速设置虚拟内存" add_swap "$@" ;; time|时区) shift - send_stats "시간대를 빠르게 설정" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -20566,42 +20395,42 @@ else status|状态) shift - send_stats "소프트웨어 상태 확인" + send_stats "软件状态查看" status "$@" ;; start|启动) shift - send_stats "소프트웨어 시작" + send_stats "软件启动" start "$@" ;; stop|停止) shift - send_stats "소프트웨어 일시 중지" + send_stats "软件暂停" stop "$@" ;; restart|重启) shift - send_stats "소프트웨어 재시작" + send_stats "软件重启" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "부팅 시 소프트웨어가 자동으로 시작됩니다." + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "인증서 상태 보기" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "빨리 자격증 신청하세요" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "빨리 자격증 신청하세요" + send_stats "快速申请证书" else k_info fi @@ -20611,15 +20440,15 @@ else shift case $1 in install|安装) - send_stats "도커를 빠르게 설치하세요" + send_stats "快捷安装docker" install_docker ;; ps|容器) - send_stats "빠른 컨테이너 관리" + send_stats "快捷容器管理" docker_ps ;; img|镜像) - send_stats "빠른 이미지 관리" + send_stats "快捷镜像管理" docker_image ;; *) @@ -20646,7 +20475,7 @@ else app) shift - send_stats "신청$@" + send_stats "应用$@" linux_panel "$@" ;; @@ -20665,30 +20494,30 @@ else shift case "$1" in "" ) - # sshkey → 대화형 메뉴 - send_stats "SSHKey 대화형 메뉴" + # sshkey → 交互菜单 + send_stats "SSHKey 交互菜单" sshkey_panel ;; github ) shift - send_stats "GitHub에서 SSH 공개 키 가져오기" + send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; http://*|https://* ) - send_stats "URL에서 SSH 공개 키 가져오기" + send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) - send_stats "공개 키를 직접 가져오기" + send_stats "公钥直接导入" import_sshkey "$1" ;; * ) - echo "오류: 알 수 없는 매개변수 '$1'" - echo "용법:" - echo "k sshkey가 대화형 메뉴로 들어갑니다." - echo "k sshkey \"\" SSH 공개 키 직접 가져오기" - echo "k sshkey URL에서 SSH 공개 키 가져오기" - echo "k sshkey github GitHub에서 SSH 공개 키 가져오기" + echo "错误:未知参数 '$1'" + echo "用法:" + echo " k sshkey 进入交互菜单" + echo " k sshkey \"\" 直接导入 SSH 公钥" + echo " k sshkey 从 URL 导入 SSH 公钥" + echo " k sshkey github 从 GitHub 导入 SSH 公钥" ;; esac From 0b60f59490de6f69faa8d1c2d4a1a6c2e32c6a2b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 17 Mar 2026 10:45:17 +0800 Subject: [PATCH 1043/1285] chore(openclaw): update menu header title --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kr/kejilion.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b80dc8c4f..deee8d975 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "🦞 OPENCLAW 管理 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" diff --git a/kejilion.sh b/kejilion.sh index 596476521..4276eb5cc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "🦞 OPENCLAW 管理 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 596476521..4276eb5cc 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "🦞 OPENCLAW 管理 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" From 911a965e1cda9bce73f677970266e0622dd82e29 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 17 Mar 2026 10:53:35 +0800 Subject: [PATCH 1044/1285] chore(openclaw): menu title include by KEJILION --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index deee8d975..12c36c10a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理 🦞" + echo -e "🦞 OPENCLAW 管理 by KEJILION 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" diff --git a/kejilion.sh b/kejilion.sh index 4276eb5cc..7b27e8342 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理 🦞" + echo -e "🦞 OPENCLAW 管理 by KEJILION 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" From 20dbc81fd23ba55e1fdc3e7203c07f71d0136817 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 17 Mar 2026 10:58:20 +0800 Subject: [PATCH 1045/1285] chore(openclaw): refine menu title wording --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 12c36c10a..99962e4e0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理 by KEJILION 🦞" + echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" diff --git a/kejilion.sh b/kejilion.sh index 7b27e8342..f1f994936 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理 by KEJILION 🦞" + echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" From 3a57634d67604620a9f3bfacaec631e3a084a054 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 10:42:42 +0800 Subject: [PATCH 1046/1285] fix: keep provider when adding only default openclaw model --- cn/kejilion.sh | 175 +++++++++++++++++++++++++++++++------------------ kejilion.sh | 137 +++++++++++++++++++++++++------------- 2 files changed, 200 insertions(+), 112 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 99962e4e0..d3843da71 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10389,15 +10389,6 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10446,6 +10437,16 @@ for name, provider in list(providers.items()): summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + + if fatal_errors: for line in summary: print(line) @@ -10527,52 +10528,20 @@ PY # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 - # 核心函数:获取并添加所有模型 - add-all-models-from-provider() { + # 构造模型配置 JSON + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 正在获取 $provider_name 的所有可用模型..." - - # 不再自动探测/纠正 API 协议;保持用户配置为准 - DETECTED_API="openai-completions" - - # 获取模型列表 - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ 无法获取模型列表" - return 1 - fi - - # 提取所有模型ID - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ 未找到任何模型" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 发现 $model_count 个模型" - - # 智能推断模型参数 + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - - # 只有价格需要分级 local input_cost=0.15 local output_cost=0.60 @@ -10610,11 +10579,22 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # 写入 provider 与模型配置 + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file="${HOME}/.openclaw/openclaw.json" + + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" - # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10648,6 +10628,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # 核心函数:获取并添加所有模型 + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 正在获取 $provider_name 的所有可用模型..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 无法获取模型列表" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 发现 $model_count 个模型" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ 成功添加 $model_count 个模型到 $provider_name" @@ -10659,6 +10672,33 @@ EOF fi } + # 仅添加默认模型并保留 provider + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ 默认模型不能为空" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider:$provider_name" + echo "✅ 仅写入默认模型:$default_model" + return 0 + else + echo "❌ 配置注入失败" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API添加" echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" @@ -10738,22 +10778,26 @@ EOF echo "模型总数 : $model_count" echo "======================" - read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + read -erp "是否同时添加其他所有可用模型?(y/N): " confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅ 完成!所有 $model_count 个模型已加载" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" start_gateway - echo "✅ 完成!所有 $model_count 个模型已加载" - echo "✅ 已自动识别协议为: $DETECTED_API" + echo "$finish_msg" + echo "✅ 当前 API 协议类型: $DETECTED_API" fi break_end @@ -11025,15 +11069,6 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11087,6 +11122,16 @@ if changed: f.write('\n') print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 删除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: diff --git a/kejilion.sh b/kejilion.sh index f1f994936..8cf90dbb5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10528,52 +10528,20 @@ PY # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 - # 核心函数:获取并添加所有模型 - add-all-models-from-provider() { + # 构造模型配置 JSON + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 正在获取 $provider_name 的所有可用模型..." - - # 不再自动探测/纠正 API 协议;保持用户配置为准 - DETECTED_API="openai-completions" - - # 获取模型列表 - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ 无法获取模型列表" - return 1 - fi - - # 提取所有模型ID - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ 未找到任何模型" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 发现 $model_count 个模型" - - # 智能推断模型参数 + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - - # 只有价格需要分级 local input_cost=0.15 local output_cost=0.60 @@ -10611,11 +10579,22 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # 写入 provider 与模型配置 + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file="${HOME}/.openclaw/openclaw.json" + + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" - # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10649,6 +10628,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # 核心函数:获取并添加所有模型 + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 正在获取 $provider_name 的所有可用模型..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 无法获取模型列表" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 发现 $model_count 个模型" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ 成功添加 $model_count 个模型到 $provider_name" @@ -10660,6 +10672,33 @@ EOF fi } + # 仅添加默认模型并保留 provider + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ 默认模型不能为空" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider:$provider_name" + echo "✅ 仅写入默认模型:$default_model" + return 0 + else + echo "❌ 配置注入失败" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API添加" echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" @@ -10739,22 +10778,26 @@ EOF echo "模型总数 : $model_count" echo "======================" - read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + read -erp "是否同时添加其他所有可用模型?(y/N): " confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅ 完成!所有 $model_count 个模型已加载" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" start_gateway - echo "✅ 完成!所有 $model_count 个模型已加载" - echo "✅ 已自动识别协议为: $DETECTED_API" + echo "$finish_msg" + echo "✅ 当前 API 协议类型: $DETECTED_API" fi break_end From e9e67aa4e2f7e8954cf52c253b1a6bc6a61e9100 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 17:58:49 +0800 Subject: [PATCH 1047/1285] feat: probe openclaw model before switching --- cn/kejilion.sh | 199 +++++++++++++++++++++++++++++++++++++++++------- kejilion.sh | 201 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 347 insertions(+), 53 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d3843da71..4785c1887 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11484,10 +11484,142 @@ REPO local orange="#FF8C00" + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed + local oc_config provider_name base_url api_key + + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + base_url=$(jq -r --arg provider "$provider_name" '.providers[$provider].baseURL // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseURL/apiKey" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$target_model" > "$tmp_payload" + + latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' +import json +import os +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout = sys.argv[1:6] +timeout = int(timeout) +url = base_url + '/chat/completions' +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + curl_exit=${latency_ms%%|*} + http_code=${latency_ms#*|} + http_code=${http_code%%|*} + latency_ms=${latency_ms##*|} + + reply_preview=$(python3 - "$tmp_response" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF +) + rm -f "$tmp_payload" "$tmp_response" + + reply_trimmed=$(printf '%s' "$reply_preview" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$curl_exit" = "0" ] && [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="HTTP ${http_code}" + OPENCLAW_PROBE_LATENCY="${latency_ms}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="HTTP ${http_code:-0} / exit ${curl_exit:-1}" + OPENCLAW_PROBE_LATENCY="${latency_ms:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } + clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # 从配置文件读取模型键(不调用 openclaw models list) local oc_config @@ -11509,53 +11641,38 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" - install_gum install gum clear - # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + read -e -p "请输入要测试并设置的模型名称(输入 0 退出): " selected_model - # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break # 跳出 while 循环 + break fi - # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then echo "错误:模型名称不能为空。请重试。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue fi else gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" echo "" - - # 底部提示 - gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" + gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" echo "" - # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ - --prompt "选择模型 > " \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜索模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -11563,10 +11680,40 @@ REPO fi fi - # 去掉编号前缀:"(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # 执行切换 + echo "" + echo "正在检测模型: $selected_model" + if openclaw_model_probe "$selected_model"; then + echo "最小检测结果:可用" + else + echo "最小检测结果:不可用" + fi + echo "返回状态:$OPENCLAW_PROBE_MESSAGE" + echo "响应延迟:$OPENCLAW_PROBE_LATENCY" + echo "返回摘要:$OPENCLAW_PROBE_REPLY" + echo "" + + if command -v gum >/dev/null 2>&1; then + if gum confirm --affirmative "切换" --negative "返回列表" "是否切换到该模型?"; then + confirm_switch="yes" + else + confirm_switch="no" + fi + else + read -e -p "是否切换到该模型?[y/N]: " confirm_switch + case "$confirm_switch" in + [yY]|[yY][eE][sS]) confirm_switch="yes" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "已返回模型选择列表。" + sleep 1 + continue + fi + echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then echo "切换失败:openclaw models set 返回错误。" @@ -11577,7 +11724,7 @@ REPO break_end done - } + } resolve_openclaw_plugin_id() { diff --git a/kejilion.sh b/kejilion.sh index 8cf90dbb5..4785c1887 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -11484,10 +11484,142 @@ REPO local orange="#FF8C00" + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed + local oc_config provider_name base_url api_key + + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + base_url=$(jq -r --arg provider "$provider_name" '.providers[$provider].baseURL // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseURL/apiKey" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$target_model" > "$tmp_payload" + + latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' +import json +import os +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout = sys.argv[1:6] +timeout = int(timeout) +url = base_url + '/chat/completions' +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + curl_exit=${latency_ms%%|*} + http_code=${latency_ms#*|} + http_code=${http_code%%|*} + latency_ms=${latency_ms##*|} + + reply_preview=$(python3 - "$tmp_response" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF +) + rm -f "$tmp_payload" "$tmp_response" + + reply_trimmed=$(printf '%s' "$reply_preview" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$curl_exit" = "0" ] && [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="HTTP ${http_code}" + OPENCLAW_PROBE_LATENCY="${latency_ms}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="HTTP ${http_code:-0} / exit ${curl_exit:-1}" + OPENCLAW_PROBE_LATENCY="${latency_ms:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } + clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # 从配置文件读取模型键(不调用 openclaw models list) local oc_config @@ -11509,53 +11641,38 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" - install_gum install gum clear - # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + read -e -p "请输入要测试并设置的模型名称(输入 0 退出): " selected_model - # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break # 跳出 while 循环 + break fi - # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then echo "错误:模型名称不能为空。请重试。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue fi else gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" echo "" - - # 底部提示 - gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" + gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" echo "" - # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ - --prompt "选择模型 > " \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜索模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -11563,10 +11680,40 @@ REPO fi fi - # 去掉编号前缀:"(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # 执行切换 + echo "" + echo "正在检测模型: $selected_model" + if openclaw_model_probe "$selected_model"; then + echo "最小检测结果:可用" + else + echo "最小检测结果:不可用" + fi + echo "返回状态:$OPENCLAW_PROBE_MESSAGE" + echo "响应延迟:$OPENCLAW_PROBE_LATENCY" + echo "返回摘要:$OPENCLAW_PROBE_REPLY" + echo "" + + if command -v gum >/dev/null 2>&1; then + if gum confirm --affirmative "切换" --negative "返回列表" "是否切换到该模型?"; then + confirm_switch="yes" + else + confirm_switch="no" + fi + else + read -e -p "是否切换到该模型?[y/N]: " confirm_switch + case "$confirm_switch" in + [yY]|[yY][eE][sS]) confirm_switch="yes" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "已返回模型选择列表。" + sleep 1 + continue + fi + echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then echo "切换失败:openclaw models set 返回错误。" @@ -11577,7 +11724,7 @@ REPO break_end done - } + } resolve_openclaw_plugin_id() { From d372fd510e4a494541d4e787d913470477f21594 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:01:58 +0800 Subject: [PATCH 1048/1285] refactor: keep legacy model switch flow without gum --- cn/kejilion.sh | 13 ++++++++++++- kejilion.sh | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4785c1887..e64463c6b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11652,7 +11652,7 @@ PYTHON_EOF echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要测试并设置的模型名称(输入 0 退出): " selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." @@ -11664,6 +11664,17 @@ PYTHON_EOF echo "" continue fi + + echo "正在切换模型为: $selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切换失败:openclaw models set 返回错误。" + break_end + return 1 + fi + start_gateway + + break_end + return 0 else gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" diff --git a/kejilion.sh b/kejilion.sh index 4785c1887..e64463c6b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11652,7 +11652,7 @@ PYTHON_EOF echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要测试并设置的模型名称(输入 0 退出): " selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." @@ -11664,6 +11664,17 @@ PYTHON_EOF echo "" continue fi + + echo "正在切换模型为: $selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切换失败:openclaw models set 返回错误。" + break_end + return 1 + fi + start_gateway + + break_end + return 0 else gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" From 3751eee960857c771a8aebd25553d6e0a6631549 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:05:22 +0800 Subject: [PATCH 1049/1285] fix: read openclaw probe config from models map --- cn/kejilion.sh | 6 +++--- kejilion.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e64463c6b..0b497a629 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11501,11 +11501,11 @@ REPO } provider_name="${target_model%%/*}" - base_url=$(jq -r --arg provider "$provider_name" '.providers[$provider].baseURL // empty' "$oc_config" 2>/dev/null) - api_key=$(jq -r --arg provider "$provider_name" '.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseURL/apiKey" + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 diff --git a/kejilion.sh b/kejilion.sh index e64463c6b..0b497a629 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11501,11 +11501,11 @@ REPO } provider_name="${target_model%%/*}" - base_url=$(jq -r --arg provider "$provider_name" '.providers[$provider].baseURL // empty' "$oc_config" 2>/dev/null) - api_key=$(jq -r --arg provider "$provider_name" '.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseURL/apiKey" + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 From bcc441d599cab99e8fdbbbdc39847b6e23caf427 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:06:47 +0800 Subject: [PATCH 1050/1285] fix: split provider prefix from openclaw model id --- cn/kejilion.sh | 5 +++-- kejilion.sh | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0b497a629..b6dfbf7e7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11488,7 +11488,7 @@ REPO local target_model="$1" local probe_timeout=25 local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed - local oc_config provider_name base_url api_key + local oc_config provider_name base_url api_key request_model oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" @@ -11501,6 +11501,7 @@ REPO } provider_name="${target_model%%/*}" + request_model="${target_model#*/}" base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then @@ -11514,7 +11515,7 @@ REPO base_url="${base_url%/}" tmp_payload=$(mktemp) tmp_response=$(mktemp) - printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$target_model" > "$tmp_payload" + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' import json diff --git a/kejilion.sh b/kejilion.sh index 0b497a629..b6dfbf7e7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11488,7 +11488,7 @@ REPO local target_model="$1" local probe_timeout=25 local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed - local oc_config provider_name base_url api_key + local oc_config provider_name base_url api_key request_model oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" @@ -11501,6 +11501,7 @@ REPO } provider_name="${target_model%%/*}" + request_model="${target_model#*/}" base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then @@ -11514,7 +11515,7 @@ REPO base_url="${base_url%/}" tmp_payload=$(mktemp) tmp_response=$(mktemp) - printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$target_model" > "$tmp_payload" + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' import json From 3b29263cf6abb187187c00d9e442ff7f9ca9dad1 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:08:04 +0800 Subject: [PATCH 1051/1285] fix: use openclaw models.providers config path --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b6dfbf7e7..0974844f5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11502,8 +11502,8 @@ REPO provider_name="${target_model%%/*}" request_model="${target_model#*/}" - base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) - api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" diff --git a/kejilion.sh b/kejilion.sh index b6dfbf7e7..0974844f5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11502,8 +11502,8 @@ REPO provider_name="${target_model%%/*}" request_model="${target_model#*/}" - base_url=$(jq -r --arg provider "$provider_name" '.models[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) - api_key=$(jq -r --arg provider "$provider_name" '.models[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" From 8e9aa4bf54c209b7063259c41b15bd4819e9c6c9 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:31:01 +0800 Subject: [PATCH 1052/1285] fix: keep legacy flow when gum is unavailable --- cn/kejilion.sh | 10 +++++++--- kejilion.sh | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0974844f5..a521b1242 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11642,9 +11642,6 @@ PYTHON_EOF default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" - install_gum - install gum - clear # 若 gum 不存在,降级为原始手动输入流程 @@ -11677,6 +11674,13 @@ PYTHON_EOF break_end return 0 else + install_gum + install gum + if ! command -v gum >/dev/null 2>&1; then + echo "gum 安装失败,返回旧版输入模式。" + sleep 1 + continue + fi gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" diff --git a/kejilion.sh b/kejilion.sh index 0974844f5..a521b1242 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11642,9 +11642,6 @@ PYTHON_EOF default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" - install_gum - install gum - clear # 若 gum 不存在,降级为原始手动输入流程 @@ -11677,6 +11674,13 @@ PYTHON_EOF break_end return 0 else + install_gum + install gum + if ! command -v gum >/dev/null 2>&1; then + echo "gum 安装失败,返回旧版输入模式。" + sleep 1 + continue + fi gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" From fbdf026c97cea3373e31d8b66c4269ab0554298d Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:31:29 +0800 Subject: [PATCH 1053/1285] fix: detect unusable gum and fallback to legacy flow --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a521b1242..a19f9fd3e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11645,7 +11645,7 @@ PYTHON_EOF clear # 若 gum 不存在,降级为原始手动输入流程 - if ! command -v gum >/dev/null 2>&1; then + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' @@ -11676,7 +11676,7 @@ PYTHON_EOF else install_gum install gum - if ! command -v gum >/dev/null 2>&1; then + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "gum 安装失败,返回旧版输入模式。" sleep 1 continue diff --git a/kejilion.sh b/kejilion.sh index a521b1242..a19f9fd3e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11645,7 +11645,7 @@ PYTHON_EOF clear # 若 gum 不存在,降级为原始手动输入流程 - if ! command -v gum >/dev/null 2>&1; then + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' @@ -11676,7 +11676,7 @@ PYTHON_EOF else install_gum install gum - if ! command -v gum >/dev/null 2>&1; then + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "gum 安装失败,返回旧版输入模式。" sleep 1 continue From 611acf65cc44b89523010427708ea4d8cf5f6ceb Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 18:54:28 +0800 Subject: [PATCH 1054/1285] refactor: use keyboard choice for model switch confirm --- cn/kejilion.sh | 18 ++++++++++-------- kejilion.sh | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a19f9fd3e..7bf554bf1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11710,16 +11710,18 @@ PYTHON_EOF echo "返回摘要:$OPENCLAW_PROBE_REPLY" echo "" - if command -v gum >/dev/null 2>&1; then - if gum confirm --affirmative "切换" --negative "返回列表" "是否切换到该模型?"; then - confirm_switch="yes" - else - confirm_switch="no" - fi + if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then + confirm_switch=$(printf '%s +' "yes" "no" | gum choose \ + --cursor "> " \ + --header "使用 ←/→ 或 Tab 切换,回车确认" \ + --selected.foreground "$orange" \ + --cursor.foreground "$orange") + [ -z "$confirm_switch" ] && confirm_switch="no" else - read -e -p "是否切换到该模型?[y/N]: " confirm_switch + read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch case "$confirm_switch" in - [yY]|[yY][eE][sS]) confirm_switch="yes" ;; + [yY][eE][sS]|[yY]) confirm_switch="yes" ;; *) confirm_switch="no" ;; esac fi diff --git a/kejilion.sh b/kejilion.sh index a19f9fd3e..7bf554bf1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11710,16 +11710,18 @@ PYTHON_EOF echo "返回摘要:$OPENCLAW_PROBE_REPLY" echo "" - if command -v gum >/dev/null 2>&1; then - if gum confirm --affirmative "切换" --negative "返回列表" "是否切换到该模型?"; then - confirm_switch="yes" - else - confirm_switch="no" - fi + if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then + confirm_switch=$(printf '%s +' "yes" "no" | gum choose \ + --cursor "> " \ + --header "使用 ←/→ 或 Tab 切换,回车确认" \ + --selected.foreground "$orange" \ + --cursor.foreground "$orange") + [ -z "$confirm_switch" ] && confirm_switch="no" else - read -e -p "是否切换到该模型?[y/N]: " confirm_switch + read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch case "$confirm_switch" in - [yY]|[yY][eE][sS]) confirm_switch="yes" ;; + [yY][eE][sS]|[yY]) confirm_switch="yes" ;; *) confirm_switch="no" ;; esac fi From c2f91e1638bb303ced49ea5245cfa6d024a7d0bb Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 19:00:54 +0800 Subject: [PATCH 1055/1285] feat: use arrow-key confirm for model switching --- cn/kejilion.sh | 44 ++++++++++++++++++++++++++++++++++++++------ kejilion.sh | 44 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7bf554bf1..d9da97935 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11617,6 +11617,43 @@ PYTHON_EOF return 1 } + openclaw_confirm_switch() { + local current_choice="yes" + local first_key rest_key + while true; do + clear + echo "是否切换到该模型?" + echo "使用 ← / → 切换,Enter 确认,Esc 返回列表" + echo "" + if [ "$current_choice" = "yes" ]; then + echo "> [ yes ] no" + else + echo " yes [ no ]" + fi + IFS= read -rsn1 first_key + if [ -z "$first_key" ]; then + printf '%s' "$current_choice" + return 0 + fi + if [ "$first_key" = $'' ]; then + IFS= read -rsn2 -t 0.1 rest_key + case "$rest_key" in + '[D'|'[C') + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + '') + printf 'no' + return 0 + ;; + esac + fi + done + } + clear while true; do @@ -11711,12 +11748,7 @@ PYTHON_EOF echo "" if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - confirm_switch=$(printf '%s -' "yes" "no" | gum choose \ - --cursor "> " \ - --header "使用 ←/→ 或 Tab 切换,回车确认" \ - --selected.foreground "$orange" \ - --cursor.foreground "$orange") + confirm_switch=$(openclaw_confirm_switch) [ -z "$confirm_switch" ] && confirm_switch="no" else read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch diff --git a/kejilion.sh b/kejilion.sh index 7bf554bf1..d9da97935 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11617,6 +11617,43 @@ PYTHON_EOF return 1 } + openclaw_confirm_switch() { + local current_choice="yes" + local first_key rest_key + while true; do + clear + echo "是否切换到该模型?" + echo "使用 ← / → 切换,Enter 确认,Esc 返回列表" + echo "" + if [ "$current_choice" = "yes" ]; then + echo "> [ yes ] no" + else + echo " yes [ no ]" + fi + IFS= read -rsn1 first_key + if [ -z "$first_key" ]; then + printf '%s' "$current_choice" + return 0 + fi + if [ "$first_key" = $'' ]; then + IFS= read -rsn2 -t 0.1 rest_key + case "$rest_key" in + '[D'|'[C') + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + '') + printf 'no' + return 0 + ;; + esac + fi + done + } + clear while true; do @@ -11711,12 +11748,7 @@ PYTHON_EOF echo "" if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - confirm_switch=$(printf '%s -' "yes" "no" | gum choose \ - --cursor "> " \ - --header "使用 ←/→ 或 Tab 切换,回车确认" \ - --selected.foreground "$orange" \ - --cursor.foreground "$orange") + confirm_switch=$(openclaw_confirm_switch) [ -z "$confirm_switch" ] && confirm_switch="no" else read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch From 288ec8c555f17863cd4485a76e5b8e7504bf7dc5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 19:02:04 +0800 Subject: [PATCH 1056/1285] fix: render arrow-key confirm interactively --- cn/kejilion.sh | 8 +++++--- kejilion.sh | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d9da97935..6ea0f34ee 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11632,7 +11632,7 @@ PYTHON_EOF fi IFS= read -rsn1 first_key if [ -z "$first_key" ]; then - printf '%s' "$current_choice" + OPENCLAW_CONFIRM_SWITCH="$current_choice" return 0 fi if [ "$first_key" = $'' ]; then @@ -11646,7 +11646,7 @@ PYTHON_EOF fi ;; '') - printf 'no' + OPENCLAW_CONFIRM_SWITCH="no" return 0 ;; esac @@ -11748,7 +11748,9 @@ PYTHON_EOF echo "" if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - confirm_switch=$(openclaw_confirm_switch) + OPENCLAW_CONFIRM_SWITCH="" + openclaw_confirm_switch + confirm_switch="$OPENCLAW_CONFIRM_SWITCH" [ -z "$confirm_switch" ] && confirm_switch="no" else read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch diff --git a/kejilion.sh b/kejilion.sh index d9da97935..6ea0f34ee 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11632,7 +11632,7 @@ PYTHON_EOF fi IFS= read -rsn1 first_key if [ -z "$first_key" ]; then - printf '%s' "$current_choice" + OPENCLAW_CONFIRM_SWITCH="$current_choice" return 0 fi if [ "$first_key" = $'' ]; then @@ -11646,7 +11646,7 @@ PYTHON_EOF fi ;; '') - printf 'no' + OPENCLAW_CONFIRM_SWITCH="no" return 0 ;; esac @@ -11748,7 +11748,9 @@ PYTHON_EOF echo "" if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - confirm_switch=$(openclaw_confirm_switch) + OPENCLAW_CONFIRM_SWITCH="" + openclaw_confirm_switch + confirm_switch="$OPENCLAW_CONFIRM_SWITCH" [ -z "$confirm_switch" ] && confirm_switch="no" else read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch From 8b1295f4982f890f777c5e4136c9a1b628010df2 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 19:03:35 +0800 Subject: [PATCH 1057/1285] refactor: support fallback keys for model confirm --- cn/kejilion.sh | 41 +++++++++++++++++++++++++---------------- kejilion.sh | 41 +++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6ea0f34ee..eb3aa14ad 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11635,22 +11635,31 @@ PYTHON_EOF OPENCLAW_CONFIRM_SWITCH="$current_choice" return 0 fi - if [ "$first_key" = $'' ]; then - IFS= read -rsn2 -t 0.1 rest_key - case "$rest_key" in - '[D'|'[C') - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - '') - OPENCLAW_CONFIRM_SWITCH="no" - return 0 - ;; - esac - fi + case "$first_key" in + $'') + IFS= read -rsn2 -t 0.1 rest_key + case "$rest_key" in + '[D'|'[C') + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + '') + OPENCLAW_CONFIRM_SWITCH="no" + return 0 + ;; + esac + ;; + [hHlL]) + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + esac done } diff --git a/kejilion.sh b/kejilion.sh index 6ea0f34ee..eb3aa14ad 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11635,22 +11635,31 @@ PYTHON_EOF OPENCLAW_CONFIRM_SWITCH="$current_choice" return 0 fi - if [ "$first_key" = $'' ]; then - IFS= read -rsn2 -t 0.1 rest_key - case "$rest_key" in - '[D'|'[C') - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - '') - OPENCLAW_CONFIRM_SWITCH="no" - return 0 - ;; - esac - fi + case "$first_key" in + $'') + IFS= read -rsn2 -t 0.1 rest_key + case "$rest_key" in + '[D'|'[C') + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + '') + OPENCLAW_CONFIRM_SWITCH="no" + return 0 + ;; + esac + ;; + [hHlL]) + if [ "$current_choice" = "yes" ]; then + current_choice="no" + else + current_choice="yes" + fi + ;; + esac done } From 210356144de2612abc9ed5131e7b8e8c837e5980 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 19:25:00 +0800 Subject: [PATCH 1058/1285] style: colorize model probe result --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index eb3aa14ad..d9b8d662f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11747,9 +11747,9 @@ PYTHON_EOF echo "" echo "正在检测模型: $selected_model" if openclaw_model_probe "$selected_model"; then - echo "最小检测结果:可用" + green "最小检测结果:可用" else - echo "最小检测结果:不可用" + red "最小检测结果:不可用" fi echo "返回状态:$OPENCLAW_PROBE_MESSAGE" echo "响应延迟:$OPENCLAW_PROBE_LATENCY" diff --git a/kejilion.sh b/kejilion.sh index eb3aa14ad..d9b8d662f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11747,9 +11747,9 @@ PYTHON_EOF echo "" echo "正在检测模型: $selected_model" if openclaw_model_probe "$selected_model"; then - echo "最小检测结果:可用" + green "最小检测结果:可用" else - echo "最小检测结果:不可用" + red "最小检测结果:不可用" fi echo "返回状态:$OPENCLAW_PROBE_MESSAGE" echo "响应延迟:$OPENCLAW_PROBE_LATENCY" From ee4c5e053ab87d21014ffb0868f67faf72ce5e1e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 19:55:24 +0800 Subject: [PATCH 1059/1285] fix: restore stable model switch confirmation --- cn/kejilion.sh | 65 +++++++++----------------------------------------- kejilion.sh | 65 +++++++++----------------------------------------- 2 files changed, 22 insertions(+), 108 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d9b8d662f..356d4fe73 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11617,52 +11617,6 @@ PYTHON_EOF return 1 } - openclaw_confirm_switch() { - local current_choice="yes" - local first_key rest_key - while true; do - clear - echo "是否切换到该模型?" - echo "使用 ← / → 切换,Enter 确认,Esc 返回列表" - echo "" - if [ "$current_choice" = "yes" ]; then - echo "> [ yes ] no" - else - echo " yes [ no ]" - fi - IFS= read -rsn1 first_key - if [ -z "$first_key" ]; then - OPENCLAW_CONFIRM_SWITCH="$current_choice" - return 0 - fi - case "$first_key" in - $'') - IFS= read -rsn2 -t 0.1 rest_key - case "$rest_key" in - '[D'|'[C') - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - '') - OPENCLAW_CONFIRM_SWITCH="no" - return 0 - ;; - esac - ;; - [hHlL]) - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - esac - done - } - clear while true; do @@ -11723,7 +11677,7 @@ PYTHON_EOF install_gum install gum if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 安装失败,返回旧版输入模式。" + echo "gum 不可用,返回旧版输入模式。" sleep 1 continue fi @@ -11756,15 +11710,18 @@ PYTHON_EOF echo "返回摘要:$OPENCLAW_PROBE_REPLY" echo "" - if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - OPENCLAW_CONFIRM_SWITCH="" - openclaw_confirm_switch - confirm_switch="$OPENCLAW_CONFIRM_SWITCH" - [ -z "$confirm_switch" ] && confirm_switch="no" + printf "是否切换到该模型?[y/N,Esc 返回列表]: " + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" else - read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch case "$confirm_switch" in - [yY][eE][sS]|[yY]) confirm_switch="yes" ;; + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; *) confirm_switch="no" ;; esac fi diff --git a/kejilion.sh b/kejilion.sh index d9b8d662f..356d4fe73 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11617,52 +11617,6 @@ PYTHON_EOF return 1 } - openclaw_confirm_switch() { - local current_choice="yes" - local first_key rest_key - while true; do - clear - echo "是否切换到该模型?" - echo "使用 ← / → 切换,Enter 确认,Esc 返回列表" - echo "" - if [ "$current_choice" = "yes" ]; then - echo "> [ yes ] no" - else - echo " yes [ no ]" - fi - IFS= read -rsn1 first_key - if [ -z "$first_key" ]; then - OPENCLAW_CONFIRM_SWITCH="$current_choice" - return 0 - fi - case "$first_key" in - $'') - IFS= read -rsn2 -t 0.1 rest_key - case "$rest_key" in - '[D'|'[C') - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - '') - OPENCLAW_CONFIRM_SWITCH="no" - return 0 - ;; - esac - ;; - [hHlL]) - if [ "$current_choice" = "yes" ]; then - current_choice="no" - else - current_choice="yes" - fi - ;; - esac - done - } - clear while true; do @@ -11723,7 +11677,7 @@ PYTHON_EOF install_gum install gum if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 安装失败,返回旧版输入模式。" + echo "gum 不可用,返回旧版输入模式。" sleep 1 continue fi @@ -11756,15 +11710,18 @@ PYTHON_EOF echo "返回摘要:$OPENCLAW_PROBE_REPLY" echo "" - if command -v gum >/dev/null 2>&1 && gum --version >/dev/null 2>&1; then - OPENCLAW_CONFIRM_SWITCH="" - openclaw_confirm_switch - confirm_switch="$OPENCLAW_CONFIRM_SWITCH" - [ -z "$confirm_switch" ] && confirm_switch="no" + printf "是否切换到该模型?[y/N,Esc 返回列表]: " + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" else - read -e -p "是否切换到该模型?[yes/NO]: " confirm_switch case "$confirm_switch" in - [yY][eE][sS]|[yY]) confirm_switch="yes" ;; + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; *) confirm_switch="no" ;; esac fi From f81e40534a8ed487fac91f349520566e8365657f Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 20:17:06 +0800 Subject: [PATCH 1060/1285] fix: inline probe result colors without extra helpers --- cn/kejilion.sh | 24 +++++++++++++++++++----- kejilion.sh | 24 +++++++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 356d4fe73..50789725f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11484,6 +11484,20 @@ REPO local orange="#FF8C00" + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "可用" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + openclaw_model_probe() { local target_model="$1" local probe_timeout=25 @@ -11701,13 +11715,13 @@ PYTHON_EOF echo "" echo "正在检测模型: $selected_model" if openclaw_model_probe "$selected_model"; then - green "最小检测结果:可用" + openclaw_probe_status_line "可用" else - red "最小检测结果:不可用" + openclaw_probe_status_line "不可用" fi - echo "返回状态:$OPENCLAW_PROBE_MESSAGE" - echo "响应延迟:$OPENCLAW_PROBE_LATENCY" - echo "返回摘要:$OPENCLAW_PROBE_REPLY" + echo "状态:$OPENCLAW_PROBE_MESSAGE" + echo "延迟:$OPENCLAW_PROBE_LATENCY" + echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" printf "是否切换到该模型?[y/N,Esc 返回列表]: " diff --git a/kejilion.sh b/kejilion.sh index 356d4fe73..50789725f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11484,6 +11484,20 @@ REPO local orange="#FF8C00" + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "可用" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + openclaw_model_probe() { local target_model="$1" local probe_timeout=25 @@ -11701,13 +11715,13 @@ PYTHON_EOF echo "" echo "正在检测模型: $selected_model" if openclaw_model_probe "$selected_model"; then - green "最小检测结果:可用" + openclaw_probe_status_line "可用" else - red "最小检测结果:不可用" + openclaw_probe_status_line "不可用" fi - echo "返回状态:$OPENCLAW_PROBE_MESSAGE" - echo "响应延迟:$OPENCLAW_PROBE_LATENCY" - echo "返回摘要:$OPENCLAW_PROBE_REPLY" + echo "状态:$OPENCLAW_PROBE_MESSAGE" + echo "延迟:$OPENCLAW_PROBE_LATENCY" + echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" printf "是否切换到该模型?[y/N,Esc 返回列表]: " From 6fd7ad67c71f9d4c6b8c8a51259ba00f9112f983 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 22:18:51 +0800 Subject: [PATCH 1061/1285] fix(openclaw): add dual probe for model switch --- cn/kejilion.sh | 161 ++++++++++++------ kejilion.sh | 161 ++++++++++++------ .../tests_change_model_dual_probe_smoke.sh | 130 ++++++++++++++ 3 files changed, 348 insertions(+), 104 deletions(-) create mode 100755 tests/openclaw/tests_change_model_dual_probe_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 50789725f..e20ad680e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11501,8 +11501,11 @@ REPO openclaw_model_probe() { local target_model="$1" local probe_timeout=25 - local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" @@ -11527,21 +11530,80 @@ REPO fi base_url="${base_url%/}" - tmp_payload=$(mktemp) - tmp_response=$(mktemp) - printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + first_endpoint="/chat/completions" + second_endpoint="/responses" - latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' import json -import os +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' import sys import time import urllib.error import urllib.request -base_url, api_key, payload_path, response_path, timeout = sys.argv[1:6] +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] timeout = int(timeout) -url = base_url + '/chat/completions' +url = base_url + endpoint payload = open(payload_path, 'rb').read() req = urllib.request.Request( url, @@ -11573,60 +11635,55 @@ with open(response_path, 'wb') as f: print(f"{exit_code}|{status}|{elapsed}") PYTHON_EOF ) - curl_exit=${latency_ms%%|*} - http_code=${latency_ms#*|} - http_code=${http_code%%|*} - latency_ms=${latency_ms##*|} + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } - reply_preview=$(python3 - "$tmp_response" <<'PYTHON_EOF' -import json -import sys -from pathlib import Path -path = Path(sys.argv[1]) -raw = path.read_text(encoding='utf-8', errors='replace').strip() -reply = '' -if raw: - try: - data = json.loads(raw) - if isinstance(data, dict): - choices = data.get('choices') or [] - if choices and isinstance(choices[0], dict): - message = choices[0].get('message') or {} - if isinstance(message, dict): - reply = message.get('content') or '' - if not reply: - for key in ('error', 'message', 'detail'): - value = data.get(key) - if isinstance(value, str) and value.strip(): - reply = value.strip() - break - if isinstance(value, dict): - nested = value.get('message') - if isinstance(nested, str) and nested.strip(): - reply = nested.strip() - break - except Exception: - reply = raw -reply = ' '.join(str(reply).split()) -print(reply) -PYTHON_EOF -) - rm -f "$tmp_payload" "$tmp_response" + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" - reply_trimmed=$(printf '%s' "$reply_preview" | cut -c1-120) + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" - if [ "$curl_exit" = "0" ] && [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" - OPENCLAW_PROBE_MESSAGE="HTTP ${http_code}" - OPENCLAW_PROBE_LATENCY="${latency_ms}ms" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 0 fi + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0},切换 ${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + OPENCLAW_PROBE_STATUS="FAIL" - OPENCLAW_PROBE_MESSAGE="HTTP ${http_code:-0} / exit ${curl_exit:-1}" - OPENCLAW_PROBE_LATENCY="${latency_ms:-?}ms" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 1 } diff --git a/kejilion.sh b/kejilion.sh index 50789725f..e20ad680e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11501,8 +11501,11 @@ REPO openclaw_model_probe() { local target_model="$1" local probe_timeout=25 - local tmp_payload tmp_response http_code curl_exit latency_ms reply_preview reply_trimmed + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply oc_config="${HOME}/.openclaw/openclaw.json" [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" @@ -11527,21 +11530,80 @@ REPO fi base_url="${base_url%/}" - tmp_payload=$(mktemp) - tmp_response=$(mktemp) - printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + first_endpoint="/chat/completions" + second_endpoint="/responses" - latency_ms=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" <<'PYTHON_EOF' + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' import json -import os +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' import sys import time import urllib.error import urllib.request -base_url, api_key, payload_path, response_path, timeout = sys.argv[1:6] +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] timeout = int(timeout) -url = base_url + '/chat/completions' +url = base_url + endpoint payload = open(payload_path, 'rb').read() req = urllib.request.Request( url, @@ -11573,60 +11635,55 @@ with open(response_path, 'wb') as f: print(f"{exit_code}|{status}|{elapsed}") PYTHON_EOF ) - curl_exit=${latency_ms%%|*} - http_code=${latency_ms#*|} - http_code=${http_code%%|*} - latency_ms=${latency_ms##*|} + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } - reply_preview=$(python3 - "$tmp_response" <<'PYTHON_EOF' -import json -import sys -from pathlib import Path -path = Path(sys.argv[1]) -raw = path.read_text(encoding='utf-8', errors='replace').strip() -reply = '' -if raw: - try: - data = json.loads(raw) - if isinstance(data, dict): - choices = data.get('choices') or [] - if choices and isinstance(choices[0], dict): - message = choices[0].get('message') or {} - if isinstance(message, dict): - reply = message.get('content') or '' - if not reply: - for key in ('error', 'message', 'detail'): - value = data.get(key) - if isinstance(value, str) and value.strip(): - reply = value.strip() - break - if isinstance(value, dict): - nested = value.get('message') - if isinstance(nested, str) and nested.strip(): - reply = nested.strip() - break - except Exception: - reply = raw -reply = ' '.join(str(reply).split()) -print(reply) -PYTHON_EOF -) - rm -f "$tmp_payload" "$tmp_response" + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" - reply_trimmed=$(printf '%s' "$reply_preview" | cut -c1-120) + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" - if [ "$curl_exit" = "0" ] && [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" - OPENCLAW_PROBE_MESSAGE="HTTP ${http_code}" - OPENCLAW_PROBE_LATENCY="${latency_ms}ms" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 0 fi + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0},切换 ${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + OPENCLAW_PROBE_STATUS="FAIL" - OPENCLAW_PROBE_MESSAGE="HTTP ${http_code:-0} / exit ${curl_exit:-1}" - OPENCLAW_PROBE_LATENCY="${latency_ms:-?}ms" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 1 } diff --git a/tests/openclaw/tests_change_model_dual_probe_smoke.sh b/tests/openclaw/tests_change_model_dual_probe_smoke.sh new file mode 100755 index 000000000..8af58cb10 --- /dev/null +++ b/tests/openclaw/tests_change_model_dual_probe_smoke.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-change-model-dual-probe-$$" +mkdir -p "$WORKDIR/home/.openclaw" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +python3 - "$SCRIPT" "$WORKDIR" <<'PY' +import json +import re +import sys +from pathlib import Path + +script_path = Path(sys.argv[1]) +workdir = Path(sys.argv[2]) +text = script_path.read_text(encoding='utf-8') +match = re.search(r'\n\t\topenclaw_model_probe\(\) \{.*?\n\t\t\}', text, re.S) +if not match: + raise SystemExit('openclaw_model_probe not found') +func = match.group(0).strip('\n') + +config = { + "models": { + "providers": { + "demo": { + "baseUrl": "https://api.example.com/v1", + "apiKey": "sk-test" + } + } + } +} +(workdir / 'home' / '.openclaw').mkdir(parents=True, exist_ok=True) +(workdir / 'home' / '.openclaw' / 'openclaw.json').write_text(json.dumps(config, ensure_ascii=False, indent=2) + '\n', encoding='utf-8') + +harness = f'''#!/usr/bin/env bash +set -euo pipefail +HOME="{workdir / 'home'}" +OPENCLAW_PROBE_STATUS="" +OPENCLAW_PROBE_MESSAGE="" +OPENCLAW_PROBE_LATENCY="" +OPENCLAW_PROBE_REPLY="" +{func} +''' +(workdir / 'harness.sh').write_text(harness, encoding='utf-8') +PY + +run_case() { + local case_name="$1" + CASE_NAME="$case_name" WORKDIR="$WORKDIR" bash <<'EOF_CASE' +set -euo pipefail +source "$WORKDIR/harness.sh" + +python3() { + if [ "$1" != "-" ]; then + command python3 "$@" + return + fi + + local script + script=$(cat) + shift + + CASE_NAME="$CASE_NAME" command python3 - "$script" "$@" <<'PYWRAP' +import io +import json +import os +import sys +import urllib.error +import urllib.request +from pathlib import Path + +script = sys.argv[1] +args = sys.argv[2:] +case = os.environ['CASE_NAME'] + +class Resp(io.BytesIO): + def __init__(self, data, code=200): + super().__init__(data) + self.status = code + def __enter__(self): + return self + def __exit__(self, exc_type, exc, tb): + return False + +real_urlopen = urllib.request.urlopen + +def fake_urlopen(req, timeout=0): + url = getattr(req, 'full_url', '') + if case == 'fallback-success': + if url.endswith('/chat/completions'): + raise urllib.error.HTTPError(url, 404, 'Not Found', {}, io.BytesIO(b'{"error":"chat disabled"}')) + if url.endswith('/responses'): + body = json.dumps({"output": [{"content": [{"text": "pong from responses"}]}]}).encode('utf-8') + return Resp(body, 200) + elif case == 'all-fail': + if url.endswith('/chat/completions'): + raise urllib.error.HTTPError(url, 404, 'Not Found', {}, io.BytesIO(b'{"error":"chat disabled"}')) + if url.endswith('/responses'): + raise urllib.error.HTTPError(url, 404, 'Not Found', {}, io.BytesIO(b'{"error":"responses disabled"}')) + return real_urlopen(req, timeout=timeout) + +urllib.request.urlopen = fake_urlopen +sys.argv = ['python3'] + args +ns = {'__name__': '__main__'} +exec(compile(script, '', 'exec'), ns, ns) +PYWRAP +} + +set +e +openclaw_model_probe "demo/test-model" +probe_rc=$? +set -e +printf 'RC=%s\nSTATUS=%s\nMESSAGE=%s\nLATENCY=%s\nREPLY=%s\n' "$probe_rc" "$OPENCLAW_PROBE_STATUS" "$OPENCLAW_PROBE_MESSAGE" "$OPENCLAW_PROBE_LATENCY" "$OPENCLAW_PROBE_REPLY" +EOF_CASE +} + +out1=$(run_case fallback-success) +printf '%s\n' "$out1" | grep -q 'STATUS=OK' +printf '%s\n' "$out1" | grep -q '/chat/completions -> HTTP 404,切换 /responses -> HTTP 200' +printf '%s\n' "$out1" | grep -q 'REPLY=pong from responses' + +out2=$(run_case all-fail || true) +printf '%s\n' "$out2" | grep -q 'RC=1' +printf '%s\n' "$out2" | grep -q 'STATUS=FAIL' +printf '%s\n' "$out2" | grep -q '/chat/completions -> HTTP 404 / exit 22;/responses -> HTTP 404 / exit 22' + +printf '%s\n' 'SMOKE_OK' From 3f14580ac30401d0201d5f5f6003eca8881c24ab Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 18 Mar 2026 23:14:43 +0800 Subject: [PATCH 1062/1285] fix(openclaw): prefer responses in model probe --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- tests/openclaw/tests_change_model_dual_probe_smoke.sh | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e20ad680e..52ed46e0d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11530,8 +11530,8 @@ REPO fi base_url="${base_url%/}" - first_endpoint="/chat/completions" - second_endpoint="/responses" + first_endpoint="/responses" + second_endpoint="/chat/completions" openclaw_extract_probe_reply() { python3 - "$1" <<'PYTHON_EOF' diff --git a/kejilion.sh b/kejilion.sh index e20ad680e..52ed46e0d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11530,8 +11530,8 @@ REPO fi base_url="${base_url%/}" - first_endpoint="/chat/completions" - second_endpoint="/responses" + first_endpoint="/responses" + second_endpoint="/chat/completions" openclaw_extract_probe_reply() { python3 - "$1" <<'PYTHON_EOF' diff --git a/tests/openclaw/tests_change_model_dual_probe_smoke.sh b/tests/openclaw/tests_change_model_dual_probe_smoke.sh index 8af58cb10..877da234d 100755 --- a/tests/openclaw/tests_change_model_dual_probe_smoke.sh +++ b/tests/openclaw/tests_change_model_dual_probe_smoke.sh @@ -119,12 +119,12 @@ EOF_CASE out1=$(run_case fallback-success) printf '%s\n' "$out1" | grep -q 'STATUS=OK' -printf '%s\n' "$out1" | grep -q '/chat/completions -> HTTP 404,切换 /responses -> HTTP 200' +printf '%s\n' "$out1" | grep -q 'MESSAGE=/responses -> HTTP 200' printf '%s\n' "$out1" | grep -q 'REPLY=pong from responses' out2=$(run_case all-fail || true) printf '%s\n' "$out2" | grep -q 'RC=1' printf '%s\n' "$out2" | grep -q 'STATUS=FAIL' -printf '%s\n' "$out2" | grep -q '/chat/completions -> HTTP 404 / exit 22;/responses -> HTTP 404 / exit 22' +printf '%s\n' "$out2" | grep -q '/responses -> HTTP 404 / exit 22;/chat/completions -> HTTP 404 / exit 22' printf '%s\n' 'SMOKE_OK' From 7406c37d3e64ebd5f19156db1e5e2668674ab531 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 19 Mar 2026 09:35:20 +0800 Subject: [PATCH 1063/1285] chore(openclaw): reorder sync summary counts --- cn/kejilion.sh | 4 ++-- kejilion.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 52ed46e0d..95f7639a8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10435,7 +10435,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + summary.append(f'✅ {name}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: summary.append(f'➕ 新增模型({len(added_ids)}):') @@ -11121,7 +11121,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') +print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: print(f'➕ 新增模型({len(added_ids)}):') diff --git a/kejilion.sh b/kejilion.sh index 52ed46e0d..95f7639a8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10435,7 +10435,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + summary.append(f'✅ {name}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: summary.append(f'➕ 新增模型({len(added_ids)}):') @@ -11121,7 +11121,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') +print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: print(f'➕ 新增模型({len(added_ids)}):') From e95549f3435a621b486451501816d35c065c3dca Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Thu, 19 Mar 2026 09:42:36 +0800 Subject: [PATCH 1064/1285] release: bump version to 4.4.8 --- kejilion.sh | 2 +- kejilion_sh_log.txt | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 95f7639a8..74e054ff3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.8" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index b3e4dda4b..58e4f0e86 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1491,4 +1491,11 @@ SSH防御优化Debian/Ubuntu系统,自动补充logpath配置避免minimal镜 ------------------------ 2026-03-13 v4.4.7 OpenClaw模型管理新增gum交互式换模型(可搜索/橙色主题/显示可用模型数与当前默认)。 +------------------------ +2026-03-19 v4.4.8 +OpenClaw模型管理新增换模型前最小可用性检测,显示状态、延迟与返回摘要。 +OpenClaw模型探测逻辑优化,优先测试 /v1/responses,不通时再回退 /v1/chat/completions。 +OpenClaw模型管理优化gum异常时的兼容性,自动回退旧版输入流程。 +OpenClaw API同步一致性输出增强,汇总显示顺序调整为新增、删除、当前。 +OpenClaw模型管理交互细节优化,提升确认流程稳定性与可用性。 From 91c31b2da548808adddf8955172b6752792a78b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:55:07 +0800 Subject: [PATCH 1065/1285] Update sh_v version from 4.4.7 to 4.4.8 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 95f7639a8..74e054ff3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.8" gl_hui='\e[37m' From 04b3a60c8e11e8c7d3495fb427a4be5ea2fa8755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:21:28 +0800 Subject: [PATCH 1066/1285] Update kejilion.sh --- cn/kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 74e054ff3..018aaa547 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10488,6 +10488,7 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway From 48c662d7260f8e9ad1fc56247f84cbfa307b4e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:22:36 +0800 Subject: [PATCH 1067/1285] Enable elevated tools in OpenClaw configuration --- kejilion.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion.sh b/kejilion.sh index 74e054ff3..018aaa547 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10488,6 +10488,7 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway From c0ab58f2e0d6f54c6763243a3012ce8b6c28754a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 10:50:10 +0800 Subject: [PATCH 1068/1285] feat: add openclaw permission management menu --- kr/kejilion.sh | 225 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 6 deletions(-) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 4276eb5cc..da3209ed7 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -10054,10 +10054,11 @@ moltbot_menu() { echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" echo "15. 记忆/Memory" + echo "16. 权限管理" echo "--------------------" - echo "16. 备份与还原" - echo "17. 更新" - echo "18. 卸载" + echo "17. 备份与还原" + echo "18. 更新" + echo "19. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -13632,6 +13633,217 @@ EOF done } + openclaw_permission_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_permission_restart_gateway() { + if command -v openclaw >/dev/null 2>&1; then + echo "正在重启 OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + fi + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + [ -f "$config_file" ] || return 1 + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + } + + openclaw_permission_detect_mode() { + local profile security ask elevated bash_enabled apply_patch workspace_only + profile=$(openclaw_permission_get_value "tools.profile") + security=$(openclaw_permission_get_value "tools.exec.security") + ask=$(openclaw_permission_get_value "tools.exec.ask") + elevated=$(openclaw_permission_get_value "tools.elevated.enabled") + bash_enabled=$(openclaw_permission_get_value "commands.bash") + apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") + workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") + + if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then + echo "标准安全模式" + elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then + echo "开发增强模式" + elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then + echo "完全开放模式" + else + echo "自定义模式" + fi + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "配置文件: $config_file" + echo "当前模式: $mode" + echo "---------------------------------------" + printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" + printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" + printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" + printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" + printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" + printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" + printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" + printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" + printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" + printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw权限-标准安全模式" + openclaw config set tools.profile coding + openclaw config unset tools.byProvider >/dev/null 2>&1 || true + openclaw config unset tools.allow >/dev/null 2>&1 || true + openclaw config set tools.deny '[]' --json + openclaw config set tools.exec.security allowlist + openclaw config set tools.exec.ask on-miss + openclaw config set tools.elevated.enabled false + openclaw config set commands.bash false + openclaw config set tools.exec.applyPatch.enabled false + openclaw config set tools.exec.applyPatch.workspaceOnly true + openclaw_permission_restart_gateway + echo "✅ 已切换为标准安全模式" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw权限-开发增强模式" + openclaw config set tools.profile coding + openclaw config unset tools.byProvider >/dev/null 2>&1 || true + openclaw config unset tools.allow >/dev/null 2>&1 || true + openclaw config set tools.deny '[]' --json + openclaw config set tools.exec.security allowlist + openclaw config set tools.exec.ask on-miss + openclaw config set tools.elevated.enabled true + openclaw config set commands.bash true + openclaw config set tools.exec.applyPatch.enabled true + openclaw config set tools.exec.applyPatch.workspaceOnly true + openclaw_permission_restart_gateway + echo "✅ 已切换为开发增强模式" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw权限-完全开放模式" + openclaw config set tools.profile full + openclaw config unset tools.byProvider >/dev/null 2>&1 || true + openclaw config unset tools.allow >/dev/null 2>&1 || true + openclaw config set tools.deny '[]' --json + openclaw config set tools.exec.security full + openclaw config set tools.exec.ask off + openclaw config set tools.elevated.enabled true + openclaw config set commands.bash true + openclaw config set tools.exec.applyPatch.enabled true + openclaw config set tools.exec.applyPatch.workspaceOnly true + openclaw_permission_restart_gateway + echo "✅ 已切换为完全开放模式" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw权限-恢复官方默认" + openclaw config unset tools.profile >/dev/null 2>&1 || true + openclaw config unset tools.byProvider >/dev/null 2>&1 || true + openclaw config unset tools.allow >/dev/null 2>&1 || true + openclaw config unset tools.deny >/dev/null 2>&1 || true + openclaw config unset tools.exec.security >/dev/null 2>&1 || true + openclaw config unset tools.exec.ask >/dev/null 2>&1 || true + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || true + openclaw config unset commands.bash >/dev/null 2>&1 || true + openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || true + openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || true + openclaw_permission_restart_gateway + echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw权限-安全审计" + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw权限管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 权限管理" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1. 查看当前权限状态" + echo "2. 切换为标准安全模式(推荐)" + echo "3. 切换为开发增强模式" + echo "4. 切换为完全开放模式(高风险)" + echo "5. 恢复官方默认策略" + echo "6. 运行安全审计" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " perm_choice + case "$perm_choice" in + 1) + openclaw_permission_render_status + break_end + ;; + 2) + echo "将应用:标准安全模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + break_end + ;; + 3) + echo "将应用:开发增强模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + break_end + ;; + 4) + echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" + read -e -p "输入 FULL 确认继续: " confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + break_end + ;; + 5) + echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + break_end + ;; + 6) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" @@ -13877,9 +14089,10 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_backup_restore_menu ;; + 18) update_moltbot ;; + 19) uninstall_moltbot ;; *) break ;; esac done From 78e7a81a739868d0dcb1b778d72417fca413020a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 11:32:08 +0800 Subject: [PATCH 1069/1285] Fix OpenClaw permission management flow --- kr/kejilion.sh | 235 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 183 insertions(+), 52 deletions(-) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index da3209ed7..d6d158da0 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -13637,22 +13637,99 @@ EOF echo "${HOME}/.openclaw/openclaw.json" } + openclaw_permission_backup_file() { + local backup_root + backup_root=$(openclaw_backup_root) + echo "${backup_root}/openclaw-permission-last.json" + } + + openclaw_permission_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_permission_backup_current() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$config_file" ]; then + echo "⚠️ 未找到 OpenClaw 配置文件,跳过权限备份。" + return 1 + fi + mkdir -p "$(dirname "$backup_file")" + cp -f "$config_file" "$backup_file" >/dev/null 2>&1 || { + echo "⚠️ 权限备份失败:$backup_file" + return 1 + } + echo "✅ 已备份当前权限配置: $backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ 未找到可恢复的权限备份文件。" + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ 权限恢复失败:$backup_file" + return 1 + } + echo "✅ 已恢复切换前权限配置" + openclaw_permission_restart_gateway || true + return 0 + } + openclaw_permission_restart_gateway() { - if command -v openclaw >/dev/null 2>&1; then - echo "正在重启 OpenClaw Gateway..." - openclaw gateway restart >/dev/null 2>&1 || { - openclaw gateway stop >/dev/null 2>&1 - openclaw gateway start >/dev/null 2>&1 - } + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + return 1 fi + echo "正在重启 OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } } openclaw_permission_get_value() { local path="$1" local config_file config_file=$(openclaw_permission_config_file) - [ -f "$config_file" ] || return 1 - python3 - "$config_file" "$path" <<'PY' + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + if [ -n "$value" ]; then + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 1; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' import json, sys path = sys.argv[2] with open(sys.argv[1], 'r', encoding='utf-8') as f: @@ -13671,6 +13748,11 @@ elif cur is None: else: print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) PY + return 0 + fi + + echo "(unset)" + return 1 } openclaw_permission_detect_mode() { @@ -13699,6 +13781,10 @@ PY config_file=$(openclaw_permission_config_file) mode=$(openclaw_permission_detect_mode) echo "配置文件: $config_file" + [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" + if ! openclaw_has_command openclaw; then + echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" + fi echo "当前模式: $mode" echo "---------------------------------------" printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" @@ -13715,70 +13801,115 @@ PY openclaw_permission_apply_standard() { send_stats "OpenClaw权限-标准安全模式" - openclaw config set tools.profile coding - openclaw config unset tools.byProvider >/dev/null 2>&1 || true - openclaw config unset tools.allow >/dev/null 2>&1 || true - openclaw config set tools.deny '[]' --json - openclaw config set tools.exec.security allowlist - openclaw config set tools.exec.ask on-miss - openclaw config set tools.elevated.enabled false - openclaw config set commands.bash false - openclaw config set tools.exec.applyPatch.enabled false - openclaw config set tools.exec.applyPatch.workspaceOnly true - openclaw_permission_restart_gateway + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi echo "✅ 已切换为标准安全模式" } openclaw_permission_apply_developer() { send_stats "OpenClaw权限-开发增强模式" - openclaw config set tools.profile coding - openclaw config unset tools.byProvider >/dev/null 2>&1 || true - openclaw config unset tools.allow >/dev/null 2>&1 || true - openclaw config set tools.deny '[]' --json - openclaw config set tools.exec.security allowlist - openclaw config set tools.exec.ask on-miss - openclaw config set tools.elevated.enabled true - openclaw config set commands.bash true - openclaw config set tools.exec.applyPatch.enabled true - openclaw config set tools.exec.applyPatch.workspaceOnly true - openclaw_permission_restart_gateway + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi echo "✅ 已切换为开发增强模式" } openclaw_permission_apply_full() { send_stats "OpenClaw权限-完全开放模式" - openclaw config set tools.profile full - openclaw config unset tools.byProvider >/dev/null 2>&1 || true - openclaw config unset tools.allow >/dev/null 2>&1 || true - openclaw config set tools.deny '[]' --json - openclaw config set tools.exec.security full - openclaw config set tools.exec.ask off - openclaw config set tools.elevated.enabled true - openclaw config set commands.bash true - openclaw config set tools.exec.applyPatch.enabled true - openclaw config set tools.exec.applyPatch.workspaceOnly true - openclaw_permission_restart_gateway + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi echo "✅ 已切换为完全开放模式" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw权限-恢复官方默认" - openclaw config unset tools.profile >/dev/null 2>&1 || true - openclaw config unset tools.byProvider >/dev/null 2>&1 || true - openclaw config unset tools.allow >/dev/null 2>&1 || true - openclaw config unset tools.deny >/dev/null 2>&1 || true - openclaw config unset tools.exec.security >/dev/null 2>&1 || true - openclaw config unset tools.exec.ask >/dev/null 2>&1 || true - openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || true - openclaw config unset commands.bash >/dev/null 2>&1 || true - openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || true - openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || true - openclaw_permission_restart_gateway + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" } openclaw_permission_run_audit() { send_stats "OpenClaw权限-安全审计" + openclaw_permission_require_openclaw || return 1 openclaw security audit } From a96daab1f7834f575716fb2645e0c9f799620e11 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 11:38:48 +0800 Subject: [PATCH 1070/1285] sync openclaw permission management to main and cn --- cn/kejilion.sh | 358 ++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 358 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 702 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 018aaa547..7fe579d2d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10054,10 +10054,11 @@ moltbot_menu() { echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" echo "15. 记忆/Memory" + echo "16. 权限管理" echo "--------------------" - echo "16. 备份与还原" - echo "17. 更新" - echo "18. 卸载" + echo "17. 备份与还原" + echo "18. 更新" + echo "19. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -13912,7 +13913,349 @@ EOF done } - openclaw_backup_restore_menu() { + openclaw_permission_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_permission_backup_file() { + local backup_root + backup_root=$(openclaw_backup_root) + echo "${backup_root}/openclaw-permission-last.json" + } + + openclaw_permission_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_permission_backup_current() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$config_file" ]; then + echo "⚠️ 未找到 OpenClaw 配置文件,跳过权限备份。" + return 1 + fi + mkdir -p "$(dirname "$backup_file")" + cp -f "$config_file" "$backup_file" >/dev/null 2>&1 || { + echo "⚠️ 权限备份失败:$backup_file" + return 1 + } + echo "✅ 已备份当前权限配置: $backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ 未找到可恢复的权限备份文件。" + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ 权限恢复失败:$backup_file" + return 1 + } + echo "✅ 已恢复切换前权限配置" + openclaw_permission_restart_gateway || true + return 0 + } + + openclaw_permission_restart_gateway() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + return 1 + fi + echo "正在重启 OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + if [ -n "$value" ]; then + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 1; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + return 0 + fi + + echo "(unset)" + return 1 + } + + openclaw_permission_detect_mode() { + local profile security ask elevated bash_enabled apply_patch workspace_only + profile=$(openclaw_permission_get_value "tools.profile") + security=$(openclaw_permission_get_value "tools.exec.security") + ask=$(openclaw_permission_get_value "tools.exec.ask") + elevated=$(openclaw_permission_get_value "tools.elevated.enabled") + bash_enabled=$(openclaw_permission_get_value "commands.bash") + apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") + workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") + + if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then + echo "标准安全模式" + elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then + echo "开发增强模式" + elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then + echo "完全开放模式" + else + echo "自定义模式" + fi + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "配置文件: $config_file" + [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" + if ! openclaw_has_command openclaw; then + echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" + fi + echo "当前模式: $mode" + echo "---------------------------------------" + printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" + printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" + printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" + printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" + printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" + printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" + printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" + printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" + printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" + printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw权限-标准安全模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为标准安全模式" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw权限-开发增强模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为开发增强模式" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw权限-完全开放模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为完全开放模式" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw权限-恢复官方默认" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw权限-安全审计" + openclaw_permission_require_openclaw || return 1 + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw权限管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 权限管理" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1. 查看当前权限状态" + echo "2. 切换为标准安全模式(推荐)" + echo "3. 切换为开发增强模式" + echo "4. 切换为完全开放模式(高风险)" + echo "5. 恢复官方默认策略" + echo "6. 运行安全审计" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " perm_choice + case "$perm_choice" in + 1) + openclaw_permission_render_status + break_end + ;; + 2) + echo "将应用:标准安全模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + break_end + ;; + 3) + echo "将应用:开发增强模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + break_end + ;; + 4) + echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" + read -e -p "输入 FULL 确认继续: " confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + break_end + ;; + 5) + echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + break_end + ;; + 6) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + +openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" while true; do @@ -14157,9 +14500,10 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_backup_restore_menu ;; + 18) update_moltbot ;; + 19) uninstall_moltbot ;; *) break ;; esac done diff --git a/kejilion.sh b/kejilion.sh index 018aaa547..7fe579d2d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10054,10 +10054,11 @@ moltbot_menu() { echo "13. WebUI访问与设置" echo "14. TUI命令行对话窗口" echo "15. 记忆/Memory" + echo "16. 权限管理" echo "--------------------" - echo "16. 备份与还原" - echo "17. 更新" - echo "18. 卸载" + echo "17. 备份与还原" + echo "18. 更新" + echo "19. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -13912,7 +13913,349 @@ EOF done } - openclaw_backup_restore_menu() { + openclaw_permission_config_file() { + echo "${HOME}/.openclaw/openclaw.json" + } + + openclaw_permission_backup_file() { + local backup_root + backup_root=$(openclaw_backup_root) + echo "${backup_root}/openclaw-permission-last.json" + } + + openclaw_permission_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_permission_backup_current() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$config_file" ]; then + echo "⚠️ 未找到 OpenClaw 配置文件,跳过权限备份。" + return 1 + fi + mkdir -p "$(dirname "$backup_file")" + cp -f "$config_file" "$backup_file" >/dev/null 2>&1 || { + echo "⚠️ 权限备份失败:$backup_file" + return 1 + } + echo "✅ 已备份当前权限配置: $backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ 未找到可恢复的权限备份文件。" + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ 权限恢复失败:$backup_file" + return 1 + } + echo "✅ 已恢复切换前权限配置" + openclaw_permission_restart_gateway || true + return 0 + } + + openclaw_permission_restart_gateway() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + return 1 + fi + echo "正在重启 OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + if [ -n "$value" ]; then + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 1; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + return 0 + fi + + echo "(unset)" + return 1 + } + + openclaw_permission_detect_mode() { + local profile security ask elevated bash_enabled apply_patch workspace_only + profile=$(openclaw_permission_get_value "tools.profile") + security=$(openclaw_permission_get_value "tools.exec.security") + ask=$(openclaw_permission_get_value "tools.exec.ask") + elevated=$(openclaw_permission_get_value "tools.elevated.enabled") + bash_enabled=$(openclaw_permission_get_value "commands.bash") + apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") + workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") + + if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then + echo "标准安全模式" + elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then + echo "开发增强模式" + elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then + echo "完全开放模式" + else + echo "自定义模式" + fi + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "配置文件: $config_file" + [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" + if ! openclaw_has_command openclaw; then + echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" + fi + echo "当前模式: $mode" + echo "---------------------------------------" + printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" + printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" + printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" + printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" + printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" + printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" + printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" + printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" + printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" + printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw权限-标准安全模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为标准安全模式" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw权限-开发增强模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为开发增强模式" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw权限-完全开放模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切换失败:写入权限配置过程中出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切换为完全开放模式" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw权限-恢复官方默认" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 + openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 + openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 + openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + return 1 + fi + echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw权限-安全审计" + openclaw_permission_require_openclaw || return 1 + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw权限管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 权限管理" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1. 查看当前权限状态" + echo "2. 切换为标准安全模式(推荐)" + echo "3. 切换为开发增强模式" + echo "4. 切换为完全开放模式(高风险)" + echo "5. 恢复官方默认策略" + echo "6. 运行安全审计" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " perm_choice + case "$perm_choice" in + 1) + openclaw_permission_render_status + break_end + ;; + 2) + echo "将应用:标准安全模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + break_end + ;; + 3) + echo "将应用:开发增强模式" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + break_end + ;; + 4) + echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" + read -e -p "输入 FULL 确认继续: " confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + break_end + ;; + 5) + echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" + read -e -p "输入 yes 确认: " confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + break_end + ;; + 6) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "无效的选择,请重试。" + sleep 1 + ;; + esac + done + } + +openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" while true; do @@ -14157,9 +14500,10 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_backup_restore_menu ;; + 18) update_moltbot ;; + 19) uninstall_moltbot ;; *) break ;; esac done From d14437d46f57c66dd83272296ea72e52feb775fd Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 12:13:50 +0800 Subject: [PATCH 1071/1285] fix: harden OpenClaw permission mode switching --- cn/kejilion.sh | 50 +++++++++++++++++++++++++++++++++----------------- kejilion.sh | 50 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7fe579d2d..9f7b69422 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13998,7 +13998,7 @@ EOF fi fi - [ -f "$config_file" ] || { echo "(unset)"; return 1; } + [ -f "$config_file" ] || { echo "(unset)"; return 0; } if openclaw_has_command jq; then local jq_value @@ -14032,6 +14032,22 @@ PY fi echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>/dev/null | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ]; then + return 0 + fi return 1 } @@ -14085,8 +14101,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -14112,8 +14128,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -14139,8 +14155,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile full || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security full || failed=1 openclaw config set tools.exec.ask off || failed=1 @@ -14165,16 +14181,16 @@ PY openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 - openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 - openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 - openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 if [ "$failed" -ne 0 ]; then echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" openclaw_permission_restore_backup || true diff --git a/kejilion.sh b/kejilion.sh index 7fe579d2d..9f7b69422 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13998,7 +13998,7 @@ EOF fi fi - [ -f "$config_file" ] || { echo "(unset)"; return 1; } + [ -f "$config_file" ] || { echo "(unset)"; return 0; } if openclaw_has_command jq; then local jq_value @@ -14032,6 +14032,22 @@ PY fi echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>/dev/null | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ]; then + return 0 + fi return 1 } @@ -14085,8 +14101,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -14112,8 +14128,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -14139,8 +14155,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile full || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security full || failed=1 openclaw config set tools.exec.ask off || failed=1 @@ -14165,16 +14181,16 @@ PY openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 - openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 - openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 - openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 if [ "$failed" -ne 0 ]; then echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" openclaw_permission_restore_backup || true From 4a318e9e7a7e017ff2d4b1ddd476f0cbd5e2d1c5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 12:34:59 +0800 Subject: [PATCH 1072/1285] fix: handle missing OpenClaw config paths --- cn/kejilion.sh | 10 +++++++--- kejilion.sh | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9f7b69422..2882b7ce3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13984,8 +13984,12 @@ EOF if openclaw_has_command openclaw; then local value - value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + value=$(openclaw config get "$path" 2>&1 | head -n 1) if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi if [ "$value" = "null" ]; then echo "(unset)" else @@ -14044,8 +14048,8 @@ PY if openclaw config unset "$key" >/dev/null 2>&1; then return 0 fi - probe=$(openclaw config get "$key" 2>/dev/null | head -n 1) - if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ]; then + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then return 0 fi return 1 diff --git a/kejilion.sh b/kejilion.sh index 9f7b69422..2882b7ce3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13984,8 +13984,12 @@ EOF if openclaw_has_command openclaw; then local value - value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + value=$(openclaw config get "$path" 2>&1 | head -n 1) if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi if [ "$value" = "null" ]; then echo "(unset)" else @@ -14044,8 +14048,8 @@ PY if openclaw config unset "$key" >/dev/null 2>&1; then return 0 fi - probe=$(openclaw config get "$key" 2>/dev/null | head -n 1) - if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ]; then + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then return 0 fi return 1 From 3235805cf9c45f627ccee07db78146ae72171199 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 13:57:09 +0800 Subject: [PATCH 1073/1285] add openclaw multi-agent management menu --- cn/kejilion.sh | 245 +++++++++++++++- kejilion.sh | 245 +++++++++++++++- kr/kejilion.sh | 745 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 1117 insertions(+), 118 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 2882b7ce3..50946135c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10056,9 +10056,11 @@ moltbot_menu() { echo "15. 记忆/Memory" echo "16. 权限管理" echo "--------------------" - echo "17. 备份与还原" - echo "18. 更新" - echo "19. 卸载" + echo "17. 多智能体管理" + echo "--------------------" + echo "18. 备份与还原" + echo "19. 更新" + echo "20. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -14275,6 +14277,236 @@ PY done } + openclaw_multiagent_config_file() { + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" + echo "默认 Agent: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。"); +else: + import itertools + for item in itertools.islice(agents, 8): + identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw多智能体-列出Agent" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw多智能体-新增Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "请输入新的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "将创建 Agent: $agent_id" + echo "Workspace: $workspace" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ Agent 创建成功: $agent_id" + else + echo "❌ Agent 创建失败" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw多智能体-删除Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "请输入要删除的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ Agent 删除成功: $agent_id" + else + echo "❌ Agent 删除失败" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw多智能体-查看Bindings" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw多智能体-新增Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将绑定 Agent [$agent_id] -> [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 添加成功" + else + echo "❌ Binding 添加失败" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw多智能体-移除Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入要移除的绑定值: " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 移除成功" + else + echo "❌ Binding 移除失败" + return 1 + fi + } + + openclaw_multiagent_set_identity() { + send_stats "OpenClaw多智能体-设置Identity" + openclaw_multiagent_require_openclaw || return 1 + local agent_id name theme emoji confirm + read -e -p "请输入 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "Identity name(可留空): " name + read -e -p "Identity theme(可留空): " theme + read -e -p "Identity emoji(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 + echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + local cmd="openclaw agents set-identity --agent '$agent_id'" + [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" + [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" + [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" + eval "$cmd" + } + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw多智能体-Session概况" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("暂无 session 数据。"); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("Session 汇总:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw多智能体-健康检查" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ 未发现已配置 agent。"); +else: + for item in agents: + ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) +print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw多智能体管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 多智能体管理" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. 查看当前多智能体状态" + echo "2. 列出所有 Agent" + echo "3. 新增 Agent" + echo "4. 删除 Agent" + echo "5. 查看 Bindings" + echo "6. 新增 Binding" + echo "7. 移除 Binding" + echo "8. 设置 Agent Identity" + echo "9. 查看 Session 概况" + echo "10. 运行多智能体健康检查" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_render_status; break_end ;; + 2) openclaw_multiagent_list_agents; break_end ;; + 3) openclaw_multiagent_add_agent; break_end ;; + 4) openclaw_multiagent_delete_agent; break_end ;; + 5) openclaw_multiagent_list_bindings; break_end ;; + 6) openclaw_multiagent_add_binding; break_end ;; + 7) openclaw_multiagent_remove_binding; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_show_sessions; break_end ;; + 10) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "无效的选择,请重试。"; sleep 1 ;; + esac + done + } + + openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" @@ -14521,9 +14753,10 @@ openclaw_backup_restore_menu() { ;; 15) openclaw_memory_menu ;; 16) openclaw_permission_menu ;; - 17) openclaw_backup_restore_menu ;; - 18) update_moltbot ;; - 19) uninstall_moltbot ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done diff --git a/kejilion.sh b/kejilion.sh index 2882b7ce3..50946135c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10056,9 +10056,11 @@ moltbot_menu() { echo "15. 记忆/Memory" echo "16. 权限管理" echo "--------------------" - echo "17. 备份与还原" - echo "18. 更新" - echo "19. 卸载" + echo "17. 多智能体管理" + echo "--------------------" + echo "18. 备份与还原" + echo "19. 更新" + echo "20. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -14275,6 +14277,236 @@ PY done } + openclaw_multiagent_config_file() { + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" + echo "默认 Agent: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。"); +else: + import itertools + for item in itertools.islice(agents, 8): + identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw多智能体-列出Agent" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw多智能体-新增Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "请输入新的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "将创建 Agent: $agent_id" + echo "Workspace: $workspace" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ Agent 创建成功: $agent_id" + else + echo "❌ Agent 创建失败" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw多智能体-删除Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "请输入要删除的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ Agent 删除成功: $agent_id" + else + echo "❌ Agent 删除失败" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw多智能体-查看Bindings" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw多智能体-新增Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将绑定 Agent [$agent_id] -> [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 添加成功" + else + echo "❌ Binding 添加失败" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw多智能体-移除Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入要移除的绑定值: " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 移除成功" + else + echo "❌ Binding 移除失败" + return 1 + fi + } + + openclaw_multiagent_set_identity() { + send_stats "OpenClaw多智能体-设置Identity" + openclaw_multiagent_require_openclaw || return 1 + local agent_id name theme emoji confirm + read -e -p "请输入 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "Identity name(可留空): " name + read -e -p "Identity theme(可留空): " theme + read -e -p "Identity emoji(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 + echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + local cmd="openclaw agents set-identity --agent '$agent_id'" + [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" + [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" + [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" + eval "$cmd" + } + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw多智能体-Session概况" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("暂无 session 数据。"); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("Session 汇总:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw多智能体-健康检查" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ 未发现已配置 agent。"); +else: + for item in agents: + ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) +print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw多智能体管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 多智能体管理" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. 查看当前多智能体状态" + echo "2. 列出所有 Agent" + echo "3. 新增 Agent" + echo "4. 删除 Agent" + echo "5. 查看 Bindings" + echo "6. 新增 Binding" + echo "7. 移除 Binding" + echo "8. 设置 Agent Identity" + echo "9. 查看 Session 概况" + echo "10. 运行多智能体健康检查" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_render_status; break_end ;; + 2) openclaw_multiagent_list_agents; break_end ;; + 3) openclaw_multiagent_add_agent; break_end ;; + 4) openclaw_multiagent_delete_agent; break_end ;; + 5) openclaw_multiagent_list_bindings; break_end ;; + 6) openclaw_multiagent_add_binding; break_end ;; + 7) openclaw_multiagent_remove_binding; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_show_sessions; break_end ;; + 10) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "无效的选择,请重试。"; sleep 1 ;; + esac + done + } + + openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" @@ -14521,9 +14753,10 @@ openclaw_backup_restore_menu() { ;; 15) openclaw_memory_menu ;; 16) openclaw_permission_menu ;; - 17) openclaw_backup_restore_menu ;; - 18) update_moltbot ;; - 19) uninstall_moltbot ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d6d158da0..50946135c 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.8" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -10035,7 +10035,7 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理 🦞" + echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" @@ -10056,9 +10056,11 @@ moltbot_menu() { echo "15. 记忆/Memory" echo "16. 权限管理" echo "--------------------" - echo "17. 备份与还原" - echo "18. 更新" - echo "19. 卸载" + echo "17. 多智能体管理" + echo "--------------------" + echo "18. 备份与还原" + echo "19. 更新" + echo "20. 卸载" echo "--------------------" echo "0. 返回上一级选单" echo "--------------------" @@ -10436,7 +10438,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') + summary.append(f'✅ {name}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: summary.append(f'➕ 新增模型({len(added_ids)}):') @@ -10489,6 +10491,7 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway @@ -10529,52 +10532,20 @@ PY # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 - # 核心函数:获取并添加所有模型 - add-all-models-from-provider() { + # 构造模型配置 JSON + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 正在获取 $provider_name 的所有可用模型..." - - # 不再自动探测/纠正 API 协议;保持用户配置为准 - DETECTED_API="openai-completions" - - # 获取模型列表 - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ 无法获取模型列表" - return 1 - fi - - # 提取所有模型ID - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ 未找到任何模型" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 发现 $model_count 个模型" - - # 智能推断模型参数 + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context 和 max_tokens 全拉满,不怕大 local context_window=1048576 local max_tokens=128000 - - # 只有价格需要分级 local input_cost=0.15 local output_cost=0.60 @@ -10612,11 +10583,22 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # 写入 provider 与模型配置 + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file="${HOME}/.openclaw/openclaw.json" + + # 不再自动探测/纠正 API 协议;保持用户配置为准 + DETECTED_API="openai-completions" - # 备份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型,并同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10650,6 +10632,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # 核心函数:获取并添加所有模型 + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 正在获取 $provider_name 的所有可用模型..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 无法获取模型列表" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 发现 $model_count 个模型" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ 成功添加 $model_count 个模型到 $provider_name" @@ -10661,6 +10676,33 @@ EOF fi } + # 仅添加默认模型并保留 provider + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ 默认模型不能为空" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ 已添加 provider:$provider_name" + echo "✅ 仅写入默认模型:$default_model" + return 0 + else + echo "❌ 配置注入失败" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API添加" echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" @@ -10740,22 +10782,26 @@ EOF echo "模型总数 : $model_count" echo "======================" - read -erp "确认添加所有 $model_count 个模型?(y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + read -erp "是否同时添加其他所有可用模型?(y/N): " confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅ 完成!所有 $model_count 个模型已加载" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" start_gateway - echo "✅ 完成!所有 $model_count 个模型已加载" - echo "✅ 已自动识别协议为: $DETECTED_API" + echo "$finish_msg" + echo "✅ 当前 API 协议类型: $DETECTED_API" fi break_end @@ -11079,7 +11125,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 删除 {len(removed_ids)} 个,新增 {len(added_ids)} 个,当前 {len(new_models)} 个') +print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: print(f'➕ 新增模型({len(added_ids)}):') @@ -11442,10 +11488,214 @@ REPO local orange="#FF8C00" + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "可用" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed + local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply + + oc_config="${HOME}/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + request_model="${target_model#*/}" + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + first_endpoint="/responses" + second_endpoint="/chat/completions" + + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] +timeout = int(timeout) +url = base_url + endpoint +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } + + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0},切换 ${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } + clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # 从配置文件读取模型键(不调用 openclaw models list) local oc_config @@ -11467,53 +11717,53 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" - - install_gum - install gum - clear - # 若 gum 不存在,降级为原始手动输入流程(保持与之前完全一致) - if ! command -v gum >/dev/null 2>&1; then + # 若 gum 不存在,降级为原始手动输入流程 + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "当前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model - # 1. 检查是否输入 0 以退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break # 跳出 while 循环 + break fi - # 2. 验证输入是否为空 if [ -z "$selected_model" ]; then echo "错误:模型名称不能为空。请重试。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue fi + + echo "正在切换模型为: $selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切换失败:openclaw models set 返回错误。" + break_end + return 1 + fi + start_gateway + + break_end + return 0 else + install_gum + install gum + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then + echo "gum 不可用,返回旧版输入模式。" + sleep 1 + continue + fi gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "当前默认:${default_model}" echo "" - - # 底部提示 - gum style --faint "↑↓ 选择 / Enter 确认 / Esc 退出" + gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" echo "" - # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "搜索模型(如 cli-api/gpt-5.2)" \ - --prompt "选择模型 > " \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜索模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -11521,10 +11771,42 @@ REPO fi fi - # 去掉编号前缀:"(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # 执行切换 + echo "" + echo "正在检测模型: $selected_model" + if openclaw_model_probe "$selected_model"; then + openclaw_probe_status_line "可用" + else + openclaw_probe_status_line "不可用" + fi + echo "状态:$OPENCLAW_PROBE_MESSAGE" + echo "延迟:$OPENCLAW_PROBE_LATENCY" + echo "摘要:$OPENCLAW_PROBE_REPLY" + echo "" + + printf "是否切换到该模型?[y/N,Esc 返回列表]: " + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" + else + case "$confirm_switch" in + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "已返回模型选择列表。" + sleep 1 + continue + fi + echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then echo "切换失败:openclaw models set 返回错误。" @@ -11535,7 +11817,7 @@ REPO break_end done - } + } resolve_openclaw_plugin_id() { @@ -13704,8 +13986,12 @@ EOF if openclaw_has_command openclaw; then local value - value=$(openclaw config get "$path" 2>/dev/null | head -n 1) + value=$(openclaw config get "$path" 2>&1 | head -n 1) if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi if [ "$value" = "null" ]; then echo "(unset)" else @@ -13718,7 +14004,7 @@ EOF fi fi - [ -f "$config_file" ] || { echo "(unset)"; return 1; } + [ -f "$config_file" ] || { echo "(unset)"; return 0; } if openclaw_has_command jq; then local jq_value @@ -13752,6 +14038,22 @@ PY fi echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then + return 0 + fi return 1 } @@ -13805,8 +14107,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -13832,8 +14134,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile coding || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security allowlist || failed=1 openclaw config set tools.exec.ask on-miss || failed=1 @@ -13859,8 +14161,8 @@ PY openclaw_permission_backup_current || true local failed=0 openclaw config set tools.profile full || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 openclaw config set tools.deny '[]' --json || failed=1 openclaw config set tools.exec.security full || failed=1 openclaw config set tools.exec.ask off || failed=1 @@ -13885,16 +14187,16 @@ PY openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 - openclaw config unset tools.profile >/dev/null 2>&1 || failed=1 - openclaw config unset tools.byProvider >/dev/null 2>&1 || failed=1 - openclaw config unset tools.allow >/dev/null 2>&1 || failed=1 - openclaw config unset tools.deny >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.security >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.ask >/dev/null 2>&1 || failed=1 - openclaw config unset tools.elevated.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset commands.bash >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.enabled >/dev/null 2>&1 || failed=1 - openclaw config unset tools.exec.applyPatch.workspaceOnly >/dev/null 2>&1 || failed=1 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 if [ "$failed" -ne 0 ]; then echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" openclaw_permission_restore_backup || true @@ -13975,7 +14277,237 @@ PY done } - openclaw_backup_restore_menu() { + openclaw_multiagent_config_file() { + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" + echo "默认 Agent: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。"); +else: + import itertools + for item in itertools.islice(agents, 8): + identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw多智能体-列出Agent" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw多智能体-新增Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "请输入新的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "将创建 Agent: $agent_id" + echo "Workspace: $workspace" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ Agent 创建成功: $agent_id" + else + echo "❌ Agent 创建失败" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw多智能体-删除Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "请输入要删除的 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ Agent 删除成功: $agent_id" + else + echo "❌ Agent 删除失败" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw多智能体-查看Bindings" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw多智能体-新增Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将绑定 Agent [$agent_id] -> [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 添加成功" + else + echo "❌ Binding 添加失败" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw多智能体-移除Binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入要移除的绑定值: " bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Binding 移除成功" + else + echo "❌ Binding 移除失败" + return 1 + fi + } + + openclaw_multiagent_set_identity() { + send_stats "OpenClaw多智能体-设置Identity" + openclaw_multiagent_require_openclaw || return 1 + local agent_id name theme emoji confirm + read -e -p "请输入 Agent ID: " agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 + read -e -p "Identity name(可留空): " name + read -e -p "Identity theme(可留空): " theme + read -e -p "Identity emoji(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 + echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "输入 yes 确认继续: " confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + local cmd="openclaw agents set-identity --agent '$agent_id'" + [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" + [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" + [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" + eval "$cmd" + } + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw多智能体-Session概况" + openclaw_multiagent_require_openclaw || return 1 + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("暂无 session 数据。"); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("Session 汇总:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw多智能体-健康检查" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ 未发现已配置 agent。"); +else: + for item in agents: + ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) +print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw多智能体管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 多智能体管理" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. 查看当前多智能体状态" + echo "2. 列出所有 Agent" + echo "3. 新增 Agent" + echo "4. 删除 Agent" + echo "5. 查看 Bindings" + echo "6. 新增 Binding" + echo "7. 移除 Binding" + echo "8. 设置 Agent Identity" + echo "9. 查看 Session 概况" + echo "10. 运行多智能体健康检查" + echo "0. 返回上一级" + echo "---------------------------------------" + read -e -p "请输入你的选择: " multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_render_status; break_end ;; + 2) openclaw_multiagent_list_agents; break_end ;; + 3) openclaw_multiagent_add_agent; break_end ;; + 4) openclaw_multiagent_delete_agent; break_end ;; + 5) openclaw_multiagent_list_bindings; break_end ;; + 6) openclaw_multiagent_add_binding; break_end ;; + 7) openclaw_multiagent_remove_binding; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_show_sessions; break_end ;; + 10) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "无效的选择,请重试。"; sleep 1 ;; + esac + done + } + + +openclaw_backup_restore_menu() { send_stats "OpenClaw备份与还原" while true; do @@ -14221,9 +14753,10 @@ PY ;; 15) openclaw_memory_menu ;; 16) openclaw_permission_menu ;; - 17) openclaw_backup_restore_menu ;; - 18) update_moltbot ;; - 19) uninstall_moltbot ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done From aab810c47e3e349b94aa62985566a38bda4691ff Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 14:01:22 +0800 Subject: [PATCH 1074/1285] fix openclaw multi-agent status fallback --- cn/kejilion.sh | 7 ++++++- kejilion.sh | 7 ++++++- kr/kejilion.sh | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 50946135c..8afa09c06 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14285,7 +14285,12 @@ PY local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then - value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) fi [ -z "$value" ] && value="(unset)" if echo "$value" | grep -q '^".*"$'; then diff --git a/kejilion.sh b/kejilion.sh index 50946135c..8afa09c06 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14285,7 +14285,12 @@ PY local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then - value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) fi [ -z "$value" ] && value="(unset)" if echo "$value" | grep -q '^".*"$'; then diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 50946135c..8afa09c06 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -14285,7 +14285,12 @@ PY local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then - value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys; data=json.load(sys.stdin); print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)"))' 2>/dev/null) + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) fi [ -z "$value" ] && value="(unset)" if echo "$value" | grep -q '^".*"$'; then From a2357b54867ba5e26379b773bf4ae60997c0a7f4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 14:33:47 +0800 Subject: [PATCH 1075/1285] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=9A=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E4=BD=93=E7=AE=A1=E7=90=86=E8=8F=9C=E5=8D=95=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 108 ++++++++++++++++++++++++------------------------- kejilion.sh | 108 ++++++++++++++++++++++++------------------------- kr/kejilion.sh | 108 ++++++++++++++++++++++++------------------------- 3 files changed, 156 insertions(+), 168 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8afa09c06..522576d93 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14324,13 +14324,13 @@ except Exception: config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" - echo "默认 Agent: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。"); + echo "默认智能体: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14350,14 +14350,14 @@ for idx,item in enumerate(agents,1): [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "将创建 Agent: $agent_id" - echo "Workspace: $workspace" + echo "将创建智能体: $agent_id" + echo "工作目录: $workspace" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ Agent 创建成功: $agent_id" + echo "✅ 智能体创建成功: $agent_id" else - echo "❌ Agent 创建失败" + echo "❌ 智能体创建失败" return 1 fi } @@ -14368,73 +14368,73 @@ for idx,item in enumerate(agents,1): local agent_id confirm read -e -p "请输入要删除的 Agent ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + echo "⚠️ 删除智能体可能影响其工作目录、路由绑定与会话路由。" read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ Agent 删除成功: $agent_id" + echo "✅ 智能体删除成功: $agent_id" else - echo "❌ Agent 删除失败" + echo "❌ 智能体删除失败" return 1 fi } openclaw_multiagent_list_bindings() { - send_stats "OpenClaw多智能体-查看Bindings" + send_stats "OpenClaw多智能体-查看路由绑定" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +if not bindings: print("暂无路由绑定。"); raise SystemExit(0) for idx,item in enumerate(bindings,1): bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { - send_stats "OpenClaw多智能体-新增Binding" + send_stats "OpenClaw多智能体-新增路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入路由绑定值(如 telegram:ops / discord:guild-a): " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将绑定 Agent [$agent_id] -> [$bind_value]" + echo "将绑定智能体 [$agent_id] -> [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 添加成功" + echo "✅ 路由绑定添加成功" else - echo "❌ Binding 添加失败" + echo "❌ 路由绑定添加失败" return 1 fi } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw多智能体-移除Binding" + send_stats "OpenClaw多智能体-移除路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入要移除的绑定值: " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入要移除的路由绑定值: " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + echo "将移除智能体 [$agent_id] 的路由绑定 [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 移除成功" + echo "✅ 路由绑定移除成功" else - echo "❌ Binding 移除失败" + echo "❌ 路由绑定移除失败" return 1 fi } openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置Identity" + send_stats "OpenClaw多智能体-设置智能体身份" openclaw_multiagent_require_openclaw || return 1 local agent_id name theme emoji confirm - read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入智能体 ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "Identity name(可留空): " name - read -e -p "Identity theme(可留空): " theme - read -e -p "Identity emoji(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 - echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "身份名称(可留空): " name + read -e -p "身份主题(可留空): " theme + read -e -p "身份表情(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 + echo "将更新智能体 [$agent_id] 的身份信息。" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } local cmd="openclaw agents set-identity --agent '$agent_id'" @@ -14445,13 +14445,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_show_sessions() { - send_stats "OpenClaw多智能体-Session概况" + send_stats "OpenClaw多智能体-会话概况" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; if not sessions: print("暂无 session 数据。"); raise SystemExit(0) by_agent={} for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 -print("Session 汇总:") +print("会话汇总:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" @@ -14465,11 +14465,11 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置 agent。"); +if not agents: print("⚠️ 未发现已配置智能体。"); else: for item in agents: ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) -print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" +print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_menu() { @@ -14481,30 +14481,26 @@ print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 查看当前多智能体状态" - echo "2. 列出所有 Agent" - echo "3. 新增 Agent" - echo "4. 删除 Agent" - echo "5. 查看 Bindings" - echo "6. 新增 Binding" - echo "7. 移除 Binding" - echo "8. 设置 Agent Identity" - echo "9. 查看 Session 概况" - echo "10. 运行多智能体健康检查" + echo "1. 新增智能体" + echo "2. 删除智能体" + echo "3. 查看路由绑定" + echo "4. 新增路由绑定" + echo "5. 移除路由绑定" + echo "6. 设置智能体身份" + echo "7. 查看会话概况" + echo "8. 运行多智能体健康检查" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice case "$multi_choice" in - 1) openclaw_multiagent_render_status; break_end ;; - 2) openclaw_multiagent_list_agents; break_end ;; - 3) openclaw_multiagent_add_agent; break_end ;; - 4) openclaw_multiagent_delete_agent; break_end ;; - 5) openclaw_multiagent_list_bindings; break_end ;; - 6) openclaw_multiagent_add_binding; break_end ;; - 7) openclaw_multiagent_remove_binding; break_end ;; - 8) openclaw_multiagent_set_identity; break_end ;; - 9) openclaw_multiagent_show_sessions; break_end ;; - 10) openclaw_multiagent_health_check; break_end ;; + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_set_identity; break_end ;; + 7) openclaw_multiagent_show_sessions; break_end ;; + 8) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac diff --git a/kejilion.sh b/kejilion.sh index 8afa09c06..522576d93 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14324,13 +14324,13 @@ except Exception: config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" - echo "默认 Agent: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。"); + echo "默认智能体: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14350,14 +14350,14 @@ for idx,item in enumerate(agents,1): [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "将创建 Agent: $agent_id" - echo "Workspace: $workspace" + echo "将创建智能体: $agent_id" + echo "工作目录: $workspace" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ Agent 创建成功: $agent_id" + echo "✅ 智能体创建成功: $agent_id" else - echo "❌ Agent 创建失败" + echo "❌ 智能体创建失败" return 1 fi } @@ -14368,73 +14368,73 @@ for idx,item in enumerate(agents,1): local agent_id confirm read -e -p "请输入要删除的 Agent ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + echo "⚠️ 删除智能体可能影响其工作目录、路由绑定与会话路由。" read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ Agent 删除成功: $agent_id" + echo "✅ 智能体删除成功: $agent_id" else - echo "❌ Agent 删除失败" + echo "❌ 智能体删除失败" return 1 fi } openclaw_multiagent_list_bindings() { - send_stats "OpenClaw多智能体-查看Bindings" + send_stats "OpenClaw多智能体-查看路由绑定" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +if not bindings: print("暂无路由绑定。"); raise SystemExit(0) for idx,item in enumerate(bindings,1): bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { - send_stats "OpenClaw多智能体-新增Binding" + send_stats "OpenClaw多智能体-新增路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入路由绑定值(如 telegram:ops / discord:guild-a): " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将绑定 Agent [$agent_id] -> [$bind_value]" + echo "将绑定智能体 [$agent_id] -> [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 添加成功" + echo "✅ 路由绑定添加成功" else - echo "❌ Binding 添加失败" + echo "❌ 路由绑定添加失败" return 1 fi } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw多智能体-移除Binding" + send_stats "OpenClaw多智能体-移除路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入要移除的绑定值: " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入要移除的路由绑定值: " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + echo "将移除智能体 [$agent_id] 的路由绑定 [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 移除成功" + echo "✅ 路由绑定移除成功" else - echo "❌ Binding 移除失败" + echo "❌ 路由绑定移除失败" return 1 fi } openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置Identity" + send_stats "OpenClaw多智能体-设置智能体身份" openclaw_multiagent_require_openclaw || return 1 local agent_id name theme emoji confirm - read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入智能体 ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "Identity name(可留空): " name - read -e -p "Identity theme(可留空): " theme - read -e -p "Identity emoji(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 - echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "身份名称(可留空): " name + read -e -p "身份主题(可留空): " theme + read -e -p "身份表情(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 + echo "将更新智能体 [$agent_id] 的身份信息。" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } local cmd="openclaw agents set-identity --agent '$agent_id'" @@ -14445,13 +14445,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_show_sessions() { - send_stats "OpenClaw多智能体-Session概况" + send_stats "OpenClaw多智能体-会话概况" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; if not sessions: print("暂无 session 数据。"); raise SystemExit(0) by_agent={} for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 -print("Session 汇总:") +print("会话汇总:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" @@ -14465,11 +14465,11 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置 agent。"); +if not agents: print("⚠️ 未发现已配置智能体。"); else: for item in agents: ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) -print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" +print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_menu() { @@ -14481,30 +14481,26 @@ print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 查看当前多智能体状态" - echo "2. 列出所有 Agent" - echo "3. 新增 Agent" - echo "4. 删除 Agent" - echo "5. 查看 Bindings" - echo "6. 新增 Binding" - echo "7. 移除 Binding" - echo "8. 设置 Agent Identity" - echo "9. 查看 Session 概况" - echo "10. 运行多智能体健康检查" + echo "1. 新增智能体" + echo "2. 删除智能体" + echo "3. 查看路由绑定" + echo "4. 新增路由绑定" + echo "5. 移除路由绑定" + echo "6. 设置智能体身份" + echo "7. 查看会话概况" + echo "8. 运行多智能体健康检查" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice case "$multi_choice" in - 1) openclaw_multiagent_render_status; break_end ;; - 2) openclaw_multiagent_list_agents; break_end ;; - 3) openclaw_multiagent_add_agent; break_end ;; - 4) openclaw_multiagent_delete_agent; break_end ;; - 5) openclaw_multiagent_list_bindings; break_end ;; - 6) openclaw_multiagent_add_binding; break_end ;; - 7) openclaw_multiagent_remove_binding; break_end ;; - 8) openclaw_multiagent_set_identity; break_end ;; - 9) openclaw_multiagent_show_sessions; break_end ;; - 10) openclaw_multiagent_health_check; break_end ;; + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_set_identity; break_end ;; + 7) openclaw_multiagent_show_sessions; break_end ;; + 8) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 8afa09c06..522576d93 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -14324,13 +14324,13 @@ except Exception: config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" - echo "默认 Agent: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置 Agent 数: %s" % len(agents)); print("Routing 绑定数: %s" % len(bindings)); print("Session 总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。"); + echo "默认智能体: $default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; ws=item.get("workspace") or "-"; print("- %s | identity=%s | bindings=%s" % (item.get("id","?"), identity, item.get("bindings",0))); print(" workspace: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14350,14 +14350,14 @@ for idx,item in enumerate(agents,1): [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "将创建 Agent: $agent_id" - echo "Workspace: $workspace" + echo "将创建智能体: $agent_id" + echo "工作目录: $workspace" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ Agent 创建成功: $agent_id" + echo "✅ 智能体创建成功: $agent_id" else - echo "❌ Agent 创建失败" + echo "❌ 智能体创建失败" return 1 fi } @@ -14368,73 +14368,73 @@ for idx,item in enumerate(agents,1): local agent_id confirm read -e -p "请输入要删除的 Agent ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - echo "⚠️ 删除 Agent 可能影响其 workspace、bindings 与 session 路由。" + echo "⚠️ 删除智能体可能影响其工作目录、路由绑定与会话路由。" read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ Agent 删除成功: $agent_id" + echo "✅ 智能体删除成功: $agent_id" else - echo "❌ Agent 删除失败" + echo "❌ 智能体删除失败" return 1 fi } openclaw_multiagent_list_bindings() { - send_stats "OpenClaw多智能体-查看Bindings" + send_stats "OpenClaw多智能体-查看路由绑定" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无 routing bindings。"); raise SystemExit(0) +if not bindings: print("暂无路由绑定。"); raise SystemExit(0) for idx,item in enumerate(bindings,1): bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { - send_stats "OpenClaw多智能体-新增Binding" + send_stats "OpenClaw多智能体-新增路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入绑定值(如 telegram:ops / discord:guild-a): " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入路由绑定值(如 telegram:ops / discord:guild-a): " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将绑定 Agent [$agent_id] -> [$bind_value]" + echo "将绑定智能体 [$agent_id] -> [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 添加成功" + echo "✅ 路由绑定添加成功" else - echo "❌ Binding 添加失败" + echo "❌ 路由绑定添加失败" return 1 fi } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw多智能体-移除Binding" + send_stats "OpenClaw多智能体-移除路由绑定" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入 Agent ID: " agent_id - read -e -p "请输入要移除的绑定值: " bind_value + read -e -p "请输入智能体 ID: " agent_id + read -e -p "请输入要移除的路由绑定值: " bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将移除 Agent [$agent_id] 的 binding [$bind_value]" + echo "将移除智能体 [$agent_id] 的路由绑定 [$bind_value]" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ Binding 移除成功" + echo "✅ 路由绑定移除成功" else - echo "❌ Binding 移除失败" + echo "❌ 路由绑定移除失败" return 1 fi } openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置Identity" + send_stats "OpenClaw多智能体-设置智能体身份" openclaw_multiagent_require_openclaw || return 1 local agent_id name theme emoji confirm - read -e -p "请输入 Agent ID: " agent_id + read -e -p "请输入智能体 ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "Identity name(可留空): " name - read -e -p "Identity theme(可留空): " theme - read -e -p "Identity emoji(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个 identity 字段。" && return 1 - echo "将更新 Agent [$agent_id] 的 identity。" + read -e -p "身份名称(可留空): " name + read -e -p "身份主题(可留空): " theme + read -e -p "身份表情(可留空): " emoji + [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 + echo "将更新智能体 [$agent_id] 的身份信息。" read -e -p "输入 yes 确认继续: " confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } local cmd="openclaw agents set-identity --agent '$agent_id'" @@ -14445,13 +14445,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_show_sessions() { - send_stats "OpenClaw多智能体-Session概况" + send_stats "OpenClaw多智能体-会话概况" openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; if not sessions: print("暂无 session 数据。"); raise SystemExit(0) by_agent={} for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 -print("Session 汇总:") +print("会话汇总:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" @@ -14465,11 +14465,11 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置 agent。"); +if not agents: print("⚠️ 未发现已配置智能体。"); else: for item in agents: ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) -print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" +print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_menu() { @@ -14481,30 +14481,26 @@ print("bindings=%s" % len(bindings)); print("✅ 多智能体健康检查完成" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 查看当前多智能体状态" - echo "2. 列出所有 Agent" - echo "3. 新增 Agent" - echo "4. 删除 Agent" - echo "5. 查看 Bindings" - echo "6. 新增 Binding" - echo "7. 移除 Binding" - echo "8. 设置 Agent Identity" - echo "9. 查看 Session 概况" - echo "10. 运行多智能体健康检查" + echo "1. 新增智能体" + echo "2. 删除智能体" + echo "3. 查看路由绑定" + echo "4. 新增路由绑定" + echo "5. 移除路由绑定" + echo "6. 设置智能体身份" + echo "7. 查看会话概况" + echo "8. 运行多智能体健康检查" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice case "$multi_choice" in - 1) openclaw_multiagent_render_status; break_end ;; - 2) openclaw_multiagent_list_agents; break_end ;; - 3) openclaw_multiagent_add_agent; break_end ;; - 4) openclaw_multiagent_delete_agent; break_end ;; - 5) openclaw_multiagent_list_bindings; break_end ;; - 6) openclaw_multiagent_add_binding; break_end ;; - 7) openclaw_multiagent_remove_binding; break_end ;; - 8) openclaw_multiagent_set_identity; break_end ;; - 9) openclaw_multiagent_show_sessions; break_end ;; - 10) openclaw_multiagent_health_check; break_end ;; + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_set_identity; break_end ;; + 7) openclaw_multiagent_show_sessions; break_end ;; + 8) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac From bb48820b53da4b1f0cb60ee8fd4f2d5ae83d1f3a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 15:06:57 +0800 Subject: [PATCH 1076/1285] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=A4=9A?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E4=BD=93=E8=8F=9C=E5=8D=95=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kejilion.sh | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 522576d93..9bf866211 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14278,10 +14278,44 @@ PY } openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi openclaw config file 2>/dev/null | tail -n 1 } openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then @@ -14308,15 +14342,124 @@ except Exception: } openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents list --json 2>/dev/null || echo '[]' } openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents bindings --json 2>/dev/null || echo '[]' } openclaw_multiagent_sessions_json() { - openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY } openclaw_multiagent_render_status() { @@ -14335,7 +14478,6 @@ else: openclaw_multiagent_list_agents() { send_stats "OpenClaw多智能体-列出Agent" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) for idx,item in enumerate(agents,1): @@ -14381,7 +14523,6 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw多智能体-查看路由绑定" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); if not bindings: print("暂无路由绑定。"); raise SystemExit(0) for idx,item in enumerate(bindings,1): @@ -14446,7 +14587,6 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; if not sessions: print("暂无 session 数据。"); raise SystemExit(0) by_agent={} From ae3504d6b521f7f6a8706c8ccd10973a763e96ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:50:49 +0800 Subject: [PATCH 1077/1285] Add multiagent functions for OpenClaw configuration --- cn/kejilion.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 522576d93..9bf866211 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14278,10 +14278,44 @@ PY } openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi openclaw config file 2>/dev/null | tail -n 1 } openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then @@ -14308,15 +14342,124 @@ except Exception: } openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents list --json 2>/dev/null || echo '[]' } openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents bindings --json 2>/dev/null || echo '[]' } openclaw_multiagent_sessions_json() { - openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY } openclaw_multiagent_render_status() { @@ -14335,7 +14478,6 @@ else: openclaw_multiagent_list_agents() { send_stats "OpenClaw多智能体-列出Agent" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) for idx,item in enumerate(agents,1): @@ -14381,7 +14523,6 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw多智能体-查看路由绑定" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); if not bindings: print("暂无路由绑定。"); raise SystemExit(0) for idx,item in enumerate(bindings,1): @@ -14446,7 +14587,6 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" - openclaw_multiagent_require_openclaw || return 1 python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; if not sessions: print("暂无 session 数据。"); raise SystemExit(0) by_agent={} From 5f7138e506d41421d8047d5dd46eaa18f44b2f60 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 15:57:10 +0800 Subject: [PATCH 1078/1285] menu: group memory/auth/multi-agent together --- cn/kejilion.sh | 1 - kejilion.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9bf866211..c72d786e0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10055,7 +10055,6 @@ moltbot_menu() { echo "14. TUI命令行对话窗口" echo "15. 记忆/Memory" echo "16. 权限管理" - echo "--------------------" echo "17. 多智能体管理" echo "--------------------" echo "18. 备份与还原" diff --git a/kejilion.sh b/kejilion.sh index 9bf866211..c72d786e0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10055,7 +10055,6 @@ moltbot_menu() { echo "14. TUI命令行对话窗口" echo "15. 记忆/Memory" echo "16. 权限管理" - echo "--------------------" echo "17. 多智能体管理" echo "--------------------" echo "18. 备份与还原" From c29f6fe4e8b2fa99677087bda214dabc9f5049df Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:05:54 +0800 Subject: [PATCH 1079/1285] fix: compatibility with 'name' field for multi-agent identity display --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c72d786e0..675c92d0f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + identity=item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { diff --git a/kejilion.sh b/kejilion.sh index c72d786e0..675c92d0f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + identity=item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { From 38ce54ae5315239836088570538e0d03dde4a5e3 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:18:45 +0800 Subject: [PATCH 1080/1285] fix: look deeper into 'identity.name' for agent identity display --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 675c92d0f..6809fb3a3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { diff --git a/kejilion.sh b/kejilion.sh index 675c92d0f..6809fb3a3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { From f9885a85ca19a7e4cc4b76342bac6e5f3aed8c55 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:38:20 +0800 Subject: [PATCH 1081/1285] refactor: merge agent identity setup into creation flow and slim down menu --- cn/kejilion.sh | 36 +++++++++++------------------------- kejilion.sh | 36 +++++++++++------------------------- 2 files changed, 22 insertions(+), 50 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6809fb3a3..592cef278 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14497,6 +14497,13 @@ for idx,item in enumerate(agents,1): [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ 智能体创建成功: $agent_id" + local name theme + read -e -p "请输入智能体身份名称 (如: 代码专家): " name + [ -z "$name" ] && name="$agent_id" + read -e -p "请输入智能体性格主题 (如: 严谨、高效): " theme + [ -z "$theme" ] && theme="助手" + echo "正在配置智能体身份..." + openclaw agents identity "$agent_id" --name "$name" --theme "$theme" else echo "❌ 智能体创建失败" return 1 @@ -14564,25 +14571,6 @@ for idx,item in enumerate(bindings,1): fi } - openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置智能体身份" - openclaw_multiagent_require_openclaw || return 1 - local agent_id name theme emoji confirm - read -e -p "请输入智能体 ID: " agent_id - [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "身份名称(可留空): " name - read -e -p "身份主题(可留空): " theme - read -e -p "身份表情(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 - echo "将更新智能体 [$agent_id] 的身份信息。" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } - local cmd="openclaw agents set-identity --agent '$agent_id'" - [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" - [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" - [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" - eval "$cmd" - } openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" @@ -14625,9 +14613,8 @@ print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查 echo "3. 查看路由绑定" echo "4. 新增路由绑定" echo "5. 移除路由绑定" - echo "6. 设置智能体身份" - echo "7. 查看会话概况" - echo "8. 运行多智能体健康检查" + echo "6. 查看会话概况" + echo "7. 运行多智能体健康检查" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice @@ -14637,9 +14624,8 @@ print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查 3) openclaw_multiagent_list_bindings; break_end ;; 4) openclaw_multiagent_add_binding; break_end ;; 5) openclaw_multiagent_remove_binding; break_end ;; - 6) openclaw_multiagent_set_identity; break_end ;; - 7) openclaw_multiagent_show_sessions; break_end ;; - 8) openclaw_multiagent_health_check; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac diff --git a/kejilion.sh b/kejilion.sh index 6809fb3a3..592cef278 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14497,6 +14497,13 @@ for idx,item in enumerate(agents,1): [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ 智能体创建成功: $agent_id" + local name theme + read -e -p "请输入智能体身份名称 (如: 代码专家): " name + [ -z "$name" ] && name="$agent_id" + read -e -p "请输入智能体性格主题 (如: 严谨、高效): " theme + [ -z "$theme" ] && theme="助手" + echo "正在配置智能体身份..." + openclaw agents identity "$agent_id" --name "$name" --theme "$theme" else echo "❌ 智能体创建失败" return 1 @@ -14564,25 +14571,6 @@ for idx,item in enumerate(bindings,1): fi } - openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置智能体身份" - openclaw_multiagent_require_openclaw || return 1 - local agent_id name theme emoji confirm - read -e -p "请输入智能体 ID: " agent_id - [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "身份名称(可留空): " name - read -e -p "身份主题(可留空): " theme - read -e -p "身份表情(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 - echo "将更新智能体 [$agent_id] 的身份信息。" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } - local cmd="openclaw agents set-identity --agent '$agent_id'" - [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" - [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" - [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" - eval "$cmd" - } openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" @@ -14625,9 +14613,8 @@ print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查 echo "3. 查看路由绑定" echo "4. 新增路由绑定" echo "5. 移除路由绑定" - echo "6. 设置智能体身份" - echo "7. 查看会话概况" - echo "8. 运行多智能体健康检查" + echo "6. 查看会话概况" + echo "7. 运行多智能体健康检查" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice @@ -14637,9 +14624,8 @@ print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查 3) openclaw_multiagent_list_bindings; break_end ;; 4) openclaw_multiagent_add_binding; break_end ;; 5) openclaw_multiagent_remove_binding; break_end ;; - 6) openclaw_multiagent_set_identity; break_end ;; - 7) openclaw_multiagent_show_sessions; break_end ;; - 8) openclaw_multiagent_health_check; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac From 3ec7d49fceeb08d5835a3aec356dec89dbf732f7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:41:31 +0800 Subject: [PATCH 1082/1285] fix: false positive 'MISSING' status for main agent in health check --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 592cef278..e2a0419ff 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14595,7 +14595,7 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item if not agents: print("⚠️ 未发现已配置智能体。"); else: for item in agents: - ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } diff --git a/kejilion.sh b/kejilion.sh index 592cef278..e2a0419ff 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14595,7 +14595,7 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item if not agents: print("⚠️ 未发现已配置智能体。"); else: for item in agents: - ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } From bfa0aec0467b7878548e9de5255c6642965bfc1c Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:47:32 +0800 Subject: [PATCH 1083/1285] style: highlight agent ID with color and remove redundant fields --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e2a0419ff..e82d92261 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { diff --git a/kejilion.sh b/kejilion.sh index e2a0419ff..e82d92261 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14472,7 +14472,7 @@ if not agents: print("当前未配置任何多智能体。") else: import itertools for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { From 3f1ef39d1cd1c7b49ad7a89344771e9035cbf53e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 16:56:18 +0800 Subject: [PATCH 1084/1285] fix: use official 'agents set-identity' command in agent creation flow --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e82d92261..a6b7068d2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14503,7 +14503,7 @@ for idx,item in enumerate(agents,1): read -e -p "请输入智能体性格主题 (如: 严谨、高效): " theme [ -z "$theme" ] && theme="助手" echo "正在配置智能体身份..." - openclaw agents identity "$agent_id" --name "$name" --theme "$theme" + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else echo "❌ 智能体创建失败" return 1 diff --git a/kejilion.sh b/kejilion.sh index e82d92261..a6b7068d2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14503,7 +14503,7 @@ for idx,item in enumerate(agents,1): read -e -p "请输入智能体性格主题 (如: 严谨、高效): " theme [ -z "$theme" ] && theme="助手" echo "正在配置智能体身份..." - openclaw agents identity "$agent_id" --name "$name" --theme "$theme" + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else echo "❌ 智能体创建失败" return 1 From e2543a6e0ed708e70db16a5e818c4a98ca03c6e4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 18:05:30 +0800 Subject: [PATCH 1085/1285] feat: upgrade memory backup/restore to support multi-agent seamlessly --- cn/kejilion.sh | 169 ++++++++++++++++++------------------------------- kejilion.sh | 169 ++++++++++++++++++------------------------------- 2 files changed, 122 insertions(+), 216 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a6b7068d2..5a43a4c4e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12597,129 +12597,82 @@ EOF return 0 } + openclaw_get_all_agent_workspaces() { + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY + else + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' + fi + } + openclaw_memory_backup_export() { send_stats "OpenClaw记忆全量备份" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ 未找到 workspace 目录: $workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可备份的记忆文件" - rm -rf "$tmp_payload" - break_end - return 1 + echo "❌ 未找到可备份的记忆文件"; rm -rf "$tmp_payload"; break_end; return 1 fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 记忆全量备份完成: $out_file" - openclaw_offer_transfer_hint "$out_file" + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ 记忆全量备份完成 (含多智能体): $out_file"; openclaw_offer_transfer_hint "$out_file" else echo "❌ 记忆全量备份失败" fi - - rm -rf "$tmp_payload" - break_end - } - - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 - echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 - echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 - read -e -p "请输入备份文件名或路径: " file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" - fi - - if [ ! -f "$file_path" ]; then - echo "❌ 备份文件不存在: $file_path" >&2 - echo "" - return 1 - fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { send_stats "OpenClaw记忆全量还原" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") - [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 检测到非法或越权路径: $rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ 还原中止:存在不安全路径" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ 记忆全量还原完成" - break_end + local archive_path=$(openclaw_read_import_path "还原记忆全量 (支持多智能体)") + [ -z "$archive_path" ] && { echo "❌ 未输入路径"; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ 已还原智能体记忆: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ 记忆全量还原完成"; break_end } + openclaw_project_backup_export() { send_stats "OpenClaw项目备份" local openclaw_root="${HOME}/.openclaw" diff --git a/kejilion.sh b/kejilion.sh index a6b7068d2..5a43a4c4e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12597,129 +12597,82 @@ EOF return 0 } + openclaw_get_all_agent_workspaces() { + local config_file="${HOME}/.openclaw/openclaw.json" + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY + else + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' + fi + } + openclaw_memory_backup_export() { send_stats "OpenClaw记忆全量备份" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ 未找到 workspace 目录: $workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可备份的记忆文件" - rm -rf "$tmp_payload" - break_end - return 1 + echo "❌ 未找到可备份的记忆文件"; rm -rf "$tmp_payload"; break_end; return 1 fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 记忆全量备份完成: $out_file" - openclaw_offer_transfer_hint "$out_file" + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ 记忆全量备份完成 (含多智能体): $out_file"; openclaw_offer_transfer_hint "$out_file" else echo "❌ 记忆全量备份失败" fi - - rm -rf "$tmp_payload" - break_end - } - - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 - echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 - echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 - read -e -p "请输入备份文件名或路径: " file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" - fi - - if [ ! -f "$file_path" ]; then - echo "❌ 备份文件不存在: $file_path" >&2 - echo "" - return 1 - fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { send_stats "OpenClaw记忆全量还原" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") - [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 检测到非法或越权路径: $rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ 还原中止:存在不安全路径" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ 记忆全量还原完成" - break_end + local archive_path=$(openclaw_read_import_path "还原记忆全量 (支持多智能体)") + [ -z "$archive_path" ] && { echo "❌ 未输入路径"; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ 已还原智能体记忆: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ 记忆全量还原完成"; break_end } + openclaw_project_backup_export() { send_stats "OpenClaw项目备份" local openclaw_root="${HOME}/.openclaw" From e023878b19f09929213ff12d99e8d300a5a9c2a6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 18:32:17 +0800 Subject: [PATCH 1086/1285] perf: use local python parser for permission status display to avoid CLI latency --- cn/kejilion.sh | 43 +++++++++++++++++++++++++++++-------------- kejilion.sh | 47 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5a43a4c4e..055acd1c4 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14030,27 +14030,42 @@ PY fi } - openclaw_permission_render_status() { + openclaw_permission_render_status() { local config_file mode config_file=$(openclaw_permission_config_file) mode=$(openclaw_permission_detect_mode) echo "配置文件: $config_file" [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" - if ! openclaw_has_command openclaw; then - echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" - fi echo "当前模式: $mode" echo "---------------------------------------" - printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" - printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" - printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" - printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" - printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" - printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" - printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" - printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" - printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" - printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except: print("❌ 配置文件解析失败") +PY } openclaw_permission_apply_standard() { diff --git a/kejilion.sh b/kejilion.sh index 5a43a4c4e..92f308bb0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14030,27 +14030,46 @@ PY fi } - openclaw_permission_render_status() { + openclaw_permission_render_status() { local config_file mode config_file=$(openclaw_permission_config_file) mode=$(openclaw_permission_detect_mode) echo "配置文件: $config_file" [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" - if ! openclaw_has_command openclaw; then - echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" - fi echo "当前模式: $mode" echo "---------------------------------------" - printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" - printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" - printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" - printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" - printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" - printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" - printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" - printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" - printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" - printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + + # 使用 Python 一次性高效解析所有权限字段 + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) + +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except Exception as e: + print("❌ 配置文件解析失败: %s" % e) +PY } openclaw_permission_apply_standard() { From 640718fedbb058956f1dbfbfd72529fc09b18437 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 23:26:36 +0800 Subject: [PATCH 1087/1285] feat: restore openclaw menu shortcut and permission menu perf fixes --- cn/kejilion.sh | 82 ++++++++++++++++++++++++++++++-------------------- kejilion.sh | 82 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 100 insertions(+), 64 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 055acd1c4..8556b4e67 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10036,6 +10036,7 @@ moltbot_menu() { echo "=======================================" echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" + echo -e "💡 终端执行 \033[1;33mk claw\033[0m 快速进入菜单" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" @@ -14010,24 +14011,43 @@ PY } openclaw_permission_detect_mode() { - local profile security ask elevated bash_enabled apply_patch workspace_only - profile=$(openclaw_permission_get_value "tools.profile") - security=$(openclaw_permission_get_value "tools.exec.security") - ask=$(openclaw_permission_get_value "tools.exec.ask") - elevated=$(openclaw_permission_get_value "tools.elevated.enabled") - bash_enabled=$(openclaw_permission_get_value "commands.bash") - apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") - workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") - - if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then - echo "标准安全模式" - elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then - echo "开发增强模式" - elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then - echo "完全开放模式" - else - echo "自定义模式" - fi + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "未知模式"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("标准安全模式") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("开发增强模式") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("完全开放模式") + else: + print("自定义模式") +except Exception: + print("自定义模式") +PY } openclaw_permission_render_status() { @@ -14191,45 +14211,40 @@ PY echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 查看当前权限状态" - echo "2. 切换为标准安全模式(推荐)" - echo "3. 切换为开发增强模式" - echo "4. 切换为完全开放模式(高风险)" - echo "5. 恢复官方默认策略" - echo "6. 运行安全审计" + echo "1. 切换为标准安全模式(推荐)" + echo "2. 切换为开发增强模式" + echo "3. 切换为完全开放模式(高风险)" + echo "4. 恢复官方默认策略" + echo "5. 运行安全审计" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice case "$perm_choice" in 1) - openclaw_permission_render_status - break_end - ;; - 2) echo "将应用:标准安全模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" break_end ;; - 3) + 2) echo "将应用:开发增强模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" break_end ;; - 4) + 3) echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" read -e -p "输入 FULL 确认继续: " confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" break_end ;; - 5) + 4) echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" break_end ;; - 6) + 5) openclaw_permission_run_audit break_end ;; @@ -21450,6 +21465,9 @@ else linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info diff --git a/kejilion.sh b/kejilion.sh index 92f308bb0..418e26e0c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10036,6 +10036,7 @@ moltbot_menu() { echo "=======================================" echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" + echo -e "💡 终端执行 \033[1;33mk claw\033[0m 快速进入菜单" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安装" @@ -14010,24 +14011,43 @@ PY } openclaw_permission_detect_mode() { - local profile security ask elevated bash_enabled apply_patch workspace_only - profile=$(openclaw_permission_get_value "tools.profile") - security=$(openclaw_permission_get_value "tools.exec.security") - ask=$(openclaw_permission_get_value "tools.exec.ask") - elevated=$(openclaw_permission_get_value "tools.elevated.enabled") - bash_enabled=$(openclaw_permission_get_value "commands.bash") - apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") - workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") - - if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then - echo "标准安全模式" - elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then - echo "开发增强模式" - elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then - echo "完全开放模式" - else - echo "自定义模式" - fi + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "未知模式"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("标准安全模式") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("开发增强模式") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("完全开放模式") + else: + print("自定义模式") +except Exception: + print("自定义模式") +PY } openclaw_permission_render_status() { @@ -14195,45 +14215,40 @@ PY echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 查看当前权限状态" - echo "2. 切换为标准安全模式(推荐)" - echo "3. 切换为开发增强模式" - echo "4. 切换为完全开放模式(高风险)" - echo "5. 恢复官方默认策略" - echo "6. 运行安全审计" + echo "1. 切换为标准安全模式(推荐)" + echo "2. 切换为开发增强模式" + echo "3. 切换为完全开放模式(高风险)" + echo "4. 恢复官方默认策略" + echo "5. 运行安全审计" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice case "$perm_choice" in 1) - openclaw_permission_render_status - break_end - ;; - 2) echo "将应用:标准安全模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" break_end ;; - 3) + 2) echo "将应用:开发增强模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" break_end ;; - 4) + 3) echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" read -e -p "输入 FULL 确认继续: " confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" break_end ;; - 5) + 4) echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" break_end ;; - 6) + 5) openclaw_permission_run_audit break_end ;; @@ -21454,6 +21469,9 @@ else linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info From 49bc5727cc5428d23e692fa221875d8df558924b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 23:49:16 +0800 Subject: [PATCH 1088/1285] chore: install git jq gum before openclaw setup --- cn/kejilion.sh | 1 + kejilion.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8556b4e67..541d00547 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10477,6 +10477,7 @@ PY install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." + install git jq gum install_node_and_tools diff --git a/kejilion.sh b/kejilion.sh index 418e26e0c..465c626d1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10477,6 +10477,7 @@ PY install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." + install git jq gum install_node_and_tools From 9f829dfd17377e795db03f77fbb066328c316497 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 20 Mar 2026 23:51:52 +0800 Subject: [PATCH 1089/1285] chore: drop gum from openclaw setup dependencies --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 541d00547..dfd61d385 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10477,7 +10477,7 @@ PY install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." - install git jq gum + install git jq install_node_and_tools diff --git a/kejilion.sh b/kejilion.sh index 465c626d1..fcabf632a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10477,7 +10477,7 @@ PY install_moltbot() { echo "开始安装 OpenClaw..." send_stats "开始安装 OpenClaw..." - install git jq gum + install git jq install_node_and_tools From 751c6b168bd086cc6d8f7d3dc1278cb4fd1ee9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Mar 2026 12:36:37 +0800 Subject: [PATCH 1090/1285] Change installation check from file to command --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dfd61d385..3a86fb717 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11456,7 +11456,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - if [ -f /etc/debian_version ]; then + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null From 782cd2aad043be357ff541efab5d275b0d0afe49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Mar 2026 12:37:45 +0800 Subject: [PATCH 1091/1285] Check for 'apt' command in install_gum function Add check for 'apt' command before installing gum on Debian. --- kejilion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index fcabf632a..ee83af67f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11456,7 +11456,8 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - if [ -f /etc/debian_version ]; then + + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null From a754c5a150640b32600bdaaf6de4f647efbacc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Mar 2026 15:01:53 +0800 Subject: [PATCH 1092/1285] Remove redundant install_gum calls --- cn/kejilion.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3a86fb717..846264aa2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11719,7 +11719,8 @@ PYTHON_EOF [ -z "$default_model" ] && default_model="(unknown)" clear - + install_gum + install gum # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -11750,8 +11751,6 @@ PYTHON_EOF break_end return 0 else - install_gum - install gum if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "gum 不可用,返回旧版输入模式。" sleep 1 From f3fe75dd9045c6aea38f01d9934a8476ec052f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 21 Mar 2026 15:02:42 +0800 Subject: [PATCH 1093/1285] Remove redundant gum installation commands --- kejilion.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ee83af67f..fb598130d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11721,6 +11721,9 @@ PYTHON_EOF clear + install_gum + install gum + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -11751,8 +11754,6 @@ PYTHON_EOF break_end return 0 else - install_gum - install gum if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "gum 不可用,返回旧版输入模式。" sleep 1 From 238d5bc0146532266fb76a93ab6eec4a82a8769b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 22 Mar 2026 12:14:37 +0800 Subject: [PATCH 1094/1285] fix: update ecs.sh source to GitHub --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 846264aa2..f1360d645 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8735,7 +8735,7 @@ linux_test() { 32) send_stats "spiritysdx融合怪测评" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) diff --git a/kejilion.sh b/kejilion.sh index fb598130d..dca28ff8f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8735,7 +8735,7 @@ linux_test() { 32) send_stats "spiritysdx融合怪测评" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) From 7e19b67cec11f2f83d76fac0097a2dfb90d390dd Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 11:33:06 +0800 Subject: [PATCH 1095/1285] feat(openclaw): detect weixin integration status --- cn/kejilion.sh | 20 ++++++++++++++++++++ kejilion.sh | 20 ++++++++++++++++++++ kr/kejilion.sh | 20 ++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f1360d645..7a3fc0f30 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12408,6 +12408,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "本地状态(仅本机配置/缓存,不做网络探测):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" @@ -12415,6 +12434,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "微信 (Weixin)" "$wx_status" } change_tg_bot_code() { diff --git a/kejilion.sh b/kejilion.sh index dca28ff8f..ccc11d1e5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12411,6 +12411,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "本地状态(仅本机配置/缓存,不做网络探测):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" @@ -12418,6 +12437,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "微信 (Weixin)" "$wx_status" } change_tg_bot_code() { diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 522576d93..f86f57d6e 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12408,6 +12408,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "本地状态(仅本机配置/缓存,不做网络探测):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" @@ -12415,6 +12434,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "微信 (Weixin)" "$wx_status" } change_tg_bot_code() { From b83aa78f792d9fde7308d5f6130617cc54e76fc7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 11:40:52 +0800 Subject: [PATCH 1096/1285] feat(openclaw): add weixin install menu option --- cn/kejilion.sh | 5 +++++ kejilion.sh | 5 +++++ kr/kejilion.sh | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7a3fc0f30..6a6c55e8a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12449,6 +12449,7 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" + echo "4. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12476,6 +12477,10 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; diff --git a/kejilion.sh b/kejilion.sh index ccc11d1e5..d69e84dbe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12452,6 +12452,7 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" + echo "4. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12479,6 +12480,10 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index f86f57d6e..886f6fa8c 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12449,6 +12449,7 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" + echo "4. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12476,6 +12477,10 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; From b7b8149c4b7ac25b4068224f1ea1f7cdae62c6c7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 11:49:20 +0800 Subject: [PATCH 1097/1285] feat(openclaw): add qq menu entry above weixin --- cn/kejilion.sh | 8 +++++++- kejilion.sh | 8 +++++++- kr/kejilion.sh | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6a6c55e8a..16b3bac60 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12449,7 +12449,8 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" - echo "4. 微信机器人对接" + echo "4. QQ 机器人对接" + echo "5. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12478,6 +12479,11 @@ openclaw_json_get_bool() { break_end ;; 4) + echo "QQ 官方对接地址:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) npx -y @tencent-weixin/openclaw-weixin-cli@latest install break_end ;; diff --git a/kejilion.sh b/kejilion.sh index d69e84dbe..1b40bf8e7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12452,7 +12452,8 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" - echo "4. 微信机器人对接" + echo "4. QQ 机器人对接" + echo "5. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12481,6 +12482,11 @@ openclaw_json_get_bool() { break_end ;; 4) + echo "QQ 官方对接地址:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) npx -y @tencent-weixin/openclaw-weixin-cli@latest install break_end ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 886f6fa8c..74fc149ae 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12449,7 +12449,8 @@ openclaw_json_get_bool() { echo "1. Telegram 机器人对接" echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" - echo "4. 微信机器人对接" + echo "4. QQ 机器人对接" + echo "5. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一级选单" echo "----------------------------------------" @@ -12478,6 +12479,11 @@ openclaw_json_get_bool() { break_end ;; 4) + echo "QQ 官方对接地址:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) npx -y @tencent-weixin/openclaw-weixin-cli@latest install break_end ;; From 32e7753befa2f775f115d69544e6ca6b46657cb9 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 12:27:01 +0800 Subject: [PATCH 1098/1285] feat(openclaw): use official lark integration flow --- cn/kejilion.sh | 8 ++++---- kejilion.sh | 8 ++++---- kr/kejilion.sh | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 16b3bac60..ae04c8718 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12465,10 +12465,10 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json + sh /workspace/projects/scripts/restart.sh break_end ;; 3) diff --git a/kejilion.sh b/kejilion.sh index 1b40bf8e7..d1ed6ab01 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12468,10 +12468,10 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json + sh /workspace/projects/scripts/restart.sh break_end ;; 3) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 74fc149ae..cabc60f53 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12465,10 +12465,10 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "请输入飞书机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json + sh /workspace/projects/scripts/restart.sh break_end ;; 3) From 8f618e2cc1c70d120ba03ceb9e211dde948811f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:29:50 +0800 Subject: [PATCH 1099/1285] Update shell version from 4.4.8 to 4.4.9 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ae04c8718..09b0bbdde 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.8" +sh_v="4.4.9" gl_hui='\e[37m' From 60d01c0c8a25e21ba5ca52aee88cdcde72396e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:30:39 +0800 Subject: [PATCH 1100/1285] Update shell version from 4.4.8 to 4.4.9 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index d1ed6ab01..15c764efb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.8" +sh_v="4.4.9" gl_hui='\e[37m' From 0f03d3955ea2d854661c70a2dea50f0b0dcd2bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:33:55 +0800 Subject: [PATCH 1101/1285] Update kejilion_sh_log.txt with new features and optimizations --- kejilion_sh_log.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 58e4f0e86..c347233d3 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1498,4 +1498,10 @@ OpenClaw模型探测逻辑优化,优先测试 /v1/responses,不通时再回 OpenClaw模型管理优化gum异常时的兼容性,自动回退旧版输入流程。 OpenClaw API同步一致性输出增强,汇总显示顺序调整为新增、删除、当前。 OpenClaw模型管理交互细节优化,提升确认流程稳定性与可用性。 +------------------------ +2026-03-23 v4.4.9 +OpenClaw菜单新增 k claw 快捷入口。 +OpenClaw菜单新增权限管理,多智能体管理。 +OpenClaw菜单对接机器人管理 新增微信官方接入与状态显示。 +OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入方式。 From f4ba9491bee0769286aa93c3a4f6c0d2f09ed82e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 12:39:42 +0800 Subject: [PATCH 1102/1285] fix(openclaw): remove invalid lark restart script --- cn/kejilion.sh | 1 - kejilion.sh | 1 - kr/kejilion.sh | 1 - 3 files changed, 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 09b0bbdde..222cc9b7c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12468,7 +12468,6 @@ openclaw_json_get_bool() { npx -y @larksuite/openclaw-lark install openclaw config set channels.feishu.streaming true openclaw config set channels.feishu.requireMention true --json - sh /workspace/projects/scripts/restart.sh break_end ;; 3) diff --git a/kejilion.sh b/kejilion.sh index 15c764efb..ce15313f8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12471,7 +12471,6 @@ openclaw_json_get_bool() { npx -y @larksuite/openclaw-lark install openclaw config set channels.feishu.streaming true openclaw config set channels.feishu.requireMention true --json - sh /workspace/projects/scripts/restart.sh break_end ;; 3) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index cabc60f53..675849833 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12468,7 +12468,6 @@ openclaw_json_get_bool() { npx -y @larksuite/openclaw-lark install openclaw config set channels.feishu.streaming true openclaw config set channels.feishu.requireMention true --json - sh /workspace/projects/scripts/restart.sh break_end ;; 3) From 32d8dc0f67b87d6f5dda50ae46e3286950b17878 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 12:55:31 +0800 Subject: [PATCH 1103/1285] fix(openclaw): compat lark feishu status detection --- cn/kejilion.sh | 12 +++++++++--- kejilion.sh | 12 +++++++++--- kr/kejilion.sh | 12 +++++++++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 222cc9b7c..eb3b2313e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -12332,19 +12332,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status diff --git a/kejilion.sh b/kejilion.sh index ce15313f8..529ab8706 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12335,19 +12335,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 675849833..6d82b191a 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -12332,19 +12332,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status From 3ecafd8feb34acb5b239225a7e8c0bab86835015 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 13:46:39 +0800 Subject: [PATCH 1104/1285] fix(openclaw): prefer user paths over root in module --- cn/kejilion.sh | 12 +++++++----- kejilion.sh | 8 +++++--- kr/kejilion.sh | 12 +++++++----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index eb3b2313e..41137f950 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11171,7 +11171,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 # 保留函数以兼容菜单调用,但不做任何改写。 - echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" return 0 } @@ -12063,7 +12063,8 @@ PYTHON_EOF fi echo "📥 本地未发现,尝试下载安装: $plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ 下载成功,正在启用..." if openclaw plugins enable "$plugin_id"; then @@ -14709,7 +14710,8 @@ openclaw_backup_restore_menu() { openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" @@ -20900,7 +20902,7 @@ while true; do 4) clear send_stats "备份集群" - echo -e "请将 ${gl_huang}/root/cluster/servers.py${gl_bai} 文件下载,完成备份!" + echo -e "请将 ${gl_huang}${HOME}/cluster/servers.py${gl_bai} 文件下载,完成备份!" break_end ;; @@ -20908,7 +20910,7 @@ while true; do clear send_stats "还原集群" echo "请上传您的servers.py,按任意键开始上传!" - echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}/root/cluster/${gl_bai} 完成还原!" + echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}${HOME}/cluster/${gl_bai} 完成还原!" break_end ;; diff --git a/kejilion.sh b/kejilion.sh index 529ab8706..baf2699fe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11171,7 +11171,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 # 保留函数以兼容菜单调用,但不做任何改写。 - echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" return 0 } @@ -12066,7 +12066,8 @@ PYTHON_EOF fi echo "📥 本地未发现,尝试下载安装: $plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ 下载成功,正在启用..." if openclaw plugins enable "$plugin_id"; then @@ -14716,7 +14717,8 @@ openclaw_backup_restore_menu() { openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 6d82b191a..6fe676987 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -11170,7 +11170,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 # 保留函数以兼容菜单调用,但不做任何改写。 - echo "ℹ️ 已关闭协议探测:请手动在 ~/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" return 0 } @@ -12063,7 +12063,8 @@ PYTHON_EOF fi echo "📥 本地未发现,尝试下载安装: $plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ 下载成功,正在启用..." if openclaw plugins enable "$plugin_id"; then @@ -14601,7 +14602,8 @@ openclaw_backup_restore_menu() { openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸载完成" @@ -20792,7 +20794,7 @@ while true; do 4) clear send_stats "备份集群" - echo -e "请将 ${gl_huang}/root/cluster/servers.py${gl_bai} 文件下载,完成备份!" + echo -e "请将 ${gl_huang}${HOME}/cluster/servers.py${gl_bai} 文件下载,完成备份!" break_end ;; @@ -20800,7 +20802,7 @@ while true; do clear send_stats "还原集群" echo "请上传您的servers.py,按任意键开始上传!" - echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}/root/cluster/${gl_bai} 完成还原!" + echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}${HOME}/cluster/${gl_bai} 完成还原!" break_end ;; From 62e5014ed2d1efb8fc3c508608832f3c2b90e349 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 14:00:35 +0800 Subject: [PATCH 1105/1285] fix(openclaw): keep config path in user home for non-root --- cn/kejilion.sh | 94 ++++++++++++------- kejilion.sh | 79 ++++++++++------ ...s_openclaw_config_path_resolution_smoke.sh | 77 +++++++++++++++ 3 files changed, 184 insertions(+), 66 deletions(-) create mode 100755 tests/tests_openclaw_config_path_resolution_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 41137f950..3002cbac1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10091,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10122,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10593,7 +10595,8 @@ EOF local base_url="$2" local api_key="$3" local models_array="$4" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) # 不再自动探测/纠正 API 协议;保持用户配置为准 DETECTED_API="openai-completions" @@ -11261,7 +11264,8 @@ PY } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then @@ -11456,7 +11460,8 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - if command -v apt >/dev/null 2>&1; then + + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null @@ -11512,8 +11517,7 @@ REPO local first_exit first_http first_latency second_exit second_http second_latency local first_reply second_reply - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) [ ! -f "$oc_config" ] && { OPENCLAW_PROBE_STATUS="ERROR" OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" @@ -11700,8 +11704,7 @@ PYTHON_EOF # 从配置文件读取模型键(不调用 openclaw models list) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then @@ -11719,8 +11722,10 @@ PYTHON_EOF [ -z "$default_model" ] && default_model="(unknown)" clear + install_gum install gum + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -11820,6 +11825,18 @@ PYTHON_EOF } + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + resolve_openclaw_plugin_id() { local raw_input="$1" local plugin_id="$raw_input" @@ -11836,12 +11853,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11907,12 +11920,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -12226,7 +12235,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12236,7 +12246,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12263,7 +12274,8 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi @@ -12313,7 +12325,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12636,7 +12649,8 @@ EOF } openclaw_get_all_agent_workspaces() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then python3 - "$config_file" <<'PY' import json, sys, os @@ -12713,7 +12727,10 @@ if os.path.isdir(agents_root): openclaw_project_backup_export() { send_stats "OpenClaw项目备份" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" break_end @@ -12772,7 +12789,10 @@ if os.path.isdir(agents_root): openclaw_project_backup_import() { send_stats "OpenClaw项目还原" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" @@ -13010,7 +13030,7 @@ if os.path.isdir(agents_root): } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + echo "$(openclaw_get_config_file)" } openclaw_memory_config_get() { @@ -13906,7 +13926,7 @@ if os.path.isdir(agents_root): } openclaw_permission_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + echo "$(openclaw_get_config_file)" } openclaw_permission_backup_file() { @@ -14095,6 +14115,8 @@ PY [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" echo "当前模式: $mode" echo "---------------------------------------" + + # 使用 Python 一次性高效解析所有权限字段 python3 - "$config_file" <<'PY' import json, sys def get_val(obj, path, default="(unset)"): @@ -14104,6 +14126,7 @@ def get_val(obj, path, default="(unset)"): else: return default if isinstance(obj, (list, dict)): return json.dumps(obj) return str(obj) + try: with open(sys.argv[1], 'r') as f: data = json.load(f) fields = [ @@ -14121,7 +14144,8 @@ try: for label, path in fields: val = get_val(data, path) print("%-28s %s" % (label, val)) -except: print("❌ 配置文件解析失败") +except Exception as e: + print("❌ 配置文件解析失败: %s" % e) PY } @@ -14721,7 +14745,7 @@ openclaw_backup_restore_menu() { nano_openclaw_json() { send_stats "编辑 OpenClaw 配置文件" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -14796,7 +14820,7 @@ openclaw_backup_restore_menu() { read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" # 自动添加域名到 allowedOrigins - config_file="$HOME/.openclaw/openclaw.json" + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 @@ -20902,7 +20926,7 @@ while true; do 4) clear send_stats "备份集群" - echo -e "请将 ${gl_huang}${HOME}/cluster/servers.py${gl_bai} 文件下载,完成备份!" + echo -e "请将 ${gl_huang}/root/cluster/servers.py${gl_bai} 文件下载,完成备份!" break_end ;; @@ -20910,7 +20934,7 @@ while true; do clear send_stats "还原集群" echo "请上传您的servers.py,按任意键开始上传!" - echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}${HOME}/cluster/${gl_bai} 完成还原!" + echo -e "请上传您的 ${gl_huang}servers.py${gl_bai} 文件到 ${gl_huang}/root/cluster/${gl_bai} 完成还原!" break_end ;; diff --git a/kejilion.sh b/kejilion.sh index baf2699fe..3002cbac1 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10091,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10122,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10593,7 +10595,8 @@ EOF local base_url="$2" local api_key="$3" local models_array="$4" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) # 不再自动探测/纠正 API 协议;保持用户配置为准 DETECTED_API="openai-completions" @@ -11261,7 +11264,8 @@ PY } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then @@ -11513,8 +11517,7 @@ REPO local first_exit first_http first_latency second_exit second_http second_latency local first_reply second_reply - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) [ ! -f "$oc_config" ] && { OPENCLAW_PROBE_STATUS="ERROR" OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" @@ -11701,8 +11704,7 @@ PYTHON_EOF # 从配置文件读取模型键(不调用 openclaw models list) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then @@ -11823,6 +11825,18 @@ PYTHON_EOF } + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + resolve_openclaw_plugin_id() { local raw_input="$1" local plugin_id="$raw_input" @@ -11839,12 +11853,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11910,12 +11920,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -12229,7 +12235,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12239,7 +12246,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12266,7 +12274,8 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi @@ -12316,7 +12325,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12639,7 +12649,8 @@ EOF } openclaw_get_all_agent_workspaces() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then python3 - "$config_file" <<'PY' import json, sys, os @@ -12716,7 +12727,10 @@ if os.path.isdir(agents_root): openclaw_project_backup_export() { send_stats "OpenClaw项目备份" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" break_end @@ -12775,7 +12789,10 @@ if os.path.isdir(agents_root): openclaw_project_backup_import() { send_stats "OpenClaw项目还原" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" @@ -13013,7 +13030,7 @@ if os.path.isdir(agents_root): } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + echo "$(openclaw_get_config_file)" } openclaw_memory_config_get() { @@ -13909,7 +13926,7 @@ if os.path.isdir(agents_root): } openclaw_permission_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + echo "$(openclaw_get_config_file)" } openclaw_permission_backup_file() { @@ -14728,7 +14745,7 @@ openclaw_backup_restore_menu() { nano_openclaw_json() { send_stats "编辑 OpenClaw 配置文件" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -14803,7 +14820,7 @@ openclaw_backup_restore_menu() { read echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" # 自动添加域名到 allowedOrigins - config_file="$HOME/.openclaw/openclaw.json" + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 diff --git a/tests/tests_openclaw_config_path_resolution_smoke.sh b/tests/tests_openclaw_config_path_resolution_smoke.sh new file mode 100755 index 000000000..eeb671014 --- /dev/null +++ b/tests/tests_openclaw_config_path_resolution_smoke.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root=$(cd "$(dirname "$0")/.." && pwd) +script="$repo_root/kejilion.sh" + +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT +export HOME="$workdir/home" +mkdir -p "$HOME/.openclaw" + +python_extract() { +python3 - "$script" <<'PY' +import re, sys +text = open(sys.argv[1], encoding='utf-8').read() +patterns = [ + r'openclaw_get_config_file\(\) \{.*?\n\t\t\}', + r'openclaw_memory_config_file\(\) \{.*?\n\t\}', + r'openclaw_permission_config_file\(\) \{.*?\n\t\}', +] +for pat in patterns: + m = re.search(pat, text, re.S) + if not m: + raise SystemExit(f'missing pattern: {pat}') + print(m.group(0)) + print() +PY +} + +snippet="$workdir/snippet.sh" +{ + echo '#!/usr/bin/env bash' + echo 'set -euo pipefail' + python_extract + cat <<'SH' +main() { + echo "CFG=$(openclaw_get_config_file)" + echo "MEM=$(openclaw_memory_config_file)" + echo "PERM=$(openclaw_permission_config_file)" +} +main "$@" +SH +} > "$snippet" +chmod +x "$snippet" + +assert_eq() { + local got="$1" expected="$2" msg="$3" + if [ "$got" != "$expected" ]; then + echo "ASSERT FAIL: $msg" + echo "got: $got" + echo "exp: $expected" + exit 1 + fi +} + +user_cfg="$HOME/.openclaw/openclaw.json" +root_cfg="$workdir/root/.openclaw/openclaw.json" +mkdir -p "$(dirname "$root_cfg")" + +out=$("$snippet") +assert_eq "$(printf '%s\n' "$out" | sed -n '1p')" "CFG=$user_cfg" 'default config path should be user path' +assert_eq "$(printf '%s\n' "$out" | sed -n '2p')" "MEM=$user_cfg" 'memory config path should follow helper' +assert_eq "$(printf '%s\n' "$out" | sed -n '3p')" "PERM=$user_cfg" 'permission config path should follow helper' + +printf '{}\n' > "$root_cfg" +rm -f "$user_cfg" +out=$("$snippet") +assert_eq "$(printf '%s\n' "$out" | sed -n '1p')" "CFG=$user_cfg" 'non-root should not silently fallback to root config' +assert_eq "$(printf '%s\n' "$out" | sed -n '2p')" "MEM=$user_cfg" 'memory config should stay in user path for non-root' +assert_eq "$(printf '%s\n' "$out" | sed -n '3p')" "PERM=$user_cfg" 'permission config should stay in user path for non-root' + +mkdir -p "$(dirname "$user_cfg")" +printf '{"user":true}\n' > "$user_cfg" +out=$("$snippet") +assert_eq "$(printf '%s\n' "$out" | sed -n '1p')" "CFG=$user_cfg" 'user config should take precedence' + +echo 'PASS: openclaw config path resolution smoke' From d6301faf2c9c99c7b5b428b7f8e20a44fb707681 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 14:30:11 +0800 Subject: [PATCH 1106/1285] feat(openclaw): support multi-agent memory management --- cn/kejilion.sh | 170 ++++++++++++++---- kejilion.sh | 170 ++++++++++++++---- .../tests_openclaw_memory_auto_setup_smoke.sh | 19 +- .../tests_openclaw_memory_menu_smoke.sh | 15 +- ...tests_openclaw_memory_multi_agent_smoke.sh | 150 ++++++++++++++++ 5 files changed, 438 insertions(+), 86 deletions(-) create mode 100644 tests/openclaw/tests_openclaw_memory_multi_agent_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3002cbac1..a2d8d2672 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13030,7 +13030,15 @@ if os.path.isdir(agents_root): } openclaw_memory_config_file() { - echo "$(openclaw_get_config_file)" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -13060,9 +13068,46 @@ if os.path.isdir(agents_root): openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -13079,58 +13124,96 @@ if os.path.isdir(agents_root): fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ 未找到索引库文件,可能为空或不存在。" + echo "⚠️ [$agent_id] 未找到索引库文件,可能为空或不存在。" echo " Store 原始值: ${store_raw:-<空>}" echo " 仍将执行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ 已备份索引: $backup_file" + echo "✅ [$agent_id] 已备份索引: $backup_file" else - echo "⚠️ 索引备份失败,继续重建。" + echo "⚠️ [$agent_id] 索引备份失败,继续重建。" fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" openclaw gateway restart echo "✅ 索引已重建并自动重启网关" echo "" openclaw_memory_render_status } + openclaw_memory_rebuild_index_all() { + local count=0 + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done < <(openclaw_memory_list_agents) + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" + echo "✅ 已为 ${count} 个智能体重建索引" + echo "" + openclaw_memory_render_status + } + openclaw_memory_prepare_workspace() { + local agent_id="${1:-main}" local workspace memory_dir - workspace=$(openclaw_memory_status_value "Workspace") + workspace=$(openclaw_memory_status_value "Workspace" "$agent_id") if [ -z "$workspace" ]; then - echo "⚠️ 未能获取 Workspace 路径,跳过目录修复。" - return 1 + workspace="$HOME/.openclaw/workspace" + [ "$agent_id" != "main" ] && workspace="$HOME/.openclaw/workspace-$agent_id" fi memory_dir="$workspace/memory" if [ ! -d "$memory_dir" ]; then - echo "🔧 记忆目录不存在,已自动创建: $memory_dir" + echo "🔧 [$agent_id] 记忆目录不存在,已自动创建: $memory_dir" mkdir -p "$memory_dir" fi return 0 } + openclaw_memory_prepare_workspace_all() { + local count=0 + echo "检查并准备 $(openclaw_memory_list_agents | sed '/^\s*$/d' | wc -l | tr -d ' ') 个智能体工作区" + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_prepare_workspace "$agent_id" + count=$((count+1)) + done < <(openclaw_memory_list_agents) + return 0 + } + openclaw_memory_render_status() { - local status_output status_lines config_file config_display - status_output=$(openclaw memory status 2>/dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') + local agent_id workspace status_output status_lines first="true" + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /' -e 's/^Workspace: /工作区: /' -e 's/^Store: /索引库: /') if [ -z "$status_lines" ]; then echo "未安装/未启动" else echo "$status_lines" fi - fi + done < <(openclaw_memory_list_agents) } openclaw_memory_get_backend() { @@ -13477,8 +13560,8 @@ if os.path.isdir(agents_root): fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 预热索引(可能下载模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + openclaw memory index --agent main --force else echo "⏭️ 已跳过预热" fi @@ -13534,8 +13617,8 @@ if os.path.isdir(agents_root): fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 预热索引(可能下载模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + openclaw memory index --agent main --force else echo "⏭️ 已跳过预热" fi @@ -13754,30 +13837,39 @@ if os.path.isdir(agents_root): openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_id base_dir memory_dir memory_file rel + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done < <(openclaw_memory_list_agents) } openclaw_memory_file_render_list() { - local base_dir="${HOME}/.openclaw/workspace" openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then echo "未找到记忆文件。" return 0 fi - echo "编号 | 相对路径 | 大小 | 修改时间" + echo "编号 | 归属 | 大小 | 修改时间" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do file="${OPENCLAW_MEMORY_FILES[$i]}" - rel="${file#$base_dir/}" + rel="${OPENCLAW_MEMORY_FILE_LABELS[$i]}" size=$(ls -lh "$file" | awk '{print $5}') mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13887,18 +13979,18 @@ if os.path.isdir(agents_root): break_end continue fi - openclaw_memory_prepare_workspace + openclaw_memory_prepare_workspace_all read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 全量重建更彻底,但耗时更长。" echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + openclaw memory index --agent main --force openclaw gateway restart - echo "✅ 索引已重建并自动重启网关" + echo "✅ 已对主智能体执行 force 重建并自动重启网关" fi else openclaw memory index diff --git a/kejilion.sh b/kejilion.sh index 3002cbac1..a2d8d2672 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13030,7 +13030,15 @@ if os.path.isdir(agents_root): } openclaw_memory_config_file() { - echo "$(openclaw_get_config_file)" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -13060,9 +13068,46 @@ if os.path.isdir(agents_root): openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -13079,58 +13124,96 @@ if os.path.isdir(agents_root): fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ 未找到索引库文件,可能为空或不存在。" + echo "⚠️ [$agent_id] 未找到索引库文件,可能为空或不存在。" echo " Store 原始值: ${store_raw:-<空>}" echo " 仍将执行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ 已备份索引: $backup_file" + echo "✅ [$agent_id] 已备份索引: $backup_file" else - echo "⚠️ 索引备份失败,继续重建。" + echo "⚠️ [$agent_id] 索引备份失败,继续重建。" fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" openclaw gateway restart echo "✅ 索引已重建并自动重启网关" echo "" openclaw_memory_render_status } + openclaw_memory_rebuild_index_all() { + local count=0 + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done < <(openclaw_memory_list_agents) + openclaw gateway restart + echo "✅ 索引已重建并自动重启网关" + echo "✅ 已为 ${count} 个智能体重建索引" + echo "" + openclaw_memory_render_status + } + openclaw_memory_prepare_workspace() { + local agent_id="${1:-main}" local workspace memory_dir - workspace=$(openclaw_memory_status_value "Workspace") + workspace=$(openclaw_memory_status_value "Workspace" "$agent_id") if [ -z "$workspace" ]; then - echo "⚠️ 未能获取 Workspace 路径,跳过目录修复。" - return 1 + workspace="$HOME/.openclaw/workspace" + [ "$agent_id" != "main" ] && workspace="$HOME/.openclaw/workspace-$agent_id" fi memory_dir="$workspace/memory" if [ ! -d "$memory_dir" ]; then - echo "🔧 记忆目录不存在,已自动创建: $memory_dir" + echo "🔧 [$agent_id] 记忆目录不存在,已自动创建: $memory_dir" mkdir -p "$memory_dir" fi return 0 } + openclaw_memory_prepare_workspace_all() { + local count=0 + echo "检查并准备 $(openclaw_memory_list_agents | sed '/^\s*$/d' | wc -l | tr -d ' ') 个智能体工作区" + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_prepare_workspace "$agent_id" + count=$((count+1)) + done < <(openclaw_memory_list_agents) + return 0 + } + openclaw_memory_render_status() { - local status_output status_lines config_file config_display - status_output=$(openclaw memory status 2>/dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') + local agent_id workspace status_output status_lines first="true" + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "获取状态失败" + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /' -e 's/^Workspace: /工作区: /' -e 's/^Store: /索引库: /') if [ -z "$status_lines" ]; then echo "未安装/未启动" else echo "$status_lines" fi - fi + done < <(openclaw_memory_list_agents) } openclaw_memory_get_backend() { @@ -13477,8 +13560,8 @@ if os.path.isdir(agents_root): fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 预热索引(可能下载模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + openclaw memory index --agent main --force else echo "⏭️ 已跳过预热" fi @@ -13534,8 +13617,8 @@ if os.path.isdir(agents_root): fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 预热索引(可能下载模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + openclaw memory index --agent main --force else echo "⏭️ 已跳过预热" fi @@ -13754,30 +13837,39 @@ if os.path.isdir(agents_root): openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_id base_dir memory_dir memory_file rel + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done < <(openclaw_memory_list_agents) } openclaw_memory_file_render_list() { - local base_dir="${HOME}/.openclaw/workspace" openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then echo "未找到记忆文件。" return 0 fi - echo "编号 | 相对路径 | 大小 | 修改时间" + echo "编号 | 归属 | 大小 | 修改时间" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do file="${OPENCLAW_MEMORY_FILES[$i]}" - rel="${file#$base_dir/}" + rel="${OPENCLAW_MEMORY_FILE_LABELS[$i]}" size=$(ls -lh "$file" | awk '{print $5}') mtime=$(date -d "$(stat -c %y "$file")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13887,18 +13979,18 @@ if os.path.isdir(agents_root): break_end continue fi - openclaw_memory_prepare_workspace + openclaw_memory_prepare_workspace_all read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 全量重建更彻底,但耗时更长。" echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + openclaw memory index --agent main --force openclaw gateway restart - echo "✅ 索引已重建并自动重启网关" + echo "✅ 已对主智能体执行 force 重建并自动重启网关" fi else openclaw memory index diff --git a/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh index 2b1d3d2cc..f4036af28 100644 --- a/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_auto_setup_smoke.sh @@ -45,7 +45,16 @@ if [[ "$cmd" == "config set"* ]]; then echo "$val" > "$file" exit 0 fi -if [[ "$cmd" == "memory status" ]]; then +if [[ "$1" == "memory" && "$2" == "status" ]]; then + agent="main" + while [ $# -gt 0 ]; do + if [ "$1" = "--agent" ] && [ $# -ge 2 ]; then + agent="$2" + shift 2 + continue + fi + shift + done cat <> "${HOME}/.openclaw/index_calls" echo "index ok" exit 0 @@ -163,13 +172,13 @@ run_auto() { HOME_QMD=$(make_home "qmd") export HOME="$HOME_QMD" FAKE_COUNTRY=US FAKE_HF_OK=0 FAKE_MIRROR_OK=1 \ - run_auto "yes-preheat\n" "qmd" "$WORKDIR/out_qmd.txt" + run_auto "yes\n" "qmd" "$WORKDIR/out_qmd.txt" # Case 2: local 模型不存在 -> 下载 -> 写入 modelPath -> index (CN) HOME_LOCAL=$(make_home "local") export HOME="$HOME_LOCAL" FAKE_COUNTRY=CN FAKE_HF_OK=1 FAKE_MIRROR_OK=0 \ - run_auto "yes-preheat\n" "local" "$WORKDIR/out_local.txt" + run_auto "yes\n" "local" "$WORKDIR/out_local.txt" # Case 3: 已存在 -> 跳过下载/安装 HOME_SKIP=$(make_home "skip") @@ -208,7 +217,7 @@ qmd_cmd = (home_qmd / '.openclaw/config/memory_qmd_command').read_text().strip() if not qmd_cmd.startswith('/'): raise SystemExit('qmd command not absolute') index_calls = (home_qmd / '.openclaw/index_calls').read_text() -if 'memory index --force' not in index_calls: +if 'memory index' not in index_calls or '--force' not in index_calls: raise SystemExit('qmd preheat index not called') # Case2: local model downloaded + modelPath written diff --git a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh index 3a555d93c..b0c2bba4f 100755 --- a/tests/openclaw/tests_openclaw_memory_menu_smoke.sh +++ b/tests/openclaw/tests_openclaw_memory_menu_smoke.sh @@ -53,7 +53,16 @@ if [[ "$cmd" == "config set"* ]]; then fi exit 0 fi -if [[ "$cmd" == "memory status" ]]; then +if [[ "$1" == "memory" && "$2" == "status" ]]; then + agent="main" + while [ $# -gt 0 ]; do + if [ "$1" = "--agent" ] && [ $# -ge 2 ]; then + agent="$2" + shift 2 + continue + fi + shift + done cat <> "${HOME}/.openclaw/index_calls" echo "index ok" exit 0 @@ -193,7 +202,7 @@ if not os.path.exists(calls_path): raise SystemExit('index calls not recorded') with open(calls_path, 'r', encoding='utf-8') as fh: calls = fh.read() -if 'memory index --force' not in calls: +if 'memory index' not in calls or '--force' not in calls: raise SystemExit('force index not called for missing store') # ensure gateway restart called after rebuild gw_calls_path = os.path.expanduser('~/.openclaw/gateway_calls') diff --git a/tests/openclaw/tests_openclaw_memory_multi_agent_smoke.sh b/tests/openclaw/tests_openclaw_memory_multi_agent_smoke.sh new file mode 100644 index 000000000..3ce983b2a --- /dev/null +++ b/tests/openclaw/tests_openclaw_memory_multi_agent_smoke.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SCRIPT="$REPO_ROOT/kejilion.sh" +WORKDIR="${TMPDIR:-/tmp}/openclaw-memory-multi-agent-test-$$" +mkdir -p "$WORKDIR/bin" "$WORKDIR/home/.openclaw/workspace/memory" +KEEP_WORKDIR=${KEEP_WORKDIR:-false} +trap '[ "$KEEP_WORKDIR" = "true" ] || rm -rf "$WORKDIR"' EXIT + +cat > "$WORKDIR/harness.sh" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +break_end() { return 0; } +send_stats() { return 0; } +EOF_INNER + +awk 'BEGIN{p=0} /openclaw_memory_config_file\(\) \{/{p=1} /openclaw_permission_config_file\(\) \{/{p=0} p{print}' "$SCRIPT" >> "$WORKDIR/harness.sh" +chmod +x "$WORKDIR/harness.sh" + +cat > "$WORKDIR/bin/openclaw" <<'EOF_INNER' +#!/usr/bin/env bash +set -euo pipefail +cmd="$*" +if [[ "$cmd" == "agents list --json" ]]; then + cat <<'JSON' +[ + {"id":"main","workspace":"~/.openclaw/workspace"}, + {"id":"work","workspace":"~/.openclaw/workspace-work"} +] +JSON + exit 0 +fi +if [[ "$cmd" == "config get"* ]]; then + key="$3" + case "$key" in + memory.backend) echo "qmd" ;; + memory.qmd.command) echo "qmd" ;; + agents.defaults.memorySearch.provider) echo "local" ;; + agents.defaults.memorySearch.local.modelPath) echo "$HOME/.openclaw/models/embedding/model.gguf" ;; + *) echo "" ;; + esac + exit 0 +fi +if [[ "$cmd" == "config set"* || "$cmd" == "config unset"* ]]; then + exit 0 +fi +if [[ "$1" == "memory" && "$2" == "status" ]]; then + agent="main" + while [ $# -gt 0 ]; do + if [ "$1" = "--agent" ] && [ $# -ge 2 ]; then + agent="$2" + shift 2 + continue + fi + shift + done + if [ "$agent" = "work" ]; then + cat <> "$HOME/.openclaw/index_calls" + exit 0 +fi +if [[ "$1" == "gateway" && "$2" == "restart" ]]; then + echo "$cmd" >> "$HOME/.openclaw/gateway_calls" + exit 0 +fi +echo "mock openclaw $*" +EOF_INNER +chmod +x "$WORKDIR/bin/openclaw" + +export HOME="$WORKDIR/home" +export PATH="$WORKDIR/bin:$PATH" +export TERM=xterm + +mkdir -p "$HOME/.openclaw/workspace/memory" "$HOME/.openclaw/workspace-work/memory" +touch "$HOME/.openclaw/workspace/memory/index.sqlite" "$HOME/.openclaw/workspace-work/memory/index.sqlite" +cat > "$HOME/.openclaw/openclaw.json" <<'JSON' +{ + "agents": { + "list": [ + {"id": "work", "workspace": "~/.openclaw/workspace-work"} + ] + } +} +JSON +cat > "$HOME/.openclaw/workspace/MEMORY.md" <<'TXT' +# main memory +TXT +cat > "$HOME/.openclaw/workspace-work/MEMORY.md" <<'TXT' +# work memory +TXT +cat > "$HOME/.openclaw/workspace-work/memory/2026-03-23.md" <<'TXT' +# work note +TXT + +source "$WORKDIR/harness.sh" + +openclaw_memory_render_status > "$WORKDIR/out_status.txt" +openclaw_memory_file_render_list > "$WORKDIR/out_files.txt" +openclaw_memory_prepare_workspace_all > "$WORKDIR/out_prepare.txt" +openclaw_memory_rebuild_index_all > "$WORKDIR/out_rebuild.txt" + +export WORKDIR +python3 - <<'PY' +import os +from pathlib import Path + +workdir = Path(os.environ['WORKDIR']) +home = workdir / 'home' +status_out = (workdir / 'out_status.txt').read_text(encoding='utf-8') +files_out = (workdir / 'out_files.txt').read_text(encoding='utf-8') +prepare_out = (workdir / 'out_prepare.txt').read_text(encoding='utf-8') +rebuild_out = (workdir / 'out_rebuild.txt').read_text(encoding='utf-8') +index_calls = (home / '.openclaw' / 'index_calls').read_text(encoding='utf-8') +gateway_calls = (home / '.openclaw' / 'gateway_calls').read_text(encoding='utf-8') + +if 'Agent: main' not in status_out or 'Agent: work' not in status_out: + raise SystemExit('multi-agent status missing agent sections') +if 'main/MEMORY.md' not in files_out or 'work/MEMORY.md' not in files_out: + raise SystemExit('multi-agent file list missing memory files') +if 'work/memory/2026-03-23.md' not in files_out: + raise SystemExit('work daily memory file missing') +if '检查并准备 2 个智能体工作区' not in prepare_out: + raise SystemExit('prepare summary missing agent count') +if '--agent main --force' not in index_calls or '--agent work --force' not in index_calls: + raise SystemExit('force index not called for all agents') +if 'gateway restart' not in gateway_calls: + raise SystemExit('gateway restart not called after multi-agent rebuild') +if '已为 2 个智能体重建索引' not in rebuild_out: + raise SystemExit('multi-agent rebuild summary missing') +print('SMOKE_OK') +PY From b5d88f5036e3a9a5c21a5ee7a78246506336bb20 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 14:37:12 +0800 Subject: [PATCH 1107/1285] fix(openclaw): use runtime agent list for memory rebuild --- cn/kejilion.sh | 32 ++++++++++++++++++++++++++++++++ kejilion.sh | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a2d8d2672..b0210fc63 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13069,6 +13069,38 @@ if os.path.isdir(agents_root): } openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - <<'PY' "$agents_json" +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi local config_path config_path=$(openclaw_memory_config_file) python3 - "$config_path" <<'PY' diff --git a/kejilion.sh b/kejilion.sh index a2d8d2672..b0210fc63 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13069,6 +13069,38 @@ if os.path.isdir(agents_root): } openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - <<'PY' "$agents_json" +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi local config_path config_path=$(openclaw_memory_config_file) python3 - "$config_path" <<'PY' From fbde51c0b210baeee8fe8c707ae1f8b6361214d6 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 14:57:56 +0800 Subject: [PATCH 1108/1285] fix(openclaw): pass agents json correctly in memory menu --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b0210fc63..e53253292 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13073,7 +13073,7 @@ if os.path.isdir(agents_root): local agents_json agents_json=$(openclaw agents list --json 2>/dev/null || true) if [ -n "$agents_json" ]; then - python3 - <<'PY' "$agents_json" + python3 - "$agents_json" <<'PY' import json, os, sys raw = sys.argv[1] try: diff --git a/kejilion.sh b/kejilion.sh index b0210fc63..e53253292 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13073,7 +13073,7 @@ if os.path.isdir(agents_root): local agents_json agents_json=$(openclaw agents list --json 2>/dev/null || true) if [ -n "$agents_json" ]; then - python3 - <<'PY' "$agents_json" + python3 - "$agents_json" <<'PY' import json, os, sys raw = sys.argv[1] try: From a9ba4a7e5ed35c414e5fd177104553a9ab618c28 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 15:53:01 +0800 Subject: [PATCH 1109/1285] fix(openclaw): fix memory index fix_index setting includeDefaultMemory=false incorrectly - openclaw_memory_fix_index: no longer blindly sets includeDefaultMemory=false which excluded all default memory files from indexing (0/N + 0 chunks) - New logic: detects includeDefaultMemory=false and offers to restore to true then rebuilds all agent indexes - When includeDefaultMemory is already true, offers direct rebuild instead - Menu force-index branch: now indexes all agents instead of only main - Updated smoke test to match new fix behavior - Synced cn/kejilion.sh --- cn/kejilion.sh | 93 +++++++++++++------ kejilion.sh | 93 +++++++++++++------ .../tests_openclaw_memory_menu_smoke.sh | 15 ++- 3 files changed, 139 insertions(+), 62 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e53253292..eca1f9492 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13188,11 +13188,15 @@ PY openclaw_memory_rebuild_index_all() { local count=0 + local agent_lines agent_id workspace + agent_lines=$(openclaw_memory_list_agents) while IFS=$'\t' read -r agent_id workspace; do [ -z "$agent_id" ] && continue openclaw_memory_rebuild_index_single "$agent_id" count=$((count+1)) - done < <(openclaw_memory_list_agents) + done </dev/null) @@ -13245,7 +13254,9 @@ PY else echo "$status_lines" fi - done < <(openclaw_memory_list_agents) + done </dev/null 2>&1; then echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" echo " 可切换 Local,或安装 bun + qmd 后再试。" fi - echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" - read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "已取消。" - break_end - return 0 - fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" - break_end - return 1 - fi - echo "✅ 已设置 includeDefaultMemory=false" - echo "推荐执行:清理并重建索引" - read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "索引修复诊断" + echo "=======================================" + echo "当前 includeDefaultMemory: ${include_dm:-未设置}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ 检测到 includeDefaultMemory=false" + echo " 这会导致默认记忆文件(MEMORY.md + memory/*.md)不被索引" + echo " 所以 Indexed 会一直显示 0/N" + echo "" + read -e -p "是否恢复为 true 并重建索引?(Y/n): " fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + break_end + return 1 + fi + echo "✅ 已恢复 includeDefaultMemory=true" + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi else - echo "可稍后在记忆管理中查看状态。" + echo "includeDefaultMemory 配置正常。" + echo "将执行:清理旧索引 → 全量重建所有智能体索引" + echo "" + read -e -p "确认执行?(Y/n): " confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi fi break_end } @@ -13870,7 +13895,8 @@ PY openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() OPENCLAW_MEMORY_FILE_LABELS=() - local agent_id base_dir memory_dir memory_file rel + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) while IFS=$'\t' read -r agent_id base_dir; do [ -z "$agent_id" ] && continue memory_dir="$base_dir/memory" @@ -13887,7 +13913,9 @@ PY OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") done < <(find "$memory_dir" -type f -name '*.md' | sort) fi - done < <(openclaw_memory_list_agents) + done </dev/null) @@ -13245,7 +13254,9 @@ PY else echo "$status_lines" fi - done < <(openclaw_memory_list_agents) + done </dev/null 2>&1; then echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" echo " 可切换 Local,或安装 bun + qmd 后再试。" fi - echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" - read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "已取消。" - break_end - return 0 - fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" - break_end - return 1 - fi - echo "✅ 已设置 includeDefaultMemory=false" - echo "推荐执行:清理并重建索引" - read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "索引修复诊断" + echo "=======================================" + echo "当前 includeDefaultMemory: ${include_dm:-未设置}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ 检测到 includeDefaultMemory=false" + echo " 这会导致默认记忆文件(MEMORY.md + memory/*.md)不被索引" + echo " 所以 Indexed 会一直显示 0/N" + echo "" + read -e -p "是否恢复为 true 并重建索引?(Y/n): " fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ 写入配置失败" + break_end + return 1 + fi + echo "✅ 已恢复 includeDefaultMemory=true" + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi else - echo "可稍后在记忆管理中查看状态。" + echo "includeDefaultMemory 配置正常。" + echo "将执行:清理旧索引 → 全量重建所有智能体索引" + echo "" + read -e -p "确认执行?(Y/n): " confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi fi break_end } @@ -13870,7 +13895,8 @@ PY openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() OPENCLAW_MEMORY_FILE_LABELS=() - local agent_id base_dir memory_dir memory_file rel + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) while IFS=$'\t' read -r agent_id base_dir; do [ -z "$agent_id" ] && continue memory_dir="$base_dir/memory" @@ -13887,7 +13913,9 @@ PY OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") done < <(find "$memory_dir" -type f -name '*.md' | sort) fi - done < <(openclaw_memory_list_agents) + done < "$HOME/.openclaw/includeDefaultMemory" run_menu "3\ny\n\n\n0\n" "fix" "$WORKDIR/out_fix.txt" # 5) 记忆方案(自动推荐并取消) run_menu "4\n1\n\n0\n0\n" "scheme" "$WORKDIR/out_scheme.txt" @@ -190,8 +197,8 @@ flag_path = os.path.expanduser('~/.openclaw/includeDefaultMemory') if not os.path.exists(flag_path): raise SystemExit('includeDefaultMemory not updated') flag = open(flag_path, 'r', encoding='utf-8').read().strip() -if flag != 'false': - raise SystemExit('includeDefaultMemory not updated') +if flag != 'true': + raise SystemExit('includeDefaultMemory not restored to true') # ensure backup created baks = glob.glob(os.path.expanduser('~/.openclaw/workspace/memory/index.sqlite.bak.*')) if not baks: From db24e32796e910824e8c27c82db4faf33fe9e523 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 16:11:19 +0800 Subject: [PATCH 1110/1285] fix(openclaw): preheat index in auto-setup also covers all agents - openclaw_memory_auto_setup_local: preheat now indexes all agents - QMD auto-setup was already fixed - All memory index paths now support multi-agent - Synced cn/kejilion.sh --- cn/kejilion.sh | 18 ++++++++++++++++-- kejilion.sh | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index eca1f9492..c821abba2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13604,7 +13604,14 @@ EOF if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace_all - openclaw memory index --agent main --force + local preh_agent_lines preh_agent_id preh_workspace + preh_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r preh_agent_id preh_workspace; do + [ -z "$preh_agent_id" ] && continue + openclaw memory index --agent "$preh_agent_id" --force + done < Date: Mon, 23 Mar 2026 16:31:26 +0800 Subject: [PATCH 1111/1285] fix(openclaw): verify qmd module integrity before skipping install - qmd command may exist but module could be corrupted (Module not found) - Now runs 'qmd --version' to verify qmd actually works - If verification fails, reinstalls instead of skipping - Also verifies after installation - Synced cn/kejilion.sh --- cn/kejilion.sh | 14 +++++++++++--- kejilion.sh | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c821abba2..15f33548c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13475,9 +13475,13 @@ EOF local qmd_path qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd 已存在: $qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd 已存在且可用: $qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ qmd 命令存在但模块损坏,重新安装..." + fi fi openclaw_memory_ensure_bun || return 1 local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" @@ -13491,6 +13495,10 @@ EOF echo "❌ qmd 安装失败" return 1 fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ qmd 安装后仍无法运行" + return 1 + fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" echo "✅ qmd 安装完成: $qmd_path" return 0 diff --git a/kejilion.sh b/kejilion.sh index c821abba2..15f33548c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13475,9 +13475,13 @@ EOF local qmd_path qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd 已存在: $qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd 已存在且可用: $qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ qmd 命令存在但模块损坏,重新安装..." + fi fi openclaw_memory_ensure_bun || return 1 local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" @@ -13491,6 +13495,10 @@ EOF echo "❌ qmd 安装失败" return 1 fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ qmd 安装后仍无法运行" + return 1 + fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" echo "✅ qmd 安装完成: $qmd_path" return 0 From ad34ab5e6c79eba1abed901b706e83594f46b6b7 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 16:55:46 +0800 Subject: [PATCH 1112/1285] fix(openclaw): use npm to install qmd instead of bun+github - bun install from github:tobi/qmd installs source code without dist/ - npm install @tobilu/qmd installs prebuilt version that works immediately - Removed bun dependency for qmd installation - openclaw_memory_ensure_bun() kept for potential future use - Synced cn/kejilion.sh --- cn/kejilion.sh | 9 ++------- kejilion.sh | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 15f33548c..3dc7ca413 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13483,14 +13483,9 @@ EOF echo "⚠️ qmd 命令存在但模块损坏,重新安装..." fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ 通过 bun 安装 qmd: $qmd_url" - bun install -g "$qmd_url" + echo "⬇️ 通过 npm 安装 qmd: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then echo "❌ qmd 安装失败" return 1 diff --git a/kejilion.sh b/kejilion.sh index 15f33548c..3dc7ca413 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13483,14 +13483,9 @@ EOF echo "⚠️ qmd 命令存在但模块损坏,重新安装..." fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ 通过 bun 安装 qmd: $qmd_url" - bun install -g "$qmd_url" + echo "⬇️ 通过 npm 安装 qmd: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then echo "❌ qmd 安装失败" return 1 From ce47e0e365c566ba1963a5645f6038f085877257 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 18:43:24 +0800 Subject: [PATCH 1113/1285] feat(openclaw): auto-sync all sessions model when switching default model - Add openclaw_get_agents_dir() helper for non-root user compatibility - Add openclaw_sync_sessions_model() to batch update modelOverride/providerOverride - Auto-sync all agent sessions when switching model via menu or API sync - Add smoke test for the new sync function --- kejilion.sh | 61 +++++++++++++++++ ...ests_openclaw_sync_sessions_model_smoke.sh | 66 +++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100755 tests/openclaw/tests_openclaw_sync_sessions_model_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index 3dc7ca413..49de50c0f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10803,6 +10803,7 @@ EOF echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway echo "$finish_msg" echo "✅ 当前 API 协议类型: $DETECTED_API" @@ -11751,6 +11752,7 @@ PYTHON_EOF break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end @@ -11818,6 +11820,7 @@ PYTHON_EOF break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end @@ -11837,6 +11840,64 @@ PYTHON_EOF fi } + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ 已同步 $count 个 agent 的会话模型为 $model_ref" + return 0 + } + resolve_openclaw_plugin_id() { local raw_input="$1" local plugin_id="$raw_input" diff --git a/tests/openclaw/tests_openclaw_sync_sessions_model_smoke.sh b/tests/openclaw/tests_openclaw_sync_sessions_model_smoke.sh new file mode 100755 index 000000000..9e922b8c5 --- /dev/null +++ b/tests/openclaw/tests_openclaw_sync_sessions_model_smoke.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root=$(cd "$(dirname "$0")/../.." && pwd) +script="$repo_root/kejilion.sh" + +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT +export HOME="$workdir/home" +mkdir -p "$HOME/.openclaw/agents/main/sessions" +mkdir -p "$HOME/.openclaw/agents/work/sessions" + +funcs_file="$workdir/funcs.sh" +{ + awk '/^[[:space:]]*openclaw_get_agents_dir\(\)/,/^[[:space:]]*\}$/' "$script" + echo + awk '/^[[:space:]]*openclaw_sync_sessions_model\(\)/,/^[[:space:]]*\}$/' "$script" +} > "$funcs_file" + +cat > "$HOME/.openclaw/agents/main/sessions/sessions.json" <<'JSON' +{ + "agent:main:telegram:direct:123": { + "sessionId": "abc-123", + "modelOverride": "gpt-4", + "providerOverride": "openai" + }, + "agent:main:main": { + "sessionId": "def-456" + } +} +JSON + +cat > "$HOME/.openclaw/agents/work/sessions/sessions.json" <<'JSON' +{ + "agent:work:slack:channel:C789": { + "sessionId": "ghi-789", + "modelOverride": "claude-3", + "providerOverride": "anthropic" + } +} +JSON + +source "$funcs_file" +openclaw_sync_sessions_model "cli-api/gpt-5-pro" + +echo "=== VERIFICATION ===" + +main_file="$HOME/.openclaw/agents/main/sessions/sessions.json" +work_file="$HOME/.openclaw/agents/work/sessions/sessions.json" + +main_model=$(jq -r '."agent:main:telegram:direct:123".modelOverride' "$main_file") +main_provider=$(jq -r '."agent:main:telegram:direct:123".providerOverride' "$main_file") +main2_model=$(jq -r '."agent:main:main".modelOverride' "$main_file") +main2_provider=$(jq -r '."agent:main:main".providerOverride // "null"' "$main_file") + +work_model=$(jq -r '."agent:work:slack:channel:C789".modelOverride' "$work_file") +work_provider=$(jq -r '."agent:work:slack:channel:C789".providerOverride' "$work_file") + +[ "$main_model" = "gpt-5-pro" ] || { echo "FAIL: main model (got: $main_model)"; exit 1; } +[ "$main_provider" = "cli-api" ] || { echo "FAIL: main provider (got: $main_provider)"; exit 1; } +[ "$main2_model" = "gpt-5-pro" ] || { echo "FAIL: main2 model (got: $main2_model)"; exit 1; } +[ "$main2_provider" = "cli-api" ] || { echo "FAIL: main2 provider (got: $main2_provider)"; exit 1; } +[ "$work_model" = "gpt-5-pro" ] || { echo "FAIL: work model (got: $work_model)"; exit 1; } +[ "$work_provider" = "cli-api" ] || { echo "FAIL: work provider (got: $work_provider)"; exit 1; } + +echo "PASS: openclaw_sync_sessions_model smoke" From 7874ffc65cb28fde6fddaacb00397c396fb30bae Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 19:42:04 +0800 Subject: [PATCH 1114/1285] feat(openclaw): auto-update MEMORY.md agent routes on create/delete - Add openclaw_update_memory_agent_routes() to sync agent list to MEMORY.md - Call on agent create/delete to keep routing rules up-to-date - Ensures new sessions can discover sub-agents for task routing --- kejilion.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 49de50c0f..f8c114260 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14764,6 +14764,56 @@ for idx,item in enumerate(agents,1): print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" } + openclaw_update_memory_agent_routes() { + local memory_file="$HOME/.openclaw/workspace/MEMORY.md" + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null) || return 1 + + if [ ! -f "$memory_file" ]; then + echo "MEMORY.md 不存在,跳过路由规则更新" + return 0 + fi + + local routes_section + routes_section=$(python3 - "$agents_json" <<'PY' +import json, sys +agents = json.loads(sys.argv[1]) +lines = ["## 子智能体路由规则", "", + "当任务涉及以下领域时,自动调用对应子智能体:", "", + "| Agent ID | 身份 | 触发关键词 |", + "|----------|------|-----------|"] +for a in agents: + aid = a.get("id", "?") + if aid == "main": + continue + name = a.get("identityName") or a.get("name") or aid + lines.append(f"| {aid} | {name} | (根据身份推断) |") +lines.append("") +lines.append("调用方式:`sessions_spawn(runtime=\"subagent\", agentId=\"\", task=\"...\")`") +lines.append("") +print("\n".join(lines)) +PY +) + + if grep -q "^## 子智能体路由规则" "$memory_file"; then + local tmp_file + tmp_file=$(mktemp) + awk -v section="$routes_section" ' + BEGIN { in_section=0 } + /^## 子智能体路由规则/ { in_section=1; print section; next } + /^## / && in_section { in_section=0 } + !in_section { print } + ' "$memory_file" > "$tmp_file" && mv "$tmp_file" "$memory_file" + echo "✅ 已更新 MEMORY.md 中的子智能体路由规则" + else + echo "" >> "$memory_file" + echo "$routes_section" >> "$memory_file" + echo "✅ 已添加子智能体路由规则到 MEMORY.md" + fi + + openclaw memory index --force >/dev/null 2>&1 & + } + openclaw_multiagent_add_agent() { send_stats "OpenClaw多智能体-新增Agent" openclaw_multiagent_require_openclaw || return 1 @@ -14785,6 +14835,7 @@ for idx,item in enumerate(agents,1): [ -z "$theme" ] && theme="助手" echo "正在配置智能体身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" + openclaw_update_memory_agent_routes else echo "❌ 智能体创建失败" return 1 @@ -14802,6 +14853,7 @@ for idx,item in enumerate(agents,1): [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then echo "✅ 智能体删除成功: $agent_id" + openclaw_update_memory_agent_routes else echo "❌ 智能体删除失败" return 1 From a67d37422e0bb8dd7cf14e45503a94add5e36955 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 23 Mar 2026 19:45:02 +0800 Subject: [PATCH 1115/1285] Revert "feat(openclaw): auto-update MEMORY.md agent routes on create/delete" This reverts commit 7874ffc65cb28fde6fddaacb00397c396fb30bae. --- kejilion.sh | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f8c114260..49de50c0f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14764,56 +14764,6 @@ for idx,item in enumerate(agents,1): print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" } - openclaw_update_memory_agent_routes() { - local memory_file="$HOME/.openclaw/workspace/MEMORY.md" - local agents_json - agents_json=$(openclaw agents list --json 2>/dev/null) || return 1 - - if [ ! -f "$memory_file" ]; then - echo "MEMORY.md 不存在,跳过路由规则更新" - return 0 - fi - - local routes_section - routes_section=$(python3 - "$agents_json" <<'PY' -import json, sys -agents = json.loads(sys.argv[1]) -lines = ["## 子智能体路由规则", "", - "当任务涉及以下领域时,自动调用对应子智能体:", "", - "| Agent ID | 身份 | 触发关键词 |", - "|----------|------|-----------|"] -for a in agents: - aid = a.get("id", "?") - if aid == "main": - continue - name = a.get("identityName") or a.get("name") or aid - lines.append(f"| {aid} | {name} | (根据身份推断) |") -lines.append("") -lines.append("调用方式:`sessions_spawn(runtime=\"subagent\", agentId=\"\", task=\"...\")`") -lines.append("") -print("\n".join(lines)) -PY -) - - if grep -q "^## 子智能体路由规则" "$memory_file"; then - local tmp_file - tmp_file=$(mktemp) - awk -v section="$routes_section" ' - BEGIN { in_section=0 } - /^## 子智能体路由规则/ { in_section=1; print section; next } - /^## / && in_section { in_section=0 } - !in_section { print } - ' "$memory_file" > "$tmp_file" && mv "$tmp_file" "$memory_file" - echo "✅ 已更新 MEMORY.md 中的子智能体路由规则" - else - echo "" >> "$memory_file" - echo "$routes_section" >> "$memory_file" - echo "✅ 已添加子智能体路由规则到 MEMORY.md" - fi - - openclaw memory index --force >/dev/null 2>&1 & - } - openclaw_multiagent_add_agent() { send_stats "OpenClaw多智能体-新增Agent" openclaw_multiagent_require_openclaw || return 1 @@ -14835,7 +14785,6 @@ PY [ -z "$theme" ] && theme="助手" echo "正在配置智能体身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" - openclaw_update_memory_agent_routes else echo "❌ 智能体创建失败" return 1 @@ -14853,7 +14802,6 @@ PY [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then echo "✅ 智能体删除成功: $agent_id" - openclaw_update_memory_agent_routes else echo "❌ 智能体删除失败" return 1 From 1a6f7706ac855c76663d190909e80516367629db Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 24 Mar 2026 17:50:28 +0800 Subject: [PATCH 1116/1285] feat(openclaw): add API providers showcase menu option - Add openclaw_api_providers_showcase() to display recommended API providers - Highlight AFF links with yellow color for easy identification - Add menu option 5 in API management --- kejilion.sh | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 49de50c0f..af8830a41 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11414,6 +11414,41 @@ PY break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API厂商推荐" + local orange="#FF8C00" + local cyan="#00CED1" + local green="#32CD32" + local purple="#9370DB" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}部分入口含 AFF${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╠════════════════════════════════════════════════════════════╣${gl_bai}" + + echo -e "${gl_kjlan}║${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● DeepSeek${gl_bai} https://api-docs.deepseek.com/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● OpenRouter${gl_bai} https://openrouter.ai/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● Kimi${gl_bai} https://platform.moonshot.cn/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 硅基流动${gl_bai} https://cloud.siliconflow.cn/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 白山云${gl_bai} https://ai.baishan.com/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 智谱 GLM${gl_bai} https://www.bigmodel.cn/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● MiniMax${gl_bai} https://www.minimaxi.com/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● NVIDIA${gl_bai} https://build.nvidia.com/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● Ollama${gl_bai} https://ollama.com/ ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_kjlan}║${gl_bai}" + + echo -e "${gl_kjlan}╠════════════════════════════════════════════════════════════╣${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}图例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" + echo "" + read -erp "按回车键返回..." dummy + } + openclaw_api_manage_menu() { send_stats "OpenClaw API入口" while true; do @@ -11427,6 +11462,7 @@ PY echo "2. 同步API供应商模型列表" echo "3. 切换 API 类型(completions / responses)" echo "4. 删除API" + echo "5. API 厂商推荐" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11444,6 +11480,9 @@ PY 4) delete-openclaw-provider-interactive ;; + 5) + openclaw_api_providers_showcase + ;; 0) return 0 ;; From 6e1c68086b279087a375122d4d60d74e21b53266 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 24 Mar 2026 18:00:54 +0800 Subject: [PATCH 1117/1285] feat(openclaw): add API providers showcase with AFF links - Display 9 API providers with full URLs - Highlight AFF links with [AFF] tag and yellow color - Clean card-style layout for easy copying --- kejilion.sh | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index af8830a41..1ae161415 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11416,34 +11416,45 @@ PY openclaw_api_providers_showcase() { send_stats "OpenClaw API厂商推荐" - local orange="#FF8C00" - local cyan="#00CED1" - local green="#32CD32" - local purple="#9370DB" clear echo "" echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}部分入口含 AFF${gl_bai} ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}╠════════════════════════════════════════════════════════════╣${gl_bai}" - - echo -e "${gl_kjlan}║${gl_bai} ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● DeepSeek${gl_bai} https://api-docs.deepseek.com/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● OpenRouter${gl_bai} https://openrouter.ai/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● Kimi${gl_bai} https://platform.moonshot.cn/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 硅基流动${gl_bai} https://cloud.siliconflow.cn/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 白山云${gl_bai} https://ai.baishan.com/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}● 智谱 GLM${gl_bai} https://www.bigmodel.cn/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● MiniMax${gl_bai} https://www.minimaxi.com/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● NVIDIA${gl_bai} https://build.nvidia.com/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_lv}● Ollama${gl_bai} https://ollama.com/ ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_kjlan}║${gl_bai}" - - echo -e "${gl_kjlan}╠════════════════════════════════════════════════════════════╣${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}图例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}● 白山云${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/auth/login?referralCode=6crtUISIWd${gl_bai}" + echo -e " ${gl_kjlan}&utm_source=kejilion&utm_medium=blog&utm_campaign=baishan-150-coupon-202603${gl_bai}" + echo "" + echo -e " ${gl_huang}● 智谱 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}图例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" + echo "" echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" echo "" read -erp "按回车键返回..." dummy From 144357979e6911d9b24e6584c77b8a795eb60538 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 24 Mar 2026 18:14:02 +0800 Subject: [PATCH 1118/1285] =?UTF-8?q?feat(openclaw):=20add=20=E4=BC=98?= =?UTF-8?q?=E4=BA=91=E6=99=BA=E7=AE=97=20to=20API=20providers=20showcase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kejilion.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index 1ae161415..770936963 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11433,6 +11433,9 @@ PY echo -e " ${gl_lv}● Kimi${gl_bai}" echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" echo "" + echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" echo "" From dfcdc10ae0d5adc41662c257426b57fb35fccdb4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 24 Mar 2026 18:19:17 +0800 Subject: [PATCH 1119/1285] =?UTF-8?q?fix(openclaw):=20move=20=E7=99=BD?= =?UTF-8?q?=E5=B1=B1=E4=BA=91=20to=20bottom=20as=20official=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kejilion.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 770936963..3b8f38aee 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11439,10 +11439,6 @@ PY echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" echo "" - echo -e " ${gl_huang}● 白山云${gl_bai} ${gl_zi}[AFF]${gl_bai}" - echo -e " ${gl_kjlan}https://ai.baishan.com/auth/login?referralCode=6crtUISIWd${gl_bai}" - echo -e " ${gl_kjlan}&utm_source=kejilion&utm_medium=blog&utm_campaign=baishan-150-coupon-202603${gl_bai}" - echo "" echo -e " ${gl_huang}● 智谱 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" echo "" @@ -11455,6 +11451,9 @@ PY echo -e " ${gl_lv}● Ollama${gl_bai}" echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" echo "" + echo -e " ${gl_lv}● 白山云${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" echo -e " ${gl_zi}图例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" echo "" From a9ff8e819c547962aae0f6e6ddece6eaf1b08ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 24 Mar 2026 19:48:41 +0800 Subject: [PATCH 1120/1285] Add API provider showcase function and menu option --- cn/kejilion.sh | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3dc7ca413..3b8f38aee 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10803,6 +10803,7 @@ EOF echo echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway echo "$finish_msg" echo "✅ 当前 API 协议类型: $DETECTED_API" @@ -11413,6 +11414,54 @@ PY break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API厂商推荐" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}部分入口含 AFF${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" + echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}● 智谱 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● 白山云${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}图例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" + echo "" + echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" + echo "" + read -erp "按回车键返回..." dummy + } + openclaw_api_manage_menu() { send_stats "OpenClaw API入口" while true; do @@ -11426,6 +11475,7 @@ PY echo "2. 同步API供应商模型列表" echo "3. 切换 API 类型(completions / responses)" echo "4. 删除API" + echo "5. API 厂商推荐" echo "0. 退出" echo "---------------------------------------" read -erp "请输入你的选择: " api_choice @@ -11443,6 +11493,9 @@ PY 4) delete-openclaw-provider-interactive ;; + 5) + openclaw_api_providers_showcase + ;; 0) return 0 ;; @@ -11751,6 +11804,7 @@ PYTHON_EOF break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end @@ -11818,6 +11872,7 @@ PYTHON_EOF break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end @@ -11837,6 +11892,64 @@ PYTHON_EOF fi } + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ 已同步 $count 个 agent 的会话模型为 $model_ref" + return 0 + } + resolve_openclaw_plugin_id() { local raw_input="$1" local plugin_id="$raw_input" From 1e199cc4f049217cb9ae35771babea05cd7ab65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Tue, 24 Mar 2026 19:49:45 +0800 Subject: [PATCH 1121/1285] Change canshu variable from 'CN' to 'default' --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 3b8f38aee..2a087511a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" From bcf570509fae270a123aa7e27999502030460917 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 25 Mar 2026 14:13:10 +0800 Subject: [PATCH 1122/1285] feat(openclaw): add PackyAPI to API provider recommendations --- cn/kejilion.sh | 3 +++ kejilion.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3b8f38aee..a8afc651b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11442,6 +11442,9 @@ PY echo -e " ${gl_huang}● 智谱 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" diff --git a/kejilion.sh b/kejilion.sh index 2a087511a..68e8d0939 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11442,6 +11442,9 @@ PY echo -e " ${gl_huang}● 智谱 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" From bae47c60dbfc069fdfa50a9e5410384dd97d6983 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 25 Mar 2026 14:20:12 +0800 Subject: [PATCH 1123/1285] feat(openclaw): add Yunwu API to provider recommendations --- cn/kejilion.sh | 3 +++ kejilion.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a8afc651b..d0534612e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11445,6 +11445,9 @@ PY echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" echo "" + echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" diff --git a/kejilion.sh b/kejilion.sh index 68e8d0939..301421034 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11445,6 +11445,9 @@ PY echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" echo "" + echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" From ea90636b46aca627465521ea71067dcb806eca61 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 25 Mar 2026 14:56:22 +0800 Subject: [PATCH 1124/1285] feat(openclaw): add Plato AI to provider recommendations --- cn/kejilion.sh | 3 +++ kejilion.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d0534612e..8655e014d 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11448,6 +11448,9 @@ PY echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" echo "" + echo -e " ${gl_huang}● 柏拉图AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" diff --git a/kejilion.sh b/kejilion.sh index 301421034..c1b2feb71 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11448,6 +11448,9 @@ PY echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" echo "" + echo -e " ${gl_huang}● 柏拉图AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" echo "" From 2e475a1ba31d72801192405b38171d06966ea82e Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Wed, 25 Mar 2026 17:26:37 +0800 Subject: [PATCH 1125/1285] feat(openclaw): add SCNet to provider recommendations --- cn/kejilion.sh | 3 +++ kejilion.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8655e014d..45be9459e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -11433,6 +11433,9 @@ PY echo -e " ${gl_lv}● Kimi${gl_bai}" echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" echo "" + echo -e " ${gl_lv}● 超算互联网${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" diff --git a/kejilion.sh b/kejilion.sh index c1b2feb71..c1f3cd332 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -11433,6 +11433,9 @@ PY echo -e " ${gl_lv}● Kimi${gl_bai}" echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" echo "" + echo -e " ${gl_lv}● 超算互联网${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" From 087a74a39197f4a64566994e82c77a98d3ef597a Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 27 Mar 2026 14:25:42 +0800 Subject: [PATCH 1126/1285] =?UTF-8?q?openclaw=E6=A8=A1=E5=9D=97:=20API?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=90=8C=E6=AD=A5=E6=94=AF=E6=8C=81=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=9B=9E=E8=BD=A6=E5=90=8C=E6=AD=A5=E5=85=A8=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sync-openclaw-provider-interactive 函数增加判断 - 用户直接回车时调用 sync_openclaw_api_models 同步全部API模型 - 同步完成后自动启动网关 - 支持 cn/tw/kr/jp/英文 多语言版本 --- cn/kejilion.sh | 13 +++++++++---- jp/kejilion.sh | 13 +++++++++---- kejilion.sh | 13 +++++++++---- kr/kejilion.sh | 13 +++++++++---- tw/kejilion.sh | 13 +++++++++---- 5 files changed, 45 insertions(+), 20 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 45be9459e..1b57a3268 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10941,11 +10941,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "请输入要同步的 API 名称(provider): " provider_name + read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name if [ -z "$provider_name" ]; then - echo "❌ provider 名称不能为空" - break_end - return 1 + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" + break_end + return 1 + fi + return 0 fi install jq curl >/dev/null 2>&1 diff --git a/jp/kejilion.sh b/jp/kejilion.sh index cb5cc4c43..a6bcf0ff9 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -10996,11 +10996,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "同期する API 名 (プロバイダー) を入力してください:" provider_name + read -erp "同期する API 名 (プロバイダー) 、Enterで全部同期: " provider_name if [ -z "$provider_name" ]; then - echo "❌ プロバイダー名を空にすることはできません" - break_end - return 1 + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ APIモデル同期失敗、ゲートウェイ再起動中止。provider /modelsを確認后再試行してください。" + break_end + return 1 + fi + return 0 fi install jq curl >/dev/null 2>&1 diff --git a/kejilion.sh b/kejilion.sh index c1f3cd332..0f2f72b88 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10941,11 +10941,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "请输入要同步的 API 名称(provider): " provider_name + read -erp "Enter the API name (provider) to sync, press Enter to sync all: " provider_name if [ -z "$provider_name" ]; then - echo "❌ provider 名称不能为空" - break_end - return 1 + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API model sync failed, gateway restart aborted. Check provider /models and retry." + break_end + return 1 + fi + return 0 fi install jq curl >/dev/null 2>&1 diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 6fe676987..e78b865db 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -10936,11 +10936,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "请输入要同步的 API 名称(provider): " provider_name + read -erp "동기화할 API 이름(provider), Enter로 전체 동기화: " provider_name if [ -z "$provider_name" ]; then - echo "❌ provider 名称不能为空" - break_end - return 1 + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 모델 동기 실패, 게이트웨이 재시작 중단. provider /models 확인 후 재시도하세요." + break_end + return 1 + fi + return 0 fi install jq curl >/dev/null 2>&1 diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 4ca78c571..055542ac0 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -10996,11 +10996,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "請輸入要同步的 API 名稱(provider):" provider_name + read -erp "請輸入要同步的 API 名稱(provider),直接 Enter 同步全部: " provider_name if [ -z "$provider_name" ]; then - echo "❌ provider 名稱不能為空" - break_end - return 1 + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API 模型同步失敗,已中止重啟網關。請檢查 provider /models 後重試。" + break_end + return 1 + fi + return 0 fi install jq curl >/dev/null 2>&1 From 0dce270c63fa6cbaf15d44a2bae69a12823bbcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:20:14 +0800 Subject: [PATCH 1127/1285] Fix break_end call placement in kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1b57a3268..692d3846a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10947,9 +10947,9 @@ sync-openclaw-provider-interactive() { start_gateway else echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" - break_end return 1 fi + break_end return 0 fi From 7fd138d71b17b2bb837570cf5de1c3bb7537e05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:23:56 +0800 Subject: [PATCH 1128/1285] Translate API sync prompts to Chinese --- kejilion.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0f2f72b88..8f5b040a6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10941,15 +10941,15 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "Enter the API name (provider) to sync, press Enter to sync all: " provider_name + read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ API model sync failed, gateway restart aborted. Check provider /models and retry." - break_end + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" return 1 fi + break_end return 0 fi From bfdf002d3d160f5dd1dd177a3aa4927fc96abc4c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 27 Mar 2026 16:50:12 +0000 Subject: [PATCH 1129/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-03-27=2016:50:12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 2418 ++++++++++---- jp/kejilion.sh | 2519 +++++++++++---- kr/kejilion.sh | 8354 +++++++++++++++++++++++++----------------------- tw/kejilion.sh | 2401 ++++++++++---- 4 files changed, 9838 insertions(+), 5854 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 09d46a098..c3dce90aa 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.9" gl_hui='\e[37m' @@ -884,7 +884,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2318,7 +2318,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2667,7 +2667,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2686,7 +2686,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3215,7 +3215,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3596,7 +3596,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -7207,7 +7207,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7386,7 +7386,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -8077,7 +8077,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8238,7 +8238,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8735,7 +8735,7 @@ linux_test() { 32) send_stats "spiritysdx fusion monster review" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) @@ -10035,7 +10035,8 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw Management" + echo -e "🦞 OPENCLAW Management Tool by KEJILION 🦞" + echo -e "💡 Terminal execution \033[1;33mk claw\033[0m to quickly enter the menu" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. Installation" @@ -10044,7 +10045,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API management" + echo "6. API Management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10054,14 +10055,16 @@ moltbot_menu() { echo "13. WebUI access and settings" echo "14. TUI command line dialog window" echo "15. Memory/Memory" + echo "16. Permission management" + echo "17. Multi-agent management" echo "--------------------" - echo "16. Backup and restore" - echo "17. Update" - echo "18. Uninstall" + echo "18. Backup and restore" + echo "19. Update" + echo "20. Uninstall" echo "--------------------" echo "0. Return to the previous menu" echo "--------------------" - printf "请输入选项并回车: " + printf "Please enter options and press Enter:" } @@ -10088,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10119,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10139,36 +10144,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10331,36 +10306,6 @@ def delete_provider_and_refs(name): return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10403,16 +10348,6 @@ for name, provider in list(providers.items()): api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: The protocol has been automatically corrected to {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: Protocol detection failed, skip correction ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models detection failed, retried {attempts} times ({type(err).__name__}: {err})') @@ -10459,15 +10394,6 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ Add new model ({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ Delete model ({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10514,7 +10440,17 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: Delete {len(removed_ids)}, add {len(added_ids)}, current {len(new_models)}') + summary.append(f'✅ {name}: Added {len(added_ids)}, deleted {len(removed_ids)}, currently {len(new_models)}') + + if added_ids: + summary.append(f'➕ Add new model ({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ Delete model ({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + if fatal_errors: for line in summary: @@ -10543,6 +10479,7 @@ PY install_moltbot() { echo "Start installing OpenClaw..." send_stats "Start installing OpenClaw..." + install git jq install_node_and_tools @@ -10551,12 +10488,13 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # Tip: If you need to modify the configuration to take effect immediately, you can restart the gateway: openclaw gateway restart configure_openclaw_session_policy start_gateway @@ -10594,91 +10532,23 @@ PY - # OpenClaw API protocol detection (priority responses -> completions) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" - - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" - return 0 - } + # OpenClaw API protocol detection logic has been removed: API types are no longer automatically detected/determined. + # Note: The API type is explicitly configured by the user (models.providers..api), and the script no longer attempts to call /responses for inference. - # Core function: get and add all models - add-all-models-from-provider() { + # Construct model configuration JSON + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 Getting$provider_nameAll available models of..." - - # Automatically identify API protocols - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" - - # Get model list - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ Unable to obtain model list" - return 1 - fi - - # Extract all model IDs - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ No models found" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ Discover$model_countmodels" - - # Intelligent inference of model parameters + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context and max_tokens are fully loaded, so you are not afraid of big problems local context_window=1048576 local max_tokens=128000 - - # Only price needs to be graded local input_cost=0.15 local output_cost=0.60 @@ -10716,11 +10586,23 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # Write provider and model configuration + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file + config_file=$(openclaw_get_config_file) + + # No longer automatically detects/corrects API protocols; maintains user configuration + DETECTED_API="openai-completions" - # Backup configuration [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # Use jq to inject all models and synchronize defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10754,6 +10636,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # Core function: get and add all models + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 Getting$provider_nameAll available models of..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ Unable to obtain model list" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ No models found" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ Discover$model_countmodels" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ Added successfully$model_countmodels arrive$provider_name" @@ -10765,6 +10680,33 @@ EOF fi } + # Add only the default model and keep the provider + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ The default model cannot be empty" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ Provider added:$provider_name" + echo "✅ Only write to the default model:$default_model" + return 0 + else + echo "❌ Configuration injection failed" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API added" echo "=== Interactively add OpenClaw Provider (full model) ===" @@ -10793,9 +10735,7 @@ EOF echo done - # 4. Protocol detection (no sense) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. No longer detecting/determining API types; protocols are selected and maintained by users themselves # 5. Get model list echo "🔍 Getting list of available models..." @@ -10846,22 +10786,27 @@ EOF echo "Total number of models:$model_count" echo "======================" - read -erp "Confirm to add all$model_countA model? (y/N):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ Canceled" - return 1 - fi + read -erp "Do you want to add all other available models at the same time? (y/N):" confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅ Done! all$model_countmodels loaded" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅ Done! Provider is retained and only the default model is loaded:$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo echo "🔄 Set default model and restart gateway..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway - echo "✅ Done! all$model_countmodels loaded" - echo "✅ The agreement has been automatically identified as:$DETECTED_API" + echo "$finish_msg" + echo "✅ Current API protocol type:$DETECTED_API" fi break_end @@ -10996,11 +10941,16 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "Please enter the API name (provider) to be synchronized:" provider_name + read -erp "Please enter the API name (provider) to be synchronized and press Enter to synchronize all:" provider_name if [ -z "$provider_name" ]; then - echo "❌ provider name cannot be empty" + if sync_openclaw_api_models; then + start_gateway + else + echo "❌ API model synchronization failed, restarting the gateway has been aborted. Please check provider /models and try again after returning." + return 1 + fi break_end - return 1 + return 0 fi install jq curl >/dev/null 2>&1 @@ -11016,35 +10966,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11128,19 +11049,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} current api={api}, will re-detect the protocol and continue') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} currently api={api}, but the script no longer detects/corrects the protocol; please manually set it to openai-completions or openai-responses') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 Auto-corrected protocol: {target} {api} ({detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ Protocol detection failed, skipping correction: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: @@ -11172,15 +11083,6 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ Add new model ({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ Delete model ({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11227,15 +11129,23 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: Remove {len(removed_ids)}, add {len(added_ids)}, current {len(new_models)}') +print(f'✅ {target}: Added {len(added_ids)}, deleted {len(removed_ids)}, current {len(new_models)}') + +if added_ids: + print(f'➕ Add new model ({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ Delete model ({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: print('✅ The specified provider model consistency synchronization is completed and the configuration has been written') else: @@ -11268,85 +11178,15 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ openclaw.json not found') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ provider: {name} not found') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ provider {name} is missing baseUrl/apiKey') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ Updated provider {name} protocol: {current_api or "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ No updates required: protocol remains {current_api or api}') -PY + # Protocol detection logic has been removed: scripts no longer automatically detect/determine API types. + # The function is retained for compatibility with menu calls, but no rewriting is done. + echo "ℹ️ Protocol detection has been turned off: please manually${HOME}Set provider.api in /.openclaw/openclaw.json to openai-completions or openai-responses" + return 0 } fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API protocol fixes" + send_stats "OpenClaw API protocol switching" if [ ! -f "$config_file" ]; then echo "❌ Configuration file not found:$config_file" @@ -11354,29 +11194,75 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - read -erp "Please enter the API name (provider) of the protocol to be repaired:" provider_name + read -erp "Please enter the API name (provider) to switch protocols:" provider_name if [ -z "$provider_name" ]; then echo "❌ provider name cannot be empty" break_end return 1 fi - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "Please select the API type you want to set up:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "Please enter your choice (1/2):" proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ Invalid selection" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ Illegal protocol value') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ provider: {name} not found') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ The provider {name} protocol has been updated to: {new_api}') +PY local rc=$? case "$rc" in 0) - echo "✅The agreement has been tested and updated (subject to change)" start_gateway ;; 2) - echo "❌ Repair failed: provider does not exist or is not configured" + echo "❌ Switching failed: provider does not exist or is not configured" ;; 3) - echo "❌ Repair failed: provider configuration is incomplete" + echo "❌ Switching failed: protocol value is illegal" ;; *) - echo "❌ Repair failed: please check the configuration file structure or log output" + echo "❌ Switching failed: please check the configuration file structure or log output" ;; esac @@ -11384,7 +11270,8 @@ fix-openclaw-provider-protocol-interactive() { } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) send_stats "OpenClaw API delete entry" if [ ! -f "$config_file" ]; then @@ -11532,6 +11419,66 @@ PY break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API Vendor Recommendations" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API vendor recommendation list${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}Some entrances contain AFF${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_lv}● Supercomputing Internet${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" + echo -e " ${gl_huang}● Youyun Intelligent Computing${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" + echo -e " ${gl_huang}● Silicon based flow${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}● GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" + echo -e " ${gl_huang}● Cloud API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" + echo -e " ${gl_huang}● Plato AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Baishan Cloud${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}legend:${gl_lv}● Official entrance${gl_bai} ${gl_huang}● AFF recommended entrance${gl_bai}" + echo "" + echo -e "${gl_huang}Tip: Copy the link and open it in your browser to access it${gl_bai}" + echo "" + read -erp "Press Enter to return..." dummy + } + openclaw_api_manage_menu() { send_stats "OpenClaw API entrance" while true; do @@ -11543,8 +11490,9 @@ PY echo "---------------------------------------" echo "1. Add API" echo "2. Synchronize API provider model list" - echo "3. Delete API" - echo "4. Protocol repair/redetection" + echo "3. Switch API type (completions/responses)" + echo "4. Delete API" + echo "5. Recommended by API vendors" echo "0. Exit" echo "---------------------------------------" read -erp "Please enter your choice:" api_choice @@ -11557,10 +11505,13 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive + ;; + 5) + openclaw_api_providers_showcase ;; 0) return 0 @@ -11575,52 +11526,255 @@ PY - install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then - cat > /etc/yum.repos.d/charm.repo <<'REPO' -[charm] -name=Charm -baseurl=https://repo.charm.sh/yum/ -enabled=1 -gpgcheck=1 -gpgkey=https://repo.charm.sh/yum/gpg.key -REPO - rpm --import https://repo.charm.sh/yum/gpg.key - if command -v dnf >/dev/null 2>&1; then - dnf install -y gum - else - yum install -y gum - fi - elif command -v zypper >/dev/null 2>&1; then - zypper --non-interactive refresh - zypper --non-interactive install gum - fi - } + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + + if command -v apt >/dev/null 2>&1; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "Change model" + + local orange="#FF8C00" + + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "Available" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed + local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply + + oc_config=$(openclaw_get_config_file) + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="openclaw configuration file not found" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + request_model="${target_model#*/}" + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="provider/baseUrl/apiKey not read" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + first_endpoint="/responses" + second_endpoint="/chat/completions" + + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] +timeout = int(timeout) +url = base_url + endpoint +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } + + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(empty return)" + + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(empty return)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint}-> HTTP ${first_http:-0}, switch${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi - - change_model() { - send_stats "Change model" + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(empty return)" - local orange="#FF8C00" + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # Read model keys from configuration file (without calling openclaw models list) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then @@ -11637,53 +11791,55 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" + clear install_gum install gum - - clear - - # If gum does not exist, downgrade to the original manual input process (remaining exactly the same as before) - if ! command -v gum >/dev/null 2>&1; then + + # If gum does not exist, it will be downgraded to the original manual input process. + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "---Model Management ---" echo "Currently available models:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "Please enter the model name to set (e.g. openrouter/openai/gpt-4o) (enter 0 to exit):" selected_model - # 1. Check if you entered 0 to exit if [ "$selected_model" = "0" ]; then echo "Operation canceled, exiting..." - break # 跳出 while 循环 + break fi - # 2. Verify that the input is empty if [ -z "$selected_model" ]; then echo "Error: Model name cannot be empty. Please try again." - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue + fi + + echo "The model being switched is:$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "Switch failed: openclaw models set returned error." + break_end + return 1 fi + openclaw_sync_sessions_model "$selected_model" + start_gateway + + break_end + return 0 else + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then + echo "gum is unavailable, returning to the old input mode." + sleep 1 + continue + fi gum style --foreground "$orange" --bold "Model management" gum style --foreground "$orange" "Available models (Auth=yes):${model_count}" gum style --foreground "$orange" "Current default:${default_model}" echo "" - - # Bottom tip - gum style --faint "↑↓ Select / Enter to confirm / Esc to exit" + gum style --faint "↑↓ Select / Enter to test / Esc to exit" echo "" - # gum filter: with search; gum versions vary greatly, only the most compatible flags are used here - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "Search models (such as cli-api/gpt-5.2)" \ - --prompt "Select model >" \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "Search models (such as cli-api/gpt-5.2)" --prompt "Select model >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "Operation canceled, exiting..." @@ -11691,22 +11847,125 @@ REPO fi fi - # Remove the number prefix: "(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # Execute switch + echo "" + echo "Detecting model:$selected_model" + if openclaw_model_probe "$selected_model"; then + openclaw_probe_status_line "Available" + else + openclaw_probe_status_line "Not available" + fi + echo "state:$OPENCLAW_PROBE_MESSAGE" + echo "Delay:$OPENCLAW_PROBE_LATENCY" + echo "summary:$OPENCLAW_PROBE_REPLY" + echo "" + + printf "Switch to this model? [y/N, Esc returns to list]:" + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" + else + case "$confirm_switch" in + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "The model selection list has been returned." + sleep 1 + continue + fi + echo "The model being switched is:$selected_model ..." if ! openclaw models set "$selected_model"; then echo "Switch failed: openclaw models set returned error." break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end done - } + } + + + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ Synced$countThe session model of an agent is$model_ref" + return 0 + } resolve_openclaw_plugin_id() { local raw_input="$1" @@ -11724,12 +11983,8 @@ REPO local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11795,12 +12050,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11951,7 +12202,8 @@ PYTHON_EOF fi echo "📥 Not found locally, try to download and install:$plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ Download successful, activating..." if openclaw plugins enable "$plugin_id"; then @@ -12113,7 +12365,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12123,7 +12376,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12150,7 +12404,8 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi @@ -12200,7 +12455,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12220,19 +12476,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status @@ -12296,6 +12558,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "Local status (only local configuration/cache, no network detection):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "Lark" "$feishu_status" @@ -12303,6 +12584,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "WeChat (Weixin)" "$wx_status" } change_tg_bot_code() { @@ -12317,6 +12599,8 @@ openclaw_json_get_bool() { echo "1. Telegram robot docking" echo "2. Feishu (Lark) robot docking" echo "3. WhatsApp bot docking" + echo "4. QQ robot docking" + echo "5. WeChat robot docking" echo "----------------------------------------" echo "0. Return to the previous menu" echo "----------------------------------------" @@ -12331,10 +12615,9 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "Please enter the connection code received by Feishu Robot (for example, NYA99R2F) (enter 0 to exit):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json break_end ;; 3) @@ -12344,6 +12627,15 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + echo "QQ official docking address:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; @@ -12486,132 +12778,89 @@ EOF return 0 } + openclaw_get_all_agent_workspaces() { + local config_file + config_file=$(openclaw_get_config_file) + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY + else + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' + fi + } + openclaw_memory_backup_export() { send_stats "OpenClaw memory full backup" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ workspace directory not found:$workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "Does it come with AGENTS/USER/SOUL/TOOLS files? (y/N):" include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ No backup memory file found" - rm -rf "$tmp_payload" - break_end - return 1 + echo "❌ No backup memory file found"; rm -rf "$tmp_payload"; break_end; return 1 fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ Full memory backup completed:$out_file" - openclaw_offer_transfer_hint "$out_file" + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ Full memory backup completed (including multi-agent):$out_file"; openclaw_offer_transfer_hint "$out_file" else echo "❌ Full memory backup failed" fi - - rm -rf "$tmp_payload" - break_end - } - - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "You can first upload the backup package to the server through scp/sftp, and then enter the path." >&2 - echo "scp example: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 - echo "Tip: When entering a file name, it will be searched in the backup directory by default; when entering a path containing /, it will be verified by the full path." >&2 - read -e -p "Please enter the backup file name or path:" file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" - fi - - if [ ! -f "$file_path" ]; then - echo "❌ The backup file does not exist:$file_path" >&2 - echo "" - return 1 - fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { send_stats "OpenClaw memory full restoration" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "Before restoration, it will be performed: type verification + sha256 verification + path whitelist verification") - [ -z "$archive_path" ] && { echo "❌ No backup path entered"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ Illegal or unauthorized path detected:$rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ Restore aborted: Insecure path exists" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ Full memory restoration completed" - break_end + local archive_path=$(openclaw_read_import_path "Restore the full amount of memory (supports multi-agent)") + [ -z "$archive_path" ] && { echo "❌ No path entered"; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ Agent memory restored: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ Full memory restoration completed"; break_end } + openclaw_project_backup_export() { send_stats "OpenClaw project backup" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then echo "❌ OpenClaw root directory not found:$openclaw_root" break_end @@ -12670,7 +12919,10 @@ EOF openclaw_project_backup_import() { send_stats "OpenClaw project restore" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" echo "⚠️ High-risk operation: Project restore will overwrite OpenClaw configuration and workspace content." @@ -12764,7 +13016,7 @@ EOF echo "Backup directory:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "No backup file yet" + echo "No backup files yet" return 0 fi @@ -12908,7 +13160,15 @@ EOF } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -12938,9 +13198,78 @@ EOF openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - "$agents_json" <<'PY' +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -12957,58 +13286,107 @@ EOF fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ The index library file was not found, it may be empty or does not exist." + echo "⚠️ [$agent_id] Index library file not found, may be empty or non-existent." echo "Store raw value: ${store_raw:-}" echo "Reindexing will still be performed." else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ Index backed up:$backup_file" + echo "✅ [$agent_id] Index backed up:$backup_file" else - echo "⚠️ Index backup failed, continue to rebuild." + echo "⚠️ [$agent_id] Index backup failed, continue rebuilding." fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" + openclaw gateway restart + echo "✅ The index has been rebuilt and the gateway has been automatically restarted." + echo "" + openclaw_memory_render_status + } + + openclaw_memory_rebuild_index_all() { + local count=0 + local agent_lines agent_id workspace + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done </dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "Failed to get status" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /Underlying solution: /' -e 's/^Vector: /Vector library status: /' -e 's/^Indexed: /Included files: /') + local agent_lines agent_id workspace status_output status_lines first="true" + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "Failed to get status" + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /Underlying solution: /' -e 's/^Vector: /Vector library status: /' -e 's/^Indexed: /Included files: /' -e 's/^Workspace: /workspace: /' -e 's/^Store: /index library: /') if [ -z "$status_lines" ]; then echo "Not installed/not started" else echo "$status_lines" fi - fi + done </dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd already exists:$qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd already exists and is available:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ The qmd command exists but the module is damaged, reinstall..." + fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ Install qmd via bun:$qmd_url" - bun install -g "$qmd_url" + echo "⬇️ Install qmd via npm: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then echo "❌ qmd installation failed" return 1 fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ qmd still cannot run after installation" + return 1 + fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" echo "✅ qmd installation completed:$qmd_path" return 0 @@ -13355,8 +13736,15 @@ EOF fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 Warm index (possibly download models)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + local preh_agent_lines preh_agent_id preh_workspace + preh_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r preh_agent_id preh_workspace; do + [ -z "$preh_agent_id" ] && continue + openclaw memory index --agent "$preh_agent_id" --force + done </dev/null 2>&1; then echo "⚠️ The current scheme is detected as QMD, but the qmd command is not installed." echo "You can switch to Local, or install bun + qmd and try again." fi - echo "Applicable scenarios: Indexed numerator > denominator (repeated collections lead to abnormal counting)" - read -e -p "Are you sure you set includeDefaultMemory to false? (y/N):" confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "Canceled." - break_end - return 0 - fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ Failed to write configuration" - break_end - return 1 - fi - echo "✅ includeDefaultMemory=false set" - echo "Recommended execution: Clean and rebuild the index" - read -e -p "Do you want to clean and rebuild the index (recommended)? (Y/n):" rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "Index repair diagnostics" + echo "=======================================" + echo "Current includeDefaultMemory: ${include_dm:-not set}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ includeDefaultMemory=false detected" + echo "This causes the default memory files (MEMORY.md + memory/*.md) to not be indexed" + echo "So Indexed will always display 0/N" + echo "" + read -e -p "Revert to true and rebuild the index? (Y/n):" fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ Failed to write configuration" + break_end + return 1 + fi + echo "✅ Restored includeDefaultMemory=true" + openclaw_memory_rebuild_index_all + else + echo "Canceled." + fi else - echo "The status can be viewed later in memory management." + echo "includeDefaultMemory configuration is normal." + echo "Will be executed: Clean old indexes → Fully rebuild all agent indexes" + echo "" + read -e -p "Confirm execution? (Y/n):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "Canceled." + fi fi break_end } @@ -13632,30 +14041,42 @@ EOF openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done </dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13692,7 +14113,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ The number of rows must be greater than 0." + echo "❌ Number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -13765,18 +14186,25 @@ EOF break_end continue fi - openclaw_memory_prepare_workspace + openclaw_memory_prepare_workspace_all read -e -p "Secondary confirmation: Enter force to use the full amount (leave blank for increment):" confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ Full reconstruction is more thorough, but takes longer." echo "Recommendation: Enter rebuild for safe reconstruction (back up the index database first)." read -e -p "Third confirmation: Enter rebuild to perform a safe rebuild; press Enter to continue with normal force:" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + local fl_agent_lines fl_agent_id fl_workspace + fl_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r fl_agent_id fl_workspace; do + [ -z "$fl_agent_id" ] && continue + openclaw memory index --agent "$fl_agent_id" --force + done </dev/null 2>&1 || { + echo "⚠️ Permission backup failed:$backup_file" + return 1 + } + echo "✅ Current permission configuration has been backed up:$backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ No restoreable rights backup file found." + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ Permission recovery failed:$backup_file" + return 1 + } + echo "✅ The permission configuration before the switch has been restored" + openclaw_permission_restart_gateway || true + return 0 + } + + openclaw_permission_restart_gateway() { + if ! openclaw_has_command openclaw; then + echo "❌ openclaw is not detected and OpenClaw Gateway cannot be restarted." + return 1 + fi + echo "Restarting OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>&1 | head -n 1) + if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 0; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + return 0 + fi + + echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then + return 0 + fi + return 1 + } + + openclaw_permission_detect_mode() { + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "Unknown mode"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("Standard safe mode") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("Develop enhanced mode") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("Fully open mode") + else: + print("Custom mode") +except Exception: + print("Custom mode") +PY + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "Configuration file:$config_file" + [ ! -s "$config_file" ] && echo "⚠️ OpenClaw configuration file not found (may not have been initialized yet)." + echo "Current mode:$mode" + echo "---------------------------------------" + + # Use Python to efficiently parse all permission fields at once + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) + +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except Exception as e: + print("❌ Configuration file parsing failed: %s" % e) +PY + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw Permissions - Standard Security Mode" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ Switching failed: An error occurred during write permission configuration." + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" + return 1 + fi + echo "✅ Switched to standard safety mode" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw Permissions - Development Enhanced Mode" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ Switching failed: An error occurred during write permission configuration." + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" + return 1 + fi + echo "✅ Switched to development enhancement mode" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw Permissions - Fully Open Mode" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ Switching failed: An error occurred during write permission configuration." + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" + return 1 + fi + echo "✅ Switched to fully open mode" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw permissions-restore official default" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ Recovery failed: An error occurred while cleaning explicit permission overrides." + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" + return 1 + fi + echo "✅ Reverted to OpenClaw official default strategy (cleared explicit overrides)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw Permissions-Security Audit" + openclaw_permission_require_openclaw || return 1 + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw permission management" + while true; do + clear + echo "=======================================" + echo "OpenClaw permission management" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1. Switch to standard safe mode (recommended)" + echo "2. Switch to development enhancement mode" + echo "3. Switch to fully open mode (high risk)" + echo "4. Restore official default strategy" + echo "5. Run a security audit" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" perm_choice + case "$perm_choice" in + 1) + echo "Will apply: Standard security mode" + read -e -p "Enter yes to confirm:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "Canceled" + break_end + ;; + 2) + echo "Will apply: development enhancement mode" + read -e -p "Enter yes to confirm:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "Canceled" + break_end + ;; + 3) + echo "⚠️ Fully open mode will turn off exec approval, enable privilege escalation and bash, and is only recommended for trusted single-user environments." + read -e -p "Enter FULL to confirm to continue:" confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "Canceled" + break_end + ;; + 4) + echo "Override explicit permissions written by cleanup scripts, reverting to the official OpenClaw default policy." + read -e -p "Enter yes to confirm:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "Canceled" + break_end + ;; + 5) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "Invalid selection, please try again." + sleep 1 + ;; + esac + done + } + + openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ The openclaw command is not detected, please install or initialize OpenClaw first." + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "Configuration file: ${config_file:-$(openclaw_permission_config_file)}" + echo "Default agent:$default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("Number of configured agents: %s" % len(agents)); print("Number of route bindings: %s" % len(bindings)); print("Total sessions: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("No multi-agent is currently configured.") +else: + import itertools + for item in itertools.islice(agents, 8): + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- Agent ID: [1;36m%s [0m" % item.get("id","?")); print("Identity name: %s %s" % (identity, emoji)); print("Working directory: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw Multi-Agent - List Agents" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("No Agent has been configured yet."); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw multi-agent-new Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "Please enter new Agent ID:" agent_id + [ -z "$agent_id" ] && echo "Canceled: Agent ID cannot be empty." && return 1 + read -e -p "Please enter the workspace path (default ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "The agent will be created:$agent_id" + echo "Working directory:$workspace" + read -e -p "Enter yes to confirm to continue:" confirm + [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ The agent was created successfully:$agent_id" + local name theme + read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name + [ -z "$name" ] && name="$agent_id" + read -e -p "Please enter the agent personality theme (eg: rigorous, efficient):" theme + [ -z "$theme" ] && theme="assistant" + echo "Configuring agent identity..." + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" + else + echo "❌ Agent creation failed" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw multi-agent-delete agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "Please enter the Agent ID to delete:" agent_id + [ -z "$agent_id" ] && echo "Canceled: Agent ID cannot be empty." && return 1 + echo "⚠️ Deleting an agent may affect its working directory, route bindings, and session routing." + read -e -p "Enter DELETE to confirm deletion${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "Canceled"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ Agent deleted successfully:$agent_id" + else + echo "❌ Agent deletion failed" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw multi-agent - view routing bindings" + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("There is no route binding yet."); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw multi-agent-new routing binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "Please enter the agent ID:" agent_id + read -e -p "Please enter the route binding value (such as telegram:ops / discord:guild-a):" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "Canceled: Parameter cannot be empty." && return 1 + echo "Will bind the agent [$agent_id] -> [$bind_value]" + read -e -p "Enter yes to confirm to continue:" confirm + [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Route binding added successfully" + else + echo "❌ Failed to add route binding" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw multi-agent - remove routing binding" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "Please enter the agent ID:" agent_id + read -e -p "Please enter the route binding value to be removed:" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "Canceled: Parameter cannot be empty." && return 1 + echo "will remove the agent [$agent_id] route binding [$bind_value]" + read -e -p "Enter yes to confirm to continue:" confirm + [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ Route binding removed successfully" + else + echo "❌ Route binding removal failed" + return 1 + fi + } + + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw Multi-Agent - Session Overview" + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("There is no session data yet."); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("Session summary:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw Multi-Agent-Health Check" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "Check the configuration file: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ Configuration verification failed, please check the output above." + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ No configured agent found."); +else: + for item in agents: + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) +print("Number of route bindings=%s" % len(bindings)); print("✅Multi-agent health check completed")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw multi-agent management" + while true; do + clear + echo "=======================================" + echo "OpenClaw multi-agent management" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. Add new intelligent agent" + echo "2. Delete the agent" + echo "3. View routing bindings" + echo "4. Add new route binding" + echo "5. Remove route binding" + echo "6. View session overview" + echo "7. Run multi-agent health checks" + echo "0. Return to the previous level" + echo "---------------------------------------" + read -e -p "Please enter your choice:" multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "Invalid selection, please try again."; sleep 1 ;; + esac + done + } + + +openclaw_backup_restore_menu() { send_stats "OpenClaw backup and restore" while true; do @@ -13842,8 +15022,8 @@ EOF echo "Update OpenClaw..." send_stats "Update OpenClaw..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -13860,7 +15040,8 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ It is detected that /root/.openclaw still exists in the root directory. If you need to clean it, please handle it manually." hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "Uninstall completed" @@ -13870,7 +15051,7 @@ EOF nano_openclaw_json() { send_stats "Edit the OpenClaw configuration file" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -13945,7 +15126,7 @@ EOF read echo -e "${gl_kjlan}Loading device list...${gl_bai}" # Automatically add domain names to allowedOrigins - config_file="$HOME/.openclaw/openclaw.json" + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" # Use jq to safely modify JSON to ensure that the structure exists and domain names are not added repeatedly @@ -14048,9 +15229,11 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done @@ -16205,7 +17388,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -16608,7 +17791,7 @@ while true; do docker_rum() { - read -e -p "set up${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "set up${docker_name}Login key (sk-a combination of letters and numbers starting with) such as: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -16789,7 +17972,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18686,7 +19869,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -18872,8 +20055,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -20132,7 +21315,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -20650,6 +21833,9 @@ else linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a6bcf0ff9..4ec4c7822 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.9" gl_hui='\e[37m' @@ -61,7 +61,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -254,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -924,12 +924,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -2231,10 +2231,10 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" + echo "CF パラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -3215,7 +3215,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3284,7 +3284,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3690,7 +3690,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "レイヤー 4 プロキシを追加する" + send_stats "レイヤ 4 プロキシを追加する" ;; 5) send_stats "転送設定の編集" @@ -3746,7 +3746,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3957,7 +3957,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4304,7 +4304,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4773,7 +4773,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5468,7 +5468,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5850,7 +5850,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6243,7 +6243,7 @@ optimize_web_server() { _kernel_optimize_core "ウェブサイト構築最適化モード" "web" } -# ── 还原默认设置(完全清理) ── +# ── 初期設定に戻す(完全クリーン) ── restore_defaults() { echo -e "${gl_lv}デフォルト設定に戻す...${gl_bai}" @@ -6279,7 +6279,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" + send_stats "Linux カーネルのチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6421,7 +6421,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6726,7 +6726,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7049,7 +7049,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -7207,7 +7207,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7226,7 +7226,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7386,7 +7386,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモート ホストにアクセスできますか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7395,7 +7395,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7485,7 +7485,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7547,7 +7547,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7667,7 +7667,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7727,7 +7727,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7785,7 +7785,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncdu をインストールする" + send_stats "ncduをインストールする" ;; 14) clear @@ -8029,7 +8029,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8206,7 +8206,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8238,7 +8238,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8735,7 +8735,7 @@ linux_test() { 32) send_stats "Spiritysdx フュージョンモンスター レビュー" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) @@ -10035,7 +10035,8 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "🦞 KEJILION による OPENCLAW 管理ツール 🦞" + echo -e "💡 ターミナル実行 \033[1;33mk 爪\033[0m ですぐにメニューに入ります" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. インストール" @@ -10054,10 +10055,12 @@ moltbot_menu() { echo "13. WebUI へのアクセスと設定" echo "14. TUIコマンドラインダイアログウィンドウ" echo "15. 記憶・記憶" + echo "16. 権限管理" + echo "17. マルチエージェント管理" echo "--------------------" - echo "16. バックアップと復元" - echo "17. アップデート" - echo "18. アンインストール" + echo "18. バックアップと復元" + echo "19. アップデート" + echo "20. アンインストール" echo "--------------------" echo "0. 前のメニューに戻る" echo "--------------------" @@ -10088,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10119,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10139,36 +10144,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10302,7 +10277,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10331,36 +10306,6 @@ def delete_provider_and_refs(name): return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10403,16 +10348,6 @@ for name, provider in list(providers.items()): api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: プロトコルは自動的に {detected_api} ({detected_reason}) に修正されました') - except Exception as e: - summary.append(f'⚠️ {name}: プロトコルの検出に失敗しました。修正をスキップします ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models の検出に失敗しました。{attempts} 回再試行しました ({type(err).__name__}: {err})') @@ -10459,15 +10394,6 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ 新しいモデルを追加します ({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ モデルを削除します ({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10514,7 +10440,17 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(removed_ids)} を削除、{len(added_ids)} を追加、現在の {len(new_models)}') + summary.append(f'✅ {name}: {len(added_ids)} を追加、{len(removed_ids)} を削除、現在は {len(new_models)}') + + if added_ids: + summary.append(f'➕ 新しいモデルを追加します ({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ モデルを削除します ({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + if fatal_errors: for line in summary: @@ -10543,6 +10479,7 @@ PY install_moltbot() { echo "OpenClaw のインストールを開始します..." send_stats "OpenClaw のインストールを開始します..." + install git jq install_node_and_tools @@ -10551,12 +10488,13 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # ヒント: 構成を変更してすぐに有効にする必要がある場合は、ゲートウェイを再起動します: openclaw ゲートウェイの再起動 configure_openclaw_session_policy start_gateway @@ -10594,91 +10532,23 @@ PY - # OpenClaw API プロトコル検出 (優先応答 -> 完了) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" - - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" - return 0 - } + # OpenClaw API プロトコル検出ロジックが削除されました。API タイプは自動的に検出/決定されなくなりました。 + # 注: API タイプはユーザー (models.providers..api) によって明示的に構成され、スクリプトは推論のために /responses を呼び出そうとしなくなりました。 - # コア機能: すべてのモデルの取得と追加 - add-all-models-from-provider() { + # モデル構成 JSON の構築 + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 取得中$provider_name利用可能なすべてのモデル..." - - # API プロトコルを自動的に識別する - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" - - # モデルリストの取得 - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ モデルリストを取得できません" - return 1 - fi - - # すべてのモデル ID を抽出します - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ モデルが見つかりません" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 発見する$model_countモデル" - - # モデルパラメータのインテリジェントな推論 + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context と max_tokens は完全にロードされているため、大きな問題を恐れる必要はありません local context_window=1048576 local max_tokens=128000 - - # 評価する必要があるのは価格だけです local input_cost=0.15 local output_cost=0.60 @@ -10716,11 +10586,23 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # プロバイダーとモデルの構成を書き込む + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file + config_file=$(openclaw_get_config_file) + + # API プロトコルを自動的に検出/修正しなくなりました。ユーザー設定を維持します + DETECTED_API="openai-completions" - # バックアップ構成 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # jq を使用してすべてのモデルを挿入し、defaults.models を同期します。 jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10754,6 +10636,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # コア機能: すべてのモデルの取得と追加 + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 取得中$provider_name利用可能なすべてのモデル..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ モデルリストを取得できません" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ モデルが見つかりません" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 発見する$model_countモデル" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ 正常に追加されました$model_countモデルが到着$provider_name" @@ -10765,6 +10680,33 @@ EOF fi } + # デフォルトのモデルのみを追加し、プロバイダーはそのままにします + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ デフォルトのモデルを空にすることはできません" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ プロバイダーが追加しました:$provider_name" + echo "✅ デフォルトのモデルにのみ書き込みます:$default_model" + return 0 + else + echo "❌ 構成の挿入に失敗しました" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API が追加されました" echo "=== OpenClaw プロバイダー (フルモデル) を対話的に追加 ===" @@ -10793,9 +10735,7 @@ EOF echo done - # 4. プロトコル検出 (無意味) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. API タイプを検出/決定しなくなりました。プロトコルはユーザー自身によって選択および維持されます # 5. モデルリストの取得 echo "🔍 利用可能なモデルのリストを取得中..." @@ -10824,7 +10764,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -10846,22 +10786,27 @@ EOF echo "モデルの総数:$model_count" echo "======================" - read -erp "すべて追加することを確認します$model_countA model? (y/N):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ キャンセルされました" - return 1 - fi + read -erp "他の利用可能なモデルをすべて同時に追加しますか? (y/N):" confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅完了!全て$model_countロードされたモデル" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅完了!プロバイダーは保持され、デフォルトのモデルのみがロードされます。$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo - echo "🔄 设置默认模型并重启网关..." + echo "🔄 デフォルトのモデルを設定し、ゲートウェイを再起動します..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway - echo "✅完了!全て$model_countロードされたモデル" - echo "✅ 契約は次のように自動的に識別されます。$DETECTED_API" + echo "$finish_msg" + echo "✅ 現在の API プロトコルの種類:$DETECTED_API" fi break_end @@ -10996,15 +10941,15 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "同期する API 名 (プロバイダー) 、Enterで全部同期: " provider_name + read -erp "同期する API 名 (プロバイダー) を入力し、Enter キーを押してすべてを同期してください。" provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ APIモデル同期失敗、ゲートウェイ再起動中止。provider /modelsを確認后再試行してください。" - break_end + echo "❌ API モデルの同期に失敗しました。ゲートウェイの再起動は中止されました。プロバイダー/モデルを確認し、戻ってからもう一度お試しください。" return 1 fi + break_end return 0 fi @@ -11021,35 +10966,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11133,19 +11049,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ プロバイダー {target} の現在の api={api}、プロトコルを再検出して続行します') - provider['api'] = '' - api = '' + print(f'ℹ️ プロバイダー {target} は現在 api={api} ですが、スクリプトはプロトコルを検出/修正しなくなりました。手動で openai-completions または openai-responses に設定してください。') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 自動修正されたプロトコル: {target} {api} ({detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ プロトコルの検出に失敗しました。修正をスキップしました: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: @@ -11177,15 +11083,6 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ 新しいモデルを追加します ({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ モデルを削除します ({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11232,15 +11129,23 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: {len(removed_ids)} を削除、{len(added_ids)} を追加、現在の {len(new_models)}') +print(f'✅ {target}: {len(added_ids)} を追加、{len(removed_ids)} を削除、現在の {len(new_models)}') + +if added_ids: + print(f'➕ 新しいモデルを追加します ({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ モデルを削除します ({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: print('✅ 指定されたプロバイダーモデルの整合性同期が完了し、設定が書き込まれました') else: @@ -11249,7 +11154,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行が完了しました" + echo "✅ 同期実行完了" start_gateway ;; 2) @@ -11265,7 +11170,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11273,85 +11178,15 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ openclaw.json が見つかりません') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ プロバイダー: {name} が見つかりません') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ プロバイダー {name} に BaseUrl/apiKey がありません') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ プロバイダー {name} プロトコルを更新しました: {current_api または "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ 更新は必要ありません: プロトコルは {current_api または api} のままです') -PY + # プロトコル検出ロジックが削除されました。スクリプトは API タイプを自動的に検出/決定しなくなりました。 + # この関数はメニュー呼び出しとの互換性のために残されていますが、書き換えは行われません。 + echo "ℹ️ プロトコル検出がオフになっています: 手動で行ってください${HOME}/.openclaw/openclaw.json の Provider.api を openai-completions または openai-responses に設定します" + return 0 } fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API プロトコルの修正" + send_stats "OpenClaw APIプロトコルの切り替え" if [ ! -f "$config_file" ]; then echo "❌ 設定ファイルが見つかりません:$config_file" @@ -11359,29 +11194,75 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - read -erp "修復するプロトコルの API 名 (プロバイダー) を入力してください:" provider_name + read -erp "プロトコルを切り替えるための API 名 (プロバイダー) を入力してください:" provider_name if [ -z "$provider_name" ]; then echo "❌ プロバイダー名を空にすることはできません" break_end return 1 fi - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "設定したい API タイプを選択してください:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "選択肢を入力してください (1/2):" proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ 選択が無効です" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ 不正なプロトコル値') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ プロバイダー: {name} が見つかりません') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ プロバイダー {name} プロトコルが {new_api} に更新されました。') +PY local rc=$? case "$rc" in 0) - echo "✅契約はテストされ、更新されています(変更される可能性があります)" start_gateway ;; 2) - echo "❌ 修復に失敗しました: プロバイダーが存在しないか、構成されていません" + echo "❌ 切り替えに失敗しました: プロバイダーが存在しないか、構成されていません" ;; 3) - echo "❌ 修復に失敗しました: プロバイダーの構成が不完全です" + echo "❌ 切り替えに失敗しました: プロトコル値が不正です" ;; *) - echo "❌ 修復に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + echo "❌ 切り替えに失敗しました: 設定ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11389,7 +11270,8 @@ fix-openclaw-provider-protocol-interactive() { } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) send_stats "OpenClaw API エントリの削除" if [ ! -f "$config_file" ]; then @@ -11537,6 +11419,66 @@ PY break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API ベンダーの推奨事項" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 APIベンダー推奨リスト${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}一部の入り口にはAFFが含まれています${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_lv}● スーパーコンピューティング インターネット${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" + echo -e " ${gl_huang}● ユユン インテリジェント コンピューティング${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" + echo -e " ${gl_huang}●シリコンベースのフロー${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}●GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" + echo -e " ${gl_huang}● クラウドAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" + echo -e " ${gl_huang}●プラトンAI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}●白山雲${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}伝説:${gl_lv}●正式な入り口${gl_bai} ${gl_huang}●AFF推奨入口${gl_bai}" + echo "" + echo -e "${gl_huang}ヒント: リンクをコピーし、ブラウザで開いてアクセスします。${gl_bai}" + echo "" + read -erp "戻るには Enter を押してください..." dummy + } + openclaw_api_manage_menu() { send_stats "OpenClaw APIの入口" while true; do @@ -11548,8 +11490,9 @@ PY echo "---------------------------------------" echo "1. APIの追加" echo "2. APIプロバイダーモデルリストを同期する" - echo "3. APIの削除" - echo "4. プロトコルの修復/再検出" + echo "3. API タイプの切り替え (完了/応答)" + echo "4. APIの削除" + echo "5. APIベンダーによる推奨" echo "0.終了" echo "---------------------------------------" read -erp "選択肢を入力してください:" api_choice @@ -11562,10 +11505,13 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive + ;; + 5) + openclaw_api_providers_showcase ;; 0) return 0 @@ -11580,52 +11526,255 @@ PY - install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then - cat > /etc/yum.repos.d/charm.repo <<'REPO' -[charm] -name=Charm -baseurl=https://repo.charm.sh/yum/ -enabled=1 -gpgcheck=1 -gpgkey=https://repo.charm.sh/yum/gpg.key -REPO - rpm --import https://repo.charm.sh/yum/gpg.key - if command -v dnf >/dev/null 2>&1; then - dnf install -y gum - else - yum install -y gum - fi - elif command -v zypper >/dev/null 2>&1; then - zypper --non-interactive refresh - zypper --non-interactive install gum - fi - } + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + + if command -v apt >/dev/null 2>&1; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "機種変更" + + local orange="#FF8C00" + + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "利用可能" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed + local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply + + oc_config=$(openclaw_get_config_file) + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="openclaw 設定ファイルが見つかりません" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + request_model="${target_model#*/}" + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="Provider/baseUrl/apiKey が読み込まれていません" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + first_endpoint="/responses" + second_endpoint="/chat/completions" + + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] +timeout = int(timeout) +url = base_url + endpoint +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } + + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空のリターン)" + + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空のリターン)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint}-> HTTP ${first_http:-0}、スイッチ${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi - - change_model() { - send_stats "機種変更" + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空のリターン)" - local orange="#FF8C00" + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # 構成ファイルからモデル キーを読み取ります (openclaw モデル リストを呼び出すことなく) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then @@ -11642,53 +11791,55 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" + clear install_gum install gum - - clear - - # ガムが存在しない場合は、元の手動入力プロセスにダウングレードします (以前とまったく同じままです)。 - if ! command -v gum >/dev/null 2>&1; then + + # ガムが存在しない場合は、元の手入力プロセスにダウングレードされます。 + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "---モデル管理---" echo "現在入手可能なモデル:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "設定するモデル名を入力してください (例: openrouter/openai/gpt-4o) (終了するには 0 を入力します):" selected_model - # 1.終了するには0を入力したかどうかを確認します if [ "$selected_model" = "0" ]; then echo "操作がキャンセルされました。終了しています..." - break # 跳出 while 循环 + break fi - # 2. 入力が空であることを確認します if [ -z "$selected_model" ]; then echo "エラー: モデル名を空にすることはできません。もう一度試してください。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue + fi + + echo "切り替わる機種は以下の通りです。$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切り替えに失敗しました: openclaw モデル セットがエラーを返しました。" + break_end + return 1 fi + openclaw_sync_sessions_model "$selected_model" + start_gateway + + break_end + return 0 else + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then + echo "ガムは使用できなくなり、古い入力モードに戻ります。" + sleep 1 + continue + fi gum style --foreground "$orange" --bold "モデル管理" gum style --foreground "$orange" "利用可能なモデル (認証=はい):${model_count}" gum style --foreground "$orange" "現在のデフォルト:${default_model}" echo "" - - # ボトムチップ - gum style --faint "↑↓ 選択 / Enter で確認 / Esc で終了" + gum style --faint "↑↓ 選択 / Enter でテスト / Esc で終了" echo "" - # ガムフィルター: 検索付き;ガムのバージョンは大きく異なります。ここでは最も互換性のあるフラグのみが使用されます - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "モデルの検索 (cli-api/gpt-5.2 など)" \ - --prompt "モデルを選択 >" \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "モデルの検索 (cli-api/gpt-5.2 など)" --prompt "モデルを選択 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作がキャンセルされました。終了しています..." @@ -11696,22 +11847,125 @@ REPO fi fi - # 番号の接頭辞を削除します: 「(10) モデル」 -> 「モデル」 selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # スイッチの実行 + echo "" + echo "検出モデル:$selected_model" + if openclaw_model_probe "$selected_model"; then + openclaw_probe_status_line "利用可能" + else + openclaw_probe_status_line "利用不可" + fi + echo "州:$OPENCLAW_PROBE_MESSAGE" + echo "遅れ:$OPENCLAW_PROBE_LATENCY" + echo "まとめ:$OPENCLAW_PROBE_REPLY" + echo "" + + printf "このモデルに切り替えますか? [y/N、Esc でリストに戻る]:" + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" + else + case "$confirm_switch" in + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "モデル選択リストが返されました。" + sleep 1 + continue + fi + echo "切り替わる機種は以下の通りです。$selected_model ..." if ! openclaw models set "$selected_model"; then echo "切り替えに失敗しました: openclaw モデル セットがエラーを返しました。" break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end done - } + } + + + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ 同期済み$countエージェントのセッション モデルは次のとおりです。$model_ref" + return 0 + } resolve_openclaw_plugin_id() { local raw_input="$1" @@ -11729,12 +11983,8 @@ REPO local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11800,12 +12050,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11891,7 +12137,7 @@ PYTHON_EOF echo "- [whatsapp] #WhatsApp オートメーション" echo "" echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル取得)" + echo "- [memory-core] # 基本メモリ (ファイル検索)" echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" @@ -11956,7 +12202,8 @@ PYTHON_EOF fi echo "📥 ローカルに見つかりません。ダウンロードしてインストールしてください:$plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ ダウンロードに成功しました。アクティブ化しています..." if openclaw plugins enable "$plugin_id"; then @@ -12118,7 +12365,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12128,7 +12376,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12155,7 +12404,8 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi @@ -12205,7 +12455,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12225,19 +12476,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status @@ -12301,6 +12558,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "ローカル ステータス (ローカル構成/キャッシュのみ、ネットワーク検出なし):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "ヒバリ" "$feishu_status" @@ -12308,6 +12584,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "WeChat (微信)" "$wx_status" } change_tg_bot_code() { @@ -12322,6 +12599,8 @@ openclaw_json_get_bool() { echo "1. テレグラムロボットドッキング" echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" + echo "4. QQロボットドッキング" + echo "5.WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12336,10 +12615,9 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "Feishu Robot が受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力します)。" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json break_end ;; 3) @@ -12349,6 +12627,15 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + echo "QQ の公式ドッキング アドレス:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; @@ -12491,132 +12778,89 @@ EOF return 0 } + openclaw_get_all_agent_workspaces() { + local config_file + config_file=$(openclaw_get_config_file) + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY + else + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' + fi + } + openclaw_memory_backup_export() { send_stats "OpenClaw メモリの完全バックアップ" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ ワークスペース ディレクトリが見つかりません:$workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "AGENTS/USER/SOUL/TOOLS ファイルは付属していますか? (y/N):" include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ バックアップメモリ​​ファイルが見つかりません" - rm -rf "$tmp_payload" - break_end - return 1 + echo "❌ バックアップメモリ​​ファイルが見つかりません"; rm -rf "$tmp_payload"; break_end; return 1 fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ メモリ全体のバックアップが完了しました:$out_file" - openclaw_offer_transfer_hint "$out_file" + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ フルメモリバックアップが完了しました (マルチエージェントを含む):$out_file"; openclaw_offer_transfer_hint "$out_file" else echo "❌ フルメモリバックアップに失敗しました" fi - - rm -rf "$tmp_payload" - break_end - } - - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "まず scp/sftp 経由でバックアップ パッケージをサーバーにアップロードし、次にパスを入力します。" >&2 - echo "scp の例: scp /local/backup package.tar.gz root@yourserver:/tmp/" >&2 - echo "ヒント: ファイル名を入力すると、デフォルトではバックアップ ディレクトリ内で検索されます。 / を含むパスを入力すると、フルパスで検証されます。" >&2 - read -e -p "バックアップ ファイル名またはパスを入力してください:" file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" - fi - - if [ ! -f "$file_path" ]; then - echo "❌ バックアップ ファイルが存在しません:$file_path" >&2 - echo "" - return 1 - fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { send_stats "OpenClaw メモリ完全復元" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "復元前に、タイプ検証 + sha256 検証 + パス ホワイトリスト検証が実行されます。") - [ -z "$archive_path" ] && { echo "❌ バックアップ パスが入力されていません"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 違法または無許可のパスが検出されました:$rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ 復元は中止されました: 安全でないパスが存在します" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ 完全なメモリ復元が完了しました" - break_end + local archive_path=$(openclaw_read_import_path "メモリの全量を復元します (マルチエージェントをサポート)") + [ -z "$archive_path" ] && { echo "❌ パスが入力されていません"; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ エージェントの記憶が復元されました: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ 完全なメモリ復元が完了しました"; break_end } + openclaw_project_backup_export() { send_stats "OpenClaw プロジェクトのバックアップ" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then echo "❌ OpenClaw ルート ディレクトリが見つかりません:$openclaw_root" break_end @@ -12675,7 +12919,10 @@ EOF openclaw_project_backup_import() { send_stats "OpenClaw プロジェクトの復元" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" echo "⚠️ リスクの高い操作: プロジェクトを復元すると、OpenClaw 構成とワークスペースのコンテンツが上書きされます。" @@ -12769,7 +13016,7 @@ EOF echo "バックアップディレクトリ:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "まだバックアップファイルがありません" + echo "バックアップファイルはまだありません" return 0 fi @@ -12913,7 +13160,15 @@ EOF } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -12943,9 +13198,78 @@ EOF openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - "$agents_json" <<'PY' +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -12962,58 +13286,107 @@ EOF fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ インデックス ライブラリ ファイルが見つかりませんでした。空であるか、存在しない可能性があります。" + echo "⚠️ [$agent_id] インデックス ライブラリ ファイルが見つかりません。空か存在しない可能性があります。" echo "生の値を保存: ${store_raw:-}" echo "インデックスの再作成は引き続き実行されます。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ インデックスのバックアップ:$backup_file" + echo "✅ [$agent_id] インデックスがバックアップされました:$backup_file" else - echo "⚠️ インデックスのバックアップに失敗しました。再構築を続けてください。" + echo "⚠️ [$agent_id] インデックスのバックアップに失敗しました。再構築を続行します。" fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" + openclaw gateway restart + echo "✅ インデックスが再構築され、ゲートウェイが自動的に再起動されました。" + echo "" + openclaw_memory_render_status + } + + openclaw_memory_rebuild_index_all() { + local count=0 + local agent_lines agent_id workspace + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done </dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "ステータスの取得に失敗しました" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^プロバイダ: /基礎となるソリューション: /' -e 's/^Vector: /Vector ライブラリのステータス: /' -e 's/^インデックス付き: /含まれるファイル: /') + local agent_lines agent_id workspace status_output status_lines first="true" + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "ステータスの取得に失敗しました" + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^プロバイダ: /基礎となるソリューション: /' -e 's/^Vector: /Vector ライブラリのステータス: /' -e 's/^インデックス付き: /含まれるファイル: /' -e 's/^ワークスペース: /ワークスペース: /' -e 's/^ストア: /index ライブラリ: /') if [ -z "$status_lines" ]; then echo "インストールされていない/起動されていない" else echo "$status_lines" fi - fi + done </dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd はすでに存在します:$qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd はすでに存在しており、利用可能です。$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ qmd コマンドは存在しますが、モジュールが破損しています。再インストールしてください..." + fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ bun 経由で qmd をインストールします。$qmd_url" - bun install -g "$qmd_url" + echo "⬇️ npm 経由で qmd をインストールします: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then echo "❌ qmd のインストールに失敗しました" return 1 fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ インストール後も qmd が実行できない" + return 1 + fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" echo "✅ qmd のインストールが完了しました:$qmd_path" return 0 @@ -13360,8 +13736,15 @@ EOF fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 ウォームインデックス (おそらくダウンロードモデル)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + local preh_agent_lines preh_agent_id preh_workspace + preh_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r preh_agent_id preh_workspace; do + [ -z "$preh_agent_id" ] && continue + openclaw memory index --agent "$preh_agent_id" --force + done </dev/null 2>&1; then echo "⚠️ 現在のスキームは QMD として検出されますが、qmd コマンドがインストールされていません。" echo "ローカルに切り替えるか、bun + qmd をインストールして再試行してください。" fi - echo "適用可能なシナリオ: インデックス付きの分子 > 分母 (収集を繰り返すと異常なカウントが発生します)" - read -e -p "includeDefaultMemory を false に設定してもよろしいですか? (y/N):" confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "キャンセル。" - break_end - return 0 - fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ 設定の書き込みに失敗しました" - break_end - return 1 - fi - echo "✅ includeDefaultMemory=false セット" - echo "推奨される実行: インデックスをクリーンアップして再構築する" - read -e -p "インデックスをクリーンして再構築しますか (推奨)? (はい/いいえ):" rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "インデックス修復診断" + echo "=======================================" + echo "現在の includeDefaultMemory: ${include_dm:-not set}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ includeDefaultMemory=false が検出されました" + echo "これにより、デフォルトのメモリ ファイル (MEMORY.md +memory/*.md) のインデックスが作成されなくなります。" + echo "したがって、インデックス付きでは常に 0/N が表示されます。" + echo "" + read -e -p "true に戻してインデックスを再構築しますか? (はい/いいえ):" fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ 設定の書き込みに失敗しました" + break_end + return 1 + fi + echo "✅ includeDefaultMemory=true が復元されました" + openclaw_memory_rebuild_index_all + else + echo "キャンセル。" + fi else - echo "ステータスは後でメモリ管理で確認できます。" + echo "includeDefaultMemory 構成は正常です。" + echo "実行内容: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" + echo "" + read -e -p "実行を確認しますか? (はい/いいえ):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "キャンセル。" + fi fi break_end } @@ -13637,30 +14041,42 @@ EOF openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done </dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13678,9 +14094,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "総行数:$total_lines" + echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -13770,18 +14186,25 @@ EOF break_end continue fi - openclaw_memory_prepare_workspace + openclaw_memory_prepare_workspace_all read -e -p "2 番目の確認: 全額を使用するには、force を入力します (増分の場合は空白のままにします):" confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 完全な再構築はより徹底的ですが、時間がかかります。" echo "推奨事項: 安全に再構築するには、再構築を入力してください (最初にインデックス データベースをバックアップします)。" read -e -p "3 番目の確認: 安全な再構築を実行するには、「再構築」と入力します。 Enter キーを押して通常の力で続行します。" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + local fl_agent_lines fl_agent_id fl_workspace + fl_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r fl_agent_id fl_workspace; do + [ -z "$fl_agent_id" ] && continue + openclaw memory index --agent "$fl_agent_id" --force + done </dev/null 2>&1 || { + echo "⚠️ 権限のバックアップが失敗しました:$backup_file" + return 1 + } + echo "✅ 現在の権限設定がバックアップされました:$backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ 復元可能な権限のバックアップ ファイルが見つかりません。" + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ 権限の回復に失敗しました:$backup_file" + return 1 + } + echo "✅ スイッチが復元される前の権限設定" + openclaw_permission_restart_gateway || true + return 0 + } + + openclaw_permission_restart_gateway() { + if ! openclaw_has_command openclaw; then + echo "❌ openclaw が検出されず、OpenClaw Gateway を再起動できません。" + return 1 + fi + echo "OpenClaw ゲートウェイを再起動しています..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>&1 | head -n 1) + if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 0; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + return 0 + fi + + echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then + return 0 + fi + return 1 + } + + openclaw_permission_detect_mode() { + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "不明なモード"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("標準セーフモード") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("拡張モードの開発") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("フルオープンモード") + else: + print("カスタムモード") +except Exception: + print("カスタムモード") +PY + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "設定ファイル:$config_file" + [ ! -s "$config_file" ] && echo "⚠️ OpenClaw 設定ファイルが見つかりません (まだ初期化されていない可能性があります)。" + echo "現在のモード:$mode" + echo "---------------------------------------" + + # Python を使用してすべての権限フィールドを一度に効率的に解析する + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) + +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except Exception as e: + print("❌ 構成ファイルの解析に失敗しました: %s" % e) +PY + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw 権限 - 標準セキュリティ モード" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" + return 1 + fi + echo "✅ 標準の安全モードに切り替えられました" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw 権限 - 開発拡張モード" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" + return 1 + fi + echo "✅ 開発強化モードに切り替えました" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw 権限 - 完全オープン モード" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" + return 1 + fi + echo "✅ 全開モードに切り替えました" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw 権限 - 公式のデフォルトに戻す" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 回復に失敗しました: 明示的なアクセス許可のオーバーライドをクリーニング中にエラーが発生しました。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" + return 1 + fi + echo "✅ OpenClaw 公式のデフォルト戦略に戻しました (明示的なオーバーライドをクリアしました)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw 権限 - セキュリティ監査" + openclaw_permission_require_openclaw || return 1 + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw権限管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw権限管理" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1.標準のセーフモードに切り替える(推奨)" + echo "2. 開発強化モードに切り替える" + echo "3. 全開モードへの切り替え(高リスク)" + echo "4. 公式のデフォルト戦略を復元する" + echo "5. セキュリティ監査を実行する" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" perm_choice + case "$perm_choice" in + 1) + echo "適用: 標準セキュリティ モード" + read -e -p "確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "キャンセル" + break_end + ;; + 2) + echo "適用される: 開発拡張モード" + read -e -p "確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "キャンセル" + break_end + ;; + 3) + echo "⚠️ フルオープン モードは実行承認をオフにし、特権エスカレーションと bash を有効にし、信頼できるシングルユーザー環境にのみ推奨されます。" + read -e -p "続行することを確認するには「FULL」と入力します。" confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "キャンセル" + break_end + ;; + 4) + echo "クリーンアップ スクリプトによって書き込まれた明示的なアクセス許可をオーバーライドし、公式の OpenClaw デフォルト ポリシーに戻します。" + read -e -p "確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "キャンセル" + break_end + ;; + 5) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "選択が無効です。もう一度お試しください。" + sleep 1 + ;; + esac + done + } + + openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ openclaw コマンドが検出されません。最初に OpenClaw をインストールまたは初期化してください。" + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "設定ファイル: ${config_file:-$(openclaw_permission_config_file)}" + echo "デフォルトのエージェント:$default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("構成されたエージェントの数: %s" % len(agents)); print("ルート バインディングの数: %s" % len(bindings)); print("合計セッション数: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("現在、マルチエージェントは構成されていません。") +else: + import itertools + for item in itertools.islice(agents, 8): + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- エージェント ID: [1;36m%s [0m" % item.get("id","?")); print("アイデンティティ名: %s %s" % (identity, emoji)); print("作業ディレクトリ: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw マルチエージェント - エージェントのリスト" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("エージェントはまだ構成されていません。"); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw マルチエージェント - 新しいエージェント" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "新しいエージェント ID を入力してください:" agent_id + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + read -e -p "ワークスペースのパスを入力してください (デフォルトは ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "エージェントが作成されます。$agent_id" + echo "作業ディレクトリ:$workspace" + read -e -p "続行することを確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ エージェントが正常に作成されました:$agent_id" + local name theme + read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name + [ -z "$name" ] && name="$agent_id" + read -e -p "エージェントの性格テーマを入力してください (例: 厳格、効率的):" theme + [ -z "$theme" ] && theme="アシスタント" + echo "エージェント ID を構成しています..." + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" + else + echo "❌ エージェントの作成に失敗しました" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw マルチエージェント - エージェントの削除" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "削除するエージェント ID を入力してください:" agent_id + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + echo "⚠️ エージェントを削除すると、その作業ディレクトリ、ルート バインディング、およびセッション ルーティングに影響する可能性があります。" + read -e -p "「DELETE」と入力して削除を確認します${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "キャンセル"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ エージェントは正常に削除されました:$agent_id" + else + echo "❌ エージェントの削除に失敗しました" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw マルチエージェント - ルーティング バインディングの表示" + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("まだルート バインディングはありません。"); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw マルチエージェント - 新しいルーティング バインディング" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "エージェント ID を入力してください:" agent_id + read -e -p "ルート バインディング値 (telegram:ops / discord:guild-a など) を入力してください。" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 + echo "エージェントをバインドします [$agent_id] -> [$bind_value]" + read -e -p "続行することを確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ ルートバインディングが正常に追加されました" + else + echo "❌ ルート バインディングの追加に失敗しました" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw マルチエージェント - ルーティング バインディングの削除" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "エージェント ID を入力してください:" agent_id + read -e -p "削除するルート バインディング値を入力してください:" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 + echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" + read -e -p "続行することを確認するには「yes」と入力します。" confirm + [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ ルートバインディングが正常に削除されました" + else + echo "❌ ルートバインディングの削除に失敗しました" + return 1 + fi + } + + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw マルチエージェント - セッションの概要" + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("まだセッション データがありません。"); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("セッションの概要:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw マルチエージェントヘルスチェック" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "設定ファイルを確認します: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 構成の検証に失敗しました。上記の出力を確認してください。" + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ 設定されたエージェントが見つかりません。"); +else: + for item in agents: + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) +print("ルート バインディングの数 = %s" % len(bindings)); print("✅マルチエージェントのヘルスチェックが完了しました")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw マルチエージェント管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw マルチエージェント管理" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. 新しいインテリジェント エージェントを追加する" + echo "2. エージェントを削除する" + echo "3. ルーティング バインディングを表示する" + echo "4. 新しいルート バインディングを追加する" + echo "5.ルートバインディングを削除する" + echo "6. セッションの概要を表示する" + echo "7. マルチエージェントのヘルスチェックを実行する" + echo "0. 前のレベルに戻ります" + echo "---------------------------------------" + read -e -p "選択肢を入力してください:" multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "選択が無効です。もう一度お試しください。"; sleep 1 ;; + esac + done + } + + +openclaw_backup_restore_menu() { send_stats "OpenClaw のバックアップと復元" while true; do @@ -13847,8 +15022,8 @@ EOF echo "OpenClaw を更新..." send_stats "OpenClaw を更新..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -13865,7 +15040,8 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ ルートディレクトリに /root/.openclaw がまだ存在していることが検出されます。掃除が必要な場合は手動で行ってください。" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アンインストールが完了しました" @@ -13875,7 +15051,7 @@ EOF nano_openclaw_json() { send_stats "OpenClaw 設定ファイルを編集する" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -13950,7 +15126,7 @@ EOF read echo -e "${gl_kjlan}デバイスリストをロード中...${gl_bai}" # ドメイン名を allowedOrigins に自動的に追加する - config_file="$HOME/.openclaw/openclaw.json" + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" # jq を使用して JSON を安全に変更し、構造が存在し、ドメイン名が繰り返し追加されないようにします。 @@ -14053,9 +15229,11 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done @@ -14391,7 +15569,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザ監視$check_docker $update_status" + echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -14400,7 +15578,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -15336,7 +16514,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -15968,7 +17146,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -16794,7 +17972,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -17938,7 +19116,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -18276,7 +19454,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -18286,7 +19464,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -18298,7 +19476,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -18324,7 +19502,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記ログ職業】" + echo "【日記帳の職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -18349,7 +19527,7 @@ log_menu() { read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -18359,7 +19537,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -18374,7 +19552,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -18462,7 +19640,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -18477,7 +19655,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -18493,7 +19671,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -18621,7 +19799,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -18877,8 +20055,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -19085,7 +20263,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -19100,7 +20278,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -19679,7 +20857,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -20015,7 +21193,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -20053,14 +21231,14 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -20137,7 +21315,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -20343,7 +21521,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -20382,8 +21560,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -20616,7 +21794,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) @@ -20655,6 +21833,9 @@ else linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info diff --git a/kr/kejilion.sh b/kr/kejilion.sh index e78b865db..6d1dadbc1 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.8" +sh_v="4.4.9" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -36,7 +36,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# 명령을 실행하는 함수 정의 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -59,9 +59,9 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!请相信我! -# 为什么要设计这个功能,目的更好的了解用户喜欢使用的功能,进一步优化功能推出更多符合用户需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! +# 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -114,22 +114,22 @@ CheckFirstRun_false() { fi } -# 提示用户同意条款 +# 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" - echo "用户许可协议: https://blog.kejilion.pro/user-license-agreement/" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" + echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." + echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -e -p "是否同意以上条款?(y/n): " user_input + read -e -p "위의 약관에 동의하십니까? (예/아니요):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "라이센스 계약" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else - send_stats "许可拒绝" + send_stats "허가가 거부되었습니다" clear exit fi @@ -173,13 +173,13 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "패키지 매개변수가 제공되지 않았습니다!" return 1 fi for package in "$@"; do if ! command -v "$package" &>/dev/null; then - echo -e "${gl_kjlan}正在安装 $package...${gl_bai}" + echo -e "${gl_kjlan}설치 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update dnf install -y epel-release @@ -207,7 +207,7 @@ install() { pkg update pkg install -y "$package" else - echo "未知的包管理器!" + echo "알 수 없는 패키지 관리자입니다!" return 1 fi fi @@ -225,11 +225,11 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}提示: ${gl_bai}磁盘空间不足!" - echo "当前可用空间: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" - send_stats "磁盘空间不足" + echo -e "${gl_huang}힌트:${gl_bai}디스크 공간이 부족합니다!" + echo "현재 사용 가능한 공간: $((available_space_mb/1024))G" + echo "최소 필요 공간:${required_gb}G" + echo "설치를 계속할 수 없습니다. 디스크 공간을 비운 후 다시 시도하십시오." + send_stats "디스크 공간이 부족합니다." break_end kejilion fi @@ -249,12 +249,12 @@ install_dependency() { remove() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "패키지 매개변수가 제공되지 않았습니다!" return 1 fi for package in "$@"; do - echo -e "${gl_kjlan}正在卸载 $package...${gl_bai}" + echo -e "${gl_kjlan}제거 중$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -272,14 +272,14 @@ remove() { elif command -v pkg &>/dev/null; then pkg delete -y "$package" else - echo "未知的包管理器!" + echo "알 수 없는 패키지 관리자입니다!" return 1 fi done } -# 通用 systemctl 函数,适用于各种发行版 +# 다양한 배포판에 적합한 범용 systemctl 기능 systemctl() { local COMMAND="$1" local SERVICE_NAME="$2" @@ -292,43 +292,43 @@ systemctl() { } -# 重启服务 +# 서비스 다시 시작 restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1서비스가 다시 시작되었습니다." else - echo "错误:重启 $1 服务失败。" + echo "오류: 다시 시작$1서비스가 실패했습니다." fi } -# 启动服务 +# 서비스 시작 start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1서비스가 시작되었습니다." else - echo "错误:启动 $1 服务失败。" + echo "오류: 시작$1서비스가 실패했습니다." fi } -# 停止服务 +# 서비스 중지 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then - echo "$1 服务已停止。" + echo "$1서비스가 중지되었습니다." else - echo "错误:停止 $1 服务失败。" + echo "오류: 중지$1서비스가 실패했습니다." fi } -# 查看服务状态 +# 서비스 상태 확인 status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1 服务状态已显示。" + echo "$1서비스 상태가 표시됩니다." else - echo "错误:无法显示 $1 服务状态。" + echo "오류: 표시할 수 없습니다.$1서비스 상태." fi } @@ -341,14 +341,14 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME 已设置为开机自启。" + echo "$SERVICE_NAME부팅시 자동으로 시작되도록 설정되어 있습니다." } break_end() { - echo -e "${gl_lv}操作完成${gl_bai}" - echo "按任意键继续..." + echo -e "${gl_lv}작업 완료${gl_bai}" + echo "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" echo "" clear @@ -451,7 +451,7 @@ install_add_docker_cn install_add_docker() { - echo -e "${gl_kjlan}正在安装docker环境...${gl_bai}" + echo -e "${gl_kjlan}도커 환경 설치 중...${gl_bai}" if command -v apt &>/dev/null || command -v yum &>/dev/null || command -v dnf &>/dev/null; then linuxmirrors_install_docker else @@ -473,63 +473,63 @@ install_docker() { docker_ps() { while true; do clear - send_stats "Docker容器管理" - echo "Docker容器列表" + send_stats "도커 컨테이너 관리" + echo "도커 컨테이너 목록" docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" - echo "容器操作" + echo "컨테이너 운영" echo "------------------------" - echo "1. 创建新的容器" + echo "1. 새 컨테이너 생성" echo "------------------------" - echo "2. 启动指定容器 6. 启动所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 删除指定容器 8. 删除所有容器" - echo "5. 重启指定容器 9. 重启所有容器" + echo "2. 지정된 컨테이너 시작 6. 모든 컨테이너 시작" + echo "3. 지정된 컨테이너를 중지합니다. 7. 모든 컨테이너를 중지합니다." + echo "4. 지정된 컨테이너 삭제 8. 모든 컨테이너 삭제" + echo "5. 지정된 컨테이너를 다시 시작합니다. 9. 모든 컨테이너를 다시 시작합니다." echo "------------------------" - echo "11. 进入指定容器 12. 查看容器日志" - echo "13. 查看容器网络 14. 查看容器占用" + echo "11. 지정된 컨테이너를 입력합니다. 12. 컨테이너 로그를 봅니다." + echo "13. 컨테이너 네트워크 확인 14. 컨테이너 점유율 확인" echo "------------------------" - echo "15. 开启容器端口访问 16. 关闭容器端口访问" + echo "15. 컨테이너 포트 액세스 활성화 16. 컨테이너 포트 액세스 닫기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "新建容器" - read -e -p "请输入创建命令: " dockername + send_stats "새 컨테이너 만들기" + read -e -p "생성 명령을 입력하십시오:" dockername $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너 시작" + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) - send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너 중지" + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) - send_stats "删除指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너 삭제" + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) - send_stats "重启指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "지정된 컨테이너를 다시 시작합니다." + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) - send_stats "启动所有容器" + send_stats "모든 컨테이너 시작" docker start $(docker ps -a -q) ;; 7) - send_stats "停止所有容器" + send_stats "모든 컨테이너 중지" docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "모든 컨테이너 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -538,32 +538,32 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; 9) - send_stats "重启所有容器" + send_stats "모든 컨테이너 다시 시작" docker restart $(docker ps -q) ;; 11) - send_stats "进入容器" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너를 입력하세요" + read -e -p "컨테이너 이름을 입력하세요:" dockername docker exec -it $dockername /bin/sh break_end ;; 12) - send_stats "查看容器日志" - read -e -p "请输入容器名: " dockername + send_stats "컨테이너 로그 보기" + read -e -p "컨테이너 이름을 입력하세요:" dockername docker logs $dockername break_end ;; 13) - send_stats "查看容器网络" + send_stats "컨테이너 네트워크 보기" echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -577,14 +577,14 @@ while true; do break_end ;; 14) - send_stats "查看容器占用" + send_stats "컨테이너 점유율 보기" docker stats --no-stream break_end ;; 15) - send_stats "允许容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 액세스 허용" + read -e -p "컨테이너 이름을 입력하세요:" docker_name ip_address clear_container_rules "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -593,8 +593,8 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" - read -e -p "请输入容器名: " docker_name + send_stats "컨테이너 포트 접근 차단" + read -e -p "컨테이너 이름을 입력하세요:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -613,44 +613,44 @@ done docker_image() { while true; do clear - send_stats "Docker镜像管理" - echo "Docker镜像列表" + send_stats "도커 이미지 관리" + echo "도커 이미지 목록" docker image ls echo "" - echo "镜像操作" + echo "미러 작동" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" - echo "2. 更新指定镜像 4. 删除所有镜像" + echo "1. 지정된 이미지 가져오기 3. 지정된 이미지 삭제" + echo "2. 지정된 이미지 업데이트 4. 모든 이미지 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "拉取镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "이미지 가져오기" + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_kjlan}正在获取镜像: $name${gl_bai}" + echo -e "${gl_kjlan}이미지 가져오기:$name${gl_bai}" docker pull $name done ;; 2) - send_stats "更新镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "이미지 업데이트" + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do - echo -e "${gl_kjlan}正在更新镜像: $name${gl_bai}" + echo -e "${gl_kjlan}이미지 업데이트 중:$name${gl_bai}" docker pull $name done ;; 3) - send_stats "删除镜像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + send_stats "이미지 삭제" + read -e -p "이미지 이름을 입력하세요(여러 이미지 이름은 공백으로 구분하세요):" imagenames for name in $imagenames; do docker rmi -f $name done ;; 4) - send_stats "删除所有镜像" + send_stats "모든 이미지 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有镜像吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -659,7 +659,7 @@ while true; do [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -727,16 +727,16 @@ install_crontab() { service cron start ;; *) - echo "不支持的发行版: $ID" + echo "지원되지 않는 배포판:$ID" return ;; esac else - echo "无法确定操作系统。" + echo "운영 체제를 확인할 수 없습니다." return fi - echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" + echo -e "${gl_lv}crontab이 설치되어 있고 cron 서비스가 실행 중입니다.${gl_bai}" } @@ -748,27 +748,27 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 구성 파일이 있는지 확인하고, 없으면 파일을 생성하고 기본 설정을 씁니다. if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # jq를 사용하여 구성 파일 업데이트 처리 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 현재 구성에 이미 ipv6 설정이 있는지 확인하십시오. local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 구성 업데이트 및 IPv6 활성화 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 원래 구성을 새 구성과 비교 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then - echo -e "${gl_huang}当前已开启ipv6访问${gl_bai}" + echo -e "${gl_huang}현재 IPv6 액세스가 활성화되어 있습니다.${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -783,28 +783,28 @@ docker_ipv6_off() { local CONFIG_FILE="/etc/docker/daemon.json" - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오. if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}구성 파일이 존재하지 않습니다.${gl_bai}" return fi - # 读取当前配置 + # 현재 구성 읽기 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 使用jq处理配置文件的更新 + # jq를 사용하여 구성 파일 업데이트 처리 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 현재 ipv6 상태 확인 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') - # 对比原始配置与新配置 + # 원래 구성을 새 구성과 비교 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스는 현재 폐쇄되었습니다.${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker - echo -e "${gl_huang}已成功关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}IPv6 액세스가 성공적으로 종료되었습니다.${gl_bai}" fi } @@ -843,117 +843,117 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "포트 번호를 하나 이상 입력하세요." return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的关闭规则 + # 기존 종료 규칙 삭제 iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # 공개 규칙 추가 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "已打开端口 $port" + echo "포트가 열렸습니다.$port" fi done save_iptables_rules - send_stats "已打开端口" + send_stats "포트가 열렸습니다." } close_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "포트 번호를 하나 이상 입력하세요." return 1 fi install iptables for port in "${ports[@]}"; do - # 删除已存在的打开规则 + # 기존 공개 규칙 삭제 iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # 添加关闭规则 + # 종료 규칙 추가 if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi if ! iptables -C INPUT -p udp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j DROP - echo "已关闭端口 $port" + echo "항구 폐쇄$port" fi done - # 删除已存在的规则(如果有) + # 기존 규칙 삭제(있는 경우) iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 插入新规则到第一条 + # 첫 번째 규칙에 새 규칙을 삽입합니다. iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT save_iptables_rules - send_stats "已关闭端口" + send_stats "항구 폐쇄" } allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 기존 차단 규칙 삭제 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 허용 규칙 추가 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "已放行IP $ip" + echo "공개된 IP$ip" fi done save_iptables_rules - send_stats "已放行IP" + send_stats "공개된 IP" } block_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "IP 주소 또는 IP 세그먼트를 하나 이상 입력하세요." return 1 fi install iptables for ip in "${ips[@]}"; do - # 删除已存在的允许规则 + # 기존 허용 규칙 삭제 iptables -D INPUT -s $ip -j ACCEPT 2>/dev/null - # 添加阻止规则 + # 차단 규칙 추가 if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "已阻止IP $ip" + echo "IP가 차단됨$ip" fi done save_iptables_rules - send_stats "已阻止IP" + send_stats "IP가 차단됨" } @@ -963,7 +963,7 @@ block_ip() { enable_ddos_defense() { - # 开启防御 DDoS + # DDoS 보호 켜기 iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -973,12 +973,12 @@ enable_ddos_defense() { iptables -A INPUT -p udp -m limit --limit 3000/s -j ACCEPT iptables -A INPUT -p udp -j DROP - send_stats "开启DDoS防御" + send_stats "DDoS 방어 켜기" } -# 关闭DDoS防御 +# DDoS 방어 끄기 disable_ddos_defense() { - # 关闭防御 DDoS + # DDoS 보호 끄기 iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -988,14 +988,14 @@ disable_ddos_defense() { iptables -D INPUT -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null iptables -D INPUT -p udp -j DROP 2>/dev/null - send_stats "关闭DDoS防御" + send_stats "DDoS 방어 끄기" } -# 管理国家IP规则的函数 +# 국가 IP 규칙을 관리하는 기능 manage_country_rules() { local action="$1" shift # 去掉第一个参数,剩下的全是国家代码 @@ -1013,7 +1013,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류: 다운로드$country_codeIP 영역 파일 실패" continue fi @@ -1023,7 +1023,7 @@ manage_country_rules() { iptables -I INPUT -m set --match-set "$ipset_name" src -j DROP - echo "已成功阻止 $country_code 的 IP 地址" + echo "성공적으로 차단되었습니다$country_codeIP 주소" rm "${country_code,,}.zone" ;; @@ -1033,7 +1033,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code 的 IP 区域文件失败" + echo "오류: 다운로드$country_codeIP 영역 파일 실패" continue fi @@ -1046,7 +1046,7 @@ manage_country_rules() { iptables -P INPUT DROP iptables -A INPUT -m set --match-set "$ipset_name" src -j ACCEPT - echo "已成功允许 $country_code 的 IP 地址" + echo "허용되었습니다.$country_codeIP 주소" rm "${country_code,,}.zone" ;; @@ -1057,11 +1057,11 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "已成功解除 $country_code 的 IP 地址限制" + echo "성공적으로 제거되었습니다$country_codeIP 주소 제한" ;; *) - echo "用法: manage_country_rules {block|allow|unblock} " + echo "사용법: prepare_country_rules {block|allow|unblock} " ;; esac done @@ -1082,42 +1082,42 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" - send_stats "高级防火墙管理" + echo "고급 방화벽 관리" + send_stats "고급 방화벽 관리" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "방화벽 관리" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "1. 지정 포트 열기 2. 지정 포트 닫기" + echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" - echo "5. IP白名单 6. IP黑名单" - echo "7. 清除指定IP" + echo "5. IP 화이트리스트 6. IP 블랙리스트" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" - echo "11. 允许PING 12. 禁止PING" + echo "11. PING 허용 12. PING 비활성화" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. DDOS 방어 시작 14. DDOS 방어 끄기" echo "------------------------" - echo "15. 阻止指定国家IP 16. 仅允许指定国家IP" - echo "17. 解除指定国家IP限制" + echo "15. 특정 국가 IP 차단 16. 특정 국가 IP만 허용" + echo "17. 지정된 국가에서 IP 제한을 해제합니다." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - read -e -p "请输入开放的端口号: " o_port + read -e -p "열려 있는 포트 번호를 입력하세요." o_port open_port $o_port - send_stats "开放指定端口" + send_stats "지정된 포트 열기" ;; 2) - read -e -p "请输入关闭的端口号: " c_port + read -e -p "닫힌 포트 번호를 입력하세요:" c_port close_port $c_port - send_stats "关闭指定端口" + send_stats "지정된 포트 닫기" ;; 3) - # 开放所有端口 + # 모든 포트 열기 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1130,10 +1130,10 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "开放所有端口" + send_stats "모든 포트 열기" ;; 4) - # 关闭所有端口 + # 모든 포트를 닫으세요 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1146,40 +1146,40 @@ iptables_panel() { iptables -A FORWARD -i lo -j ACCEPT iptables -A INPUT -p tcp --dport $current_port -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "关闭所有端口" + send_stats "모든 포트를 닫으세요" ;; 5) - # IP 白名单 - read -e -p "请输入放行的IP或IP段: " o_ip + # IP 화이트리스트 + read -e -p "허용된 IP 또는 IP 세그먼트를 입력하세요." o_ip allow_ip $o_ip ;; 6) - # IP 黑名单 - read -e -p "请输入封锁的IP或IP段: " c_ip + # IP 블랙리스트 + read -e -p "차단된 IP 또는 IP 범위를 입력하세요." c_ip block_ip $c_ip ;; 7) - # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + # 지정된 IP 지우기 + read -e -p "삭제된 IP를 입력하세요:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "清除指定IP" + send_stats "지정된 IP 지우기" ;; 11) - # 允许 PING + # 핑 허용 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "핑 허용" ;; 12) - # 禁用 PING + # 핑 비활성화 iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "禁用PING" + send_stats "핑 비활성화" ;; 13) enable_ddos_defense @@ -1189,20 +1189,20 @@ iptables_panel() { ;; 15) - read -e -p "请输入阻止的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "차단된 국가 코드를 입력하세요(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules block $country_code - send_stats "允许国家 $country_code 的IP" + send_stats "국가 허용$country_codeIP" ;; 16) - read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "허용되는 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분할 수 있음)." country_code manage_country_rules allow $country_code - send_stats "阻止国家 $country_code 的IP" + send_stats "블록 국가$country_codeIP" ;; 17) - read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code - send_stats "清除国家 $country_code 的IP" + send_stats "명확한 국가$country_codeIP" ;; *) @@ -1221,23 +1221,23 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 获取当前系统中所有的 swap 分区 + # 현재 시스템의 모든 스왑 파티션을 가져옵니다. local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') - # 遍历并删除所有的 swap 分区 + # 모든 스왑 파티션을 탐색하고 삭제합니다. for partition in $swap_partitions; do swapoff "$partition" wipefs -a "$partition" mkswap -f "$partition" done - # 确保 /swapfile 不再被使用 + # /swapfile이 더 이상 사용되지 않는지 확인하세요. swapoff /swapfile - # 删除旧的 /swapfile + # 이전 /swap 파일 삭제 rm -f /swapfile - # 创建新的 swap 分区 + # 새로운 스왑 파티션 생성 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1252,7 +1252,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "가상 메모리 크기가 다음과 같이 조정되었습니다.${gl_huang}${new_swap}${gl_bai}M" } @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1278,21 +1278,21 @@ local swap_total=$(free -m | awk 'NR==3{print $2}') ldnmp_v() { - # 获取nginx版本 + # nginx 버전 받기 local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e "nginx : ${gl_huang}v$nginx_version${gl_bai}" - # 获取mysql版本 + # mysql 버전 받기 local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') local mysql_version=$(docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SELECT VERSION();" 2>/dev/null | tail -n 1) echo -n -e " mysql : ${gl_huang}v$mysql_version${gl_bai}" - # 获取php版本 + # PHP 버전 받기 local php_version=$(docker exec php php -v 2>/dev/null | grep -oP "PHP \K[0-9]+\.[0-9]+\.[0-9]+") echo -n -e " php : ${gl_huang}v$php_version${gl_bai}" - # 获取redis版本 + # Redis 버전 받기 local redis_version=$(docker exec redis redis-server -v 2>&1 | grep -oP "v=+\K[0-9]+\.[0-9]+") echo -e " redis : ${gl_huang}v$redis_version${gl_bai}" @@ -1305,18 +1305,18 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 필요한 디렉토리 및 파일 생성 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf default_server_ssl - # 下载 docker-compose.yml 文件并进行替换 + # docker-compose.yml 파일을 다운로드하여 교체하세요. wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # 在 docker-compose.yml 文件中进行替换 + # docker-compose.yml 파일에서 교체 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1352,10 +1352,10 @@ update_docker_compose_with_db_creds() { auto_optimize_dns() { - # 获取国家代码(如 CN、US 等) + # 국가 코드(예: CN, US 등)를 가져옵니다. local country=$(curl -s ipinfo.io/country) - # 根据国家设置 DNS + # 국가에 따라 DNS 설정 if [ "$country" = "CN" ]; then local dns1_ipv4="223.5.5.5" local dns2_ipv4="183.60.83.19" @@ -1377,8 +1377,8 @@ auto_optimize_dns() { prefer_ipv4() { grep -q '^precedence ::ffff:0:0/96 100' /etc/gai.conf 2>/dev/null \ || echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf -echo "已切换为 IPv4 优先" -send_stats "已切换为 IPv4 优先" +echo "IPv4 우선순위로 전환됨" +send_stats "IPv4 우선순위로 전환됨" } @@ -1396,7 +1396,7 @@ install_ldnmp() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -1407,7 +1407,7 @@ install_ldnmp() { sleep 2 clear - echo "LDNMP环境安装完毕" + echo "LDNMP 환경이 설치되었습니다" echo "------------------------" ldnmp_v @@ -1424,7 +1424,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "갱신 작업이 업데이트되었습니다." } @@ -1458,15 +1458,15 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming공개키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" - echo -e "${gl_huang}$yuming 私钥信息${gl_bai}" + echo -e "${gl_huang}$yuming개인 키 정보${gl_bai}" cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" - echo -e "${gl_huang}证书存放路径${gl_bai}" - echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo -e "${gl_huang}인증서 저장 경로${gl_bai}" + echo "공개 키: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "개인 키: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1475,7 +1475,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申请SSL证书,过期前自动续签${gl_bai}" +echo -e "${gl_huang}SSL 인증서를 빠르게 신청하고 만료되기 전에 자동으로 갱신하세요.${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1491,8 +1491,8 @@ ssl_ps ssl_ps() { - echo -e "${gl_huang}已申请的证书到期情况${gl_bai}" - echo "站点信息 证书到期时间" + echo -e "${gl_huang}신청한 인증서의 만료 상태${gl_bai}" + echo "사이트 정보 인증서 만료 시간" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1531,56 +1531,56 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "도메인 이름 인증서 신청이 성공했습니다." else - send_stats "域名证书申请失败" - echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" - echo -e "3. 网络配置问题 ➠ 如使用Cloudflare Warp等虚拟网络请暂时关闭" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + send_stats "도메인 이름 인증서 신청 실패" + echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." + echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." + echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." + echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." + echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" - echo "1. 重新申请 2. 导入已有证书 0. 退出" + echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "重新申请" - echo "请再次尝试部署 $webname" + send_stats "재신청" + echo "다시 배포해 보세요.$webname" add_yuming install_ssltls certs_status ;; 2) - send_stats "导入已有证书" + send_stats "기존 인증서 가져오기" - # 定义文件路径 + # 파일 경로 정의 local cert_file="/home/web/certs/${yuming}_cert.pem" local key_file="/home/web/certs/${yuming}_key.pem" mkdir -p /home/web/certs - # 1. 输入证书 (ECC 和 RSA 证书开头都是 BEGIN CERTIFICATE) - echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" + # 1. 인증서를 입력합니다(ECC 및 RSA 인증서 모두 BEGIN CERTIFICATE로 시작함). + echo "인증서(CRT/PEM) 콘텐츠를 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break cert_content+="${line}"$'\n' done - # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) - echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" + # 2. 개인 키를 입력하세요. (RSA, ECC, PKCS#8과 호환 가능) + echo "인증서 개인 키(개인 키) 내용을 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break key_content+="${line}"$'\n' done - # 3. 智能校验 - # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 + # 3. 지능형 검증 + # 통과하려면 "BEGIN CERTIFICATE" 및 "PRIVATE KEY"만 포함하면 됩니다. if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1588,15 +1588,15 @@ certs_status() { chmod 644 "$cert_file" chmod 600 "$key_file" - # 识别当前证书类型并显示 + # 현재 인증서 유형을 식별하고 표시합니다. if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then - echo "检测到 ECC 证书已成功保存。" + echo "ECC 인증서가 성공적으로 저장되었음을 감지했습니다." else - echo "检测到 RSA 证书已成功保存。" + echo "RSA 인증서가 성공적으로 저장되었음을 감지했습니다." fi auth_method="ssl_imported" else - echo "错误:无效的证书或私钥格式!" + echo "오류: 잘못된 인증서 또는 개인 키 형식입니다!" certs_status fi ;; @@ -1611,7 +1611,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "도메인 이름 재사용" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1620,8 +1620,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "먼저 도메인 이름을 로컬 IP로 확인합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "귀하의 IP 또는 확인된 도메인 이름을 입력하십시오:" yuming } @@ -1632,7 +1632,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port + read -e -p "액세스/수신 포트를 입력하고 Enter를 눌러 기본적으로 80을 사용하십시오." access_port access_port=${access_port:-80} fi } @@ -1644,13 +1644,13 @@ update_nginx_listen_port() { local access_port="$2" local conf="/home/web/conf.d/${yuming}.conf" - # 如果 access_port 为空,则跳过 + # access_port가 비어 있으면 건너뛰세요. [ -z "$access_port" ] && return 0 - # 删除所有 listen 行 + # 모든 청취 라인 제거 sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" - # 在 server { 后插入新的 listen + # 서버 { 뒤에 새 수신 대기 삽입 sed -i "/server {/a\\ listen ${access_port};\\ listen [::]:${access_port}; @@ -1700,8 +1700,8 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" } @@ -1720,11 +1720,11 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "登录信息: " - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "로그인 정보:" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" echo - send_stats "启动$ldnmp_pods" + send_stats "시작하다$ldnmp_pods" } @@ -1734,29 +1734,29 @@ cf_purge_cache() { local EMAIL local ZONE_IDS - # 检查配置文件是否存在 + # 구성 파일이 있는지 확인하십시오. if [ -f "$CONFIG_FILE" ]; then - # 从配置文件读取 API_TOKEN 和 zone_id + # 구성 파일에서 API_TOKEN 및 zone_id를 읽습니다. read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # ZONE_IDS를 어레이로 변환 ZONE_IDS=($ZONE_IDS) else - # 提示用户是否清理缓存 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + # 캐시를 지울지 여부를 사용자에게 묻습니다. + read -e -p "Cloudflare의 캐시를 지워야 합니까? (예/아니요):" answer if [[ "$answer" == "y" ]]; then - echo "CF信息保存在$CONFIG_FILE,可以后期修改CF信息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + echo "CF 정보는 다음 위치에 저장됩니다.$CONFIG_FILE, 나중에 CF 정보를 수정할 수 있습니다." + read -e -p "API_TOKEN을 입력하세요:" API_TOKEN + read -e -p "CF 사용자 이름을 입력하세요:" EMAIL + read -e -p "zone_id를 입력하십시오(여러 개는 공백으로 구분)." -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 각 zone_id를 반복하고 캐시 지우기 명령을 실행합니다. for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "zone_id에 대한 캐시 지우기:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1764,13 +1764,13 @@ cf_purge_cache() { --data '{"purge_everything":true}' done - echo "缓存清除请求已发送完毕。" + echo "캐시 삭제 요청이 전송되었습니다." } web_cache() { - send_stats "清理站点缓存" + send_stats "사이트 캐시 지우기" cf_purge_cache cd /home/web && docker compose restart } @@ -1779,28 +1779,28 @@ web_cache() { web_del() { - send_stats "删除站点数据" + send_stats "사이트 데이터 삭제" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_list if [[ -z "$yuming_list" ]]; then return fi fi for yuming in $yuming_list; do - echo "正在删除域名: $yuming" + echo "도메인 이름을 삭제하는 중입니다:$yuming" rm -r /home/web/html/$yuming > /dev/null 2>&1 rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # 도메인 이름을 데이터베이스 이름으로 변환 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" + # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. + echo "데이터베이스 삭제 중:$dbname" docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 done @@ -1816,23 +1816,23 @@ nginx_waf() { wget -O /home/web/nginx.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf" fi - # 根据 mode 参数来决定开启或关闭 WAF + # 모드 매개변수에 따라 WAF를 켤지 끌지 결정합니다. if [ "$mode" == "on" ]; then - # 开启 WAF:去掉注释 + # WAF 켜기: 댓글 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # WAF 끄기: 댓글 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -1846,7 +1846,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status=" WAF已开启" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -1855,7 +1855,7 @@ check_waf_status() { check_cf_mode() { if [ -f "/etc/fail2ban/action.d/cloudflare-docker.conf" ]; then - CFmessage=" cf模式已开启" + CFmessage="cf 모드가 켜져 있습니다" else CFmessage="" fi @@ -1879,11 +1879,11 @@ patch_wp_memory_limit() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 이전 정의 삭제 sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1906,12 +1906,12 @@ patch_wp_debug() { local TARGET_DIR="/home/web/html" # 路径写死 find "$TARGET_DIR" -type f -name "wp-config.php" | while read -r FILE; do - # 删除旧定义 + # 이전 정의 삭제 sed -i "/define(['\"]WP_DEBUG['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_DISPLAY['\"].*/d" "$FILE" sed -i "/define(['\"]WP_DEBUG_LOG['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # "HappyPublishing"이 포함된 줄 앞에 새 정의를 삽입합니다. awk -v insert="define('WP_DEBUG_DISPLAY', $DEBUG_DISPLAY);\ndefine('WP_DEBUG_LOG', $DEBUG_LOG);" \ ' /Happy publishing/ { @@ -1933,17 +1933,17 @@ patch_wp_url() { local TARGET_DIR="/home/web/html" find "$TARGET_DIR" -type f -name "wp-config-sample.php" | while read -r FILE; do - # 删除旧定义 + # 이전 정의 삭제 sed -i "/define(['\"]WP_HOME['\"].*/d" "$FILE" sed -i "/define(['\"]WP_SITEURL['\"].*/d" "$FILE" - # 生成插入内容 + # 삽입 콘텐츠 생성 INSERT=" define('WP_HOME', '$HOME_URL'); define('WP_SITEURL', '$SITE_URL'); " - # 插入到 “Happy publishing” 之前 + # '행복한 출판' 앞에 삽입 awk -v insert="$INSERT" ' /Happy publishing/ { print insert @@ -1971,7 +1971,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # Brotli 켜기: 댓글 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # 关闭 Brotli:加上注释 + # Brotli 닫기: 댓글 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2001,11 +2001,11 @@ nginx_br() { }' /home/web/nginx.conf else - echo "无效的参数:使用 'on' 或 'off'" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2027,7 +2027,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # Zstd 켜기: 주석 제거 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2042,7 +2042,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # Zstd 닫기: 설명 추가 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2058,11 +2058,11 @@ nginx_zstd() { else - echo "无效的参数:使用 'on' 或 'off'" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi - # 检查 nginx 镜像并根据情况处理 + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2089,7 +2089,7 @@ nginx_gzip() { elif [ "$mode" == "off" ]; then sed -i 's|^\(\s*\)gzip on;|\1# gzip on;|' /home/web/nginx.conf > /dev/null 2>&1 else - echo "无效的参数:使用 'on' 或 'off'" + echo "잘못된 인수: 'on' 또는 'off'를 사용하세요." return 1 fi @@ -2103,31 +2103,31 @@ nginx_gzip() { web_security() { - send_stats "LDNMP环境防御" + send_stats "LDNMP 환경 방어" while true; do check_f2b_status check_waf_status check_cf_mode clear - echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "서버 웹사이트 방어 프로그램${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램 설치" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" - echo "7. 查看防御规则列表 8. 查看日志实时监控" + echo "5. SSH 차단 기록 보기 6. 웹사이트 차단 기록 보기" + echo "7. 방어규칙 목록 보기 8. 실시간 모니터링을 위한 로그 보기" echo "------------------------" - echo "11. 配置拦截参数 12. 清除所有拉黑的IP" + echo "11. 차단 매개변수 구성 12. 차단된 IP 모두 삭제" echo "------------------------" - echo "21. cloudflare模式 22. 高负载开启5秒盾" + echo "21. cloudflare 모드 22. 고부하에서 5초 보호 활성화" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" - echo "33. 开启DDOS防御 34. 关闭DDOS防御" + echo "31. WAF 켜기 32. WAF 끄기" + echo "33. DDOS 방어 켜기 34. DDOS 방어 끄기" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -2192,7 +2192,7 @@ web_security() { remove fail2ban rm -rf /etc/fail2ban crontab -l | grep -v "CF-Under-Attack.sh" | crontab - 2>/dev/null - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban 방어 프로그램이 제거되었습니다." break ;; @@ -2208,11 +2208,11 @@ web_security() { ;; 21) - send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + send_stats "클라우드플레어 모드" + echo "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고 글로벌 API 키를 받으세요." echo "https://dash.cloudflare.com/login" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "CF의 계좌번호를 입력하세요:" cfuser + read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2227,21 +2227,21 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "Cloudflare 모드가 구성되었으며, 차단 기록은 cf 백그라운드, site-security-events에서 볼 수 있습니다." ;; 22) - send_stats "高负载开启5秒盾" - echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" + send_stats "고부하로 5초 쉴드 가능" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" - echo "获取CF参数: " - echo -e "到cf后台右上角我的个人资料,选择左侧API令牌,获取${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}区域ID${gl_bai}" + echo "CF 매개변수 가져오기:" + echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" + echo -e "cf 백엔드 도메인 이름 요약 페이지 오른쪽 하단으로 이동하여 가져오세요.${gl_huang}지역 ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" - read -e -p "输入CF的账号: " cfuser - read -e -p "输入CF的Global API Key: " cftoken - read -e -p "输入CF中域名的区域ID: " cfzonID + read -e -p "CF의 계좌번호를 입력하세요:" cfuser + read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken + read -e -p "CF에 도메인 이름의 영역 ID를 입력하세요." cfzonID cd ~ install jq bc @@ -2258,23 +2258,23 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "고부하 자동 쉴드 오픈 스크립트가 추가되었습니다." else - echo "自动开盾脚本已存在,无需添加" + echo "자동 방패 열기 스크립트가 이미 있으므로 추가할 필요가 없습니다." fi ;; 31) nginx_waf on - echo "站点WAF已开启" - send_stats "站点WAF已开启" + echo "사이트 WAF가 활성화되었습니다" + send_stats "사이트 WAF가 활성화되었습니다" ;; 32) nginx_waf off - echo "站点WAF已关闭" - send_stats "站点WAF已关闭" + echo "사이트 WAF가 다운되었습니다" + send_stats "사이트 WAF가 다운되었습니다" ;; 33) @@ -2300,11 +2300,11 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # 检查 MySQL 配置文件中是否包含 4096M + # MySQL 구성 파일에 4096M이 포함되어 있는지 확인하세요. if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info=" 高性能模式" + mode_info="고성능 모드" else - mode_info=" 标准模式" + mode_info="표준 모드" fi @@ -2316,23 +2316,23 @@ check_nginx_compression() { local CONFIG_FILE="/home/web/nginx.conf" - # 检查 zstd 是否开启且未被注释(整行以 zstd on; 开头) + # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status=" zstd压缩已开启" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # brotli가 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="br압축이 켜져 있습니다" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # gzip이 활성화되어 있고 주석 처리가 해제되어 있는지 확인하세요. if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then - gzip_status=" gzip压缩已开启" + gzip_status="gzip 압축이 켜져 있습니다" else gzip_status="" fi @@ -2346,21 +2346,21 @@ web_optimization() { check_ldnmp_mode check_nginx_compression clear - send_stats "优化LDNMP环境" - echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + send_stats "LDNMP 환경 최적화" + echo -e "LDNMP 환경 최적화${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. 표준 모드 2. 고성능 모드(2H4G 이상 권장)" echo "------------------------" - echo "3. 开启gzip压缩 4. 关闭gzip压缩" - echo "5. 开启br压缩 6. 关闭br压缩" - echo "7. 开启zstd压缩 8. 关闭zstd压缩" + echo "3. gzip 압축 켜기 4. gzip 압축 끄기" + echo "5. br 압축을 켭니다. 6. br 압축을 끕니다." + echo "7. zstd 압축을 켭니다. 8. zstd 압축을 끕니다." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "사이트 표준 모드" local cpu_cores=$(nproc) local connections=$((1024 * ${cpu_cores})) @@ -2368,13 +2368,13 @@ web_optimization() { sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2386,7 +2386,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2397,25 +2397,25 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP 환경이 표준 모드로 설정되었습니다." ;; 2) - send_stats "站点高性能模式" + send_stats "사이트 고성능 모드" - # nginx调优 + # nginx 튜닝 local cpu_cores=$(nproc) local connections=$((2048 * ${cpu_cores})) sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - # php调优 + # PHP 튜닝 wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini rm -rf /home/optimized_php.ini - # php调优 + # PHP 튜닝 wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf @@ -2427,7 +2427,7 @@ web_optimization() { fix_phpfpm_conf php fix_phpfpm_conf php74 - # mysql调优 + # MySQL 튜닝 wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ rm -rf /home/custom_mysql_config.cnf @@ -2436,7 +2436,7 @@ web_optimization() { optimize_web_server - echo "LDNMP环境已设置成 高性能模式" + echo "LDNMP 환경이 고성능 모드로 설정되었습니다." ;; 3) @@ -2485,9 +2485,9 @@ web_optimization() { check_docker_app() { if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name" ; then - check_docker="${gl_lv}已安装${gl_bai}" + check_docker="${gl_lv}설치됨${gl_bai}" else - check_docker="${gl_hui}未安装${gl_bai}" + check_docker="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -2496,9 +2496,9 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}未安装${gl_bai}" +# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2506,7 +2506,7 @@ check_docker_app() { check_docker_app_ip() { echo "------------------------" -echo "访问地址:" +echo "방문 주소:" ip_address @@ -2538,11 +2538,11 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 区域检查 + # 1. 지역점검 local country=$(curl -s --max-time 2 ipinfo.io/country) [[ "$country" == "CN" ]] && return - # 2. 获取本地镜像信息 + # 2. 로컬 미러 정보 얻기 local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return @@ -2550,22 +2550,22 @@ check_docker_image_update() { local full_image_name=$(echo "$container_info" | cut -d',' -f2) local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 智能路由判断 + # 3. 지능형 라우팅 판단 if [[ "$full_image_name" == ghcr.io* ]]; then - # --- 场景 A: 镜像在 GitHub (ghcr.io) --- - # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg + # --- 시나리오 A: GitHub(ghcr.io)의 미러링 --- + # 웨어하우스 경로를 추출합니다(예: ghcr.io/onexru/oneimg -> onexru/oneimg). local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注意:ghcr.io 的 API 比较复杂,通常最快的方法是查 GitHub Repo 的 Release + # 참고: ghcr.io의 API는 비교적 복잡합니다. 일반적으로 가장 빠른 방법은 GitHub Repo 릴리스를 확인하는 것입니다. local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- + # --- 시나리오 B: 특별 지정(Docker Hub에서도 GitHub 릴리스로 판단하고 싶습니다) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) else - # --- 场景 C: 标准 Docker Hub --- + # --- 시나리오 C: 표준 Docker 허브 --- local image_repo=${full_image_name%%:*} local image_tag=${full_image_name##*:} [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" @@ -2575,11 +2575,11 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) fi - # 4. 时间戳对比 + # 4. 타임스탬프 비교 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) if [[ $container_created_ts -lt $remote_ts ]]; then - update_status="${gl_huang}发现新版本!${gl_bai}" + update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" fi fi } @@ -2594,7 +2594,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소 가져오기 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2604,34 +2604,34 @@ block_container_port() { install iptables - # 检查并封禁其他所有 IP + # 다른 모든 IP를 확인하고 차단하세요. if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP 확인 및 해제 if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8 확인 및 허용 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi - # 检查并封禁其他所有 IP + # 다른 모든 IP를 확인하고 차단하세요. if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 지정된 IP 확인 및 해제 if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 检查并放行本地网络 127.0.0.0/8 + # 로컬 네트워크 127.0.0.0/8 확인 및 허용 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2641,7 +2641,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "IP+포트가 서비스 접근을 차단했습니다." save_iptables_rules } @@ -2652,7 +2652,7 @@ clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 컨테이너의 IP 주소 가져오기 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2662,17 +2662,17 @@ clear_container_rules() { install iptables - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2681,17 +2681,17 @@ clear_container_rules() { - # 清除封禁其他所有 IP 的规则 + # 다른 모든 IP를 차단하는 명확한 규칙 if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 清除放行指定 IP 的规则 + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # 清除放行本地网络 127.0.0.0/8 的规则 + # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2702,7 +2702,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules } @@ -2716,25 +2716,25 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: block_host_port <端口号> <允许的IP>" + echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." + echo "사용법: block_host_port <포트 번호> <허용 IP>" return 1 fi install iptables - # 拒绝其他所有 IP 访问 + # 다른 모든 IP의 접근을 거부 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP에 대한 접근을 허용 if ! iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스 허용 if ! iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2743,27 +2743,27 @@ block_host_port() { - # 拒绝其他所有 IP 访问 + # 다른 모든 IP의 접근을 거부 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi - # 允许指定 IP 访问 + # 지정된 IP에 대한 접근을 허용 if ! iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 允许本机访问 + # 로컬 액세스 허용 if ! iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 允许已建立和相关连接的流量 + # 확립된 관련 연결에 대한 트래픽 허용 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi - echo "已阻止IP+端口访问该服务" + echo "IP+포트가 서비스 접근을 차단했습니다." save_iptables_rules } @@ -2775,47 +2775,47 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." + echo "사용법:clear_host_port_rules <포트 번호> <허용 IP>" return 1 fi install iptables - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 로컬 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - # 清除封禁所有其他 IP 访问的规则 + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 로컬 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # 清除允许指定 IP 访问的规则 + # 지정된 IP로부터의 액세스를 허용하는 명확한 규칙 if iptables -C INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s "$allowed_ip" -j ACCEPT fi - echo "已允许IP+端口访问该服务" + echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules } @@ -2854,7 +2854,7 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker docker_app() { -send_stats "${docker_name}管理" +send_stats "${docker_name}관리하다" while true; do clear @@ -2874,25 +2874,25 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" + echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." + send_stats "애플리케이션 포트가 점유되어 있습니다." else local docker_port=$app_port break @@ -2907,12 +2907,12 @@ while true; do add_app_id clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치 완료" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "安装$docker_name" + send_stats "설치하다$docker_name" ;; 2) docker rm -f "$docker_name" @@ -2922,12 +2922,12 @@ while true; do add_app_id clear - echo "$docker_name 已经安装完成" + echo "$docker_name설치 완료" check_docker_app_ip echo "" $docker_use $docker_passwd - send_stats "更新$docker_name" + send_stats "고쳐 쓰다$docker_name" ;; 3) docker rm -f "$docker_name" @@ -2936,30 +2936,30 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" - send_stats "卸载$docker_name" + echo "앱이 제거되었습니다." + send_stats "제거$docker_name" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 이름 액세스 설정" + send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 접근 차단${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -2996,26 +2996,26 @@ docker_app_plus() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 도메인 이름 액세스 추가 6. 도메인 이름 액세스 삭제" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" + echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." + send_stats "애플리케이션 포트가 점유되어 있습니다." else local docker_port=$app_port break @@ -3028,13 +3028,13 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id - send_stats "$app_name 安装" + send_stats "$app_name설치하다" ;; 2) docker_app_update add_app_id - send_stats "$app_name 更新" + send_stats "$app_name고쳐 쓰다" ;; 3) @@ -3042,27 +3042,27 @@ docker_app_plus() { rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name 卸载" + send_stats "$app_name제거" ;; 5) - echo "${docker_name}域名访问设置" - send_stats "${docker_name}域名访问设置" + echo "${docker_name}도메인 이름 액세스 설정" + send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; 7) - send_stats "允许IP访问 ${docker_name}" + send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "IP 접근 차단${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; *) @@ -3147,17 +3147,17 @@ tmux_run_d() { local base_name="tmuxd" local tmuxd_ID=1 -# 检查会话是否存在的函数 +# 세션이 존재하는지 확인하는 함수 session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 존재하지 않는 세션 이름을 찾을 때까지 반복 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done -# 创建新的 tmux 会话 +# 새 tmux 세션 만들기 tmux new -d -s "$base_name-$tmuxd_ID" "$tmuxd" @@ -3177,9 +3177,9 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}已安装${gl_bai}" + check_f2b_status="${gl_lv}설치됨${gl_bai}" else - check_f2b_status="${gl_hui}未安装${gl_bai}" + check_f2b_status="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -3213,31 +3213,31 @@ f2b_sshd() { fi } -# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) -# 说明: -# - 优先写入 /etc/fail2ban/jail.d/sshd.local(覆盖默认 jail 配置,升级不易丢) -# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 +# 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) +# 설명하다: +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use install nano if ! command -v fail2ban-client >/dev/null 2>&1; then - echo -e "${gl_hui}未检测到 fail2ban-client,请先安装 fail2ban。${gl_bai}" + echo -e "${gl_hui}FAIL2BAN-클라이언트가 감지되지 않습니다. 먼저 Fail2ban을 설치하십시오.${gl_bai}" return fi local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 + # 알파인 기본 감옥은 일반적으로 sshd입니다. 사용자 정의 alpine-sshd 규칙이 감지된 경우에만 전환됩니다. if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi fi - echo "即将配置 SSH jail:$jail_name" - read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime - read -e -p "时间窗口 findtime (秒/分钟/小时,如 600 或 10m) [默认 10m]: " findtime - read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry + echo "SSH 감옥을 구성하려고 합니다:$jail_name" + read -e -p "금지 시간 금지 시간(초/분/시간, 예: 3600 또는 1h) [기본값 1h]:" bantime + read -e -p "시간 창 찾기 시간(초/분/시간, 예: 600 또는 10m) [기본값 10m]:" findtime + read -e -p "재시도 횟수 maxretry(정수) [기본값 5]:" maxretry bantime=${bantime:-1h} findtime=${findtime:-10m} @@ -3262,20 +3262,20 @@ EOF fi fi - echo -e "${gl_lv}已写入配置${gl_bai}: /etc/fail2ban/jail.d/sshd.local" + echo -e "${gl_lv}구성이 작성되었습니다.${gl_bai}: /etc/fail2ban/jail.d/sshd.local" fail2ban-client reload >/dev/null 2>&1 || true sleep 2 fail2ban-client status $jail_name || true } -# 直接打开主配置/覆盖配置编辑(nano) -# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 +# 기본 구성/오버레이 구성 편집기(나노)를 직접 엽니다. +# /etc/fail2ban/jail.d/sshd.local을 먼저 편집하고(보다 안전함) 존재하지 않는 경우 생성합니다. f2b_edit_config() { root_use install nano if [ ! -d /etc/fail2ban ]; then - echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" + echo -e "${gl_hui}/etc/fail2ban이 존재하지 않습니다. 먼저 fall2ban을 설치하십시오.${gl_bai}" return fi @@ -3284,7 +3284,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}已保存${gl_bai},正在 reload fail2ban..." + echo -e "${gl_lv}저장됨${gl_bai}, Fail2ban을 다시 로드하는 중..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3295,11 +3295,11 @@ server_reboot() { read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}现在重启服务器吗?(Y/N): ")" rboot case "$rboot" in [Yy]) - echo "已重启" + echo "다시 시작됨" reboot ;; *) - echo "已取消" + echo "취소" ;; esac @@ -3342,8 +3342,8 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" - echo -e "${gl_huang}提示: ${gl_bai}建站环境已安装。无需再次安装!" + send_stats "LDNMP 환경을 다시 설치할 수 없습니다" + echo -e "${gl_huang}힌트:${gl_bai}홈페이지 구축 환경이 설치되었습니다. 다시 설치할 필요가 없습니다!" break_end linux_ldnmp fi @@ -3353,10 +3353,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "LDNMP 환경 설치" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP 환경이 설치되지 않았습니다. LDNMP 환경 설치를 시작합니다...${gl_bai}" check_disk_space 3 /home install_dependency install_docker @@ -3369,10 +3369,10 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "nginx 환경 설치" root_use clear -echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" +echo -e "${gl_huang}nginx가 설치되지 않았습니다. nginx 환경 설치를 시작하세요...${gl_bai}" install_dependency install_docker install_certbot @@ -3381,8 +3381,8 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安装完成" -echo -e "当前版本: ${gl_huang}v$nginx_version${gl_bai}" +echo "nginx가 설치되었습니다" +echo -e "현재 버전:${gl_huang}v$nginx_version${gl_bai}" echo "" } @@ -3393,7 +3393,7 @@ echo "" ldnmp_install_status() { if ! docker inspect "php" &>/dev/null; then - send_stats "请先安装LDNMP环境" + send_stats "먼저 LDNMP 환경을 설치해 주세요" ldnmp_install_all fi @@ -3403,7 +3403,7 @@ ldnmp_install_status() { nginx_install_status() { if ! docker inspect "nginx" &>/dev/null; then - send_stats "请先安装nginx环境" + send_stats "먼저 nginx 환경을 설치해주세요" nginx_install_all fi @@ -3414,10 +3414,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的 $webname 搭建好了!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname 安装信息如下: " + echo "$webname설치 정보는 다음과 같습니다." } @@ -3427,7 +3427,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "您的 $webname 搭建好了!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3446,8 +3446,8 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3489,13 +3489,13 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="역방향 프록시-IP+포트" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3503,12 +3503,12 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "请输入你的反代IP (回车默认本机IP 127.0.0.1): " reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi if [ -z "$port" ]; then - read -e -p "请输入你的反代端口: " port + read -e -p "안티 세대 포트를 입력하십시오:" port fi nginx_install_status @@ -3531,7 +3531,7 @@ ldnmp_Proxy() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf sed -i '/remote_addr/d' /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3545,10 +3545,10 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="역방향 프록시-로드 밸런싱" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3556,7 +3556,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "여러 개의 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port fi nginx_install_status @@ -3578,7 +3578,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -3596,34 +3596,34 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服务名" "通信类型" "本机地址" "后端地址" + printf "%-25s %-18s %-25s %-20s\n" "서비스 이름" "통신 유형" "현지 주소" "백엔드 주소" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return fi for conf in "$STREAM_DIR"/*; do - # 服务名取文件名 + # 서비스 이름은 파일 이름을 사용합니다. service_name=$(basename "$conf" .conf) - # 获取 upstream 块中的 server 后端 IP:端口 + # 업스트림 블록에서 서버 백엔드 IP:포트 가져오기 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) - # 获取 listen 端口 + # 청취 포트 가져오기 listen_port=$(grep -Po '(?<=listen )[^;]+' "$conf" | head -n1) - # 默认本地 IP + # 기본 로컬 IP ip_address local_ip="$ipv4_address" - # 获取通信类型,优先从文件名后缀或内容判断 + # 먼저 파일 이름 접미사 또는 내용으로 판단하여 통신 유형을 가져옵니다. if grep -qi 'udp;' "$conf"; then proto="udp" else proto="tcp" fi - # 拼接监听 IP:端口 + # 스플라이스 청취 IP:포트 local_addr="$local_ip:$listen_port" printf "%-22s %-14s %-21s %-20s\n" "$service_name" "$proto" "$local_addr" "$backend" @@ -3639,7 +3639,7 @@ list_stream_services() { stream_panel() { - send_stats "Stream四层代理" + send_stats "4계층 프록시 스트리밍" local app_id="104" local docker_name="nginx" @@ -3647,42 +3647,42 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四层代理转发工具 $check_docker $update_status" - echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模块,用于实现高性能的 传输层流量转发和负载均衡。" + echo -e "스트림 4계층 프록시 전달 도구$check_docker $update_status" + echo "NGINX 스트림은 고성능 전송 계층 트래픽 전달 및 로드 밸런싱을 달성하는 데 사용되는 NGINX의 TCP/UDP 프록시 모듈입니다." echo "------------------------" if [ -d "/home/web/stream.d" ]; then list_stream_services fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" + echo "4. 포워딩 서비스 추가 5. 포워딩 서비스 수정 6. 포워딩 서비스 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) nginx_install_status add_app_id - send_stats "安装Stream四层代理" + send_stats "Stream 4계층 에이전트 설치" ;; 2) update_docker_compose_with_db_creds nginx_upgrade add_app_id - send_stats "更新Stream四层代理" + send_stats "Stream 4계층 프록시 업데이트" ;; 3) - read -e -p "确定要删除 nginx 容器吗?这可能会影响网站功能!(y/N): " confirm + read -e -p "nginx 컨테이너를 삭제하시겠습니까? 이는 웹사이트 기능에 영향을 미칠 수 있습니다! (예/아니요):" confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "更新Stream四层代理" - echo "nginx 容器已删除。" + send_stats "Stream 4계층 프록시 업데이트" + echo "nginx 컨테이너가 삭제되었습니다." else - echo "操作已取消。" + echo "작업이 취소되었습니다." fi ;; @@ -3690,22 +3690,22 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "添加四层代理" + send_stats "레이어 4 프록시 추가" ;; 5) - send_stats "编辑转发配置" - read -e -p "请输入你要编辑的服务名: " stream_name + send_stats "전달 구성 수정" + read -e -p "편집하려는 서비스 이름을 입력하십시오:" stream_name install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四层代理" + send_stats "레이어 4 프록시 수정" ;; 6) - send_stats "删除转发配置" - read -e -p "请输入你要删除的服务名: " stream_name + send_stats "전달 구성 삭제" + read -e -p "삭제하려는 서비스 이름을 입력하세요." stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx - send_stats "删除四层代理" + send_stats "레이어 4 프록시 삭제" ;; *) break @@ -3719,34 +3719,34 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="Stream四层代理-负载均衡" + webname="스트리밍 4계층 프록시-로드 밸런싱" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" - # 获取代理名称 - read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + # 에이전트 이름 가져오기 + read -erp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name if [ -z "$proxy_name" ]; then - echo "名称不能为空"; return 1 + echo "이름은 비워둘 수 없습니다."; return 1 fi - # 获取监听端口 - read -erp "请输入本机监听端口 (如 3306): " listen_port + # 수신 포트 가져오기 + read -erp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then - echo "端口必须是数字"; return 1 + echo "포트는 숫자여야 합니다."; return 1 fi - echo "请选择协议类型:" + echo "계약 유형을 선택하십시오:" echo "1. TCP 2. UDP" - read -erp "请输入序号 [1-2]: " proto_choice + read -erp "일련 번호 [1-2]를 입력하십시오:" proto_choice case "$proto_choice" in 1) proto="tcp"; listen_suffix="" ;; 2) proto="udp"; listen_suffix=" udp" ;; - *) echo "无效选择"; return 1 ;; + *) echo "잘못된 선택"; return 1 ;; esac - read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port + read -e -p "하나 이상의 백엔드 IP+포트를 공백으로 구분하여 입력하세요(예: 10.13.0.2:3306 10.13.0.3:3306)." reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3763,13 +3763,13 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear - echo "您的 $webname 搭建好了!" + echo "당신의$webname건설되었습니다!" echo "------------------------" - echo "访问地址:" + echo "방문 주소:" ip_address if [ -n "$ipv4_address" ]; then echo "$ipv4_address:${listen_port}" @@ -3808,12 +3808,12 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站点管理" - echo "LDNMP环境" + send_stats "LDNMP 사이트 관리" + echo "LDNMP 환경" echo "------------------------" ldnmp_v - echo -e "站点: ${output} 证书到期时间" + echo -e "대지:${output}인증서 만료 시간" echo -e "------------------------" for cert_file in /home/web/certs/*_cert.pem; do local domain=$(basename "$cert_file" | sed 's/_cert.pem//') @@ -3845,35 +3845,35 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "数据库: ${db_output}" + echo -e "데이터 베이스:${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" echo "------------------------" echo "" - echo "站点目录" + echo "사이트 디렉토리" echo "------------------------" - echo -e "数据 ${gl_hui}/home/web/html${gl_bai} 证书 ${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "데이터${gl_hui}/home/web/html${gl_bai}자격증${gl_hui}/home/web/certs${gl_bai}구성${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 申请/更新域名证书 2. 克隆站点域名" - echo "3. 清理站点缓存 4. 创建关联站点" - echo "5. 查看访问日志 6. 查看错误日志" - echo "7. 编辑全局配置 8. 编辑站点配置" - echo "9. 管理站点数据库 10. 查看站点分析报告" + echo "1. 도메인 이름 인증서 적용/업데이트 2. 사이트 도메인 이름 복제" + echo "3. 사이트 캐시 지우기 4. 관련 사이트 생성" + echo "5. 접속 로그 보기 6. 오류 로그 보기" + echo "7. 전역 구성 편집 8. 사이트 구성 편집" + echo "9. 사이트 데이터베이스 관리 10. 사이트 분석 보고서 보기" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. 특정 사이트 데이터 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" - read -e -p "请输入你的域名: " yuming + send_stats "도메인 이름 인증서 신청" + read -e -p "도메인 이름을 입력하세요:" yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3882,9 +3882,9 @@ ldnmp_web_status() { ;; 2) - send_stats "克隆站点域名" - read -e -p "请输入旧域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "복제 사이트 도메인 이름" + read -e -p "이전 도메인 이름을 입력하세요:" oddyuming + read -e -p "새 도메인 이름을 입력하세요:" yuming install_certbot install_ssltls certs_status @@ -3904,7 +3904,7 @@ ldnmp_web_status() { done done - # 网站目录替换 + # 웹사이트 디렉토리 교체 cp -r /home/web/html/$oddyuming /home/web/html/$yuming find /home/web/html/$yuming -type f -exec sed -i "s/$odd_dbname/$dbname/g" {} + @@ -3922,10 +3922,10 @@ ldnmp_web_status() { web_cache ;; 4) - send_stats "创建关联站点" - echo -e "为现有的站点再关联一个新域名用于访问" - read -e -p "请输入现有的域名: " oddyuming - read -e -p "请输入新域名: " yuming + send_stats "연결된 사이트 만들기" + echo -e "액세스하려면 새 도메인 이름을 기존 사이트에 연결하세요." + read -e -p "기존 도메인 이름을 입력하세요:" oddyuming + read -e -p "새 도메인 이름을 입력하세요:" yuming install_certbot install_ssltls certs_status @@ -3939,25 +3939,25 @@ ldnmp_web_status() { ;; 5) - send_stats "查看访问日志" + send_stats "접속 로그 보기" tail -n 200 /home/web/log/nginx/access.log break_end ;; 6) - send_stats "查看错误日志" + send_stats "오류 로그 보기" tail -n 200 /home/web/log/nginx/error.log break_end ;; 7) - send_stats "编辑全局配置" + send_stats "전역 구성 편집" install nano nano /home/web/nginx.conf docker exec nginx nginx -s reload ;; 8) - send_stats "编辑站点配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + send_stats "사이트 구성 편집" + read -e -p "사이트 구성을 편집하려면 편집하려는 도메인 이름을 입력하십시오:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -3967,7 +3967,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "查看站点数据" + send_stats "사이트 데이터 보기" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -3989,7 +3989,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安装${gl_bai}" + check_panel="${gl_lv}설치됨${gl_bai}" else check_panel="" fi @@ -3998,21 +3998,21 @@ fi install_panel() { -send_stats "${panelname}管理" +send_stats "${panelname}관리하다" while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}대중적이고 강력한 운영 및 유지 관리 관리 패널입니다." + echo "공식 웹사이트 소개:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 설치 2. 관리 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) check_disk_space 1 @@ -4021,20 +4021,20 @@ while true; do panel_app_install add_app_id - send_stats "${panelname}安装" + send_stats "${panelname}설치하다" ;; 2) panel_app_manage add_app_id - send_stats "${panelname}控制" + send_stats "${panelname}제어" ;; 3) panel_app_uninstall sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "${panelname}卸载" + send_stats "${panelname}제거" ;; *) break @@ -4050,9 +4050,9 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}已安装${gl_bai}" + check_frp="${gl_lv}설치됨${gl_bai}" else - check_frp="${gl_hui}未安装${gl_bai}" + check_frp="${gl_hui}설치되지 않음${gl_bai}" fi } @@ -4078,8 +4078,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "FRP 서버 설치" + # 임의의 포트 및 자격 증명 생성 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -4100,17 +4100,17 @@ EOF donlond_frp frps - # 输出生成的信息 + # 생성된 정보 출력 ip_address echo "------------------------" - echo "客户端部署时需要用的参数" - echo "服务IP: $ipv4_address" + echo "클라이언트 배포에 필요한 매개변수" + echo "서비스 IP:$ipv4_address" echo "token: $token" echo - echo "FRP面板信息" - echo "FRP面板地址: http://$ipv4_address:$dashboard_port" - echo "FRP面板用户名: $dashboard_user" - echo "FRP面板密码: $dashboard_pwd" + echo "FRP 패널 정보" + echo "FRP 패널 주소: http://$ipv4_address:$dashboard_port" + echo "FRP 패널 사용자 이름:$dashboard_user" + echo "FRP 패널 비밀번호:$dashboard_pwd" echo open_port 8055 8056 @@ -4120,9 +4120,9 @@ EOF configure_frpc() { - send_stats "安装frp客户端" - read -e -p "请输入外网对接IP: " server_addr - read -e -p "请输入外网对接token: " token + send_stats "FRP 클라이언트 설치" + read -e -p "외부 네트워크 도킹 IP를 입력하세요." server_addr + read -e -p "외부 네트워크 도킹 토큰을 입력하세요." token echo mkdir -p /home/frp @@ -4142,17 +4142,17 @@ EOF } add_forwarding_service() { - send_stats "添加frp内网服务" - # 提示用户输入服务名称和转发信息 - read -e -p "请输入服务名称: " service_name - read -e -p "请输入转发类型 (tcp/udp) [回车默认tcp]: " service_type + send_stats "FRP 인트라넷 서비스 추가" + # 사용자에게 서비스 이름 및 전달 정보를 묻는 메시지를 표시합니다. + read -e -p "서비스 이름을 입력하세요:" service_name + read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} - read -e -p "请输入内网IP [回车默认127.0.0.1]: " local_ip + read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} - read -e -p "请输入内网端口: " local_port - read -e -p "请输入外网端口: " remote_port + read -e -p "인트라넷 포트를 입력하십시오:" local_port + read -e -p "외부 네트워크 포트를 입력하세요:" remote_port - # 将用户输入写入配置文件 + # 구성 파일에 사용자 입력 쓰기 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -4162,8 +4162,8 @@ remote_port = ${remote_port} EOF - # 输出生成的信息 - echo "服务 $service_name 已成功添加到 frpc.toml" + # 생성된 정보 출력 + echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4174,12 +4174,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + send_stats "FRP 인트라넷 서비스 삭제" + # 삭제해야 하는 서비스 이름을 입력하라는 메시지를 사용자에게 표시합니다. + read -e -p "삭제할 서비스 이름을 입력하세요:" service_name + # sed를 사용하여 서비스 및 관련 구성 삭제 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服务 $service_name 已成功从 frpc.toml 删除" + echo "제공하다$service_namefrpc.toml에서 성공적으로 제거되었습니다." docker restart frpc @@ -4189,8 +4189,8 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 - printf "%-20s %-25s %-30s %-10s\n" "服务名称" "内网地址" "外网地址" "协议" + # 헤더 인쇄 + printf "%-20s %-25s %-30s %-10s\n" "서비스 이름" "인트라넷 주소" "외부 네트워크 주소" "규약" awk ' BEGIN { @@ -4210,7 +4210,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 서비스 정보가 이미 존재하는 경우 새 서비스를 처리하기 전에 현재 서비스를 인쇄하십시오. if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4219,11 +4219,11 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 현재 서비스 이름 업데이트 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 - # 清除之前的值 + # 이전 값 지우기 local_ip="" local_port="" remote_port="" @@ -4252,7 +4252,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 마지막 서비스에 대한 정보 인쇄 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4265,17 +4265,17 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# FRP 서버 포트 가져오기 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } -# 生成访问地址 +# 액세스 주소 생성 generate_access_urls() { - # 首先获取所有端口 + # 먼저 모든 포트를 확보하십시오. get_frp_ports - # 检查是否有非 8055/8056 的端口 + # 8055/8056 이외의 포트가 있는지 확인하세요. local has_valid_ports=false for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4284,18 +4284,18 @@ generate_access_urls() { fi done - # 只在有有效端口时显示标题和内容 + # 유효한 포트가 있는 경우에만 제목과 내용 표시 if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP 서비스 외부 액세스 주소:" - # 处理 IPv4 地址 + # IPv4 주소 처리 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then echo "http://${ipv4_address}:${port}" fi done - # 处理 IPv6 地址(如果存在) + # IPv6 주소가 있는 경우 처리 if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4304,7 +4304,7 @@ generate_access_urls() { done fi - # 处理 HTTPS 配置 + # HTTPS 구성 처리 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4331,7 +4331,7 @@ frps_main_ports() { frps_panel() { - send_stats "FRP服务端" + send_stats "FRP 서버" local app_id="55" local docker_name="frps" local docker_port=8056 @@ -4339,25 +4339,25 @@ frps_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP服务端 $check_frp $update_status" - echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" - echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo -e "FRP 서버$check_frp $update_status" + echo "FRP 인트라넷 침투 서비스 환경을 구축하고 공인 IP가 없는 장치를 인터넷에 노출시킵니다." + echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" + echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "5. 内网服务域名访问 6. 删除域名访问" + echo "5. 인트라넷 서비스 도메인 이름 접근 6. 도메인 이름 접근 삭제" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. IP+포트 접근 허용 8. IP+포트 접근 차단" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. 서비스 상태 새로고침 0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) install jq grep ss @@ -4365,7 +4365,7 @@ frps_panel() { generate_frps_config add_app_id - echo "FRP服务端已经安装完成" + echo "FRP 서버가 설치되었습니다" ;; 2) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -4375,7 +4375,7 @@ frps_panel() { donlond_frp frps add_app_id - echo "FRP服务端已经更新完成" + echo "FRP 서버가 업데이트되었습니다" ;; 3) crontab -l | grep -v 'frps' | crontab - > /dev/null 2>&1 @@ -4386,37 +4386,37 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다." ;; 5) - echo "将内网穿透服务反代成域名访问" - send_stats "FRP对外域名访问" + echo "도메인 이름 액세스에 대한 역인트라넷 침투 서비스" + send_stats "FRP 외부 도메인 이름 액세스" add_yuming - read -e -p "请输入你的内网穿透服务端口: " frps_port + read -e -p "인트라넷 침투 서비스 포트를 입력하십시오:" frps_port ldnmp_Proxy ${yuming} 127.0.0.1 ${frps_port} block_host_port "$frps_port" "$ipv4_address" ;; 6) - echo "域名格式 example.com 不带https://" + echo "https://가 없는 도메인 이름 형식 example.com" web_del ;; 7) - send_stats "允许IP访问" - read -e -p "请输入需要放行的端口: " frps_port + send_stats "IP 액세스 허용" + read -e -p "해제해야 하는 포트를 입력하세요." frps_port clear_host_port_rules "$frps_port" "$ipv4_address" ;; 8) - send_stats "阻止IP访问" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" - read -e -p "请输入需要阻止的端口: " frps_port + send_stats "IP 접근 차단" + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; 00) - send_stats "刷新FRP服务状态" - echo "已经刷新FRP服务状态" + send_stats "FRP 서비스 상태 새로 고침" + echo "FRP 서비스 상태가 새로 고쳐졌습니다." ;; *) @@ -4429,7 +4429,7 @@ frps_panel() { frpc_panel() { - send_stats "FRP客户端" + send_stats "FRP 클라이언트" local app_id="56" local docker_name="frpc" local docker_port=8055 @@ -4437,10 +4437,10 @@ frpc_panel() { clear check_frp_app check_docker_image_update $docker_name - echo -e "FRP客户端 $check_frp $update_status" - echo "与服务端对接,对接后可创建内网穿透服务到互联网访问" - echo "官网介绍: ${gh_https_url}github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo -e "FRP 클라이언트$check_frp $update_status" + echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." + echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" + echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -4448,13 +4448,13 @@ frpc_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. 외부 서비스 추가 5. 외부 서비스 삭제 6. 서비스 수동 구성" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) install jq grep ss @@ -4462,7 +4462,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP客户端已经安装完成" + echo "FRP 클라이언트가 설치되었습니다" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4472,7 +4472,7 @@ frpc_panel() { donlond_frp frpc add_app_id - echo "FRP客户端已经更新完成" + echo "FRP 클라이언트가 업데이트되었습니다." ;; 3) @@ -4483,7 +4483,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다." ;; 4) @@ -4523,74 +4523,74 @@ yt_menu_pro() { while true; do if [ -x "/usr/local/bin/yt-dlp" ]; then - local YTDLP_STATUS="${gl_lv}已安装${gl_bai}" + local YTDLP_STATUS="${gl_lv}설치됨${gl_bai}" else - local YTDLP_STATUS="${gl_hui}未安装${gl_bai}" + local YTDLP_STATUS="${gl_hui}설치되지 않음${gl_bai}" fi clear - send_stats "yt-dlp 下载工具" + send_stats "yt-dlp 다운로드 도구" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" - echo -e "官网地址:${gh_https_url}github.com/yt-dlp/yt-dlp" + echo -e "yt-dlp는 YouTube, Bilibili, Twitter 등과 같은 수천 개의 사이트를 지원하는 강력한 비디오 다운로드 도구입니다." + echo -e "공식 웹사이트 주소:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + echo "다운로드한 동영상 목록:" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(아직 없음)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. 단일 비디오 다운로드 6. 일괄 비디오 다운로드 7. 사용자 정의 매개변수 다운로드" + echo "8. MP3 오디오로 다운로드 9. 비디오 디렉터리 삭제 10. 쿠키 관리(개발 중)" echo "-------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "-------------------------" - read -e -p "请输入选项编号: " choice + read -e -p "옵션 번호를 입력하세요:" choice case $choice in 1) - send_stats "正在安装 yt-dlp..." - echo "正在安装 yt-dlp..." + send_stats "yt-dlp 설치 중..." + echo "yt-dlp 설치 중..." install ffmpeg curl -L ${gh_https_url}github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp chmod a+rx /usr/local/bin/yt-dlp add_app_id - echo "安装完成。按任意键继续..." + echo "설치가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 2) - send_stats "正在更新 yt-dlp..." - echo "正在更新 yt-dlp..." + send_stats "yt-dlp 업데이트 중..." + echo "yt-dlp 업데이트 중..." yt-dlp -U add_app_id - echo "更新完成。按任意键继续..." + echo "업데이트가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "yt-dlp 제거 중..." + echo "yt-dlp 제거 중..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成。按任意键继续..." + echo "제거가 완료되었습니다. 계속하려면 아무 키나 누르세요..." read ;; 5) - send_stats "单个视频下载" - read -e -p "请输入视频链接: " url + send_stats "단일 비디오 다운로드" + read -e -p "동영상 링크를 입력하세요:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 6) - send_stats "批量视频下载" + send_stats "일괄 비디오 다운로드" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 여러 개의 동영상 링크 주소를 입력하세요\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE - echo "现在开始批量下载..." + echo "지금 일괄 다운로드를 시작하세요..." yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4598,31 +4598,31 @@ yt_menu_pro() { -a "$URL_FILE" \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "批量下载完成,按任意键继续..." ;; + read -e -p "일괄 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 7) - send_stats "自定义视频下载" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + send_stats "맞춤형 비디오 다운로드" + read -e -p "전체 yt-dlp 매개변수를 입력하세요(yt-dlp 제외)." custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites - read -e -p "执行完成,按任意键继续..." ;; + read -e -p "실행이 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 8) - send_stats "MP3下载" - read -e -p "请输入视频链接: " url + send_stats "MP3 다운로드" + read -e -p "동영상 링크를 입력하세요:" url yt-dlp -P "$VIDEO_DIR" -x --audio-format mp3 \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "오디오 다운로드가 완료되었습니다. 계속하려면 아무 키나 누르세요..." ;; 9) - send_stats "删除视频" - read -e -p "请输入删除视频名称: " rmdir + send_stats "동영상 삭제" + read -e -p "삭제된 동영상의 이름을 입력하세요:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4658,7 +4658,7 @@ set_timedate() { -# 修复dpkg中断问题 +# dpkg 중단 문제 수정 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4667,7 +4667,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_kjlan}正在系统更新...${gl_bai}" + echo -e "${gl_kjlan}시스템 업데이트 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4686,7 +4686,7 @@ linux_update() { elif command -v opkg &>/dev/null; then opkg update else - echo "未知的包管理器!" + echo "알 수 없는 패키지 관리자입니다!" return fi } @@ -4694,7 +4694,7 @@ linux_update() { linux_clean() { - echo -e "${gl_kjlan}正在系统清理...${gl_bai}" + echo -e "${gl_kjlan}시스템 청소 진행 중...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -4723,13 +4723,13 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v apk &>/dev/null; then - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 정리..." apk cache clean - echo "删除系统日志..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "删除APK缓存..." + echo "APK 캐시 삭제..." rm -rf /var/cache/apk/* - echo "删除临时文件..." + echo "임시 파일 삭제..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -4747,23 +4747,23 @@ linux_clean() { journalctl --vacuum-size=500M elif command -v opkg &>/dev/null; then - echo "删除系统日志..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제..." rm -rf /tmp/* elif command -v pkg &>/dev/null; then - echo "清理未使用的依赖..." + echo "사용하지 않는 종속성을 정리합니다..." pkg autoremove -y - echo "清理包管理器缓存..." + echo "패키지 관리자 캐시 정리..." pkg clean -y - echo "删除系统日志..." + echo "시스템 로그 삭제..." rm -rf /var/log/* - echo "删除临时文件..." + echo "임시 파일 삭제..." rm -rf /tmp/* else - echo "未知的包管理器!" + echo "알 수 없는 패키지 관리자입니다!" return fi return @@ -4773,13 +4773,13 @@ linux_clean() { bbr_on() { -# 统一写入到 sysctl.d 以防与内核调优模块打架 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能导致冲突的旧版 sysctl.conf 残留 +# 충돌을 일으킬 수 있는 이전 sysctl.conf의 남은 부분을 정리합니다. sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4817,26 +4817,26 @@ chattr +i /etc/resolv.conf set_dns_ui() { root_use -send_stats "优化DNS" +send_stats "DNS 최적화" while true; do clear - echo "优化DNS地址" + echo "DNS 주소 최적화" echo "------------------------" - echo "当前DNS地址" + echo "현재 DNS 주소" cat /etc/resolv.conf echo "------------------------" echo "" - echo "1. 国外DNS优化: " + echo "1. 외국 DNS 최적화:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 国内DNS优化: " + echo "2. 국내 DNS 최적화:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. 手动编辑DNS配置" + echo "3. DNS 구성을 수동으로 편집" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) local dns1_ipv4="1.1.1.1" @@ -4844,7 +4844,7 @@ while true; do local dns1_ipv6="2606:4700:4700::1111" local dns2_ipv6="2001:4860:4860::8888" set_dns - send_stats "国外DNS优化" + send_stats "외국 DNS 최적화" ;; 2) local dns1_ipv4="223.5.5.5" @@ -4852,14 +4852,14 @@ while true; do local dns1_ipv6="2400:3200::1" local dns2_ipv6="2400:da00::6666" set_dns - send_stats "国内DNS优化" + send_stats "국내 DNS 최적화" ;; 3) install nano chattr -i /etc/resolv.conf nano /etc/resolv.conf chattr +i /etc/resolv.conf - send_stats "手动编辑DNS配置" + send_stats "DNS 구성을 수동으로 편집" ;; *) break @@ -4913,7 +4913,7 @@ new_ssh_port() { open_port $new_port remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "SSH 端口已修改为: $new_port" + echo "SSH 포트가 다음과 같이 수정되었습니다.$new_port" sleep 1 @@ -4929,7 +4929,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" + echo -e "${gl_lv}사용자 키 로그인 모드가 켜져 있고 비밀번호 로그인 모드가 꺼졌습니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -4947,7 +4947,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "개인키 정보가 생성되었습니다. 꼭 복사해서 저장하세요. 다음과 같이 저장될 수 있습니다.${gl_huang}${ipv4_address}_ssh.key${gl_bai}향후 SSH 로그인을 위한 파일" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -4968,21 +4968,21 @@ import_sshkey() { local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "SSH 공개 키(일반적으로 'ssh-rsa' 또는 'ssh-ed25519'로 시작)의 내용을 입력하세요." public_key fi if [[ -z "$public_key" ]]; then - echo -e "${gl_hong}错误:未输入公钥内容。${gl_bai}" + echo -e "${gl_hong}오류: 공개 키 내용이 입력되지 않았습니다.${gl_bai}" return 1 fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}错误:看起来不像合法的 SSH 公钥。${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi if grep -Fxq "$public_key" "$auth_keys" 2>/dev/null; then - echo "该公钥已存在,无需重复添加" + echo "공개 키가 이미 존재하므로 다시 추가할 필요가 없습니다." return 0 fi @@ -5006,40 +5006,40 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - read -e -p "请输入您的远端公钥URL: " keys_url + read -e -p "원격 공개 키 URL을 입력하세요:" keys_url fi - echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" + echo "이 스크립트는 원격 URL에서 SSH 공개 키를 가져와서${authorized_keys}" echo "" - echo "远程公钥地址:" + echo "원격 공개 키 주소:" echo " ${keys_url}" echo "" - # 创建临时文件 + # 임시 파일 만들기 temp_file=$(mktemp) - # 下载公钥 + # 공개 키 다운로드 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 + echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 + echo "오류: URL에서 공개 키를 다운로드할 수 없습니다(네트워크 문제 또는 잘못된 주소)." >&2 rm -f "${temp_file}" return 1 } else - echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + echo "오류: 시스템에서 컬 또는 wget을 찾을 수 없어 공개 키를 다운로드할 수 없습니다." >&2 rm -f "${temp_file}" return 1 fi - # 检查内容是否有效 + # 콘텐츠가 유효한지 확인하세요. if [[ ! -s "${temp_file}" ]]; then - echo "错误:下载到的文件为空,URL 可能不包含任何公钥" >&2 + echo "오류: 다운로드한 파일이 비어 있으며 URL에 공개 키가 포함되어 있지 않을 수 있습니다." >&2 rm -f "${temp_file}" return 1 fi @@ -5049,13 +5049,13 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 备份原有 authorized_keys + # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "已备份原有 authorized_keys 文件" + echo "원래 Authorized_keys 파일이 백업되었습니다." fi - # 追加公钥(避免重复) + # 공개 키 추가(중복 방지) local added=0 while IFS= read -r line; do [[ -z "${line}" || "${line}" =~ ^# ]] && continue @@ -5070,10 +5070,10 @@ fetch_remote_ssh_keys() { echo "" if (( added > 0 )); then - echo "成功添加 ${added} 条新的公钥到 ${authorized_keys}" + echo "성공적으로 추가되었습니다${added}새로운 공개 키가 도착합니다${authorized_keys}" sshkey_on else - echo "没有新的公钥需要添加(可能已全部存在)" + echo "새로운 공개 키를 추가할 필요가 없습니다(모두 이미 존재할 수도 있음)." fi echo "" @@ -5087,24 +5087,24 @@ fetch_github_ssh_keys() { local username="$1" local base_dir="${2:-$HOME}" - echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo " 1. 登录 ${gh_https_url}github.com/settings/keys" - echo " 2. 点击 New SSH key 或 Add SSH key" - echo " 3. Title 可随意填写(例如:Home Laptop 2026)" - echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" - echo " 5. 点击 Add SSH key 完成添加" + echo "계속하기 전에 SSH 공개 키를 GitHub 계정에 추가했는지 확인하세요." + echo "1. 로그인${gh_https_url}github.com/settings/keys" + echo "2. 새 SSH 키 또는 SSH 키 추가를 클릭하세요." + echo "3. 제목은 원하는 대로 입력할 수 있습니다. (예: Home Laptop 2026)" + echo "4. 로컬 공개 키의 내용(일반적으로 ~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 전체 내용)을 키 필드에 붙여넣습니다." + echo "5. SSH 키 추가를 클릭하여 추가를 완료합니다." echo "" - echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " ${gh_https_url}github.com/您的用户名.keys" + echo "추가되면 모든 공개 키는 다음 GitHub에서 공개적으로 사용할 수 있습니다." + echo " ${gh_https_url}github.com/yourusername.keys" echo "" if [[ -z "${username}" ]]; then - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + read -e -p "GitHub 사용자 이름(@ 없는 사용자 이름)을 입력하세요." username fi if [[ -z "${username}" ]]; then - echo "错误:GitHub 用户名不能为空" >&2 + echo "오류: GitHub 사용자 이름은 비워둘 수 없습니다." >&2 return 1 fi @@ -5117,64 +5117,64 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "用户密钥登录" + send_stats "사용자 키 로그인" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') if [[ "$REAL_STATUS" =~ "yes" ]]; then - IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" + IS_KEY_ENABLED="${gl_lv}활성화됨${gl_bai}" else - IS_KEY_ENABLED="${gl_hui}未启用${gl_bai}" + IS_KEY_ENABLED="${gl_hui}활성화되지 않음${gl_bai}" fi - echo -e "用户密钥登录模式 ${IS_KEY_ENABLED}" - echo "进阶玩法: https://blog.kejilion.pro/ssh-key" + echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" + echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" - echo "1. 生成新密钥对 2. 手动输入已有公钥" - echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" - echo "5. 编辑公钥文件 6. 查看本机密钥" + echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" + echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." + echo "5. 공개 키 파일 편집 6. 로컬 키 보기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택사항을 입력하세요:" host_dns case $host_dns in 1) - send_stats "生成新密钥" + send_stats "새 키 생성" add_sshkey break_end ;; 2) - send_stats "导入已有公钥" + send_stats "기존 공개 키 가져오기" import_sshkey break_end ;; 3) - send_stats "导入GitHub远端公钥" + send_stats "GitHub 원격 공개 키 가져오기" fetch_github_ssh_keys break_end ;; 4) - send_stats "导入URL远端公钥" - read -e -p "请输入您的远端公钥URL: " keys_url + send_stats "URL 원격 공개 키 가져오기" + read -e -p "원격 공개 키 URL을 입력하세요:" keys_url fetch_remote_ssh_keys "${keys_url}" break_end ;; 5) - send_stats "编辑公钥文件" + send_stats "공개 키 파일 편집" install nano nano ${HOME}/.ssh/authorized_keys break_end ;; 6) - send_stats "查看本机密钥" + send_stats "로컬 키 보기" echo "------------------------" - echo "公钥信息" + echo "공개키 정보" cat ${HOME}/.ssh/authorized_keys echo "------------------------" - echo "私钥信息" + echo "개인 키 정보" cat ${HOME}/.ssh/sshkey echo "------------------------" break_end @@ -5196,22 +5196,22 @@ sshkey_panel() { add_sshpasswd() { root_use - send_stats "设置密码登录模式" - echo "设置密码登录模式" + send_stats "비밀번호 로그인 모드 설정" + echo "비밀번호 로그인 모드 설정" local target_user="$1" - # 如果没有通过参数传入,则交互输入 + # 매개변수가 전달되지 않으면 대화형으로 입력하세요. if [[ -z "$target_user" ]]; then - read -e -p "请输入要修改密码的用户名(默认 root): " target_user + read -e -p "비밀번호를 변경하려는 사용자 이름을 입력하십시오(기본 루트):" target_user fi - # 回车不输入,默认 root + # Enter를 누르고 입력하지 마십시오. 기본값은 root입니다. target_user=${target_user:-root} - # 校验用户是否存在 + # 사용자가 존재하는지 확인 if ! id "$target_user" >/dev/null 2>&1; then - echo "错误:用户 $target_user 不存在" + echo "오류: 사용자$target_user존재하지 않는다" return 1 fi @@ -5226,7 +5226,7 @@ add_sshpasswd() { restart_ssh - echo -e "${gl_lv}密码设置完毕,已更改为密码登录模式!${gl_bai}" + echo -e "${gl_lv}비밀번호가 설정되어 비밀번호 로그인 모드로 변경되었습니다!${gl_bai}" } @@ -5244,7 +5244,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}提示: ${gl_bai}该功能需要root用户才能运行!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}힌트:${gl_bai}이 기능을 실행하려면 루트 사용자가 필요합니다!" && break_end && kejilion } @@ -5259,7 +5259,7 @@ clear dd_xitong() { - send_stats "重装系统" + send_stats "시스템 재설치" dd_xitong_MollyLau() { wget --no-check-certificate -qO InstallNET.sh "${gh_proxy}raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh" && chmod a+x InstallNET.sh @@ -5270,44 +5270,44 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令行输入passwd修改密码${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}LeitboGi0ro${gl_bai}초기 포트:${gl_huang}22${gl_bai}" + echo -e "${gl_huang}재설치 후에는 초기 비밀번호를 적시에 변경하여 폭력적인 침입을 방지하시기 바랍니다. 비밀번호를 변경하려면 명령줄에 passwd를 입력하세요.${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_2() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget dd_xitong_MollyLau } dd_xitong_3() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}22${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름:${gl_huang}root${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}22${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" dd_xitong_bin456789 } dd_xitong_4() { - echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai} 初始密码: ${gl_huang}123@@@${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" - echo -e "按任意键继续..." + echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}123@@@${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" dd_xitong_bin456789 } while true; do root_use - echo "重装系统" + echo "시스템 재설치" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " - echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro项目地址: ${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." + echo -e "${gl_hui}스크립트 지원을 해주신 bin456789 보스와 leitbogioro 보스에게 감사드립니다!${gl_bai} " + echo -e "${gl_hui}bin456789 프로젝트 주소:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}leitbogioro 프로젝트 주소:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -5323,21 +5323,21 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. openSUSE Tumbleweed 36. fnos Feiniu 공개 베타 버전" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" echo "45. Windows Server 2022 46. Windows Server 2019" echo "47. Windows 11 ARM" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "다시 설치하려는 시스템을 선택하십시오:" sys_choice case "$sys_choice" in 1) - send_stats "重装debian 13" + send_stats "데비안 13 재설치" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -5345,49 +5345,49 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "데비안 12 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 12 reboot exit ;; 3) - send_stats "重装debian 11" + send_stats "데비안 11 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 11 reboot exit ;; 4) - send_stats "重装debian 10" + send_stats "데비안 10 다시 설치" dd_xitong_1 bash InstallNET.sh -debian 10 reboot exit ;; 11) - send_stats "重装ubuntu 24.04" + send_stats "우분투 24.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "우분투 22.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "우분투 20.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 20.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "우분투 18.04 다시 설치" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -5396,7 +5396,7 @@ dd_xitong() { 21) - send_stats "重装rockylinux10" + send_stats "rockylinux10 재설치" dd_xitong_3 bash reinstall.sh rocky reboot @@ -5404,7 +5404,7 @@ dd_xitong() { ;; 22) - send_stats "重装rockylinux9" + send_stats "rockylinux9 재설치" dd_xitong_3 bash reinstall.sh rocky 9 reboot @@ -5412,7 +5412,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "alma10 재설치" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5420,7 +5420,7 @@ dd_xitong() { ;; 24) - send_stats "重装alma9" + send_stats "alma9 재설치" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -5428,7 +5428,7 @@ dd_xitong() { ;; 25) - send_stats "重装oracle10" + send_stats "oracle10 재설치" dd_xitong_3 bash reinstall.sh oracle reboot @@ -5436,7 +5436,7 @@ dd_xitong() { ;; 26) - send_stats "重装oracle9" + send_stats "oracle9 재설치" dd_xitong_3 bash reinstall.sh oracle 9 reboot @@ -5444,7 +5444,7 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "fedora42 재설치" dd_xitong_3 bash reinstall.sh fedora reboot @@ -5452,7 +5452,7 @@ dd_xitong() { ;; 28) - send_stats "重装fedora41" + send_stats "fedora41 재설치" dd_xitong_3 bash reinstall.sh fedora 41 reboot @@ -5460,7 +5460,7 @@ dd_xitong() { ;; 29) - send_stats "重装centos10" + send_stats "centos10 재설치" dd_xitong_3 bash reinstall.sh centos 10 reboot @@ -5468,7 +5468,7 @@ dd_xitong() { ;; 30) - send_stats "重装centos9" + send_stats "centos9 재설치" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5476,7 +5476,7 @@ dd_xitong() { ;; 31) - send_stats "重装alpine" + send_stats "알파인 재설치" dd_xitong_1 bash InstallNET.sh -alpine reboot @@ -5484,7 +5484,7 @@ dd_xitong() { ;; 32) - send_stats "重装arch" + send_stats "아치 재설치" dd_xitong_3 bash reinstall.sh arch reboot @@ -5492,7 +5492,7 @@ dd_xitong() { ;; 33) - send_stats "重装kali" + send_stats "칼리 재설치" dd_xitong_3 bash reinstall.sh kali reboot @@ -5500,7 +5500,7 @@ dd_xitong() { ;; 34) - send_stats "重装openeuler" + send_stats "openeuler 다시 설치" dd_xitong_3 bash reinstall.sh openeuler reboot @@ -5508,7 +5508,7 @@ dd_xitong() { ;; 35) - send_stats "重装opensuse" + send_stats "Openuse 다시 설치" dd_xitong_3 bash reinstall.sh opensuse reboot @@ -5516,7 +5516,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "Feiniu 재설치" dd_xitong_3 bash reinstall.sh fnos reboot @@ -5524,7 +5524,7 @@ dd_xitong() { ;; 41) - send_stats "重装windows11" + send_stats "윈도우 11 재설치" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5533,14 +5533,14 @@ dd_xitong() { 42) dd_xitong_2 - send_stats "重装windows10" + send_stats "윈도우 10 재설치" bash InstallNET.sh -windows 10 -lang "cn" reboot exit ;; 43) - send_stats "重装windows7" + send_stats "Windows7을 다시 설치하세요." dd_xitong_4 bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' reboot @@ -5548,7 +5548,7 @@ dd_xitong() { ;; 44) - send_stats "重装windows server 25" + send_stats "Windows Server 25를 다시 설치하세요." dd_xitong_2 bash InstallNET.sh -windows 2025 -lang "cn" reboot @@ -5556,7 +5556,7 @@ dd_xitong() { ;; 45) - send_stats "重装windows server 22" + send_stats "윈도우 서버 22 재설치" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -5564,7 +5564,7 @@ dd_xitong() { ;; 46) - send_stats "重装windows server 19" + send_stats "윈도우 서버 19 재설치" dd_xitong_2 bash InstallNET.sh -windows 2019 -lang "cn" reboot @@ -5572,7 +5572,7 @@ dd_xitong() { ;; 47) - send_stats "重装windows11 ARM" + send_stats "windows11 ARM 재설치" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -5589,7 +5589,7 @@ dd_xitong() { bbrv3() { root_use - send_stats "bbrv3管理" + send_stats "bbrv3 관리" local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then @@ -5602,17 +5602,17 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "您已安装xanmod的BBRv3内核" - echo "当前内核版本: $kernel_version" + echo "xanmod의 BBRv3 커널이 설치되어 있습니다." + echo "현재 커널 버전:$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. BBRv3 커널 업데이트 2. BBRv3 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) @@ -5622,7 +5622,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3단계: 저장소 추가 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5631,7 +5631,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod内核已更新。重启后生效" + echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5641,7 +5641,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod内核已卸载。重启后生效" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot ;; @@ -5654,13 +5654,13 @@ bbrv3() { else clear - echo "设置BBR3加速" - echo "视频介绍: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" + echo "BBR3 가속 설정" + echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" - echo "请备份数据,将为你升级Linux内核开启BBR3" + echo "데비안/우분투만 지원" + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -5668,12 +5668,12 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." break_end linux_Settings fi else - echo "无法确定操作系统类型" + echo "운영 체제 유형을 확인할 수 없습니다." break_end linux_Settings fi @@ -5684,7 +5684,7 @@ bbrv3() { # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - # 步骤3:添加存储库 + # 3단계: 저장소 추가 echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') @@ -5695,17 +5695,17 @@ bbrv3() { bbr_on - echo "XanMod内核安装并BBR3启用成功。重启后生效" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac fi @@ -5714,40 +5714,40 @@ bbrv3() { elrepo_install() { - # 导入 ELRepo GPG 公钥 - echo "导入 ELRepo GPG 公钥..." + # ELRepo GPG 공개 키 가져오기 + echo "ELRepo GPG 공개 키 가져오기..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - # 检测系统版本 + # 시스템 버전 확인 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 지원되는 운영 체제에서 실행되고 있는지 확인하세요. if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then - echo "不支持的操作系统:$os_name" + echo "지원되지 않는 운영 체제:$os_name" break_end linux_Settings fi - # 打印检测到的操作系统信息 - echo "检测到的操作系统: $os_name $os_version" - # 根据系统版本安装对应的 ELRepo 仓库配置 + # 감지된 운영 체제 정보 인쇄 + echo "감지된 운영 체제:$os_name $os_version" + # 시스템 버전에 따라 해당 ELRepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then - echo "安装 ELRepo 仓库配置 (版本 8)..." + echo "ELRepo 저장소 구성(버전 8) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "ELRepo 저장소 구성(버전 9) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "ELRepo 저장소 구성(버전 10) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "지원되지 않는 시스템 버전:$os_version" break_end linux_Settings fi - # 启用 ELRepo 内核仓库并安装最新的主线内核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + # ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치합니다. + echo "ELRepo 커널 저장소를 활성화하고 최신 메인라인 커널을 설치하세요..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "ELRepo 저장소 구성을 설치하고 최신 메인라인 커널로 업데이트했습니다." server_reboot } @@ -5755,37 +5755,37 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "Red Hat 커널 관리" if uname -r | grep -q 'elrepo'; then while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" - echo "当前内核版本: $kernel_version" + echo "elrepo 커널을 설치했습니다" + echo "현재 커널 버전:$kernel_version" echo "" - echo "内核管理" + echo "커널 관리" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. elrepo 커널 업데이트 2. elrepo 커널 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps elrepo_install - send_stats "更新红帽内核" + send_stats "Red Hat 커널 업데이트" server_reboot ;; 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重启后生效" - send_stats "卸载红帽内核" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + send_stats "Red Hat 커널 제거" server_reboot ;; @@ -5798,26 +5798,26 @@ elrepo() { else clear - echo "请备份数据,将为你升级Linux内核" - echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드해 드리겠습니다." + echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" - read -e -p "确定继续吗?(Y/N): " choice + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hat 커널 업그레이드" server_reboot ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac fi @@ -5828,7 +5828,7 @@ elrepo() { clamav_freshclam() { - echo -e "${gl_kjlan}正在更新病毒库...${gl_bai}" + echo -e "${gl_kjlan}바이러스 데이터베이스 업데이트 중...${gl_bai}" docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5838,19 +5838,19 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "스캔할 디렉터리를 지정하십시오." return fi - echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_kjlan}$@ 디렉터리를 검색하는 중...${gl_bai}" - # 构建 mount 参数 + # 마운트 매개변수 빌드 local MOUNT_PARAMS="" for dir in "$@"; do MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # clamscan 명령 매개변수 빌드 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5859,7 +5859,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # 도커 명령 실행 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5869,7 +5869,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}바이러스 있으면 제발${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" } @@ -5881,23 +5881,23 @@ clamav_scan() { clamav() { root_use - send_stats "病毒扫描管理" + send_stats "바이러스 검사 관리" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav 바이러스 검사 도구" + echo "영상 소개: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" - echo "是一个开源的防病毒软件工具,主要用于检测和删除各种类型的恶意软件。" - echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" + echo "다양한 유형의 악성 코드를 탐지하고 제거하는 데 주로 사용되는 오픈 소스 바이러스 백신 소프트웨어 도구입니다." + echo "바이러스, 트로이 목마, 스파이웨어, 악성 스크립트 및 기타 유해한 소프트웨어가 포함됩니다." echo "------------------------" - echo -e "${gl_lv}1. 全盘扫描 ${gl_bai} ${gl_huang}2. 重要目录扫描 ${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. 전체 스캔${gl_bai} ${gl_huang}2. 중요한 디렉토리 스캔${gl_bai} ${gl_kjlan}3. 사용자 정의 디렉터리 검색${gl_bai}" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "全盘扫描" + send_stats "전체 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5906,7 +5906,7 @@ clamav() { ;; 2) - send_stats "重要目录扫描" + send_stats "중요한 디렉토리 스캔" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -5914,8 +5914,8 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + send_stats "사용자 정의 디렉토리 스캔" + read -e -p "스캔할 디렉터리를 공백으로 구분하여 입력하십시오(예: /etc /var /usr /home /root)." directories install_docker clamav_freshclam clamav_scan $directories @@ -5931,27 +5931,27 @@ clamav() { # ============================================================================ -# Linux 内核调优模块(重构版) -# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 -# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# Linux 커널 조정 모듈(리팩터링 버전) +# 통합 핵심 기능 + 장면 차별화 매개변수 + 구성 파일 지속성 + 하드웨어 적응 +# 원래의optim_high_performance/optim_balanced/optim_web_server/restore_defaults를 교체하십시오. # ============================================================================ -# 获取内存大小(MB) +# 메모리 크기(MB) 가져오기 _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo } -# 统一内核调优核心函数 -# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) +# 통합 커널 튜닝 핵심 기능 +# 매개변수: $1 = 모드 이름, $2 = 장면(하이/밸런스/웹/스트림/게임) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" local MEM_MB=$(_get_mem_mb) - echo -e "${gl_lv}切换到${mode_name}...${gl_bai}" + echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ── 根据场景设定参数 ── + # ──장면에 따라 매개변수를 설정하세요── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -5960,7 +5960,7 @@ _kernel_optimize_core() { case "$scene" in high|stream|game) - # 高性能/直播/游戏:激进参数 + # 고성능/생방송/게임: 급진적인 매개변수 SWAPPINESS=10 DIRTY_RATIO=15 DIRTY_BG_RATIO=5 @@ -5983,7 +5983,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; web) - # 网站服务器:高并发优先 + # 웹사이트 서버: 높은 동시성 우선순위 SWAPPINESS=10 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6006,7 +6006,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; balanced) - # 均衡模式:适度优化 + # 균형 모드: 보통 최적화 SWAPPINESS=30 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6030,7 +6030,7 @@ _kernel_optimize_core() { ;; esac - # ── 根据内存大小自适应调整 ── + # ── 메모리 크기에 따라 적응적으로 조정 ── if [ "$MEM_MB" -ge 16384 ]; then MIN_FREE_KB=131072 [ "$scene" != "balanced" ] && SWAPPINESS=5 @@ -6038,7 +6038,7 @@ _kernel_optimize_core() { MIN_FREE_KB=65536 elif [ "$MEM_MB" -ge 1024 ]; then MIN_FREE_KB=32768 - # 小内存缩小缓冲区 + # 작은 메모리 축소 버퍼 if [ "$scene" != "balanced" ]; then RMEM_MAX=16777216 WMEM_MAX=16777216 @@ -6057,28 +6057,28 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── 直播场景额外:UDP 缓冲区加大 ── + # ── 추가 라이브 방송 시나리오: UDP 버퍼 확대 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" -# 直播推流 UDP 优化 +# 라이브 스트리밍 UDP 최적화 net.ipv4.udp_rmem_min = 16384 net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 游戏服场景额外:低延迟优先 ── + # ── 게임 서버 장면 추가: 낮은 대기 시간 우선 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" -# 游戏服低延迟优化 +# 게임 서버 낮은 대기 시간 최적화 net.ipv4.udp_rmem_min = 16384 net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384 net.ipv4.tcp_slow_start_after_idle = 0" fi - # ── 加载 BBR 模块 ── + # ── BBR 모듈 로드 ── local CC="bbr" local QDISC="fq" local KVER @@ -6096,21 +6096,21 @@ net.ipv4.tcp_slow_start_after_idle = 0" QDISC="fq_codel" fi - # ── 备份已有配置 ── + # ── 기존 구성 백업 ── [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" - # ── 写入配置文件(持久化) ── - echo -e "${gl_lv}写入优化配置...${gl_bai}" + # ── 구성 파일 쓰기(지속성) ── + echo -e "${gl_lv}최적화 구성 쓰기...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 内核调优配置 -# 模式: $mode_name | 场景: $scene -# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') +# 케질리온 커널 튜닝 구성 +# 모드: $mode_name | 장면: $장면 +# 메모리: ${MEM_MB}MB | 생성 시간: $(날짜 '+%Y-%m-%d %H:%M:%S') -# ── TCP 拥塞控制 ── +# ──TCP 혼잡 제어── net.core.default_qdisc = $QDISC net.ipv4.tcp_congestion_control = $CC -# ── TCP 缓冲区 ── +# ── TCP 버퍼 ── net.core.rmem_max = $RMEM_MAX net.core.wmem_max = $WMEM_MAX net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') @@ -6118,12 +6118,12 @@ net.core.wmem_default = $(echo "$TCP_WMEM" | awk '{print $2}') net.ipv4.tcp_rmem = $TCP_RMEM net.ipv4.tcp_wmem = $TCP_WMEM -# ── 连接队列 ── +# ── 연결 큐 ── net.core.somaxconn = $SOMAXCONN net.core.netdev_max_backlog = $BACKLOG net.ipv4.tcp_max_syn_backlog = $SYN_BACKLOG -# ── TCP 连接优化 ── +# ── TCP 연결 최적화 ── net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = $FIN_TIMEOUT @@ -6139,12 +6139,12 @@ net.ipv4.tcp_sack = 1 net.ipv4.tcp_timestamps = 1 net.ipv4.tcp_window_scaling = 1 -# ── 端口与内存 ── +# ── 포트와 메모리 ── net.ipv4.ip_local_port_range = $PORT_RANGE net.ipv4.tcp_mem = $((MEM_MB * 1024 / 8)) $((MEM_MB * 1024 / 4)) $((MEM_MB * 1024 / 2)) net.ipv4.tcp_max_orphans = 32768 -# ── 虚拟内存 ── +# ── 가상 메모리 ── vm.swappiness = $SWAPPINESS vm.dirty_ratio = $DIRTY_RATIO vm.dirty_background_ratio = $DIRTY_BG_RATIO @@ -6152,11 +6152,11 @@ vm.overcommit_memory = $OVERCOMMIT vm.min_free_kbytes = $MIN_FREE_KB vm.vfs_cache_pressure = $VFS_PRESSURE -# ── CPU/内核调度 ── +# ──CPU/커널 스케줄링── kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP -$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing 不支持") +$([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing은 지원되지 않습니다") -# ── 安全防护 ── +# ──안전 보호── net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 @@ -6168,11 +6168,11 @@ net.ipv4.conf.default.send_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 -# ── 文件描述符 ── +# ── 파일 설명자 ── fs.file-max = 1048576 fs.nr_open = 1048576 -# ── 连接跟踪 ── +# ── 연결 추적 ── $(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" @@ -6180,17 +6180,17 @@ echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30" echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15" echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15" else -echo "# conntrack 未启用" +echo "# conntrack이 활성화되어 있지 않습니다" fi) $STREAM_EXTRA $GAME_EXTRA SYSCTL - # ── 应用配置(逐行,跳过不支持的参数) ── - echo -e "${gl_lv}应用优化参数...${gl_bai}" + # ── 구성 적용(한 줄씩, 지원되지 않는 매개변수 건너뛰기) ── + echo -e "${gl_lv}최적화 매개변수 적용...${gl_bai}" local applied=0 skipped=0 while IFS= read -r line; do - # 跳过注释和空行 + # 주석과 빈 줄 건너뛰기 [[ "$line" =~ ^[[:space:]]*# ]] && continue [[ -z "${line// /}" ]] && continue if sysctl -w "$line" >/dev/null 2>&1; then @@ -6199,14 +6199,14 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}已应用 ${applied} 项参数${skipped:+,跳过 ${skipped} 项不支持的参数}${gl_bai}" + echo -e "${gl_lv}적용된${applied}항목 매개변수 ${skipped:+, 건너뛰기${skipped}지원되지 않는 항목 매개변수}${gl_bai}" - # ── 透明大页面 ── + # ── 투명 대형 페이지 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi - # ── 文件描述符限制 ── + # ── 파일 설명자 제한 사항 ── if ! grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then cat >> /etc/security/limits.conf << 'LIMITS' @@ -6218,60 +6218,60 @@ root hard nofile 1048576 LIMITS fi - # ── BBR 持久化 ── + # ── BBR 지속성 ── if [ "$CC" = "bbr" ]; then echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null - # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) + # 이전 sysctl.conf에서 bbr 구성을 정리합니다(충돌을 방지하기 위해). sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name} 优化完成!配置已持久化到 ${CONF}${gl_bai}" - echo -e "${gl_lv}内存: ${MEM_MB}MB | 拥塞算法: ${CC} | 队列: ${QDISC}${gl_bai}" + echo -e "${gl_lv}${mode_name}최적화 완료! 구성은 다음과 같이 유지되었습니다.${CONF}${gl_bai}" + echo -e "${gl_lv}메모리:${MEM_MB}MB | 혼잡 알고리즘:${CC}| 대기줄:${QDISC}${gl_bai}" } -# ── 各模式入口函数(保持原有调用接口不变) ── +# ── 각 모드의 진입 기능(원래 호출 인터페이스를 그대로 유지) ── optimize_high_performance() { _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" } optimize_balanced() { - _kernel_optimize_core "均衡优化模式" "balanced" + _kernel_optimize_core "균형 잡힌 최적화 모드" "balanced" } optimize_web_server() { - _kernel_optimize_core "网站搭建优化模式" "web" + _kernel_optimize_core "웹사이트 구축 최적화 모드" "web" } -# ── 还原默认设置(完全清理) ── +# ── 기본 설정 복원(완전 청소) ── restore_defaults() { - echo -e "${gl_lv}还原到默认设置...${gl_bai}" + echo -e "${gl_lv}기본 설정으로 되돌리기...${gl_bai}" local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 删除优化配置文件(含外链自动调优配置) + # 최적화 구성 파일 삭제(외부 링크 자동 튜닝 구성 포함) rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf - # 清理 sysctl.conf 里可能残留的 bbr 配置 + # sysctl.conf에서 가능한 나머지 bbr 구성을 정리합니다. sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新加载系统默认配置 + # 시스템 기본 구성 다시 로드 sysctl --system 2>/dev/null | tail -1 - # 还原透明大页面 + # 투명한 대용량 페이지 복원 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null - # 清理文件描述符配置 + # 파일 설명자 구성 정리 if grep -q "# kejilion-optimize" /etc/security/limits.conf 2>/dev/null; then sed -i '/# kejilion-optimize/,+4d' /etc/security/limits.conf fi - # 清理 BBR 持久化 + # BBR 지속성 정리 rm -f /etc/modules-load.d/bbr.conf 2>/dev/null - echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" + echo -e "${gl_lv}시스템이 기본 설정으로 복원되었습니다.${gl_bai}" } @@ -6279,76 +6279,76 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux内核调优管理" - local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) - [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" - echo "Linux系统内核参数优化" + send_stats "Linux 커널 튜닝 관리" + local current_mode=$(grep "^# 모드:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 모드: //' | awk -F'|' '{print $1}' | xargs) + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="자동 튜닝 모드" + echo "Linux 시스템 커널 매개변수 최적화" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + echo -e "현재 모드:${gl_lv}${current_mode}${gl_bai}" else - echo -e "当前模式: ${gl_hui}未优化${gl_bai}" + echo -e "현재 모드:${gl_hui}최적화되지 않음${gl_bai}" fi - echo "视频介绍: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" + echo "영상 소개: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" - echo -e "${gl_huang}提示: ${gl_bai}生产环境请谨慎使用!" + echo "다양한 시스템 매개변수 조정 모드를 제공하며 사용자는 자신의 사용 시나리오에 따라 전환하도록 선택할 수 있습니다." + echo -e "${gl_huang}힌트:${gl_bai}프로덕션 환경에서는 주의해서 사용해주세요!" echo -e "--------------------" - echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" - echo -e "2. 均衡优化模式: 在性能与资源消耗之间取得平衡,适合日常使用。" - echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" - echo -e "4. 直播优化模式: 针对直播推流优化,UDP 缓冲区加大,减少延迟。" - echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" - echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" - echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" + echo -e "1. 고성능 최적화 모드: 시스템 성능, 적극적인 메모리 및 네트워크 매개변수를 최대화합니다." + echo -e "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." + echo -e "3. 웹사이트 최적화 모드: 웹사이트 서버에 최적화되어 있으며 동시 연결 대기열이 매우 높습니다." + echo -e "4. 라이브 방송 최적화 모드: 라이브 스트리밍 최적화를 위해 UDP 버퍼가 확장되어 지연이 줄어듭니다." + echo -e "5. 게임 서버 최적화 모드: 게임 서버에 최적화되어 낮은 대기 시간을 우선시합니다." + echo -e "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." + echo -e "7. 자동 튜닝: 테스트 데이터를 기반으로 커널 매개변수를 자동으로 튜닝합니다.${gl_huang}★${gl_bai}" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) cd ~ clear - local tiaoyou_moshi="高性能优化模式" + local tiaoyou_moshi="고성능 최적화 모드" optimize_high_performance - send_stats "高性能模式优化" + send_stats "고성능 모드 최적화" ;; 2) cd ~ clear optimize_balanced - send_stats "均衡模式优化" + send_stats "균형 모드 최적화" ;; 3) cd ~ clear optimize_web_server - send_stats "网站优化模式" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ clear - _kernel_optimize_core "直播优化模式" "stream" - send_stats "直播推流优化" + _kernel_optimize_core "라이브 방송 최적화 모드" "stream" + send_stats "라이브 스트리밍 최적화" ;; 5) cd ~ clear - _kernel_optimize_core "游戏服优化模式" "game" - send_stats "游戏服优化" + _kernel_optimize_core "게임 서버 최적화 모드" "game" + send_stats "게임 서버 최적화" ;; 6) cd ~ clear restore_defaults curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults - send_stats "还原默认设置" + send_stats "기본 설정 복원" ;; 7) cd ~ clear curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - send_stats "内核自动调优" + send_stats "커널 자동 튜닝" ;; *) @@ -6378,7 +6378,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" hash -r break_end @@ -6387,17 +6387,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}시스템 언어가 다음과 같이 수정되었습니다.$lang적용하려면 SSH에 다시 연결하세요.${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "지원되지 않는 시스템:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "지원되지 않는 시스템, 시스템 유형을 식별할 수 없습니다." break_end fi } @@ -6407,29 +6407,29 @@ update_locale() { linux_language() { root_use -send_stats "切换系统语言" +send_stats "시스템 언어 전환" while true; do clear - echo "当前系统语言: $LANG" + echo "현재 시스템 언어:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. 영어 2. 중국어 간체 3. 중국어 번체" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "切换到英文" + send_stats "영어로 전환" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "切换到简体中文" + send_stats "중국어 간체로 전환" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" - send_stats "切换到繁体中文" + send_stats "중국어 번체로 전환" ;; *) break @@ -6451,7 +6451,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}변경이 완료되었습니다. 변경 사항을 보려면 SSH에 다시 연결하세요!${gl_bai}" hash -r break_end @@ -6462,10 +6462,10 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "명령줄 미화 도구" while true; do clear - echo "命令行美化工具" + echo "명령줄 미화 도구" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -6475,9 +6475,9 @@ shell_bianse() { echo -e "6. \033[1;33mroot \033[1;34mlocalhost \033[1;35m~ \033[0m${gl_bai}#" echo -e "7. root localhost ~ #" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -6522,7 +6522,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "系统回收站" + send_stats "시스템 휴지통" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -6531,23 +6531,23 @@ linux_trash() { local trash_status if ! grep -q "trash-put" "$bashrc_profile"; then - trash_status="${gl_hui}未启用${gl_bai}" + trash_status="${gl_hui}활성화되지 않음${gl_bai}" else - trash_status="${gl_lv}已启用${gl_bai}" + trash_status="${gl_lv}활성화됨${gl_bai}" fi clear - echo -e "当前回收站 ${trash_status}" - echo -e "启用后rm删除的文件先进入回收站,防止误删重要文件!" + echo -e "현재 휴지통${trash_status}" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" - ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站为空" + ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" - echo "1. 启用回收站 2. 关闭回收站" - echo "3. 还原内容 4. 清空回收站" + echo "1. 휴지통 활성화 2. 휴지통 닫기" + echo "3. 콘텐츠 복원 4. 휴지통 비우기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -6555,7 +6555,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "휴지통이 활성화되면 삭제된 파일은 휴지통으로 이동됩니다." sleep 2 ;; 2) @@ -6563,23 +6563,23 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已关闭,文件将直接删除。" + echo "휴지통이 닫히고 파일이 직접 삭제됩니다." sleep 2 ;; 3) - read -e -p "输入要还原的文件名: " file_to_restore + read -e -p "복원할 파일 이름을 입력하세요:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore 已还原到主目录。" + echo "$file_to_restore홈 디렉토리로 복원되었습니다." else - echo "文件不存在。" + echo "파일이 존재하지 않습니다." fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "휴지통을 비우시겠습니까? [예/아니요]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty - echo "回收站已清空。" + echo "휴지통이 비워졌습니다." fi ;; *) @@ -6590,23 +6590,23 @@ linux_trash() { } linux_fav() { -send_stats "命令收藏夹" +send_stats "명령 즐겨찾기" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# 创建备份 +# 백업 만들기 create_backup() { - send_stats "创建备份" + send_stats "백업 만들기" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") - # 提示用户输入备份目录 - echo "创建备份示例:" - echo " - 备份单个目录: /var/www" - echo " - 备份多个目录: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" - read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + # 사용자에게 백업 디렉터리를 묻는 메시지 표시 + echo "백업 생성 예:" + echo "- 단일 디렉터리 백업: /var/www" + echo "- 여러 디렉터리 백업: /etc /home /var/log" + echo "- Enter를 눌러 기본 디렉터리(/etc/usr/home)를 사용합니다." + read -e -p "백업할 디렉터리를 입력하십시오(여러 디렉터리를 공백으로 구분하고 Enter를 눌러 기본 디렉터리를 사용하십시오)." input - # 如果用户没有输入目录,则使用默认目录 + # 사용자가 디렉터리를 입력하지 않으면 기본 디렉터리가 사용됩니다. if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6614,119 +6614,119 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 사용자가 입력한 디렉토리를 공백으로 배열로 구분합니다. IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 백업 파일 접두사 생성 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # 디렉토리 이름 추출 및 슬래시 제거 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done - # 去除最后一个下划线 + # 마지막 밑줄 제거 local PREFIX=${PREFIX%_} - # 生成备份文件名 + # 백업 파일 이름 생성 local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" - # 打印用户选择的目录 - echo "您选择的备份目录为:" + # 사용자가 선택한 디렉토리 인쇄 + echo "선택한 백업 디렉터리는 다음과 같습니다." for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done - # 创建备份 - echo "正在创建备份 $BACKUP_NAME..." + # 백업 만들기 + echo "백업 생성$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 检查命令是否成功 + # 명령이 성공했는지 확인 if [ $? -eq 0 ]; then - echo "备份创建成功: $BACKUP_DIR/$BACKUP_NAME" + echo "백업이 성공적으로 생성되었습니다:$BACKUP_DIR/$BACKUP_NAME" else - echo "备份创建失败!" + echo "백업 생성에 실패했습니다!" exit 1 fi } -# 恢复备份 +# 백업 복원 restore_backup() { - send_stats "恢复备份" - # 选择要恢复的备份 - read -e -p "请输入要恢复的备份文件名: " BACKUP_NAME + send_stats "백업 복원" + # 복원할 백업을 선택하세요 + read -e -p "복원할 백업 파일 이름을 입력하십시오:" BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - echo "正在恢复备份 $BACKUP_NAME..." + echo "백업 복원 중$BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then - echo "备份恢复成功!" + echo "백업 및 복원 성공!" else - echo "备份恢复失败!" + echo "백업 복원에 실패했습니다!" exit 1 fi } -# 列出备份 +# 백업 나열 list_backups() { - echo "可用的备份:" + echo "사용 가능한 백업:" ls -1 "$BACKUP_DIR" } -# 删除备份 +# 백업 삭제 delete_backup() { - send_stats "删除备份" + send_stats "백업 삭제" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "삭제할 백업 파일 이름을 입력하십시오:" BACKUP_NAME - # 检查备份文件是否存在 + # 백업 파일이 있는지 확인 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "备份文件不存在!" + echo "백업 파일이 존재하지 않습니다!" exit 1 fi - # 删除备份 + # 백업 삭제 rm -f "$BACKUP_DIR/$BACKUP_NAME" if [ $? -eq 0 ]; then - echo "备份删除成功!" + echo "백업이 삭제되었습니다!" else - echo "备份删除失败!" + echo "백업 삭제에 실패했습니다!" exit 1 fi } -# 备份主菜单 +# 백업 메인 메뉴 linux_backup() { BACKUP_DIR="/backups" mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" - echo "系统备份功能" + send_stats "시스템 백업 기능" + echo "시스템 백업 기능" echo "------------------------" list_backups echo "------------------------" - echo "1. 创建备份 2. 恢复备份 3. 删除备份" + echo "1. 백업 생성 2. 백업 복원 3. 백업 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) create_backup ;; 2) restore_backup ;; 3) delete_backup ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르세요..." done } @@ -6738,7 +6738,7 @@ linux_backup() { -# SSH 输入标准化函数 +# SSH 입력 정규화 기능 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -6764,7 +6764,7 @@ kj_ssh_read_host_port() { if kj_ssh_validate_host "$KJ_SSH_HOST"; then break fi - echo "错误: 请输入有效的服务器地址。" + echo "오류: 유효한 서버 주소를 입력하세요." done while true; do @@ -6773,7 +6773,7 @@ kj_ssh_read_host_port() { if kj_ssh_validate_port "$KJ_SSH_PORT"; then break fi - echo "错误: 端口必须是 1-65535 之间的数字。" + echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." done } @@ -6792,7 +6792,7 @@ kj_ssh_read_host_user_port() { if kj_ssh_validate_user "$KJ_SSH_USER"; then break fi - echo "错误: 用户名格式不正确。" + echo "오류: 사용자 이름 형식이 잘못되었습니다." done } @@ -6810,12 +6810,12 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "错误: SSH 用户名格式不正确。" + echo "오류: SSH 사용자 이름 형식이 잘못되었습니다." return 1 fi if ! kj_ssh_validate_host "$remote_host"; then - echo "错误: SSH 主机地址格式不正确。" + echo "오류: SSH 호스트 주소 형식이 잘못되었습니다." return 1 fi @@ -6828,24 +6828,24 @@ kj_ssh_read_auth() { local key_file="$1" local password_or_key="" - echo "请选择身份验证方式:" - echo "1. 密码" - echo "2. 密钥" - read -e -p "请输入选择 (1/2): " auth_choice + echo "인증 방법을 선택하세요:" + echo "1. 비밀번호" + echo "2. 열쇠" + read -e -p "원하는 항목(1/2)을 입력하세요." auth_choice case $auth_choice in 1) - read -s -p "请输入密码: " password_or_key + read -s -p "비밀번호를 입력하세요:" password_or_key echo if [ -z "$password_or_key" ]; then - echo "错误: 密码不能为空。" + echo "오류: 비밀번호는 비워둘 수 없습니다." return 1 fi KJ_SSH_AUTH_METHOD="password" KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -6856,7 +6856,7 @@ kj_ssh_read_auth() { done if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then - echo "无效的密钥内容!" + echo "잘못된 키 콘텐츠입니다!" return 1 fi @@ -6867,7 +6867,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$key_file" ;; *) - echo "无效的选择!" + echo "잘못된 선택입니다!" return 1 ;; esac @@ -6879,7 +6879,7 @@ kj_ssh_read_password() { read -e -s -p "$prompt" KJ_SSH_PASSWORD echo [ -n "$KJ_SSH_PASSWORD" ] && break - echo "错误: 密码不能为空。" + echo "오류: 비밀번호는 비워둘 수 없습니다." done } @@ -6892,113 +6892,113 @@ kj_ssh_read_port() { if kj_ssh_validate_port "$KJ_SSH_PORT"; then return 0 fi - echo "错误: 端口必须是 1-65535 之间的数字。" + echo "오류: 포트는 1~65535 사이의 숫자여야 합니다." done } -# 显示连接列表 +# 연결 목록 표시 list_connections() { - echo "已保存的连接:" + echo "저장된 연결:" echo "------------------------" cat "$CONFIG_FILE" | awk -F'|' '{print NR " - " $1 " (" $2 ")"}' echo "------------------------" } -# 添加新连接 +# 새 연결 추가 add_connection() { - send_stats "添加新连接" - echo "创建新连接示例:" - echo " - 连接名称: my_server" - echo " - IP地址: 192.168.1.100" - echo " - 用户名: root" - echo " - 端口: 22" + send_stats "새 연결 추가" + echo "새 연결 생성의 예:" + echo "- 연결 이름: my_server" + echo "- IP 주소: 192.168.1.100" + echo "- 사용자 이름: 루트" + echo "- 포트: 22" echo "------------------------" - read -e -p "请输入连接名称: " name + read -e -p "연결 이름을 입력하세요:" name - kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "请输入端口号 (默认: 22): " "root" "22" + kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "포트 번호를 입력하십시오(기본값: 22):" "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "연결이 저장되었습니다!" } -# 删除连接 +# 연결 삭제 delete_connection() { - send_stats "删除连接" - read -e -p "请输入要删除的连接编号: " num + send_stats "연결 삭제" + read -e -p "삭제할 연결 번호를 입력하세요:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류: 해당 연결을 찾을 수 없습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 연결이 키 파일을 사용하는 경우 키 파일을 삭제하세요. if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "连接已删除!" + echo "연결이 삭제되었습니다!" } -# 使用连接 +# 연결 사용 use_connection() { - send_stats "使用连接" - read -e -p "请输入要使用的连接编号: " num + send_stats "연결 사용" + read -e -p "사용할 연결 번호를 입력하세요:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then - echo "错误:未找到对应的连接。" + echo "오류: 해당 연결을 찾을 수 없습니다." return fi IFS='|' read -r name ip user port password_or_key <<< "$connection" - echo "正在连接到 $name ($ip)..." + echo "연결 중$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 키를 사용하여 연결 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" - echo "3. 目标服务器是否允许使用密钥登录。" + echo "연결에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 키파일 경로가 맞나요?$password_or_key" + echo "2. 키 파일 권한이 올바른가요(600이어야 함)." + echo "3. 대상 서버에서 키를 이용한 로그인을 허용하는지 여부." fi else - # 使用密码连接 + # 비밀번호를 사용하여 연결 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." + echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then - echo "连接失败!请检查以下内容:" - echo "1. 用户名和密码是否正确。" - echo "2. 目标服务器是否允许密码登录。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "연결에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 사용자 이름과 비밀번호가 정확합니까?" + echo "2. 대상 서버에서 비밀번호 로그인을 허용하는지 여부." + echo "3. 대상 서버의 SSH 서비스가 정상적으로 실행되고 있는지 여부." fi fi } ssh_manager() { - send_stats "ssh远程连接工具" + send_stats "SSH 원격 연결 도구" CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 구성 파일과 키 디렉터리가 있는지 확인하고 없으면 만듭니다. if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -7010,21 +7010,21 @@ ssh_manager() { while true; do clear - echo "SSH 远程连接工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "SSH 원격 연결 도구" + echo "SSH를 통해 다른 Linux 시스템에 연결할 수 있습니다." echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. 새 연결 생성 2. 연결 사용 3. 연결 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) add_connection ;; 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; esac done } @@ -7040,184 +7040,184 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 사용 가능한 하드 디스크 파티션 나열 list_partitions() { - echo "可用的硬盘分区:" + echo "사용 가능한 하드 드라이브 파티션:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } -# 持久化挂载分区 +# 지속적으로 마운트된 파티션 mount_partition() { - send_stats "挂载分区" - read -e -p "请输入要挂载的分区名称(例如 sda1): " PARTITION + send_stats "마운트 파티션" + read -e -p "마운트할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" - # 检查分区是否存在 + # 파티션이 존재하는지 확인 if ! lsblk -no NAME | grep -qw "$PARTITION"; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return 1 fi - # 检查是否已挂载 + # 마운트되어 있는지 확인해보세요 if mount | grep -qw "$DEVICE"; then - echo "分区已经挂载!" + echo "파티션이 마운트되었습니다!" return 1 fi - # 获取 UUID + # UUID 가져오기 UUID=$(blkid -s UUID -o value "$DEVICE") if [ -z "$UUID" ]; then - echo "无法获取 UUID!" + echo "UUID를 얻을 수 없습니다!" return 1 fi - # 获取文件系统类型 + # 파일 시스템 유형 가져오기 FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then - echo "无法获取文件系统类型!" + echo "파일 시스템 유형을 가져올 수 없습니다!" return 1 fi - # 创建挂载点 + # 마운트 지점 생성 mkdir -p "$MOUNT_POINT" - # 挂载 + # 산 if ! mount "$DEVICE" "$MOUNT_POINT"; then - echo "分区挂载失败!" + echo "파티션 마운트에 실패했습니다!" rmdir "$MOUNT_POINT" return 1 fi - echo "分区已成功挂载到 $MOUNT_POINT" + echo "파티션이 성공적으로 마운트되었습니다.$MOUNT_POINT" - # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 + # /etc/fstab을 확인하여 UUID 또는 마운트 지점이 이미 존재하는지 확인하세요. if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "/etc/fstab 中已存在该分区记录,跳过写入" + echo "파티션 기록이 /etc/fstab에 이미 존재합니다. 쓰기를 건너뛰세요." return 0 fi - # 写入 /etc/fstab + # /etc/fstab에 쓰기 echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab - echo "已写入 /etc/fstab,实现持久化挂载" + echo "지속적인 마운트를 위해 /etc/fstab에 기록" } -# 卸载分区 +# 파티션 마운트 해제 unmount_partition() { - send_stats "卸载分区" - read -e -p "请输入要卸载的分区名称(例如 sda1): " PARTITION + send_stats "파티션 마운트 해제" + read -e -p "마운트 해제할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION - # 检查分区是否已经挂载 + # 파티션이 마운트되었는지 확인 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then - echo "分区未挂载!" + echo "파티션이 마운트되지 않았습니다!" return fi - # 卸载分区 + # 파티션 마운트 해제 umount "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区卸载成功: $MOUNT_POINT" + echo "파티션이 성공적으로 제거되었습니다:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "파티션 제거에 실패했습니다!" fi } -# 列出已挂载的分区 +# 마운트된 파티션 나열 list_mounted_partitions() { - echo "已挂载的分区:" + echo "마운트된 파티션:" df -h | grep -v "tmpfs\|udev\|overlay" } -# 格式化分区 +# 파티션 포맷 format_partition() { - send_stats "格式化分区" - read -e -p "请输入要格式化的分区名称(例如 sda1): " PARTITION + send_stats "파티션 포맷" + read -e -p "포맷할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION - # 检查分区是否存在 + # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区是否已经挂载 + # 파티션이 마운트되었는지 확인 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "파티션이 마운트되었습니다. 먼저 마운트를 해제하세요!" return fi - # 选择文件系统类型 - echo "请选择文件系统类型:" + # 파일 시스템 유형 선택 + echo "파일 시스템 유형을 선택하십시오:" echo "1. ext4" echo "2. xfs" echo "3. ntfs" echo "4. vfat" - read -e -p "请输入你的选择: " FS_CHOICE + read -e -p "선택사항을 입력하세요:" FS_CHOICE case $FS_CHOICE in 1) FS_TYPE="ext4" ;; 2) FS_TYPE="xfs" ;; 3) FS_TYPE="ntfs" ;; 4) FS_TYPE="vfat" ;; - *) echo "无效的选择!"; return ;; + *) echo "잘못된 선택입니다!"; return ;; esac - # 确认格式化 - read -e -p "确认格式化分区 /dev/$PARTITION 为 $FS_TYPE 吗?(y/n): " CONFIRM + # 포맷 확인 + read -e -p "포맷된 파티션 /dev/ 확인$PARTITION~을 위한$FS_TYPE? (예/아니요):" CONFIRM if [ "$CONFIRM" != "y" ]; then - echo "操作已取消。" + echo "작업이 취소되었습니다." return fi - # 格式化分区 - echo "正在格式化分区 /dev/$PARTITION 为 $FS_TYPE ..." + # 파티션 포맷 + echo "파티션 /dev/ 포맷 중$PARTITION~을 위한$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "파티션이 성공적으로 포맷되었습니다!" else - echo "分区格式化失败!" + echo "파티션 포맷에 실패했습니다!" fi } -# 检查分区状态 +# 파티션 상태 확인 check_partition() { - send_stats "检查分区状态" - read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION + send_stats "파티션 상태 확인" + read -e -p "확인할 파티션 이름을 입력하세요(예: sda1):" PARTITION - # 检查分区是否存在 + # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then - echo "分区不存在!" + echo "파티션이 존재하지 않습니다!" return fi - # 检查分区状态 - echo "检查分区 /dev/$PARTITION 的状态:" + # 파티션 상태 확인 + echo "파티션 확인 /dev/$PARTITION상태:" fsck "/dev/$PARTITION" } -# 主菜单 +# 메인 메뉴 disk_manager() { - send_stats "硬盘管理功能" + send_stats "하드디스크 관리 기능" while true; do clear - echo "硬盘分区管理" - echo -e "${gl_huang}该功能内部测试阶段,请勿在生产环境使用。${gl_bai}" + echo "하드 디스크 파티션 관리" + echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions echo "------------------------" - echo "1. 挂载分区 2. 卸载分区 3. 查看已挂载分区" - echo "4. 格式化分区 5. 检查分区状态" + echo "1. 파티션 마운트 2. 파티션 마운트 해제 3. 마운트된 파티션 보기" + echo "4. 파티션 포맷 5. 파티션 상태 확인" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -7226,44 +7226,44 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르세요..." done } -# 显示任务列表 +# 작업 목록 표시 list_tasks() { - echo "已保存的同步任务:" + echo "저장된 동기화 작업:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" } -# 添加新任务 +# 새 작업 추가 add_task() { - send_stats "添加新同步任务" - echo "创建新同步任务示例:" - echo " - 任务名称: backup_www" - echo " - 本地目录: /var/www" - echo " - 远程地址: user@192.168.1.100" - echo " - 远程目录: /backup/www" - echo " - 端口号 (默认 22)" + send_stats "새 동기화 작업 추가" + echo "새 동기화 작업 생성의 예:" + echo "- 작업 이름: backup_www" + echo "- 로컬 디렉터리: /var/www" + echo "- 원격 주소: user@192.168.1.100" + echo "- 원격 디렉터리: /backup/www" + echo "- 포트 번호(기본값 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name - read -e -p "请输入本地目录: " local_path - read -e -p "请输入远程目录: " remote_path + read -e -p "작업 이름을 입력하세요:" name + read -e -p "로컬 디렉토리를 입력하십시오:" local_path + read -e -p "원격 디렉토리를 입력하십시오:" remote_path while true; do - read -e -p "请输入远程用户@IP: " remote + read -e -p "원격 user@IP를 입력하십시오:" remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break fi done - kj_ssh_read_port "请输入 SSH 端口 (默认 22): " "22" + kj_ssh_read_port "SSH 포트(기본값 22)를 입력하세요." "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7272,54 +7272,54 @@ add_task() { auth_method="$KJ_SSH_AUTH_METHOD" password_or_key="$KJ_SSH_AUTH_SECRET" - echo "请选择同步模式:" - echo "1. 标准模式 (-avz)" - echo "2. 删除目标文件 (-avz --delete)" - read -e -p "请选择 (1/2): " mode + echo "동기화 모드를 선택하십시오:" + echo "1. 표준 모드(-avz)" + echo "2. 대상 파일 삭제(-avz --delete)" + read -e -p "(1/2)을 선택하세요:" mode case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "선택이 잘못되었습니다. 기본값 -avz를 사용하세요."; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" install rsync rsync - echo "任务已保存!" + echo "임무가 저장되었습니다!" } -# 删除任务 +# 할 일 삭제 delete_task() { - send_stats "删除同步任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 작업 삭제" + read -e -p "삭제할 작업 번호를 입력하세요:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "오류: 해당 작업을 찾을 수 없습니다." return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任务使用的是密钥文件,则删除该密钥文件 + # 작업이 키 파일을 사용하는 경우 키 파일을 삭제하세요. if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "작업이 삭제되었습니다!" } run_task() { - send_stats "执行同步任务" + send_stats "동기화 작업 수행" CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # 매개변수 구문 분석 local direction="push" # 默认是推送到远端 local num @@ -7330,51 +7330,51 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 작업 번호가 전달되지 않으면 사용자에게 입력하라는 메시지가 표시됩니다. if [[ -z "$num" ]]; then - read -e -p "请输入要执行的任务编号: " num + read -e -p "실행할 작업 번호를 입력하세요:" num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "오류: 작업을 찾을 수 없습니다!" return fi IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 根据同步方向调整源和目标路径 + # 동기화 방향에 따라 소스 및 대상 경로 조정 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "로컬로 가져오기 및 동기화:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "원격 끝에 푸시 및 동기화:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # SSH 연결 공통 매개변수 추가 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" - echo "安装方法:" + echo "오류: sshpass가 설치되지 않았습니다. 먼저 sshpass를 설치하십시오." + echo "설치 방법:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" return fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # 키 파일이 존재하는지, 권한이 올바른지 확인하세요. if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "오류: 키 파일이 존재하지 않습니다:$password_or_key" return fi if [[ "$(stat -c %a "$password_or_key")" != "600" ]]; then - echo "警告:密钥文件权限不正确,正在修复..." + echo "경고: 잘못된 키 파일 권한, 수정 중..." chmod 600 "$password_or_key" fi @@ -7382,32 +7382,32 @@ run_task() { fi if [[ $? -eq 0 ]]; then - echo "同步完成!" + echo "동기화가 완료되었습니다!" else - echo "同步失败! 请检查以下内容:" - echo "1. 网络连接是否正常" - echo "2. 远程主机是否可访问" - echo "3. 认证信息是否正确" - echo "4. 本地和远程目录是否有正确的访问权限" + echo "동기화에 실패했습니다! 다음 사항을 확인하세요." + echo "1. 네트워크 연결이 정상인가요?" + echo "2. 원격 호스트에 접근 가능한지 여부" + echo "3. 인증정보가 정확합니까?" + echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi } -# 创建定时任务 +# 예약된 작업 만들기 schedule_task() { - send_stats "添加同步定时任务" + send_stats "동기화 예약 작업 추가" - read -e -p "请输入要定时同步的任务编号: " num + read -e -p "정기적으로 동기화할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류: 유효한 작업 번호를 입력하십시오!" return fi - echo "请选择定时执行间隔:" - echo "1) 每小时执行一次" - echo "2) 每天执行一次" - echo "3) 每周执行一次" - read -e -p "请输入选项 (1/2/3): " interval + echo "예약된 실행 간격을 선택하십시오." + echo "1) 매 시간마다 한 번씩 실행" + echo "2) 하루에 한 번 실행" + echo "3) 일주일에 한 번 실행" + read -e -p "옵션을 입력하세요(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 local cron_time="" @@ -7415,66 +7415,66 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "错误: 请输入有效的选项!" ; return ;; + *) echo "오류: 유효한 옵션을 입력하십시오!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 동일한 작업이 이미 존재하는지 확인하세요. if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "오류: 이 작업에 대해 예약된 동기화가 이미 존재합니다!" return fi - # 创建到用户的 crontab + # 사용자의 crontab에 생성 (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "定时任务已创建: $cron_job" + echo "예약된 작업이 생성되었습니다:$cron_job" } -# 查看定时任务 +# 예약된 작업 보기 view_tasks() { - echo "当前的定时任务:" + echo "현재 예약된 작업:" echo "---------------------------------" crontab -l | grep "k rsync_run" echo "---------------------------------" } -# 删除定时任务 +# 예약된 작업 삭제 delete_task_schedule() { - send_stats "删除同步定时任务" - read -e -p "请输入要删除的任务编号: " num + send_stats "동기화 예약 작업 삭제" + read -e -p "삭제할 작업 번호를 입력하세요:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "错误: 请输入有效的任务编号!" + echo "오류: 유효한 작업 번호를 입력하십시오!" return fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "已删除任务编号 $num 的定时任务" + echo "태스크 번호가 삭제되었습니다.$num예약된 작업" } -# 任务管理主菜单 +# 작업 관리 메인 메뉴 rsync_manager() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" while true; do clear - echo "Rsync 远程同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "Rsync 원격 동기화 도구" + echo "원격 디렉터리 간의 동기화는 효율적이고 안정적인 증분 동기화를 지원합니다." echo "---------------------------------" list_tasks echo view_tasks echo - echo "1. 创建新任务 2. 删除任务" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "1. 새 작업 생성 2. 작업 삭제" + echo "3. 원격 사이트에 대한 로컬 동기화 수행 4. 로컬 사이트에 대한 원격 동기화 수행" + echo "5. 예약된 작업 생성 6. 예약된 작업 삭제" echo "---------------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "---------------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case $choice in 1) add_task ;; 2) delete_task ;; @@ -7483,9 +7483,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "선택이 잘못되었습니다. 다시 시도해 주세요." ;; esac - read -e -p "按回车键继续..." + read -e -p "계속하려면 Enter를 누르세요..." done } @@ -7502,8 +7502,8 @@ linux_info() { clear - echo -e "${gl_kjlan}正在查询系统信息……${gl_bai}" - send_stats "系统信息查询" + echo -e "${gl_kjlan}시스템 정보를 쿼리하는 중...${gl_bai}" + send_stats "시스템 정보 쿼리" ip_address @@ -7547,7 +7547,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d시간 ", run_hours); printf("%d분\n", run_mins)}') local timezone=$(current_timezone) @@ -7555,42 +7555,42 @@ linux_info() { local udp_count=$(ss -u | wc -l) clear - echo -e "系统信息查询" + echo -e "시스템 정보 쿼리" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}主机名: ${gl_bai}$hostname" - echo -e "${gl_kjlan}系统版本: ${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" + echo -e "${gl_kjlan}호스트 이름:${gl_bai}$hostname" + echo -e "${gl_kjlan}시스템 버전:${gl_bai}$os_info" + echo -e "${gl_kjlan}리눅스 버전:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU架构: ${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU 아키텍처:${gl_bai}$cpu_arch" + echo -e "${gl_kjlan}CPU 모델:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU 코어 수:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU 주파수:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" - echo -e "${gl_kjlan}虚拟内存: ${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" + echo -e "${gl_kjlan}CPU 사용량:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP 연결 수:${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}물리적 메모리:${gl_bai}$mem_info" + echo -e "${gl_kjlan}가상 메모리:${gl_bai}$swap_info" + echo -e "${gl_kjlan}하드 드라이브 사용량:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" + echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}网络算法: ${gl_bai}$congestion_algorithm $queue_algorithm" + echo -e "${gl_kjlan}네트워크 알고리즘:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" + echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4 주소:${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6 주소:${gl_bai}$ipv6_address" fi - echo -e "${gl_kjlan}DNS地址: ${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" - echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}DNS 주소:${gl_bai}$dns_addresses" + echo -e "${gl_kjlan}위치:${gl_bai}$country $city" + echo -e "${gl_kjlan}시스템 시간:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}运行时长: ${gl_bai}$runtime" + echo -e "${gl_kjlan}실행 시간:${gl_bai}$runtime" echo @@ -7603,8 +7603,8 @@ linux_tools() { while true; do clear - # send_stats "基础工具" - echo -e "基础工具" + # send_stats "기본 도구" + echo -e "기본 도구" tools=( curl wget sudo socat htop iftop unzip tar tmux ffmpeg @@ -7629,27 +7629,27 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未识别的包管理器" + echo "❌ 인식할 수 없는 패키지 관리자" exit 1 fi - echo "📦 使用包管理器: $PM" + echo "📦 패키지 관리자를 사용하세요:$PM" echo -e "${gl_kjlan}------------------------${gl_bai}" for ((i=0; i<${#tools[@]}; i+=2)); do - # 左列 + # 왼쪽 열 if command -v "${tools[i]}" >/dev/null 2>&1; then - left=$(printf "✅ %-12s 已安装" "${tools[i]}") + left=$(printf "✅ %-12s 설치됨" "${tools[i]}") else - left=$(printf "❌ %-12s 未安装" "${tools[i]}") + left=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i]}") fi - # 右列(防止数组越界) + # 오른쪽 열(배열이 범위를 벗어나는 것을 방지하기 위해) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then - right=$(printf "✅ %-12s 已安装" "${tools[i+1]}") + right=$(printf "✅ %-12s 설치됨" "${tools[i+1]}") else - right=$(printf "❌ %-12s 未安装" "${tools[i+1]}") + right=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i+1]}") fi printf "%-42s %s\n" "$left" "$right" else @@ -7658,108 +7658,108 @@ linux_tools() { done echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下载工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 网络流量监控工具" - echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP压缩解压工具 ${gl_kjlan}8. ${gl_bai}tar GZ压缩解压工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}1. ${gl_bai}컬 다운로드 도구${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 다운로드 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 최고 관리 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" + echo -e "${gl_kjlan}5. ${gl_bai}htop 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}iftop 네트워크 트래픽 모니터링 도구" + echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP 압축 및 압축 풀기 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁盘占用查看工具 ${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系统 ${gl_kjlan}18. ${gl_bai}opencode AI编程助手 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}레인저 파일 관리 도구" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 디스크 사용량 보기 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" + echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템${gl_kjlan}18. ${gl_bai}오픈코드 AI 프로그래밍 도우미${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}黑客帝国屏保 ${gl_kjlan}22. ${gl_bai}跑火车屏保" - echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}贪吃蛇小游戏" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" + echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 스크린세이버${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" + echo -e "${gl_kjlan}26. ${gl_bai}테트리스 미니 게임${gl_kjlan}27. ${gl_bai}뱀 미니게임" + echo -e "${gl_kjlan}28. ${gl_bai}우주 침략자 미니 게임" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}全部安装 ${gl_kjlan}32. ${gl_bai}全部安装(不含屏保和游戏)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}全部卸载" + echo -e "${gl_kjlan}31. ${gl_bai}모두 설치${gl_kjlan}32. ${gl_bai}모두 설치(화면 보호기 및 게임 제외)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}모두 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}卸载指定工具" + echo -e "${gl_kjlan}41. ${gl_bai}지정된 도구 설치${gl_kjlan}42. ${gl_bai}지정된 도구 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear install curl clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." curl --help - send_stats "安装curl" + send_stats "컬 설치" ;; 2) clear install wget clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." wget --help - send_stats "安装wget" + send_stats "wget 설치" ;; 3) clear install sudo clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." sudo --help - send_stats "安装sudo" + send_stats "sudo 설치" ;; 4) clear install socat clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." socat -h - send_stats "安装socat" + send_stats "socat 설치" ;; 5) clear install htop clear htop - send_stats "安装htop" + send_stats "htop 설치" ;; 6) clear install iftop clear iftop - send_stats "安装iftop" + send_stats "iftop 설치" ;; 7) clear install unzip clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." unzip - send_stats "安装unzip" + send_stats "설치압축 해제" ;; 8) clear install tar clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." tar --help - send_stats "安装tar" + send_stats "타르 설치" ;; 9) clear install tmux clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." tmux --help - send_stats "安装tmux" + send_stats "tmux 설치" ;; 10) clear install ffmpeg clear - echo "工具已安装,使用方法如下:" + echo "도구가 설치되었으며 다음과 같이 사용됩니다." ffmpeg --help - send_stats "安装ffmpeg" + send_stats "ffmpeg 설치" ;; 11) @@ -7767,7 +7767,7 @@ linux_tools() { install btop clear btop - send_stats "安装btop" + send_stats "btop 설치" ;; 12) clear @@ -7776,7 +7776,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "레인저 설치" ;; 13) clear @@ -7785,7 +7785,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "安装ncdu" + send_stats "ncdu 설치" ;; 14) clear @@ -7794,7 +7794,7 @@ linux_tools() { clear fzf cd ~ - send_stats "安装fzf" + send_stats "fzf 설치" ;; 15) clear @@ -7803,7 +7803,7 @@ linux_tools() { clear vim -h cd ~ - send_stats "安装vim" + send_stats "vim 설치" ;; 16) clear @@ -7812,7 +7812,7 @@ linux_tools() { clear nano -h cd ~ - send_stats "安装nano" + send_stats "나노 설치" ;; @@ -7823,7 +7823,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "자식 설치" ;; 18) @@ -7833,7 +7833,7 @@ linux_tools() { source ~/.bashrc source ~/.profile opencode - send_stats "安装opencode" + send_stats "오픈코드 설치" ;; @@ -7842,28 +7842,28 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "安装cmatrix" + send_stats "cmatrix 설치" ;; 22) clear install sl clear sl - send_stats "安装sl" + send_stats "sl 설치" ;; 26) clear install bastet clear bastet - send_stats "安装bastet" + send_stats "바스테트 설치" ;; 27) clear install nsnake clear nsnake - send_stats "安装nsnake" + send_stats "nsnake 설치" ;; 28) @@ -7871,25 +7871,25 @@ linux_tools() { install ninvaders clear ninvaders - send_stats "安装ninvaders" + send_stats "닌베이더 설치" ;; 31) clear - send_stats "全部安装" + send_stats "모두 설치" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git ;; 32) clear - send_stats "全部安装(不含游戏和屏保)" + send_stats "모두 설치(게임 및 화면 보호기 제외)" install curl wget sudo socat htop iftop unzip tar tmux ffmpeg btop ranger ncdu fzf vim nano git ;; 33) clear - send_stats "全部卸载" + send_stats "모두 제거" remove htop iftop tmux ffmpeg btop ranger ncdu fzf cmatrix sl bastet nsnake ninvaders vim nano git opencode uninstall rm -rf ~/.opencode @@ -7897,15 +7897,15 @@ linux_tools() { 41) clear - read -e -p "请输入安装的工具名(wget curl sudo htop): " installname + read -e -p "설치된 도구 이름을 입력하십시오(wget 컬 sudo htop):" installname install $installname - send_stats "安装指定软件" + send_stats "지정된 소프트웨어 설치" ;; 42) clear - read -e -p "请输入卸载的工具名(htop ufw tmux cmatrix): " removename + read -e -p "제거된 도구 이름(htop ufw tmux cmatrix)을 입력하십시오." removename remove $removename - send_stats "卸载指定软件" + send_stats "지정된 소프트웨어 제거" ;; 0) @@ -7913,7 +7913,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -7927,27 +7927,27 @@ linux_tools() { linux_bbr() { clear - send_stats "bbr管理" + send_stats "BBR 관리" if [ -f "/etc/alpine-release" ]; then while true; do clear local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) local queue_algorithm=$(sysctl -n net.core.default_qdisc) - echo "当前TCP阻塞算法: $congestion_algorithm $queue_algorithm" + echo "현재 TCP 차단 알고리즘:$congestion_algorithm $queue_algorithm" echo "" - echo "BBR管理" + echo "BBR 관리" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. BBRv3를 켭니다. 2. BBRv3을 끕니다(다시 시작됩니다)." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) bbr_on - send_stats "alpine开启bbr3" + send_stats "알파인이 열립니다 bbr3" ;; 2) sed -i '/net.ipv4.tcp_congestion_control=/d' /etc/sysctl.conf @@ -7983,21 +7983,21 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${gl_kjlan}当前备份列表:${gl_bai}" - ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "无备份" + echo -e "${gl_kjlan}현재 백업 목록:${gl_bai}" + ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "백업 없음" } # ---------------------------- - # 备份 + # 지원 # ---------------------------- backup_docker() { - send_stats "Docker备份" + send_stats "도커 백업" - echo -e "${gl_kjlan}正在备份 Docker 容器...${gl_bai}" + echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -8010,7 +8010,7 @@ docker_ssh_migration() { else read -ra TARGET_CONTAINERS <<< "$containers" fi - [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}没有找到容器${gl_bai}"; return; } + [[ ${#TARGET_CONTAINERS[@]} -eq 0 ]] && { echo -e "${gl_hong}컨테이너를 찾을 수 없습니다.${gl_bai}"; return; } local BACKUP_DIR="${BACKUP_ROOT}/docker_backup_${DATE_STR}" mkdir -p "$BACKUP_DIR" @@ -8018,28 +8018,28 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "# 자동으로 생성된 복원 스크립트" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # 반복되는 패키징을 피하기 위해 패키징된 Compose 프로젝트 경로를 기록하세요. declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do - echo -e "${gl_lv}备份容器: $c${gl_bai}" + echo -e "${gl_lv}백업 컨테이너:$c${gl_bai}" local inspect_file="${BACKUP_DIR}/${c}_inspect.json" docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}检测到 $c 是 docker-compose 容器${gl_bai}" + echo -e "${gl_kjlan}감지됨$c도커 작성 컨테이너입니다${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -e -p "작성 디렉터리가 감지되지 않습니다. 경로를 수동으로 입력하세요." project_dir fi - # 如果该 Compose 项目已经打包过,跳过 + # Compose 프로젝트가 이미 패키징된 경우 건너뛰세요. if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}Compose 项目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" + echo -e "${gl_huang}프로젝트 작성 [$project_name] 이미 백업되어 있으니 반복 패키징은 생략하세요...${gl_bai}" continue fi @@ -8047,137 +8047,137 @@ docker_ssh_migration() { echo "compose" > "${BACKUP_DIR}/backup_type_${project_name}" echo "$project_dir" > "${BACKUP_DIR}/compose_path_${project_name}.txt" tar -czf "${BACKUP_DIR}/compose_project_${project_name}.tar.gz" -C "$project_dir" . - echo "# docker-compose 恢复: $project_name" >> "$RESTORE_SCRIPT" + echo "# docker-compose 복원:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${gl_lv}Compose 项目 [$project_name] 已打包: ${project_dir}${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name] 포장:${project_dir}${gl_bai}" else - echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" + echo -e "${gl_hong}docker-compose.yml을 찾을 수 없습니다. 이 컨테이너를 건너뛰는 중입니다...${gl_bai}" fi else - # 普通容器备份卷 + # 일반 컨테이너 백업 볼륨 local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "打包卷: $path" + echo "포장량:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done - # 端口 + # 포트 local PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[] | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$inspect_file" 2>/dev/null) for p in "${PORTS[@]}"; do PORT_ARGS+="-p $p "; done - # 环境变量 + # 환경 변수 local ENV_VARS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # 卷映射 + # 볼륨 매핑 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # 镜像 + # 거울 local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") - echo -e "\n# 还原容器: $c" >> "$RESTORE_SCRIPT" + echo -e "\n# 복원 컨테이너:$c" >> "$RESTORE_SCRIPT" echo "docker run -d --name $c $PORT_ARGS $VOL_ARGS $ENV_VARS $IMAGE" >> "$RESTORE_SCRIPT" fi done - # 备份 /home/docker 下的所有文件(不含子目录) + # /home/docker 아래의 모든 파일을 백업합니다(하위 디렉터리 제외). if [ -d "/home/docker" ]; then - echo -e "${gl_kjlan}备份 /home/docker 下的文件...${gl_bai}" + echo -e "${gl_kjlan}/home/docker 아래의 파일을 백업합니다...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 아래의 파일은 다음과 같이 패키지되었습니다.${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" - echo -e "${gl_lv}可用还原脚本: ${RESTORE_SCRIPT}${gl_bai}" + echo -e "${gl_lv}백업 완료:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}사용 가능한 복원 스크립트:${RESTORE_SCRIPT}${gl_bai}" } # ---------------------------- - # 还原 + # 절감 # ---------------------------- restore_docker() { - send_stats "Docker还原" - read -e -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } + send_stats "도커 복원" + read -e -p "복원할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } - echo -e "${gl_kjlan}开始执行还原操作...${gl_bai}" + echo -e "${gl_kjlan}복원 작업을 시작하는 중...${gl_bai}" install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # --------- Compose 프로젝트 복원 우선순위 지정 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then project_name=$(basename "$f" | sed 's/backup_type_//') path_file="$BACKUP_DIR/compose_path_${project_name}.txt" [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" - [[ -z "$original_path" ]] && read -e -p "未找到原始路径,请输入还原目录路径: " original_path + [[ -z "$original_path" ]] && read -e -p "원래 경로를 찾을 수 없습니다. 복원 디렉터리 경로를 입력하십시오:" original_path - # 检查该 compose 项目的容器是否已经在运行 + # Compose 프로젝트의 컨테이너가 이미 실행 중인지 확인하세요. running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then - echo -e "${gl_huang}Compose 项目 [$project_name] 已有容器在运行,跳过还原...${gl_bai}" + echo -e "${gl_huang}프로젝트 작성 [$project_name] 컨테이너가 이미 실행 중입니다. 복원을 건너뛰세요...${gl_bai}" continue fi - read -e -p "确认还原 Compose 项目 [$project_name] 到路径 [$original_path] ? (y/n): " confirm - [[ "$confirm" != "y" ]] && read -e -p "请输入新的还原路径: " original_path + read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로 [$original_path] ? (y/n): " confirm + [[ "$confirm" != "y" ]] && read -e -p "새 복원 경로를 입력하십시오." original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}Compose 项目 [$project_name] 已解压到: $original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true docker compose up -d - echo -e "${gl_lv}Compose 项目 [$project_name] 还原完成!${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name] 복원 완료!${gl_bai}" fi done - # --------- 继续还原普通容器 --------- - echo -e "${gl_kjlan}检查并还原普通 Docker 容器...${gl_bai}" + # --------- 일반 컨테이너를 계속 복원합니다 --------- + echo -e "${gl_kjlan}일반 Docker 컨테이너 확인 및 복원...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}处理容器: $container${gl_bai}" + echo -e "${gl_lv}처리용기:$container${gl_bai}" - # 检查容器是否已经存在且正在运行 + # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}容器 [$container] 已在运行,跳过还原...${gl_bai}" + echo -e "${gl_huang}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${gl_bai}" continue fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}미러 정보를 찾을 수 없습니다. 건너뛰세요:$container${gl_bai}"; continue; } - # 端口映射 + # 포트 매핑 PORT_ARGS="" mapfile -t PORTS < <(jq -r '.[0].HostConfig.PortBindings | to_entries[]? | "\(.value[0].HostPort):\(.key | split("/")[0])"' "$json") for p in "${PORTS[@]}"; do [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # 环境变量 + # 환경 변수 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do ENV_ARGS="$ENV_ARGS -e \"$e\"" done - # 卷映射 + 卷数据恢复 + # 볼륨 매핑 + 볼륨 데이터 복구 VOL_ARGS="" mapfile -t VOLS < <(jq -r '.[0].Mounts[] | "\(.Source):\(.Destination)"' "$json") for v in "${VOLS[@]}"; do @@ -8188,32 +8188,32 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "恢复卷数据: $VOL_SRC" + echo "볼륨 데이터 복구:$VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done - # 删除已存在但未运行的容器 + # 기존이지만 실행되지 않는 컨테이너 삭제 if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}容器 [$container] 存在但未运行,删除旧容器...${gl_bai}" + echo -e "${gl_huang}컨테이너 [$container]가 있지만 실행 중이 아닙니다. 이전 컨테이너를 삭제하세요...${gl_bai}" docker rm -f "$container" fi - # 启动容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + # 컨테이너 시작 + echo "복원 명령을 실행합니다: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}공통 컨테이너에 대한 백업 정보가 없습니다.${gl_bai}" - # 还原 /home/docker 下的文件 + # /home/docker 아래의 파일 복원 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then - echo -e "${gl_kjlan}正在还原 /home/docker 下的文件...${gl_bai}" + echo -e "${gl_kjlan}/home/docker 아래의 파일을 복원하는 중...${gl_bai}" mkdir -p /home/docker tar -xzf "$BACKUP_DIR/home_docker_files.tar.gz" -C / - echo -e "${gl_lv}/home/docker 下的文件已还原完成${gl_bai}" + echo -e "${gl_lv}/home/docker 아래의 파일이 복원되었습니다.${gl_bai}" else - echo -e "${gl_huang}未找到 /home/docker 下文件的备份,跳过...${gl_bai}" + echo -e "${gl_huang}/home/docker 아래의 파일 백업을 찾을 수 없습니다. 건너뛰는 중...${gl_bai}" fi @@ -8221,68 +8221,68 @@ docker_ssh_migration() { # ---------------------------- - # 迁移 + # 이주하다 # ---------------------------- migrate_docker() { - send_stats "Docker迁移" + send_stats "도커 마이그레이션" install jq - read -e -p "请输入要迁移的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } + read -e -p "마이그레이션할 백업 디렉터리를 입력하세요." BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } - kj_ssh_read_host_user_port "目标服务器IP: " "目标服务器SSH用户名 [默认root]: " "目标服务器SSH端口 [默认22]: " "root" "22" + kj_ssh_read_host_user_port "대상 서버 IP:" "대상 서버 SSH 사용자 이름 [기본 루트]:" "대상 서버 SSH 포트 [기본값 22]:" "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" local LATEST_TAR="$BACKUP_DIR" - echo -e "${gl_huang}传输备份中...${gl_bai}" + echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 使用密钥登录 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi } # ---------------------------- - # 删除备份 + # 백업 삭제 # ---------------------------- delete_backup() { - send_stats "Docker备份文件删除" - read -e -p "请输入要删除的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } + send_stats "Docker 백업 파일 삭제" + read -e -p "삭제할 백업 디렉터리를 입력하십시오:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}백업 디렉터리가 존재하지 않습니다.${gl_bai}"; return; } rm -rf "$BACKUP_DIR" - echo -e "${gl_lv}已删除备份: ${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}삭제된 백업:${BACKUP_DIR}${gl_bai}" } # ---------------------------- - # 主菜单 + # 메인 메뉴 # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "Docker 백업 마이그레이션 복원" while true; do clear echo "------------------------" - echo -e "Docker备份/迁移/还原工具" + echo -e "Docker 백업/마이그레이션/복원 도구" echo "------------------------" list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" - echo -e "2. 迁移docker项目" - echo -e "3. 还原docker项目" - echo -e "4. 删除docker项目的备份文件" + echo -e "1. 도커 프로젝트 백업" + echo -e "2. 도커 프로젝트 마이그레이션" + echo -e "3. 도커 프로젝트 복원" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" - echo -e "0. 返回上一级选单" + echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请选择: " choice + read -e -p "선택하세요:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${gl_hong}无效选项${gl_bai}" ;; + *) echo -e "${gl_hong}잘못된 옵션${gl_bai}" ;; esac break_end done @@ -8299,38 +8299,38 @@ linux_docker() { while true; do clear - # send_stats "docker管理" - echo -e "Docker管理" + # send_stats "도커 관리" + echo -e "도커 관리" docker_tato echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装更新Docker环境 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}Docker 환경 설치 및 업데이트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}2. ${gl_bai}查看Docker全局状态 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}2. ${gl_bai}Docker 전역 상태 보기${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}4. ${gl_bai}Docker镜像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" - echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" + echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" + echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" + echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너를 정리하고 네트워크 데이터 볼륨을 미러링하세요." echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" - echo -e "${gl_kjlan}9. ${gl_bai}编辑daemon.json文件" + echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스 변경" + echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}开启Docker-ipv6访问" - echo -e "${gl_kjlan}12. ${gl_bai}关闭Docker-ipv6访问" + echo -e "${gl_kjlan}11. ${gl_bai}Docker-ipv6 액세스 활성화" + echo -e "${gl_kjlan}12. ${gl_bai}Docker-ipv6 액세스 끄기" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" - echo -e "${gl_kjlan}20. ${gl_bai}卸载Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}Docker 환경 백업/마이그레이션/복원" + echo -e "${gl_kjlan}20. ${gl_bai}Docker 환경 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear - send_stats "安装docker环境" + send_stats "도커 환경 설치" install_add_docker ;; @@ -8341,22 +8341,22 @@ linux_docker() { local network_count=$(docker network ls -q 2>/dev/null | wc -l) local volume_count=$(docker volume ls -q 2>/dev/null | wc -l) - send_stats "docker全局状态" - echo "Docker版本" + send_stats "도커 전역 상태" + echo "도커 버전" docker -v docker compose version echo "" - echo -e "Docker镜像: ${gl_lv}$image_count${gl_bai} " + echo -e "도커 이미지:${gl_lv}$image_count${gl_bai} " docker image ls echo "" - echo -e "Docker容器: ${gl_lv}$container_count${gl_bai}" + echo -e "도커 컨테이너:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Docker 볼륨:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "도커 네트워크:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8371,15 +8371,15 @@ linux_docker() { 5) while true; do clear - send_stats "Docker网络管理" - echo "Docker网络列表" + send_stats "도커 네트워크 관리" + echo "도커 네트워크 목록" echo "------------------------------------------------------------" docker network ls echo "" echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名称" "网络名称" "IP地址" + printf "%-25s %-25s %-25s\n" "컨테이너 이름" "네트워크 이름" "IP 주소" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -8396,36 +8396,36 @@ linux_docker() { done echo "" - echo "网络操作" + echo "네트워크 운영" echo "------------------------" - echo "1. 创建网络" - echo "2. 加入网络" - echo "3. 退出网络" - echo "4. 删除网络" + echo "1. 네트워크 생성" + echo "2. 네트워크에 가입하세요" + echo "3. 네트워크 종료" + echo "4. 네트워크 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "创建网络" - read -e -p "设置新网络名: " dockernetwork + send_stats "네트워크 생성" + read -e -p "새 네트워크 이름 설정:" dockernetwork docker network create $dockernetwork ;; 2) - send_stats "加入网络" - read -e -p "加入网络名: " dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + send_stats "네트워크에 가입하세요" + read -e -p "네트워크 이름 추가:" dockernetwork + read -e -p "네트워크에 참여하는 컨테이너(여러 컨테이너 이름을 공백으로 구분하세요):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入网络" - read -e -p "退出网络名: " dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + send_stats "네트워크에 가입하세요" + read -e -p "종료 네트워크 이름:" dockernetwork + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8434,8 +8434,8 @@ linux_docker() { ;; 4) - send_stats "删除网络" - read -e -p "请输入要删除的网络名: " dockernetwork + send_stats "네트워크 삭제" + read -e -p "삭제할 네트워크 이름을 입력하세요:" dockernetwork docker network rm $dockernetwork ;; @@ -8449,29 +8449,29 @@ linux_docker() { 6) while true; do clear - send_stats "Docker卷管理" - echo "Docker卷列表" + send_stats "도커 볼륨 관리" + echo "도커 볼륨 목록" docker volume ls echo "" - echo "卷操作" + echo "볼륨 작업" echo "------------------------" - echo "1. 创建新卷" - echo "2. 删除指定卷" - echo "3. 删除所有卷" + echo "1. 새 볼륨 생성" + echo "2. 지정된 볼륨 삭제" + echo "3. 모든 볼륨 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - send_stats "新建卷" - read -e -p "设置新卷名: " dockerjuan + send_stats "새 볼륨 생성" + read -e -p "새 볼륨 이름 설정:" dockerjuan docker volume create $dockerjuan ;; 2) - read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8480,7 +8480,7 @@ linux_docker() { ;; 3) - send_stats "删除所有卷" + send_stats "모든 볼륨 삭제" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有未使用的卷吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8489,7 +8489,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -8502,7 +8502,7 @@ linux_docker() { ;; 7) clear - send_stats "Docker清理" + send_stats "도커 정리" read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}将清理无用的镜像容器网络,包括停止的容器,确定清理吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8511,13 +8511,13 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; 8) clear - send_stats "Docker源" + send_stats "도커 소스" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -8533,13 +8533,13 @@ linux_docker() { 11) clear - send_stats "Docker v6 开" + send_stats "도커 v6 켜짐" docker_ipv6_on ;; 12) clear - send_stats "Docker v6 关" + send_stats "도커 v6 닫기" docker_ipv6_off ;; @@ -8550,7 +8550,7 @@ linux_docker() { 20) clear - send_stats "Docker卸载" + send_stats "도커 제거" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -8562,7 +8562,7 @@ linux_docker() { [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -8571,7 +8571,7 @@ linux_docker() { kejilion ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -8588,158 +8588,158 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" - echo -e "测试脚本合集" + # send_stats "테스트 스크립트 수집" + echo -e "테스트 스크립트 수집" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}IP及解锁状态检测" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}IP 및 잠금 해제 상태 감지" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 잠금 해제 상태 감지" + echo -e "${gl_kjlan}2. ${gl_bai}지역 스트리밍 미디어 잠금 해제 테스트" + echo -e "${gl_kjlan}3. ${gl_bai}예우 스트리밍 미디어 잠금 해제 감지" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP 품질 확인 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}网络线路测速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" - echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三网测速" - echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程测试脚本" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}네트워크 회선 속도 테스트" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 3 네트워크 백홀 지연 라우팅 테스트" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 삼중 네트워크 백홀 회선 테스트" + echo -e "${gl_kjlan}13. ${gl_bai}초고속 트리플 네트워크 속도 테스트" + echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 빠른 백홀 테스트 스크립트" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 세 개의 네트워크 라인 테스트" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 네트워크 품질 확인 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}硬件性能测试" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" - echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU性能测试脚本" + echo -e "${gl_kjlan}하드웨어 성능 테스트" + echo -e "${gl_kjlan}21. ${gl_bai}Yabs 성능 테스트" + echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU 성능 테스트 스크립트" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}综合性测试" - echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" - echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 融合怪测评 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}nodequality 融合怪测评 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}종합적인 테스트" + echo -e "${gl_kjlan}31. ${gl_bai}벤치 성능 테스트" + echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx 퓨전 몬스터 평가${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}Nodequality 융합 몬스터 평가${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear - send_stats "ChatGPT解锁状态检测" + send_stats "ChatGPT 잠금 해제 상태 감지" bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; 2) clear - send_stats "Region流媒体解锁测试" + send_stats "지역 스트리밍 미디어 잠금 해제 테스트" bash <(curl -L -s check.unlock.media) ;; 3) clear - send_stats "yeahwu流媒体解锁检测" + send_stats "예우 스트리밍 미디어 잠금 해제 감지" install wget wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash ;; 4) clear - send_stats "xykt_IP质量体检脚本" + send_stats "xykt_IP 품질 확인 스크립트" bash <(curl -Ls IP.Check.Place) ;; 11) clear - send_stats "besttrace三网回程延迟路由测试" + send_stats "besttrace 삼중 네트워크 백홀 지연 라우팅 테스트" install wget wget -qO- git.io/besttrace | bash ;; 12) clear - send_stats "mtr_trace三网回程线路测试" + send_stats "mtr_trace 삼중 네트워크 백홀 회선 테스트" curl ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash ;; 13) clear - send_stats "Superspeed三网测速" + send_stats "초고속 트리플 네트워크 속도 테스트" bash <(curl -Lso- https://git.io/superspeed_uxh) ;; 14) clear - send_stats "nxtrace快速回程测试脚本" + send_stats "nxtrace 빠른 백홀 테스트 스크립트" curl nxtrace.org/nt |bash nexttrace --fast-trace --tcp ;; 15) clear - send_stats "nxtrace指定IP回程测试脚本" - echo "可参考的IP列表" + send_stats "nxtrace는 IP 백홀 테스트 스크립트를 지정합니다." + echo "참조 IP 목록" echo "------------------------" - echo "北京电信: 219.141.136.12" - echo "北京联通: 202.106.50.1" - echo "北京移动: 221.179.155.161" - echo "上海电信: 202.96.209.133" - echo "上海联通: 210.22.97.1" - echo "上海移动: 211.136.112.200" - echo "广州电信: 58.60.188.222" - echo "广州联通: 210.21.196.6" - echo "广州移动: 120.196.165.24" - echo "成都电信: 61.139.2.69" - echo "成都联通: 119.6.6.6" - echo "成都移动: 211.137.96.205" - echo "湖南电信: 36.111.200.100" - echo "湖南联通: 42.48.16.100" - echo "湖南移动: 39.134.254.6" + echo "베이징 통신: 219.141.136.12" + echo "베이징 유니콤: 202.106.50.1" + echo "베이징 모바일: 221.179.155.161" + echo "상하이 통신: 202.96.209.133" + echo "상하이 유니콤: 210.22.97.1" + echo "상하이 모바일: 211.136.112.200" + echo "광저우 통신: 58.60.188.222" + echo "광저우 차이나 유니콤: 210.21.196.6" + echo "광저우 모바일: 120.196.165.24" + echo "청두통신: 61.139.2.69" + echo "청두 차이나 유니콤: 119.6.6.6" + echo "청두 모바일: 211.137.96.205" + echo "후난 통신: 36.111.200.100" + echo "후난 유니콤: 42.48.16.100" + echo "후난 모바일: 39.134.254.6" echo "------------------------" - read -e -p "输入一个指定IP: " testip + read -e -p "특정 IP를 입력하세요:" testip curl nxtrace.org/nt |bash nexttrace $testip ;; 16) clear - send_stats "ludashi2020三网线路测试" + send_stats "ludashi2020 세 개의 네트워크 라인 테스트" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; 17) clear - send_stats "i-abc多功能测速脚本" + send_stats "i-abc 다기능 속도 테스트 스크립트" bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh) ;; 18) clear - send_stats "网络质量测试脚本" + send_stats "네트워크 품질 테스트 스크립트" bash <(curl -sL Net.Check.Place) ;; 21) clear - send_stats "yabs性能测试" + send_stats "Yabs 성능 테스트" check_swap curl -sL yabs.sh | bash -s -- -i -5 ;; 22) clear - send_stats "icu/gb5 CPU性能测试脚本" + send_stats "icu/gb5 CPU 성능 테스트 스크립트" check_swap bash <(curl -sL bash.icu/gb5) ;; 31) clear - send_stats "bench性能测试" + send_stats "벤치 성능 테스트" curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "spiritysdx 퓨전 몬스터 리뷰" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) - send_stats "nodequality融合怪测评" + send_stats "Nodequality 융합 몬스터 평가" clear bash <(curl -sL https://run.NodeQuality.com) ;; @@ -8751,7 +8751,7 @@ linux_test() { ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -8767,51 +8767,51 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" - echo -e "甲骨文云脚本合集" + send_stats "Oracle Cloud 스크립트 컬렉션" + echo -e "Oracle Cloud 스크립트 컬렉션" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}安装闲置机器活跃脚本" - echo -e "${gl_kjlan}2. ${gl_bai}卸载闲置机器活跃脚本" + echo -e "${gl_kjlan}1. ${gl_bai}유휴 머신 활성 스크립트 설치" + echo -e "${gl_kjlan}2. ${gl_bai}유휴 컴퓨터에서 활성 스크립트 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}3. ${gl_bai}DD重装系统脚本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" + echo -e "${gl_kjlan}3. ${gl_bai}DD 재설치 시스템 스크립트" + echo -e "${gl_kjlan}4. ${gl_bai}R 형사 시작 스크립트" + echo -e "${gl_kjlan}5. ${gl_bai}ROOT 비밀번호 로그인 모드 활성화" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6 복구 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "确定安装吗?(Y/N): " choice + echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) install_docker - # 设置默认值 + # 기본값 설정 local DEFAULT_CPU_CORE=1 local DEFAULT_CPU_UTIL="10-20" local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter 키를 누르면 기본값이 사용됩니다. + read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "CPU 사용량 백분율 범위(예: 10-20)를 입력하십시오. [기본값:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "메모리 사용량 비율을 입력하십시오.[기본값:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "속도 테스트 간격 시간(초)을 입력하십시오. [기본값:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # 运行Docker容器 + # Docker 컨테이너 실행 docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -8819,14 +8819,14 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "Oracle Cloud 설치 활성 스크립트" ;; [Nn]) ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -8834,20 +8834,20 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "Oracle Cloud 제거 활성 스크립트" ;; 3) clear - echo "重装系统" + echo "시스템 재설치" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" - read -e -p "确定继续吗?(Y/N): " choice + echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "다시 설치하려는 시스템을 선택하십시오: 1. Debian12 | 2. 우분투20.04:" sys_choice case "$sys_choice" in 1) @@ -8859,28 +8859,28 @@ linux_Oracle() { break # 结束循环 ;; *) - echo "无效的选择,请重新输入。" + echo "선택이 잘못되었습니다. 다시 입력해 주세요." ;; esac done - read -e -p "请输入你重装后的密码: " vpspasswd + read -e -p "재설치 후 비밀번호를 입력해주세요:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "Oracle Cloud 재설치 시스템 스크립트" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; 4) clear - send_stats "R探长开机脚本" + send_stats "R 형사 시작 스크립트" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -8890,15 +8890,15 @@ linux_Oracle() { 6) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 jhb에서 제공합니다. 감사합니다!" + send_stats "IPv6 수리" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -8922,7 +8922,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}环境已经安装${gl_bai} 容器: ${gl_lv}$container_count${gl_bai} 镜像: ${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai} 卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}환경이 설치되었습니다.${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" fi } @@ -8943,7 +8943,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai} 站点: $output 数据库: $db_output" + echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}대지:$output데이터 베이스:$db_output" fi fi @@ -8971,31 +8971,31 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" - echo -e "${gl_huang}LDNMP建站" + # send_stats "LDNMP 웹사이트 구축" + echo -e "${gl_huang}LDNMP 웹사이트 구축" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安装WordPress ${gl_huang}★${gl_bai}" - echo -e "${gl_huang}3. ${gl_bai}安装Discuz论坛 ${gl_huang}4. ${gl_bai}安装可道云桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安装typecho轻量博客网站" - echo -e "${gl_huang}9. ${gl_bai}安装LinkStack共享链接平台 ${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경 설치${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" + echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼 설치${gl_huang}4. ${gl_bai}Kedao 클라우드 데스크탑 설치" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 TV 스테이션 설치${gl_huang}6. ${gl_bai}Unicorn 디지털 카드 네트워크 설치" + echo -e "${gl_huang}7. ${gl_bai}flarum 포럼 웹사이트 설치${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" + echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}맞춤 동적 사이트" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}仅安装nginx ${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站点反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}安装Halo博客网站" - echo -e "${gl_huang}27. ${gl_bai}安装AI绘画提示词生成器 ${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" - echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自定义静态站点" + echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" + echo -e "${gl_huang}23. ${gl_bai}사이트 역방향 프록시-IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" + echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" + echo -e "${gl_huang}29. ${gl_bai}스트림 4계층 프록시 전달${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}备份全站数据" - echo -e "${gl_huang}33. ${gl_bai}定时远程备份 ${gl_huang}34. ${gl_bai}还原全站数据" + echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" + echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터 복원" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}35. ${gl_bai}防护LDNMP环境 ${gl_huang}36. ${gl_bai}优化LDNMP环境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP环境 ${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경 보호${gl_huang}36. ${gl_bai}LDNMP 환경 최적화" + echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경 업데이트${gl_huang}38. ${gl_bai}LDNMP 환경 제거" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}0. ${gl_bai}返回主菜单" + echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -9009,10 +9009,10 @@ linux_ldnmp() { 3) clear - # Discuz论坛 - webname="Discuz论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + # 토론 포럼 + webname="토론 포럼" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9040,21 +9040,21 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: discuz_" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사: discuz_" ;; 4) clear - # 可道云桌面 - webname="可道云桌面" - send_stats "安装$webname" - echo "开始部署 $webname" + # Kedao 클라우드 데스크탑 + webname="Kedao 클라우드 데스크탑" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9079,20 +9079,20 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" - echo "redis主机: redis" + echo "데이터베이스 주소: mysql" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름:$dbname" + echo "레디스 호스트: 레디스" ;; 5) clear - # 苹果CMS - webname="苹果CMS" - send_stats "安装$webname" - echo "开始部署 $webname" + # AppleCMS + webname="AppleCMS" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9123,24 +9123,24 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库前缀: mac_" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 포트: 3306" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 접두사: mac_" echo "------------------------" - echo "安装成功后登录后台地址" + echo "설치가 성공적으로 완료되면 백엔드 주소로 로그인하세요." echo "https://$yuming/vip.php" ;; 6) clear - # 独脚数卡 - webname="独脚数卡" - send_stats "安装$webname" - echo "开始部署 $webname" + # 한쪽다리 숫자카드 + webname="한쪽다리 숫자카드" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9167,34 +9167,34 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 포트: 3306" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" echo "" - echo "redis地址: redis" - echo "redis密码: 默认不填写" - echo "redis端口: 6379" + echo "레디스 주소 : 레디스" + echo "redis 비밀번호: 기본적으로 입력되지 않음" + echo "레디스 포트: 6379" echo "" - echo "网站url: https://$yuming" - echo "后台登录路径: /admin" + echo "웹사이트 URL: https://$yuming" + echo "백엔드 로그인 경로: /admin" echo "------------------------" - echo "用户名: admin" - echo "密码: admin" + echo "사용자 이름: 관리자" + echo "비밀번호: 관리자" echo "------------------------" - echo "登录时右上角如果出现红色error0请使用如下命令: " - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; 7) clear - # flarum论坛 - webname="flarum论坛" - send_stats "安装$webname" - echo "开始部署 $webname" + # 플라럼 포럼 + webname="플라럼 포럼" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9241,12 +9241,12 @@ linux_ldnmp() { ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: flarum_" - echo "管理员信息自行设置" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사: flarum_" + echo "관리자 정보는 직접 설정 가능" ;; @@ -9254,8 +9254,8 @@ linux_ldnmp() { clear # typecho webname="typecho" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9285,11 +9285,11 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" - echo "数据库地址: mysql" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "数据库名: $dbname" + echo "데이터베이스 접두사: typecho_" + echo "데이터베이스 주소: mysql" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "데이터베이스 이름:$dbname" ;; @@ -9298,8 +9298,8 @@ linux_ldnmp() { clear # LinkStack webname="LinkStack" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9328,18 +9328,18 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库地址: mysql" - echo "数据库端口: 3306" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 포트: 3306" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" ;; 20) clear - webname="PHP动态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + webname="PHP 동적 사이트" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -9359,10 +9359,10 @@ linux_ldnmp() { cd $yuming clear - echo -e "[${gl_huang}1/6${gl_bai}] 上传PHP源码" + echo -e "[${gl_huang}1/6${gl_bai}] PHP 소스 코드 업로드" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9372,20 +9372,20 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/6${gl_bai}] index.php所在路径" + echo -e "[${gl_huang}2/6${gl_bai}] index.php가 위치한 경로" echo "-------------" # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "(/home/web/html/과 유사하게 index.php 경로를 입력하세요.$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" + echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택해주세요." echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. PHP 최신 버전 | 2.php7.4:" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -9396,15 +9396,15 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "无效的选择,请重新输入。" + echo "선택이 잘못되었습니다. 다시 입력해 주세요." ;; esac clear - echo -e "[${gl_huang}4/6${gl_bai}] 安装指定扩展" + echo -e "[${gl_huang}4/6${gl_bai}] 지정된 확장 설치" echo "-------------" - echo "已经安装的扩展" + echo "설치된 확장 프로그램" docker exec php php -m read -e -p "$(echo -e "输入需要安装的扩展名称,如 ${gl_huang}SourceGuardian imap ftp${gl_bai} 等等。直接回车将跳过安装 : ")" php_extensions @@ -9414,25 +9414,25 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}5/6${gl_bai}] 编辑站点配置" + echo -e "[${gl_huang}5/6${gl_bai}] 사이트 구성 편집" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "계속하려면 아무 키나 누르세요. 의사정적 콘텐츠 등 사이트 구성을 세부적으로 설정할 수 있습니다." read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" + echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db case $use_db in 1) echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" - read -e -p "也可以输入下载链接,远程下载备份数据,直接回车将跳过远程下载: " url_download_db + echo "데이터베이스 백업은 .gz로 끝나는 압축 패키지여야 합니다. Pagoda/1panel 백업 데이터 가져오기를 지원하려면 /home/ 디렉토리에 넣으십시오." + read -e -p "다운로드 링크를 입력하여 원격으로 백업 데이터를 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download_db cd /home/ if [ -n "$url_download_db" ]; then @@ -9442,10 +9442,10 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "数据库导入的表数据" + echo "데이터베이스에서 가져온 테이블 데이터" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "데이터베이스 가져오기 완료" ;; *) echo @@ -9457,12 +9457,12 @@ linux_ldnmp() { restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" - echo "数据库地址: mysql" - echo "数据库名: $dbname" - echo "用户名: $dbuse" - echo "密码: $dbusepasswd" - echo "表前缀: $prefix" - echo "管理员登录信息自行设置" + echo "데이터베이스 주소: mysql" + echo "데이터베이스 이름:$dbname" + echo "사용자 이름:$dbuse" + echo "비밀번호:$dbusepasswd" + echo "테이블 접두사:$prefix" + echo "관리자 로그인 정보는 직접 설정합니다." ;; @@ -9474,11 +9474,11 @@ linux_ldnmp() { 22) clear - webname="站点重定向" - send_stats "安装$webname" - echo "开始部署 $webname" + webname="사이트 리디렉션" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming - read -e -p "请输入跳转域名: " reverseproxy + read -e -p "리디렉션 도메인 이름을 입력하세요." reverseproxy nginx_install_status @@ -9505,7 +9505,7 @@ linux_ldnmp() { find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address close_port "$port" @@ -9516,12 +9516,12 @@ linux_ldnmp() { 24) clear - webname="反向代理-域名" - send_stats "安装$webname" - echo "开始部署 $webname" + webname="역방향 프록시 도메인 이름" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming - echo -e "域名格式: ${gl_huang}google.com${gl_bai}" - read -e -p "请输入你的反代域名: " fandai_yuming + echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -9545,8 +9545,8 @@ linux_ldnmp() { 25) clear webname="Bitwarden" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming docker run -d \ @@ -9565,8 +9565,8 @@ linux_ldnmp() { 26) clear webname="halo" - send_stats "安装$webname" - echo "开始部署 $webname" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming docker run -d --name halo --restart=always -p 8010:8090 -v /home/web/html/$yuming/.halo2:/root/.halo2 halohub/halo:2 @@ -9578,9 +9578,9 @@ linux_ldnmp() { 27) clear - webname="AI绘画提示词生成器" - send_stats "安装$webname" - echo "开始部署 $webname" + webname="AI 그림 프롬프트 단어 생성기" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming nginx_install_status @@ -9619,9 +9619,9 @@ linux_ldnmp() { 30) clear - webname="静态站点" - send_stats "安装$webname" - echo "开始部署 $webname" + webname="정적 사이트" + send_stats "설치하다$webname" + echo "배포 시작$webname" add_yuming repeat_add_yuming nginx_install_status @@ -9641,10 +9641,10 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}1/2${gl_bai}] 上传静态源码" + echo -e "[${gl_huang}1/2${gl_bai}] 정적 소스 코드 업로드" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目录下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + echo "현재는 zip 형식의 소스 코드 패키지만 업로드할 수 있습니다. 소스 코드 패키지를 /home/web/html/에 넣어주세요.${yuming}디렉토리 아래" + read -e -p "다운로드 링크를 입력하여 소스 코드 패키지를 원격으로 다운로드할 수도 있습니다. 원격 다운로드를 건너뛰려면 Enter를 직접 누르세요." url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9654,12 +9654,12 @@ linux_ldnmp() { rm -f $(ls -t *.zip | head -n 1) clear - echo -e "[${gl_huang}2/2${gl_bai}] index.html所在路径" + echo -e "[${gl_huang}2/2${gl_bai}] index.html이 위치한 경로" echo "-------------" # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "(/home/web/html/과 유사하게 index.html 경로를 입력하세요.$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -9684,19 +9684,19 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP 환경 백업" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" cd /home/ && tar czvf "$backup_filename" web while true; do clear - echo "备份文件已创建: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "생성된 백업 파일: /home/$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -9704,9 +9704,9 @@ linux_ldnmp() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/home/" - echo "文件已传送至远程服务器home目录。" + echo "파일이 원격 서버 홈 디렉터리로 전송되었습니다." else - echo "未找到要传送的文件。" + echo "전송할 파일을 찾을 수 없습니다." fi break ;; @@ -9714,7 +9714,7 @@ linux_ldnmp() { break ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac done @@ -9722,9 +9722,9 @@ linux_ldnmp() { 33) clear - send_stats "定时远程备份" - read -e -p "输入远程服务器IP: " useip - read -e -p "输入远程服务器密码: " usepasswd + send_stats "예약된 원격 백업" + read -e -p "원격 서버 IP를 입력하세요." useip + read -e -p "원격 서버 비밀번호를 입력하세요:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -9734,18 +9734,18 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" - read -e -p "请输入你的选择: " dingshi + echo "1. 주간 백업 2. 일일 백업" + read -e -p "선택사항을 입력하세요:" dingshi case $dingshi in 1) check_crontab_installed - read -e -p "选择每周备份的星期几 (0-6,0代表星期日): " weekday + read -e -p "주간 백업 요일을 선택합니다(0-6, 0은 일요일을 나타냄)." weekday (crontab -l ; echo "0 0 * * $weekday ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "일일 백업 시간 선택(시간, 0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -9759,19 +9759,19 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP环境还原" - echo "可用的站点备份" + send_stats "LDNMP 환경 복원" + echo "사용 가능한 사이트 백업" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename if [ "$filename" == "0" ]; then break_end linux_ldnmp fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. if [ -z "$filename" ]; then local filename=$(ls -t /home/*.tar.gz | head -1) fi @@ -9781,7 +9781,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9789,7 +9789,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "압축된 패키지를 찾을 수 없습니다." fi ;; @@ -9807,11 +9807,11 @@ linux_ldnmp() { root_use while true; do clear - send_stats "更新LDNMP环境" - echo "更新LDNMP环境" + send_stats "LDNMP 환경 업데이트" + echo "LDNMP 환경 업데이트" echo "------------------------" ldnmp_v - echo "发现新版本的组件" + echo "새 버전의 구성 요소가 발견되었습니다." echo "------------------------" check_docker_image_update nginx if [ -n "$update_status" ]; then @@ -9831,13 +9831,13 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. nginx 업데이트 2. mysql 업데이트 3. PHP 업데이트 4. redis 업데이트" echo "------------------------" - echo "5. 更新完整环境" + echo "5. 전체 환경 업데이트" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) nginx_upgrade @@ -9846,7 +9846,7 @@ linux_ldnmp() { 2) local ldnmp_pods="mysql" - read -e -p "请输入${ldnmp_pods}版本号 (如: 8.0 8.3 8.4 9.0)(回车获取最新版): " version + read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 8.0 8.3 8.4 9.0)(최신 버전을 얻으려면 Enter 키를 누르세요):" version local version=${version:-latest} cd /home/web/ @@ -9857,13 +9857,13 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 3) local ldnmp_pods="php" - read -e -p "请输入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "입력해주세요${ldnmp_pods}버전 번호(예: 7.4 8.0 8.1 8.2 8.3)(최신 버전을 얻으려면 Enter 키를 누르세요):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -9896,8 +9896,8 @@ linux_ldnmp() { docker restart $ldnmp_pods > /dev/null 2>&1 cp /home/web/docker-compose1.yml /home/web/docker-compose.yml - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 4) @@ -9907,15 +9907,15 @@ linux_ldnmp() { docker images --filter=reference="$ldnmp_pods*" -q | xargs docker rmi > /dev/null 2>&1 docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "更新$ldnmp_pods" - echo "更新${ldnmp_pods}完成" + send_stats "고쳐 쓰다$ldnmp_pods" + echo "고쳐 쓰다${ldnmp_pods}마치다" ;; 5) read -e -p "$(echo -e "${gl_huang}提示: ${gl_bai}长时间不更新环境的用户,请慎重更新LDNMP环境,会有数据库更新失败的风险。确定更新LDNMP环境吗?(Y/N): ")" choice case "$choice" in [Yy]) - send_stats "完整更新LDNMP环境" + send_stats "LDNMP 환경 전체 업데이트" cd /home/web/ docker compose down --rmi all @@ -9940,7 +9940,7 @@ linux_ldnmp() { 38) root_use - send_stats "卸载LDNMP环境" + send_stats "LDNMP 환경 제거" read -e -p "$(echo -e "${gl_hong}强烈建议:${gl_bai}先备份全部网站数据,再卸载LDNMP环境。确定删除所有网站数据吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -9954,7 +9954,7 @@ linux_ldnmp() { ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -9964,7 +9964,7 @@ linux_ldnmp() { ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" esac break_end @@ -9980,14 +9980,14 @@ linux_ldnmp() { moltbot_menu() { local app_id="114" - send_stats "clawdbot/moltbot管理" + send_stats "클로드봇/몰트봇 관리" check_openclaw_update() { if ! command -v npm >/dev/null 2>&1; then return 1 fi - # 加上 --no-update-notifier,并确保错误重定向位置正确 + # --no-update-notifier를 추가하고 오류 리디렉션이 올바른 위치에 있는지 확인하세요. local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10001,26 +10001,26 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" + echo "${gl_huang}새 버전이 감지되었습니다.$remote_version${gl_bai}" else - echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}현재 버전이 최신 버전입니다.$local_version${gl_bai}" fi } get_install_status() { if command -v openclaw >/dev/null 2>&1; then - echo "${gl_lv}已安装${gl_bai}" + echo "${gl_lv}설치됨${gl_bai}" else - echo "${gl_hui}未安装${gl_bai}" + echo "${gl_hui}설치되지 않음${gl_bai}" fi } get_running_status() { if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then - echo "${gl_lv}运行中${gl_bai}" + echo "${gl_lv}달리기${gl_bai}" else - echo "${gl_hui}未运行${gl_bai}" + echo "${gl_hui}실행되지 않음${gl_bai}" fi } @@ -10035,36 +10035,36 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" + echo -e "🦞 KEJILION의 OPENCLAW 관리 도구 🦞" + echo -e "💡 터미널 실행 \033[1;33mk 클로\033[0m 빠르게 메뉴 진입" echo -e "$install_status $running_status $update_message" echo "=======================================" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" + echo "1. 설치" + echo "2. 시작" + echo "3. 중지" echo "--------------------" - echo "4. 状态日志查看" - echo "5. 换模型" - echo "6. API管理" - echo "7. 机器人连接对接" - echo "8. 插件管理(安装/删除)" - echo "9. 技能管理(安装/删除)" - echo "10. 编辑主配置文件" - echo "11. 配置向导" - echo "12. 健康检测与修复" - echo "13. WebUI访问与设置" - echo "14. TUI命令行对话窗口" - echo "15. 记忆/Memory" - echo "16. 权限管理" + echo "4. 상태 로그 보기" + echo "5. 모델 변경" + echo "6. API 관리" + echo "7. 로봇 연결 및 도킹" + echo "8. 플러그인 관리(설치/제거)" + echo "9. 스킬 관리(설치/제거)" + echo "10. 기본 구성 파일 편집" + echo "11. 구성 마법사" + echo "12. 건강 상태 감지 및 복구" + echo "13. WebUI 접속 및 설정" + echo "14. TUI 명령줄 대화 상자 창" + echo "15. 기억/기억" + echo "16. 권한 관리" + echo "17. 다중 에이전트 관리" echo "--------------------" - echo "17. 多智能体管理" + echo "18. 백업 및 복원" + echo "19. 업데이트" + echo "20. 제거" echo "--------------------" - echo "18. 备份与还原" - echo "19. 更新" - echo "20. 卸载" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------" - echo "0. 返回上一级选单" - echo "--------------------" - printf "请输入选项并回车: " + printf "옵션을 입력하고 Enter를 누르십시오." } @@ -10091,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10122,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10172,7 +10174,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') + print('ℹ️ API 제공업체가 감지되지 않음, 모델 동기화 건너뛰기') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10240,7 +10242,7 @@ def collect_available_refs(exclude_provider=None): def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型?[y/N]: " + prompt = f"⚠️ {name} /models 프로브가 3번 연속 실패했습니다. 이 API 제공업체 및 모든 관련 모델을 삭제하시겠습니까? [예/아니요]:" try: ans = input(prompt).strip().lower() except EOFError: @@ -10264,22 +10266,22 @@ def rebind_defaults_before_delete(name): if ref_provider(primary_ref) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: 默认主模型指向该 provider,但无可用替代模型,已中止删除') + summary.append(f'❌ {name}: 기본 기본 모델이 이 공급자를 가리키지만 사용 가능한 대체 모델이 없어 삭제가 중단되었습니다.') return False set_primary_ref(defaults, repl) changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + summary.append(f'🔁 삭제 전에 기본 기본 모델이 전환되었습니다: {primary_ref} -> {repl}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + summary.append(f'❌ {name}: {fk}가 공급자를 가리키지만 대체 모델을 사용할 수 없어 삭제가 중단되었습니다.') return False defaults[fk] = repl changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + summary.append(f'🔁 삭제 전 전환됨 {fk}: {val} -> {repl}') return True @@ -10300,7 +10302,7 @@ def delete_provider_and_refs(name): providers.pop(name, None) changed = True - summary.append(f'🗑️ 已删除 provider {name},并移除 defaults.models 下 {len(removed_refs)} 个模型引用') + summary.append(f'🗑️ 제공자 {name}이(가) 삭제되었으며 defaults.models 아래의 {len(removed_refs)} 모델 참조가 제거되었습니다.') return True @@ -10328,7 +10330,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + summary.append(f'ℹ️ {name} 건너뛰기: 공급자 구조가 불법입니다.') continue api = provider.get('api', '') @@ -10337,34 +10339,34 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + summary.append(f'ℹ️ {name} 건너뛰기: 없음 baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + summary.append(f'🔁 {name}: 잘못된 프로토콜 {api 또는 "(unset)"}이 발견되어 다시 감지됩니다.') provider['api'] = '' api = '' changed = True data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') + summary.append(f'⚠️ {name}: /models 감지 실패, {attempts} 번 재시도됨 ({type(err).__name__}: {err})') + send_stat('OpenClaw API 확인 개입') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: - send_stat('OpenClaw API删失败Provider-确认') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + send_stat('OpenClaw API 삭제 실패 공급자 확인') + summary.append(f'✅ {name}: 사용자가 공급자 및 모든 관련 모델 참조 삭제를 확인했습니다.') else: - send_stat('OpenClaw API删失败Provider-拒绝') - summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') + send_stat('OpenClaw API 삭제 실패 공급자 거부') + summary.append(f'ℹ️ {name}: 사용자가 삭제를 확인하지 않았으며 기존 공급자 구성을 유지합니다.') continue if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + summary.append(f'🔁 {name}: /models {시도}번 재시도 후 성공') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + summary.append(f'⚠️ {name} 건너뛰기: /models 반환 구조가 인식되지 않습니다.') continue remote_ids = [] @@ -10374,7 +10376,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + fatal_errors.append(f'❌ {name}의 업스트림 /models가 비어 있으며 이 공급자에 대한 상향식 모델을 제공할 수 없습니다.') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10386,7 +10388,7 @@ for name, provider in list(providers.items()): template = copy.deepcopy(m) break if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + summary.append(f'⚠️ {name} 건너뛰기: 로컬 모델에 유효한 템플릿 모델이 없습니다.') continue removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -10403,7 +10405,7 @@ for name, provider in list(providers.items()): new_models.append(nm) if not new_models: - fatal_errors.append(f'❌ {name} 同步后无可用模型,无法保障默认模型/回退模型兜底') + fatal_errors.append(f'❌ {name}은(는) 동기화 후 사용 가능한 모델이 없으며 기본 모델/폴백 모델을 보장할 수 없습니다.') continue expected_refs = {model_ref(name, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -10415,14 +10417,14 @@ for name, provider in list(providers.items()): if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): set_primary_ref(defaults, first_ref) changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + summary.append(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if isinstance(val, str) and val in (local_refs - expected_refs): defaults[fk] = first_ref changed = True - summary.append(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + summary.append(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/') and r not in expected_refs] for r in stale_refs: @@ -10438,14 +10440,14 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') + summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') + summary.append(f'➕ 새 모델 추가({len(add_ids)}):') for mid in added_ids: summary.append(f' + {mid}') if removed_ids: - summary.append(f'➖ 删除模型({len(removed_ids)}):') + summary.append(f'➖ 모델 삭제({len(removed_ids)}):') for mid in removed_ids: summary.append(f' - {mid}') @@ -10455,7 +10457,7 @@ if fatal_errors: print(line) for err in fatal_errors: print(err) - print('❌ 模型同步失败:存在 provider 同步后无可用模型,已中止写入') + print('❌ 모델 동기화 실패: 공급자가 있습니다. 동기화 후 사용 가능한 모델이 없으며 쓰기가 중단되었습니다.') raise SystemExit(2) if changed: @@ -10464,19 +10466,20 @@ if changed: f.write('\n') for line in summary: print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + print('✅ OpenClaw API 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') else: for line in summary: print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + print('ℹ️ 동기화가 필요하지 않습니다. 구성이 이미 업스트림/모델과 일치합니다.') PY } install_moltbot() { - echo "开始安装 OpenClaw..." - send_stats "开始安装 OpenClaw..." + echo "OpenClaw 설치를 시작합니다..." + send_stats "OpenClaw 설치를 시작합니다..." + install git jq install_node_and_tools @@ -10492,7 +10495,7 @@ PY openclaw onboard --install-daemon openclaw config set tools.profile full openclaw config set tools.elevated.enabled true - # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart + # 팁: 즉시 적용되도록 구성을 수정해야 하는 경우 게이트웨이를 다시 시작할 수 있습니다. openclaw Gateway restart configure_openclaw_session_policy start_gateway add_app_id @@ -10502,23 +10505,23 @@ PY start_bot() { - echo "启动 OpenClaw..." - send_stats "启动 OpenClaw..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_gateway break_end } stop_bot() { - echo "停止 OpenClaw..." - send_stats "停止 OpenClaw..." + echo "OpenClaw를 중지하세요..." + send_stats "OpenClaw를 중지하세요..." tmux kill-session -t gateway > /dev/null 2>&1 openclaw gateway stop break_end } view_logs() { - echo "查看 OpenClaw 状态日志" - send_stats "查看 OpenClaw 日志" + echo "OpenClaw 상태 로그 보기" + send_stats "OpenClaw 로그 보기" openclaw status openclaw gateway status openclaw logs @@ -10529,10 +10532,10 @@ PY - # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 - # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 + # OpenClaw API 프로토콜 감지 논리가 제거되었습니다. API 유형은 더 이상 자동으로 감지/결정되지 않습니다. + # 참고: API 유형은 사용자(models.providers..api)에 의해 명시적으로 구성되며 스크립트는 더 이상 추론을 위해 /responses를 호출하려고 시도하지 않습니다. - # 构造模型配置 JSON + # 모델 구성 JSON 구성 build-openclaw-provider-models-json() { local provider_name="$1" local model_ids="$2" @@ -10586,15 +10589,16 @@ EOF echo "$models_array" } - # 写入 provider 与模型配置 + # 공급자 및 모델 구성 쓰기 write-openclaw-provider-models() { local provider_name="$1" local base_url="$2" local api_key="$3" local models_array="$4" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) - # 不再自动探测/纠正 API 协议;保持用户配置为准 + # 더 이상 API 프로토콜을 자동으로 감지/수정하지 않습니다. 사용자 구성 유지 DETECTED_API="openai-completions" [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" @@ -10634,32 +10638,32 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" } - # 核心函数:获取并添加所有模型 + # 핵심 기능: 모든 모델 가져오기 및 추가 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" local api_key="$3" - echo "🔍 正在获取 $provider_name 的所有可用模型..." + echo "🔍 받기$provider_name사용 가능한 모든 모델..." local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ "${base_url}/models") if [[ -z "$models_json" ]]; then - echo "❌ 无法获取模型列表" + echo "❌ 모델 목록을 가져올 수 없습니다" return 1 fi local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') if [[ -z "$model_ids" ]]; then - echo "❌ 未找到任何模型" + echo "❌ 모델을 찾을 수 없습니다" return 1 fi local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 发现 $model_count 个模型" + echo "✅ 발견$model_count모델" local models_array models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") @@ -10667,16 +10671,16 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 成功添加 $model_count 个模型到 $provider_name" - echo "📦 模型引用格式: $provider_name/" + echo "✅ 성공적으로 추가되었습니다$model_count모델 도착$provider_name" + echo "📦 모델 참조 형식:$provider_name/" return 0 else - echo "❌ 配置注入失败" + echo "❌ 구성 삽입 실패" return 1 fi } - # 仅添加默认模型并保留 provider + # 기본 모델만 추가하고 공급자는 유지 add-default-model-only-to-provider() { local provider_name="$1" local base_url="$2" @@ -10684,7 +10688,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 默认模型不能为空" + echo "❌ 기본 모델은 비워둘 수 없습니다." return 1 fi @@ -10694,47 +10698,47 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 已添加 provider:$provider_name" - echo "✅ 仅写入默认模型:$default_model" + echo "✅ 제공업체 추가됨:$provider_name" + echo "✅ 기본 모델에만 쓰기:$default_model" return 0 else - echo "❌ 配置注入失败" + echo "❌ 구성 삽입 실패" return 1 fi } add-openclaw-provider-interactive() { - send_stats "OpenClaw API添加" - echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" + send_stats "OpenClaw API가 추가되었습니다." + echo "=== 대화식으로 OpenClaw 공급자 추가(전체 모델) ===" - # 1. Provider 名称 - read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + # 1. 제공자 이름 + read -erp "공급자 이름을 입력하십시오(예: deepseek):" provider_name while [[ -z "$provider_name" ]]; do - echo "❌ Provider 名称不能为空" - read -erp "请输入 Provider 名称: " provider_name + echo "❌ 제공업체 이름은 비워둘 수 없습니다." + read -erp "제공업체 이름을 입력하세요." provider_name done # 2. Base URL - read -erp "请输入 Base URL (如: https://api.xxx.com/v1): " base_url + read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do - echo "❌ Base URL 不能为空" - read -erp "请输入 Base URL: " base_url + echo "❌ 기본 URL은 비워둘 수 없습니다." + read -erp "기본 URL을 입력하세요:" base_url done base_url="${base_url%/}" # 3. API Key - read -rsp "请输入 API Key (输入不显示): " api_key + read -rsp "API 키를 입력하세요(입력은 표시되지 않습니다):" api_key echo while [[ -z "$api_key" ]]; do - echo "❌ API Key 不能为空" - read -rsp "请输入 API Key: " api_key + echo "❌ API 키는 비워둘 수 없습니다." + read -rsp "API 키를 입력하세요:" api_key echo done - # 4. 不再探测/判断 API 类型;协议由用户自行选择与维护 + # 4. 더 이상 API 유형을 감지/결정하지 않습니다. 프로토콜은 사용자가 직접 선택하고 유지 관리합니다. - # 5. 获取模型列表 - echo "🔍 正在获取可用模型列表..." + # 5. 모델 목록 가져오기 + echo "🔍 사용 가능한 모델 목록을 가져오는 중..." models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ "${base_url}/models") @@ -10744,9 +10748,9 @@ EOF if [[ -n "$available_models" ]]; then model_count=$(echo "$available_models" | wc -l) - echo "✅ 发现 $model_count 个可用模型:" + echo "✅ 발견$model_count사용 가능한 모델:" echo "--------------------------------" - # 全部显示,带序号 + # 일련번호와 함께 모두 표시 i=1 model_list=() while read -r model; do @@ -10758,50 +10762,51 @@ EOF fi fi - # 5. 选择默认模型 + # 5. 기본 모델을 선택하세요 echo - read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model + read -erp "기본 모델 ID(또는 일련번호, 첫 번째 번호를 사용하려면 비워 두세요)를 입력하세요." input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) - echo "🎯 使用第一个模型: $default_model" + echo "🎯 첫 번째 모델 사용:$default_model" elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then default_model="${model_list[$((input_model-1))]}" - echo "🎯 已选择模型: $default_model" + echo "🎯 선택 모델:$default_model" else default_model="$input_model" fi - # 6. 确认信息 + # 6. 정보 확인 echo - echo "====== 确认信息 ======" + echo "====== 확인 ======" echo "Provider : $provider_name" echo "Base URL : $base_url" echo "API Key : ${api_key:0:8}****" - echo "默认模型 : $default_model" - echo "模型总数 : $model_count" + echo "기본 모델:$default_model" + echo "총 모델 수:$model_count" echo "======================" - read -erp "是否同时添加其他所有可用模型?(y/N): " confirm + read -erp "사용 가능한 다른 모든 모델을 동시에 추가하시겠습니까? (예/아니요):" confirm install jq if [[ "$confirm" =~ ^[Yy]$ ]]; then add-all-models-from-provider "$provider_name" "$base_url" "$api_key" add_result=$? - finish_msg="✅ 完成!所有 $model_count 个模型已加载" + finish_msg="✅ 완료! 모두$model_count로드된 모델" else add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" add_result=$? - finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" + finish_msg="✅ 완료! 공급자는 유지되고 기본 모델만 로드됩니다.$default_model" fi if [[ $add_result -eq 0 ]]; then echo - echo "🔄 设置默认模型并重启网关..." + echo "🔄 기본 모델을 설정하고 게이트웨이를 다시 시작하세요..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway echo "$finish_msg" - echo "✅ 当前 API 协议类型: $DETECTED_API" + echo "✅ 현재 API 프로토콜 유형:$DETECTED_API" fi break_end @@ -10811,7 +10816,7 @@ EOF openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API列表" + send_stats "OpenClaw API 목록" while IFS=$'\t' read -r rec_type idx name base_url model_count api_type latency_txt latency_level; do case "$rec_type" in @@ -10827,7 +10832,7 @@ openclaw_api_manage_list() { unchecked) latency_color="$gl_bai" ;; esac - printf '%b\n' "[$idx] ${name} | API: ${base_url} | 协议: ${api_type} | 模型数量: ${gl_huang}${model_count}${gl_bai} | 延迟/状态: ${latency_color}${latency_txt}${gl_bai}" + printf '%b\n' "[$idx] ${name} | API: ${base_url}| 합의:${api_type}| 모델 수:${gl_huang}${model_count}${gl_bai}| 지연/상태:${latency_color}${latency_txt}${gl_bai}" ;; esac done < <(python3 - "$config_file" <<-'PY' @@ -10855,10 +10860,10 @@ def ping_models(base_url, api_key): def classify_latency(latency): - if latency == '不可用': - return '不可用', 'unavailable' - if latency == '未检测': - return '未检测', 'unchecked' + if latency == '사용할 수 없음': + return '사용할 수 없음', 'unavailable' + if latency == '감지되지 않음': + return '감지되지 않음', 'unchecked' if isinstance(latency, int): if latency <= 800: level = 'low' @@ -10874,25 +10879,25 @@ try: with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + print('MSG\tℹ️ openclaw.json을 찾을 수 없습니다. 먼저 설치/초기화를 완료하세요.') raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + print(f'MSG\t❌ 구성을 읽지 못했습니다: {type(e).__name__}: {e}') raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') + print('MSG\tℹ️ 현재 구성된 API 제공업체가 없습니다.') raise SystemExit(0) -print('MSG\t--- 已配置 API 列表 ---') +print('MSG\t--- 구성된 API 목록 ---') for idx, name in enumerate(sorted(providers.keys()), start=1): provider = providers.get(name) if not isinstance(provider, dict): base_url = '-' model_count = 0 - latency_raw = '不可用' + latency_raw = '사용할 수 없음' else: base_url = provider.get('baseUrl') or provider.get('url') or provider.get('endpoint') or '-' models = provider.get('models') if isinstance(provider.get('models'), list) else [] @@ -10900,15 +10905,15 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): api = provider.get('api', '') api_key = provider.get('apiKey') - latency_raw = '未检测' + latency_raw = '감지되지 않음' if api in SUPPORTED_APIS: if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: try: latency_raw = ping_models(base_url, api_key) except Exception: - latency_raw = '不可用' + latency_raw = '사용할 수 없음' else: - latency_raw = '不可用' + latency_raw = '사용할 수 없음' latency_text, latency_level = classify_latency(latency_raw) api_label = api if api in SUPPORTED_APIS else '-' @@ -10928,23 +10933,23 @@ PY } sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API按Provider同步" + send_stats "공급자별 OpenClaw API 동기화" if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" break_end return 1 fi - read -erp "동기화할 API 이름(provider), Enter로 전체 동기화: " provider_name + read -erp "동기화할 API 이름(공급자)을 입력하고 Enter를 눌러 모두 동기화하세요." provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ API 모델 동기 실패, 게이트웨이 재시작 중단. provider /models 확인 후 재시도하세요." - break_end + echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." return 1 fi + break_end return 0 fi @@ -10968,12 +10973,12 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') + print('❌ API 제공업체가 감지되지 않아 동기화할 수 없습니다.') raise SystemExit(2) provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') + print(f'❌ 제공자: {target}을(를) 찾을 수 없습니다') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11040,21 +11045,21 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + print(f'❌ 공급자 {target}에 baseUrl/apiKey/models가 누락되어 동기화를 수행할 수 없습니다.') raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') + print(f'ℹ️ 공급자 {target}은 현재 api={api}이지만 스크립트는 더 이상 프로토콜을 감지/수정하지 않습니다. openai-completions 또는 openai-responses로 수동으로 설정하세요.') protocol_msg = None data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: - print(f'❌ {target}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + print(f'❌ {target}: /models 감지 실패, {attempts}번 재시도됨 ({type(err).__name__}: {err})') raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') + print(f'❌ {target}: /models 반환된 구조가 인식되지 않습니다.') raise SystemExit(4) remote_ids = [] @@ -11063,7 +11068,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') + print(f'❌ {target}: 업스트림 /models가 비어 있고 동기화가 중단되었습니다.') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11072,7 +11077,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + print(f'❌ {target}: 로컬 모델에 유효한 템플릿 모델이 없어 새 모델을 추가할 수 없습니다.') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -11088,7 +11093,7 @@ for mid in added_ids: new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') + print(f'❌ {target}: 동기화 후 사용할 수 있는 모델이 없어 쓰기가 중단되었습니다.') raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -11101,14 +11106,14 @@ primary_ref = get_primary_ref(defaults) if isinstance(primary_ref, str) and primary_ref in removed_refs: set_primary_ref(defaults, first_ref) changed = True - print(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + print(f'🔁 기본 모델이 완전히 교체되었습니다: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if isinstance(val, str) and val in removed_refs: defaults[fk] = first_ref changed = True - print(f'🔁 {fk} 已兜底替换: {val} -> {first_ref}') + print(f'🔁 {fk}가 완전히 대체되었습니다: {val} -> {first_ref}') stale_refs = [r for r in list(defaults_models.keys()) if r.startswith(target + '/') and r not in expected_refs] for r in stale_refs: @@ -11130,42 +11135,42 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') +print(f'✅ {target}: {len(add_ids)} 추가, 삭제 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') + print(f'➕ 새 모델 추가({len(add_ids)}):') for mid in added_ids: print(f' + {mid}') if removed_ids: - print(f'➖ 删除模型({len(removed_ids)}):') + print(f'➖ 모델 삭제({len(removed_ids)}):') for mid in removed_ids: print(f' - {mid}') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 지정된 공급자 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 동기화가 필요하지 않습니다. 공급자 구성이 이미 업스트림/모델과 일치합니다.') PY2 local rc=$? case "$rc" in 0) - echo "✅ 同步执行完成" + echo "✅ 동기 실행 완료" start_gateway ;; 2) - echo "❌ 同步失败:provider 不存在或未配置" + echo "❌ 동기화 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." ;; 3) - echo "❌ 同步失败:provider 配置不完整或类型不支持" + echo "❌ 동기화 실패: 공급자 구성이 불완전하거나 유형이 지원되지 않습니다." ;; 4) - echo "❌ 同步失败:上游 /models 请求失败" + echo "❌ 동기화 실패: 업스트림 /models 요청 실패" ;; 5) - echo "❌ 同步失败:上游模型为空或同步后无可用模型" + echo "❌ 동기화 실패: 업스트림 모델이 비어 있거나 동기화 후 사용 가능한 모델이 없습니다." ;; *) - echo "❌ 同步失败:请检查配置文件结构或日志输出" + echo "❌ 동기화 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." ;; esac @@ -11173,40 +11178,40 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 - # 保留函数以兼容菜单调用,但不做任何改写。 - echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + # 프로토콜 감지 논리가 제거되었습니다. 스크립트는 더 이상 API 유형을 자동으로 감지/결정하지 않습니다. + # 이 기능은 메뉴 호출과의 호환성을 위해 유지되지만 재작성은 수행되지 않습니다. + echo "ℹ️ 프로토콜 감지가 꺼졌습니다. 수동으로 감지하세요.${HOME}/.openclaw/openclaw.json의 공급자.api를 openai-completions 또는 openai-responses로 설정합니다." return 0 } fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API协议切换" + send_stats "OpenClaw API 프로토콜 전환" if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" break_end return 1 fi - read -erp "请输入要切换协议的 API 名称(provider): " provider_name + read -erp "프로토콜을 전환하려면 API 이름(공급자)을 입력하세요." provider_name if [ -z "$provider_name" ]; then - echo "❌ provider 名称不能为空" + echo "❌ 제공업체 이름은 비워둘 수 없습니다." break_end return 1 fi - echo "请选择要设置的 API 类型:" + echo "설정하려는 API 유형을 선택하세요." echo "1. openai-completions" echo "2. openai-responses" - read -erp "请输入你的选择 (1/2): " proto_choice + read -erp "원하는 항목(1/2)을 입력하세요." proto_choice local new_api="" case "$proto_choice" in 1) new_api="openai-completions" ;; 2) new_api="openai-responses" ;; *) - echo "❌ 无效选择" + echo "❌ 잘못된 선택" break_end return 1 ;; @@ -11225,7 +11230,7 @@ new_api = sys.argv[3] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} if new_api not in SUPPORTED_APIS: - print('❌ 非法协议值') + print('❌ 잘못된 프로토콜 값') raise SystemExit(3) with open(path, 'r', encoding='utf-8') as f: @@ -11234,7 +11239,7 @@ with open(path, 'r', encoding='utf-8') as f: work = copy.deepcopy(obj) providers = ((work.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): - print(f'❌ 未找到 provider: {name}') + print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') raise SystemExit(2) providers[name]['api'] = new_api @@ -11243,7 +11248,7 @@ with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ 已更新 provider {name} 协议为: {new_api}') +print(f'✅ 공급자 {name} 프로토콜이 다음으로 업데이트되었습니다: {new_api}') PY local rc=$? case "$rc" in @@ -11251,13 +11256,13 @@ PY start_gateway ;; 2) - echo "❌ 切换失败:provider 不存在或未配置" + echo "❌ 전환 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." ;; 3) - echo "❌ 切换失败:协议值非法" + echo "❌ 전환 실패: 프로토콜 값이 잘못되었습니다." ;; *) - echo "❌ 切换失败:请检查配置文件结构或日志输出" + echo "❌ 전환 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." ;; esac @@ -11265,19 +11270,20 @@ PY } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API删除入口" + local config_file + config_file=$(openclaw_get_config_file) + send_stats "OpenClaw API 삭제 항목" if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" + echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" break_end return 1 fi - read -erp "请输入要删除的 API 名称(provider): " provider_name + read -erp "삭제할 API 이름(공급자)을 입력하세요." provider_name if [ -z "$provider_name" ]; then - send_stats "OpenClaw API删除取消" - echo "❌ provider 名称不能为空" + send_stats "OpenClaw API 삭제 취소" + echo "❌ 제공업체 이름은 비워둘 수 없습니다." break_end return 1 fi @@ -11297,7 +11303,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or name not in providers: - print(f'❌ 未找到 provider: {name}') + print(f'❌ 제공자: {name}을(를) 찾을 수 없습니다') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11364,19 +11370,19 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + print('❌ 삭제가 중단됨: 기본 기본 모델이 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') raise SystemExit(3) set_primary_ref(defaults, replacement) - print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') + print(f'🔁 기본 기본 모델 전환: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) if ref_provider(val) == name: if not replacement: - print(f'❌ 删除中止:{fk} 指向该 provider,且无可用替代模型') + print(f'❌ 삭제가 중단되었습니다. {fk}가 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + print(f'🔁 {fk} 스위치: {val} -> {교체}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11388,47 +11394,108 @@ with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'🗑️ 已删除 provider: {name}') -print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') +print(f'🗑️ 삭제된 제공자: {name}') +print(f'🧹 defaults.models에서 {len(removed_refs)} 관련 모델 참조를 정리했습니다.') PY local rc=$? case "$rc" in 0) - send_stats "OpenClaw API删除确认" - echo "✅ 删除完成" + send_stats "OpenClaw API 삭제 확인" + echo "✅삭제 완료" start_gateway ;; 2) - echo "❌ 删除失败:provider 不存在" + echo "❌ 삭제 실패: 공급자가 존재하지 않습니다." ;; 3) - send_stats "OpenClaw API删除取消" - echo "❌ 删除失败:无可用替代模型,已保持原配置" + send_stats "OpenClaw API 삭제 취소" + echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." ;; *) - echo "❌ 删除失败:请检查配置文件结构或日志输出" + echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." ;; esac break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API 공급업체 권장 사항" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 벤더 추천 목록${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}일부 입구에는 AFF가 포함되어 있습니다.${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_lv}● 슈퍼컴퓨팅 인터넷${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" + echo -e " ${gl_huang}● Youyun 지능형 컴퓨팅${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" + echo -e " ${gl_huang}● 실리콘 기반 흐름${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}● GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" + echo -e " ${gl_huang}● 클라우드 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" + echo -e " ${gl_huang}● 플라톤 AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● 백산구름${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 추천 입장${gl_bai}" + echo "" + echo -e "${gl_huang}팁: 링크를 복사하고 브라우저에서 열어서 액세스하세요.${gl_bai}" + echo "" + read -erp "돌아가려면 Enter를 누르세요..." dummy + } + openclaw_api_manage_menu() { - send_stats "OpenClaw API入口" + send_stats "OpenClaw API 입구" while true; do clear echo "=======================================" - echo "OpenClaw API 管理" + echo "OpenClaw API 관리" echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. 添加API" - echo "2. 同步API供应商模型列表" - echo "3. 切换 API 类型(completions / responses)" - echo "4. 删除API" - echo "0. 退出" + echo "1. API 추가" + echo "2. API 제공자 모델 목록 동기화" + echo "3. API 유형 전환(완료/응답)" + echo "4. API 삭제" + echo "5. API 공급업체에서 권장하는 사항" + echo "0. 종료" echo "---------------------------------------" - read -erp "请输入你的选择: " api_choice + read -erp "선택사항을 입력하세요:" api_choice case "$api_choice" in 1) @@ -11443,11 +11510,14 @@ PY 4) delete-openclaw-provider-interactive ;; + 5) + openclaw_api_providers_showcase + ;; 0) return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -11460,7 +11530,8 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - if [ -f /etc/debian_version ]; then + + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null @@ -11489,7 +11560,7 @@ REPO change_model() { - send_stats "换模型" + send_stats "모델 변경" local orange="#FF8C00" @@ -11498,7 +11569,7 @@ REPO local status_color_ok='' local status_color_fail='' local status_color_reset='' - if [ "$status_text" = "可用" ]; then + if [ "$status_text" = "사용 가능" ]; then printf "%b最小检测结果:%s%b " "$status_color_ok" "$status_text" "$status_color_reset" else @@ -11516,11 +11587,10 @@ REPO local first_exit first_http first_latency second_exit second_http second_latency local first_reply second_reply - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) [ ! -f "$oc_config" ] && { OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" + OPENCLAW_PROBE_MESSAGE="openclaw 구성 파일을 찾을 수 없습니다" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 @@ -11532,7 +11602,7 @@ REPO api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" + OPENCLAW_PROBE_MESSAGE="공급자/baseUrl/apiKey를 읽을 수 없습니다." OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 @@ -11658,7 +11728,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11676,11 +11746,11 @@ PYTHON_EOF second_reply="$reply_preview" reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" - OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0},切换 ${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_MESSAGE="${first_endpoint}-> HTTP ${first_http:-0}, 스위치${second_endpoint} -> HTTP ${second_http}" OPENCLAW_PROBE_LATENCY="${second_latency}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 0 @@ -11688,7 +11758,7 @@ PYTHON_EOF reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" OPENCLAW_PROBE_STATUS="FAIL" OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" @@ -11702,76 +11772,77 @@ PYTHON_EOF while true; do local models_raw models_list default_model model_count selected_model confirm_switch - # 从配置文件读取模型键(不调用 openclaw models list) + # 구성 파일에서 모델 키 읽기(openclaw 모델 목록을 호출하지 않고) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" + echo "모델 목록을 가져오지 못했습니다. 구성 파일에서 Agent.defaults.models를 찾을 수 없습니다." break_end return 1 fi - # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") + # 빠른 찾기를 위해 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # 从配置文件读取默认模型(更快);失败再回退到 openclaw 命令 + # 구성 파일에서 기본 모델을 읽습니다(더 빠름). 실패 시 openclaw 명령으로 대체 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" clear - # 若 gum 不存在,降级为原始手动输入流程 + install_gum + install gum + + # 껌이 존재하지 않을 경우 기존의 수동 입력 과정으로 다운그레이드됩니다. if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "--- 模型管理 ---" - echo "当前可用模型:" + echo "---모델 관리 ---" + echo "현재 사용 가능한 모델:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." selected_model if [ "$selected_model" = "0" ]; then - echo "操作已取消,正在退出..." + echo "작업이 취소되었습니다. 종료하는 중..." break fi if [ -z "$selected_model" ]; then - echo "错误:模型名称不能为空。请重试。" + echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." echo "" continue fi - echo "正在切换模型为: $selected_model ..." + echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "切换失败:openclaw models set 返回错误。" + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end return 0 else - install_gum - install gum if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 不可用,返回旧版输入模式。" + echo "껌을 사용할 수 없습니다. 이전 입력 모드로 돌아갑니다." sleep 1 continue fi - gum style --foreground "$orange" --bold "模型管理" - gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" - gum style --foreground "$orange" "当前默认:${default_model}" + gum style --foreground "$orange" --bold "모델 관리" + gum style --foreground "$orange" "사용 가능한 모델(인증=예):${model_count}" + gum style --foreground "$orange" "현재 기본값:${default_model}" echo "" - gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" + gum style --faint "↑↓ 테스트하려면 선택 / Enter / 종료하려면 Esc" echo "" - selected_model=$(echo "$models_list" | gum filter --placeholder "搜索模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "검색 모델(예: cli-api/gpt-5.2)" --prompt "모델 선택 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then - echo "操作已取消,正在退出..." + echo "작업이 취소되었습니다. 종료하는 중..." break fi fi @@ -11779,18 +11850,18 @@ PYTHON_EOF selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') echo "" - echo "正在检测模型: $selected_model" + echo "모델 감지:$selected_model" if openclaw_model_probe "$selected_model"; then - openclaw_probe_status_line "可用" + openclaw_probe_status_line "사용 가능" else - openclaw_probe_status_line "不可用" + openclaw_probe_status_line "사용할 수 없음" fi - echo "状态:$OPENCLAW_PROBE_MESSAGE" - echo "延迟:$OPENCLAW_PROBE_LATENCY" - echo "摘要:$OPENCLAW_PROBE_REPLY" + echo "상태:$OPENCLAW_PROBE_MESSAGE" + echo "지연:$OPENCLAW_PROBE_LATENCY" + echo "요약:$OPENCLAW_PROBE_REPLY" echo "" - printf "是否切换到该模型?[y/N,Esc 返回列表]: " + printf "이 모델로 전환하시겠습니까? [y/N, Esc가 목록으로 돌아갑니다]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -11807,17 +11878,18 @@ PYTHON_EOF fi if [ "$confirm_switch" != "yes" ]; then - echo "已返回模型选择列表。" + echo "모델 선택 목록이 반환되었습니다." sleep 1 continue fi - echo "正在切换模型为: $selected_model ..." + echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "切换失败:openclaw models set 返回错误。" + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end @@ -11825,6 +11897,76 @@ PYTHON_EOF } + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ 동기화됨$count에이전트의 세션 모델은 다음과 같습니다.$model_ref" + return 0 + } + resolve_openclaw_plugin_id() { local raw_input="$1" local plugin_id="$raw_input" @@ -11841,12 +11983,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11861,7 +11999,7 @@ PYTHON_EOF | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) | if (.plugins.allow | index($pid)) == null then .plugins.allow += [$pid] else . end ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then - echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" return 0 fi rm -f "$tmp_json" @@ -11899,12 +12037,12 @@ data['plugins'] = plugins config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') PYTHON_EOF then - echo "✅ 已同步 plugins.allow 白名单: $plugin_id" + echo "✅ 동기화된 플러그인.허용 목록:$plugin_id" return 0 fi fi - echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -11912,12 +12050,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11932,7 +12066,7 @@ PYTHON_EOF | .plugins.allow = (if (.plugins.allow | type) == "array" then .plugins.allow else [] end) | .plugins.allow = (.plugins.allow | map(select(. != $pid))) ' "$config_file" > "$tmp_json" 2>/dev/null && mv "$tmp_json" "$config_file"; then - echo "✅ 已从 plugins.allow 移除: $plugin_id" + echo "✅plugins.allow에서 제거됨:$plugin_id" return 0 fi rm -f "$tmp_json" @@ -11968,12 +12102,12 @@ data['plugins'] = plugins config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') PYTHON_EOF then - echo "✅ 已从 plugins.allow 移除: $plugin_id" + echo "✅plugins.allow에서 제거됨:$plugin_id" return 0 fi fi - echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" + echo "⚠️plugins.allow 제거에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -11983,45 +12117,45 @@ PYTHON_EOF install_plugin() { - send_stats "插件管理" + send_stats "플러그인 관리" while true; do clear echo "========================================" - echo " 插件管理 (安装/删除) " + echo "플러그인 관리(설치/제거)" echo "========================================" - echo "当前插件列表:" + echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "推荐的常用插件 ID (直接复制括号内的 ID 即可):" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" echo "--------------------------------------------------------" - echo "📱 通讯渠道:" - echo " - [feishu] # 飞书/Lark 集成" - echo " - [telegram] # Telegram 机器人" - echo " - [slack] # Slack 企业通讯" + echo "📱 커뮤니케이션 채널:" + echo "- [feishu] # 페이슈/종달새 통합" + echo "- [텔레그램] # 텔레그램 봇" + echo "- [slack] #Slack 기업 커뮤니케이션" echo " - [msteams] # Microsoft Teams" - echo " - [discord] # Discord 社区管理" - echo " - [whatsapp] # WhatsApp 自动化" + echo "- [디스코드] # 디스코드 커뮤니티 관리" + echo "- [whatsapp] #WhatsApp 자동화" echo "" - echo "🧠 记忆与 AI:" - echo " - [memory-core] # 基础记忆 (文件检索)" - echo " - [memory-lancedb] # 增强记忆 (向量数据库)" - echo " - [copilot-proxy] # Copilot 接口转发" + echo "🧠 메모리와 AI:" + echo "- [memory-core] # 기본 메모리(파일 검색)" + echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" + echo "- [copilot-proxy] # Copilot 인터페이스 전달" echo "" - echo "⚙️ 功能扩展:" - echo " - [lobster] # 审批流 (带人工确认)" - echo " - [voice-call] # 语音通话能力" - echo " - [nostr] # 加密隐私聊天" + echo "⚙️ 기능 확장:" + echo "- [랍스터] # 승인 흐름(수동 확인 포함)" + echo "- [음성통화] # 음성통화 기능" + echo "- [nostr] # 암호화된 비공개 채팅" echo "--------------------------------------------------------" - echo "1) 安装/启用插件" - echo "2) 删除/禁用插件" - echo "0) 返回" - read -e -p "请选择操作:" plugin_action + echo "1) 플러그인 설치/활성화" + echo "2) 플러그인 삭제/비활성화" + echo "0) 반품" + read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue - read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input + read -e -p "플러그인 ID를 입력하십시오(공백으로 구분, 종료하려면 0 입력)." raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue @@ -12039,12 +12173,12 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 正在检查插件状态: $plugin_id" + echo "🔍 플러그인 상태 확인:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已预装,正在激活..." + echo "💡 플러그인 [$plugin_id] 사전 설치되어 활성화 중..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12056,7 +12190,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12067,11 +12201,11 @@ PYTHON_EOF continue fi - echo "📥 本地未发现,尝试下载安装: $plugin_full" + echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요.$plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ 下载成功,正在启用..." + echo "✅ 다운로드 성공, 활성화 중..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12080,16 +12214,16 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 安装失败:$plugin_full" + echo "❌ 설치 실패:$plugin_full" failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在删除/禁用插件: $plugin_id" + echo "🗑️ 플러그인 제거/비활성화:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then - echo "✅ 已卸载: $plugin_id" + echo "✅ 제거됨:$plugin_id" else - echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" + echo "⚠️ 제거에 실패했습니다. 사전 설치된 플러그인일 수 있습니다. 다음만 비활성화하세요.$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12098,13 +12232,13 @@ PYTHON_EOF done echo "" - echo "====== 操作汇总 ======" - echo "✅ 成功:$success_list" - [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" + echo "====== 작업 요약 ======" + echo "✅ 성공:$success_list" + [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重启 OpenClaw 服务以加载变更..." + echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." start_gateway fi break_end @@ -12113,43 +12247,43 @@ PYTHON_EOF install_skill() { - send_stats "技能管理" + send_stats "스킬 관리" while true; do clear echo "========================================" - echo " 技能管理 (安装/删除) " + echo "스킬 관리(설치/제거)" echo "========================================" - echo "当前已安装技能:" + echo "현재 설치된 스킬:" openclaw skills list echo "----------------------------------------" - # 输出推荐的实用技能列表 - echo "推荐的实用技能(可直接复制名称输入):" - echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 页面、数据库和块" - echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" - echo "apple-reminders # macOS 提醒事项管理 (待办清单)" - echo "1password # 自动化读取和注入 1Password 密钥" - echo "gog # Google Workspace (Gmail/云盘/文档) 全能助手" - echo "things-mac # 深度整合 Things 3 任务管理" - echo "bluebubbles # 通过 BlueBubbles 完美收发 iMessage" - echo "himalaya # 终端邮件管理 (IMAP/SMTP 强力工具)" - echo "summarize # 网页/播客/YouTube 视频内容一键总结" - echo "openhue # 控制 Philips Hue 智能灯光场景" - echo "video-frames # 视频抽帧与短片剪辑 (ffmpeg 驱动)" - echo "openai-whisper # 本地音频转文字 (离线隐私保护)" - echo "coding-agent # 自动运行 Claude Code/Codex 等编程助手" + # 추천 실기 목록 출력 + echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" + echo "github # GitHub 문제/PR/CI 관리(gh CLI)" + echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." + echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" + echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" + echo "1password # 1Password 키 읽기 및 삽입 자동화" + echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" + echo "things-mac # Things 3 작업 관리의 심층 통합" + echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." + echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" + echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" + echo "openhue # Philips Hue 스마트 조명 장면 제어" + echo "video-frames # 비디오 프레임 추출 및 짧은 클립 편집(ffmpeg 드라이버)" + echo "openai-whisper # 로컬 오디오를 텍스트로 변환(오프라인 개인 정보 보호)" + echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." echo "----------------------------------------" - echo "1) 安装技能" - echo "2) 删除技能" - echo "0) 返回" - read -e -p "请选择操作:" skill_action + echo "1) 설치 기술" + echo "2) 스킬 삭제" + echo "0) 반품" + read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break [ -z "$skill_action" ] && continue - read -e -p "请输入技能名称(空格分隔,输入 0 退出): " skill_input + read -e -p "스킬 이름을 입력하십시오(공백으로 구분, 종료하려면 0 입력):" skill_input [ "$skill_input" = "0" ] && break [ -z "$skill_input" ] && continue @@ -12160,9 +12294,9 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续?(y/N): " confirm_del + read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. 계속하시겠습니까? (예/아니요):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then - echo "已取消删除。" + echo "삭제가 취소되었습니다." break_end continue fi @@ -12176,53 +12310,53 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在用户目录安装。" + echo "💡 스킬 [$skill_name]는 사용자 디렉토리에 설치됩니다." skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系统目录安装。" + echo "💡 스킬 [$skill_name]는 시스템 디렉토리에 설치됩니다." skill_found=true fi if [ "$skill_found" = true ]; then - read -e -p "技能 [$skill_name] 已安装,是否重新安装?(y/N): " reinstall + read -e -p "스킬 [$skill_name] 이미 설치되어 있습니다. 다시 설치하시겠습니까? (예/아니요):" reinstall if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then skipped_list="$skipped_list $skill_name" continue fi fi - echo "正在安装技能:$skill_name ..." + echo "기술 설치:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then - echo "✅ 技能 $skill_name 安装成功。" + echo "✅ 스킬$skill_name설치가 성공했습니다." success_list="$success_list $skill_name" changed=true else - echo "❌ 安装失败:$skill_name" + echo "❌ 설치 실패:$skill_name" failed_list="$failed_list $skill_name" fi else - echo "🗑️ 正在删除技能: $skill_name" + echo "🗑️ 스킬 삭제:$skill_name" npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" - echo "✅ 已删除用户技能目录: $skill_name" + echo "✅ 사용자 스킬 디렉토리가 삭제되었습니다:$skill_name" success_list="$success_list $skill_name" changed=true else - echo "⏭️ 未发现用户技能目录: $skill_name" + echo "⏭️ 사용자 스킬 디렉터리를 찾을 수 없습니다:$skill_name" skipped_list="$skipped_list $skill_name" fi fi done echo "" - echo "====== 操作汇总 ======" - echo "✅ 成功:$success_list" - [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" + echo "====== 작업 요약 ======" + echo "✅ 성공:$success_list" + [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" + [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重启 OpenClaw 服务以加载变更..." + echo "🔄 변경 사항을 로드하기 위해 OpenClaw 서비스를 다시 시작하는 중..." start_gateway fi break_end @@ -12231,7 +12365,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12241,7 +12376,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12268,15 +12404,16 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi - # 兼容两种常见目录命名: + # 두 가지 일반적인 디렉터리 이름과 호환됩니다. # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 + # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12289,15 +12426,15 @@ openclaw_json_get_bool() { local connected="$3" local abnormal="$4" if [ "$abnormal" = "true" ]; then - echo "异常" + echo "이상" elif [ "$enabled" != "true" ]; then - echo "未启用" + echo "활성화되지 않음" elif [ "$connected" = "true" ]; then - echo "已连接" + echo "연결됨" elif [ "$configured" = "true" ]; then - echo "已配置" + echo "구성된" else - echo "未配置" + echo "구성되지 않음" fi } @@ -12318,7 +12455,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12439,40 +12577,40 @@ openclaw_json_get_bool() { fi wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") - echo "本地状态(仅本机配置/缓存,不做网络探测):" + echo "로컬 상태(로컬 구성/캐시만, 네트워크 감지 없음):" openclaw_print_bot_status_line "Telegram" "$tg_status" - openclaw_print_bot_status_line "飞书(Lark)" "$feishu_status" + openclaw_print_bot_status_line "종달새" "$feishu_status" openclaw_print_bot_status_line "WhatsApp" "$wa_status" openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" - openclaw_print_bot_status_line "微信 (Weixin)" "$wx_status" + openclaw_print_bot_status_line "위챗(웨이신)" "$wx_status" } change_tg_bot_code() { - send_stats "机器人对接" + send_stats "로봇 도킹" while true; do clear echo "========================================" - echo " 机器人连接对接 " + echo "로봇 연결 및 도킹" echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" - echo "1. Telegram 机器人对接" - echo "2. 飞书 (Lark) 机器人对接" - echo "3. WhatsApp 机器人对接" - echo "4. QQ 机器人对接" - echo "5. 微信机器人对接" + echo "1. 텔레그램 로봇 도킹" + echo "2. Feishu(Lark) 로봇 도킹" + echo "3. WhatsApp 봇 도킹" + echo "4. QQ 로봇 도킹" + echo "5. 위챗 로봇 도킹" echo "----------------------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "----------------------------------------" - read -e -p "请输入你的选择: " bot_choice + read -e -p "선택사항을 입력하세요:" bot_choice case $bot_choice in 1) - read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve telegram "$code" break_end ;; @@ -12483,14 +12621,14 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "请输入WhatsApp收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" break_end ;; 4) - echo "QQ 官方对接地址:" + echo "QQ 공식 도킹 주소:" echo "https://q.qq.com/qqbot/openclaw/login.html" break_end ;; @@ -12502,7 +12640,7 @@ openclaw_json_get_bool() { return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -12600,10 +12738,10 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "可使用以下方式下载备份文件:" - echo "- 本地路径: $file_path" - echo "- scp 示例: scp root@你的服务器:$file_path ./" - echo "- 或使用 SFTP 客户端下载" + echo "백업 파일은 다음 방법을 사용하여 다운로드할 수 있습니다." + echo "- 로컬 경로:$file_path" + echo "- scp 예: scp root@yourserver:$file_path ./" + echo "- 또는 SFTP 클라이언트를 사용하여 다운로드" } openclaw_prepare_import_archive() { @@ -12611,9 +12749,9 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 파일이 존재하지 않습니다:$archive_path"; return 1; } mkdir -p "$unpack_root" - tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 备份包解压失败"; return 1; } + tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 백업 패키지의 압축을 풀지 못했습니다."; return 1; } local pkg_dir="$unpack_root/package" if [ -f "$unpack_root/backup.meta" ]; then @@ -12621,161 +12759,118 @@ EOF fi for required in backup.meta manifest.files manifest.sha256 payload; do - [ -e "$pkg_dir/$required" ] || { echo "❌ 备份包缺少必要文件: $required"; return 1; } + [ -e "$pkg_dir/$required" ] || { echo "❌ 백업 패키지에 필요한 파일이 없습니다:$required"; return 1; } done local real_type real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) if [ "$real_type" != "$expected_type" ]; then - echo "❌ 备份类型不匹配,期望: $expected_type,实际: ${real_type:-未知}" + echo "❌ 백업 유형 불일치 예상:$expected_type, 실제: ${real_type:-unknown}" return 1 fi ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } + ) || { echo "❌ sha256 확인이 실패하고 복원이 거부되었습니다."; return 1; } echo "$pkg_dir" return 0 } - openclaw_memory_backup_export() { - send_stats "OpenClaw记忆全量备份" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) - local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ 未找到 workspace 目录: $workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "是否附带 AGENTS/USER/SOUL/TOOLS 文件?(y/N): " include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - - if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可备份的记忆文件" - rm -rf "$tmp_payload" - break_end - return 1 - fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 记忆全量备份完成: $out_file" - openclaw_offer_transfer_hint "$out_file" + openclaw_get_all_agent_workspaces() { + local config_file + config_file=$(openclaw_get_config_file) + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY else - echo "❌ 记忆全量备份失败" + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' fi - - rm -rf "$tmp_payload" - break_end } - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "可先通过 scp/sftp 上传备份包到服务器,再输入路径。" >&2 - echo "scp 示例: scp /本地/备份包.tar.gz root@你的服务器:/tmp/" >&2 - echo "提示:输入文件名时默认在备份目录查找;输入含 / 的路径时按完整路径校验。" >&2 - read -e -p "请输入备份文件名或路径: " file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) + openclaw_memory_backup_export() { + send_stats "OpenClaw 메모리 전체 백업" + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) + local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" + if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then + echo "❌ 백업 메모리 파일이 없습니다."; rm -rf "$tmp_payload"; break_end; return 1 fi - - if [ ! -f "$file_path" ]; then - echo "❌ 备份文件不存在: $file_path" >&2 - echo "" - return 1 + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ 전체 메모리 백업 완료(멀티 에이전트 포함):$out_file"; openclaw_offer_transfer_hint "$out_file" + else + echo "❌ 전체 메모리 백업 실패" fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { - send_stats "OpenClaw记忆全量还原" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "还原前将执行:类型校验 + sha256 校验 + 路径白名单校验") - [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 检测到非法或越权路径: $rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ 还原中止:存在不安全路径" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ 记忆全量还原完成" - break_end + send_stats "OpenClaw 메모리 전체 복원" + local archive_path=$(openclaw_read_import_path "전체 메모리 양 복원(멀티 에이전트 지원)") + [ -z "$archive_path" ] && { echo "❌ 입력된 경로가 없습니다."; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end } + openclaw_project_backup_export() { - send_stats "OpenClaw项目备份" - local openclaw_root="${HOME}/.openclaw" + send_stats "OpenClaw 프로젝트 백업" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then - echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" + echo "❌ OpenClaw 루트 디렉터리를 찾을 수 없습니다:$openclaw_root" break_end return 1 fi - echo "备份模式:" - echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" - echo "2. 完整模式(含更多状态,敏感风险更高)" - read -e -p "请选择备份模式(默认 1): " export_mode + echo "백업 모드:" + echo "1. 안전 모드(기본값, 권장): 작업 공간 + openclaw.json + 확장/기술/프롬프트/도구(존재하는 경우)" + echo "2. 전체 모드(더 많은 상태 포함, 더 높은 민감도 위험)" + read -e -p "백업 모드를 선택하십시오(기본값 1):" export_mode [ -z "$export_mode" ] && export_mode="1" local mode_label="safe" @@ -12800,7 +12895,7 @@ EOF fi if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可备份的 OpenClaw 项目内容" + echo "❌ 백업 가능한 OpenClaw 프로젝트 콘텐츠가 없습니다." rm -rf "$tmp_payload" break_end return 1 @@ -12812,10 +12907,10 @@ EOF local out_file="$backup_root/openclaw-project-${mode_label}-$(date +%Y%m%d-%H%M%S).tar.gz" if openclaw_pack_backup_archive "openclaw-project" "$mode_label" "$tmp_payload" "$out_file"; then - echo "✅ OpenClaw 项目备份完成 (${mode_label}): $out_file" + echo "✅ OpenClaw 프로젝트 백업 완료 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 项目备份失败" + echo "❌ OpenClaw 프로젝트 백업 실패" fi rm -rf "$tmp_payload" @@ -12823,22 +12918,25 @@ EOF } openclaw_project_backup_import() { - send_stats "OpenClaw项目还原" - local openclaw_root="${HOME}/.openclaw" + send_stats "OpenClaw 프로젝트 복원" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" - echo "⚠️ 高风险操作:项目还原会覆盖 OpenClaw 配置与工作区内容。" - echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" - read -e -p "请输入确认词【我已知晓高风险并继续还原】后继续: " confirm_text - if [ "$confirm_text" != "我已知晓高风险并继续还原" ]; then - echo "❌ 确认词不匹配,已取消还原" + echo "⚠️ 고위험 작업: 프로젝트 복원은 OpenClaw 구성 및 작업 공간 콘텐츠를 덮어씁니다." + echo "⚠️ 복원 전 매니페스트/sha256 확인, 화이트리스트 복원, 게이트웨이 종료 및 상태 점검이 수행됩니다." + read -e -p "계속하려면 확인 단어 [위험도가 높다는 것을 알고 있으며 복원을 계속합니다]를 입력하십시오." confirm_text + if [ "$confirm_text" != "위험성이 높다는 것을 인지하고 복원을 계속하고 있습니다." ]; then + echo "❌ 확인문자가 일치하지 않아 복원이 취소되었습니다." break_end return 1 fi local archive_path - archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") - [ -z "$archive_path" ] && { echo "❌ 未输入备份路径"; break_end; return 1; } + archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요") + [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } local tmp_unpack tmp_unpack=$(mktemp -d) || return 1 @@ -12851,7 +12949,7 @@ EOF while IFS= read -r rel; do [ -z "$rel" ] && continue if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then - echo "❌ 检测到非法或越权路径: $rel" + echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" invalid=1 break fi @@ -12861,14 +12959,14 @@ EOF if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 还原中止:存在不安全路径" + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi if command -v openclaw >/dev/null 2>&1; then - echo "⏸️ 还原前停止 OpenClaw gateway..." + echo "⏸️ 복원하기 전에 OpenClaw 게이트웨이를 중지하세요..." openclaw gateway stop >/dev/null 2>&1 fi @@ -12878,27 +12976,27 @@ EOF done < "$valid_list" if command -v openclaw >/dev/null 2>&1; then - echo "▶️ 还原后启动 OpenClaw gateway..." + echo "▶️ 복원 후 OpenClaw 게이트웨이를 시작하세요..." openclaw gateway start >/dev/null 2>&1 sleep 2 - echo "🩺 gateway 健康检查:" + echo "🩺 게이트웨이 상태 점검:" openclaw gateway status || true fi rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw 项目还原完成" + echo "✅ OpenClaw 프로젝트 복원 완료" break_end } openclaw_backup_detect_type() { local file_name="$1" if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then - echo "记忆备份文件" + echo "메모리 백업 파일" elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then - echo "项目备份文件" + echo "프로젝트 백업 파일" else - echo "其他备份文件" + echo "기타 백업 파일" fi } @@ -12916,27 +13014,27 @@ EOF backup_root=$(openclaw_backup_root) openclaw_backup_collect_files - echo "备份目录: $backup_root" + echo "백업 디렉터리:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "暂无备份文件" + echo "아직 백업 파일이 없습니다." return 0 fi for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_type=$(openclaw_backup_detect_type "${OPENCLAW_BACKUP_FILES[$i]}") case "$file_type" in - "记忆备份文件") has_memory=1 ;; - "项目备份文件") has_project=1 ;; - "其他备份文件") has_other=1 ;; + "메모리 백업 파일") has_memory=1 ;; + "프로젝트 백업 파일") has_project=1 ;; + "기타 백업 파일") has_other=1 ;; esac done if [ "$has_memory" -eq 1 ]; then - echo "记忆备份文件" + echo "메모리 백업 파일" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "记忆备份文件" ] && continue + [ "$file_type" != "메모리 백업 파일" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12945,11 +13043,11 @@ EOF fi if [ "$has_project" -eq 1 ]; then - echo "项目备份文件" + echo "프로젝트 백업 파일" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "项目备份文件" ] && continue + [ "$file_type" != "프로젝트 백업 파일" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12958,11 +13056,11 @@ EOF fi if [ "$has_other" -eq 1 ]; then - echo "其他备份文件" + echo "기타 백업 파일" for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "其他备份文件" ] && continue + [ "$file_type" != "기타 백업 파일" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -12981,7 +13079,7 @@ EOF } openclaw_backup_delete_file() { - send_stats "OpenClaw删除备份文件" + send_stats "OpenClaw 삭제 백업 파일" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -12991,14 +13089,14 @@ EOF return 0 fi - read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input + read -e -p "삭제할 파일 이름이나 전체 경로를 입력하십시오. (취소하려면 0):" user_input if [ "$user_input" = "0" ]; then - echo "已取消删除。" + echo "삭제가 취소되었습니다." break_end return 0 fi if [ -z "$user_input" ]; then - echo "❌ 输入不能为空。" + echo "❌ 입력은 비워둘 수 없습니다." break_end return 1 fi @@ -13009,7 +13107,7 @@ EOF case "$target_path" in "$backup_root_real"/*) ;; *) - echo "❌ 路径越界:仅允许删除备份根目录内的文件。" + echo "❌ 경로 초과: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." break_end return 1 ;; @@ -13021,37 +13119,37 @@ EOF fi if [ ! -f "$target_path" ]; then - echo "❌ 目标文件不存在: $target_path" + echo "❌ 대상 파일이 존재하지 않습니다:$target_path" break_end return 1 fi if ! openclaw_backup_file_exists_in_list "$target_file"; then - echo "❌ 目标文件不在当前备份列表中。" + echo "❌ 현재 백업 목록에 대상 파일이 없습니다." break_end return 1 fi target_type=$(openclaw_backup_detect_type "$target_file") - echo "即将删除: [$target_type] $target_path" - read -e -p "第一次确认:输入 yes 确认继续: " confirm_step1 + echo "삭제 예정: [$target_type] $target_path" + read -e -p "첫 번째 확인: 확인하고 계속하려면 yes를 입력하세요." confirm_step1 if [ "$confirm_step1" != "yes" ]; then - echo "已取消删除。" + echo "삭제가 취소되었습니다." break_end return 0 fi - read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 + read -e -p "보조 확인: 삭제하려면 DELETE를 입력하세요." confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then - echo "已取消删除。" + echo "삭제가 취소되었습니다." break_end return 0 fi if rm -f -- "$target_path"; then - echo "✅ 删除成功: $target_file" + echo "✅ 삭제 성공:$target_file" else - echo "❌ 删除失败: $target_file" + echo "❌ 삭제 실패:$target_file" fi break_end } @@ -13062,7 +13160,15 @@ EOF } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -13092,9 +13198,78 @@ EOF openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - "$agents_json" <<'PY' +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -13111,58 +13286,107 @@ EOF fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ 未找到索引库文件,可能为空或不存在。" - echo " Store 原始值: ${store_raw:-<空>}" - echo " 仍将执行重建索引。" + echo "⚠️ [$agent_id] 인덱스 라이브러리 파일을 찾을 수 없습니다. 비어 있거나 존재하지 않을 수 있습니다." + echo "원시 값 저장: ${store_raw:-}" + echo "재인덱싱은 계속 수행됩니다." else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ 已备份索引: $backup_file" + echo "✅ [$agent_id] 백업된 인덱스:$backup_file" else - echo "⚠️ 索引备份失败,继续重建。" + echo "⚠️ [$agent_id] 인덱스 백업이 실패했습니다. 재구축을 계속하세요." fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" + openclaw gateway restart + echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "" + openclaw_memory_render_status + } + + openclaw_memory_rebuild_index_all() { + local count=0 + local agent_lines agent_id workspace + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done </dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /') + local agent_lines agent_id workspace status_output status_lines first="true" + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "상태를 가져오지 못했습니다." + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^공급자: /기본 솔루션: /' -e 's/^벡터: /벡터 라이브러리 상태: /' -e 's/^색인: /포함된 파일: /' -e 's/^작업 공간: /작업 공간: /' -e 's/^저장소: /색인 라이브러리: /') if [ -z "$status_lines" ]; then - echo "未安装/未启动" + echo "설치되지 않음/시작되지 않음" else echo "$status_lines" fi - fi + done </dev/null 2>&1; then - echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" + echo "⚠️ sqlite3이 감지되지 않으면 QMD가 제대로 작동하지 않을 수 있습니다." return 1 fi local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') - echo "✅ sqlite3 可用: ${ver:-unknown}" - echo "ℹ️ sqlite 扩展支持无法可靠检测,将继续。" + echo "✅ sqlite3 사용 가능: ${ver:-unknown}" + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." return 0 } @@ -13354,26 +13578,26 @@ EOF export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 已存在" + echo "✅ 롤빵이 이미 존재합니다" return 0 fi - echo "⬇️ 安装 bun..." + echo "⬇️ 번 설치..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 未检测到 curl 或 wget,无法安装 bun。" + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 安装完成" + echo "✅ 번 설치 완료" return 0 fi - echo "❌ bun 安装失败" + echo "❌ 번 설치 실패" return 1 } @@ -13381,57 +13605,60 @@ EOF local qmd_path qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd 已存在: $qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd가 이미 존재하며 사용 가능합니다:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ qmd 명령이 존재하지만 모듈이 손상되었습니다. 다시 설치하세요..." + fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ 通过 bun 安装 qmd: $qmd_url" - bun install -g "$qmd_url" + echo "⬇️ npm을 통해 qmd 설치: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then - echo "❌ qmd 安装失败" + echo "❌ qmd 설치 실패" + return 1 + fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ 설치 후에도 qmd를 실행할 수 없습니다." return 1 fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - echo "✅ qmd 安装完成: $qmd_path" + echo "✅ qmd 설치 완료:$qmd_path" return 0 } openclaw_memory_render_auto_summary() { echo "---------------------------------------" - echo "✅ 环境就绪" - echo "方案: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" + echo "✅ 환경 준비" + echo "구성표: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "模式: 仅写配置(未安装/未下载)" + echo "모드: 쓰기 구성만(설치되지 않음/다운로드되지 않음)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "索引: 已执行" + echo "색인: 실행됨" else - echo "索引: 已跳过" + echo "색인: 건너뛰었습니다." fi if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then - echo "重启: 已执行" + echo "다시 시작: 실행됨" else - echo "重启: 已跳过" + echo "다시 시작: 건너뛰었습니다." fi if [ -n "$OPENCLAW_MEMORY_QMD_PATH" ]; then echo "qmd: $OPENCLAW_MEMORY_QMD_PATH" fi if [ -n "$OPENCLAW_MEMORY_MODEL_PATH" ]; then - echo "模型: $OPENCLAW_MEMORY_MODEL_PATH" + echo "모델:$OPENCLAW_MEMORY_MODEL_PATH" fi if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then - echo "地区: $OPENCLAW_MEMORY_COUNTRY" + echo "영역:$OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then - echo "下载源: $OPENCLAW_MEMORY_HF_BASE" + echo "다운로드 소스:$OPENCLAW_MEMORY_HF_BASE" fi - echo "最终状态:" + echo "최종 상태:" openclaw_memory_render_status echo "---------------------------------------" } @@ -13441,22 +13668,22 @@ EOF OPENCLAW_MEMORY_PREHEAT="true" OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" - echo "即将执行自动部署(详细模式)" - echo "目标方案: $scheme_label" - echo "地区: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" - echo "下载源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" + echo "자동 배포가 곧 수행됩니다(상세 모드)." + echo "목표 계획:$scheme_label" + echo "지역: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" + echo "미러 소스 감지:huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "다운로드 소스: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then - echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" + echo "예상 다운로드 경로:$OPENCLAW_MEMORY_EXPECT_PATH" fi if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then - echo "可能流量/磁盘占用: $OPENCLAW_MEMORY_EXPECT_SIZE" + echo "가능한 트래픽/디스크 사용량:$OPENCLAW_MEMORY_EXPECT_SIZE" else - echo "可能流量/磁盘占用: 视实际情况而定" + echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" - echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" - read -e -p "输入 yes 确认继续(默认 N): " confirm_step + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." + read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in yes|YES) OPENCLAW_MEMORY_PREHEAT="true" @@ -13466,20 +13693,20 @@ EOF OPENCLAW_MEMORY_PREHEAT="false" ;; *) - echo "已取消自动部署。" + echo "자동 배포가 취소되었습니다." return 1 ;; esac if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "⚠️ 已选择仅写配置,不安装不下载" + echo "⚠️ 설치나 다운로드 없이 구성만 작성하도록 선택됨" else - echo "✅ 将自动构建索引并重启网关" + echo "✅ 인덱스가 자동으로 구축되고 게이트웨이가 다시 시작됩니다." fi return 0 } openclaw_memory_auto_setup_qmd() { - echo "🔍 检测 QMD 环境" + echo "🔍 QMD 환경 감지" openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then @@ -13494,46 +13721,53 @@ EOF local backend backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ]; then - echo "✅ memory.backend 已是 qmd" + echo "✅ memory.backend는 이미 qmd입니다." else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ 已设置 memory.backend=qmd" + echo "✅ memory.backend=qmd가 설정되었습니다" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") if [ -z "$qmd_cmd" ] || [[ "$qmd_cmd" != /* ]] || [ "$qmd_cmd" != "$OPENCLAW_MEMORY_QMD_PATH" ]; then openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" - echo "✅ 已写入 memory.qmd.command: $OPENCLAW_MEMORY_QMD_PATH" + echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正确" + echo "✅ memory.qmd.command가 정확합니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 预热索引(可能下载模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + echo "🔥 따뜻한 지수(모델 다운로드 가능)" + openclaw_memory_prepare_workspace_all + local preh_agent_lines preh_agent_id preh_workspace + preh_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r preh_agent_id preh_workspace; do + [ -z "$preh_agent_id" ] && continue + openclaw memory index --agent "$preh_agent_id" --force + done </dev/null 2>&1; then start_gateway else @@ -13630,14 +13871,14 @@ EOF while true; do clear echo "=======================================" - echo "记忆方案自动部署" + echo "메모리 솔루션 자동 배포" echo "=======================================" echo "1. QMD" echo "2. Local" - echo "3. Auto(自动选择)" - echo "0. 返回上一级" + echo "3. 자동(자동 선택)" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " auto_choice + read -e -p "선택사항을 입력하세요:" auto_choice case "$auto_choice" in 1) openclaw_memory_auto_setup_run "qmd" @@ -13655,7 +13896,7 @@ EOF return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -13669,7 +13910,7 @@ EOF qmd) openclaw_memory_config_set "memory.backend" "qmd" if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" + echo "❌ 구성을 쓰지 못했습니다." return 1 fi openclaw_memory_config_set "memory.qmd.command" "qmd" >/dev/null 2>&1 @@ -13677,24 +13918,24 @@ EOF local) openclaw_memory_config_set "memory.backend" "builtin" if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" + echo "❌ 구성을 쓰지 못했습니다." return 1 fi openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 未知方案: $scheme" + echo "❌ 알 수 없는 해결책:$scheme" return 1 esac - echo "✅ 已更新记忆方案配置" + echo "✅ 메모리 체계 구성이 업데이트되었습니다." return 0 } openclaw_memory_offer_restart() { - echo "配置已写入,需要重启 OpenClaw 网关后生效。" - read -e -p "是否立即重启 OpenClaw 网关?(Y/n): " restart_choice + echo "구성이 작성되었으며 OpenClaw 게이트웨이를 다시 시작한 후 적용하려면 다시 시작해야 합니다." + read -e -p "지금 OpenClaw Gateway를 다시 시작하시겠습니까? (예/아니요):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then - echo "已跳过重启,可稍后执行: openclaw gateway restart" + echo "다시 시작을 건너뛰었습니다. 나중에 수행할 수 있습니다. openclaw 게이트웨이 다시 시작" return 0 fi if declare -F start_gateway >/dev/null 2>&1; then @@ -13705,32 +13946,46 @@ EOF } openclaw_memory_fix_index() { - local backend + local backend include_dm backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then - echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" - echo " 可切换 Local,或安装 bun + qmd 后再试。" - fi - echo "适用场景:Indexed 分子 > 分母(重复 collection 导致计数异常)" - read -e -p "确认将 includeDefaultMemory 设为 false?(y/N): " confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "已取消。" - break_end - return 0 + echo "⚠️ 현재 구성표는 QMD로 감지되지만 qmd 명령은 설치되지 않습니다." + echo "로컬로 전환하거나 bun + qmd를 설치하고 다시 시도할 수 있습니다." fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ 写入配置失败" - break_end - return 1 - fi - echo "✅ 已设置 includeDefaultMemory=false" - echo "推荐执行:清理并重建索引" - read -e -p "是否执行清理并重建索引(推荐)?(Y/n): " rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "인덱스 복구 진단" + echo "=======================================" + echo "현재 includeDefaultMemory: ${include_dm:-not set}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ includeDefaultMemory=false 감지됨" + echo "이로 인해 기본 메모리 파일(MEMORY.md + memory/*.md)이 색인화되지 않습니다." + echo "따라서 Indexed는 항상 0/N을 표시합니다." + echo "" + read -e -p "true로 되돌리고 인덱스를 다시 작성하시겠습니까? (예/아니요):" fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ 구성을 쓰지 못했습니다." + break_end + return 1 + fi + echo "✅ 복원된 includeDefaultMemory=true" + openclaw_memory_rebuild_index_all + else + echo "취소." + fi else - echo "可稍后在记忆管理中查看状态。" + echo "includeDefaultMemory 구성이 정상입니다." + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" + echo "" + read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "취소." + fi fi break_end } @@ -13739,27 +13994,27 @@ EOF while true; do clear echo "=======================================" - echo "OpenClaw 记忆方案" + echo "OpenClaw 메모리 솔루션" echo "=======================================" local backend current_label backend=$(openclaw_memory_get_backend) case "$backend" in qmd) current_label="QMD" ;; builtin|local) current_label="Local" ;; - *) current_label="未配置" ;; + *) current_label="구성되지 않음" ;; esac - echo "当前方案: $current_label" + echo "현재 계획:$current_label" echo "" - echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" - echo "Local: 本地向量检索,依赖 embedding 模型文件" - echo "Auto : 自动推荐(基于可用性 + 网络探测)" + echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" + echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" echo "---------------------------------------" - echo "1. 切换 QMD(自动部署/已装则跳过)" - echo "2. 切换 Local(自动部署/已装则跳过)" - echo "3. Auto(自动推荐并自动部署)" - echo "0. 返回上一级" + echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" + echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" + echo "3. 자동(자동 추천 및 자동 배포)" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " scheme_choice + read -e -p "선택사항을 입력하세요:" scheme_choice case "$scheme_choice" in 1) openclaw_memory_auto_setup_run "qmd" @@ -13777,7 +14032,7 @@ EOF return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -13786,30 +14041,42 @@ EOF openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done </dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13819,17 +14086,17 @@ EOF openclaw_memory_view_file() { local file="$1" [ -f "$file" ] || { - echo "❌ 文件不存在: $file" + echo "❌ 파일이 존재하지 않습니다:$file" return 1 } local total_lines total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) local default_lines=120 local start_line count - echo "文件: $file" - echo "总行数: $total_lines" - read -e -p "请输入起始行(回车默认末尾 $default_lines 行): " start_line - read -e -p "请输入显示行数(回车默认 $default_lines): " count + echo "문서:$file" + echo "총 행 수:$total_lines" + read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line + read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -13839,14 +14106,14 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 请输入有效的数字。" + echo "❌ 유효한 숫자를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ 行数必须大于 0。" + echo "❌ 행 개수는 0보다 커야 합니다." return 1 fi local end_line=$((start_line + count - 1)) @@ -13854,7 +14121,7 @@ EOF end_line=$total_lines fi if [ "$total_lines" -eq 0 ]; then - echo "(空文件)" + echo "(빈 파일)" return 0 fi echo "---------------------------------------" @@ -13866,71 +14133,78 @@ EOF while true; do clear echo "=======================================" - echo "OpenClaw 记忆文件" + echo "OpenClaw 메모리 파일" echo "=======================================" openclaw_memory_file_render_list echo "---------------------------------------" - read -e -p "请输入文件编号查看(0 返回): " file_choice + read -e -p "보려는 파일 번호를 입력하십시오(0을 반환)." file_choice if [ "$file_choice" = "0" ]; then return 0 fi if ! [[ "$file_choice" =~ ^[0-9]+$ ]]; then - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 continue fi openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then - read -p "未找到记忆文件,按回车返回..." + read -p "메모리 파일을 찾을 수 없습니다. 돌아가려면 Enter를 누르세요..." return 0 fi local idx=$((file_choice-1)) if [ "$idx" -lt 0 ] || [ "$idx" -ge ${#OPENCLAW_MEMORY_FILES[@]} ]; then - echo "无效的编号,请重试。" + echo "잘못된 번호입니다. 다시 시도해 주세요." sleep 1 continue fi openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" - read -p "按回车返回列表..." + read -p "목록으로 돌아가려면 Enter를 누르세요..." done } openclaw_memory_menu() { - send_stats "OpenClaw记忆管理" + send_stats "OpenClaw 메모리 관리" while true; do clear echo "=======================================" - echo "OpenClaw 记忆管理" + echo "OpenClaw 메모리 관리" echo "=======================================" openclaw_memory_render_status - echo "1. 更新记忆索引" - echo "2. 查看记忆文件" - echo "3. 索引修复(Indexed 异常)" - echo "4. 记忆方案(QMD/Local/Auto)" - echo "0. 返回上一级" + echo "1. 메모리 인덱스 업데이트" + echo "2. 메모리 파일 보기" + echo "3. 인덱스 복구(인덱스 예외)" + echo "4. 메모리 솔루션(QMD/Local/Auto)" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " memory_choice + read -e -p "선택사항을 입력하세요:" memory_choice case "$memory_choice" in 1) - echo "即将更新记忆索引。" - read -e -p "第一次确认:输入 yes 继续: " confirm_step1 + echo "메모리 인덱스는 곧 업데이트될 예정입니다." + read -e -p "첫 번째 확인: 계속하려면 yes를 입력하세요." confirm_step1 if [ "$confirm_step1" != "yes" ]; then - echo "已取消。" + echo "취소." break_end continue fi - openclaw_memory_prepare_workspace - read -e -p "二次确认:输入 force 使用全量(留空为增量): " confirm_step2 + openclaw_memory_prepare_workspace_all + read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then - echo "⚠️ 全量重建更彻底,但耗时更长。" - echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" - read -e -p "第三次确认:输入 rebuild 执行安全重建;直接回车继续普通 force: " confirm_step3 + echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + local fl_agent_lines fl_agent_id fl_workspace + fl_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r fl_agent_id fl_workspace; do + [ -z "$fl_agent_id" ] && continue + openclaw memory index --agent "$fl_agent_id" --force + done </dev/null 2>&1 || { - echo "⚠️ 权限备份失败:$backup_file" + echo "⚠️ 권한 백업 실패:$backup_file" return 1 } - echo "✅ 已备份当前权限配置: $backup_file" + echo "✅ 현재 권한 구성이 백업되었습니다:$backup_file" return 0 } @@ -13997,24 +14271,24 @@ EOF config_file=$(openclaw_permission_config_file) backup_file=$(openclaw_permission_backup_file) if [ ! -s "$backup_file" ]; then - echo "❌ 未找到可恢复的权限备份文件。" + echo "❌ 복원 가능한 권한 백업 파일이 없습니다." return 1 fi cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { - echo "❌ 权限恢复失败:$backup_file" + echo "❌ 권한 복구 실패:$backup_file" return 1 } - echo "✅ 已恢复切换前权限配置" + echo "✅ 스위치가 복원되기 전의 권한 구성" openclaw_permission_restart_gateway || true return 0 } openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + echo "❌ openclaw가 감지되지 않아 OpenClaw Gateway를 다시 시작할 수 없습니다." return 1 fi - echo "正在重启 OpenClaw Gateway..." + echo "OpenClaw 게이트웨이 다시 시작 중..." openclaw gateway restart >/dev/null 2>&1 || { openclaw gateway stop >/dev/null 2>&1 openclaw gateway start >/dev/null 2>&1 @@ -14100,51 +14374,89 @@ PY } openclaw_permission_detect_mode() { - local profile security ask elevated bash_enabled apply_patch workspace_only - profile=$(openclaw_permission_get_value "tools.profile") - security=$(openclaw_permission_get_value "tools.exec.security") - ask=$(openclaw_permission_get_value "tools.exec.ask") - elevated=$(openclaw_permission_get_value "tools.elevated.enabled") - bash_enabled=$(openclaw_permission_get_value "commands.bash") - apply_patch=$(openclaw_permission_get_value "tools.exec.applyPatch.enabled") - workspace_only=$(openclaw_permission_get_value "tools.exec.applyPatch.workspaceOnly") - - if [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "false" ] && [ "$bash_enabled" = "false" ] && [ "$apply_patch" = "false" ]; then - echo "标准安全模式" - elif [ "$profile" = "coding" ] && [ "$security" = "allowlist" ] && [ "$ask" = "on-miss" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ] && [ "$workspace_only" = "true" ]; then - echo "开发增强模式" - elif { [ "$profile" = "full" ] || [ "$profile" = "(unset)" ]; } && [ "$security" = "full" ] && [ "$ask" = "off" ] && [ "$elevated" = "true" ] && [ "$bash_enabled" = "true" ] && [ "$apply_patch" = "true" ]; then - echo "完全开放模式" - else - echo "自定义模式" - fi + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "알 수 없는 모드"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("표준 안전 모드") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("향상된 모드 개발") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("완전 개방 모드") + else: + print("커스텀 모드") +except Exception: + print("커스텀 모드") +PY } - openclaw_permission_render_status() { + openclaw_permission_render_status() { local config_file mode config_file=$(openclaw_permission_config_file) mode=$(openclaw_permission_detect_mode) - echo "配置文件: $config_file" - [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" - if ! openclaw_has_command openclaw; then - echo "⚠️ 未检测到 openclaw 命令,状态读取将基于配置文件。" - fi - echo "当前模式: $mode" + echo "구성 파일:$config_file" + [ ! -s "$config_file" ] && echo "⚠️ OpenClaw 구성 파일을 찾을 수 없습니다(아직 초기화되지 않았을 수 있음)." + echo "현재 모드:$mode" echo "---------------------------------------" - printf "%-28s %s\n" "tools.profile" "$(openclaw_permission_get_value tools.profile)" - printf "%-28s %s\n" "tools.allow" "$(openclaw_permission_get_value tools.allow)" - printf "%-28s %s\n" "tools.deny" "$(openclaw_permission_get_value tools.deny)" - printf "%-28s %s\n" "tools.byProvider" "$(openclaw_permission_get_value tools.byProvider)" - printf "%-28s %s\n" "tools.exec.security" "$(openclaw_permission_get_value tools.exec.security)" - printf "%-28s %s\n" "tools.exec.ask" "$(openclaw_permission_get_value tools.exec.ask)" - printf "%-28s %s\n" "tools.elevated.enabled" "$(openclaw_permission_get_value tools.elevated.enabled)" - printf "%-28s %s\n" "commands.bash" "$(openclaw_permission_get_value commands.bash)" - printf "%-28s %s\n" "applyPatch.enabled" "$(openclaw_permission_get_value tools.exec.applyPatch.enabled)" - printf "%-28s %s\n" "applyPatch.workspaceOnly" "$(openclaw_permission_get_value tools.exec.applyPatch.workspaceOnly)" + + # Python을 사용하여 모든 권한 필드를 한 번에 효율적으로 구문 분석 + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) + +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except Exception as e: + print("❌ 구성 파일 구문 분석 실패: %s" % e) +PY } openclaw_permission_apply_standard() { - send_stats "OpenClaw权限-标准安全模式" + send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 @@ -14159,19 +14471,19 @@ PY openclaw config set tools.exec.applyPatch.enabled false || failed=1 openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" + echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." openclaw_permission_restore_backup || true return 1 fi if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" return 1 fi - echo "✅ 已切换为标准安全模式" + echo "✅ 표준 안전 모드로 전환됨" } openclaw_permission_apply_developer() { - send_stats "OpenClaw权限-开发增强模式" + send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 @@ -14186,19 +14498,19 @@ PY openclaw config set tools.exec.applyPatch.enabled true || failed=1 openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" + echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." openclaw_permission_restore_backup || true return 1 fi if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" return 1 fi - echo "✅ 已切换为开发增强模式" + echo "✅ 개발 강화 모드로 전환됨" } openclaw_permission_apply_full() { - send_stats "OpenClaw权限-完全开放模式" + send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 @@ -14213,19 +14525,19 @@ PY openclaw config set tools.exec.applyPatch.enabled true || failed=1 openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" + echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." openclaw_permission_restore_backup || true return 1 fi if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" return 1 fi - echo "✅ 已切换为完全开放模式" + echo "✅ 완전 개방 모드로 전환됨" } openclaw_permission_restore_official_defaults() { - send_stats "OpenClaw权限-恢复官方默认" + send_stats "OpenClaw 권한-공식 기본값 복원" openclaw_permission_require_openclaw || return 1 openclaw_permission_backup_current || true local failed=0 @@ -14240,71 +14552,66 @@ PY openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 if [ "$failed" -ne 0 ]; then - echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" + echo "❌ 복구 실패: 명시적 권한 재정의를 정리하는 동안 오류가 발생했습니다." openclaw_permission_restore_backup || true return 1 fi if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" + echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" return 1 fi - echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + echo "✅ OpenClaw 공식 기본 전략으로 되돌림(명시적 재정의 삭제)" } openclaw_permission_run_audit() { - send_stats "OpenClaw权限-安全审计" + send_stats "OpenClaw 권한-보안 감사" openclaw_permission_require_openclaw || return 1 openclaw security audit } openclaw_permission_menu() { - send_stats "OpenClaw权限管理" + send_stats "OpenClaw 권한 관리" while true; do clear echo "=======================================" - echo "OpenClaw 权限管理" + echo "OpenClaw 권한 관리" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 查看当前权限状态" - echo "2. 切换为标准安全模式(推荐)" - echo "3. 切换为开发增强模式" - echo "4. 切换为完全开放模式(高风险)" - echo "5. 恢复官方默认策略" - echo "6. 运行安全审计" - echo "0. 返回上一级" + echo "1. 표준 안전 모드로 전환(권장)" + echo "2. 개발 강화 모드로 전환" + echo "3. 완전 개방 모드로 전환(고위험)" + echo "4. 공식 기본 전략 복원" + echo "5. 보안 감사 실행" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " perm_choice + read -e -p "선택사항을 입력하세요:" perm_choice case "$perm_choice" in 1) - openclaw_permission_render_status + echo "적용 예정: 표준 보안 모드" + read -e -p "확인하려면 yes를 입력하세요." confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "취소" break_end ;; 2) - echo "将应用:标准安全模式" - read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + echo "적용 예정: 개발 강화 모드" + read -e -p "확인하려면 yes를 입력하세요." confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "취소" break_end ;; 3) - echo "将应用:开发增强模式" - read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + echo "⚠️ 완전 개방 모드는 exec 승인을 끄고 권한 상승 및 bash를 활성화하며 신뢰할 수 있는 단일 사용자 환경에만 권장됩니다." + read -e -p "계속하려면 FULL을 입력하여 확인하세요." confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "취소" break_end ;; 4) - echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" - read -e -p "输入 FULL 确认继续: " confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + echo "정리 스크립트로 작성된 명시적 권한을 재정의하여 공식 OpenClaw 기본 정책으로 되돌립니다." + read -e -p "확인하려면 yes를 입력하세요." confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "취소" break_end ;; 5) - echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" - read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" - break_end - ;; - 6) openclaw_permission_run_audit break_end ;; @@ -14312,7 +14619,7 @@ PY return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -14320,10 +14627,44 @@ PY } openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi openclaw config file 2>/dev/null | tail -n 1 } openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi local value value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then @@ -14343,208 +14684,300 @@ except Exception: openclaw_multiagent_require_openclaw() { if ! openclaw_has_command openclaw; then - echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + echo "❌ openclaw 명령이 감지되지 않습니다. 먼저 OpenClaw를 설치하거나 초기화하세요." return 1 fi return 0 } openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents list --json 2>/dev/null || echo '[]' } openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi openclaw agents bindings --json 2>/dev/null || echo '[]' } openclaw_multiagent_sessions_json() { - openclaw sessions --all-agents --json 2>/dev/null || echo '{}' + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY } openclaw_multiagent_render_status() { local config_file default_agent config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) - echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" - echo "默认智能体: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。") + echo "구성 파일: ${config_file:-$(openclaw_permission_config_file)}" + echo "기본 에이전트:$default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("구성된 에이전트 수: %s" % len(agents)); print("경로 바인딩 수: %s" % len(bindings)); print("총 세션: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("현재 다중 에이전트가 구성되어 있지 않습니다.") else: import itertools for item in itertools.islice(agents, 8): - identity=item.get("identityName") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; is_default="是" if item.get("isDefault") else "否"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws); print(" 默认智能体: %s" % is_default); print(" 路由绑定数: %s" % item.get("bindings",0))' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 에이전트 ID: [1;36m%s [0m" % item.get("id","?")); print("ID 이름: %s %s" % (identity, emoji)); print("작업 디렉터리: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { - send_stats "OpenClaw多智能体-列出Agent" - openclaw_multiagent_require_openclaw || return 1 + send_stats "OpenClaw 다중 에이전트 - 에이전트 나열" python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); -if not agents: print("暂无已配置 Agent。"); raise SystemExit(0) +if not agents: print("아직 구성된 에이전트가 없습니다."); raise SystemExit(0) for idx,item in enumerate(agents,1): print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" } openclaw_multiagent_add_agent() { - send_stats "OpenClaw多智能体-新增Agent" + send_stats "OpenClaw 다중 에이전트-새 에이전트" openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm - read -e -p "请输入新的 Agent ID: " agent_id - [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace + read -e -p "새 에이전트 ID를 입력하세요." agent_id + [ -z "$agent_id" ] && echo "취소됨: 에이전트 ID는 비워둘 수 없습니다." && return 1 + read -e -p "작업공간 경로를 입력해주세요(기본값 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "将创建智能体: $agent_id" - echo "工作目录: $workspace" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + echo "에이전트가 생성됩니다:$agent_id" + echo "작업 디렉토리:$workspace" + read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm + [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ 智能体创建成功: $agent_id" + echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" + local name theme + read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name + [ -z "$name" ] && name="$agent_id" + read -e -p "상담원 성격 주제(예: 엄격함, 효율적)를 입력하세요." theme + [ -z "$theme" ] && theme="어시스턴트" + echo "에이전트 ID 구성 중..." + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能体创建失败" + echo "❌ 에이전트 생성 실패" return 1 fi } openclaw_multiagent_delete_agent() { - send_stats "OpenClaw多智能体-删除Agent" + send_stats "OpenClaw 다중 에이전트 삭제 에이전트" openclaw_multiagent_require_openclaw || return 1 local agent_id confirm - read -e -p "请输入要删除的 Agent ID: " agent_id - [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - echo "⚠️ 删除智能体可能影响其工作目录、路由绑定与会话路由。" - read -e -p "输入 DELETE 确认删除 ${agent_id}: " confirm - [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } + read -e -p "삭제할 에이전트 ID를 입력하세요:" agent_id + [ -z "$agent_id" ] && echo "취소됨: 에이전트 ID는 비워둘 수 없습니다." && return 1 + echo "⚠️ 에이전트를 삭제하면 작업 디렉터리, 경로 바인딩 및 세션 라우팅에 영향을 미칠 수 있습니다." + read -e -p "삭제를 확인하려면 DELETE를 입력하세요.${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "취소"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ 智能体删除成功: $agent_id" + echo "✅ 에이전트가 성공적으로 삭제되었습니다:$agent_id" else - echo "❌ 智能体删除失败" + echo "❌ 에이전트 삭제 실패" return 1 fi } openclaw_multiagent_list_bindings() { - send_stats "OpenClaw多智能体-查看路由绑定" - openclaw_multiagent_require_openclaw || return 1 + send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 보기" python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无路由绑定。"); raise SystemExit(0) +if not bindings: print("아직 경로 바인딩이 없습니다."); raise SystemExit(0) for idx,item in enumerate(bindings,1): bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { - send_stats "OpenClaw多智能体-新增路由绑定" + send_stats "OpenClaw 다중 에이전트-새 라우팅 바인딩" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入智能体 ID: " agent_id - read -e -p "请输入路由绑定值(如 telegram:ops / discord:guild-a): " bind_value - { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将绑定智能体 [$agent_id] -> [$bind_value]" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + read -e -p "상담원 ID를 입력하세요:" agent_id + read -e -p "경로 바인딩 값을 입력하세요(예: telegram:ops / discord:guild-a):" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 + echo "에이전트를 바인딩합니다 [$agent_id] -> [$bind_value]" + read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm + [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由绑定添加成功" + echo "✅ 경로 바인딩이 성공적으로 추가되었습니다." else - echo "❌ 路由绑定添加失败" + echo "❌ 경로 바인딩을 추가하지 못했습니다." return 1 fi } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw多智能体-移除路由绑定" + send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "请输入智能体 ID: " agent_id - read -e -p "请输入要移除的路由绑定值: " bind_value - { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 - echo "将移除智能体 [$agent_id] 的路由绑定 [$bind_value]" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + read -e -p "상담원 ID를 입력하세요:" agent_id + read -e -p "제거할 경로 바인딩 값을 입력하세요." bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 + echo "에이전트를 제거합니다. [$agent_id] 경로 바인딩 [$bind_value]" + read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm + [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由绑定移除成功" + echo "✅ 경로 바인딩이 성공적으로 제거되었습니다." else - echo "❌ 路由绑定移除失败" + echo "❌ 경로 바인딩 제거 실패" return 1 fi } - openclaw_multiagent_set_identity() { - send_stats "OpenClaw多智能体-设置智能体身份" - openclaw_multiagent_require_openclaw || return 1 - local agent_id name theme emoji confirm - read -e -p "请输入智能体 ID: " agent_id - [ -z "$agent_id" ] && echo "已取消:Agent ID 不能为空。" && return 1 - read -e -p "身份名称(可留空): " name - read -e -p "身份主题(可留空): " theme - read -e -p "身份表情(可留空): " emoji - [ -z "$name$theme$emoji" ] && echo "已取消:至少填写一个身份字段。" && return 1 - echo "将更新智能体 [$agent_id] 的身份信息。" - read -e -p "输入 yes 确认继续: " confirm - [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } - local cmd="openclaw agents set-identity --agent '$agent_id'" - [ -n "$name" ] && cmd="$cmd --name '$(printf %s "$name" | sed "s/'/'\\''/g")'" - [ -n "$theme" ] && cmd="$cmd --theme '$(printf %s "$theme" | sed "s/'/'\\''/g")'" - [ -n "$emoji" ] && cmd="$cmd --emoji '$(printf %s "$emoji" | sed "s/'/'\\''/g")'" - eval "$cmd" - } openclaw_multiagent_show_sessions() { - send_stats "OpenClaw多智能体-会话概况" - openclaw_multiagent_require_openclaw || return 1 + send_stats "OpenClaw 다중 에이전트 - 세션 개요" python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("暂无 session 数据。"); raise SystemExit(0) +if not sessions: print("아직 세션 데이터가 없습니다."); raise SystemExit(0) by_agent={} for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 -print("会话汇总:") +print("세션 요약:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { - send_stats "OpenClaw多智能体-健康检查" + send_stats "OpenClaw 다중 에이전트 상태 확인" openclaw_multiagent_require_openclaw || return 1 local config_file config_file=$(openclaw_multiagent_config_file) - echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" - openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" + echo "구성 파일을 확인하세요: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 구성 확인에 실패했습니다. 위의 출력을 확인하세요." python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置智能体。"); +if not agents: print("⚠️ 구성된 에이전트를 찾을 수 없습니다."); else: for item in agents: - ws=item.get("workspace") or ""; state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else "MISSING"; print("agent=%s workspace=%s [%s]" % (item.get("id","?"), ws or "-", state)) -print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) +print("경로 바인딩 수=%s" % len(bindings)); print("✅멀티에이전트 헬스체크 완료")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_menu() { - send_stats "OpenClaw多智能体管理" + send_stats "OpenClaw 다중 에이전트 관리" while true; do clear echo "=======================================" - echo "OpenClaw 多智能体管理" + echo "OpenClaw 다중 에이전트 관리" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 新增智能体" - echo "2. 删除智能体" - echo "3. 查看路由绑定" - echo "4. 新增路由绑定" - echo "5. 移除路由绑定" - echo "6. 设置智能体身份" - echo "7. 查看会话概况" - echo "8. 运行多智能体健康检查" - echo "0. 返回上一级" + echo "1. 새로운 지능형 에이전트 추가" + echo "2. 에이전트 삭제" + echo "3. 라우팅 바인딩 보기" + echo "4. 새로운 경로 바인딩 추가" + echo "5. 경로 바인딩 제거" + echo "6. 세션 개요 보기" + echo "7. 다중 에이전트 상태 확인 실행" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " multi_choice + read -e -p "선택사항을 입력하세요:" multi_choice case "$multi_choice" in 1) openclaw_multiagent_add_agent; break_end ;; 2) openclaw_multiagent_delete_agent; break_end ;; 3) openclaw_multiagent_list_bindings; break_end ;; 4) openclaw_multiagent_add_binding; break_end ;; 5) openclaw_multiagent_remove_binding; break_end ;; - 6) openclaw_multiagent_set_identity; break_end ;; - 7) openclaw_multiagent_show_sessions; break_end ;; - 8) openclaw_multiagent_health_check; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; 0) return 0 ;; - *) echo "无效的选择,请重试。"; sleep 1 ;; + *) echo "선택이 잘못되었습니다. 다시 시도해 주세요."; sleep 1 ;; esac done } @@ -14552,22 +14985,22 @@ print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查 openclaw_backup_restore_menu() { - send_stats "OpenClaw备份与还原" + send_stats "OpenClaw 백업 및 복원" while true; do clear echo "=======================================" - echo "OpenClaw 备份与还原" + echo "OpenClaw 백업 및 복원" echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" - echo "1. 备份记忆全量" - echo "2. 还原记忆全量" - echo "3. 备份 OpenClaw 项目(默认安全模式)" - echo "4. 还原 OpenClaw 项目(高级/高风险)" - echo "5. 删除备份文件" - echo "0. 返回上一级" + echo "1. 메모리 전체를 백업하세요" + echo "2. 전체 메모리 복원" + echo "3. OpenClaw 프로젝트 백업(기본 안전 모드)" + echo "4. OpenClaw 프로젝트 복원(고급/고위험)" + echo "5. 백업 파일 삭제" + echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "请输入你的选择: " backup_choice + read -e -p "선택사항을 입력하세요:" backup_choice case "$backup_choice" in 1) openclaw_memory_backup_export ;; @@ -14577,7 +15010,7 @@ openclaw_backup_restore_menu() { 5) openclaw_backup_delete_file ;; 0) return 0 ;; *) - echo "无效的选择,请重试。" + echo "선택이 잘못되었습니다. 다시 시도해 주세요." sleep 1 ;; esac @@ -14586,8 +15019,8 @@ openclaw_backup_restore_menu() { update_moltbot() { - echo "更新 OpenClaw..." - send_stats "更新 OpenClaw..." + echo "오픈클로 업데이트..." + send_stats "오픈클로 업데이트..." install_node_and_tools git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: @@ -14596,29 +15029,29 @@ openclaw_backup_restore_menu() { start_gateway hash -r add_app_id - echo "更新完成" + echo "업데이트 완료" break_end } uninstall_moltbot() { - echo "卸载 OpenClaw..." - send_stats "卸载 OpenClaw..." + echo "OpenClaw 제거..." + send_stats "OpenClaw 제거..." openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 루트 디렉터리에 /root/.openclaw가 여전히 존재하는 것으로 감지됩니다. 청소가 필요한 경우 수동으로 처리하십시오." hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "卸载完成" + echo "제거가 완료되었습니다." break_end } nano_openclaw_json() { - send_stats "编辑 OpenClaw 配置文件" + send_stats "OpenClaw 구성 파일 편집" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -14650,7 +15083,7 @@ openclaw_backup_restore_menu() { local local_ip token domains echo "==================================" - echo "OpenClaw WebUI 访问地址" + echo "OpenClaw WebUI 접속 주소" local_ip="127.0.0.1" token=$( @@ -14659,12 +15092,12 @@ openclaw_backup_restore_menu() { | head -n 1 ) echo - echo "本机地址:" + echo "현지 주소:" echo "http://${local_ip}:18789/#token=${token}" domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "域名地址:" + echo "도메인 이름 주소:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -14675,7 +15108,7 @@ openclaw_backup_restore_menu() { - # 添加域名(调用你给的函数) + # 도메인 이름 추가(제공한 기능 호출) openclaw_domain_webui() { add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 18789 @@ -14687,30 +15120,30 @@ openclaw_backup_restore_menu() { ) clear - echo "访问地址:" + echo "방문 주소:" echo "https://${yuming}/#token=$token" - echo "先访问URL触发设备ID,然后回车下一步进行配对。" + echo "먼저 URL에 액세스하여 장치 ID를 트리거한 다음 Enter를 눌러 페어링을 진행하세요." read - echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" - # 自动添加域名到 allowedOrigins - config_file="$HOME/.openclaw/openclaw.json" + echo -e "${gl_kjlan}기기 목록 로드 중...${gl_bai}" + # allowedOrigins에 도메인 이름을 자동으로 추가합니다. + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" - # 使用 jq 安全修改 JSON,确保结构存在且不重复添加域名 + # 구조가 존재하고 도메인 이름이 반복적으로 추가되지 않도록 jq를 사용하여 JSON을 안전하게 수정하세요. if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已将域名 ${yuming} 加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}도메인 이름이${yuming}allowedOrigins 구성 추가${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi openclaw devices list - read -e -p "请输入 Request_Key: " Request_Key + read -e -p "Request_Key를 입력하십시오:" Request_Key [ -z "$Request_Key" ] && { - echo "Request_Key 不能为空" + echo "Request_Key는 비워둘 수 없습니다." return 1 } @@ -14718,41 +15151,41 @@ openclaw_backup_restore_menu() { } - # 删除域名 + # 도메인 이름 삭제 openclaw_remove_domain() { - echo "域名格式 example.com 不带https://" + echo "https://가 없는 도메인 이름 형식 example.com" web_del } - # 主菜单 + # 메인 메뉴 openclaw_webui_menu() { - send_stats "WebUI访问与设置" + send_stats "WebUI 액세스 및 설정" while true; do clear openclaw_show_webui_addr echo - echo "1. 添加域名访问" - echo "2. 删除域名访问" - echo "0. 退出" + echo "1. 도메인 이름 액세스 추가" + echo "2. 도메인 이름 액세스 삭제" + echo "0. 종료" echo - read -e -p "请选择: " choice + read -e -p "선택하세요:" choice case "$choice" in 1) openclaw_domain_webui echo - read -p "按回车返回菜单..." + read -p "메뉴로 돌아가려면 Enter를 누르세요..." ;; 2) openclaw_remove_domain - read -p "按回车返回菜单..." + read -p "메뉴로 돌아가려면 Enter를 누르세요..." ;; 0) break ;; *) - echo "无效选项" + echo "잘못된 옵션" sleep 1 ;; esac @@ -14761,7 +15194,7 @@ openclaw_backup_restore_menu() { - # 主循环 + # 메인 루프 while true; do show_menu read choice @@ -14776,22 +15209,22 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初始化配置向导" + 11) send_stats "초기 구성 마법사" openclaw onboard --install-daemon break_end ;; - 12) send_stats "健康检测与修复" + 12) send_stats "상태 감지 및 수리" openclaw doctor --fix - send_stats "OpenClaw API同步触发" + send_stats "OpenClaw API 동기식 트리거링" if sync_openclaw_api_models; then start_gateway else - echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" + echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." fi break_end ;; 13) openclaw_webui_menu ;; - 14) send_stats "TUI命令行对话" + 14) send_stats "TUI 명령줄 대화" openclaw tui break_end ;; @@ -14817,7 +15250,7 @@ local sub_choice="$1" clear cd ~ install git -echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" +echo -e "${gl_kjlan}신청 목록이 업데이트 중입니다. 기다리세요...${gl_bai}" if [ ! -d apps/.git ]; then timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git else @@ -14830,12 +15263,12 @@ while true; do if [ -z "$sub_choice" ]; then clear - echo -e "应用市场" + echo -e "응용 시장" echo -e "${gl_kjlan}-------------------------" local app_numbers=$([ -f /home/docker/appno.txt ] && cat /home/docker/appno.txt || echo "") - # 用循环设置颜色 + # 루프를 사용하여 색상 설정 for i in {1..150}; do if echo "$app_numbers" | grep -q "^$i$"; then declare "color$i=${gl_lv}" @@ -14844,91 +15277,91 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel宝塔国际版" - echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板 ${gl_kjlan}4. ${color4}NginxProxyManager可视化面板" - echo -e "${gl_kjlan}5. ${color5}OpenList多存储文件列表程序 ${gl_kjlan}6. ${color6}Ubuntu远程桌面网页版" - echo -e "${gl_kjlan}7. ${color7}哪吒探针VPS监控面板 ${gl_kjlan}8. ${color8}QB离线BT磁力下载面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" + echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" + echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" - echo -e "${gl_kjlan}13. ${color13}Cloudreve网盘 ${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}简单图床图片管理程序" - echo -e "${gl_kjlan}15. ${color15}emby多媒体管理系统 ${gl_kjlan}16. ${color16}Speedtest测速面板" - echo -e "${gl_kjlan}17. ${color17}AdGuardHome去广告软件 ${gl_kjlan}18. ${color18}onlyoffice在线办公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}11. ${color11}ZenTao 프로젝트 관리 소프트웨어${gl_kjlan}12. ${color12}Qinglong 패널 예정된 작업 관리 플랫폼" + echo -e "${gl_kjlan}13. ${color13}Cloudreve 네트워크 디스크${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}간단한 그림 침대 그림 관리 프로그램" + echo -e "${gl_kjlan}15. ${color15}emby 멀티미디어 관리 시스템${gl_kjlan}16. ${color16}Speedtest 속도 테스트 패널" + echo -e "${gl_kjlan}17. ${color17}AdGuardHome은 애드웨어를 제거합니다${gl_kjlan}18. ${color18}onlyoffice온라인 오피스 OFFICE" + echo -e "${gl_kjlan}19. ${color19}Leichi WAF 방화벽 패널${gl_kjlan}20. ${color20}포테이너 컨테이너 관리 패널" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma监控工具" - echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop远程桌面网页版 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud网盘 ${gl_kjlan}26. ${color26}QD-Today定时任务管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆栈管理面板 ${gl_kjlan}28. ${color28}LibreSpeed测速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" + echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" + echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${color33}Sun-Panel导航面板 ${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" - echo -e "${gl_kjlan}39. ${color39}Bililive直播录制工具 ${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" + echo -e "${gl_kjlan}35. ${color35}미니멀리스트 친구들${gl_kjlan}36. ${color36}LobeChatAI 채팅 집계 웹사이트" + echo -e "${gl_kjlan}37. ${color37}MyIP 도구 상자${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist 가족 버킷" + echo -e "${gl_kjlan}39. ${color39}Bililive 라이브 방송 녹음 도구${gl_kjlan}40. ${color40}webssh 웹 버전 SSH 연결 도구" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm远程连接工具" - echo -e "${gl_kjlan}43. ${color43}RustDesk远程桌面(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk远程桌面(中继端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}补货监控工具" + echo -e "${gl_kjlan}41. ${color41}마우스 관리 패널${gl_kjlan}42. ${color42}Nexterm 원격 연결 도구" + echo -e "${gl_kjlan}43. ${color43}RustDesk 원격 데스크톱(서버)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk 원격 데스크톱(릴레이)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}45. ${color45}도커 가속 스테이션${gl_kjlan}46. ${color46}GitHub 가속 스테이션${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}프로메테우스 모니터링${gl_kjlan}48. ${color48}프로메테우스(호스트 모니터링)" + echo -e "${gl_kjlan}49. ${color49}프로메테우스(컨테이너 모니터링)${gl_kjlan}50. ${color50}보충 모니터링 도구" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}51. ${color51}PVE开小鸡面板 ${gl_kjlan}52. ${color52}DPanel容器管理面板" - echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型 ${gl_kjlan}54. ${color54}AMH主机建站管理面板" - echo -e "${gl_kjlan}55. ${color55}FRP内网穿透(服务端) ${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP内网穿透(客户端) ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知识库 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI大模型资产管理 ${gl_kjlan}60. ${color60}JumpServer开源堡垒机" + echo -e "${gl_kjlan}51. ${color51}PVE 오픈 병아리 패널${gl_kjlan}52. ${color52}DPanel 컨테이너 관리 패널" + echo -e "${gl_kjlan}53. ${color53}라마3 채팅 AI 대형 모델${gl_kjlan}54. ${color54}AMH 호스트 웹사이트 구축 관리 패널" + echo -e "${gl_kjlan}55. ${color55}FRP 인트라넷 침투(서버)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP 인트라넷 침투(클라이언트)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek 채팅 AI 대형 모델${gl_kjlan}58. ${color58}대규모 모델 지식 기반 확장${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}59. ${color59}NewAPI 대형 모델 자산 관리${gl_kjlan}60. ${color60}JumpServer 오픈 소스 요새 머신" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}61. ${color61}在线翻译服务器 ${gl_kjlan}62. ${color62}RAGFlow大模型知识库" - echo -e "${gl_kjlan}63. ${color63}OpenWebUI自托管AI平台 ${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL证书管理平台" - echo -e "${gl_kjlan}69. ${color69}SFTPGo文件传输工具 ${gl_kjlan}70. ${color70}AstrBot聊天机器人框架" + echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" + echo -e "${gl_kjlan}63. ${color63}OpenWebUI 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" + echo -e "${gl_kjlan}65. ${color65}n8n 자동화된 워크플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp 비디오 다운로드 도구" + echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音乐服务器 ${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影视" - echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}在线DOS老游戏" - echo -e "${gl_kjlan}77. ${color77}迅雷离线下载工具 ${gl_kjlan}78. ${color78}PandaWiki智能文档管理系统" - echo -e "${gl_kjlan}79. ${color79}Beszel服务器监控 ${gl_kjlan}80. ${color80}linkwarden书签管理" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" + echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" + echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" + echo -e "${gl_kjlan}79. ${color79}베젤 서버 모니터링${gl_kjlan}80. ${color80}링크워든 북마크 관리" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" - echo -e "${gl_kjlan}83. ${color83}komari服务器监控工具 ${gl_kjlan}84. ${color84}Wallos个人财务管理工具" - echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒体管理系统" - echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器 ${gl_kjlan}88. ${color88}Owncast自托管直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}gpt-load 고성능 AI 투명 프록시" + echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" + echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" - echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速下载工具" - echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自托管二步验证器" - echo -e "${gl_kjlan}97. ${color97}WireGuard组网(服务端) ${gl_kjlan}98. ${color98}WireGuard组网(客户端)" - echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing点对点文件同步工具" + echo -e "${gl_kjlan}91. ${color91}gitea 비공개 코드 저장소${gl_kjlan}92. ${color92}FileBrowser 파일 관리자" + echo -e "${gl_kjlan}93. ${color93}Dufs 미니멀리스트 정적 파일 서버${gl_kjlan}94. ${color94}Gopeed 고속 다운로드 도구" + echo -e "${gl_kjlan}95. ${color95}종이 없는 문서 관리 플랫폼${gl_kjlan}96. ${color96}2FAuth 자체 호스팅 2단계 인증자" + echo -e "${gl_kjlan}97. ${color97}WireGuard 네트워킹(서버)${gl_kjlan}98. ${color98}WireGuard 네트워킹(클라이언트)" + echo -e "${gl_kjlan}99. ${color99}DSM Synology 가상 컴퓨터${gl_kjlan}100. ${color100}P2P 파일 동기화 도구 동기화" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI视频生成工具 ${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" - echo -e "${gl_kjlan}103. ${color103}Umami网站统计工具 ${gl_kjlan}104. ${color104}Stream四层代理转发工具" - echo -e "${gl_kjlan}105. ${color105}思源笔记 ${gl_kjlan}106. ${color106}Drawnix开源白板工具" - echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot聊天机器人" - echo -e "${gl_kjlan}109. ${color109}ZFile在线网盘 ${gl_kjlan}110. ${color110}Karakeep书签管理" + echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" + echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" + echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}第三方应用列表" - echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}타사 애플리케이션 목록" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue local base_name=$(basename "$f" .conf) - # 获取应用描述 + # 앱 설명 가져오기 local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - # 检查安装状态 (匹配 appno.txt 中的 ID) - # 这里假设 appno.txt 中记录的是 base_name (即文件名) + # 설치 상태 확인(appno.txt의 ID 일치) + # 여기서는 appno.txt에 기록되는 내용이 base_name(즉, 파일 이름)이라고 가정합니다. if echo "$app_numbers" | grep -q "^$base_name$"; then - # 如果已安装:显示 base_name - 描述 [已安装] (绿色) - echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" + # 설치된 경우: show base_name - 설명 [설치됨](녹색) + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[설치됨]${gl_bai}" else - # 如果未安装:正常显示 + # 설치되지 않은 경우: 정상적으로 표시됩니다. echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" fi done @@ -14936,18 +15369,18 @@ while true; do echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}还原全部应用数据" + echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice fi case $sub_choice in 1|bt|baota) local app_id="1" local lujing="[ -d "/www/server/panel" ]" - local panelname="宝塔面板" + local panelname="탑 패널" local panelurl="https://www.bt.cn/new/index.html" panel_app_install() { @@ -15040,10 +15473,10 @@ while true; do } - local docker_describe="一个Nginx反向代理工具面板,不支持添加域名访问。" - local docker_url="官网介绍: https://nginxproxymanager.com/" - local docker_use="echo \"初始用户名: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_describe="도메인 이름 액세스 추가를 지원하지 않는 Nginx 역방향 프록시 도구 패널." + local docker_url="공식 홈페이지 소개: https://nginxproxymanager.com/" + local docker_use="echo \"초기 사용자 이름: admin@example.com\"" + local docker_passwd="echo \"초기 비밀번호:changeme\"" local app_size="1" docker_app @@ -15075,8 +15508,8 @@ while true; do } - local docker_describe="一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动" - local docker_url="官网介绍: ${gh_https_url}github.com/OpenListTeam/OpenList" + local docker_describe="gin 및 Solidjs로 구동되는 다중 저장소, 웹 브라우징 및 WebDAV를 지원하는 파일 목록 프로그램" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/OpenListTeam/OpenList" local docker_use="docker exec openlist ./openlist admin random" local docker_passwd="" local app_size="1" @@ -15093,8 +15526,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 비밀번호 설정:" admin_password docker run -d \ --name=webtop-ubuntu \ --security-opt seccomp=unconfined \ @@ -15116,8 +15549,8 @@ while true; do } - local docker_describe="webtop基于Ubuntu的容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -15127,7 +15560,7 @@ while true; do ;; 7|nezha) clear - send_stats "搭建哪吒" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -15136,20 +15569,20 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒监控 $check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" - echo "官网搭建文档: https://nezha.wiki/guide/dashboard.html" + echo -e "나타 모니터링$check_docker $update_status" + echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" + echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 使用" + echo "1. 사용" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -15196,8 +15629,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent 오프라인 BT 자기 다운로드 서비스" + local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -15206,7 +15639,7 @@ while true; do ;; 9|mail) - send_stats "搭建邮局" + send_stats "우체국을 짓다" clear install telnet local app_id="9" @@ -15216,44 +15649,44 @@ while true; do check_docker_image_update $docker_name clear - echo -e "邮局服务 $check_docker $update_status" - echo "poste.io 是一个开源的邮件服务器解决方案," - echo "视频介绍: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" + echo -e "우정$check_docker $update_status" + echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." + echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" - echo "端口检测" + echo "포트 감지" port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}端口 $port 当前可用${gl_bai}" + echo -e "${gl_lv}포트$port현재 사용 가능${gl_bai}" else - echo -e "${gl_hong}端口 $port 当前不可用${gl_bai}" + echo -e "${gl_hong}포트$port현재는 이용할 수 없습니다${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "방문 주소:" echo "https://$yuming" fi echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 설치 2. 업데이트 3. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" ip_address - echo "先解析这些DNS记录" + echo "먼저 이 DNS 레코드를 구문 분석하세요." echo "A mail $ipv4_address" echo "CNAME imap $yuming" echo "CNAME pop $yuming" @@ -15263,7 +15696,7 @@ while true; do echo "TXT ? ?" echo "" echo "------------------------" - echo "按任意键继续..." + echo "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install jq @@ -15282,9 +15715,9 @@ while true; do add_app_id clear - echo "poste.io已经安装完成" + echo "poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." echo "https://$yuming" echo "" @@ -15307,9 +15740,9 @@ while true; do add_app_id clear - echo "poste.io已经安装完成" + echo "poste.io가 설치되었습니다" echo "------------------------" - echo "您可以使用以下地址访问poste.io:" + echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." echo "https://$yuming" echo "" ;; @@ -15320,7 +15753,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "앱이 제거되었습니다." ;; *) @@ -15336,9 +15769,9 @@ while true; do 10|rocketchat) local app_id="10" - local app_name="Rocket.Chat聊天系统" - local app_text="Rocket.Chat 是一个开源的团队通讯平台,支持实时聊天、音视频通话、文件共享等多种功能," - local app_url="官方介绍: https://www.rocket.chat/" + local app_name="Rocket.Chat 채팅 시스템" + local app_text="Rocket.Chat은 실시간 채팅, 음성 및 영상 통화, 파일 공유 및 기타 기능을 지원하는 오픈 소스 팀 커뮤니케이션 플랫폼입니다." + local app_url="공식소개 : https://www.rocket.chat/" local docker_name="rocketchat" local docker_port="3897" local app_size="2" @@ -15354,7 +15787,7 @@ while true; do clear ip_address - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -15364,7 +15797,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已经安装完成" + echo "Rocket.chat이 설치되었습니다" check_docker_app_ip } @@ -15374,7 +15807,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -15404,10 +15837,10 @@ while true; do } - local docker_describe="禅道是通用的项目管理软件" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" - local docker_passwd="echo \"初始密码: 123456\"" + local docker_describe="ZenTao는 범용 프로젝트 관리 소프트웨어입니다" + local docker_url="공식 홈페이지 소개 : https://www.zentao.net/" + local docker_use="echo \"초기 사용자 이름: admin\"" + local docker_passwd="echo \"초기 비밀번호: 123456\"" local app_size="2" docker_app @@ -15433,8 +15866,8 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" - local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" + local docker_describe="Qinglong Panel은 예약된 작업 관리 플랫폼입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -15444,9 +15877,9 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="cloudreve网盘" - local app_text="cloudreve是一个支持多家云存储的网盘系统" - local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_name="클라우드리브 네트워크 디스크" + local app_text="cloudreve는 여러 클라우드 스토리지를 지원하는 네트워크 디스크 시스템입니다." + local app_url="영상 소개: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -15458,7 +15891,7 @@ while true; do cd /home/docker/cloud/ docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -15472,7 +15905,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -15498,8 +15931,8 @@ while true; do } - local docker_describe="简单图床是一个简单的图床程序" - local docker_url="官网介绍: ${gh_proxy}github.com/icret/EasyImages2.0" + local docker_describe="심플드로잉베드는 심플드로잉베드 프로그램입니다" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" local app_size="1" @@ -15526,8 +15959,8 @@ while true; do } - local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" - local docker_url="官网介绍: https://emby.media/" + local docker_describe="emby는 서버의 비디오 및 오디오를 구성하고 오디오 및 비디오를 클라이언트 장치로 스트리밍하는 데 사용할 수 있는 마스터-슬레이브 아키텍처 미디어 서버 소프트웨어입니다." + local docker_url="공식 홈페이지 소개 : https://emby.media/" local docker_use="" local docker_passwd="" local app_size="1" @@ -15547,8 +15980,8 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" - local docker_url="官网介绍: ${gh_proxy}github.com/wikihost-opensource/als" + local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" local app_size="1" @@ -15578,8 +16011,8 @@ while true; do } - local docker_describe="AdGuardHome是一款全网广告拦截与反跟踪软件,未来将不止是一个DNS服务器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_describe="AdGuardHome은 미래에 단순한 DNS 서버 이상의 역할을 할 네트워크 전체의 광고 차단 및 추적 방지 소프트웨어입니다." + local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -15607,8 +16040,8 @@ while true; do } - local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_describe="onlyoffice는 오픈 소스 온라인 오피스 도구로 매우 강력합니다!" + local docker_url="공식 홈페이지 소개 : https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -15617,7 +16050,7 @@ while true; do ;; 19|safeline) - send_stats "搭建雷池" + send_stats "천둥 웅덩이를 만들어라" local app_id="19" local docker_name=safeline-mgt @@ -15625,20 +16058,20 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "썬더 풀 서비스$check_docker" + echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 重置密码 4. 卸载" + echo "1. 설치 2. 업데이트 3. 비밀번호 재설정 4. 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) @@ -15648,7 +16081,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已经安装完成" + echo "Leichi WAF 패널이 설치되었습니다." check_docker_app_ip docker exec safeline-mgt resetadmin @@ -15661,7 +16094,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已经更新完成" + echo "Leichi WAF 패널이 업데이트되었습니다." check_docker_app_ip ;; 3) @@ -15672,7 +16105,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是默认安装目录那现在项目已经卸载。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "기본 설치 디렉터리에 있다면 이제 프로젝트가 제거된 것입니다. 설치 디렉터리를 사용자 정의하는 경우 설치 디렉터리로 이동하여 직접 실행해야 합니다." echo "docker compose down && docker compose down --rmi all" ;; *) @@ -15704,8 +16137,8 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" - local docker_url="官网介绍: https://www.portainer.io/" + local docker_describe="portainer는 경량 도커 컨테이너 관리 패널입니다." + local docker_url="공식 홈페이지 소개 : https://www.portainer.io/" local docker_use="" local docker_passwd="" local app_size="1" @@ -15727,8 +16160,8 @@ while true; do } - local docker_describe="VScode是一款强大的在线代码编写工具" - local docker_url="官网介绍: ${gh_proxy}github.com/coder/code-server" + local docker_describe="VScode는 강력한 온라인 코드 작성 도구입니다" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/coder/code-server" local docker_use="sleep 3" local docker_passwd="docker exec vscode-web cat /home/coder/.config/code-server/config.yaml" local app_size="1" @@ -15755,8 +16188,8 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/uptime-kuma" + local docker_describe="가동 시간 Kuma 사용하기 쉬운 자체 호스팅 모니터링 도구" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" local app_size="1" @@ -15775,8 +16208,8 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" - local docker_url="官网介绍: ${gh_proxy}github.com/usememos/memos" + local docker_describe="Memos는 경량의 자체 호스팅 메모 센터입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" local app_size="1" @@ -15791,8 +16224,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password + read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 비밀번호 설정:" admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -15816,8 +16249,8 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" - local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -15837,9 +16270,9 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" - local docker_use="echo \"账号: nextcloud 密码: $rootpasswd\"" + local docker_describe="400,000개 이상 배포된 Nextcloud는 다운로드할 수 있는 가장 인기 있는 로컬 콘텐츠 협업 플랫폼입니다." + local docker_url="공식 홈페이지 소개 : https://nextcloud.com/" + local docker_use="echo \"계정: nextcloud 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="3" docker_app @@ -15857,8 +16290,8 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" - local docker_url="官网介绍: https://qd-today.github.io/qd/zh_CN/" + local docker_describe="QD-Today는 HTTP 요청 예약 작업 자동 실행 프레임워크입니다." + local docker_url="공식 홈페이지 소개: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" local app_size="1" @@ -15877,8 +16310,8 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" - local docker_url="官网介绍: ${gh_proxy}github.com/louislam/dockge" + local docker_describe="Dockge는 시각적 Docker 작성 컨테이너 관리 패널입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" local app_size="1" @@ -15897,8 +16330,8 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" - local docker_url="官网介绍: ${gh_proxy}github.com/librespeed/speedtest" + local docker_describe="librespeed는 즉시 사용할 수 있는 Javascript로 구현된 경량 속도 테스트 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" local app_size="1" @@ -15922,8 +16355,8 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" - local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" + local docker_describe="searxng는 비공개 및 비공개 검색 엔진 사이트입니다." + local docker_url="공식 홈페이지 소개 : https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -15954,9 +16387,9 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" - local docker_url="官网介绍: https://www.photoprism.app/" - local docker_use="echo \"账号: admin 密码: $rootpasswd\"" + local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." + local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" + local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" docker_app @@ -15982,8 +16415,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="这是一个强大的本地托管基于 Web 的 PDF 操作工具,使用 docker,允许您对 PDF 文件执行各种操作,例如拆分合并、转换、重新组织、添加图像、旋转、压缩等。" - local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -16003,8 +16436,8 @@ while true; do } - local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" - local docker_url="官网介绍: https://www.drawio.com/" + local docker_describe="이것은 강력한 차트 작성 소프트웨어입니다. 마인드맵, 토폴로지 다이어그램, 흐름도를 그릴 수 있습니다." + local docker_url="공식 홈페이지 소개 : https://www.drawio.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16028,9 +16461,9 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" - local docker_url="官网介绍: https://doc.sun-panel.top/zh_cn/" - local docker_use="echo \"账号: admin@sun.cc 密码: 12345678\"" + local docker_describe="Sun-Panel 서버, NAS 탐색 패널, 홈페이지, 브라우저 홈페이지" + local docker_url="공식 홈페이지 소개: https://doc.sun-panel.top/zh_cn/" + local docker_use="echo \"계정: admin@sun.cc 비밀번호: 12345678\"" local docker_passwd="" local app_size="1" docker_app @@ -16052,8 +16485,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" - local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share는 자체 구축 가능한 파일 공유 플랫폼이자 WeTransfer의 대안입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -16079,9 +16512,9 @@ while true; do } - local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" - local docker_url="官网介绍: ${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_describe="미니멀리스트 순간, 높은 모방 WeChat 순간, 멋진 삶을 기록하세요" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" + local docker_use="echo \"계정: admin 비밀번호: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -16103,8 +16536,8 @@ while true; do lobehub/lobe-chat } - local docker_describe="LobeChat聚合市面上主流的AI大模型,ChatGPT/Claude/Gemini/Groq/Ollama" - local docker_url="官网介绍: ${gh_proxy}github.com/lobehub/lobe-chat" + local docker_describe="LobeChat은 시장의 주류 AI 대형 모델인 ChatGPT/Claude/Gemini/Groq/Ollama를 통합합니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/lobehub/lobe-chat" local docker_use="" local docker_passwd="" local app_size="2" @@ -16124,8 +16557,8 @@ while true; do } - local docker_describe="是一个多功能IP工具箱,可以查看自己IP信息及连通性,用网页面板呈现" - local docker_url="官网介绍: ${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" + local docker_describe="자신의 IP 정보와 연결성을 확인하고 웹 패널을 통해 표시할 수 있는 다기능 IP 도구 상자입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/jason5ng32/MyIP/blob/main/README_ZH.md" local docker_use="" local docker_passwd="" local app_size="1" @@ -16133,7 +16566,7 @@ while true; do ;; 38|xiaoya) - send_stats "小雅全家桶" + send_stats "Xiaoya 가족 버킷" clear install_docker check_disk_space 1 @@ -16158,8 +16591,8 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" - local docker_url="官网介绍: ${gh_proxy}github.com/hr3lxphr6j/bililive-go" + local docker_describe="Bililive-go는 다양한 라이브 방송 플랫폼을 지원하는 라이브 방송 녹음 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -16175,8 +16608,8 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="简易在线ssh连接工具和sftp工具" - local docker_url="官网介绍: ${gh_proxy}github.com/Jrohy/webssh" + local docker_describe="간단한 온라인 SSH 연결 도구 및 SFTP 도구" + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" local app_size="1" @@ -16187,8 +16620,8 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 原耗子面板" - local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" + local panelname="AcePanel 오리지널 마우스 패널" + local panelurl="공식 주소:${gh_proxy}github.com/acepanel/panel" panel_app_install() { cd ~ @@ -16229,8 +16662,8 @@ while true; do } - local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" - local docker_url="官网介绍: ${gh_proxy}github.com/gnmyt/Nexterm" + local docker_describe="nexterm은 강력한 온라인 SSH/VNC/RDP 연결 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" local app_size="1" @@ -16250,10 +16683,10 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" + local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(서버)은 자체 Sunflower 개인 서버와 유사합니다." + local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" + local docker_passwd="echo \"원격 데스크톱 클라이언트에서 사용될 IP와 키를 기록하세요. 릴레이를 설치하려면 옵션 44로 이동하세요!\"" local app_size="1" docker_app ;; @@ -16270,9 +16703,9 @@ while true; do } - local docker_describe="rustdesk开源的远程桌面(中继端),类似自己的向日葵私服。" - local docker_url="官网介绍: https://rustdesk.com/zh-cn/" - local docker_use="echo \"前往官网下载远程桌面的客户端: https://rustdesk.com/zh-cn/\"" + local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(릴레이)은 자체 Sunflower 개인 서버와 유사합니다." + local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" + local docker_use="echo \"원격 데스크톱 클라이언트를 다운로드하려면 공식 웹사이트로 이동하세요: https://rustdesk.com/zh-cn/\"" local docker_passwd="" local app_size="1" docker_app @@ -16296,8 +16729,8 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" - local docker_url="官网介绍: https://hub.docker.com/_/registry" + local docker_describe="Docker Registry는 Docker 이미지를 저장하고 배포하는 서비스입니다." + local docker_url="공식 홈페이지 소개: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" local app_size="2" @@ -16316,8 +16749,8 @@ while true; do } - local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" - local docker_url="官网介绍: ${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" + local docker_describe="Go를 사용하여 구현된 GHProxy는 일부 영역에서 Github 저장소 가져오기를 가속화하는 데 사용됩니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" local app_size="1" @@ -16327,9 +16760,9 @@ while true; do 47|prometheus|grafana) local app_id="47" - local app_name="普罗米修斯监控" - local app_text="Prometheus+Grafana企业级监控系统" - local app_url="官网介绍: https://prometheus.io" + local app_name="프로메테우스 모니터링" + local app_text="Prometheus+Grafana 전사적 모니터링 시스템" + local app_url="공식 홈페이지 소개 : https://prometheus.io" local docker_name="grafana" local docker_port="8047" local app_size="2" @@ -16338,9 +16771,9 @@ while true; do prometheus_install clear ip_address - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip - echo "初始用户名密码均为: admin" + echo "초기 사용자 이름과 비밀번호는 admin입니다." } docker_app_update() { @@ -16358,7 +16791,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -16381,8 +16814,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: ${gh_https_url}github.com/prometheus/node_exporter" + local docker_describe="이는 Prometheus 호스트 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -16411,8 +16844,8 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" - local docker_url="官网介绍: ${gh_https_url}github.com/google/cadvisor" + local docker_describe="이는 Prometheus 컨테이너 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" local app_size="1" @@ -16434,8 +16867,8 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" - local docker_url="官网介绍: ${gh_https_url}github.com/dgtlmoon/changedetection.io" + local docker_describe="이는 웹사이트 변경 감지, 보충 모니터링 및 알림을 위한 작은 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" local app_size="1" @@ -16445,7 +16878,7 @@ while true; do 51|pve) clear - send_stats "PVE开小鸡" + send_stats "PVE 오픈 병아리" check_disk_space 1 curl -L ${gh_proxy}raw.githubusercontent.com/oneclickvirt/pve/main/scripts/install_pve.sh -o install_pve.sh && chmod +x install_pve.sh && bash install_pve.sh ;; @@ -16467,8 +16900,8 @@ while true; do } - local docker_describe="Docker可视化面板系统,提供完善的docker管理功能。" - local docker_url="官网介绍: ${gh_https_url}github.com/donknap/dpanel" + local docker_describe="Docker 시각적 패널 시스템은 완전한 Docker 관리 기능을 제공합니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/donknap/dpanel" local docker_use="" local docker_passwd="" local app_size="1" @@ -16487,8 +16920,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" - local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" local app_size="5" @@ -16499,8 +16932,8 @@ while true; do local app_id="54" local lujing="[ -d "/www/server/panel" ]" - local panelname="AMH面板" - local panelurl="官方地址: https://amh.sh/index.htm?amh" + local panelname="AMH 패널" + local panelurl="공식 주소 : https://amh.sh/index.htm?amh" panel_app_install() { cd ~ @@ -16539,8 +16972,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的DeepSeek R1大语言模型" - local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 새로운 DeepSeek R1 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run deepseek-r1:1.5b" local docker_passwd="" local app_size="5" @@ -16550,9 +16983,9 @@ while true; do 58|dify) local app_id="58" - local app_name="Dify知识库" - local app_text="是一款开源的大语言模型(LLM) 应用开发平台。自托管训练数据用于AI生成" - local app_url="官方网站: https://docs.dify.ai/zh-hans" + local app_name="DifyKnowledge Base" + local app_text="오픈 소스 LLM(대형 언어 모델) 애플리케이션 개발 플랫폼입니다. AI 생성을 위한 자체 호스팅 학습 데이터" + local app_url="공식 홈페이지: https://docs.dify.ai/zh-hans" local docker_name="docker-nginx-1" local docker_port="8058" local app_size="3" @@ -16570,7 +17003,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -16585,7 +17018,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -16595,8 +17028,8 @@ while true; do 59|new-api) local app_id="59" local app_name="NewAPI" - local app_text="新一代大模型网关与AI资产管理系统" - local app_url="官方网站: ${gh_https_url}github.com/Calcium-Ion/new-api" + local app_text="차세대 대형 모델 게이트웨이 및 AI 자산 관리 시스템" + local app_url="공식 웹사이트:${gh_https_url}github.com/Calcium-Ion/new-api" local docker_name="new-api" local docker_port="8059" local app_size="3" @@ -16613,7 +17046,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -16629,7 +17062,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -16637,7 +17070,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -16648,9 +17081,9 @@ while true; do 60|jms) local app_id="60" - local app_name="JumpServer开源堡垒机" - local app_text="是一个开源的特权访问管理 (PAM) 工具,该程序占用80端口不支持添加域名访问了" - local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" + local app_name="JumpServer 오픈 소스 요새 머신" + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -16658,17 +17091,17 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: ChangeMe" + echo "초기 사용자 이름: admin" + echo "초기 비밀번호: ChangeMe" } docker_app_update() { cd /opt/jumpserver-installer*/ ./jmsctl.sh upgrade - echo "应用已更新" + echo "앱이 업데이트되었습니다" } @@ -16678,7 +17111,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -16700,8 +17133,8 @@ while true; do } - local docker_describe="免费开源机器翻译 API,完全自托管,它的翻译引擎由开源Argos Translate库提供支持。" - local docker_url="官网介绍: ${gh_https_url}github.com/LibreTranslate/LibreTranslate" + local docker_describe="무료 오픈 소스 기계 번역 API, 완전 자체 호스팅 및 번역 엔진은 오픈 소스 Argos Translate 라이브러리에 의해 구동됩니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreTranslate/LibreTranslate" local docker_use="" local docker_passwd="" local app_size="5" @@ -16712,9 +17145,9 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知识库" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" - local app_url="官方网站: ${gh_https_url}github.com/infiniflow/ragflow" + local app_name="RAGFlow 지식 기반" + local app_text="깊은 문서 이해를 기반으로 한 오픈소스 RAG(Retrieval Augmented Generation) 엔진" + local app_url="공식 웹사이트:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" local app_size="8" @@ -16725,7 +17158,7 @@ while true; do sed -i "s/- 80:80/- ${docker_port}:80/; /- 443:443/d" docker-compose.yml docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -16741,7 +17174,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -16761,8 +17194,8 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,官方精简版本,支持各大模型API接入" - local docker_url="官网介绍: ${gh_https_url}github.com/open-webui/open-webui" + local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 단순화 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" local app_size="3" @@ -16779,8 +17212,8 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" - local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" + local docker_describe="개발자와 IT 작업자에게 매우 유용한 도구" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -16815,8 +17248,8 @@ while true; do } - local docker_describe="是一款功能强大的自动化工作流平台" - local docker_url="官网介绍: ${gh_https_url}github.com/n8n-io/n8n" + local docker_describe="강력한 자동화된 워크플로우 플랫폼입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/n8n-io/n8n" local docker_use="" local docker_passwd="" local app_size="1" @@ -16844,8 +17277,8 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" - local docker_url="官网介绍: ${gh_https_url}github.com/jeessy2/ddns-go" + local docker_describe="동적 도메인 이름 확인을 위해 공용 IP(IPv4/IPv6)를 주요 DNS 서비스 제공업체에 실시간으로 자동 업데이트합니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" local app_size="1" @@ -16862,10 +17295,10 @@ while true; do docker run -d --name allinssl -p ${docker_port}:8888 -v /home/docker/allinssl/data:/www/allinssl/data -e ALLINSSL_USER=allinssl -e ALLINSSL_PWD=allinssldocker -e ALLINSSL_URL=allinssl allinssl/allinssl:latest } - local docker_describe="开源免费的 SSL 证书自动化管理平台" - local docker_url="官网介绍: https://allinssl.com" - local docker_use="echo \"安全入口: /allinssl\"" - local docker_passwd="echo \"用户名: allinssl 密码: allinssldocker\"" + local docker_describe="오픈 소스 무료 SSL 인증서 자동화 관리 플랫폼" + local docker_url="공식 홈페이지 소개: https://allinssl.com" + local docker_use="echo \"보안 입구: /allinssl\"" + local docker_passwd="echo \"사용자 이름: allinssl 비밀번호: allinssldocker\"" local app_size="1" docker_app ;; @@ -16894,8 +17327,8 @@ while true; do } - local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" - local docker_url="官网介绍: https://sftpgo.com/" + local docker_describe="언제 어디서나 무료 오픈 소스 SFTP FTP WebDAV 파일 전송 도구" + local docker_url="공식 홈페이지 소개 : https://sftpgo.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16926,9 +17359,9 @@ while true; do } - local docker_describe="开源AI聊天机器人框架,支持微信,QQ,TG接入AI大模型" - local docker_url="官网介绍: https://astrbot.app/" - local docker_use="echo \"用户名: astrbot 密码: astrbot\"" + local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_url="공식 홈페이지 소개: https://astrbot.app/" + local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" local app_size="1" docker_app @@ -16955,8 +17388,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="경량, 고성능 음악 스트리밍 서버입니다." + local docker_url="공식 홈페이지 소개 : https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -16982,8 +17415,8 @@ while true; do } - local docker_describe="一个你可以控制数据的密码管理器" - local docker_url="官网介绍: https://bitwarden.com/" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17003,7 +17436,7 @@ while true; do docker_rum() { - read -e -p "设置LibreTV的登录密码: " app_passwd + read -e -p "LibreTV 로그인 비밀번호 설정:" app_passwd docker run -d \ --name libretv \ @@ -17014,8 +17447,8 @@ while true; do } - local docker_describe="免费在线视频搜索与观看平台" - local docker_url="官网介绍: ${gh_https_url}github.com/LibreSpark/LibreTV" + local docker_describe="무료 온라인 비디오 검색 및 시청 플랫폼" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" local app_size="1" @@ -17029,17 +17462,17 @@ while true; do local app_id="74" - local app_name="moontv私有影视" - local app_text="免费在线视频搜索与观看平台" - local app_url="视频介绍: ${gh_https_url}github.com/MoonTechLab/LunaTV" + local app_name="Moontv 개인 영화 및 TV" + local app_text="무료 온라인 비디오 검색 및 시청 플랫폼" + local app_url="비디오 소개:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" local app_size="2" docker_app_install() { - read -e -p "设置登录用户名: " admin - read -e -p "设置登录用户密码: " admin_password - read -e -p "输入授权码: " shouquanma + read -e -p "로그인 사용자 이름 설정:" admin + read -e -p "로그인 사용자 비밀번호 설정:" admin_password + read -e -p "인증 코드 입력:" shouquanma mkdir -p /home/docker/moontv @@ -17055,7 +17488,7 @@ while true; do cd /home/docker/moontv/ docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17069,7 +17502,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17096,8 +17529,8 @@ while true; do } - local docker_describe="你的音乐精灵,旨在帮助你更好地管理音乐。" - local docker_url="官网介绍: ${gh_https_url}github.com/foamzou/melody" + local docker_describe="음악을 더 잘 관리할 수 있도록 설계된 음악 마법사입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/foamzou/melody" local docker_use="" local docker_passwd="" local app_size="1" @@ -17123,8 +17556,8 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" - local docker_url="官网介绍: ${gh_https_url}github.com/rwv/chinese-dos-games" + local docker_describe="중국의 DOS 게임 컬렉션 웹사이트입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" local app_size="2" @@ -17142,8 +17575,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "로그인 사용자 이름 설정:" app_use + read -e -p "로그인 비밀번호 설정:" app_passwd docker run -d \ --name xunlei \ @@ -17158,9 +17591,9 @@ while true; do } - local docker_describe="迅雷你的离线高速BT磁力下载工具" - local docker_url="官网介绍: ${gh_https_url}github.com/cnk3x/xunlei" - local docker_use="echo \"手机登录迅雷,再输入邀请码,邀请码: 迅雷牛通\"" + local docker_describe="오프라인 고속 BT 자기 다운로드 도구인 Xunlei" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/cnk3x/xunlei" + local docker_use="echo \"휴대폰으로 Xunlei에 로그인하고 초대 코드를 입력하세요. 초대 코드: Xunlei Niutong\"" local docker_passwd="" local app_size="1" docker_app @@ -17173,8 +17606,8 @@ while true; do local app_id="78" local app_name="PandaWiki" - local app_text="PandaWiki是一款AI大模型驱动的开源智能文档管理系统,强烈建议不要自定义端口部署。" - local app_url="官方介绍: ${gh_https_url}github.com/chaitin/PandaWiki" + local app_text="PandaWiki는 AI 대형 모델을 기반으로 하는 오픈 소스 지능형 문서 관리 시스템입니다. 포트 배포를 사용자 정의하지 않는 것이 좋습니다." + local app_url="공식 소개:${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -17216,8 +17649,8 @@ while true; do } - local docker_describe="Beszel轻量易用的服务器监控" - local docker_url="官网介绍: https://beszel.dev/zh/" + local docker_describe="Beszel은 가볍고 사용하기 쉬운 서버 모니터링입니다." + local docker_url="공식 홈페이지 소개: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17229,9 +17662,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden书签管理" - local app_text="一个开源的自托管书签管理平台,支持标签、搜索和团队协作。" - local app_url="官方网站: https://linkwarden.app/" + local app_name="링크워든 북마크 관리" + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -17240,11 +17673,11 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 공식 docker-compose 및 env 파일 다운로드 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" - # 生成随机密钥与密码 + # 임의의 키와 비밀번호 생성 local ADMIN_EMAIL="admin@example.com" local ADMIN_PASSWORD=$(openssl rand -hex 8) @@ -17253,17 +17686,17 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # 追加管理员账号信息 + # 관리자 계정 정보 추가 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env sed -i "s/3000:3000/${docker_port}:3000/g" /home/docker/linkwarden/docker-compose.yml - # 启动容器 + # 컨테이너 시작 docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17273,7 +17706,7 @@ while true; do curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env.new" - # 保留原本的变量 + # 원래 변수 유지 source .env mv .env.new .env echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env @@ -17290,7 +17723,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17301,9 +17734,9 @@ while true; do 81|jitsi) local app_id="81" - local app_name="JitsiMeet视频会议" - local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" - local app_url="官方网站: https://jitsi.org/" + local app_name="JitsiMeet 화상 회의" + local app_text="다자간 온라인 회의, 화면 공유, 암호화된 통신을 지원하는 오픈 소스 보안 화상 회의 솔루션입니다." + local app_url="공식 홈페이지: https://jitsi.org/" local docker_name="jitsi" local docker_port="8081" local app_size="3" @@ -17340,7 +17773,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17358,7 +17791,7 @@ while true; do docker_rum() { - read -e -p "设置${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "설정${docker_name}로그인 키(sk-다음과 같이 시작하는 문자와 숫자의 조합): sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -17369,8 +17802,8 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_describe="고성능 AI 인터페이스 투명 프록시 서비스" + local docker_url="공식 홈페이지 소개: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17402,9 +17835,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" - local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_describe="경량 자체 호스팅 서버 모니터링 도구" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/komari-monitor/komari/tree/main" + local docker_use="echo \"기본 계정: admin 기본 비밀번호: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -17433,8 +17866,8 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" - local docker_url="官网介绍: ${gh_https_url}github.com/ellite/Wallos" + local docker_describe="재무 관리를 위한 오픈 소스 개인 구독 추적기" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" local app_size="1" @@ -17445,9 +17878,9 @@ while true; do 85|immich) local app_id="85" - local app_name="immich图片视频管理器" - local app_text="高性能自托管照片和视频管理解决方案。" - local app_url="官网介绍: ${gh_https_url}github.com/immich-app/immich" + local app_name="이미치 픽처 비디오 매니저" + local app_text="고성능 자체 호스팅 사진 및 비디오 관리 솔루션입니다." + local app_url="공식 웹사이트 소개:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -17463,7 +17896,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17476,7 +17909,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17511,8 +17944,8 @@ while true; do } - local docker_describe="是一款开源媒体服务器软件" - local docker_url="官网介绍: https://jellyfin.org/" + local docker_describe="오픈 소스 미디어 서버 소프트웨어입니다" + local docker_url="공식 홈페이지 소개 : https://jellyfin.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17539,9 +17972,9 @@ while true; do } - local docker_describe="远程一起观看电影和直播的程序。它提供了同步观影、直播、聊天等功能" - local docker_url="官网介绍: ${gh_https_url}github.com/synctv-org/synctv" - local docker_use="echo \"初始账号和密码: root 登陆后请及时修改登录密码\"" + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -17569,10 +18002,10 @@ while true; do } - local docker_describe="开源、免费的自建直播平台" - local docker_url="官网介绍: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" + local docker_url="공식 홈페이지 소개 : https://owncast.online" + local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -17598,10 +18031,10 @@ while true; do } - local docker_describe="匿名口令分享文本和文件,像拿快递一样取文件" - local docker_url="官网介绍: ${gh_https_url}github.com/vastsa/FileCodeBox" - local docker_use="echo \"访问地址后面带 /#/admin 访问管理员页面\"" - local docker_passwd="echo \"管理员密码: FileCodeBox2023\"" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" + local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" + local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" local app_size="1" docker_app @@ -17637,7 +18070,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "创建初始用户或管理员。请设置以下内容用户名和密码以及是否为管理员。" + echo "초기 사용자 또는 관리자를 생성합니다. 다음 사용자 이름과 비밀번호를 설정하고 관리자인지 여부를 설정하세요." docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -17654,8 +18087,8 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" - local docker_url="官网介绍: https://matrix.org/" + local docker_describe="Matrix는 분산형 채팅 프로토콜입니다." + local docker_url="공식 홈페이지 소개 : https://matrix.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -17669,9 +18102,9 @@ while true; do local app_id="91" - local app_name="gitea私有代码仓库" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" - local app_url="视频介绍: ${gh_https_url}github.com/go-gitea/gitea" + local app_name="gitea 비공개 코드 저장소" + local app_text="GitHub에 가까운 경험을 제공하는 무료 차세대 코드 호스팅 플랫폼입니다." + local app_url="비디오 소개:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" local app_size="2" @@ -17689,7 +18122,7 @@ while true; do cd /home/docker/gitea/ docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17703,7 +18136,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17733,8 +18166,8 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_describe="웹 기반 파일 관리자입니다" + local docker_url="공식 홈페이지 소개 : https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -17760,8 +18193,8 @@ while true; do } - local docker_describe="极简静态文件服务器,支持上传下载" - local docker_url="官网介绍: ${gh_https_url}github.com/sigoden/dufs" + local docker_describe="미니멀리스트 정적 파일 서버, 업로드 및 다운로드 지원" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -17778,8 +18211,8 @@ while true; do docker_rum() { - read -e -p "设置登录用户名: " app_use - read -e -p "设置登录密码: " app_passwd + read -e -p "로그인 사용자 이름 설정:" app_use + read -e -p "로그인 비밀번호 설정:" app_passwd docker run -d \ --name ${docker_name} \ @@ -17791,8 +18224,8 @@ while true; do } - local docker_describe="分布式高速下载工具,支持多种协议" - local docker_url="官网介绍: ${gh_https_url}github.com/GopeedLab/gopeed" + local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" local app_size="1" @@ -17806,9 +18239,9 @@ while true; do local app_id="95" - local app_name="paperless文档管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_name="종이 없는 문서 관리 플랫폼" + local app_text="오픈 소스 전자 문서 관리 시스템으로, 주요 목적은 종이 문서를 디지털화하고 관리하는 것입니다." + local app_url="영상 소개: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -17827,7 +18260,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17841,7 +18274,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17854,9 +18287,9 @@ while true; do local app_id="96" - local app_name="2FAuth自托管二步验证器" - local app_text="自托管的双重身份验证 (2FA) 账户管理和验证码生成工具。" - local app_url="官网: ${gh_https_url}github.com/Bubka/2FAuth" + local app_name="2FAuth 자체 호스팅 2단계 인증자" + local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." + local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" local app_size="1" @@ -17881,7 +18314,7 @@ while true; do block_container_port "$docker_name" "$ipv4_address" clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -17895,7 +18328,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -17913,9 +18346,9 @@ while true; do docker_rum() { - read -e -p "请输入组网的客户端数量 (默认 5): " COUNT + read -e -p "네트워크의 클라이언트 수를 입력하십시오(기본값 5):" COUNT COUNT=${COUNT:-5} - read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + read -e -p "WireGuard 네트워크 세그먼트(기본값 10.13.13.0)를 입력하세요." NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -17985,24 +18418,24 @@ while true; do sleep 2 echo - echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" + echo -e "${gl_huang}모든 클라이언트 QR 코드 구성:${gl_bai}" docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo - echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" + echo -e "${gl_huang}모든 클라이언트 구성 코드:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" - echo -e "${gl_lv}1. 手机下载wg的APP,扫描上方二维码,可以快速连接网络${gl_bai}" - echo -e "${gl_lv}2. Windows下载客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" - echo -e "${gl_lv}官方客户端下载方式: https://www.wireguard.com/install/${gl_bai}" + echo -e "${gl_lv}${COUNT}각 클라이언트에 대한 모든 출력을 구성합니다. 사용방법은 다음과 같습니다.${gl_bai}" + echo -e "${gl_lv}1. 휴대폰에 wg APP을 다운로드하고 위의 QR 코드를 스캔하면 빠르게 인터넷에 연결됩니다.${gl_bai}" + echo -e "${gl_lv}2. Windows용 클라이언트를 다운로드하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" + echo -e "${gl_lv}3. 스크립트를 사용하여 Linux에 WG 클라이언트를 배포하고 구성 코드를 복사하여 네트워크에 연결합니다.${gl_bai}" + echo -e "${gl_lv}공식 클라이언트 다운로드 방법: https://www.wireguard.com/install/${gl_bai}" break_end } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="최신 고성능 가상 사설망 도구" + local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18024,16 +18457,16 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # 디렉터리가 없으면 생성 mkdir -p "$(dirname "$CONFIG_FILE")" - echo "请粘贴你的客户端配置,连续按两次回车保存:" + echo "클라이언트 구성을 붙여넣고 Enter를 두 번 눌러 저장하세요." - # 初始化变量 + # 변수 초기화 input="" empty_line_count=0 - # 逐行读取用户输入 + # 사용자 입력을 한 줄씩 읽습니다. while IFS= read -r line; do if [[ -z "$line" ]]; then ((empty_line_count++)) @@ -18046,10 +18479,10 @@ while true; do fi done - # 写入配置文件 + # 구성 파일 쓰기 echo "$input" > "$CONFIG_FILE" - echo "客户端配置已保存到 $CONFIG_FILE" + echo "클라이언트 구성이 다음에 저장되었습니다.$CONFIG_FILE" ip link delete wg0 &>/dev/null @@ -18071,8 +18504,8 @@ while true; do } - local docker_describe="现代化、高性能的虚拟专用网络工具" - local docker_url="官网介绍: https://www.wireguard.com/" + local docker_describe="최신 고성능 가상 사설망 도구" + local docker_url="공식 홈페이지 소개 : https://www.wireguard.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18085,19 +18518,19 @@ while true; do local app_id="99" - local app_name="dsm群晖虚拟机" - local app_text="Docker容器中的虚拟DSM" - local app_url="官网: ${gh_https_url}github.com/vdsm/virtual-dsm" + local app_name="dsm 시놀로지 가상 머신" + local app_text="Docker 컨테이너의 가상 DSM" + local app_url="공식 웹사이트:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" docker_app_install() { - read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES + read -e -p "CPU 코어 수를 설정합니다(기본값 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "设置内存大小 (默认 4G): " RAM_SIZE + read -e -p "메모리 크기 설정(기본 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -18114,7 +18547,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -18128,7 +18561,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -18157,8 +18590,8 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" - local docker_url="官网介绍: ${gh_https_url}github.com/syncthing/syncthing" + local docker_describe="Dropbox 및 Resilio Sync와 유사하지만 완전히 분산된 오픈 소스 P2P 파일 동기화 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" local app_size="1" @@ -18169,9 +18602,9 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI视频生成工具" - local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" - local app_url="官方网站: ${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" + local app_name="AI 영상 생성 도구" + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" local app_size="3" @@ -18183,7 +18616,7 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -18199,7 +18632,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -18225,8 +18658,8 @@ while true; do } - local docker_describe="是一款支持独立部署的个人云社交媒体聊天服务" - local docker_url="官网介绍: ${gh_https_url}github.com/Privoce/vocechat-web" + local docker_describe="독립적인 배포를 지원하는 개인용 클라우드 소셜 미디어 채팅 서비스입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/Privoce/vocechat-web" local docker_use="" local docker_passwd="" local app_size="1" @@ -18237,9 +18670,9 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami网站统计工具" - local app_text="开源、轻量、隐私友好的网站分析工具,类似于GoogleAnalytics。" - local app_url="官方网站: ${gh_https_url}github.com/umami-software/umami" + local app_name="Umami 웹사이트 통계 도구" + local app_text="Google Analytics와 유사한 오픈 소스, 가볍고 개인정보 보호 친화적인 웹사이트 분석 도구입니다." + local app_url="공식 웹사이트:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" local docker_port="8103" local app_size="1" @@ -18251,10 +18684,10 @@ while true; do docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip - echo "初始用户名: admin" - echo "初始密码: umami" + echo "초기 사용자 이름: admin" + echo "초기 비밀번호 : umami" } docker_app_update() { @@ -18268,7 +18701,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -18289,7 +18722,7 @@ while true; do docker_rum() { - read -e -p "设置登录密码: " app_passwd + read -e -p "로그인 비밀번호 설정:" app_passwd docker run -d \ --name siyuan \ @@ -18304,8 +18737,8 @@ while true; do } - local docker_describe="思源笔记是一款隐私优先的知识管理系统" - local docker_url="官网介绍: ${gh_https_url}github.com/siyuan-note/siyuan" + local docker_describe="Siyuan Notes는 개인 정보 보호를 최우선으로 하는 지식 관리 시스템입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/siyuan-note/siyuan" local docker_use="" local docker_passwd="" local app_size="1" @@ -18331,8 +18764,8 @@ while true; do } - local docker_describe="是一款强大的开源白板工具,集成思维导图、流程图等。" - local docker_url="官网介绍: ${gh_https_url}github.com/plait-board/drawnix" + local docker_describe="마인드맵, 플로우차트 등을 통합한 강력한 오픈소스 화이트보드 도구입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/plait-board/drawnix" local docker_use="" local docker_passwd="" local app_size="1" @@ -18366,8 +18799,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="PanSou是一个高性能的网盘资源搜索API服务。" - local docker_url="官网介绍: ${gh_https_url}github.com/fish2018/pansou" + local docker_describe="PanSou는 고성능 네트워크 디스크 리소스 검색 API 서비스입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -18380,9 +18813,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 108|langbot) local app_id="108" - local app_name="LangBot聊天机器人" - local app_text="是一个开源的大语言模型原生即时通信机器人开发平台" - local app_url="官方网站: ${gh_https_url}github.com/langbot-app/LangBot" + local app_name="LangBot 챗봇" + local app_text="오픈 소스 대형 언어 모델 기반 인스턴트 메시징 로봇 개발 플랫폼입니다." + local app_url="공식 웹사이트:${gh_https_url}github.com/langbot-app/LangBot" local docker_name="langbot_plugin_runtime" local docker_port="8108" local app_size="1" @@ -18394,7 +18827,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -18409,7 +18842,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -18438,8 +18871,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" - local docker_url="官网介绍: ${gh_https_url}github.com/zfile-dev/zfile" + local docker_describe="개인이나 소규모 팀에 적합한 온라인 네트워크 디스크 프로그램입니다." + local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -18450,9 +18883,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" - local app_name="karakeep书签管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" - local app_url="官方网站: ${gh_https_url}github.com/karakeep-app/karakeep" + local app_name="karakeep 북마크 관리" + local app_text="데이터 수집가를 위해 설계된 인공 지능 기능을 갖춘 자체 호스팅 북마크 앱입니다." + local app_url="공식 웹사이트:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" local app_size="1" @@ -18464,7 +18897,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker compose up -d clear - echo "已经安装完成" + echo "설치 완료" check_docker_app_ip } @@ -18479,7 +18912,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "应用已卸载" + echo "앱이 제거되었습니다." } docker_app_plus @@ -18504,8 +18937,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个功能强大的多格式文件转换工具(支持文档、图像、音频视频等)强烈建议添加域名访问" - local docker_url="项目地址: ${gh_https_url}github.com/c4illin/ConvertX" + local docker_describe="강력한 다중 형식 파일 변환 도구입니다(문서, 이미지, 오디오 및 비디오 등 지원). 도메인 이름 액세스를 추가하는 것이 좋습니다." + local docker_url="프로젝트 주소:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" local app_size="2" @@ -18519,7 +18952,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -18530,15 +18963,15 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - echo "正在等待 Lucky 初始化..." + echo "Lucky가 초기화되기를 기다리는 중..." sleep 10 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} } - local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" - local docker_url="项目地址: ${gh_https_url}github.com/gdy666/lucky" - local docker_use="echo \"默认账号密码: 666\"" + local docker_describe="Lucky는 DDNS, 역방향 프록시, WOL 및 기타 기능을 지원하는 대규모 인트라넷 침투 및 포트 전달 관리 도구입니다." + local docker_url="프로젝트 주소:${gh_https_url}github.com/gdy666/lucky" + local docker_use="echo \"기본 계정 비밀번호: 666\"" local docker_passwd="" local app_size="1" docker_app @@ -18555,7 +18988,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_rum() { - read -e -p "设置登录密码: " admin_password + read -e -p "로그인 비밀번호 설정:" admin_password docker run -d --name=${docker_name} --restart=always \ -p ${docker_port}:5800 \ @@ -18566,8 +18999,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" - local docker_url="项目地址: ${gh_https_url}github.com/jlesage/docker-firefox" + local docker_describe="웹 페이지를 통해 데스크톱 브라우저 인터페이스에 대한 직접 액세스를 지원하는 Docker에서 실행되는 Firefox 브라우저입니다." + local docker_url="프로젝트 주소:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" local app_size="1" @@ -18582,19 +19015,19 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ b) clear - send_stats "全部应用备份" + send_stats "모든 애플리케이션 백업" local backup_filename="app_$(date +"%Y%m%d%H%M%S").tar.gz" - echo -e "${gl_kjlan}正在备份 $backup_filename ...${gl_bai}" + echo -e "${gl_kjlan}백업 중$backup_filename ...${gl_bai}" cd / && tar czvf "$backup_filename" home while true; do clear - echo "备份文件已创建: /$backup_filename" - read -e -p "要传送备份数据到远程服务器吗?(Y/N): " choice + echo "생성된 백업 파일: /$backup_filename" + read -e -p "백업 데이터를 원격 서버로 전송하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" + kj_ssh_read_host_port "원격 서버 IP를 입력하세요:" "대상 서버 SSH 포트 [기본값 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -18602,14 +19035,14 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "원격 서버/루트 디렉터리로 파일이 전송되었습니다." else - echo "未找到要传送的文件。" + echo "전송할 파일을 찾을 수 없습니다." fi break ;; *) - echo "注意: 目前备份仅包含docker项目,不包含宝塔,1panel等建站面板的数据备份。" + echo "참고: 현재 백업에는 docker 프로젝트만 포함되며, Pagoda, 1panel 등 웹사이트 구축 패널의 데이터 백업은 포함되지 않습니다." break ;; esac @@ -18619,29 +19052,29 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use - send_stats "全部应用还原" - echo "可用的应用备份" + send_stats "모든 앱 복원" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "최신 백업을 복원하려면 Enter 키를 누르고, 지정된 백업을 복원하려면 백업 파일 이름을 입력하고, 종료하려면 0을 입력하세요." filename if [ "$filename" == "0" ]; then break_end linux_panel fi - # 如果用户没有输入文件名,使用最新的压缩包 + # 사용자가 파일명을 입력하지 않으면 최신 압축 패키지가 사용됩니다. if [ -z "$filename" ]; then local filename=$(ls -t /app*.tar.gz | head -1) fi if [ -n "$filename" ]; then - echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}압축 해제 중$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "애플리케이션 데이터가 복원되었습니다. 현재 해당 애플리케이션을 복원하려면 지정된 애플리케이션 메뉴에 수동으로 진입한 후 애플리케이션을 업데이트하시기 바랍니다." else - echo "没有找到压缩包。" + echo "압축된 패키지를 찾을 수 없습니다." fi ;; @@ -18663,7 +19096,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -f "$custom_app" ]; then . "$custom_app" else - echo -e "${gl_hong}错误: 未找到编号为 ${sub_choice} 的应用配置${gl_bai}" + echo -e "${gl_hong}오류: 번호가 없습니다.${sub_choice}애플리케이션 구성${gl_bai}" fi ;; esac @@ -18679,35 +19112,35 @@ linux_work() { while true; do clear - send_stats "后台工作区" - echo -e "后台工作区" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" - echo -e "${gl_huang}提示: ${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + send_stats "백엔드 작업공간" + echo -e "백엔드 작업공간" + echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "현재 존재하는 작업공간 목록" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}1号工作区" - echo -e "${gl_kjlan}2. ${gl_bai}2号工作区" - echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" - echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" - echo -e "${gl_kjlan}5. ${gl_bai}5号工作区" - echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" - echo -e "${gl_kjlan}7. ${gl_bai}7号工作区" - echo -e "${gl_kjlan}8. ${gl_bai}8号工作区" - echo -e "${gl_kjlan}9. ${gl_bai}9号工作区" - echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" + echo -e "${gl_kjlan}1. ${gl_bai}작업 영역 1" + echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" + echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" + echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" + echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" + echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" + echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" + echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}22. ${gl_bai}创建/进入工作区" - echo -e "${gl_kjlan}23. ${gl_bai}注入命令到后台工作区" - echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" + echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" + echo -e "${gl_kjlan}23. ${gl_bai}백그라운드 작업 공간에 명령 삽입" + echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업공간 삭제" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -18715,7 +19148,7 @@ linux_work() { clear install tmux local SESSION_NAME="work1" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; @@ -18723,63 +19156,63 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 3) clear install tmux local SESSION_NAME="work3" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 4) clear install tmux local SESSION_NAME="work4" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 5) clear install tmux local SESSION_NAME="work5" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 6) clear install tmux local SESSION_NAME="work6" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 8) clear install tmux local SESSION_NAME="work8" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 9) clear install tmux local SESSION_NAME="work9" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; 10) clear install tmux local SESSION_NAME="work10" - send_stats "启动工作区$SESSION_NAME" + send_stats "작업공간 시작$SESSION_NAME" tmux_run ;; @@ -18787,30 +19220,30 @@ linux_work() { while true; do clear if grep -q 'tmux attach-session -t sshd || tmux new-session -s sshd' ~/.bashrc; then - local tmux_sshd_status="${gl_lv}开启${gl_bai}" + local tmux_sshd_status="${gl_lv}켜다${gl_bai}" else - local tmux_sshd_status="${gl_hui}关闭${gl_bai}" + local tmux_sshd_status="${gl_hui}폐쇄${gl_bai}" fi - send_stats "SSH常驻模式 " - echo -e "SSH常驻模式 ${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + send_stats "SSH 상주 모드" + echo -e "SSH 상주 모드${tmux_sshd_status}" + echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 켜기 2. 끄기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " gongzuoqu_del + read -e -p "선택사항을 입력하세요:" gongzuoqu_del case "$gongzuoqu_del" in 1) install tmux local SESSION_NAME="sshd" - send_stats "启动工作区$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + send_stats "작업공간 시작$SESSION_NAME" + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 자동으로 tmux 세션 시작\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; 2) - sed -i '/# 自动进入 tmux 会话/,+4d' ~/.bashrc + sed -i '/# 자동으로 tmux 세션을 입력합니다/,+4d' ~/.bashrc tmux kill-window -t sshd ;; *) @@ -18821,29 +19254,29 @@ linux_work() { ;; 22) - read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME + read -e -p "1001 kj001 work1과 같이 생성하거나 입력한 작업공간의 이름을 입력하세요." SESSION_NAME tmux_run - send_stats "自定义工作区" + send_stats "맞춤형 작업공간" ;; 23) - read -e -p "请输入你要后台执行的命令,如:curl -fsSL https://get.docker.com | sh: " tmuxd + read -e -p "다음과 같이 백그라운드에서 실행하려는 명령을 입력하십시오. 컬 -fsSL https://get.docker.com | 쉿:" tmuxd tmux_run_d - send_stats "注入命令到后台工作区" + send_stats "백그라운드 작업 공간에 명령 삽입" ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "삭제하려는 작업공간의 이름을 입력하세요:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name - send_stats "删除工作区" + send_stats "작업공간 삭제" ;; 0) kejilion ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -18862,20 +19295,20 @@ linux_work() { -# 智能切换镜像源函数 +# 지능형 스위칭 미러 소스 기능 switch_mirror() { - # 可选参数,默认为 false + # 선택적 매개변수, 기본값은 false입니다. local upgrade_software=${1:-false} local clean_cache=${2:-false} - # 获取用户国家 + # 사용자 국가 가져오기 local country country=$(curl -s ipinfo.io/country) - echo "检测到国家:$country" + echo "감지된 국가:$country" if [ "$country" = "CN" ]; then - echo "使用国内镜像源..." + echo "국내 미러 소스를 사용하세요..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.huaweicloud.com \ --protocol https \ @@ -18887,7 +19320,7 @@ switch_mirror() { --install-epel false \ --pure-mode else - echo "使用海外镜像源..." + echo "해외 미러 소스를 활용하세요.." if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ @@ -18917,27 +19350,27 @@ switch_mirror() { fail2ban_panel() { root_use - send_stats "ssh防御" + send_stats "SSH 방어" while true; do check_f2b_status - echo -e "SSH防御程序 $check_f2b_status" - echo "fail2ban是一个SSH防止暴力破解工具" - echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" + echo -e "SSH 방어 프로그램$check_f2b_status" + echo "fall2ban은 무차별 대입 크래킹을 방지하는 SSH 도구입니다." + echo "공식 웹사이트 소개:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" - echo "1. 安装防御程序" + echo "1. 방어 프로그램 설치" echo "------------------------" - echo "2. 查看SSH拦截记录" - echo "3. 日志实时监控" + echo "2. SSH 차단 기록 보기" + echo "3. 실시간 로그 모니터링" echo "------------------------" - echo "4. 基础参数配置(封禁时长/时间窗口/重试次数)" - echo "5. 编辑配置文件(nano)" + echo "4. 기본 매개변수 구성(금지 기간/기간/재시도 횟수)" + echo "5. 구성 파일 편집(나노)" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 방어 프로그램 제거" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) f2b_install_sshd @@ -18956,19 +19389,19 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH防御基础参数配置" + send_stats "SSH 방어 기본 매개변수 구성" f2b_basic_config break_end ;; 5) - send_stats "SSH防御编辑配置文件" + send_stats "SSH 방어 편집 구성 파일" f2b_edit_config break_end ;; 9) remove fail2ban rm -rf /etc/fail2ban - echo "Fail2Ban防御程序已卸载" + echo "Fail2Ban 방어 프로그램이 제거되었습니다." break ;; *) @@ -18985,10 +19418,10 @@ fail2ban_panel() { net_menu() { - send_stats "网卡管理工具" + send_stats "네트워크 카드 관리 도구" show_nics() { - echo "================ 当前网卡信息 ================" - printf "%-18s %-12s %-20s %-26s\n" "网卡名" "状态" "IP地址" "MAC地址" + echo "================ 현재 네트워크 카드 정보 =================" + printf "%-18s %-12s %-20s %-26s\n" "네트워크 카드 이름" "상태" "IP 주소" "MAC 주소" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -19003,50 +19436,50 @@ net_menu() { clear show_nics echo - echo "=========== 网卡管理菜单 ===========" - echo "1. 启用网卡" - echo "2. 禁用网卡" - echo "3. 查看网卡详细信息" - echo "4. 刷新网卡信息" - echo "0. 返回上一级选单" + echo "=========== 네트워크 카드 관리 메뉴 ===========" + echo "1. 네트워크 카드 활성화" + echo "2. 네트워크 카드 비활성화" + echo "3. 네트워크 카드 세부정보 보기" + echo "4. 네트워크 카드 정보 새로 고침" + echo "0. 이전 메뉴로 돌아가기" echo "====================================" - read -erp "请选择操作: " choice + read -erp "작업을 선택하십시오:" choice case $choice in 1) - send_stats "启用网卡" - read -erp "请输入要启用的网卡名: " nic + send_stats "네트워크 카드 활성화" + read -erp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 网卡 $nic 已启用" + ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" else - echo "✘ 网卡不存在" + echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 2) - send_stats "禁用网卡" - read -erp "请输入要禁用的网卡名: " nic + send_stats "네트워크 카드 비활성화" + read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" down && echo "✔ 网卡 $nic 已禁用" + ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" else - echo "✘ 网卡不存在" + echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 3) - send_stats "查看网卡详情" - read -erp "请输入要查看的网卡名: " nic + send_stats "네트워크 카드 세부정보 보기" + read -erp "보려는 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then - echo "========== $nic 详细信息 ==========" + echo "========== $nic세부정보 ==========" ip addr show "$nic" ethtool "$nic" 2>/dev/null | head -n 10 else - echo "✘ 网卡不存在" + echo "✘ 네트워크 카드가 존재하지 않습니다." fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 4) - send_stats "刷新网卡信息" + send_stats "네트워크 카드 정보 새로 고침" continue ;; *) @@ -19059,17 +19492,17 @@ net_menu() { log_menu() { - send_stats "系统日志管理工具" + send_stats "시스템 로그 관리 도구" show_log_overview() { - echo "============= 系统日志概览 =============" - echo "主机名: $(hostname)" - echo "系统时间: $(date)" + echo "============= 시스템 로그 개요 =============" + echo "호스트 이름: $(호스트 이름)" + echo "시스템 시간: $(날짜)" echo - echo "[ /var/log 目录占用 ]" + echo "[/var/log 디렉토리 직업]" du -sh /var/log 2>/dev/null echo - echo "[ journal 日志占用 ]" + echo "[일지 로그 직업]" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -19078,77 +19511,77 @@ log_menu() { clear show_log_overview echo - echo "=========== 系统日志管理菜单 ===========" - echo "1. 查看最近系统日志(journal)" - echo "2. 查看指定服务日志" - echo "3. 查看登录/安全日志" - echo "4. 实时跟踪日志" - echo "5. 清理旧 journal 日志" - echo "0. 返回上一级选单" + echo "=========== 시스템 로그 관리 메뉴 ===========" + echo "1. 최신 시스템 로그(일지) 보기" + echo "2. 지정된 서비스 로그 보기" + echo "3. 로그인/보안 로그 보기" + echo "4. 실시간 추적 로그" + echo "5. 오래된 저널 로그 정리" + echo "0. 이전 메뉴로 돌아가기" echo "=======================================" - read -erp "请选择操作: " choice + read -erp "작업을 선택하십시오:" choice case $choice in 1) - send_stats "查看最近日志" - read -erp "查看最近多少行日志?[默认 100]: " lines + send_stats "최근 로그 보기" + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 2) - send_stats "查看指定服务日志" - read -erp "请输入服务名(如 sshd、nginx): " svc + send_stats "지정된 서비스 로그 보기" + read -erp "서비스 이름(예: sshd, nginx)을 입력하세요." svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else - echo "✘ 服务不存在或无日志" + echo "✘ 서비스가 존재하지 않거나 로그가 없습니다." fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 3) - send_stats "查看登录/安全日志" - echo "====== 最近登录日志 ======" + send_stats "로그인/보안 로그 보기" + echo "====== 최근 로그인 로그 ======" last -n 10 echo - echo "====== 认证日志 ======" + echo "====== 인증 로그 ======" if [ -f /var/log/secure ]; then tail -n 20 /var/log/secure elif [ -f /var/log/auth.log ]; then tail -n 20 /var/log/auth.log else - echo "未找到安全日志文件" + echo "보안 로그 파일을 찾을 수 없습니다." fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." ;; 4) - send_stats "实时跟踪日志" - echo "1) 系统日志" - echo "2) 指定服务日志" - read -erp "选择跟踪类型: " t + send_stats "실시간 추적 로그" + echo "1) 시스템 로그" + echo "2) 서비스 로그 지정" + read -erp "추적 유형 선택:" t if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -erp "输入服务名: " svc + read -erp "서비스 이름 입력:" svc journalctl -u "$svc" -f else - echo "无效选择" + echo "잘못된 선택" fi ;; 5) - send_stats "清理旧 journal 日志" - echo "⚠️ 清理 journal 日志(安全方式)" - echo "1) 保留最近 7 天" - echo "2) 保留最近 3 天" - echo "3) 限制日志最大 500M" - read -erp "请选择清理方式: " c + send_stats "오래된 저널 로그 정리" + echo "⚠️ 일지를 청소하세요(안전한 방법)" + echo "1) 최근 7일을 보관" + echo "2) 최근 3일을 보관한다" + echo "3) 최대 로그 크기를 500M로 제한하십시오." + read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; 2) journalctl --vacuum-time=3d ;; 3) journalctl --vacuum-size=500M ;; - *) echo "无效选项" ;; + *) echo "잘못된 옵션" ;; esac - echo "✔ journal 日志清理完成" + echo "✔ 저널 로그 정리 완료" sleep 2 ;; *) @@ -19165,13 +19598,13 @@ env_menu() { BASHRC="$HOME/.bashrc" PROFILE="$HOME/.profile" - send_stats "系统变量管理工具" + send_stats "시스템 변수 관리 도구" show_env_vars() { clear - send_stats "当前已生效环境变量" - echo "========== 当前已生效环境变量(节选) ==========" - printf "%-20s %s\n" "变量名" "值" + send_stats "현재 유효한 환경 변수" + echo "========== 현재 적용되는 환경변수(발췌) ==========" + printf "%-20s %s\n" "변수 이름" "값" echo "-----------------------------------------------" for v in USER HOME SHELL LANG PWD; do printf "%-20s %s\n" "$v" "${!v}" @@ -19182,17 +19615,17 @@ env_menu() { echo "$PATH" | tr ':' '\n' | nl -ba echo - echo "========== 配置文件中定义的变量(解析) ==========" + echo "========== 구성 파일에 정의된 변수(파싱) ==========" parse_file_vars() { local file="$1" [ -f "$file" ] || return echo - echo ">>> 来源文件:$file" + echo ">>> 소스 파일:$file" echo "-----------------------------------------------" - # 提取 export VAR=xxx 或 VAR=xxx + # 내보내기 VAR=xxx 또는 VAR=xxx 추출 grep -Ev '^\s*#|^\s*$' "$file" \ | grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \ | while read -r line; do @@ -19207,55 +19640,55 @@ env_menu() { echo echo "===============================================" - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." } view_file() { local file="$1" - send_stats "查看变量文件 $file" + send_stats "변수 파일 보기$file" clear if [ -f "$file" ]; then - echo "========== 查看文件:$file ==========" + echo "========== 파일 보기:$file ==========" cat -n "$file" echo "====================================" else - echo "文件不存在:$file" + echo "파일이 존재하지 않습니다:$file" fi - read -erp "按回车继续..." + read -erp "계속하려면 Enter를 누르세요..." } edit_file() { local file="$1" - send_stats "编辑变量文件 $file" + send_stats "변수 파일 편집$file" install nano nano "$file" } source_files() { - echo "正在重新加载环境变量..." - send_stats "正在重新加载环境变量" + echo "환경 변수를 다시 로드하는 중..." + send_stats "환경 변수 다시 로드 중" source "$BASHRC" source "$PROFILE" - echo "✔ 环境变量已重新加载" - read -erp "按回车继续..." + echo "✔ 환경 변수가 다시 로드되었습니다." + read -erp "계속하려면 Enter를 누르세요..." } while true; do clear - echo "=========== 系统环境变量管理 ==========" - echo "当前用户:$USER" + echo "=========== 시스템 환경 변수 관리 ==========" + echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 查看当前常用环境变量" - echo "2. 查看 ~/.bashrc" - echo "3. 查看 ~/.profile" - echo "4. 编辑 ~/.bashrc" - echo "5. 编辑 ~/.profile" - echo "6. 重新加载环境变量(source)" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "2. ~/.bashrc 보기" + echo "3. ~/.profile 보기" + echo "4. ~/.bashrc 편집" + echo "5. ~/.profile 편집" + echo "6. 환경 변수 다시 로드(출처)" echo "--------------------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------------------------" - read -erp "请选择操作: " choice + read -erp "작업을 선택하십시오:" choice case "$choice" in 1) @@ -19280,7 +19713,7 @@ env_menu() { break ;; *) - echo "无效选项" + echo "잘못된 옵션" sleep 1 ;; esac @@ -19294,40 +19727,40 @@ create_user_with_sshkey() { local sshkey_vl if [[ -z "$new_username" ]]; then - echo "用法:create_user_with_sshkey <用户名>" + echo "사용법: create_user_with_sshkey <사용자 이름>" return 1 fi - # 创建用户 + # 사용자 생성 useradd -m -s /bin/bash "$new_username" || return 1 - echo "导入公钥范例:" + echo "공개 키 가져오기의 예:" echo " - URL: ${gh_https_url}github.com/torvalds.keys" - echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." - read -e -p "请导入 ${new_username} 的公钥: " sshkey_vl + echo "- 직접 붙여넣기: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "수입해주세요${new_username}공개 키:" sshkey_vl case "$sshkey_vl" in http://*|https://*) - send_stats "从 URL 导入 SSH 公钥" + send_stats "URL에서 SSH 공개 키 가져오기" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "公钥直接导入" + send_stats "공개 키를 직접 가져오기" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) - echo "错误:未知参数 '$sshkey_vl'" + echo "오류: 알 수 없는 매개변수 '$sshkey_vl'" return 1 ;; esac - # 修正权限 + # 권한 수정 chown -R "$new_username:$new_username" "/home/$new_username/.ssh" install sudo - # sudo 免密 + # sudo 비밀번호가 필요하지 않음 if [[ "$is_sudo" == "true" ]]; then cat >"/etc/sudoers.d/$new_username" </dev/null restart_ssh - echo "用户 $new_username 创建完成" + echo "사용자$new_username생성 완료" } @@ -19361,48 +19794,48 @@ linux_Settings() { while true; do clear - # send_stats "系统工具" - echo -e "系统工具" + # send_stats "시스템 도구" + echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}设置脚本启动快捷键 ${gl_kjlan}2. ${gl_bai}修改登录密码" - echo -e "${gl_kjlan}3. ${gl_bai}用户密码登录模式 ${gl_kjlan}4. ${gl_bai}安装Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}开放所有端口 ${gl_kjlan}6. ${gl_bai}修改SSH连接端口" - echo -e "${gl_kjlan}7. ${gl_bai}优化DNS地址 ${gl_kjlan}8. ${gl_bai}一键重装系统 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}切换优先ipv4/ipv6" + echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" + echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虚拟内存大小" - echo -e "${gl_kjlan}13. ${gl_bai}用户管理 ${gl_kjlan}14. ${gl_bai}用户/密码生成器" - echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}设置BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火墙高级管理器 ${gl_kjlan}18. ${gl_bai}修改主机名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定时任务管理" + echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" + echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" + echo -e "${gl_kjlan}15. ${gl_bai}시스템 시간대 조정${gl_kjlan}16. ${gl_bai}BBR3 가속 설정" + echo -e "${gl_kjlan}17. ${gl_bai}방화벽 고급 관리자${gl_kjlan}18. ${gl_bai}호스트 이름 수정" + echo -e "${gl_kjlan}19. ${gl_bai}시스템 업데이트 소스 전환${gl_kjlan}20. ${gl_bai}예약된 작업 관리" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}本机host解析 ${gl_kjlan}22. ${gl_bai}SSH防御程序" - echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}用户密钥登录模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系统监控预警 ${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" - echo -e "${gl_kjlan}27. ${gl_bai}红帽系Linux内核升级 ${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}29. ${gl_bai}病毒扫描工具 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" + echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" + echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}31. ${gl_bai}切换系统语言 ${gl_kjlan}32. ${gl_bai}命令行美化工具 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}设置系统回收站 ${gl_kjlan}34. ${gl_bai}系统备份与恢复" - echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" - echo -e "${gl_kjlan}37. ${gl_bai}命令行历史记录 ${gl_kjlan}38. ${gl_bai}rsync远程同步工具" - echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夹 ${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}网卡管理工具" + echo -e "${gl_kjlan}31. ${gl_bai}시스템 언어 전환${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" + echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}rsync 원격 동기화 도구" + echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}네트워크 카드 관리 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}系统日志管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系统变量管理工具" + echo -e "${gl_kjlan}41. ${gl_bai}시스템 로그 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}시스템 변수 관리 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}61. ${gl_bai}留言板 ${gl_kjlan}66. ${gl_bai}一条龙系统调优 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隐私与安全" - echo -e "${gl_kjlan}101. ${gl_bai}k命令高级用法 ${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}卸载科技lion脚本" + echo -e "${gl_kjlan}61. ${gl_bai}메시지 보드${gl_kjlan}66. ${gl_bai}원스톱 시스템 튜닝${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}99. ${gl_bai}서버를 다시 시작하세요${gl_kjlan}100. ${gl_bai}개인 정보 보호 및 보안" + echo -e "${gl_kjlan}101. ${gl_bai}k 명령의 고급 사용법${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}기술 사자 스크립트 제거" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" + echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "바로가기 키를 입력하십시오(종료하려면 0을 입력하십시오):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -19412,8 +19845,8 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快捷键已设置" - send_stats "脚本快捷键已设置" + echo "단축키가 설정되었습니다" + send_stats "스크립트 단축키가 설정되었습니다" break_end linux_Settings done @@ -19421,8 +19854,8 @@ linux_Settings() { 2) clear - send_stats "设置你的登录密码" - echo "设置你的登录密码" + send_stats "로그인 비밀번호를 설정하세요" + echo "로그인 비밀번호를 설정하세요" passwd ;; 3) @@ -19432,22 +19865,22 @@ linux_Settings() { 4) root_use - send_stats "py版本管理" - echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + send_stats "py 버전 관리" + echo "파이썬 버전 관리" + echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" - echo "推荐版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "권장 버전: 3.12 3.11 3.10 3.9 3.8 2.7" + echo "더 많은 버전 확인: https://www.python.org/downloads/" echo "------------" - read -e -p "输入你要安装的python版本号(输入0退出): " py_new_v + read -e -p "설치하려는 Python 버전 번호를 입력하세요(종료하려면 0 입력)." py_new_v if [[ "$py_new_v" == "0" ]]; then - send_stats "脚本PY管理" + send_stats "스크립트 PY 관리" break_end linux_Settings fi @@ -19480,7 +19913,7 @@ linux_Settings() { apk update && apk add git apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev else - echo "未知的包管理器!" + echo "알 수 없는 패키지 관리자입니다!" return fi @@ -19509,55 +19942,55 @@ EOF rm -rf $(pyenv root)/cache/* local VERSION=$(python -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" - send_stats "脚本PY版本切换" + echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" + send_stats "스크립트 PY 버전 전환" ;; 5) root_use - send_stats "开放端口" + send_stats "열린 포트" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "모든 포트가 열려 있습니다." ;; 6) root_use - send_stats "修改SSH端口" + send_stats "SSH 포트 수정" while true; do clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 현재 SSH 포트 번호 읽기 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 - echo -e "当前的 SSH 端口号是: ${gl_huang}$current_port ${gl_bai}" + # 현재 SSH 포트 번호 인쇄 + echo -e "현재 SSH 포트 번호는 다음과 같습니다.${gl_huang}$current_port ${gl_bai}" echo "------------------------" - echo "端口号范围1到65535之间的数字。(输入0退出)" + echo "포트 번호 범위는 1~65535입니다. (종료하려면 0을 입력하세요.)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 사용자에게 새 SSH 포트 번호를 묻는 메시지 표시 + read -e -p "새 SSH 포트 번호를 입력하세요." new_port - # 判断端口号是否在有效范围内 + # 포트 번호가 유효한 범위 내에 있는지 확인 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then - send_stats "SSH端口已修改" + send_stats "SSH 포트가 수정되었습니다." new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH端口修改" + send_stats "SSH 포트 수정 종료" break else - echo "端口号无效,请输入1到65535之间的数字。" - send_stats "输入无效SSH端口" + echo "포트 번호가 잘못되었습니다. 1~65535 사이의 숫자를 입력하세요." + send_stats "잘못된 SSH 포트가 입력되었습니다." break_end fi else - echo "输入无效,请输入数字。" - send_stats "输入无效SSH端口" + echo "입력이 잘못되었습니다. 숫자를 입력하세요." + send_stats "잘못된 SSH 포트가 입력되었습니다." break_end fi done @@ -19576,8 +20009,8 @@ EOF ;; 9) root_use - send_stats "新用户禁用root" - read -e -p "请输入新用户名(输入0退出): " new_username + send_stats "신규 사용자에 대한 루트 비활성화" + read -e -p "새 사용자 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_username if [ "$new_username" == "0" ]; then break_end linux_Settings @@ -19595,26 +20028,26 @@ EOF 10) root_use - send_stats "设置v4/v6优先级" + send_stats "v4/v6 우선순위 설정" while true; do clear - echo "设置v4/v6优先级" + echo "v4/v6 우선순위 설정" echo "------------------------" if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai} 优先" + echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv4${gl_bai}우선 사항" else - echo -e "当前网络优先级设置: ${gl_huang}IPv6${gl_bai} 优先" + echo -e "현재 네트워크 우선순위 설정:${gl_huang}IPv6${gl_bai}우선 사항" fi echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 우선 2. IPv6 우선 3. IPv6 복구 도구" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "선호하는 네트워크를 선택하세요:" choice case $choice in 1) @@ -19622,15 +20055,15 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "已切换为 IPv6 优先" - send_stats "已切换为 IPv6 优先" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) clear bash <(curl -L -s jhb.ovh/jb/v6.sh) - echo "该功能由jhb大神提供,感谢他!" - send_stats "ipv6修复" + echo "이 기능은 jhb에서 제공합니다. 감사합니다!" + send_stats "IPv6 수리" ;; *) @@ -19648,43 +20081,43 @@ EOF 12) root_use - send_stats "设置虚拟内存" + send_stats "가상 메모리 설정" while true; do clear - echo "设置虚拟内存" + echo "가상 메모리 설정" local swap_used=$(free -m | awk 'NR==3{print $3}') local swap_total=$(free -m | awk 'NR==3{print $2}') local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - echo -e "当前虚拟内存: ${gl_huang}$swap_info${gl_bai}" + echo -e "현재 가상 메모리:${gl_huang}$swap_info${gl_bai}" echo "------------------------" - echo "1. 分配1024M 2. 分配2048M 3. 分配4096M 4. 自定义大小" + echo "1. 1024M 할당 2. 2048M 할당 3. 4096M 할당 4. 사용자 정의 크기" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " choice + read -e -p "선택사항을 입력하세요:" choice case "$choice" in 1) - send_stats "已设置1G虚拟内存" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; 2) - send_stats "已设置2G虚拟内存" + send_stats "2G 가상 메모리가 설정되었습니다" add_swap 2048 ;; 3) - send_stats "已设置4G虚拟内存" + send_stats "4G 가상 메모리가 설정되었습니다." add_swap 4096 ;; 4) - read -e -p "请输入虚拟内存大小(单位M): " new_swap + read -e -p "가상 메모리 크기(단위 M)를 입력하세요." new_swap add_swap "$new_swap" - send_stats "已设置自定义虚拟内存" + send_stats "사용자 정의 가상 메모리 세트" ;; *) @@ -19697,10 +20130,10 @@ EOF 13) while true; do root_use - send_stats "用户管理" - echo "用户列表" + send_stats "사용자 관리" + echo "사용자 목록" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" + printf "%-24s %-34s %-20s %-10s\n" "사용자 이름" "사용자 권한" "사용자 그룹" "sudo 권한" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status @@ -19714,34 +20147,34 @@ EOF echo "" - echo "账户操作" + echo "계정 운영" echo "------------------------" - echo "1. 创建普通用户 2. 创建高级用户" + echo "1. 일반 사용자 생성 2. 고급 사용자 생성" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 가장 높은 권한을 부여합니다. 4. 가장 높은 권한을 제거합니다." echo "------------------------" - echo "5. 删除账号" + echo "5. 계정 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 묻는 메시지 표시 + read -e -p "새 사용자 이름을 입력하세요:" new_username create_user_with_sshkey $new_username false ;; 2) - # 提示用户输入新用户名 - read -e -p "请输入新用户名: " new_username + # 사용자에게 새 사용자 이름을 묻는 메시지 표시 + read -e -p "새 사용자 이름을 입력하세요:" new_username create_user_with_sshkey $new_username true ;; 3) - read -e -p "请输入用户名: " username + read -e -p "사용자 이름을 입력하세요:" username install sudo cat >"/etc/sudoers.d/$username" </dev/null | xargs rm -f fi sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username + read -e -p "삭제하려는 사용자 이름을 입력하세요:" username userdel -r "$username" ;; @@ -19771,50 +20204,50 @@ EOF 14) clear - send_stats "用户信息生成器" - echo "随机用户名" + send_stats "사용자 정보 생성기" + echo "임의의 사용자 이름" echo "------------------------" for i in {1..5}; do username="user$(< /dev/urandom tr -dc _a-z0-9 | head -c6)" - echo "随机用户名 $i: $username" + echo "임의의 사용자 이름$i: $username" done echo "" - echo "随机姓名" + echo "임의의 이름" echo "------------------------" local first_names=("John" "Jane" "Michael" "Emily" "David" "Sophia" "William" "Olivia" "James" "Emma" "Ava" "Liam" "Mia" "Noah" "Isabella") local last_names=("Smith" "Johnson" "Brown" "Davis" "Wilson" "Miller" "Jones" "Garcia" "Martinez" "Williams" "Lee" "Gonzalez" "Rodriguez" "Hernandez") - # 生成5个随机用户姓名 + # 5개의 무작위 사용자 이름 생성 for i in {1..5}; do local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "随机用户姓名 $i: $user_name" + echo "임의의 사용자 이름$i: $user_name" done echo "" - echo "随机UUID" + echo "무작위 UUID" echo "------------------------" for i in {1..5}; do uuid=$(cat /proc/sys/kernel/random/uuid) - echo "随机UUID $i: $uuid" + echo "무작위 UUID$i: $uuid" done echo "" - echo "16位随机密码" + echo "16자리 랜덤 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) - echo "随机密码 $i: $password" + echo "임의의 비밀번호$i: $password" done echo "" - echo "32位随机密码" + echo "32비트 임의 비밀번호" echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "随机密码 $i: $password" + echo "임의의 비밀번호$i: $password" done echo "" @@ -19822,46 +20255,46 @@ EOF 15) root_use - send_stats "换时区" + send_stats "시간대 변경" while true; do clear - echo "系统时间信息" + echo "시스템 시간 정보" - # 获取当前系统时区 + # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 获取当前系统时间 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") - # 显示时区和时间 - echo "当前系统时区:$timezone" - echo "当前系统时间:$current_time" + # 시간대 및 시간 표시 + echo "현재 시스템 시간대:$timezone" + echo "현재 시스템 시간:$current_time" echo "" - echo "时区切换" + echo "시간대 스위치" echo "------------------------" - echo "亚洲" - echo "1. 中国上海时间 2. 中国香港时间" - echo "3. 日本东京时间 4. 韩国首尔时间" - echo "5. 新加坡时间 6. 印度加尔各答时间" - echo "7. 阿联酋迪拜时间 8. 澳大利亚悉尼时间" - echo "9. 泰国曼谷时间" + echo "아시아" + echo "1. 중국 상하이 시간 2. 중국 홍콩 시간" + echo "3. 일본 도쿄 시간 4. 한국 서울 시간" + echo "5. 싱가포르 시간 6. 콜카타, 인도 시간" + echo "7. 아랍에미리트 두바이 시간 8. 호주 시드니 시간" + echo "9. 태국 방콕 시간" echo "------------------------" - echo "欧洲" - echo "11. 英国伦敦时间 12. 法国巴黎时间" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "유럽" + echo "11. 영국 런던 시간 12. 프랑스 파리 시간" + echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" - echo "美洲" - echo "21. 美国西部时间 22. 美国东部时间" - echo "23. 加拿大时间 24. 墨西哥时间" - echo "25. 巴西时间 26. 阿根廷时间" + echo "미국" + echo "21. 미국 서부 시간 22. 미국 동부 시간" + echo "23. 캐나다 시간 24. 멕시코 시간" + echo "25. 브라질 시간 26. 아르헨티나 시간" echo "------------------------" - echo "31. UTC全球标准时间" + echo "31. UTC 세계 표준시" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in @@ -19904,21 +20337,21 @@ EOF 18) root_use - send_stats "修改主机名" + send_stats "호스트 이름 수정" while true; do clear local current_hostname=$(uname -n) - echo -e "当前主机名: ${gl_huang}$current_hostname${gl_bai}" + echo -e "현재 호스트 이름:${gl_huang}$current_hostname${gl_bai}" echo "------------------------" - read -e -p "请输入新的主机名(输入0退出): " new_hostname + read -e -p "새 호스트 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_hostname if [ -n "$new_hostname" ] && [ "$new_hostname" != "0" ]; then if [ -f /etc/alpine-release ]; then # Alpine echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # 其他系统,如 Debian, Ubuntu, CentOS 等 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -19936,11 +20369,11 @@ EOF echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts fi - echo "主机名已更改为: $new_hostname" - send_stats "主机名已更改" + echo "호스트 이름이 다음으로 변경되었습니다.$new_hostname" + send_stats "호스트 이름이 변경됨" sleep 1 else - echo "已退出,未更改主机名。" + echo "호스트 이름을 변경하지 않고 종료되었습니다." break fi done @@ -19948,37 +20381,37 @@ EOF 19) root_use - send_stats "换系统更新源" + send_stats "시스템 업데이트 소스 변경" clear - echo "选择更新源区域" - echo "接入LinuxMirrors切换系统更新源" + echo "업데이트 소스 지역 선택" + echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" + echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "输入你的选择: " choice + read -e -p "선택 항목을 입력하세요." choice case $choice in 1) - send_stats "中国大陆默认源" + send_stats "중국 본토 기본 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) - send_stats "中国大陆教育源" + send_stats "중국 본토 교육 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu ;; 3) - send_stats "海外源" + send_stats "해외 소스" bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; 4) - send_stats "智能切换更新源" + send_stats "업데이트 소스의 지능적인 전환" switch_mirror false false ;; *) - echo "已取消" + echo "취소" ;; esac @@ -19986,62 +20419,62 @@ EOF ;; 20) - send_stats "定时任务管理" + send_stats "예약된 작업 관리" while true; do clear check_crontab_installed clear - echo "定时任务列表" + echo "예약된 작업 목록" crontab -l echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 예약된 작업 추가 2. 예약된 작업 삭제 3. 예약된 작업 편집" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) - read -e -p "请输入新任务的执行命令: " newquest + read -e -p "새 작업의 실행 명령을 입력하십시오:" newquest echo "------------------------" - echo "1. 每月任务 2. 每周任务" - echo "3. 每天任务 4. 每小时任务" + echo "1. 월간 작업 2. 주간 작업" + echo "3. 일일 작업 4. 시간별 작업" echo "------------------------" - read -e -p "请输入你的选择: " dingshi + read -e -p "선택사항을 입력하세요:" dingshi case $dingshi in 1) - read -e -p "选择每月的几号执行任务? (1-30): " day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "작업을 수행할 요일을 선택하시겠습니까? (0-6, 0은 일요일을 나타냄):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "选择每天几点执行任务?(小时,0-23): " hour + read -e -p "매일 몇 시에 작업을 수행하기로 선택하시나요? (시간, 0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "输入每小时的第几分钟执行任务?(分钟,0-60): " minute + read -e -p "작업을 실행해야 하는 시간을 입력하세요. (분, 0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "예약된 작업 추가" ;; 2) - read -e -p "请输入需要删除任务的关键字: " kquest + read -e -p "삭제할 작업의 키워드를 입력하세요:" kquest crontab -l | grep -v "$kquest" | crontab - - send_stats "删除定时任务" + send_stats "예약된 작업 삭제" ;; 3) crontab -e - send_stats "编辑定时任务" + send_stats "예약된 작업 편집" ;; *) break # 跳出循环,退出菜单 @@ -20053,32 +20486,32 @@ EOF 21) root_use - send_stats "本地host解析" + send_stats "로컬 호스트 확인" while true; do clear - echo "本机host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "기본 호스트 확인 목록" + echo "여기에 파싱 매칭을 추가하면 더 이상 동적 파싱이 사용되지 않습니다." cat /etc/hosts echo "" - echo "操作" + echo "작동하다" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 새로운 해상도 추가 2. 해상도 주소 삭제" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " host_dns + read -e -p "선택사항을 입력하세요:" host_dns case $host_dns in 1) - read -e -p "请输入新的解析记录 格式: 110.25.5.33 kejilion.pro : " addhost + read -e -p "새로운 구문 분석 기록 형식을 입력하세요: 110.25.5.33 kejilion.pro:" addhost echo "$addhost" >> /etc/hosts - send_stats "本地host解析新增" + send_stats "로컬 호스트 해상도가 추가되었습니다." ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "삭제해야 하는 구문 분석된 콘텐츠의 키워드를 입력하세요." delhost sed -i "/$delhost/d" /etc/hosts - send_stats "本地host解析删除" + send_stats "로컬 호스트 확인 및 삭제" ;; *) break # 跳出循环,退出菜单 @@ -20094,47 +20527,47 @@ EOF 23) root_use - send_stats "限流关机功能" + send_stats "전류 제한 차단 기능" while true; do clear - echo "限流关机功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "전류 제한 차단 기능" + echo "영상 소개: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" - echo "当前流量使用情况,重启服务器流量计算会清零!" + echo "서버가 다시 시작되면 현재 트래픽 사용량이 지워집니다!" output_status - echo -e "${gl_kjlan}总接收: ${gl_bai}$rx" - echo -e "${gl_kjlan}总发送: ${gl_bai}$tx" + echo -e "${gl_kjlan}받은 총액:${gl_bai}$rx" + echo -e "${gl_kjlan}보낸 총액:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # Limiting_Shut_down.sh 파일이 있는지 확인하세요. if [ -f ~/Limiting_Shut_down.sh ]; then - # 获取 threshold_gb 的值 + # Threshold_gb 값을 가져옵니다. local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}当前未启用限流关机功能${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "시스템은 매분마다 실제 트래픽이 임계값에 도달했는지 여부를 감지하고 임계값에 도달한 후 자동으로 서버를 종료합니다!" echo "------------------------" - echo "1. 开启限流关机功能 2. 停用限流关机功能" + echo "1. 전류 제한 종료 기능을 활성화합니다. 2. 전류 제한 종료 기능을 비활성화합니다." echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) - # 输入新的虚拟内存大小 - echo "如果实际服务器就100G流量,可设置阈值为95G,提前关机,以免出现流量误差或溢出。" - read -e -p "请输入进站流量阈值(单位为G,默认100G): " rx_threshold_gb + # 새 가상 메모리 크기 입력 + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} - read -e -p "请输入出站流量阈值(单位为G,默认100G): " tx_threshold_gb + read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "트래픽 재설정 날짜를 입력하세요(기본적으로 매월 1일 재설정)." cz_day cz_day=${cz_day:-1} cd ~ @@ -20147,15 +20580,15 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + echo "전류 제한 종료가 설정되었습니다." + send_stats "전류 제한 종료가 설정되었습니다." ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + echo "전류 제한 차단 기능이 꺼졌습니다." ;; *) break @@ -20171,18 +20604,18 @@ EOF 25) root_use - send_stats "电报预警" - echo "TG-bot监控预警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + send_stats "전신 경고" + echo "TG-bot 모니터링 및 조기경보 기능" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要配置tg机器人API和接收预警的用户ID,即可实现本机CPU,内存,硬盘,流量,SSH登录的实时监控预警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" - read -e -p "确定继续吗?(Y/N): " choice + echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." + echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." + echo -e "${gl_hui}- 트래픽에 관해서는 서버를 다시 시작하면 다시 계산됩니다 -${gl_bai}" + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "텔레그램 경고 활성화됨" cd ~ install nano tmux bc jq check_crontab_installed @@ -20204,7 +20637,7 @@ EOF sed -i "4i$(grep '^CHAT_ID=' ~/TG-check-notify.sh)" TG-SSH-check-notify.sh chmod +x ~/TG-SSH-check-notify.sh - # 添加到 ~/.profile 文件中 + # ~/.profile 파일에 추가 if ! grep -q 'bash ~/TG-SSH-check-notify.sh' ~/.profile > /dev/null 2>&1; then echo 'bash ~/TG-SSH-check-notify.sh' >> ~/.profile if command -v dnf &>/dev/null || command -v yum &>/dev/null; then @@ -20215,21 +20648,21 @@ EOF source ~/.profile clear - echo "TG-bot预警系统已启动" - echo -e "${gl_hui}你还可以将root目录中的TG-check-notify.sh预警文件放到其他机器上直接使用!${gl_bai}" + echo "TG-bot 조기경보 시스템이 활성화되었습니다." + echo -e "${gl_hui}TG-check-notify.sh 경고 파일을 다른 컴퓨터의 루트 디렉터리에 넣고 직접 사용할 수도 있습니다!${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "고위험 SSH 취약점 수정" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -20273,7 +20706,7 @@ EOF ;; 37) clear - send_stats "命令行历史记录" + send_stats "명령줄 기록" get_history_file() { for file in "$HOME"/.bash_history "$HOME"/.ash_history "$HOME"/.zsh_history "$HOME"/.local/share/fish/fish_history; do [ -f "$file" ] && { echo "$file"; return; } @@ -20312,94 +20745,94 @@ EOF 61) clear - send_stats "留言板" - echo "访问科技lion官方留言板,您对脚本有任何想法欢迎留言交流!" + send_stats "메시지 보드" + echo "Technology Lion 공식 게시판을 방문해 보세요. 스크립트에 대한 아이디어가 있으시면 교환 메시지를 남겨주세요!" echo "https://board.kejilion.pro" - echo "公共密码: kejilion.sh" + echo "공개 비밀번호: kejilion.sh" ;; 66) root_use - send_stats "一条龙调优" - echo "一条龙系统调优" + send_stats "원스톱 튜닝" + echo "원스톱 시스템 튜닝" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. 优化系统更新源,更新系统到最新" - echo "2. 清理系统垃圾文件" - echo -e "3. 设置虚拟内存${gl_huang}1G${gl_bai}" - echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo -e "5. 启动fail2ban防御SSH暴力破解" - echo -e "6. 开放所有端口" - echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" - echo -e "9. 自动优化DNS地址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" - echo -e "10. 设置网络为${gl_huang}ipv4优先${gl_bai}" - echo -e "11. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linux系统内核参数优化${gl_huang}自动根据网络环境调优${gl_bai}" + echo "다음 콘텐츠가 운영 및 최적화됩니다." + echo "1. 시스템 업데이트 소스를 최적화하고 시스템을 최신 버전으로 업데이트하세요." + echo "2. 시스템 정크 파일 정리" + echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" + echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" + echo -e "5. SSH 무차별 대입 크래킹을 방어하기 위해 fall2ban을 시작하세요." + echo -e "6. 모든 포트를 엽니다" + echo -e "7. 켜다${gl_huang}BBR${gl_bai}가속하다" + echo -e "8. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" + echo -e "9. DNS 주소 자동 최적화${gl_huang}해외: 1.1.1.1 8.8.8.8 국내: 223.5.5.5${gl_bai}" + echo -e "10. 네트워크를 다음으로 설정합니다.${gl_huang}IPv4 우선순위${gl_bai}" + echo -e "11. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "12. Linux 시스템 커널 매개변수 최적화${gl_huang}네트워크 환경에 따라 자동으로 튜닝${gl_bai}" echo "------------------------------------------------" - read -e -p "确定一键保养吗?(Y/N): " choice + read -e -p "원클릭 유지 관리를 원하시나요? (예/아니요):" choice case "$choice" in [Yy]) clear - send_stats "一条龙调优启动" + send_stats "원스톱 튜닝 시작" echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 시스템을 최신으로 업데이트하세요" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 시스템 정크 파일 정리" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 - echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 4/12. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" echo "------------------------------------------------" f2b_install_sshd cd ~ f2b_status - echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" + echo -e "[${gl_lv}OK${gl_bai}] 5/12. SSH 무차별 대입 크래킹을 방어하려면 Fail2ban을 시작하세요." echo "------------------------------------------------" - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" + echo -e "[${gl_lv}OK${gl_bai}] 6/12. 모든 포트 열기" echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "[${gl_lv}OK${gl_bai}] 7/12. 열려 있는${gl_huang}BBR${gl_bai}가속하다" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 시간대를 다음으로 설정하세요.${gl_huang}상하이${gl_bai}" echo "------------------------------------------------" auto_optimize_dns - echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 9/12. DNS 주소 자동 최적화${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 네트워크를 다음으로 설정하세요.${gl_huang}IPv4 우선순위${gl_bai}}" echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 기본 도구 설치${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" - echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux 시스템 커널 매개변수 최적화" + echo -e "${gl_lv}원스톱 시스템 튜닝이 완료되었습니다${gl_bai}" ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac @@ -20407,7 +20840,7 @@ EOF 99) clear - send_stats "重启系统" + send_stats "시스템을 다시 시작하세요" server_reboot ;; 100) @@ -20416,39 +20849,39 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}데이터 수집${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}컬렉션이 닫혔습니다.${gl_bai}" else - local status_message="无法确定的状态" + local status_message="불확실한 상태" fi - echo "隐私与安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "개인 정보 보호 및 보안" + echo "스크립트는 사용자의 기능 사용에 대한 데이터를 수집하고 스크립트 경험을 최적화하며 더 재미 있고 유용한 기능을 만듭니다." + echo "스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 사용된 기능 이름이 수집됩니다." echo "------------------------------------------------" - echo -e "当前状态: $status_message" + echo -e "현재 상태:$status_message" echo "--------------------" - echo "1. 开启采集" - echo "2. 关闭采集" + echo "1. 수집 시작" + echo "2. 수집 종료" echo "--------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "--------------------" - read -e -p "请输入你的选择: " sub_choice + read -e -p "선택사항을 입력하세요:" sub_choice case $sub_choice in 1) cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "已开启采集" - send_stats "隐私与安全已开启采集" + echo "수집이 시작되었습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 설정되었습니다." ;; 2) cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" - send_stats "隐私与安全已关闭采集" + echo "컬렉션이 닫혔습니다." + send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." ;; *) break @@ -20464,11 +20897,11 @@ EOF 102) clear - send_stats "卸载科技lion脚本" - echo "卸载科技lion脚本" + send_stats "기술 사자 스크립트 제거" + echo "기술 사자 스크립트 제거" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" - read -e -p "确定继续吗?(Y/N): " choice + echo "kejilion 스크립트는 다른 기능에 영향을 주지 않고 완전히 제거됩니다." + read -e -p "계속하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -20476,16 +20909,16 @@ EOF (crontab -l | grep -v "kejilion.sh") | crontab - rm -f /usr/local/bin/k rm ~/kejilion.sh - echo "脚本已卸载,再见!" + echo "스크립트가 제거되었습니다. 안녕!" break_end clear exit ;; [Nn]) - echo "已取消" + echo "취소" ;; *) - echo "无效的选择,请输入 Y 或 N。" + echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." ;; esac ;; @@ -20495,7 +20928,7 @@ EOF ;; *) - echo "无效的输入!" + echo "입력이 잘못되었습니다!" ;; esac break_end @@ -20513,174 +20946,174 @@ EOF linux_file() { root_use - send_stats "文件管理器" + send_stats "파일 관리자" while true; do clear - echo "文件管理器" + echo "파일 관리자" echo "------------------------" - echo "当前路径" + echo "현재 경로" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" - echo "5. 删除目录 6. 返回上一级选单目录" + echo "1. 디렉터리 입력 2. 디렉터리 생성 3. 디렉터리 권한 수정 4. 디렉터리 이름 바꾸기" + echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" - echo "15. 删除文件" + echo "11. 파일 생성 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" + echo "15. 파일 삭제" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" - echo "25. 传文件至其他服务器" + echo "21. 파일 디렉터리 압축 22. 파일 디렉터리 압축 풀기 23. 파일 디렉터리 이동 24. 파일 디렉터리 복사" + echo "25. 다른 서버로 파일 전송" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "请输入你的选择: " Limiting + read -e -p "선택사항을 입력하세요:" Limiting case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname - cd "$dirname" 2>/dev/null || echo "无法进入目录" - send_stats "进入目录" + read -e -p "디렉토리 이름을 입력하십시오:" dirname + cd "$dirname" 2>/dev/null || echo "디렉토리에 들어갈 수 없습니다" + send_stats "디렉토리 입력" ;; 2) # 创建目录 - read -e -p "请输入要创建的目录名: " dirname - mkdir -p "$dirname" && echo "目录已创建" || echo "创建失败" - send_stats "创建目录" + read -e -p "생성할 디렉터리 이름을 입력하세요." dirname + mkdir -p "$dirname" && echo "디렉터리가 생성되었습니다." || echo "생성 실패" + send_stats "디렉터리 생성" ;; 3) # 修改目录权限 - read -e -p "请输入目录名: " dirname - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失败" - send_stats "修改目录权限" + read -e -p "디렉토리 이름을 입력하십시오:" dirname + read -e -p "권한을 입력하세요(예: 755):" perm + chmod "$perm" "$dirname" && echo "권한이 수정되었습니다." || echo "수정 실패" + send_stats "디렉터리 권한 수정" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name - read -e -p "请输入新目录名: " new_name - mv "$current_name" "$new_name" && echo "目录已重命名" || echo "重命名失败" - send_stats "重命名目录" + read -e -p "현재 디렉터리 이름을 입력하세요." current_name + read -e -p "새 디렉터리 이름을 입력하세요." new_name + mv "$current_name" "$new_name" && echo "디렉터리 이름이 변경되었습니다." || echo "이름 바꾸기 실패" + send_stats "디렉터리 이름 바꾸기" ;; 5) # 删除目录 - read -e -p "请输入要删除的目录名: " dirname - rm -rf "$dirname" && echo "目录已删除" || echo "删除失败" - send_stats "删除目录" + read -e -p "삭제할 디렉터리 이름을 입력하세요:" dirname + rm -rf "$dirname" && echo "디렉터리가 삭제되었습니다." || echo "삭제 실패" + send_stats "디렉토리 삭제" ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "이전 메뉴 디렉토리로 돌아가기" ;; 11) # 创建文件 - read -e -p "请输入要创建的文件名: " filename - touch "$filename" && echo "文件已创建" || echo "创建失败" - send_stats "创建文件" + read -e -p "생성할 파일 이름을 입력하세요:" filename + touch "$filename" && echo "파일이 생성되었습니다." || echo "생성 실패" + send_stats "파일 생성" ;; 12) # 编辑文件 - read -e -p "请输入要编辑的文件名: " filename + read -e -p "편집할 파일 이름을 입력하십시오:" filename install nano nano "$filename" - send_stats "编辑文件" + send_stats "파일 편집" ;; 13) # 修改文件权限 - read -e -p "请输入文件名: " filename - read -e -p "请输入权限 (如 755): " perm - chmod "$perm" "$filename" && echo "权限已修改" || echo "修改失败" - send_stats "修改文件权限" + read -e -p "파일 이름을 입력하세요:" filename + read -e -p "권한을 입력하세요(예: 755):" perm + chmod "$perm" "$filename" && echo "권한이 수정되었습니다." || echo "수정 실패" + send_stats "파일 권한 수정" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name - read -e -p "请输入新文件名: " new_name - mv "$current_name" "$new_name" && echo "文件已重命名" || echo "重命名失败" - send_stats "重命名文件" + read -e -p "현재 파일 이름을 입력하십시오:" current_name + read -e -p "새 파일 이름을 입력하세요:" new_name + mv "$current_name" "$new_name" && echo "파일 이름이 변경되었습니다." || echo "이름 바꾸기 실패" + send_stats "파일 이름 바꾸기" ;; 15) # 删除文件 - read -e -p "请输入要删除的文件名: " filename - rm -f "$filename" && echo "文件已删除" || echo "删除失败" - send_stats "删除文件" + read -e -p "삭제할 파일 이름을 입력하세요:" filename + rm -f "$filename" && echo "파일이 삭제되었습니다." || echo "삭제 실패" + send_stats "파일 삭제" ;; 21) # 压缩文件/目录 - read -e -p "请输入要压缩的文件/目录名: " name + read -e -p "압축할 파일/디렉터리 이름을 입력하십시오:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已压缩为 $name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "압축$name.tar.gz" || echo "압축 실패" + send_stats "압축된 파일/디렉토리" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "추출할 파일 이름(.tar.gz)을 입력하십시오." filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解压失败" - send_stats "解压文件/目录" + tar -xzvf "$filename" && echo "압축이 풀렸습니다.$filename" || echo "압축 해제 실패" + send_stats "파일/디렉토리 압축 풀기" ;; 23) # 移动文件或目录 - read -e -p "请输入要移动的文件或目录路径: " src_path + read -e -p "이동할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 이동 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "移动文件或目录失败: 目标路径未指定" + echo "오류: 대상 경로를 입력하십시오." + send_stats "파일 또는 디렉터리 이동 실패: 대상 경로가 지정되지 않았습니다." continue fi - mv "$src_path" "$dest_path" && echo "文件或目录已移动到 $dest_path" || echo "移动文件或目录失败" - send_stats "移动文件或目录" + mv "$src_path" "$dest_path" && echo "파일 또는 디렉토리가 다음으로 이동되었습니다.$dest_path" || echo "파일 또는 디렉터리를 이동하지 못했습니다." + send_stats "파일 또는 디렉터리 이동" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then - echo "错误: 文件或目录不存在。" - send_stats "复制文件或目录失败: 文件或目录不存在" + echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi - read -e -p "请输入目标路径 (包括新文件名或目录名): " dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then - echo "错误: 请输入目标路径。" - send_stats "复制文件或目录失败: 目标路径未指定" + echo "오류: 대상 경로를 입력하십시오." + send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." continue fi - # 使用 -r 选项以递归方式复制目录 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "复制文件或目录失败" - send_stats "复制文件或目录" + # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. + cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." + send_stats "파일 또는 디렉터리 복사" ;; 25) # 传送文件至远端服务器 - read -e -p "请输入要传送的文件路径: " file_to_transfer + read -e -p "전송할 파일 경로를 입력하십시오:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + echo "오류: 파일이 존재하지 않습니다." + send_stats "파일 전송 실패: 파일이 존재하지 않습니다." continue fi - kj_ssh_read_host_user_port "请输入远端服务器IP: " "请输入远端服务器用户名 (默认root): " "请输入登录端口 (默认22): " "root" "22" + kj_ssh_read_host_user_port "원격 서버 IP를 입력하세요:" "원격 서버 사용자 이름(기본 루트)을 입력하십시오:" "로그인 포트(기본값 22)를 입력하세요." "root" "22" local remote_ip="$KJ_SSH_HOST" local remote_user="$KJ_SSH_USER" local remote_port="$KJ_SSH_PORT" - kj_ssh_read_password "请输入远端服务器密码: " + kj_ssh_read_password "원격 서버 비밀번호를 입력하세요:" local remote_password="$KJ_SSH_PASSWORD" - # 清除已知主机的旧条目 + # 알려진 호스트에 대한 이전 항목 지우기 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # scp를 사용하여 파일 전송 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" < /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + echo -e "${gl_lv}스크립트가 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "스크립트가 최신 상태입니다.$sh_v_new" break_end ~/kejilion.sh exit @@ -21036,15 +21469,15 @@ while true; do (crontab -l | grep -v "kejilion.sh") | crontab - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" - send_stats "开启脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 켜져 있고 매일 새벽 2시에 스크립트가 자동으로 업데이트됩니다!${gl_bai}" + send_stats "자동 스크립트 업데이트 활성화" break_end ;; 3) clear (crontab -l | grep -v "kejilion.sh") | crontab - - echo -e "${gl_lv}自动更新已关闭${gl_bai}" - send_stats "关闭脚本自动更新" + echo -e "${gl_lv}자동 업데이트가 꺼졌습니다${gl_bai}" + send_stats "자동 스크립트 업데이트 끄기" break_end ;; *) @@ -21066,40 +21499,40 @@ echo -e "${gl_kjlan}" echo "╦╔═╔═╗ ╦╦╦ ╦╔═╗╔╗╔ ╔═╗╦ ╦" echo "╠╩╗║╣ ║║║ ║║ ║║║║ ╚═╗╠═╣" echo "╩ ╩╚═╝╚╝╩╩═╝╩╚═╝╝╚╝o╚═╝╩ ╩" -echo -e "科技lion脚本工具箱 v$sh_v" -echo -e "命令行输入${gl_huang}k${gl_kjlan}可快速启动脚本${gl_bai}" +echo -e "기술 사자 스크립트 도구 상자 v$sh_v" +echo -e "명령줄 입력${gl_huang}k${gl_kjlan}빠른 시작 스크립트${gl_bai}" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}1. ${gl_bai}系统信息查询" -echo -e "${gl_kjlan}2. ${gl_bai}系统更新" -echo -e "${gl_kjlan}3. ${gl_bai}系统清理" -echo -e "${gl_kjlan}4. ${gl_bai}基础工具" -echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" -echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" -echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" -echo -e "${gl_kjlan}8. ${gl_bai}测试脚本合集" -echo -e "${gl_kjlan}9. ${gl_bai}甲骨文云脚本合集" -echo -e "${gl_huang}10. ${gl_bai}LDNMP建站" -echo -e "${gl_kjlan}11. ${gl_bai}应用市场" -echo -e "${gl_kjlan}12. ${gl_bai}后台工作区" -echo -e "${gl_kjlan}13. ${gl_bai}系统工具" -echo -e "${gl_kjlan}14. ${gl_bai}服务器集群控制" -echo -e "${gl_kjlan}15. ${gl_bai}广告专栏" -echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" +echo -e "${gl_kjlan}1. ${gl_bai}시스템 정보 쿼리" +echo -e "${gl_kjlan}2. ${gl_bai}시스템 업데이트" +echo -e "${gl_kjlan}3. ${gl_bai}시스템 정리" +echo -e "${gl_kjlan}4. ${gl_bai}기본 도구" +echo -e "${gl_kjlan}5. ${gl_bai}BBR 관리" +echo -e "${gl_kjlan}6. ${gl_bai}도커 관리" +echo -e "${gl_kjlan}7. ${gl_bai}워프 관리" +echo -e "${gl_kjlan}8. ${gl_bai}테스트 스크립트 수집" +echo -e "${gl_kjlan}9. ${gl_bai}Oracle Cloud 스크립트 컬렉션" +echo -e "${gl_huang}10. ${gl_bai}LDNMP 웹사이트 구축" +echo -e "${gl_kjlan}11. ${gl_bai}응용 시장" +echo -e "${gl_kjlan}12. ${gl_bai}백엔드 작업공간" +echo -e "${gl_kjlan}13. ${gl_bai}시스템 도구" +echo -e "${gl_kjlan}14. ${gl_bai}서버 클러스터 제어" +echo -e "${gl_kjlan}15. ${gl_bai}광고 칼럼" +echo -e "${gl_kjlan}16. ${gl_bai}게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}00. ${gl_bai}脚本更新" +echo -e "${gl_kjlan}00. ${gl_bai}스크립트 업데이트" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}退出脚本" +echo -e "${gl_kjlan}0. ${gl_bai}스크립트 종료" echo -e "${gl_kjlan}------------------------${gl_bai}" -read -e -p "请输入你的选择: " choice +read -e -p "선택사항을 입력하세요:" choice case $choice in 1) linux_info ;; - 2) clear ; send_stats "系统更新" ; linux_update ;; - 3) clear ; send_stats "系统清理" ; linux_clean ;; + 2) clear ; send_stats "시스템 업데이트" ; linux_update ;; + 3) clear ; send_stats "시스템 정리" ; linux_clean ;; 4) linux_tools ;; 5) linux_bbr ;; 6) linux_docker ;; - 7) clear ; send_stats "warp管理" ; install wget + 7) clear ; send_stats "워프 관리" ; install wget wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh ; bash menu.sh [option] [lisence/url/token] ;; 8) linux_test ;; @@ -21113,7 +21546,7 @@ case $choice in 16) games_server_tools ;; 00) kejilion_update ;; 0) clear ; exit ;; - *) echo "无效的输入!" ;; + *) echo "입력이 잘못되었습니다!" ;; esac break_end done @@ -21121,76 +21554,76 @@ done k_info() { -send_stats "k命令参考用例" +send_stats "k 명령 참조 예" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" -echo "启动脚本 k" -echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" -echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" -echo "更新系统 k update | k 更新" -echo "清理系统垃圾 k clean | k 清理" -echo "重装系统面板 k dd | k 重装" -echo "bbr3控制面板 k bbr3 | k bbrv3" -echo "内核调优面板 k nhyh | k 内核优化" -echo "设置虚拟内存 k swap 2048" -echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" -echo "ssh远程连接工具 k ssh | k 远程连接" -echo "rsync远程同步工具 k rsync | k 远程同步" -echo "硬盘管理工具 k disk | k 硬盘管理" -echo "内网穿透(服务端) k frps" -echo "内网穿透(客户端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " -echo "软件停止 k stop sshd | k 停止 sshd " -echo "软件重启 k restart sshd | k 重启 sshd " -echo "软件状态查看 k status sshd | k 状态 sshd " -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " -echo "域名证书申请 k ssl" -echo "域名证书到期查询 k ssl ps" -echo "docker管理平面 k docker" -echo "docker环境安装 k docker install |k docker 安装" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" -echo "安装L4负载均衡 k stream |k L4负载均衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" -echo "命令收藏夹 k fav | k 命令收藏夹" -echo "应用市场管理 k app" -echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" -echo "显示系统信息 k info" -echo "ROOT密钥管理 k sshkey" -echo "SSH公钥导入(URL) k sshkey " -echo "SSH公钥导入(GitHub) k sshkey github " +echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "다음은 k 명령의 참조 사용 사례입니다." +echo "시작 스크립트 k" +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" +echo "시스템 k 업데이트 업데이트 | k 업데이트" +echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" +echo "시스템 패널을 다시 설치하십시오. k dd | k 다시 설치하다" +echo "bbr3 제어판 k bbr3 | kbbrv3" +echo "커널 튜닝 패널 k nhyh | k 커널 최적화" +echo "가상 메모리 k 스왑 2048 설정" +echo "가상 시간대 설정 k 시간 아시아/상하이 | k 시간대 아시아/상하이" +echo "시스템 휴지통 k 쓰레기 | khsz | k 휴지통" +echo "시스템 백업 기능 k 백업 | k bf | k 백업" +echo "SSH 원격 연결 도구 k SSH | k 원격 연결" +echo "rsync 원격 동기화 도구 k rsync | k 원격 동기화" +echo "하드 디스크 관리 도구 k 디스크 | k 하드 디스크 관리" +echo "인트라넷 침투(서버) k frps" +echo "인트라넷 침투(클라이언트) k frpc" +echo "소프트웨어 시작 k start sshd | k sshd를 시작하세요" +echo "소프트웨어 중지 k 중지 sshd | k sshd 중지" +echo "소프트웨어 재시작 k 재시작 sshd | k sshd를 다시 시작하세요" +echo "소프트웨어 상태 확인 k status sshd | k 상태 sshd" +echo "k 도커 활성화 | k 자동 시작 도커 | k 소프트웨어를 부팅할 때 도커를 활성화합니다." +echo "도메인 이름 인증서 신청 k SSL" +echo "도메인 이름 인증서 만료 쿼리 k SSL ps" +echo "도커 관리 플레인 k 도커" +echo "docker 환경 설치 k docker 설치 |k docker 설치" +echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" +echo "도커 이미지 관리 k docker img |k 도커 이미지" +echo "LDNMP 사이트 관리 k web" +echo "LDNMP 캐시 정리 k 웹 캐시" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" +echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" +echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" +echo "방화벽 패널 k fhq |k 방화벽" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" +echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" +echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" +echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" +echo "애플리케이션 시장관리 kapp" +echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" +echo "Fail2ban 관리 k Fail2ban | 케이 F2B" +echo "시스템 정보 표시 k 정보" +echo "ROOT 키 관리 k sshkey" +echo "SSH 공개 키 가져오기(URL) k sshkey " +echo "SSH 공개 키 가져오기(GitHub) k sshkey github " } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 인수 없이 대화형 논리를 실행합니다. kejilion_sh else - # 如果有参数,执行相应函数 + # 매개변수가 있으면 해당 함수를 실행합니다. case $1 in install|add|安装) shift - send_stats "安装软件" + send_stats "소프트웨어 설치" install "$@" ;; remove|del|uninstall|卸载) shift - send_stats "卸载软件" + send_stats "소프트웨어 제거" remove "$@" ;; update|更新) @@ -21224,7 +21657,7 @@ else rsync_run) shift - send_stats "定时rsync同步" + send_stats "예약된 rsync 동기화" run_task "$@" ;; @@ -21243,7 +21676,7 @@ else find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" - echo "已阻止IP+端口访问该服务" + echo "IP+포트가 서비스 접근을 차단했습니다." else ip_address close_port "$port" @@ -21262,13 +21695,13 @@ else swap) shift - send_stats "快速设置虚拟内存" + send_stats "가상 메모리를 빠르게 설정하세요" add_swap "$@" ;; time|时区) shift - send_stats "快速设置时区" + send_stats "시간대를 빠르게 설정" set_timedate "$@" ;; @@ -21316,42 +21749,42 @@ else status|状态) shift - send_stats "软件状态查看" + send_stats "소프트웨어 상태 확인" status "$@" ;; start|启动) shift - send_stats "软件启动" + send_stats "소프트웨어 시작" start "$@" ;; stop|停止) shift - send_stats "软件暂停" + send_stats "소프트웨어 일시 중지" stop "$@" ;; restart|重启) shift - send_stats "软件重启" + send_stats "소프트웨어 재시작" restart "$@" ;; enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "부팅 시 소프트웨어가 자동으로 시작됩니다." enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "인증서 상태 보기" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "빨리 자격증 신청하세요" elif [ -n "$1" ]; then add_ssl "$1" - send_stats "快速申请证书" + send_stats "빨리 자격증 신청하세요" else k_info fi @@ -21361,15 +21794,15 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "도커를 빠르게 설치하세요" install_docker ;; ps|容器) - send_stats "快捷容器管理" + send_stats "빠른 컨테이너 관리" docker_ps ;; img|镜像) - send_stats "快捷镜像管理" + send_stats "빠른 이미지 관리" docker_image ;; *) @@ -21396,10 +21829,13 @@ else app) shift - send_stats "应用$@" + send_stats "신청$@" linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info @@ -21415,30 +21851,30 @@ else shift case "$1" in "" ) - # sshkey → 交互菜单 - send_stats "SSHKey 交互菜单" + # sshkey → 대화형 메뉴 + send_stats "SSHKey 대화형 메뉴" sshkey_panel ;; github ) shift - send_stats "从 GitHub 导入 SSH 公钥" + send_stats "GitHub에서 SSH 공개 키 가져오기" fetch_github_ssh_keys "$1" ;; http://*|https://* ) - send_stats "从 URL 导入 SSH 公钥" + send_stats "URL에서 SSH 공개 키 가져오기" fetch_remote_ssh_keys "$1" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) - send_stats "公钥直接导入" + send_stats "공개 키를 직접 가져오기" import_sshkey "$1" ;; * ) - echo "错误:未知参数 '$1'" - echo "用法:" - echo " k sshkey 进入交互菜单" - echo " k sshkey \"\" 直接导入 SSH 公钥" - echo " k sshkey 从 URL 导入 SSH 公钥" - echo " k sshkey github 从 GitHub 导入 SSH 公钥" + echo "오류: 알 수 없는 매개변수 '$1'" + echo "용법:" + echo "k sshkey가 대화형 메뉴로 들어갑니다." + echo "k sshkey \"\" SSH 공개 키 직접 가져오기" + echo "k sshkey URL에서 SSH 공개 키 가져오기" + echo "k sshkey github GitHub에서 SSH 공개 키 가져오기" ;; esac diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 055542ac0..182f2cc84 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.7" +sh_v="4.4.9" gl_hui='\e[37m' @@ -1221,7 +1221,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1492,7 +1492,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "網站資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -4163,7 +4163,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4779,7 +4779,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -7665,7 +7665,7 @@ linux_tools() { echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" - echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全局搜索工具" + echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文字編輯器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI程式設計助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8735,7 +8735,7 @@ linux_test() { 32) send_stats "spiritysdx融合怪測評" clear - curl -L ${gh_proxy}gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh + curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; 33) @@ -10035,7 +10035,8 @@ moltbot_menu() { local update_message=$(check_openclaw_update) echo "=======================================" - echo -e "ClawdBot > MoltBot > OpenClaw 管理" + echo -e "🦞 OPENCLAW 管理工具 by KEJILION 🦞" + echo -e "💡 終端執行 \033[1;33mk claw\033[0m 快速進入選單" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 安裝" @@ -10054,10 +10055,12 @@ moltbot_menu() { echo "13. WebUI存取與設置" echo "14. TUI命令列對話窗口" echo "15. 記憶/Memory" + echo "16. 權限管理" + echo "17. 多智能體管理" echo "--------------------" - echo "16. 備份與還原" - echo "17. 更新" - echo "18. 卸載" + echo "18. 備份與還原" + echo "19. 更新" + echo "20. 卸載" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -10088,7 +10091,8 @@ moltbot_menu() { } configure_openclaw_session_policy() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 1 @@ -10119,7 +10123,8 @@ PY sync_openclaw_api_models() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) [ ! -f "$config_file" ] && return 0 @@ -10139,36 +10144,6 @@ path = sys.argv[1] stats_enabled = (sys.argv[2].lower() == "true") if len(sys.argv) > 2 else True script_version = sys.argv[3] if len(sys.argv) > 3 else "" -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def send_stat(action): if not stats_enabled: return @@ -10331,36 +10306,6 @@ def delete_provider_and_refs(name): return True -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - - def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): last_error = None for attempt in range(1, retries + 1): @@ -10403,16 +10348,6 @@ for name, provider in list(providers.items()): api = '' changed = True - try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - changed = True - summary.append(f'🔁 {name}: 已自動修正協定為 {detected_api} ({detected_reason})') - except Exception as e: - summary.append(f'⚠️ {name}: 協定偵測失敗,跳過修正 ({type(e).__name__}: {e})') - data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models 偵測失敗,已重試 {attempts} 次 ({type(err).__name__}: {err})') @@ -10459,15 +10394,6 @@ for name, provider in list(providers.items()): removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] - if added_ids: - summary.append(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - summary.append(f' + {mid}') - if removed_ids: - summary.append(f'➖ 刪除模型({len(removed_ids)}):') - for mid in removed_ids: - summary.append(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] @@ -10514,7 +10440,17 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: 刪除 {len(removed_ids)} 個,新增 {len(added_ids)} 個,目前 {len(new_models)} 個') + summary.append(f'✅ {name}: 新增 {len(added_ids)} 個,刪除 {len(removed_ids)} 個,目前 {len(new_models)} 個') + + if added_ids: + summary.append(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + summary.append(f' + {mid}') + if removed_ids: + summary.append(f'➖ 刪除模型({len(removed_ids)}):') + for mid in removed_ids: + summary.append(f' - {mid}') + if fatal_errors: for line in summary: @@ -10543,6 +10479,7 @@ PY install_moltbot() { echo "開始安裝 OpenClaw..." send_stats "開始安裝 OpenClaw..." + install git jq install_node_and_tools @@ -10551,12 +10488,13 @@ PY npm config set registry https://registry.npmmirror.com fi - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest openclaw onboard --install-daemon openclaw config set tools.profile full + openclaw config set tools.elevated.enabled true # 提示:修改配置後如需立即生效,可重新啟動 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway @@ -10594,91 +10532,23 @@ PY - # OpenClaw API 協定探測(優先 responses -> completions) - openclaw_probe_api_endpoint() { - local base_url="$1" - local api_key="$2" - local path="$3" - local url="${base_url%/}${path}" - local http_code - http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 8 \ - -X POST \ - -H "Authorization: Bearer $api_key" \ - -H "Content-Type: application/json" \ - -d '{}' "$url" 2>/dev/null || echo "000") - if [ -z "$http_code" ]; then - http_code="000" - fi - echo "$http_code" - } - - openclaw_detect_api_protocol() { - local base_url="$1" - local api_key="$2" - local code_responses="000" - - DETECTED_API="openai-completions" - DETECTED_REASON="fallback: /responses not supported" - - code_responses=$(openclaw_probe_api_endpoint "$base_url" "$api_key" "/responses") - if [[ "$code_responses" != "404" && "$code_responses" != "405" && "$code_responses" != "000" ]]; then - DETECTED_API="openai-responses" - DETECTED_REASON="POST /responses -> HTTP $code_responses" - return 0 - fi - - DETECTED_API="openai-completions" - DETECTED_REASON="POST /responses=$code_responses -> fallback /completions" - return 0 - } + # OpenClaw API 協定偵測邏輯已移除:不再自動偵測/判定 API 類型。 + # 說明:API 類型由使用者明確配置(models.providers..api),腳本不再嘗試呼叫 /responses 做推論。 - # 核心函數:取得並加入所有模型 - add-all-models-from-provider() { + # 建構模型配置 JSON + build-openclaw-provider-models-json() { local provider_name="$1" - local base_url="$2" - local api_key="$3" - local config_file="${HOME}/.openclaw/openclaw.json" - - echo "🔍 正在獲取$provider_name的所有可用模型..." - - # 自動識別 API 協議 - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" - - # 取得模型列表 - local models_json=$(curl -s -m 10 \ - -H "Authorization: Bearer $api_key" \ - "${base_url}/models") - - if [[ -z "$models_json" ]]; then - echo "❌ 無法取得模型列表" - return 1 - fi - - # 提取所有模型ID - local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') - - if [[ -z "$model_ids" ]]; then - echo "❌ 未找到任何模型" - return 1 - fi - - local model_count=$(echo "$model_ids" | wc -l) - echo "✅ 發現$model_count個模型" - - # 智慧推斷模型參數 + local model_ids="$2" local models_array="[" local first=true while read -r model_id; do + [ -z "$model_id" ] && continue [[ $first == false ]] && models_array+="," first=false - # context 和 max_tokens 全拉滿,不怕大 local context_window=1048576 local max_tokens=128000 - - # 只有價格需要分級 local input_cost=0.15 local output_cost=0.60 @@ -10716,11 +10586,23 @@ EOF done <<< "$model_ids" models_array+="]" + echo "$models_array" + } + + # 寫入 provider 與模型配置 + write-openclaw-provider-models() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local models_array="$4" + local config_file + config_file=$(openclaw_get_config_file) + + # 不再自動探測/修正 API 協定;保持使用者配置為準 + DETECTED_API="openai-completions" - # 備份配置 [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" - # 使用jq注入所有模型,並同步 defaults.models jq --arg prov "$provider_name" \ --arg url "$base_url" \ --arg key "$api_key" \ @@ -10754,6 +10636,39 @@ EOF ) ) ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" + } + + # 核心函數:取得並加入所有模型 + add-all-models-from-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + + echo "🔍 正在獲取$provider_name的所有可用模型..." + + local models_json=$(curl -s -m 10 \ + -H "Authorization: Bearer $api_key" \ + "${base_url}/models") + + if [[ -z "$models_json" ]]; then + echo "❌ 無法取得模型列表" + return 1 + fi + + local model_ids=$(echo "$models_json" | grep -oP '"id":\s*"\K[^"]+') + + if [[ -z "$model_ids" ]]; then + echo "❌ 未找到任何模型" + return 1 + fi + + local model_count=$(echo "$model_ids" | wc -l) + echo "✅ 發現$model_count個模型" + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then echo "✅ 成功添加$model_count個模型到$provider_name" @@ -10765,9 +10680,36 @@ EOF fi } + # 僅添加預設模型並保留 provider + add-default-model-only-to-provider() { + local provider_name="$1" + local base_url="$2" + local api_key="$3" + local default_model="$4" + + if [[ -z "$default_model" ]]; then + echo "❌ 預設模型不能為空" + return 1 + fi + + local models_array + models_array=$(build-openclaw-provider-models-json "$provider_name" "$default_model") + + write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" + + if [[ $? -eq 0 ]]; then + echo "✅ 已新增 provider:$provider_name" + echo "✅ 僅寫入預設模型:$default_model" + return 0 + else + echo "❌ 配置注入失敗" + return 1 + fi + } + add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10793,9 +10735,7 @@ EOF echo done - # 4. 協議探測(無感) - install curl >/dev/null 2>&1 - openclaw_detect_api_protocol "$base_url" "$api_key" + # 4. 不再偵測/判斷 API 類型;協定由使用者自行選擇與維護 # 5. 取得模型列表 echo "🔍 正在取得可用模型清單..." @@ -10846,22 +10786,27 @@ EOF echo "模型總數 :$model_count" echo "======================" - read -erp "確認添加所有$model_count個模型? (y/N):" confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "❎ 已取消" - return 1 - fi + read -erp "是否同時新增其他所有可用模型? (y/N):" confirm install jq - add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + if [[ "$confirm" =~ ^[Yy]$ ]]; then + add-all-models-from-provider "$provider_name" "$base_url" "$api_key" + add_result=$? + finish_msg="✅ 完成!所有$model_count個模型已載入" + else + add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" + add_result=$? + finish_msg="✅ 完成!已保留 provider,並僅載入預設模型:$default_model" + fi - if [[ $? -eq 0 ]]; then + if [[ $add_result -eq 0 ]]; then echo echo "🔄 設定預設模型並重新啟動網關..." openclaw models set "$provider_name/$default_model" + openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway - echo "✅ 完成!所有$model_count個模型已載入" - echo "✅ 已自動辨識協定為:$DETECTED_API" + echo "$finish_msg" + echo "✅ 當前 API 協定類型:$DETECTED_API" fi break_end @@ -10996,15 +10941,15 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "請輸入要同步的 API 名稱(provider),直接 Enter 同步全部: " provider_name + read -erp "請輸入要同步的 API 名稱(provider),直接回車同步全部:" provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ API 模型同步失敗,已中止重啟網關。請檢查 provider /models 後重試。" - break_end + echo "❌ API 模型同步失敗,已中止重新啟動網關。請檢查 provider /models 返回後重試。" return 1 fi + break_end return 0 fi @@ -11021,35 +10966,6 @@ path = sys.argv[1] target = sys.argv[2] SUPPORTED_APIS = {'openai-completions', 'openai-responses'} -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) @@ -11133,19 +11049,9 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 目前 api={api},重新探測協定後繼續') - provider['api'] = '' - api = '' + print(f'ℹ️ provider {target} 目前 api={api},但腳本已不再探測/修正協定;請手動設定為 openai-completions 或 openai-responses') protocol_msg = None -try: - detected_api, detected_reason, detect_err = detect_api_protocol(base_url, api_key) - if detected_api and api != detected_api: - provider['api'] = detected_api - api = detected_api - protocol_msg = f'🔁 已自動修正協定: {target} {api} ({detected_reason})' -except Exception as e: - protocol_msg = f'⚠️ 協定探測失敗,跳過修正: {target} ({type(e).__name__}: {e})' data, err, attempts = fetch_remote_models_with_retry(base_url, api_key, retries=3) if err is not None: @@ -11177,15 +11083,6 @@ if template is None: removed_ids = [mid for mid in local_ids if mid not in remote_set] added_ids = [mid for mid in remote_ids if mid not in local_set] -if added_ids: - print(f'➕ 新增模型({len(added_ids)}):') - for mid in added_ids: - print(f' + {mid}') -if removed_ids: - print(f'➖ 刪除模型({len(removed_ids)}):') - for mid in removed_ids: - print(f' - {mid}') - kept_models = [copy.deepcopy(m) for m in local_models if str(m['id']) in remote_set] new_models = kept_models[:] for mid in added_ids: @@ -11232,15 +11129,23 @@ if removed_ids or added_ids or len(local_models) != len(new_models): provider['models'] = new_models changed = True -if protocol_msg: - print(protocol_msg) if changed: with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 刪除 {len(removed_ids)} 個,新增 {len(added_ids)} 個,目前 {len(new_models)} 個') +print(f'✅ {target}: 新增 {len(added_ids)} 個,刪除 {len(removed_ids)} 個,目前 {len(new_models)} 個') + +if added_ids: + print(f'➕ 新增模型({len(added_ids)}):') + for mid in added_ids: + print(f' + {mid}') +if removed_ids: + print(f'➖ 刪除模型({len(removed_ids)}):') + for mid in removed_ids: + print(f' - {mid}') + if changed: print('✅ 指定 provider 模型一致性同步完成並已寫入配置') else: @@ -11273,85 +11178,15 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - local config_file="$1" - local provider_name="$2" - - python3 - "$config_file" "$provider_name" <<'PY' -import json -import sys -import urllib.request - -path = sys.argv[1] -name = sys.argv[2] -SUPPORTED_APIS = {'openai-completions', 'openai-responses'} - -def probe_endpoint(base_url, api_key, path, timeout=6): - url = base_url.rstrip('/') + path - req = urllib.request.Request( - url, - data=b'{}', - headers={ - 'Authorization': f'Bearer {api_key}', - 'Content-Type': 'application/json', - 'User-Agent': 'OpenClaw-API-Manage/1.0', - }, - method='POST', - ) - try: - with urllib.request.urlopen(req, timeout=timeout) as resp: - return resp.getcode(), None - except urllib.error.HTTPError as e: - return e.code, None - except Exception as e: - return None, e - - -def detect_api_protocol(base_url, api_key): - code, err = probe_endpoint(base_url, api_key, '/responses') - if code is not None and code not in (404, 405): - return 'openai-responses', f'POST /responses -> HTTP {code}', None - if err: - return 'openai-completions', 'fallback: probe failed', err - return 'openai-completions', f'POST /responses={code} -> fallback /completions', None - -try: - with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) -except FileNotFoundError: - print('❌ 找不到 openclaw.json') - raise SystemExit(2) - -providers = ((obj.get('models') or {}).get('providers') or {}) -provider = providers.get(name) if isinstance(providers, dict) else None -if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {name}') - raise SystemExit(2) - -base_url = provider.get('baseUrl') -api_key = provider.get('apiKey') -if not base_url or not api_key: - print(f'❌ provider {name} 缺少 baseUrl/apiKey') - raise SystemExit(3) - -current_api = provider.get('api', '') -if current_api not in SUPPORTED_APIS: - current_api = '' - -api, reason, err = detect_api_protocol(base_url, api_key) -if api and api != current_api: - provider['api'] = api - with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') - print(f'✅ 已更新 provider {name} 協定: {current_api or "(unset)"} -> {api} ({reason})') -else: - print(f'ℹ️ 無需更新:協議保持為 {current_api or api}') -PY + # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 + # 保留函數以相容選單調用,但不做任何改寫。 + echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" + return 0 } fix-openclaw-provider-protocol-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API協定修復" + send_stats "OpenClaw API協定切換" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11359,29 +11194,75 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - read -erp "請輸入要修復協定的 API 名稱(provider):" provider_name + read -erp "請輸入要切換協定的 API 名稱(provider):" provider_name if [ -z "$provider_name" ]; then echo "❌ provider 名稱不能為空" break_end return 1 fi - install jq curl >/dev/null 2>&1 - openclaw_detect_api_protocol_by_provider "$config_file" "$provider_name" + echo "請選擇要設定的 API 類型:" + echo "1. openai-completions" + echo "2. openai-responses" + read -erp "請輸入你的選擇 (1/2):" proto_choice + + local new_api="" + case "$proto_choice" in + 1) new_api="openai-completions" ;; + 2) new_api="openai-responses" ;; + *) + echo "❌ 無效選擇" + break_end + return 1 + ;; + esac + + install python3 >/dev/null 2>&1 + + python3 - "$config_file" "$provider_name" "$new_api" <<'PY' +import copy +import json +import sys + +path = sys.argv[1] +name = sys.argv[2] +new_api = sys.argv[3] + +SUPPORTED_APIS = {'openai-completions', 'openai-responses'} +if new_api not in SUPPORTED_APIS: + print('❌ 非法協議值') + raise SystemExit(3) + +with open(path, 'r', encoding='utf-8') as f: + obj = json.load(f) + +work = copy.deepcopy(obj) +providers = ((work.get('models') or {}).get('providers') or {}) +if not isinstance(providers, dict) or name not in providers or not isinstance(providers.get(name), dict): + print(f'❌ 未找到 provider: {name}') + raise SystemExit(2) + +providers[name]['api'] = new_api + +with open(path, 'w', encoding='utf-8') as f: + json.dump(work, f, ensure_ascii=False, indent=2) + f.write('\n') + +print(f'✅ 已更新 provider {name} 協定為: {new_api}') +PY local rc=$? case "$rc" in 0) - echo "✅ 協議已檢測並更新(如有變更)" start_gateway ;; 2) - echo "❌ 修復失敗:provider 不存在或未配置" + echo "❌ 切換失敗:provider 不存在或未配置" ;; 3) - echo "❌ 修復失敗:provider 配置不完整" + echo "❌ 切換失敗:協定值非法" ;; *) - echo "❌ 修復失敗:請檢查設定檔結構或日誌輸出" + echo "❌ 切換失敗:請檢查設定檔結構或日誌輸出" ;; esac @@ -11389,7 +11270,8 @@ fix-openclaw-provider-protocol-interactive() { } delete-openclaw-provider-interactive() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) send_stats "OpenClaw API刪除入口" if [ ! -f "$config_file" ]; then @@ -11537,6 +11419,66 @@ PY break_end } + openclaw_api_providers_showcase() { + send_stats "OpenClaw API廠商推薦" + + clear + echo "" + echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 廠商推薦列表${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}部分入口含 AFF${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" + echo "" + echo -e " ${gl_lv}● DeepSeek${gl_bai}" + echo -e " ${gl_kjlan}https://api-docs.deepseek.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● OpenRouter${gl_bai}" + echo -e " ${gl_kjlan}https://openrouter.ai/${gl_bai}" + echo "" + echo -e " ${gl_lv}● Kimi${gl_bai}" + echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" + echo "" + echo -e " ${gl_lv}● 超算互聯網${gl_bai}" + echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" + echo "" + echo -e " ${gl_huang}● 優雲智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" + echo "" + echo -e " ${gl_huang}● 矽基流動${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" + echo "" + echo -e " ${gl_huang}● 智譜 GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.bigmodel.cn/glm-coding?ic=HYOTDOAJMR${gl_bai}" + echo "" + echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" + echo "" + echo -e " ${gl_huang}● 雲霧 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" + echo "" + echo -e " ${gl_huang}●柏拉圖AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" + echo "" + echo -e " ${gl_lv}● MiniMax${gl_bai}" + echo -e " ${gl_kjlan}https://www.minimaxi.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● NVIDIA${gl_bai}" + echo -e " ${gl_kjlan}https://build.nvidia.com/settings/api-keys${gl_bai}" + echo "" + echo -e " ${gl_lv}● Ollama${gl_bai}" + echo -e " ${gl_kjlan}https://ollama.com/${gl_bai}" + echo "" + echo -e " ${gl_lv}● 白山雲${gl_bai}" + echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" + echo "" + echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" + echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推薦入口${gl_bai}" + echo "" + echo -e "${gl_huang}提示:複製連結到瀏覽器開啟即可訪問${gl_bai}" + echo "" + read -erp "按回車鍵返回..." dummy + } + openclaw_api_manage_menu() { send_stats "OpenClaw API入口" while true; do @@ -11548,8 +11490,9 @@ PY echo "---------------------------------------" echo "1. 新增API" echo "2. 同步API供應商模型列表" - echo "3. 刪除API" - echo "4. 協議修復/重新探測" + echo "3. 切換 API 類型(completions / responses)" + echo "4. 刪除API" + echo "5. API 廠商推薦" echo "0. 退出" echo "---------------------------------------" read -erp "請輸入你的選擇:" api_choice @@ -11562,10 +11505,13 @@ PY sync-openclaw-provider-interactive ;; 3) - delete-openclaw-provider-interactive + fix-openclaw-provider-protocol-interactive ;; 4) - fix-openclaw-provider-protocol-interactive + delete-openclaw-provider-interactive + ;; + 5) + openclaw_api_providers_showcase ;; 0) return 0 @@ -11580,52 +11526,255 @@ PY - install_gum() { - if command -v gum >/dev/null 2>&1; then - return 0 - fi - if [ -f /etc/debian_version ]; then - mkdir -p /etc/apt/keyrings - curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg - echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null - apt update && apt install -y gum - elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then - cat > /etc/yum.repos.d/charm.repo <<'REPO' -[charm] -name=Charm -baseurl=https://repo.charm.sh/yum/ -enabled=1 -gpgcheck=1 -gpgkey=https://repo.charm.sh/yum/gpg.key -REPO - rpm --import https://repo.charm.sh/yum/gpg.key - if command -v dnf >/dev/null 2>&1; then - dnf install -y gum - else - yum install -y gum - fi - elif command -v zypper >/dev/null 2>&1; then - zypper --non-interactive refresh - zypper --non-interactive install gum - fi - } + install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + + if command -v apt >/dev/null 2>&1; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update && apt install -y gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then + dnf install -y gum + else + yum install -y gum + fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install gum + fi + } + + + + change_model() { + send_stats "換模型" + + local orange="#FF8C00" + + openclaw_probe_status_line() { + local status_text="$1" + local status_color_ok='' + local status_color_fail='' + local status_color_reset='' + if [ "$status_text" = "可用" ]; then + printf "%b最小检测结果:%s%b +" "$status_color_ok" "$status_text" "$status_color_reset" + else + printf "%b最小检测结果:%s%b +" "$status_color_fail" "$status_text" "$status_color_reset" + fi + } + + openclaw_model_probe() { + local target_model="$1" + local probe_timeout=25 + local tmp_payload tmp_response probe_result probe_status reply_preview reply_trimmed + local oc_config provider_name base_url api_key request_model + local first_endpoint second_endpoint + local first_exit first_http first_latency second_exit second_http second_latency + local first_reply second_reply + + oc_config=$(openclaw_get_config_file) + [ ! -f "$oc_config" ] && { + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未找到 openclaw 設定文件" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + } + + provider_name="${target_model%%/*}" + request_model="${target_model#*/}" + base_url=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].baseUrl // empty' "$oc_config" 2>/dev/null) + api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) + if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then + OPENCLAW_PROBE_STATUS="ERROR" + OPENCLAW_PROBE_MESSAGE="未讀取到 provider/baseUrl/apiKey" + OPENCLAW_PROBE_LATENCY="-" + OPENCLAW_PROBE_REPLY="-" + return 1 + fi + + base_url="${base_url%/}" + first_endpoint="/responses" + second_endpoint="/chat/completions" + + openclaw_extract_probe_reply() { + python3 - "$1" <<'PYTHON_EOF' +import json +import sys +from pathlib import Path +path = Path(sys.argv[1]) +raw = path.read_text(encoding='utf-8', errors='replace').strip() +reply = '' +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get('choices') or [] + if choices and isinstance(choices[0], dict): + message = choices[0].get('message') or {} + if isinstance(message, dict): + reply = message.get('content') or '' + if not reply: + output = data.get('output') or [] + if isinstance(output, list): + texts = [] + for item in output: + if not isinstance(item, dict): + continue + for content in item.get('content') or []: + if not isinstance(content, dict): + continue + text = content.get('text') + if isinstance(text, str) and text.strip(): + texts.append(text.strip()) + if texts: + break + if texts: + reply = ' '.join(texts) + if not reply: + for key in ('error', 'message', 'detail'): + value = data.get(key) + if isinstance(value, str) and value.strip(): + reply = value.strip() + break + if isinstance(value, dict): + nested = value.get('message') + if isinstance(nested, str) and nested.strip(): + reply = nested.strip() + break + except Exception: + reply = raw +reply = ' '.join(str(reply).split()) +print(reply) +PYTHON_EOF + } + + openclaw_run_probe() { + local endpoint="$1" + tmp_payload=$(mktemp) + tmp_response=$(mktemp) + if [ "$endpoint" = "/responses" ]; then + printf '{"model":"%s","input":"hi","temperature":0,"max_output_tokens":16}' "$request_model" > "$tmp_payload" + else + printf '{"model":"%s","messages":[{"role":"user","content":"hi"}],"temperature":0,"max_tokens":16}' "$request_model" > "$tmp_payload" + fi + + probe_result=$(python3 - "$base_url" "$api_key" "$tmp_payload" "$tmp_response" "$probe_timeout" "$endpoint" <<'PYTHON_EOF' +import sys +import time +import urllib.error +import urllib.request + +base_url, api_key, payload_path, response_path, timeout, endpoint = sys.argv[1:7] +timeout = int(timeout) +url = base_url + endpoint +payload = open(payload_path, 'rb').read() +req = urllib.request.Request( + url, + data=payload, + headers={ + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}', + }, + method='POST', +) +start = time.time() +body = b'' +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, 'status', 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, 'code', 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode('utf-8', errors='replace') + exit_code = 1 +elapsed = int((time.time() - start) * 1000) +with open(response_path, 'wb') as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYTHON_EOF +) + probe_status=$? + reply_preview=$(openclaw_extract_probe_reply "$tmp_response") + rm -f "$tmp_payload" "$tmp_response" + return $probe_status + } + + openclaw_run_probe "$first_endpoint" + first_exit=${probe_result%%|*} + first_http=${probe_result#*|} + first_http=${first_http%%|*} + first_latency=${probe_result##*|} + first_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http}" + OPENCLAW_PROBE_LATENCY="${first_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi + openclaw_run_probe "$second_endpoint" + second_exit=${probe_result%%|*} + second_http=${probe_result#*|} + second_http=${second_http%%|*} + second_latency=${probe_result##*|} + second_reply="$reply_preview" + + reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + + if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then + OPENCLAW_PROBE_STATUS="OK" + OPENCLAW_PROBE_MESSAGE="${first_endpoint}-> HTTP ${first_http:-0},切換${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_LATENCY="${second_latency}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 0 + fi - - change_model() { - send_stats "換模型" + reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" - local orange="#FF8C00" + OPENCLAW_PROBE_STATUS="FAIL" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" + OPENCLAW_PROBE_LATENCY="${first_latency:-?}ms -> ${second_latency:-?}ms" + OPENCLAW_PROBE_REPLY="$reply_trimmed" + return 1 + } clear while true; do - local models_raw models_list default_model model_count selected_model + local models_raw models_list default_model model_count selected_model confirm_switch # 從設定檔讀取模型鍵(不呼叫 openclaw models list) local oc_config - oc_config="${HOME}/.openclaw/openclaw.json" - [ ! -f "$oc_config" ] && [ -f /root/.openclaw/openclaw.json ] && oc_config="/root/.openclaw/openclaw.json" + oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then @@ -11642,53 +11791,55 @@ REPO default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" + clear install_gum install gum - - clear - - # 若 gum 不存在,降級為原始手動輸入流程(保持與之前完全一致) - if ! command -v gum >/dev/null 2>&1; then + + # 若 gum 不存在,降級為原始手動輸入流程 + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" echo "目前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" selected_model - # 1. 檢查是否輸入 0 退出 if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." - break # 跳出 while 循环 + break fi - # 2. 驗證輸入是否為空 if [ -z "$selected_model" ]; then echo "錯誤:模型名稱不能為空。請重試。" - echo "" # 换行美化 - continue # 跳过本次循环,重新开始 + echo "" + continue + fi + + echo "正在切換模型為:$selected_model ..." + if ! openclaw models set "$selected_model"; then + echo "切換失敗:openclaw models set 回傳錯誤。" + break_end + return 1 fi + openclaw_sync_sessions_model "$selected_model" + start_gateway + + break_end + return 0 else + if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then + echo "gum 不可用,傳回舊版輸入模式。" + sleep 1 + continue + fi gum style --foreground "$orange" --bold "模型管理" gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "目前預設:${default_model}" echo "" - - # 底部提示 - gum style --faint "↑↓ 選擇 / Enter 確認 / Esc 退出" + gum style --faint "↑↓ 選擇 / Enter 測試 / Esc 退出" echo "" - # gum filter:带搜索;gum 版本差异较大,这里只用兼容性最强的 flags - selected_model=$(echo "$models_list" | gum filter \ - --placeholder "搜尋模型(如 cli-api/gpt-5.2)" \ - --prompt "選擇模型 >" \ - --indicator "➜ " \ - --prompt.foreground "$orange" \ - --indicator.foreground "$orange" \ - --cursor-text.foreground "$orange" \ - --match.foreground "$orange" \ - --header "" \ - --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜尋模型(如 cli-api/gpt-5.2)" --prompt "選擇模型 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -11696,22 +11847,125 @@ REPO fi fi - # 去掉編號前綴:"(10) model" -> "model" selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') - # 執行切換 + echo "" + echo "正在檢測模型:$selected_model" + if openclaw_model_probe "$selected_model"; then + openclaw_probe_status_line "可用" + else + openclaw_probe_status_line "不可用" + fi + echo "狀態:$OPENCLAW_PROBE_MESSAGE" + echo "延遲:$OPENCLAW_PROBE_LATENCY" + echo "摘要:$OPENCLAW_PROBE_REPLY" + echo "" + + printf "是否切換到該模型? [y/N,Esc 返回列表]:" + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'' ]; then + confirm_switch="no" + else + case "$confirm_switch" in + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + [nN]|"") confirm_switch="no" ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "已返回模型選擇清單。" + sleep 1 + continue + fi + echo "正在切換模型為:$selected_model ..." if ! openclaw models set "$selected_model"; then echo "切換失敗:openclaw models set 回傳錯誤。" break_end return 1 fi + openclaw_sync_sessions_model "$selected_model" start_gateway break_end done - } + } + + + openclaw_get_config_file() { + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi + } + openclaw_get_agents_dir() { + local user_agents="${HOME}/.openclaw/agents" + local root_agents="/root/.openclaw/agents" + if [ -d "$user_agents" ]; then + echo "$user_agents" + elif [ "$HOME" = "/root" ] && [ -d "$root_agents" ]; then + echo "$root_agents" + else + echo "$user_agents" + fi + } + + openclaw_sync_sessions_model() { + local model_ref="$1" + [ -z "$model_ref" ] && return 1 + + local agents_dir + agents_dir=$(openclaw_get_agents_dir) + [ ! -d "$agents_dir" ] && return 0 + + local provider="${model_ref%%/*}" + local model="${model_ref#*/}" + [ "$provider" = "$model_ref" ] && { provider=""; model="$model_ref"; } + + local count=0 + local agent_dir sessions_file backup_file + + for agent_dir in "$agents_dir"/*/; do + [ ! -d "$agent_dir" ] && continue + sessions_file="$agent_dir/sessions/sessions.json" + [ ! -f "$sessions_file" ] && continue + + backup_file="${sessions_file}.bak" + cp "$sessions_file" "$backup_file" 2>/dev/null || continue + + if command -v jq >/dev/null 2>&1; then + local tmp_json + tmp_json=$(mktemp) + if [ -n "$provider" ]; then + jq --arg model "$model" --arg provider "$provider" \ + 'to_entries | map(.value.modelOverride = $model | .value.providerOverride = $provider) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + else + jq --arg model "$model" \ + 'to_entries | map(.value.modelOverride = $model | del(.value.providerOverride)) | from_entries' \ + "$sessions_file" > "$tmp_json" 2>/dev/null && \ + mv "$tmp_json" "$sessions_file" && \ + count=$((count + 1)) + fi + fi + done + + [ "$count" -gt 0 ] && echo "✅ 已同步$count個 agent 的會話模型為$model_ref" + return 0 + } resolve_openclaw_plugin_id() { local raw_input="$1" @@ -11729,12 +11983,8 @@ REPO local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11800,12 +12050,8 @@ PYTHON_EOF local plugin_id="$1" [ -z "$plugin_id" ] && return 1 - local home_config="${HOME}/.openclaw/openclaw.json" - local root_config="/root/.openclaw/openclaw.json" - local config_file="$home_config" - if [ ! -f "$home_config" ] && [ -f "$root_config" ]; then - config_file="$root_config" - fi + local config_file + config_file=$(openclaw_get_config_file) mkdir -p "$(dirname "$config_file")" if [ ! -s "$config_file" ]; then @@ -11956,7 +12202,8 @@ PYTHON_EOF fi echo "📥 本機未發現,嘗試下載安裝:$plugin_full" - rm -rf "/root/.openclaw/extensions/$plugin_id" + rm -rf "${HOME}/.openclaw/extensions/$plugin_id" + [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then echo "✅ 下載成功,正在啟用..." if openclaw plugins enable "$plugin_id"; then @@ -11967,7 +12214,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 安装失败:$plugin_full" + echo "❌ 安裝失敗:$plugin_full" failed_list="$failed_list $plugin_id" fi else @@ -12118,7 +12365,8 @@ PYTHON_EOF openclaw_json_get_bool() { local expr="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12128,7 +12376,8 @@ openclaw_json_get_bool() { openclaw_channel_has_cfg() { local channel="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ ! -s "$config_file" ]; then echo "false" return @@ -12155,7 +12404,8 @@ openclaw_json_get_bool() { openclaw_plugin_local_installed() { local plugin="$1" - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) if [ -s "$config_file" ] && jq -e --arg p "$plugin" '.plugins.installs[$p]' "$config_file" >/dev/null 2>&1; then return 0 fi @@ -12205,7 +12455,8 @@ openclaw_json_get_bool() { } openclaw_show_bot_local_status_block() { - local config_file="${HOME}/.openclaw/openclaw.json" + local config_file + config_file=$(openclaw_get_config_file) local json_ok="false" if [ -s "$config_file" ] && jq empty "$config_file" >/dev/null 2>&1; then json_ok="true" @@ -12225,19 +12476,25 @@ openclaw_json_get_bool() { tg_status=$(openclaw_bot_status_text "$tg_enabled" "$tg_cfg" "$tg_connected" "$tg_abnormal") local feishu_enabled feishu_cfg feishu_connected feishu_abnormal feishu_status - feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .channels.feishu.enabled // false') + feishu_enabled=$(openclaw_json_get_bool '.plugins.entries.feishu.enabled // .plugins.entries["openclaw-lark"].enabled // .channels.feishu.enabled // .channels.lark.enabled // false') feishu_cfg=$(openclaw_channel_has_cfg "feishu") + if [ "$feishu_cfg" != "true" ]; then + feishu_cfg=$(openclaw_channel_has_cfg "lark") + fi feishu_connected="false" - if openclaw_dir_has_files "${HOME}/.openclaw/feishu"; then + if openclaw_dir_has_files "${HOME}/.openclaw/feishu" || openclaw_dir_has_files "${HOME}/.openclaw/lark" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-lark"; then feishu_connected="true" fi feishu_abnormal="false" - if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu"; then + if [ "$feishu_enabled" = "true" ] && ! openclaw_plugin_local_installed "feishu" && ! openclaw_plugin_local_installed "lark" && ! openclaw_plugin_local_installed "openclaw-lark"; then feishu_abnormal="true" fi if [ "$feishu_enabled" = "true" ] && [ "$json_ok" != "true" ]; then feishu_abnormal="true" fi + if [ "$feishu_connected" != "true" ] && [ "$feishu_enabled" = "true" ] && [ "$feishu_cfg" = "true" ] && { openclaw_plugin_local_installed "feishu" || openclaw_plugin_local_installed "lark" || openclaw_plugin_local_installed "openclaw-lark"; }; then + feishu_connected="true" + fi feishu_status=$(openclaw_bot_status_text "$feishu_enabled" "$feishu_cfg" "$feishu_connected" "$feishu_abnormal") local wa_enabled wa_cfg wa_connected wa_abnormal wa_status @@ -12301,6 +12558,25 @@ openclaw_json_get_bool() { fi qq_status=$(openclaw_bot_status_text "$qq_enabled" "$qq_cfg" "$qq_connected" "$qq_abnormal") + local wx_enabled wx_cfg wx_connected wx_abnormal wx_status + wx_enabled=$(openclaw_json_get_bool '.plugins.entries.weixin.enabled // .plugins.entries["openclaw-weixin"].enabled // .channels.weixin.enabled // .channels["openclaw-weixin"].enabled // false') + wx_cfg=$(openclaw_channel_has_cfg "weixin") + if [ "$wx_cfg" != "true" ]; then + wx_cfg=$(openclaw_channel_has_cfg "openclaw-weixin") + fi + wx_connected="false" + if openclaw_dir_has_files "${HOME}/.openclaw/weixin" || openclaw_dir_has_files "${HOME}/.openclaw/openclaw-weixin"; then + wx_connected="true" + fi + wx_abnormal="false" + if [ "$wx_enabled" = "true" ] && ! openclaw_plugin_local_installed "weixin" && ! openclaw_plugin_local_installed "openclaw-weixin"; then + wx_abnormal="true" + fi + if [ "$wx_enabled" = "true" ] && [ "$json_ok" != "true" ]; then + wx_abnormal="true" + fi + wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") + echo "本機狀態(僅本機配置/緩存,不做網路探測):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飛書(Lark)" "$feishu_status" @@ -12308,6 +12584,7 @@ openclaw_json_get_bool() { openclaw_print_bot_status_line "Discord" "$dc_status" openclaw_print_bot_status_line "Slack" "$slack_status" openclaw_print_bot_status_line "QQ Bot" "$qq_status" + openclaw_print_bot_status_line "微信 (Weixin)" "$wx_status" } change_tg_bot_code() { @@ -12322,6 +12599,8 @@ openclaw_json_get_bool() { echo "1. Telegram 機器人對接" echo "2. 飛書 (Lark) 機器人對接" echo "3. WhatsApp 機器人對接" + echo "4. QQ 機器人對接" + echo "5. 微信機器人對接" echo "----------------------------------------" echo "0. 返回上一級選單" echo "----------------------------------------" @@ -12336,10 +12615,9 @@ openclaw_json_get_bool() { break_end ;; 2) - read -e -p "請輸入飛書機器人收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code - if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi - openclaw pairing approve feishu "$code" + npx -y @larksuite/openclaw-lark install + openclaw config set channels.feishu.streaming true + openclaw config set channels.feishu.requireMention true --json break_end ;; 3) @@ -12349,6 +12627,15 @@ openclaw_json_get_bool() { openclaw pairing approve whatsapp "$code" break_end ;; + 4) + echo "QQ 官方對接位址:" + echo "https://q.qq.com/qqbot/openclaw/login.html" + break_end + ;; + 5) + npx -y @tencent-weixin/openclaw-weixin-cli@latest install + break_end + ;; 0) return 0 ;; @@ -12491,132 +12778,89 @@ EOF return 0 } + openclaw_get_all_agent_workspaces() { + local config_file + config_file=$(openclaw_get_config_file) + if [ -f "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json, sys, os +try: + with open(sys.argv[1]) as f: data = json.load(f) + agents = data.get("agents", {}).get("list", []) + results = [{"id": "main", "ws": os.path.expanduser("~/.openclaw/workspace")}] + for a in agents: + aid = a.get("id"); ws = a.get("workspace") + if aid and ws and aid != "main": results.append({"id": aid, "ws": os.path.expanduser(ws)}) + print(json.dumps(results)) +except: print("[]") +PY + else + echo '[{"id": "main", "ws": "'"${HOME}"'/.openclaw/workspace"}]' + fi + } + openclaw_memory_backup_export() { send_stats "OpenClaw記憶全量備份" - local workspace_dir="${HOME}/.openclaw/workspace" - local backup_root - backup_root=$(openclaw_backup_root) - local ts - ts=$(date +%Y%m%d-%H%M%S) + local backup_root=$(openclaw_backup_root) + local ts=$(date +%Y%m%d-%H%M%S) local out_file="$backup_root/openclaw-memory-full-${ts}.tar.gz" - mkdir -p "$backup_root" - if [ ! -d "$workspace_dir" ]; then - echo "❌ 未找到 workspace 目录: $workspace_dir" - break_end - return 1 - fi - - local tmp_payload - tmp_payload=$(mktemp -d) || return 1 - - [ -f "$workspace_dir/MEMORY.md" ] && cp -a "$workspace_dir/MEMORY.md" "$tmp_payload/" - [ -d "$workspace_dir/memory" ] && cp -a "$workspace_dir/memory" "$tmp_payload/" - - read -e -p "是否附帶 AGENTS/USER/SOUL/TOOLS 檔案? (y/N):" include_optional - if [[ "$include_optional" =~ ^[Yy]$ ]]; then - for f in AGENTS.md USER.md SOUL.md TOOLS.md; do - [ -f "$workspace_dir/$f" ] && cp -a "$workspace_dir/$f" "$tmp_payload/" - done - fi - + local tmp_payload=$(mktemp -d) || return 1 + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c "import json, sys, os, shutil; +workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] +for item in workspaces: + aid = item['id']; ws = item['ws'] + if not os.path.isdir(ws): continue + target_dir = os.path.join(tmp_payload, 'agents', aid) + os.makedirs(target_dir, exist_ok=True) + for f in ['MEMORY.md', 'memory']: + src = os.path.join(ws, f) + if os.path.exists(src): + if os.path.isfile(src): shutil.copy2(src, target_dir) + else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) +" "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可備份的記憶文件" - rm -rf "$tmp_payload" - break_end - return 1 + echo "❌ 未找到可備份的記憶文件"; rm -rf "$tmp_payload"; break_end; return 1 fi - - if openclaw_pack_backup_archive "memory-full" "default" "$tmp_payload" "$out_file"; then - echo "✅ 記憶全量備份完成:$out_file" - openclaw_offer_transfer_hint "$out_file" + if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then + echo "✅ 記憶全量備份完成 (含多智能體):$out_file"; openclaw_offer_transfer_hint "$out_file" else echo "❌ 記憶全量備份失敗" fi - - rm -rf "$tmp_payload" - break_end - } - - openclaw_read_import_path() { - local prompt_text="$1" - local file_input file_path backup_root - echo "$prompt_text" >&2 - - echo "可先透過 scp/sftp 上傳備份包到伺服器,再輸入路徑。" >&2 - echo "scp 範例: scp /本地/備份包.tar.gz root@你的伺服器:/tmp/" >&2 - echo "提示:輸入檔案名稱時預設在備份目錄中尋找;輸入含 / 的路徑時按完整路徑校驗。" >&2 - read -e -p "請輸入備份檔名或路徑:" file_input - [ -z "$file_input" ] && { echo ""; return 0; } - - backup_root=$(openclaw_backup_root) - mkdir -p "$backup_root" - - if [[ "$file_input" == */* ]]; then - file_path="$file_input" - else - file_path="$backup_root/$file_input" - fi - - if [ ! -f "$file_path" ]; then - echo "❌ 備份檔不存在:$file_path" >&2 - echo "" - return 1 - fi - - echo "$file_path" + rm -rf "$tmp_payload"; break_end } openclaw_memory_backup_import() { send_stats "OpenClaw記憶全量還原" - local workspace_dir="${HOME}/.openclaw/workspace" - mkdir -p "$workspace_dir" - - local archive_path - archive_path=$(openclaw_read_import_path "還原前將執行:類型校驗 + sha256 校驗 + 路徑白名單校驗") - [ -z "$archive_path" ] && { echo "❌ 未輸入備份路徑"; break_end; return 1; } - - local tmp_unpack - tmp_unpack=$(mktemp -d) || return 1 - local pkg_dir - pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } - - local invalid=0 - local valid_list - valid_list=$(mktemp) - while IFS= read -r rel; do - [ -z "$rel" ] && continue - if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed memory "$rel"; then - echo "❌ 偵測到非法或越權路徑:$rel" - invalid=1 - break - fi - echo "$rel" >> "$valid_list" - done < "$pkg_dir/manifest.files" - - if [ "$invalid" -ne 0 ]; then - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "❌ 還原中止:存在不安全路徑" - break_end - return 1 - fi - - - while IFS= read -r rel; do - mkdir -p "$workspace_dir/$(dirname "$rel")" - cp -a "$pkg_dir/payload/$rel" "$workspace_dir/$rel" - done < "$valid_list" - - rm -f "$valid_list" - rm -rf "$tmp_unpack" - echo "✅ 記憶全量還原完成" - break_end + local archive_path=$(openclaw_read_import_path "還原記憶全量 (支援多智能體)") + [ -z "$archive_path" ] && { echo "❌ 未輸入路徑"; break_end; return 1; } + local tmp_unpack=$(mktemp -d) || return 1 + local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } + local workspaces_json=$(openclaw_get_all_agent_workspaces) + python3 -c 'import json, sys, os, shutil; +workspaces = {item["id"]: item["ws"] for item in json.loads(sys.argv[1])}; +payload_dir = sys.argv[2]; agents_root = os.path.join(payload_dir, "agents") +if os.path.isdir(agents_root): + for aid in os.listdir(agents_root): + if aid in workspaces: + src_agent_dir = os.path.join(agents_root, aid); dest_ws = workspaces[aid] + os.makedirs(dest_ws, exist_ok=True) + for f in os.listdir(src_agent_dir): + src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) + if os.path.isfile(src): shutil.copy2(src, dest) + else: shutil.copytree(src, dest, dirs_exist_ok=True) + print(f"✅ 已還原智能體記憶: {aid}")' "$workspaces_json" "$pkg_dir/payload" + rm -rf "$tmp_unpack"; echo "✅ 記憶全量還原完成"; break_end } + openclaw_project_backup_export() { send_stats "OpenClaw專案備份" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then echo "❌ 未找到 OpenClaw 根目錄:$openclaw_root" break_end @@ -12675,7 +12919,10 @@ EOF openclaw_project_backup_import() { send_stats "OpenClaw專案還原" - local openclaw_root="${HOME}/.openclaw" + local config_file + config_file=$(openclaw_get_config_file) + local openclaw_root + openclaw_root=$(dirname "$config_file") mkdir -p "$openclaw_root" echo "⚠️ 高風險操作:專案還原會涵蓋 OpenClaw 設定與工作區內容。" @@ -12913,7 +13160,15 @@ EOF } openclaw_memory_config_file() { - echo "${HOME}/.openclaw/openclaw.json" + local user_config="${HOME}/.openclaw/openclaw.json" + local root_config="/root/.openclaw/openclaw.json" + if [ -f "$user_config" ]; then + echo "$user_config" + elif [ "$HOME" = "/root" ] && [ -f "$root_config" ]; then + echo "$root_config" + else + echo "$user_config" + fi } openclaw_memory_config_get() { @@ -12943,9 +13198,78 @@ EOF openclaw_memory_config_unset "memory.local" } + openclaw_memory_list_agents() { + if command -v openclaw >/dev/null 2>&1; then + local agents_json + agents_json=$(openclaw agents list --json 2>/dev/null || true) + if [ -n "$agents_json" ]; then + python3 - "$agents_json" <<'PY' +import json, os, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + data = None +seen = set() +results = [] +if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + aid = item.get('id') + if not aid or aid in seen: + continue + ws = item.get('workspace') or ("~/.openclaw/workspace" if aid == 'main' else f"~/.openclaw/workspace-{aid}") + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +if results: + for aid, ws in results: + print(f"{aid}\t{ws}") + raise SystemExit(0) +raise SystemExit(1) +PY + [ $? -eq 0 ] && return 0 + fi + fi + local config_path + config_path=$(openclaw_memory_config_file) + python3 - "$config_path" <<'PY' +import json, os, sys +config_path = sys.argv[1] +results = [("main", os.path.expanduser("~/.openclaw/workspace"))] +seen = {"main"} +try: + if os.path.exists(config_path): + with open(config_path, encoding='utf-8') as f: + data = json.load(f) + agents = data.get('agents', {}).get('list', []) + if isinstance(agents, list): + for item in agents: + if not isinstance(item, dict): + continue + aid = item.get('id') + ws = item.get('workspace') + if not aid or aid in seen: + continue + if not ws: + ws = f"~/.openclaw/workspace-{aid}" + results.append((aid, os.path.expanduser(ws))) + seen.add(aid) +except Exception: + pass +for aid, ws in results: + print(f"{aid}\t{ws}") +PY + } + openclaw_memory_status_value() { local key="$1" - openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + local agent_id="${2:-}" + if [ -n "$agent_id" ]; then + openclaw memory status --agent "$agent_id" 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + else + openclaw memory status 2>/dev/null | awk -F': ' -v k="$key" '$1==k {print $2; exit}' + fi } openclaw_memory_expand_path() { @@ -12962,58 +13286,107 @@ EOF fi } - openclaw_memory_rebuild_index_safe() { + openclaw_memory_rebuild_index_single() { + local agent_id="${1:-main}" local store_raw store_file ts backup_file - store_raw=$(openclaw_memory_status_value "Store") + store_raw=$(openclaw_memory_status_value "Store" "$agent_id") store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then - echo "⚠️ 未找到索引庫文件,可能為空或不存在。" + echo "⚠️ [$agent_id] 未找到索引庫文件,可能為空或不存在。" echo "Store 原始值: ${store_raw:-<空>}" echo "仍將執行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ 已備份索引:$backup_file" + echo "✅ [$agent_id] 已備份索引:$backup_file" else - echo "⚠️ 索引備份失敗,繼續重建。" + echo "⚠️ [$agent_id] 索引備份失敗,繼續重建。" fi fi - openclaw memory index --force + openclaw memory index --agent "$agent_id" --force + } + + openclaw_memory_rebuild_index_safe() { + local agent_id="${1:-main}" + openclaw_memory_rebuild_index_single "$agent_id" + openclaw gateway restart + echo "✅ 索引已重建並自動重新啟動網關" + echo "" + openclaw_memory_render_status + } + + openclaw_memory_rebuild_index_all() { + local count=0 + local agent_lines agent_id workspace + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + openclaw_memory_rebuild_index_single "$agent_id" + count=$((count+1)) + done </dev/null) - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "獲取狀態失敗" - else - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed)" | head -n 3 | sed -e 's/^Provider: /底層方案: /' -e 's/^Vector: /向量庫狀態: /' -e 's/^Indexed: /已收錄文件: /') + local agent_lines agent_id workspace status_output status_lines first="true" + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id workspace; do + [ -z "$agent_id" ] && continue + status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) + [ "$first" = "true" ] || echo "" + first="false" + echo "Agent: $agent_id" + if [ $? -ne 0 ] || [ -z "$status_output" ]; then + echo "獲取狀態失敗" + continue + fi + status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底層方案: /' -e 's/^Vector: /向量庫狀態: /' -e 's/^Indexed: /已收錄文件: /' -e 's/^Workspace: /工作區: /' -e 's/^Store: /索引庫: /') if [ -z "$status_lines" ]; then echo "未安裝/未啟動" else echo "$status_lines" fi - fi + done </dev/null || true) if [ -n "$qmd_path" ]; then - echo "✅ qmd 已存在:$qmd_path" - OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - return 0 + if qmd --version >/dev/null 2>&1; then + echo "✅ qmd 已存在且可用:$qmd_path" + OPENCLAW_MEMORY_QMD_PATH="$qmd_path" + return 0 + else + echo "⚠️ qmd 指令存在但模組損壞,重新安裝..." + fi fi - openclaw_memory_ensure_bun || return 1 - local qmd_url="${OPENCLAW_MEMORY_GH_PROXY}github.com/tobi/qmd" - echo "⬇️ 透過 bun 安裝 qmd:$qmd_url" - bun install -g "$qmd_url" + echo "⬇️ 透過 npm 安裝 qmd: @tobilu/qmd" + npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) - if [ -z "$qmd_path" ] && [ -x "$HOME/.bun/bin/qmd" ]; then - qmd_path="$HOME/.bun/bin/qmd" - fi if [ -z "$qmd_path" ]; then echo "❌ qmd 安裝失敗" return 1 fi + if ! qmd --version >/dev/null 2>&1; then + echo "❌ qmd 安裝後仍無法運作" + return 1 + fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" echo "✅ qmd 安裝完成:$qmd_path" return 0 @@ -13360,8 +13736,15 @@ EOF fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" - openclaw_memory_prepare_workspace - openclaw memory index --force + openclaw_memory_prepare_workspace_all + local preh_agent_lines preh_agent_id preh_workspace + preh_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r preh_agent_id preh_workspace; do + [ -z "$preh_agent_id" ] && continue + openclaw memory index --agent "$preh_agent_id" --force + done </dev/null 2>&1; then echo "⚠️ 偵測到目前方案為 QMD,但未安裝 qmd 指令。" echo "可切換 Local,或安裝 bun + qmd 後再試。" fi - echo "適用場景:Indexed 分子 > 分母(重複 collection 導致計數異常)" - read -e -p "確認將 includeDefaultMemory 設為 false? (y/N):" confirm_fix - if [[ ! "$confirm_fix" =~ ^[Yy]$ ]]; then - echo "已取消。" - break_end - return 0 - fi - openclaw_memory_config_set "memory.qmd.includeDefaultMemory" false - if [ $? -ne 0 ]; then - echo "❌ 寫入配置失敗" - break_end - return 1 - fi - echo "✅ 已設定 includeDefaultMemory=false" - echo "推薦執行:清理並重建索引" - read -e -p "是否執行清理並重建索引(建議)? (Y/n):" rebuild_choice - if [[ ! "$rebuild_choice" =~ ^[Nn]$ ]]; then - openclaw_memory_rebuild_index_safe + include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) + echo "=======================================" + echo "索引修復診斷" + echo "=======================================" + echo "目前 includeDefaultMemory: ${include_dm:-未設定}" + echo "" + if [ "$include_dm" = "false" ]; then + echo "⚠️ 偵測到 includeDefaultMemory=false" + echo "這會導致預設記憶檔案(MEMORY.md + memory/*.md)不被索引" + echo "所以 Indexed 會一直顯示 0/N" + echo "" + read -e -p "是否恢復為 true 並重建索引? (Y/n):" fix_choice + if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then + openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true + if [ $? -ne 0 ]; then + echo "❌ 寫入配置失敗" + break_end + return 1 + fi + echo "✅ 已恢復 includeDefaultMemory=true" + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi else - echo "可稍後在記憶管理中查看狀態。" + echo "includeDefaultMemory 配置正常。" + echo "將執行:清理舊索引 → 全量重建所有智能體索引" + echo "" + read -e -p "確認執行? (Y/n):" confirm_fix + if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then + openclaw_memory_rebuild_index_all + else + echo "已取消。" + fi fi break_end } @@ -13637,30 +14041,42 @@ EOF openclaw_memory_file_collect() { OPENCLAW_MEMORY_FILES=() - local base_dir="${HOME}/.openclaw/workspace" - local memory_dir="$base_dir/memory" - local memory_file="$base_dir/MEMORY.md" - [ -f "$memory_file" ] && OPENCLAW_MEMORY_FILES+=("$memory_file") - if [ -d "$memory_dir" ]; then - while IFS= read -r file; do - [ -f "$file" ] && OPENCLAW_MEMORY_FILES+=("$file") - done < <(find "$memory_dir" -type f -name '*.md' | sort) - fi + OPENCLAW_MEMORY_FILE_LABELS=() + local agent_lines agent_id base_dir memory_dir memory_file rel + agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r agent_id base_dir; do + [ -z "$agent_id" ] && continue + memory_dir="$base_dir/memory" + memory_file="$base_dir/MEMORY.md" + if [ -f "$memory_file" ]; then + OPENCLAW_MEMORY_FILES+=("$memory_file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/MEMORY.md") + fi + if [ -d "$memory_dir" ]; then + while IFS= read -r file; do + [ -f "$file" ] || continue + rel="${file#$base_dir/}" + OPENCLAW_MEMORY_FILES+=("$file") + OPENCLAW_MEMORY_FILE_LABELS+=("$agent_id/$rel") + done < <(find "$memory_dir" -type f -name '*.md' | sort) + fi + done </dev/null || stat -c %y "$file" | awk '{print $1" "$2}') printf "%s | %s | %s | %s\\n" "$((i+1))" "$rel" "$size" "$mtime" @@ -13770,18 +14186,25 @@ EOF break_end continue fi - openclaw_memory_prepare_workspace + openclaw_memory_prepare_workspace_all read -e -p "二次確認:輸入 force 使用全量(留空為增量):" confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 全量重建更徹底,但耗時更長。" echo "建議:輸入 rebuild 進行安全重建(先備份索引庫)。" read -e -p "第三次確認:輸入 rebuild 執行安全重建;直接回車繼續普通 force:" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then - openclaw_memory_rebuild_index_safe + openclaw_memory_rebuild_index_all else - openclaw memory index --force + local fl_agent_lines fl_agent_id fl_workspace + fl_agent_lines=$(openclaw_memory_list_agents) + while IFS=$'\t' read -r fl_agent_id fl_workspace; do + [ -z "$fl_agent_id" ] && continue + openclaw memory index --agent "$fl_agent_id" --force + done </dev/null 2>&1 || { + echo "⚠️ 權限備份失敗:$backup_file" + return 1 + } + echo "✅ 已備份目前權限配置:$backup_file" + return 0 + } + + openclaw_permission_restore_backup() { + local config_file backup_file + config_file=$(openclaw_permission_config_file) + backup_file=$(openclaw_permission_backup_file) + if [ ! -s "$backup_file" ]; then + echo "❌ 未找到可還原的權限備份檔。" + return 1 + fi + cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { + echo "❌ 權限恢復失敗:$backup_file" + return 1 + } + echo "✅ 已恢復切換前權限配置" + openclaw_permission_restart_gateway || true + return 0 + } + + openclaw_permission_restart_gateway() { + if ! openclaw_has_command openclaw; then + echo "❌ 未偵測到 openclaw,無法重新啟動 OpenClaw Gateway。" + return 1 + fi + echo "正在重啟 OpenClaw Gateway..." + openclaw gateway restart >/dev/null 2>&1 || { + openclaw gateway stop >/dev/null 2>&1 + openclaw gateway start >/dev/null 2>&1 + } + } + + openclaw_permission_get_value() { + local path="$1" + local config_file + config_file=$(openclaw_permission_config_file) + + if openclaw_has_command openclaw; then + local value + value=$(openclaw config get "$path" 2>&1 | head -n 1) + if [ -n "$value" ]; then + if echo "$value" | grep -qi "config path not found"; then + echo "(unset)" + return 0 + fi + if [ "$value" = "null" ]; then + echo "(unset)" + else + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + fi + return 0 + fi + fi + + [ -f "$config_file" ] || { echo "(unset)"; return 0; } + + if openclaw_has_command jq; then + local jq_value + jq_value=$(jq -r --arg p "$path" 'getpath($p|split(".")) // "(unset)"' "$config_file" 2>/dev/null) || jq_value="(unset)" + [ "$jq_value" = "null" ] && jq_value="(unset)" + echo "$jq_value" + return 0 + fi + + if openclaw_has_command python3; then + python3 - "$config_file" "$path" <<'PY' +import json, sys +path = sys.argv[2] +with open(sys.argv[1], 'r', encoding='utf-8') as f: + obj = json.load(f) +cur = obj +for part in path.split('.'): + if isinstance(cur, dict) and part in cur: + cur = cur[part] + else: + print('(unset)') + raise SystemExit(0) +if isinstance(cur, bool): + print('true' if cur else 'false') +elif cur is None: + print('(unset)') +else: + print(json.dumps(cur, ensure_ascii=False) if isinstance(cur, (dict, list)) else str(cur)) +PY + return 0 + fi + + echo "(unset)" + return 0 + } + + openclaw_permission_unset_optional() { + local key="$1" + local probe + if ! openclaw_has_command openclaw; then + return 1 + fi + if openclaw config unset "$key" >/dev/null 2>&1; then + return 0 + fi + probe=$(openclaw config get "$key" 2>&1 | head -n 1) + if [ -z "$probe" ] || [ "$probe" = "null" ] || [ "$probe" = "(unset)" ] || echo "$probe" | grep -qi "config path not found"; then + return 0 + fi + return 1 + } + + openclaw_permission_detect_mode() { + local config_file + config_file=$(openclaw_permission_config_file) + [ ! -f "$config_file" ] && { echo "未知模式"; return; } + + python3 - "$config_file" <<'PY' +import json, sys + +def get_v(o, p): + for k in p.split('.'): + if isinstance(o, dict) and k in o: + o = o[k] + else: + return "(unset)" + return str(o).lower() + +try: + with open(sys.argv[1], 'r', encoding='utf-8') as f: + d = json.load(f) + p = get_v(d, "tools.profile") + s = get_v(d, "tools.exec.security") + a = get_v(d, "tools.exec.ask") + e = get_v(d, "tools.elevated.enabled") + b = get_v(d, "commands.bash") + ap = get_v(d, "tools.exec.applyPatch.enabled") + w = get_v(d, "tools.exec.applyPatch.workspaceOnly") + + if p == "coding" and s == "allowlist" and a == "on-miss" and e == "false" and b == "false" and ap == "false": + print("標準安全模式") + elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": + print("開發增強模式") + elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": + print("完全開放模式") + else: + print("自訂模式") +except Exception: + print("自訂模式") +PY + } + + openclaw_permission_render_status() { + local config_file mode + config_file=$(openclaw_permission_config_file) + mode=$(openclaw_permission_detect_mode) + echo "設定檔:$config_file" + [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 設定檔(可能尚未初始化)。" + echo "當前模式:$mode" + echo "---------------------------------------" + + # 使用 Python 一次高效能解析所有權限字段 + python3 - "$config_file" <<'PY' +import json, sys +def get_val(obj, path, default="(unset)"): + parts = path.split('.') + for p in parts: + if isinstance(obj, dict) and p in obj: obj = obj[p] + else: return default + if isinstance(obj, (list, dict)): return json.dumps(obj) + return str(obj) + +try: + with open(sys.argv[1], 'r') as f: data = json.load(f) + fields = [ + ("tools.profile", "tools.profile"), + ("tools.allow", "tools.allow"), + ("tools.deny", "tools.deny"), + ("tools.byProvider", "tools.byProvider"), + ("tools.exec.security", "tools.exec.security"), + ("tools.exec.ask", "tools.exec.ask"), + ("tools.elevated.enabled", "tools.elevated.enabled"), + ("commands.bash", "commands.bash"), + ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), + ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") + ] + for label, path in fields: + val = get_val(data, path) + print("%-28s %s" % (label, val)) +except Exception as e: + print("❌ 設定檔解析失敗: %s" % e) +PY + } + + openclaw_permission_apply_standard() { + send_stats "OpenClaw權限-標準安全模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled false || failed=1 + openclaw config set commands.bash false || failed=1 + openclaw config set tools.exec.applyPatch.enabled false || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切換為標準安全模式" + } + + openclaw_permission_apply_developer() { + send_stats "OpenClaw權限-開發增強模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile coding || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security allowlist || failed=1 + openclaw config set tools.exec.ask on-miss || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切換為開發增強模式" + } + + openclaw_permission_apply_full() { + send_stats "OpenClaw權限-完全開放模式" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw config set tools.profile full || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw config set tools.deny '[]' --json || failed=1 + openclaw config set tools.exec.security full || failed=1 + openclaw config set tools.exec.ask off || failed=1 + openclaw config set tools.elevated.enabled true || failed=1 + openclaw config set commands.bash true || failed=1 + openclaw config set tools.exec.applyPatch.enabled true || failed=1 + openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" + return 1 + fi + echo "✅ 已切換為完全開放模式" + } + + openclaw_permission_restore_official_defaults() { + send_stats "OpenClaw權限-恢復官方默認" + openclaw_permission_require_openclaw || return 1 + openclaw_permission_backup_current || true + local failed=0 + openclaw_permission_unset_optional tools.profile || failed=1 + openclaw_permission_unset_optional tools.byProvider || failed=1 + openclaw_permission_unset_optional tools.allow || failed=1 + openclaw_permission_unset_optional tools.deny || failed=1 + openclaw_permission_unset_optional tools.exec.security || failed=1 + openclaw_permission_unset_optional tools.exec.ask || failed=1 + openclaw_permission_unset_optional tools.elevated.enabled || failed=1 + openclaw_permission_unset_optional commands.bash || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 + openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 + if [ "$failed" -ne 0 ]; then + echo "❌ 恢復失敗:清理明確權限覆蓋時發生錯誤。" + openclaw_permission_restore_backup || true + return 1 + fi + if ! openclaw_permission_restart_gateway; then + echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" + return 1 + fi + echo "✅ 已恢復為 OpenClaw 官方預設策略(清除明確覆蓋)" + } + + openclaw_permission_run_audit() { + send_stats "OpenClaw權限-安全性審計" + openclaw_permission_require_openclaw || return 1 + openclaw security audit + } + + openclaw_permission_menu() { + send_stats "OpenClaw權限管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 權限管理" + echo "=======================================" + openclaw_permission_render_status + echo "---------------------------------------" + echo "1. 切換為標準安全模式(建議)" + echo "2. 切換為開發增強模式" + echo "3. 切換為完全開放模式(高風險)" + echo "4. 恢復官方預設策略" + echo "5. 運行安全審計" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" perm_choice + case "$perm_choice" in + 1) + echo "將應用:標準安全模式" + read -e -p "輸入 yes 確認:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + break_end + ;; + 2) + echo "將應用:開發增強模式" + read -e -p "輸入 yes 確認:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + break_end + ;; + 3) + echo "⚠️ 完全開放模式會關閉 exec 審核、啟用提權與 bash,僅建議可信任單一使用者環境使用。" + read -e -p "輸入 FULL 確認繼續:" confirm + [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + break_end + ;; + 4) + echo "將清除腳本寫入的明確權限覆寫,恢復到 OpenClaw 官方預設策略。" + read -e -p "輸入 yes 確認:" confirm + [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + break_end + ;; + 5) + openclaw_permission_run_audit + break_end + ;; + 0) + return 0 + ;; + *) + echo "無效的選擇,請重試。" + sleep 1 + ;; + esac + done + } + + openclaw_multiagent_config_file() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + echo "$config_file" + return 0 + fi + openclaw config file 2>/dev/null | tail -n 1 + } + + openclaw_multiagent_default_agent() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +value="(unset)" +try: + with open(path) as f: + data=json.load(f) + defaults=data.get("agents",{}).get("defaults",{}) if isinstance(data,dict) else {} + value=defaults.get("agent") or None + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and (item.get("isDefault") or item.get("default")): + value=item.get("id") + break + if not value: + for item in data.get("agents",{}).get("list",[]) or []: + if isinstance(item,dict) and item.get("id"): + value=item.get("id") + break +except Exception: + value="(unset)" +print(value or "(unset)") +PY + return 0 + fi + local value + value=$(openclaw config get agents.defaults.agent 2>&1 | head -n 1) + if [ -z "$value" ] || echo "$value" | grep -qi "config path not found"; then + value=$(openclaw agents list --json 2>/dev/null | python3 -c 'import json,sys +try: + data=json.load(sys.stdin) + print(next((x.get("id","(unset)") for x in data if x.get("isDefault")), "(unset)")) +except Exception: + print("(unset)")' 2>/dev/null) + fi + [ -z "$value" ] && value="(unset)" + if echo "$value" | grep -q '^".*"$'; then + value=$(echo "$value" | sed -e 's/^"//' -e 's/"$//') + fi + echo "$value" + } + + openclaw_multiagent_require_openclaw() { + if ! openclaw_has_command openclaw; then + echo "❌ 未偵測到 openclaw 指令,請先安裝或初始化 OpenClaw。" + return 1 + fi + return 0 + } + + openclaw_multiagent_agents_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if not isinstance(agents,list): + agents=[] + print(json.dumps(agents, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents list --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_bindings_json() { + local config_file + config_file=$(openclaw_permission_config_file) + if [ -s "$config_file" ]; then + python3 - "$config_file" <<'PY' +import json,sys,os +path=sys.argv[1] +results=[] + +def add_item(item): + if not isinstance(item,dict): + return + bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") + agent=item.get("agentId") or item.get("agent") + if agent or bind: + results.append({"agentId": agent or "?", "bind": bind or "-"}) + +def walk(obj): + if isinstance(obj,dict): + if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): + add_item(obj) + for v in obj.values(): + walk(v) + elif isinstance(obj,list): + for v in obj: + walk(v) + +try: + with open(path) as f: + data=json.load(f) + bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None + if isinstance(bindings,list): + for item in bindings: + add_item(item) + walk(data) + print(json.dumps(results, ensure_ascii=False)) +except Exception: + print("[]") +PY + return 0 + fi + openclaw agents bindings --json 2>/dev/null || echo '[]' + } + + openclaw_multiagent_sessions_json() { + local config_file + config_file=$(openclaw_permission_config_file) + python3 - "$config_file" <<'PY' +import json,sys,os +config_path=sys.argv[1] if len(sys.argv)>1 else "" + +def load_agents(path): + if path and os.path.exists(path): + try: + with open(path) as f: + data=json.load(f) + agents=data.get("agents",{}).get("list",[]) + if isinstance(agents,list) and agents: + ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] + if ids: + return ids + except Exception: + pass + base=os.path.expanduser("~/.openclaw/agents") + try: + return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] + except Exception: + return [] + +agent_ids=load_agents(config_path) +sessions=[] +for agent_id in agent_ids: + path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") + if not os.path.exists(path): + continue + try: + with open(path) as f: + data=json.load(f) + except Exception: + continue + if isinstance(data,dict): + items=data.items() + elif isinstance(data,list): + items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + else: + continue + for key,item in items: + if not isinstance(item,dict): + continue + model=item.get("model") + if not model: + report=item.get("systemPromptReport") or {} + if isinstance(report,dict): + model=report.get("model") or report.get("modelProvider") or report.get("provider") + sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) +print(json.dumps({"sessions": sessions}, ensure_ascii=False)) +PY + } + + openclaw_multiagent_render_status() { + local config_file default_agent + config_file=$(openclaw_multiagent_config_file) + default_agent=$(openclaw_multiagent_default_agent) + echo "設定檔: ${config_file:-$(openclaw_permission_config_file)}" + echo "預設智能體:$default_agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能體數: %s" % len(agents)); print("路由綁定數: %s" % len(bindings)); print("會話總數: %s" % len(sessions)); print("---------------------------------------"); +if not agents: print("目前未配置任何多智能體。") +else: + import itertools + for item in itertools.islice(agents, 8): + ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能體ID: [1;36m%s [0m" % item.get("id","?")); print("身份名稱: %s %s" % (identity, emoji)); print("工作目錄: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_list_agents() { + send_stats "OpenClaw多智能體-列出Agent" + python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); +if not agents: print("暫無已配置 Agent。"); raise SystemExit(0) +for idx,item in enumerate(agents,1): + print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" + } + + openclaw_multiagent_add_agent() { + send_stats "OpenClaw多智能體-新增Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id workspace confirm + read -e -p "請輸入新的 Agent ID:" agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 + read -e -p "請輸入 workspace 路徑(預設為 ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" + echo "將創建智能體:$agent_id" + echo "工作目錄:$workspace" + read -e -p "輸入 yes 確認繼續:" confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents add "$agent_id" --workspace "$workspace"; then + echo "✅ 智能體創建成功:$agent_id" + local name theme + read -e -p "請輸入智能體身分名稱 (如: 代碼專家):" name + [ -z "$name" ] && name="$agent_id" + read -e -p "請輸入智能體性格主題 (如: 嚴謹、有效率):" theme + [ -z "$theme" ] && theme="助理" + echo "正在配置智能體身份..." + openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" + else + echo "❌ 智能體建立失敗" + return 1 + fi + } + + openclaw_multiagent_delete_agent() { + send_stats "OpenClaw多智能體-刪除Agent" + openclaw_multiagent_require_openclaw || return 1 + local agent_id confirm + read -e -p "請輸入要刪除的 Agent ID:" agent_id + [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 + echo "⚠️ 刪除智能體可能會影響其工作目錄、路由綁定與會話路由。" + read -e -p "輸入 DELETE 確認刪除${agent_id}: " confirm + [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } + if openclaw agents delete "$agent_id"; then + echo "✅ 智能體刪除成功:$agent_id" + else + echo "❌ 智能體刪除失敗" + return 1 + fi + } + + openclaw_multiagent_list_bindings() { + send_stats "OpenClaw多智能體-檢視路由綁定" + python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); +if not bindings: print("暫無路由綁定。"); raise SystemExit(0) +for idx,item in enumerate(bindings,1): + bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_add_binding() { + send_stats "OpenClaw多智能體-新增路由綁定" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "請輸入智能體 ID:" agent_id + read -e -p "請輸入路由綁定值(如 telegram:ops / discord:guild-a):" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 + echo "將綁定智能體 [$agent_id] -> [$bind_value]" + read -e -p "輸入 yes 確認繼續:" confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ 路由綁定新增成功" + else + echo "❌ 路由綁定新增失敗" + return 1 + fi + } + + openclaw_multiagent_remove_binding() { + send_stats "OpenClaw多智能體-移除路由綁定" + openclaw_multiagent_require_openclaw || return 1 + local agent_id bind_value confirm + read -e -p "請輸入智能體 ID:" agent_id + read -e -p "請輸入要移除的路由綁定值:" bind_value + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 + echo "將移除智能體 [$agent_id] 的路由綁定 [$bind_value]" + read -e -p "輸入 yes 確認繼續:" confirm + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } + if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then + echo "✅ 路由綁定移除成功" + else + echo "❌ 路由綁定移除失敗" + return 1 + fi + } + + + openclaw_multiagent_show_sessions() { + send_stats "OpenClaw多智能體-會話概況" + python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; +if not sessions: print("暫無 session 資料。"); raise SystemExit(0) +by_agent={} +for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +print("會話匯總:") +for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +print("---------------------------------------") +for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" + } + + openclaw_multiagent_health_check() { + send_stats "OpenClaw多智能體-健康檢查" + openclaw_multiagent_require_openclaw || return 1 + local config_file + config_file=$(openclaw_multiagent_config_file) + echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" + openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" + python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); +if not agents: print("⚠️ 未發現配置智能體。"); +else: + for item in agents: + ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) +print("路由綁定數=%s" % len(bindings)); print("✅ 多智能體健康檢查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + } + + openclaw_multiagent_menu() { + send_stats "OpenClaw多智能體管理" + while true; do + clear + echo "=======================================" + echo "OpenClaw 多智能體管理" + echo "=======================================" + openclaw_multiagent_render_status + echo "---------------------------------------" + echo "1. 新增智能體" + echo "2. 刪除智能體" + echo "3. 查看路由綁定" + echo "4. 新增路由綁定" + echo "5. 移除路由綁定" + echo "6. 查看會話概況" + echo "7. 執行多智能體健康檢查" + echo "0. 返回上一級" + echo "---------------------------------------" + read -e -p "請輸入你的選擇:" multi_choice + case "$multi_choice" in + 1) openclaw_multiagent_add_agent; break_end ;; + 2) openclaw_multiagent_delete_agent; break_end ;; + 3) openclaw_multiagent_list_bindings; break_end ;; + 4) openclaw_multiagent_add_binding; break_end ;; + 5) openclaw_multiagent_remove_binding; break_end ;; + 6) openclaw_multiagent_show_sessions; break_end ;; + 7) openclaw_multiagent_health_check; break_end ;; + 0) return 0 ;; + *) echo "無效的選擇,請重試。"; sleep 1 ;; + esac + done + } + + +openclaw_backup_restore_menu() { send_stats "OpenClaw備份與還原" while true; do @@ -13847,8 +15022,8 @@ EOF echo "更新 OpenClaw..." send_stats "更新 OpenClaw..." install_node_and_tools - git config --global url."${gh_https_url}github.com/".insteadOf ssh://git@github.com/ - git config --global url."${gh_https_url}github.com/".insteadOf git@github.com: + git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ + git config --global url."${gh_proxy}github.com/".insteadOf git@github.com: npm install -g openclaw@latest crontab -l 2>/dev/null | grep -v "s gateway" | crontab - start_gateway @@ -13865,7 +15040,8 @@ EOF openclaw uninstall npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - - rm -rf /root/.openclaw + rm -rf "$HOME/.openclaw" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -13875,7 +15051,7 @@ EOF nano_openclaw_json() { send_stats "編輯 OpenClaw 設定檔" install nano - nano ~/.openclaw/openclaw.json + nano "$(openclaw_get_config_file)" start_gateway } @@ -13950,7 +15126,7 @@ EOF read echo -e "${gl_kjlan}正在載入設備列表…${gl_bai}" # 自動新增網域到 allowedOrigins - config_file="$HOME/.openclaw/openclaw.json" + config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" # 使用 jq 安全性修改 JSON,確保結構存在且不重複新增域名 @@ -14053,9 +15229,11 @@ EOF break_end ;; 15) openclaw_memory_menu ;; - 16) openclaw_backup_restore_menu ;; - 17) update_moltbot ;; - 18) uninstall_moltbot ;; + 16) openclaw_permission_menu ;; + 17) openclaw_multiagent_menu ;; + 18) openclaw_backup_restore_menu ;; + 19) update_moltbot ;; + 20) uninstall_moltbot ;; *) break ;; esac done @@ -14159,9 +15337,9 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" - echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix开源白板工具" + echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" @@ -15595,7 +16773,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼均為: admin" + echo "初始使用者名稱密碼皆為: admin" } docker_app_update() { @@ -17424,7 +18602,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -18384,7 +19562,7 @@ log_menu() { if [ "$t" = "1" ]; then journalctl -f elif [ "$t" = "2" ]; then - read -erp "输入服务名: " svc + read -erp "輸入服務名稱:" svc journalctl -u "$svc" -f else echo "無效選擇" @@ -18424,7 +19602,7 @@ env_menu() { show_env_vars() { clear - send_stats "当前已生效环境变量" + send_stats "目前已生效環境變數" echo "========== 目前已生效環境變數(節選) ==========" printf "%-20s %s\n" "變數名" "值" echo "-----------------------------------------------" @@ -19430,7 +20608,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -19781,7 +20959,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" + echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -20655,6 +21833,9 @@ else linux_panel "$@" ;; + claw|oc|OpenClaw) + moltbot_menu + ;; info) linux_info From fe0f37f96dbd4b3c9513ac2fd26f1100a565ab21 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 28 Mar 2026 13:50:26 +0800 Subject: [PATCH 1130/1285] =?UTF-8?q?refactor:=20=E5=85=A8=E9=9D=A2?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20OpenClaw=20=E5=AE=89=E5=85=A8=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=AE=A1=E7=90=86=EF=BC=8C=E9=80=82=E9=85=8D=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E5=8F=8C=E5=B1=82=E6=8B=A6=E6=88=AA=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 272 ++++++++++++++++++++++++------------------------- kejilion.sh | 272 ++++++++++++++++++++++++------------------------- 2 files changed, 266 insertions(+), 278 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 692d3846a..d419e0e11 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14413,160 +14413,155 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "配置文件: $config_file" - [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" - echo "当前模式: $mode" - echo "---------------------------------------" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # 使用 Python 安全更新或创建 exec-approvals.json + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} - # 使用 Python 一次性高效解析所有权限字段 - python3 - "$config_file" <<'PY' -import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + openclaw_permission_render_status() { + echo "应用层配置: ~/.openclaw/openclaw.json" + echo "宿主机审批: ~/.openclaw/exec-approvals.json" + echo "---------------------------------------" + echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 审批提示: /' || echo " 审批提示: (unset)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提权开关: /' || echo " 提权开关: (unset)" + + echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " +import json, sys try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ 配置文件解析失败: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print(' 拦截策略 (Security): ' + str(d.get('security', '(unset)'))) + print(' 提示策略 (Ask): ' + str(d.get('ask', '(unset)'))) + print(' 无UI兜底 (AskFallback): ' + str(d.get('askFallback', '(unset)'))) +except Exception: + print(' (配置文件解析失败)') +" + else: + echo " (未配置,强制使用系统内置安全兜底策略)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw权限-标准安全模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为标准安全模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "正在配置宿主机审批拦截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw权限-开发增强模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为开发增强模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在配置宿主机审批拦截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw权限-完全开放模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为完全开放模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在瓦解宿主机拦截防御..." + # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw权限-恢复官方默认" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + + echo "清理应用层强制覆盖..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "清理宿主机拦截配置..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw权限-安全审计" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "运行 OpenClaw 官方安全审计与体检..." + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "是否尝试自动修复发现的安全隐患?(y/n): " fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ 自动修复完成。${gl_bai}" + fi + echo "按任意键返回..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14569,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw 权限管理" + echo " OpenClaw 权限管理 (双层架构深度适配)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 切换为标准安全模式(推荐)" - echo "2. 切换为开发增强模式" - echo "3. 切换为完全开放模式(高风险)" - echo "4. 恢复官方默认策略" - echo "5. 运行安全审计" - echo "0. 返回上一级" + echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" + echo -e "${gl_kjlan}2.${gl_bai} 切换为开发增强模式(允许智能体申请提权)" + echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高风险!彻底解除所有宿主机拦截${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai} 恢复官方默认沙盒防御策略" + echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" + echo -e "${gl_kjlan}0.${gl_bai} 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice case "$perm_choice" in 1) - echo "将应用:标准安全模式" + echo "准备应用:标准安全模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" break_end ;; 2) - echo "将应用:开发增强模式" + echo "准备应用:开发增强模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" break_end ;; 3) - echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" + echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" read -e -p "输入 FULL 确认继续: " confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" break_end ;; 4) - echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" + echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 diff --git a/kejilion.sh b/kejilion.sh index 8f5b040a6..2b3a14b9a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14413,160 +14413,155 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "配置文件: $config_file" - [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 配置文件(可能尚未初始化)。" - echo "当前模式: $mode" - echo "---------------------------------------" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # 使用 Python 安全更新或创建 exec-approvals.json + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} - # 使用 Python 一次性高效解析所有权限字段 - python3 - "$config_file" <<'PY' -import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + openclaw_permission_render_status() { + echo "应用层配置: ~/.openclaw/openclaw.json" + echo "宿主机审批: ~/.openclaw/exec-approvals.json" + echo "---------------------------------------" + echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 审批提示: /' || echo " 审批提示: (unset)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提权开关: /' || echo " 提权开关: (unset)" + + echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " +import json, sys try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ 配置文件解析失败: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print(' 拦截策略 (Security): ' + str(d.get('security', '(unset)'))) + print(' 提示策略 (Ask): ' + str(d.get('ask', '(unset)'))) + print(' 无UI兜底 (AskFallback): ' + str(d.get('askFallback', '(unset)'))) +except Exception: + print(' (配置文件解析失败)') +" + else: + echo " (未配置,强制使用系统内置安全兜底策略)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw权限-标准安全模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为标准安全模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "正在配置宿主机审批拦截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw权限-开发增强模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为开发增强模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在配置宿主机审批拦截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw权限-完全开放模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切换失败:写入权限配置过程中出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切换为完全开放模式" + + echo "正在配置应用层策略..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在瓦解宿主机拦截防御..." + # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw权限-恢复官方默认" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 恢复失败:清理显式权限覆盖时出现错误。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已写入配置,但重启失败,请手动执行: openclaw gateway restart" - return 1 - fi - echo "✅ 已恢复为 OpenClaw 官方默认策略(清除显式覆盖)" + + echo "清理应用层强制覆盖..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "清理宿主机拦截配置..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw权限-安全审计" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "运行 OpenClaw 官方安全审计与体检..." + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "是否尝试自动修复发现的安全隐患?(y/n): " fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ 自动修复完成。${gl_bai}" + fi + echo "按任意键返回..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14569,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw 权限管理" + echo " OpenClaw 权限管理 (双层架构深度适配)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 切换为标准安全模式(推荐)" - echo "2. 切换为开发增强模式" - echo "3. 切换为完全开放模式(高风险)" - echo "4. 恢复官方默认策略" - echo "5. 运行安全审计" - echo "0. 返回上一级" + echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" + echo -e "${gl_kjlan}2.${gl_bai} 切换为开发增强模式(允许智能体申请提权)" + echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高风险!彻底解除所有宿主机拦截${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai} 恢复官方默认沙盒防御策略" + echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" + echo -e "${gl_kjlan}0.${gl_bai} 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice case "$perm_choice" in 1) - echo "将应用:标准安全模式" + echo "准备应用:标准安全模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" break_end ;; 2) - echo "将应用:开发增强模式" + echo "准备应用:开发增强模式" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" break_end ;; 3) - echo "⚠️ 完全开放模式会关闭 exec 审批、启用提权与 bash,仅建议可信单用户环境使用。" + echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" read -e -p "输入 FULL 确认继续: " confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" break_end ;; 4) - echo "将清除脚本写入的显式权限覆盖,恢复到 OpenClaw 官方默认策略。" + echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "输入 yes 确认: " confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 From ada260873b7146ea183a77f699e60f02f4b159ea Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 28 Mar 2026 14:27:32 +0800 Subject: [PATCH 1131/1285] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20bash=20?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E8=AF=AD=E5=8F=A5=E4=B8=AD=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=20else:=20=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d419e0e11..12e3003d7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14470,7 +14470,7 @@ try: except Exception: print(' (配置文件解析失败)') " - else: + else echo " (未配置,强制使用系统内置安全兜底策略)" fi } diff --git a/kejilion.sh b/kejilion.sh index 2b3a14b9a..73d36025a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14470,7 +14470,7 @@ try: except Exception: print(' (配置文件解析失败)') " - else: + else echo " (未配置,强制使用系统内置安全兜底策略)" fi } From 5d7f330ff0dda5e6ff5c03574daf77eec845d8c5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 28 Mar 2026 14:39:42 +0800 Subject: [PATCH 1132/1285] =?UTF-8?q?feat:=20=E5=9C=A8=20OpenClaw=20?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E8=8F=9C=E5=8D=95=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E3=80=8E=E5=BD=93=E5=89=8D=E7=BB=BC=E5=90=88=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E7=AD=89=E7=BA=A7=E3=80=8F=E7=9A=84=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E9=A2=84=E5=88=A4=E5=8F=8A=E9=AB=98=E4=BA=AE=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 20 ++++++++++++++++++++ kejilion.sh | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 12e3003d7..efa0efcf3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14451,6 +14451,26 @@ with open(path, 'w') as f: echo "应用层配置: ~/.openclaw/openclaw.json" echo "宿主机审批: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi + + local current_mode="未知 / 自定义" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32m标准安全模式\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31m完全开放模式\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33m开发增强模式\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36m官方沙盒兜底\033[0m" + fi + echo -e " 当前综合安全等级: ${current_mode}" + echo "---------------------------------------" echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" diff --git a/kejilion.sh b/kejilion.sh index 73d36025a..c74d93387 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14451,6 +14451,26 @@ with open(path, 'w') as f: echo "应用层配置: ~/.openclaw/openclaw.json" echo "宿主机审批: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi + + local current_mode="未知 / 自定义" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32m标准安全模式\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31m完全开放模式\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33m开发增强模式\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36m官方沙盒兜底\033[0m" + fi + echo -e " 当前综合安全等级: ${current_mode}" + echo "---------------------------------------" echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" From 8c504e99a37f223d156da0c74dbea85c7d9a8c1b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 29 Mar 2026 05:29:41 +0000 Subject: [PATCH 1133/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-03-29=2005:29:41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 374 +++++++++++++++++++++-------------------- jp/kejilion.sh | 440 +++++++++++++++++++++++++------------------------ kr/kejilion.sh | 386 ++++++++++++++++++++++--------------------- tw/kejilion.sh | 408 +++++++++++++++++++++++---------------------- 4 files changed, 832 insertions(+), 776 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index c3dce90aa..b30e11883 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -2318,7 +2318,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2936,7 +2936,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3215,7 +3215,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3596,7 +3596,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4386,7 +4386,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4483,7 +4483,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -5088,7 +5088,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -7091,7 +7091,7 @@ mount_partition() { return 1 fi - echo "Partition successfully mounted to$MOUNT_POINT" + echo "The partition was successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8238,7 +8238,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -10339,7 +10339,7 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ Skip {name}: None baseUrl/apiKey/models') + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: @@ -12149,7 +12149,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12277,7 +12277,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -14113,7 +14113,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ Number of rows must be greater than 0." + echo "❌ The number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14413,160 +14413,175 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "Configuration file:$config_file" - [ ! -s "$config_file" ] && echo "⚠️ OpenClaw configuration file not found (may not have been initialized yet)." - echo "Current mode:$mode" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # Use Python security updates or create exec-approvals.json + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} + +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + + openclaw_permission_render_status() { + echo "Application layer configuration: ~/.openclaw/openclaw.json" + echo "Host approval: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi - # Use Python to efficiently parse all permission fields at once - python3 - "$config_file" <<'PY' + local current_mode="Unknown / Custom" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32mStandard safe mode\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31mFull open mode\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33mDevelop enhanced mode\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36mThe official sandbox tells the truth\033[0m" + fi + echo -e "Current comprehensive security level:${current_mode}" + echo "---------------------------------------" + echo -e "${gl_huang}[Application Layer Tool Policy Status]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (default): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec limit: /' || echo "Exec limit: (unset)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ Approval prompt: /' || echo "Approval prompt: (unset)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ Privilege escalation switch: /' || echo "Privilege escalation switch: (unset)" + + echo -e "\n${gl_huang}[Underlying Exec Approvals status]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) - try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ Configuration file parsing failed: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print('Interception strategy (Security):' + str(d.get('security', '(unset)'))) + print('Prompt strategy (Ask):' + str(d.get('ask', '(unset)'))) + print('No UI cover (AskFallback):' + str(d.get('askFallback', '(unset)'))) +except Exception: + print('(Configuration file parsing failed)') +" + else + echo "(Not configured, forced to use the system's built-in security policy)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw Permissions - Standard Security Mode" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ Switching failed: An error occurred during write permission configuration." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" - return 1 - fi - echo "✅ Switched to standard safety mode" + + echo "Configuring application layer policy..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "Configuring host approval interception..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ Switched to standard safety mode (all dangerous commands will ask for your approval through UI/TG)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw Permissions - Development Enhanced Mode" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ Switching failed: An error occurred during write permission configuration." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" - return 1 - fi - echo "✅ Switched to development enhancement mode" + + echo "Configuring application layer policy..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "Configuring host approval interception..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ Switched to development enhancement mode (privilege escalation is allowed, but common dangerous commands still require approval)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw Permissions - Fully Open Mode" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ Switching failed: An error occurred during write permission configuration." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" - return 1 - fi - echo "✅ Switched to fully open mode" + + echo "Configuring application layer policy..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "Disintegrating host interception defense..." + # The full and off here will completely bypass the exec approval system of the underlying host. + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ Has been switched to fully open mode (Warning: All host command interceptions have expired, and the agent has the highest permissions)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw permissions-restore official default" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ Recovery failed: An error occurred while cleaning explicit permission overrides." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ The configuration has been written, but the restart failed, please execute it manually: openclaw gateway restart" - return 1 - fi - echo "✅ Reverted to OpenClaw official default strategy (cleared explicit overrides)" + + echo "Clean application layer force coverage..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "Clean host interception configuration..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ Reverted to OpenClaw official security sandbox defense mechanism${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw Permissions-Security Audit" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "Run the official OpenClaw security audit and physical..." + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "Attempt to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ Automatic repair completed.${gl_bai}" + fi + echo "Press any key to return..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14589,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw permission management" + echo "OpenClaw permission management (dual-layer architecture deep adaptation)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. Switch to standard safe mode (recommended)" - echo "2. Switch to development enhancement mode" - echo "3. Switch to fully open mode (high risk)" - echo "4. Restore official default strategy" - echo "5. Run a security audit" - echo "0. Return to the previous level" + echo -e "${gl_kjlan}1.${gl_bai}Switch to standard security mode (daily recommendations, pop-up card approval)" + echo -e "${gl_kjlan}2.${gl_bai}Switch to development enhancement mode (allowing agents to apply for privilege escalation)" + echo -e "${gl_kjlan}3.${gl_bai}Switch to fully open mode (${gl_hong}High risk! Completely remove all host interceptions${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai}Restore the official default sandbox defense strategy" + echo -e "${gl_kjlan}5.${gl_bai}Run underlying security audits and automatic repairs" + echo -e "${gl_kjlan}0.${gl_bai}Return to previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" perm_choice case "$perm_choice" in 1) - echo "Will apply: Standard security mode" + echo "Prepare to apply: Standard safe mode" read -e -p "Enter yes to confirm:" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "Canceled" break_end ;; 2) - echo "Will apply: development enhancement mode" + echo "Preparing the App: Developing Enhanced Mode" read -e -p "Enter yes to confirm:" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "Canceled" break_end ;; 3) - echo "⚠️ Fully open mode will turn off exec approval, enable privilege escalation and bash, and is only recommended for trusted single-user environments." + echo -e "${gl_hong}⚠️ Fully open mode will completely collapse exec approval and automatically release high-risk code.${gl_bai}" read -e -p "Enter FULL to confirm to continue:" confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "Canceled" break_end ;; 4) - echo "Override explicit permissions written by cleanup scripts, reverting to the official OpenClaw default policy." + echo "All custom overrides will be cleared, restoring OpenClaw to its strictly sandboxed state when first installed." read -e -p "Enter yes to confirm:" confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "Canceled" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 @@ -14904,7 +14918,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw multi-agent - remove routing binding" + send_stats "OpenClaw multi-agent - remove route binding" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "Please enter the agent ID:" agent_id @@ -15279,7 +15293,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15649,7 +15663,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -15753,7 +15767,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -15807,7 +15821,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -15905,7 +15919,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -16791,7 +16805,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17018,7 +17032,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17070,7 +17084,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17111,7 +17125,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17174,7 +17188,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17388,7 +17402,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -17502,7 +17516,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17723,7 +17737,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17773,7 +17787,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17909,7 +17923,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18136,7 +18150,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18274,7 +18288,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18328,7 +18342,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18561,7 +18575,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18632,7 +18646,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18701,7 +18715,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18842,7 +18856,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18912,7 +18926,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19126,7 +19140,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19524,7 +19538,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -19869,7 +19883,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21164,7 +21178,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21315,7 +21329,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 4ec4c7822..b31f86a9d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -254,7 +254,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -924,12 +924,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1985,7 +1985,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2231,10 +2231,10 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2555,7 +2555,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2614,7 +2614,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2631,7 +2631,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3215,7 +3215,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3284,7 +3284,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3690,7 +3690,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "レイヤ 4 プロキシを追加する" + send_stats "レイヤー 4 プロキシを追加する" ;; 5) send_stats "転送設定の編集" @@ -3746,7 +3746,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4304,7 +4304,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4409,7 +4409,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4773,7 +4773,7 @@ linux_clean() { bbr_on() { -# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5468,7 +5468,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5802,7 +5802,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5850,7 +5850,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6279,7 +6279,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6421,7 +6421,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6726,7 +6726,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7049,7 +7049,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -7091,7 +7091,7 @@ mount_partition() { return 1 fi - echo "パーティションが正常にマウントされました$MOUNT_POINT" + echo "パーティションは正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7226,7 +7226,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7395,7 +7395,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7485,7 +7485,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7667,7 +7667,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7727,7 +7727,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -7785,7 +7785,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncduをインストールする" + send_stats "ncdu をインストールする" ;; 14) clear @@ -8029,7 +8029,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8206,7 +8206,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8238,7 +8238,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8455,7 +8455,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -9181,7 +9181,7 @@ linux_ldnmp() { echo "バックエンドのログイン パス: /admin" echo "------------------------" echo "ユーザー名: 管理者" - echo "パスワード: 管理者" + echo "密码: admin" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" @@ -10598,7 +10598,7 @@ EOF local config_file config_file=$(openclaw_get_config_file) - # API プロトコルを自動的に検出/修正しなくなりました。ユーザー設定を維持します + # API プロトコルを自動的に検出/修正しなくなりました。ユーザー構成を維持します DETECTED_API="openai-completions" [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" @@ -10764,7 +10764,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11154,7 +11154,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行完了" + echo "✅ 同期実行が完了しました" start_gateway ;; 2) @@ -11201,7 +11201,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "設定したい API タイプを選択してください:" + echo "セットアップする API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -11480,7 +11480,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入口" + send_stats "OpenClaw APIの入り口" while true; do clear echo "=======================================" @@ -12238,7 +12238,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." start_gateway fi break_end @@ -12247,7 +12247,7 @@ PYTHON_EOF install_skill() { - send_stats "スキル管理" + send_stats "スキルマネジメント" while true; do clear echo "========================================" @@ -12356,7 +12356,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." start_gateway fi break_end @@ -13682,7 +13682,7 @@ EOF echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -13871,7 +13871,7 @@ EOF while true; do clear echo "=======================================" - echo "メモリソリューションの自動展開" + echo "メモリソリューションの自動導入" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14094,7 +14094,7 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "合計行数:$total_lines" + echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines @@ -14413,160 +14413,175 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "設定ファイル:$config_file" - [ ! -s "$config_file" ] && echo "⚠️ OpenClaw 設定ファイルが見つかりません (まだ初期化されていない可能性があります)。" - echo "現在のモード:$mode" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # Python セキュリティ更新プログラムを使用するか、exec-approvals.json を作成します。 + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} + +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + + openclaw_permission_render_status() { + echo "アプリケーション層の構成: ~/.openclaw/openclaw.json" + echo "ホストの承認: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi - # Python を使用してすべての権限フィールドを一度に効率的に解析する - python3 - "$config_file" <<'PY' + local current_mode="不明 / カスタム" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32m標準セーフモード\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31m全開モード\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33m開発拡張モード\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36m公式サンドボックスが真実を語る\033[0m" + fi + echo -e "現在の包括的なセキュリティ レベル:${current_mode}" + echo "---------------------------------------" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ プロファイル (デフォルト): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ 実行制限: /' || echo "実行制限: (未設定)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 承認プロンプト: /' || echo "承認プロンプト: (未設定)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 権限昇格スイッチ: /' || echo "権限昇格スイッチ: (未設定)" + + echo -e "\n${gl_huang}[基本的な幹部の承認ステータス]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) - try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ 構成ファイルの解析に失敗しました: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print('傍受戦略 (セキュリティ):' + str(d.get('security', '(unset)'))) + print('即時戦略 (質問):' + str(d.get('ask', '(unset)'))) + print('UI カバーなし (AskFallback):' + str(d.get('askFallback', '(unset)'))) +except Exception: + print('(設定ファイルの解析に失敗しました)') +" + else + echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw 権限 - 標準セキュリティ モード" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" - return 1 - fi - echo "✅ 標準の安全モードに切り替えられました" + + echo "アプリケーション層ポリシーを構成しています..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "ホスト承認インターセプトを構成しています..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw 権限 - 開発拡張モード" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" - return 1 - fi - echo "✅ 開発強化モードに切り替えました" + + echo "アプリケーション層ポリシーを構成しています..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "ホスト承認インターセプトを構成しています..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには引き続き承認が必要です)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw 権限 - 完全オープン モード" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切り替え失敗:書き込み権限の設定中にエラーが発生しました。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" - return 1 - fi - echo "✅ 全開モードに切り替えました" + + echo "アプリケーション層ポリシーを構成しています..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "ホストの迎撃防御が崩壊中..." + # ここでの full と off は、基礎となるホストの実行承認システムを完全にバイパスします。 + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw 権限 - 公式のデフォルトに戻す" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 回復に失敗しました: 明示的なアクセス許可のオーバーライドをクリーニング中にエラーが発生しました。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 設定は書き込まれましたが、再起動に失敗しました。手動で実行してください: openclaw ゲートウェイの再起動" - return 1 - fi - echo "✅ OpenClaw 公式のデフォルト戦略に戻しました (明示的なオーバーライドをクリアしました)" + + echo "クリーンなアプリケーション層の適用範囲を強化します..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "クリーンなホストインターセプト構成..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ OpenClaw 公式セキュリティ サンドボックス防御メカニズムに戻しました${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw 権限 - セキュリティ監査" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "公式の OpenClaw セキュリティ監査と物理的な監査を実行します。" + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "発見されたセキュリティ脆弱性を自動的に修復してみますか? (y/n):" fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ 自動修復が完了しました。${gl_bai}" + fi + echo "戻るには任意のキーを押してください..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14589,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw権限管理" + echo "OpenClaw 権限管理 (デュアルレイヤー アーキテクチャの高度な適応)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1.標準のセーフモードに切り替える(推奨)" - echo "2. 開発強化モードに切り替える" - echo "3. 全開モードへの切り替え(高リスク)" - echo "4. 公式のデフォルト戦略を復元する" - echo "5. セキュリティ監査を実行する" - echo "0. 前のレベルに戻ります" + echo -e "${gl_kjlan}1.${gl_bai}標準セキュリティ モードに切り替える (毎日の推奨事項、ポップアップ カードの承認)" + echo -e "${gl_kjlan}2.${gl_bai}開発拡張モードに切り替える (エージェントが権限昇格を申請できるようにする)" + echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}ハイリスク!すべてのホストインターセプトを完全に削除します${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai}公式のデフォルトのサンドボックス防御戦略を復元する" + echo -e "${gl_kjlan}5.${gl_bai}基盤となるセキュリティ監査と自動修復を実行する" + echo -e "${gl_kjlan}0.${gl_bai}前のレベルに戻る" echo "---------------------------------------" read -e -p "選択肢を入力してください:" perm_choice case "$perm_choice" in 1) - echo "適用: 標準セキュリティ モード" + echo "適用の準備: 標準セーフ モード" read -e -p "確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "キャンセル" break_end ;; 2) - echo "適用される: 開発拡張モード" + echo "アプリの準備: 拡張モードの開発" read -e -p "確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "キャンセル" break_end ;; 3) - echo "⚠️ フルオープン モードは実行承認をオフにし、特権エスカレーションと bash を有効にし、信頼できるシングルユーザー環境にのみ推奨されます。" + echo -e "${gl_hong}⚠️ フルオープンモードでは、実行承認が完全に崩壊し、高リスクコードが自動的にリリースされます。${gl_bai}" read -e -p "続行することを確認するには「FULL」と入力します。" confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "キャンセル" break_end ;; 4) - echo "クリーンアップ スクリプトによって書き込まれた明示的なアクセス許可をオーバーライドし、公式の OpenClaw デフォルト ポリシーに戻します。" + echo "すべてのカスタム オーバーライドがクリアされ、OpenClaw が最初にインストールされたときの厳密にサンドボックス化された状態に戻ります。" read -e -p "確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "キャンセル" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 @@ -14904,13 +14918,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw マルチエージェント - ルーティング バインディングの削除" + send_stats "OpenClaw マルチエージェント - ルート バインディングの削除" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" + echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15049,7 +15063,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 設定ファイルを編集する" + send_stats "OpenClaw 構成ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15209,7 +15223,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期設定ウィザード" + 11) send_stats "初期構成ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15279,7 +15293,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -16514,7 +16528,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -17146,7 +17160,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -19126,7 +19140,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19454,7 +19468,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19464,7 +19478,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19476,7 +19490,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19502,7 +19516,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記帳の職業】" + echo "【日記ログ職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -19524,10 +19538,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19537,7 +19551,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19552,7 +19566,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19640,7 +19654,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -19655,7 +19669,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -19671,7 +19685,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -19682,7 +19696,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集する" + echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -19799,7 +19813,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20263,7 +20277,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -20857,7 +20871,7 @@ EOF fi echo "プライバシーとセキュリティ" - echo "スクリプトはユーザーによる機能の使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" + echo "スクリプトはユーザーの機能使用に関するデータを収集し、スクリプト エクスペリエンスを最適化し、より楽しくて便利な機能を作成します。" echo "スクリプトのバージョン番号、使用時間、システムバージョン、CPUアーキテクチャ、マシンの国、使用された機能の名前が収集されます。" echo "------------------------------------------------" echo -e "現在のステータス:$status_message" @@ -21164,7 +21178,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21315,7 +21329,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21521,7 +21535,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -21560,8 +21574,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 6d1dadbc1..e9ab02b61 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1093,7 +1093,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1200,7 +1200,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1262,7 +1262,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -2318,7 +2318,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2783,7 +2783,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2799,7 +2799,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2887,7 +2887,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3010,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3215,7 +3215,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3503,7 +3503,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4409,7 +4409,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4773,7 +4773,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5802,7 +5802,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5838,7 +5838,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -5951,7 +5951,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정하세요── + # ──장면에 따라 매개변수를 설정합니다── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6538,7 +6538,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7997,7 +7997,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -8136,7 +8136,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8238,7 +8238,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8271,7 +8271,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8786,7 +8786,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -11783,7 +11783,7 @@ PYTHON_EOF return 1 fi - # 빠른 찾기를 위해 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12149,7 +12149,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12173,7 +12173,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인:$plugin_id" + echo "🔍 플러그인 상태 확인 중:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12190,7 +12190,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12277,7 +12277,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -13461,7 +13461,7 @@ EOF OPENCLAW_MEMORY_RECOMMEND_REASON=() if [ "$qmd_ok" = "true" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") fi @@ -13587,7 +13587,7 @@ EOF elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13732,7 +13732,7 @@ EOF openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command가 정확합니다." fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -14007,7 +14007,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14190,7 +14190,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14413,160 +14413,175 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "구성 파일:$config_file" - [ ! -s "$config_file" ] && echo "⚠️ OpenClaw 구성 파일을 찾을 수 없습니다(아직 초기화되지 않았을 수 있음)." - echo "현재 모드:$mode" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # Python 보안 업데이트를 사용하거나 exec-approvals.json을 생성하세요. + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} + +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + + openclaw_permission_render_status() { + echo "애플리케이션 계층 구성: ~/.openclaw/openclaw.json" + echo "호스트 승인: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi - # Python을 사용하여 모든 권한 필드를 한 번에 효율적으로 구문 분석 - python3 - "$config_file" <<'PY' + local current_mode="알 수 없음/커스텀" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32m표준 안전 모드\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31m완전 개방 모드\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33m향상된 모드 개발\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36m공식 샌드박스가 진실을 말해줍니다\033[0m" + fi + echo -e "현재 포괄적인 보안 수준:${current_mode}" + echo "---------------------------------------" + echo -e "${gl_huang}[애플리케이션 레이어 도구 정책 현황]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ 프로필(기본값): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ 실행 제한: /' || echo "실행 한도: (설정되지 않음)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 승인 메시지: /' || echo "승인 메시지: (설정되지 않음)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 권한 상승 스위치: /' || echo "권한 에스컬레이션 스위치: (설정되지 않음)" + + echo -e "\n${gl_huang}[기본 Exec 승인 상태]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) - try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ 구성 파일 구문 분석 실패: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print('차단 전략(보안):' + str(d.get('security', '(unset)'))) + print('신속한 전략(질문):' + str(d.get('ask', '(unset)'))) + print('UI 커버 없음(AskFallback):' + str(d.get('askFallback', '(unset)'))) +except Exception: + print('(구성 파일 구문 분석 실패)') +" + else + echo "(구성되지 않음, 시스템에 내장된 보안 정책을 강제로 사용함)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" - return 1 - fi - echo "✅ 표준 안전 모드로 전환됨" + + echo "애플리케이션 레이어 정책 구성 중..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "호스트 승인 차단 구성 중..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 명령은 모두 UI/TG를 통해 승인을 요청합니다)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" - return 1 - fi - echo "✅ 개발 강화 모드로 전환됨" + + echo "애플리케이션 레이어 정책 구성 중..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "호스트 승인 차단 구성 중..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 전환 실패: 쓰기 권한 구성 중 오류가 발생했습니다." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" - return 1 - fi - echo "✅ 완전 개방 모드로 전환됨" + + echo "애플리케이션 레이어 정책 구성 중..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "호스트 차단 방어 붕괴…" + # 여기서 전체 및 해제는 기본 호스트의 실행 승인 시스템을 완전히 우회합니다. + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 완전 개방 모드로 전환되었습니다. (경고: 모든 호스트 명령 차단이 만료되었으며 에이전트는 가장 높은 권한을 가집니다.)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw 권한-공식 기본값 복원" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 복구 실패: 명시적 권한 재정의를 정리하는 동안 오류가 발생했습니다." - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 구성이 작성되었지만 다시 시작에 실패했습니다. 수동으로 실행하십시오: openclaw Gateway restart" - return 1 - fi - echo "✅ OpenClaw 공식 기본 전략으로 되돌림(명시적 재정의 삭제)" + + echo "깨끗한 애플리케이션 레이어 힘 범위..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "호스트 차단 구성을 정리합니다..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ OpenClaw 공식 보안 샌드박스 방어 메커니즘으로 복귀${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw 권한-보안 감사" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "공식 OpenClaw 보안 감사를 실행하고 물리적..." + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "발견된 보안 취약점을 자동으로 해결하려고 합니까? (예/아니요):" fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ 자동 복구가 완료되었습니다.${gl_bai}" + fi + echo "돌아가려면 아무 키나 누르세요..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14589,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw 권한 관리" + echo "OpenClaw 권한 관리(이중 레이어 아키텍처 심층 적응)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 표준 안전 모드로 전환(권장)" - echo "2. 개발 강화 모드로 전환" - echo "3. 완전 개방 모드로 전환(고위험)" - echo "4. 공식 기본 전략 복원" - echo "5. 보안 감사 실행" - echo "0. 이전 레벨로 돌아갑니다" + echo -e "${gl_kjlan}1.${gl_bai}표준보안모드로 전환(일일권장, 팝업카드 승인)" + echo -e "${gl_kjlan}2.${gl_bai}개발 강화 모드로 전환(에이전트가 권한 승격을 신청할 수 있도록 허용)" + echo -e "${gl_kjlan}3.${gl_bai}완전 개방 모드로 전환(${gl_hong}위험! 모든 호스트 차단을 완전히 제거합니다.${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai}공식 기본 샌드박스 방어 전략 복원" + echo -e "${gl_kjlan}5.${gl_bai}기본 보안 감사 및 자동 복구 실행" + echo -e "${gl_kjlan}0.${gl_bai}이전 레벨로 돌아가기" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" perm_choice case "$perm_choice" in 1) - echo "적용 예정: 표준 보안 모드" + echo "적용 준비: 표준 안전 모드" read -e -p "확인하려면 yes를 입력하세요." confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "취소" break_end ;; 2) - echo "적용 예정: 개발 강화 모드" + echo "앱 준비: 고급 모드 개발" read -e -p "확인하려면 yes를 입력하세요." confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "취소" break_end ;; 3) - echo "⚠️ 완전 개방 모드는 exec 승인을 끄고 권한 상승 및 bash를 활성화하며 신뢰할 수 있는 단일 사용자 환경에만 권장됩니다." + echo -e "${gl_hong}⚠️ 완전 개방 모드는 실행 승인을 완전히 무너뜨리고 고위험 코드를 자동으로 공개합니다.${gl_bai}" read -e -p "계속하려면 FULL을 입력하여 확인하세요." confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "취소" break_end ;; 4) - echo "정리 스크립트로 작성된 명시적 권한을 재정의하여 공식 OpenClaw 기본 정책으로 되돌립니다." + echo "모든 사용자 정의 재정의가 지워지고 OpenClaw를 처음 설치할 때 엄격한 샌드박스 상태로 복원됩니다." read -e -p "확인하려면 yes를 입력하세요." confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "취소" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 @@ -14904,7 +14918,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 제거" + send_stats "OpenClaw 다중 에이전트 - 경로 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "상담원 ID를 입력하세요:" agent_id @@ -15213,7 +15227,7 @@ openclaw_backup_restore_menu() { openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 수리" + 12) send_stats "상태 감지 및 복구" openclaw doctor --fix send_stats "OpenClaw API 동기식 트리거링" if sync_openclaw_api_models; then @@ -15279,7 +15293,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15319,7 +15333,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15339,7 +15353,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15649,7 +15663,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17082,7 +17096,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -19126,7 +19140,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19524,7 +19538,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -19573,7 +19587,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "3) 최대 로그 크기를 500M로 제한합니다." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19679,7 +19693,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -19798,7 +19812,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -20099,7 +20113,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -20283,7 +20297,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -21164,7 +21178,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21315,7 +21329,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21598,7 +21612,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 182f2cc84..5af72ae36 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1221,7 +1221,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1492,7 +1492,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "網站資訊 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -3694,11 +3694,11 @@ stream_panel() { ;; 5) send_stats "編輯轉送配置" - read -e -p "請輸入你要編輯的服務名稱:" stream_name + read -e -p "请输入你要编辑的服务名: " stream_name install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四層代理" + send_stats "修改四层代理" ;; 6) send_stats "刪除轉送配置" @@ -3724,8 +3724,8 @@ ldnmp_Proxy_backend_stream() { send_stats "安裝$webname" echo "開始部署$webname" - # 取得代理名稱 - read -erp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name + # 获取代理名称 + read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name if [ -z "$proxy_name" ]; then echo "名稱不能為空"; return 1 fi @@ -3884,7 +3884,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3925,7 +3925,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -4078,8 +4078,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安裝frp服務端" - # 產生隨機連接埠和憑證 + send_stats "安装frp服务端" + # 生成随机端口和凭证 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -4163,7 +4163,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入 frpc.toml" + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4779,7 +4779,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版本 sysctl.conf 殘留 +# 清理可能導致衝突的舊版 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5037,7 +5037,7 @@ fetch_remote_ssh_keys() { return 1 fi - # 檢查內容是否有效 + # 检查内容是否有效 if [[ ! -s "${temp_file}" ]]; then echo "錯誤:下載到的檔案為空,URL 可能不包含任何公鑰" >&2 rm -f "${temp_file}" @@ -5209,7 +5209,7 @@ add_sshpasswd() { # 回車不輸入,預設 root target_user=${target_user:-root} - # 校驗用戶是否存在 + # 校验用户是否存在 if ! id "$target_user" >/dev/null 2>&1; then echo "錯誤:用戶$target_user不存在" return 1 @@ -6334,21 +6334,21 @@ Kernel_optimize() { cd ~ clear _kernel_optimize_core "遊戲服優化模式" "game" - send_stats "遊戲服優化" + send_stats "游戏服优化" ;; 6) cd ~ clear restore_defaults curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults - send_stats "還原預設設定" + send_stats "还原默认设置" ;; 7) cd ~ clear curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - send_stats "核心自動調優" + send_stats "内核自动调优" ;; *) @@ -6378,7 +6378,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang 重新连接SSH生效。${gl_bai}" hash -r break_end @@ -6387,17 +6387,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "不支援的系統:$ID" + echo "不支持的系统: $ID" break_end ;; esac else - echo "不支援的系統,無法辨識系統類型。" + echo "不支持的系统,无法识别系统类型。" break_end fi } @@ -6910,7 +6910,7 @@ add_connection() { send_stats "新增連接" echo "建立新連接範例:" echo "- 連線名稱: my_server" - echo "- IP位址: 192.168.1.100" + echo " - IP地址: 192.168.1.100" echo "- 使用者名稱: root" echo "- 連接埠: 22" echo "------------------------" @@ -6930,7 +6930,7 @@ add_connection() { # 刪除連接 delete_connection() { send_stats "刪除連接" - read -e -p "請輸入要刪除的連接編號:" num + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -7011,7 +7011,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以透過SSH連接到其他Linux系統上" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -7091,7 +7091,7 @@ mount_partition() { return 1 fi - echo "分區已成功掛載到$MOUNT_POINT" + echo "分割區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7099,10 +7099,10 @@ mount_partition() { return 0 fi - # 寫入 /etc/fstab + # 写入 /etc/fstab echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab - echo "已寫入 /etc/fstab,實現持久化掛載" + echo "已写入 /etc/fstab,实现持久化挂载" } @@ -8271,7 +8271,7 @@ docker_ssh_migration() { echo -e "1. 備份docker項目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" - echo -e "4. 刪除docker專案的備份文件" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" echo -e "0. 返回上一級選單" echo "------------------------" @@ -8785,7 +8785,7 @@ linux_Oracle() { case $sub_choice in 1) clear - echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" + echo "活跃脚本: CPU占用10-20% 内存占用20% " read -e -p "確定安裝嗎? (Y/N):" choice case "$choice" in [Yy]) @@ -9659,7 +9659,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "請輸入index.html的路徑,類似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -9987,7 +9987,7 @@ moltbot_menu() { return 1 fi - # 加上 --no-update-notifier,並確保錯誤重定向位置正確 + # 加上 --no-update-notifier,并确保错误重定向位置正确 local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10003,7 +10003,7 @@ moltbot_menu() { if [ "$local_version" != "$remote_version" ]; then echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } @@ -10709,7 +10709,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11161,7 +11161,7 @@ PY2 echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失敗:provider 配置不完整或類型不支持" + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11370,7 +11370,7 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 刪除中止:預設主模型指向該 provider,且無可用替代模型') + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') raise SystemExit(3) set_primary_ref(defaults, replacement) print(f'🔁 預設主模型切換: {primary_ref} -> {replacement}') @@ -12173,12 +12173,12 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 正在檢查插件狀態:$plugin_id" + echo "🔍 正在检查插件状态: $plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." + echo "💡 插件 [$plugin_id] 已预装,正在激活..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12276,7 +12276,7 @@ PYTHON_EOF echo "----------------------------------------" echo "1) 安裝技能" - echo "2) 刪除技能" + echo "2) 删除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -13119,7 +13119,7 @@ if os.path.isdir(agents_root): fi if [ ! -f "$target_path" ]; then - echo "❌ 目標檔案不存在:$target_path" + echo "❌ 目标文件不存在: $target_path" break_end return 1 fi @@ -13724,7 +13724,7 @@ EOF echo "✅ memory.backend 已是 qmd" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ 已設定 memory.backend=qmd" + echo "✅ 已设置 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") @@ -14163,11 +14163,11 @@ EOF } openclaw_memory_menu() { - send_stats "OpenClaw記憶管理" + send_stats "OpenClaw记忆管理" while true; do clear echo "=======================================" - echo "OpenClaw 記憶管理" + echo "OpenClaw 记忆管理" echo "=======================================" openclaw_memory_render_status echo "1. 更新記憶索引" @@ -14413,160 +14413,175 @@ except Exception: PY } - openclaw_permission_render_status() { - local config_file mode - config_file=$(openclaw_permission_config_file) - mode=$(openclaw_permission_detect_mode) - echo "設定檔:$config_file" - [ ! -s "$config_file" ] && echo "⚠️ 未找到 OpenClaw 設定檔(可能尚未初始化)。" - echo "當前模式:$mode" + openclaw_permission_update_exec_approvals() { + local sec="$1" + local ask="$2" + local fallback="$3" + local approvals_file="$HOME/.openclaw/exec-approvals.json" + + mkdir -p "$HOME/.openclaw" + + # 使用 Python 安全性更新或建立 exec-approvals.json + python3 -c " +import json, sys, os +path = sys.argv[1] +try: + if os.path.exists(path): + with open(path, 'r') as f: + data = json.load(f) + else: + data = {'version': 1, 'defaults': {}} +except Exception: + data = {'version': 1, 'defaults': {}} + +if 'defaults' not in data: + data['defaults'] = {} + +data['defaults']['security'] = sys.argv[2] +data['defaults']['ask'] = sys.argv[3] +data['defaults']['askFallback'] = sys.argv[4] +data['defaults']['autoAllowSkills'] = True + +with open(path, 'w') as f: + json.dump(data, f, indent=2) +" "$approvals_file" "$sec" "$ask" "$fallback" + } + + openclaw_permission_render_status() { + echo "應用層配置: ~/.openclaw/openclaw.json" + echo "宿主機核准: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" + local current_profile=$(openclaw config get tools.profile 2>/dev/null) + local sec_val + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") + else + sec_val="unset" + fi - # 使用 Python 一次高效能解析所有權限字段 - python3 - "$config_file" <<'PY' + local current_mode="未知 / 自訂" + if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then + current_mode="\033[1;32m標準安全模式\033[0m" + elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;31m完全開放模式\033[0m" + elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + current_mode="\033[1;33m開發增強模式\033[0m" + elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + current_mode="\033[1;36m官方沙盒兜底\033[0m" + fi + echo -e "當前綜合安全等級:${current_mode}" + echo "---------------------------------------" + echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" + openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (預設): /' || echo " Profile: (unset)" + openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo "Exec 限制: (unset)" + openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 審核提示: /' || echo "審核提示: (unset)" + openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提權開關: /' || echo "提權開關: (unset)" + + echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" + if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c " import json, sys -def get_val(obj, path, default="(unset)"): - parts = path.split('.') - for p in parts: - if isinstance(obj, dict) and p in obj: obj = obj[p] - else: return default - if isinstance(obj, (list, dict)): return json.dumps(obj) - return str(obj) - try: - with open(sys.argv[1], 'r') as f: data = json.load(f) - fields = [ - ("tools.profile", "tools.profile"), - ("tools.allow", "tools.allow"), - ("tools.deny", "tools.deny"), - ("tools.byProvider", "tools.byProvider"), - ("tools.exec.security", "tools.exec.security"), - ("tools.exec.ask", "tools.exec.ask"), - ("tools.elevated.enabled", "tools.elevated.enabled"), - ("commands.bash", "commands.bash"), - ("applyPatch.enabled", "tools.exec.applyPatch.enabled"), - ("applyPatch.workspaceOnly", "tools.exec.applyPatch.workspaceOnly") - ] - for label, path in fields: - val = get_val(data, path) - print("%-28s %s" % (label, val)) -except Exception as e: - print("❌ 設定檔解析失敗: %s" % e) -PY + with open('$HOME/.openclaw/exec-approvals.json') as f: + d = json.load(f).get('defaults', {}) + print('攔截策略 (Security):' + str(d.get('security', '(unset)'))) + print('提示策略 (Ask):' + str(d.get('ask', '(unset)'))) + print('無UI兜底 (AskFallback):' + str(d.get('askFallback', '(unset)'))) +except Exception: + print('(設定檔解析失敗)') +" + else + echo "(未配置,強制使用系統內建安全兜底策略)" + fi } openclaw_permission_apply_standard() { send_stats "OpenClaw權限-標準安全模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled false || failed=1 - openclaw config set commands.bash false || failed=1 - openclaw config set tools.exec.applyPatch.enabled false || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切換為標準安全模式" + + echo "正在設定應用層策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled false >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 + openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 + + echo "正在設定宿主機審批攔截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切換為標準安全模式 (所有危險命令將透過UI/TG請求你的批准)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw權限-開發增強模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile coding || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security allowlist || failed=1 - openclaw config set tools.exec.ask on-miss || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切換為開發增強模式" + + echo "正在設定應用層策略..." + openclaw config set tools.profile coding >/dev/null 2>&1 + openclaw config set tools.exec.security allowlist >/dev/null 2>&1 + openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在設定宿主機審批攔截..." + openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切換為開發增強模式 (允許提權,但常規危險命令仍需審批)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw權限-完全開放模式" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw config set tools.profile full || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw config set tools.deny '[]' --json || failed=1 - openclaw config set tools.exec.security full || failed=1 - openclaw config set tools.exec.ask off || failed=1 - openclaw config set tools.elevated.enabled true || failed=1 - openclaw config set commands.bash true || failed=1 - openclaw config set tools.exec.applyPatch.enabled true || failed=1 - openclaw config set tools.exec.applyPatch.workspaceOnly true || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 切換失敗:寫入權限配置過程中出現錯誤。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" - return 1 - fi - echo "✅ 已切換為完全開放模式" + + echo "正在設定應用層策略..." + openclaw config set tools.profile full >/dev/null 2>&1 + openclaw config set tools.exec.security full >/dev/null 2>&1 + openclaw config set tools.exec.ask off >/dev/null 2>&1 + openclaw config set tools.elevated.enabled true >/dev/null 2>&1 + openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 + + echo "正在瓦解宿主機攔截防禦..." + # 這裡的 full 和 off 將徹底繞過底層宿主機的 exec 審批系統 + openclaw_permission_update_exec_approvals "full" "off" "full" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已切換為完全開放模式 (警告:所有宿主機指令攔截已失效,智能體具有最高權限)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw權限-恢復官方默認" openclaw_permission_require_openclaw || return 1 - openclaw_permission_backup_current || true - local failed=0 - openclaw_permission_unset_optional tools.profile || failed=1 - openclaw_permission_unset_optional tools.byProvider || failed=1 - openclaw_permission_unset_optional tools.allow || failed=1 - openclaw_permission_unset_optional tools.deny || failed=1 - openclaw_permission_unset_optional tools.exec.security || failed=1 - openclaw_permission_unset_optional tools.exec.ask || failed=1 - openclaw_permission_unset_optional tools.elevated.enabled || failed=1 - openclaw_permission_unset_optional commands.bash || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.enabled || failed=1 - openclaw_permission_unset_optional tools.exec.applyPatch.workspaceOnly || failed=1 - if [ "$failed" -ne 0 ]; then - echo "❌ 恢復失敗:清理明確權限覆蓋時發生錯誤。" - openclaw_permission_restore_backup || true - return 1 - fi - if ! openclaw_permission_restart_gateway; then - echo "⚠️ 已寫入配置,但重啟失敗,請手動執行: openclaw gateway restart" - return 1 - fi - echo "✅ 已恢復為 OpenClaw 官方預設策略(清除明確覆蓋)" + + echo "清理應用層強制覆蓋..." + openclaw config unset tools.profile >/dev/null 2>&1 + openclaw config unset tools.exec.security >/dev/null 2>&1 + openclaw config unset tools.exec.ask >/dev/null 2>&1 + openclaw config unset tools.elevated.enabled >/dev/null 2>&1 + openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 + + echo "清理宿主機攔截配置..." + rm -f "$HOME/.openclaw/exec-approvals.json" + + openclaw_permission_restart_gateway + echo -e "${gl_lv}✅ 已恢復到 OpenClaw 官方安全沙盒防禦機制${gl_bai}" } openclaw_permission_run_audit() { - send_stats "OpenClaw權限-安全性審計" - openclaw_permission_require_openclaw || return 1 + echo "=======================================" + echo "運行 OpenClaw 官方安全審計與體檢..." + echo "=======================================" openclaw security audit + echo "---------------------------------------" + read -e -p "是否嘗試自動修復發現的安全隱患? (y/n):" fix_choice + if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then + openclaw security audit --fix + echo -e "${gl_lv}✅ 自動修復完成。${gl_bai}" + fi + echo "按任意鍵返回..." + read -n 1 -s } openclaw_permission_menu() { @@ -14574,46 +14589,45 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw 權限管理" + echo "OpenClaw 權限管理 (雙層架構深度適配)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo "1. 切換為標準安全模式(建議)" - echo "2. 切換為開發增強模式" - echo "3. 切換為完全開放模式(高風險)" - echo "4. 恢復官方預設策略" - echo "5. 運行安全審計" - echo "0. 返回上一級" + echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" + echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" + echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" + echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" + echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" + echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" perm_choice case "$perm_choice" in 1) - echo "將應用:標準安全模式" + echo "準備應用:標準安全模式" read -e -p "輸入 yes 確認:" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" break_end ;; 2) - echo "將應用:開發增強模式" + echo "準備應用:開發增強模式" read -e -p "輸入 yes 確認:" confirm [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" break_end ;; 3) - echo "⚠️ 完全開放模式會關閉 exec 審核、啟用提權與 bash,僅建議可信任單一使用者環境使用。" - read -e -p "輸入 FULL 確認繼續:" confirm + echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" + read -e -p "输入 FULL 确认继续: " confirm [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" break_end ;; 4) - echo "將清除腳本寫入的明確權限覆寫,恢復到 OpenClaw 官方預設策略。" + echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "輸入 yes 確認:" confirm [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" break_end ;; 5) openclaw_permission_run_audit - break_end ;; 0) return 0 @@ -14855,7 +14869,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體建立失敗" + echo "❌ 智能體創建失敗" return 1 fi } @@ -15097,7 +15111,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15289,7 +15303,7 @@ while true; do echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" + echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma监控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" @@ -16773,7 +16787,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼皆為: admin" + echo "初始使用者名稱密碼均為: admin" } docker_app_update() { @@ -17388,7 +17402,7 @@ while true; do } - local docker_describe="是一個輕量、高效能的音樂串流伺服器" + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" local docker_url="官網介紹: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -19670,16 +19684,16 @@ env_menu() { send_stats "正在重新載入環境變數" source "$BASHRC" source "$PROFILE" - echo "✔ 環境變數已重新載入" + echo "✔ 环境变量已重新加载" read -erp "按回車繼續..." } while true; do clear - echo "=========== 系統環境變數管理 ==========" + echo "=========== 系统环境变量管理 ==========" echo "目前使用者:$USER" echo "--------------------------------------" - echo "1. 查看目前常用環境變數" + echo "1. 查看当前常用环境变量" echo "2. 查看 ~/.bashrc" echo "3. 查看 ~/.profile" echo "4. 編輯 ~/.bashrc" @@ -19727,7 +19741,7 @@ create_user_with_sshkey() { local sshkey_vl if [[ -z "$new_username" ]]; then - echo "用法:create_user_with_sshkey <使用者名稱>" + echo "用法:create_user_with_sshkey <用户名>" return 1 fi @@ -19817,7 +19831,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令列美化工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}設定係統回收站${gl_kjlan}34. ${gl_bai}系統備份與復原" - echo -e "${gl_kjlan}35. ${gl_bai}ssh遠端連線工具${gl_kjlan}36. ${gl_bai}硬碟分割區管理工具" + echo -e "${gl_kjlan}35. ${gl_bai}ssh遠端連線工具${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令列歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠端同步工具" echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}網路卡管理工具" echo -e "${gl_kjlan}------------------------" @@ -19981,7 +19995,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH埠修改" + send_stats "退出SSH連接埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20608,7 +20622,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -20959,7 +20973,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21022,7 +21036,7 @@ linux_file() { read -e -p "請輸入目前檔名:" current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" - send_stats "重新命名文件" + send_stats "重命名文件" ;; 15) # 删除文件 read -e -p "請輸入要刪除的檔名:" filename @@ -21312,7 +21326,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G記憶體 20G硬碟 800G流量每月${gl_bai}" echo -e "${gl_bai}網址: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" +echo -e "${gl_zi}V.PS 6.9刀每月 东京软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" @@ -21794,7 +21808,7 @@ else shift case $1 in install|安装) - send_stats "快速安裝docker" + send_stats "快捷安装docker" install_docker ;; ps|容器) From 11f56dba64e0d8cbdeb15c7fc3829f45720d2986 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 29 Mar 2026 14:13:16 +0800 Subject: [PATCH 1134/1285] =?UTF-8?q?refactor:=20=E5=85=A8=E9=9D=A2?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=B0=E5=BF=86/=E6=9D=83=E9=99=90/?= =?UTF-8?q?=E5=A4=9A=E6=99=BA=E8=83=BD=E4=BD=93=E4=B8=89=E5=A4=A7=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=8C=E9=80=82=E9=85=8D=20OpenClaw=202026.3.28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 权限模块: 使用 openclaw approvals get --json 替代表格解析,解决非 TTY 环境下 Unicode 表格线解析失败问题;新增 autoAllowSkills 状态展示 - 多智能体模块: 修复 openclaw sessions --json 的 stderr 泄漏导致 JSON 解析失败;过滤 [agents/model-providers] 行 - 记忆模块: 使用 openclaw memory status --json 替代逐 agent 文本解析,展示 backend/files/chunks/dirty/vector/dbPath 等完整字段 - 通过 bash -n 语法检查和测试机实测验证 --- cn/kejilion.sh | 418 ++++++++++++++++++++++++++++++++----------------- kejilion.sh | 418 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 546 insertions(+), 290 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index efa0efcf3..f3364f67a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -13366,27 +13366,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /' -e 's/^Workspace: /工作区: /' -e 's/^Store: /索引库: /') - if [ -z "$status_lines" ]; then - echo "未安装/未启动" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "获取记忆状态失败(openclaw memory status --json 无输出)" + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("获取记忆状态失败(JSON 解析错误)") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("未检测到任何智能体记忆状态。") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print(" 底层方案: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print(" 已收录: %s 文件 / %s 块" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "是" if dirty else "否" + print(" 待刷新: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "就绪" if vec.get("available") else "已启用(不可用)" + else: + vec_str = "未启用" + print(" 向量库: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print(" 工作区: %s" % ws) + db = s.get("dbPath") or "-" + print(" 索引库: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -14421,75 +14454,111 @@ PY mkdir -p "$HOME/.openclaw" - # 使用 Python 安全更新或创建 exec-approvals.json - python3 -c " + # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) + # 若 CLI 不支持则回退直接写文件 + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # 回退:直接写文件 + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "应用层配置: ~/.openclaw/openclaw.json" echo "宿主机审批: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # 清理空值 + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="未知 / 自定义" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32m标准安全模式\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m完全开放模式\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m开发增强模式\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ]; then + current_mode="\033[1;32m标准安全模式\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" fi echo -e " 当前综合安全等级: ${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 审批提示: /' || echo " 审批提示: (unset)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提权开关: /' || echo " 提权开关: (unset)" + echo " Profile (预设): ${current_profile:-(unset)}" + echo " Exec 限制: ${current_sec:-(unset)}" + echo " 审批提示: ${current_ask:-(unset)}" + echo " 提权开关: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print(' 拦截策略 (Security): ' + str(d.get('security', '(unset)'))) - print(' 提示策略 (Ask): ' + str(d.get('ask', '(unset)'))) - print(' 无UI兜底 (AskFallback): ' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print(" 拦截策略 (Security): " + str(sec)) + print(" 提示策略 (Ask): " + str(ask)) + print(" 无UI兜底 (AskFallback): " + str(fb)) + print(" 自动放行技能 (autoAllowSkills): " + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print(" (审批文件不存在,使用系统内置安全兜底)") +except Exception as e: + print(" (解析失败: " + str(e) + ")") +' "$approvals_json" + else + echo " (openclaw approvals get --json 无输出)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print(" 拦截策略 (Security): " + str(d.get("security", "(unset)"))) + print(" 提示策略 (Ask): " + str(d.get("ask", "(unset)"))) + print(" 无UI兜底 (AskFallback): " + str(d.get("askFallback", "(unset)"))) except Exception: - print(' (配置文件解析失败)') -" + print(" (配置文件解析失败)") +' else echo " (未配置,强制使用系统内置安全兜底策略)" fi @@ -14563,7 +14632,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "清理宿主机拦截配置..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # 优先通过 CLI 清空审批配置,回退直接删文件 + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" @@ -14705,6 +14779,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从配置文件读取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14806,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从配置文件读取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从文件系统读取 + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14875,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14893,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" echo "默认智能体: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("已配置智能体数: %s" % len(agents)) +print("路由绑定数: %s" % len(bindings)) +print("会话总数: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("当前未配置任何多智能体。") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = " [默认]" if is_default else "" + print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print(" 身份名称: %s %s" % (identity, emoji)) + print(" 模型: %s" % model) + print(" 工作目录: %s" % ws) + print(" 绑定数: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +14977,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw多智能体-查看路由绑定" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无路由绑定。"); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("暂无路由绑定。") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14938,14 +15028,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("暂无 session 数据。"); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("暂无 session 数据。") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("会话汇总:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15063,32 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置智能体。"); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ 未发现已配置智能体。") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("路由绑定数=%s" % len(bindings)) +print("✅ 多智能体健康检查完成") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "运行安全审计..." + openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" } openclaw_multiagent_menu() { diff --git a/kejilion.sh b/kejilion.sh index c74d93387..2d0e81fed 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -13366,27 +13366,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "获取状态失败" - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底层方案: /' -e 's/^Vector: /向量库状态: /' -e 's/^Indexed: /已收录文件: /' -e 's/^Workspace: /工作区: /' -e 's/^Store: /索引库: /') - if [ -z "$status_lines" ]; then - echo "未安装/未启动" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "获取记忆状态失败(openclaw memory status --json 无输出)" + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("获取记忆状态失败(JSON 解析错误)") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("未检测到任何智能体记忆状态。") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print(" 底层方案: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print(" 已收录: %s 文件 / %s 块" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "是" if dirty else "否" + print(" 待刷新: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "就绪" if vec.get("available") else "已启用(不可用)" + else: + vec_str = "未启用" + print(" 向量库: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print(" 工作区: %s" % ws) + db = s.get("dbPath") or "-" + print(" 索引库: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -14421,75 +14454,111 @@ PY mkdir -p "$HOME/.openclaw" - # 使用 Python 安全更新或创建 exec-approvals.json - python3 -c " + # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) + # 若 CLI 不支持则回退直接写文件 + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # 回退:直接写文件 + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "应用层配置: ~/.openclaw/openclaw.json" echo "宿主机审批: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # 清理空值 + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="未知 / 自定义" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32m标准安全模式\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m完全开放模式\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m开发增强模式\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ]; then + current_mode="\033[1;32m标准安全模式\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" fi echo -e " 当前综合安全等级: ${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (预设): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo " Exec 限制: (unset)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 审批提示: /' || echo " 审批提示: (unset)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提权开关: /' || echo " 提权开关: (unset)" + echo " Profile (预设): ${current_profile:-(unset)}" + echo " Exec 限制: ${current_sec:-(unset)}" + echo " 审批提示: ${current_ask:-(unset)}" + echo " 提权开关: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print(' 拦截策略 (Security): ' + str(d.get('security', '(unset)'))) - print(' 提示策略 (Ask): ' + str(d.get('ask', '(unset)'))) - print(' 无UI兜底 (AskFallback): ' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print(" 拦截策略 (Security): " + str(sec)) + print(" 提示策略 (Ask): " + str(ask)) + print(" 无UI兜底 (AskFallback): " + str(fb)) + print(" 自动放行技能 (autoAllowSkills): " + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print(" (审批文件不存在,使用系统内置安全兜底)") +except Exception as e: + print(" (解析失败: " + str(e) + ")") +' "$approvals_json" + else + echo " (openclaw approvals get --json 无输出)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print(" 拦截策略 (Security): " + str(d.get("security", "(unset)"))) + print(" 提示策略 (Ask): " + str(d.get("ask", "(unset)"))) + print(" 无UI兜底 (AskFallback): " + str(d.get("askFallback", "(unset)"))) except Exception: - print(' (配置文件解析失败)') -" + print(" (配置文件解析失败)") +' else echo " (未配置,强制使用系统内置安全兜底策略)" fi @@ -14563,7 +14632,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "清理宿主机拦截配置..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # 优先通过 CLI 清空审批配置,回退直接删文件 + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" @@ -14705,6 +14779,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从配置文件读取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14806,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从配置文件读取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:从文件系统读取 + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14875,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14893,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" echo "默认智能体: $default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能体数: %s" % len(agents)); print("路由绑定数: %s" % len(bindings)); print("会话总数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("当前未配置任何多智能体。") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("已配置智能体数: %s" % len(agents)) +print("路由绑定数: %s" % len(bindings)) +print("会话总数: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("当前未配置任何多智能体。") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能体ID: %s" % item.get("id","?")); print(" 身份名称: %s %s" % (identity, emoji)); print(" 工作目录: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = " [默认]" if is_default else "" + print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print(" 身份名称: %s %s" % (identity, emoji)) + print(" 模型: %s" % model) + print(" 工作目录: %s" % ws) + print(" 绑定数: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +14977,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw多智能体-查看路由绑定" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暂无路由绑定。"); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("暂无路由绑定。") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14938,14 +15028,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能体-会话概况" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("暂无 session 数据。"); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("暂无 session 数据。") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("会话汇总:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15063,32 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未发现已配置智能体。"); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ 未发现已配置智能体。") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("路由绑定数=%s" % len(bindings)); print("✅ 多智能体健康检查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("路由绑定数=%s" % len(bindings)) +print("✅ 多智能体健康检查完成") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "运行安全审计..." + openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" } openclaw_multiagent_menu() { From 3a25ae5d3998201b6e0c0e571befb338558f227b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 29 Mar 2026 14:23:18 +0800 Subject: [PATCH 1135/1285] =?UTF-8?q?feat:=20=E4=B8=89=E5=A4=A7=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=96=B0=E5=A2=9E=206=20=E4=B8=AA=E5=AE=9E=E7=94=A8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 记忆模块: - 新增 [5] 搜索测试: 输入关键词验证索引是否正常工作 - 新增 [6] 深度状态探测: 探测嵌入模型就绪状态 权限模块: - 新增 [6] Exec 命令白名单管理: 添加/移除放行的命令路径(glob) 多智能体模块: - 新增 [8] 修改智能体身份: 修改名称/Emoji,支持从 IDENTITY.md 读取 - 新增 [9] 清理过期会话: 清理冗余会话数据 --- cn/kejilion.sh | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ kejilion.sh | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3364f67a..bc6a00a27 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14195,6 +14195,22 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "输入搜索关键词: " query + if [ -z "$query" ]; then + echo "关键词不能为空。" + return 1 + fi + echo "正在搜索记忆..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "正在探测嵌入模型就绪状态..." + openclaw memory status --deep + } + openclaw_memory_menu() { send_stats "OpenClaw记忆管理" while true; do @@ -14207,6 +14223,8 @@ EOF echo "2. 查看记忆文件" echo "3. 索引修复(Indexed 异常)" echo "4. 记忆方案(QMD/Local/Auto)" + echo "5. 搜索测试(验证索引是否工作)" + echo "6. 深度状态探测(检查嵌入模型)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice @@ -14253,6 +14271,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14658,6 +14684,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo " Exec 命令白名单管理" + echo "=======================================" + echo "当前白名单:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print(" 智能体 [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print(" (空,未配置任何白名单规则)") +except Exception as e: + print(" (解析失败: " + str(e) + ")") +' "$allowlist_json" + else + echo " (无法获取)" + fi + echo "---------------------------------------" + echo "1. 添加白名单规则" + echo "2. 移除白名单规则" + echo "0. 返回" + echo "---------------------------------------" + read -e -p "请选择: " al_choice + case "$al_choice" in + 1) + read -e -p "输入要放行的命令路径 (支持 glob,如 /usr/bin/git): " pattern + [ -z "$pattern" ] && { echo "不能为空"; break_end; continue; } + read -e -p "指定智能体ID (留空=所有智能体 *): " agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "输入要移除的命令路径: " pattern + [ -z "$pattern" ] && { echo "不能为空"; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "无效选择"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw权限管理" while true; do @@ -14672,6 +14758,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高风险!彻底解除所有宿主机拦截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai} 恢复官方默认沙盒防御策略" echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" + echo -e "${gl_kjlan}6.${gl_bai} 管理 Exec 命令白名单" echo -e "${gl_kjlan}0.${gl_bai} 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice @@ -14703,6 +14790,9 @@ except Exception: 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -15091,6 +15181,34 @@ print("✅ 多智能体健康检查完成") openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" } + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "输入要修改身份的智能体ID: " agent_id + [ -z "$agent_id" ] && { echo "ID 不能为空"; return 1; } + echo "修改选项(留空跳过):" + read -e -p " 新名称: " new_name + read -e -p " 新 Emoji: " new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "也可以从 IDENTITY.md 自动读取身份信息。" + read -e -p "是否从 IDENTITY.md 读取?(y/n): " from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "即将清理过期/冗余会话数据..." + read -e -p "输入 yes 确认: " confirm + [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } + openclaw sessions cleanup + } + openclaw_multiagent_menu() { send_stats "OpenClaw多智能体管理" while true; do @@ -15107,6 +15225,8 @@ print("✅ 多智能体健康检查完成") echo "5. 移除路由绑定" echo "6. 查看会话概况" echo "7. 运行多智能体健康检查" + echo "8. 修改智能体身份(名称/Emoji)" + echo "9. 清理过期会话" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice @@ -15118,6 +15238,8 @@ print("✅ 多智能体健康检查完成") 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac diff --git a/kejilion.sh b/kejilion.sh index 2d0e81fed..de3203a65 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14195,6 +14195,22 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "输入搜索关键词: " query + if [ -z "$query" ]; then + echo "关键词不能为空。" + return 1 + fi + echo "正在搜索记忆..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "正在探测嵌入模型就绪状态..." + openclaw memory status --deep + } + openclaw_memory_menu() { send_stats "OpenClaw记忆管理" while true; do @@ -14207,6 +14223,8 @@ EOF echo "2. 查看记忆文件" echo "3. 索引修复(Indexed 异常)" echo "4. 记忆方案(QMD/Local/Auto)" + echo "5. 搜索测试(验证索引是否工作)" + echo "6. 深度状态探测(检查嵌入模型)" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " memory_choice @@ -14253,6 +14271,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14658,6 +14684,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo " Exec 命令白名单管理" + echo "=======================================" + echo "当前白名单:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print(" 智能体 [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print(" (空,未配置任何白名单规则)") +except Exception as e: + print(" (解析失败: " + str(e) + ")") +' "$allowlist_json" + else + echo " (无法获取)" + fi + echo "---------------------------------------" + echo "1. 添加白名单规则" + echo "2. 移除白名单规则" + echo "0. 返回" + echo "---------------------------------------" + read -e -p "请选择: " al_choice + case "$al_choice" in + 1) + read -e -p "输入要放行的命令路径 (支持 glob,如 /usr/bin/git): " pattern + [ -z "$pattern" ] && { echo "不能为空"; break_end; continue; } + read -e -p "指定智能体ID (留空=所有智能体 *): " agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "输入要移除的命令路径: " pattern + [ -z "$pattern" ] && { echo "不能为空"; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "无效选择"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw权限管理" while true; do @@ -14672,6 +14758,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高风险!彻底解除所有宿主机拦截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai} 恢复官方默认沙盒防御策略" echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" + echo -e "${gl_kjlan}6.${gl_bai} 管理 Exec 命令白名单" echo -e "${gl_kjlan}0.${gl_bai} 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " perm_choice @@ -14703,6 +14790,9 @@ except Exception: 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -15091,6 +15181,34 @@ print("✅ 多智能体健康检查完成") openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" } + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "输入要修改身份的智能体ID: " agent_id + [ -z "$agent_id" ] && { echo "ID 不能为空"; return 1; } + echo "修改选项(留空跳过):" + read -e -p " 新名称: " new_name + read -e -p " 新 Emoji: " new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "也可以从 IDENTITY.md 自动读取身份信息。" + read -e -p "是否从 IDENTITY.md 读取?(y/n): " from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "即将清理过期/冗余会话数据..." + read -e -p "输入 yes 确认: " confirm + [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } + openclaw sessions cleanup + } + openclaw_multiagent_menu() { send_stats "OpenClaw多智能体管理" while true; do @@ -15107,6 +15225,8 @@ print("✅ 多智能体健康检查完成") echo "5. 移除路由绑定" echo "6. 查看会话概况" echo "7. 运行多智能体健康检查" + echo "8. 修改智能体身份(名称/Emoji)" + echo "9. 清理过期会话" echo "0. 返回上一级" echo "---------------------------------------" read -e -p "请输入你的选择: " multi_choice @@ -15118,6 +15238,8 @@ print("✅ 多智能体健康检查完成") 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "无效的选择,请重试。"; sleep 1 ;; esac From ff436b7436cfc80f385c0d252e47008842a0a237 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 29 Mar 2026 21:16:25 +0800 Subject: [PATCH 1136/1285] =?UTF-8?q?refactor:=20=E5=8A=A0=E5=9B=BA?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进清单: - 版本检测: 用 -r 0-200 只下载前200字节取版本号,避免下载整个脚本 - 超时控制: 所有 curl 请求加 --max-time 防止挂住 - 下载校验: 下载到临时文件,校验非空+shebang行后再替换 - 备份回滚: 更新前备份 kejilion.sh.bak,失败自动恢复 - 失败提示: 网络错误/校验失败时给用户明确红色提示 - 手动更新: 补上 ln -sf /usr/local/bin/k /usr/bin/k - 自动更新cron彻底重写: - 加 cd ~ 确保下载到正确目录 - 临时文件+校验+备份流程 - 自动恢复 canshu/permission_granted/ENABLE_STATS 设置 - 部署到 /usr/local/bin/k 和 /usr/bin/k - 失败时清理临时文件 --- cn/kejilion.sh | 78 ++++++++++++++++++++++++++++++++++++++------------ kejilion.sh | 78 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 120 insertions(+), 36 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index bc6a00a27..6ddbbd392 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -21673,10 +21673,13 @@ while true; do echo "全部日志: ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # 只下载前5行获取版本号,避免下载整个脚本 + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}无法获取最新版本信息,请检查网络连接${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}你已经是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "脚本已经最新了,无需更新" else @@ -21702,37 +21705,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # 备份当前脚本 + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # 下载到临时文件,校验后再替换 + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" + else + rm -f "$tmp_file" + # 恢复备份 + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}更新失败!下载出错或文件校验不通过,已恢复原版本${gl_bai}" + send_stats "脚本更新失败" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" fi + + # 构建健壮的自动更新命令:下载到临时文件 → 校验 → 备份 → 替换 → 恢复本地设置 → 部署 + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # 追加设置恢复 + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" + fi + # 从旧脚本恢复 permission_granted 和 ENABLE_STATS 设置 + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # 部署到 /usr/local/bin/k 和 /usr/bin/k + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # 下载失败时清理临时文件 + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" send_stats "开启脚本自动更新" break_end diff --git a/kejilion.sh b/kejilion.sh index de3203a65..6ae803f67 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -21673,10 +21673,13 @@ while true; do echo "全部日志: ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # 只下载前5行获取版本号,避免下载整个脚本 + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}无法获取最新版本信息,请检查网络连接${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}你已经是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "脚本已经最新了,无需更新" else @@ -21702,37 +21705,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # 备份当前脚本 + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # 下载到临时文件,校验后再替换 + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "脚本已经最新$sh_v_new" + else + rm -f "$tmp_file" + # 恢复备份 + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}更新失败!下载出错或文件校验不通过,已恢复原版本${gl_bai}" + send_stats "脚本更新失败" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" fi + + # 构建健壮的自动更新命令:下载到临时文件 → 校验 → 备份 → 替换 → 恢复本地设置 → 部署 + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # 追加设置恢复 + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" + fi + # 从旧脚本恢复 permission_granted 和 ENABLE_STATS 设置 + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # 部署到 /usr/local/bin/k 和 /usr/bin/k + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # 下载失败时清理临时文件 + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" send_stats "开启脚本自动更新" break_end From 265b84bcac195ec0280d3bf728ac08e7505a0da5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 30 Mar 2026 10:28:34 +0800 Subject: [PATCH 1137/1285] =?UTF-8?q?fix:=20=E8=87=AA=E5=8A=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=8E=E8=AE=BE=E7=BD=AE=E4=B8=A2=E5=A4=B1=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E9=87=8D=E6=96=B0=E5=BC=B9=E8=AE=B8=E5=8F=AF=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: cron自动更新下载新脚本后,/usr/local/bin/k 和 ~/kejilion.sh 都变成 permission_granted="false", CheckFirstRun_true() 无法恢复 修复: canshu_v6/CheckFirstRun_true/yinsiyuanquan2 三个函数增加 从 ~/kejilion.sh.bak 回读设置的 fallback 逻辑, 当 /usr/local/bin/k 读不到旧状态时, 从备份文件恢复 permission_granted/canshu/ENABLE_STATS --- cn/kejilion.sh | 6 ++++++ kejilion.sh | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6ddbbd392..b813f605b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } diff --git a/kejilion.sh b/kejilion.sh index 6ae803f67..485b9c3a7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } From 1c0759ec0347767c71ed4c0214942bb76d006f82 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Tue, 31 Mar 2026 18:28:31 +0800 Subject: [PATCH 1138/1285] =?UTF-8?q?=E4=BC=98=E5=8C=96=20openclaw=20sessi?= =?UTF-8?q?on=20=E9=85=8D=E7=BD=AE=EF=BC=9A=E7=A7=BB=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=20resetTriggers=EF=BC=8CdmScope=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=20setdefault?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 3 +-- kejilion.sh | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b813f605b..057ad52c7 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10109,8 +10109,7 @@ with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] +session.setdefault('dmScope', 'per-channel-peer') session['reset'] = { 'mode': 'idle', 'idleMinutes': 10080 diff --git a/kejilion.sh b/kejilion.sh index 485b9c3a7..d04f81fd3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10109,8 +10109,7 @@ with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] +session.setdefault('dmScope', 'per-channel-peer') session['reset'] = { 'mode': 'idle', 'idleMinutes': 10080 From 84544984c2abfb665fb7e9551c2f24000d5ac772 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 3 Apr 2026 09:30:09 +0800 Subject: [PATCH 1139/1285] =?UTF-8?q?fix:=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E8=8F=9C=E5=8D=95=E5=BC=80=E5=8F=91=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=88=A4=E6=96=AD=E4=B8=8E=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. render_status 标准安全模式判断增加 elevated!=true 条件, 避免 elevated 读取异常时错误匹配标准安全模式 2. 菜单确认行改用 if/then/else/fi 替代 && || 组合, 修复运算符优先级导致 apply 函数返回非0时误报已取消 --- kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d04f81fd3..e88ec36b8 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -14535,7 +14535,7 @@ print(json.dumps(data, indent=2)) current_mode="\033[1;31m完全开放模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m开发增强模式\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then current_mode="\033[1;32m标准安全模式\033[0m" elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" @@ -14771,25 +14771,25 @@ except Exception as e: 1) echo "准备应用:标准安全模式" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "已取消"; fi break_end ;; 2) echo "准备应用:开发增强模式" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" read -e -p "输入 FULL 确认继续: " confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end ;; 4) echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "已取消"; fi break_end ;; 5) From e4f9f7b17ee83b00bc1df25fc7dcdc82e2fe67a0 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 3 Apr 2026 10:04:43 +0800 Subject: [PATCH 1140/1285] =?UTF-8?q?sync:=20=E8=A6=86=E7=9B=96=20cn/kejil?= =?UTF-8?q?ion.sh=20=E5=B9=B6=E8=AE=BE=E7=BD=AE=20canshu=3DCN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 057ad52c7..6351640fc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -14535,7 +14535,7 @@ print(json.dumps(data, indent=2)) current_mode="\033[1;31m完全开放模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m开发增强模式\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then current_mode="\033[1;32m标准安全模式\033[0m" elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" @@ -14771,25 +14771,25 @@ except Exception as e: 1) echo "准备应用:标准安全模式" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "已取消"; fi break_end ;; 2) echo "准备应用:开发增强模式" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" read -e -p "输入 FULL 确认继续: " confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end ;; 4) echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "输入 yes 确认: " confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "已取消"; fi break_end ;; 5) From 25016f5a18af68a09bd45f1a89ba70bafc976c6b Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 3 Apr 2026 10:37:04 +0800 Subject: [PATCH 1141/1285] =?UTF-8?q?refactor:=20install=5Fmoltbot=20?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=A2=84=E8=AE=BE=E6=9D=83=E9=99=90=EF=BC=8C?= =?UTF-8?q?=E4=BA=A4=E7=94=B1=E7=94=A8=E6=88=B7=E5=90=8E=E6=9C=9F=E8=87=AA?= =?UTF-8?q?=E8=A1=8C=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 2 -- kejilion.sh | 2 -- 2 files changed, 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6351640fc..03c0937d1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10498,8 +10498,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway diff --git a/kejilion.sh b/kejilion.sh index e88ec36b8..07142fd48 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10498,8 +10498,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart configure_openclaw_session_policy start_gateway From 144c35772260434b3af6ff08910f3a65aaad58b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:45:49 +0800 Subject: [PATCH 1142/1285] Remove configure_openclaw_session_policy function Removed the configure_openclaw_session_policy function and its invocation. --- cn/kejilion.sh | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 03c0937d1..b32043b4e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10096,37 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session.setdefault('dmScope', 'per-channel-peer') -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10498,8 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart - configure_openclaw_session_policy start_gateway add_app_id break_end From 5d194675c057c8d05eed3825f41a5354bf1e9344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:46:56 +0800 Subject: [PATCH 1143/1285] Remove configure_openclaw_session_policy function Removed the configure_openclaw_session_policy function and its invocation. --- kejilion.sh | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 07142fd48..1061b8bfc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10096,37 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session.setdefault('dmScope', 'per-channel-peer') -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10498,8 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - # 提示:修改配置后如需立即生效,可重启 gateway:openclaw gateway restart - configure_openclaw_session_policy start_gateway add_app_id break_end From d9713886e774159f28e48116cf5d1f52dadbe454 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 5 Apr 2026 05:34:14 +0000 Subject: [PATCH 1144/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-04-05=2005:34:14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 754 +++++++++++++++++++++++++++-------------- jp/kejilion.sh | 772 ++++++++++++++++++++++++++++-------------- kr/kejilion.sh | 772 ++++++++++++++++++++++++++++-------------- tw/kejilion.sh | 888 ++++++++++++++++++++++++++++++++----------------- 4 files changed, 2117 insertions(+), 1069 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index b30e11883..93e3e7fe5 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } @@ -2318,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2936,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3215,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3596,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4386,7 +4392,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4483,7 +4489,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -6594,9 +6600,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6638,7 +6644,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7207,7 +7213,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -8077,7 +8083,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -10090,38 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10339,7 +10313,7 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + summary.append(f'ℹ️ Skip {name}: None baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: @@ -10493,10 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true - # Tip: If you need to modify the configuration to take effect immediately, you can restart the gateway: openclaw gateway restart - configure_openclaw_session_policy start_gateway add_app_id break_end @@ -12149,7 +12119,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12277,7 +12247,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -13366,27 +13336,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "Failed to get status" - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /Underlying solution: /' -e 's/^Vector: /Vector library status: /' -e 's/^Indexed: /Included files: /' -e 's/^Workspace: /workspace: /' -e 's/^Store: /index library: /') - if [ -z "$status_lines" ]; then - echo "Not installed/not started" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "Failed to obtain memory status (openclaw memory status --json no output)" + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("Failed to get memory status (JSON parsing error)") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("No agent memory state detected.") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print("Underlying solution: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print("Included: %s files / %s blocks" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "yes" if dirty else "no" + print("To be refreshed: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "ready" if vec.get("available") else "Enabled (not available)" + else: + vec_str = "Not enabled" + print("Vector library: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print("Workspace: %s" % ws) + db = s.get("dbPath") or "-" + print("Index library: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -14113,7 +14116,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ The number of rows must be greater than 0." + echo "❌ Number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14162,6 +14165,22 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "Enter search keywords:" query + if [ -z "$query" ]; then + echo "Keywords cannot be empty." + return 1 + fi + echo "Searching memory..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "Detecting embedded model readiness status..." + openclaw memory status --deep + } + openclaw_memory_menu() { send_stats "OpenClaw memory management" while true; do @@ -14174,6 +14193,8 @@ EOF echo "2. View memory files" echo "3. Index repair (Indexed exception)" echo "4. Memory solution (QMD/Local/Auto)" + echo "5. Search testing (verify that the index is working)" + echo "6. Deep state detection (checking embedded models)" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" memory_choice @@ -14220,6 +14241,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14421,75 +14450,111 @@ PY mkdir -p "$HOME/.openclaw" - # Use Python security updates or create exec-approvals.json - python3 -c " + # Generate JSON and write via openclaw approvals set --stdin (preferred) + # If the CLI does not support it, it will fall back to writing the file directly. + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # Fallback: write file directly + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "Application layer configuration: ~/.openclaw/openclaw.json" echo "Host approval: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # Clean up null values + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="Unknown / Custom" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32mStandard safe mode\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31mFull open mode\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33mDevelop enhanced mode\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then + current_mode="\033[1;32mStandard safe mode\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36mThe official sandbox tells the truth\033[0m" fi echo -e "Current comprehensive security level:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[Application Layer Tool Policy Status]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (default): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec limit: /' || echo "Exec limit: (unset)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ Approval prompt: /' || echo "Approval prompt: (unset)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ Privilege escalation switch: /' || echo "Privilege escalation switch: (unset)" + echo "Profile (default): ${current_profile:-(unset)}" + echo "Exec limit: ${current_sec:-(unset)}" + echo "Approval prompt: ${current_ask:-(unset)}" + echo "Privilege elevation switch: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[Underlying Exec Approvals status]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print('Interception strategy (Security):' + str(d.get('security', '(unset)'))) - print('Prompt strategy (Ask):' + str(d.get('ask', '(unset)'))) - print('No UI cover (AskFallback):' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print("Interception strategy (Security):" + str(sec)) + print("Prompt strategy (Ask):" + str(ask)) + print("No UI cover (AskFallback):" + str(fb)) + print("AutoAllowSkills:" + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print("(The approval document does not exist, use the system’s built-in safety net)") +except Exception as e: + print("(Parse failed:" + str(e) + ")") +' "$approvals_json" + else + echo "(openclaw approvals get --json no output)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print("Interception strategy (Security):" + str(d.get("security", "(unset)"))) + print("Prompt strategy (Ask):" + str(d.get("ask", "(unset)"))) + print("No UI cover (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print('(Configuration file parsing failed)') -" + print("(Configuration file parsing failed)") +' else echo "(Not configured, forced to use the system's built-in security policy)" fi @@ -14563,7 +14628,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "Clean host interception configuration..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # Prioritize clearing the approval configuration through the CLI, and fall back to directly deleting the file. + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ Reverted to OpenClaw official security sandbox defense mechanism${gl_bai}" @@ -14584,6 +14654,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo "Exec command whitelist management" + echo "=======================================" + echo "Current whitelist:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print("Agent [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print("(Empty, no whitelist rules configured)") +except Exception as e: + print("(Parse failed:" + str(e) + ")") +' "$allowlist_json" + else + echo "(unable to obtain)" + fi + echo "---------------------------------------" + echo "1. Add whitelist rules" + echo "2. Remove whitelist rules" + echo "0. Return" + echo "---------------------------------------" + read -e -p "Please select:" al_choice + case "$al_choice" in + 1) + read -e -p "Enter the command path to be released (supports glob, such as /usr/bin/git):" pattern + [ -z "$pattern" ] && { echo "cannot be empty"; break_end; continue; } + read -e -p "Specify agent ID (leave blank = all agents *):" agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "Enter the command path to be removed:" pattern + [ -z "$pattern" ] && { echo "cannot be empty"; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "Invalid selection"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw permission management" while true; do @@ -14598,6 +14728,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai}Switch to fully open mode (${gl_hong}High risk! Completely remove all host interceptions${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}Restore the official default sandbox defense strategy" echo -e "${gl_kjlan}5.${gl_bai}Run underlying security audits and automatic repairs" + echo -e "${gl_kjlan}6.${gl_bai}Manage Exec command whitelist" echo -e "${gl_kjlan}0.${gl_bai}Return to previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" perm_choice @@ -14605,30 +14736,33 @@ except Exception: 1) echo "Prepare to apply: Standard safe mode" read -e -p "Enter yes to confirm:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "Canceled" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "Canceled"; fi break_end ;; 2) echo "Preparing the App: Developing Enhanced Mode" read -e -p "Enter yes to confirm:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "Canceled" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "Canceled"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ Fully open mode will completely collapse exec approval and automatically release high-risk code.${gl_bai}" read -e -p "Enter FULL to confirm to continue:" confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "Canceled" + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "Canceled"; fi break_end ;; 4) echo "All custom overrides will be cleared, restoring OpenClaw to its strictly sandboxed state when first installed." read -e -p "Enter yes to confirm:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "Canceled" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "Canceled"; fi break_end ;; 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -14705,6 +14839,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # Fallback: reading from configuration file local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14866,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # Fallback: reading from configuration file local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # Fallback: Reading from the file system + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14935,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14953,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "Configuration file: ${config_file:-$(openclaw_permission_config_file)}" echo "Default agent:$default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("Number of configured agents: %s" % len(agents)); print("Number of route bindings: %s" % len(bindings)); print("Total sessions: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("No multi-agent is currently configured.") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("Number of configured agents: %s" % len(agents)) +print("Number of route bindings: %s" % len(bindings)) +print("Total sessions: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("No multi-agent is currently configured.") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- Agent ID: [1;36m%s [0m" % item.get("id","?")); print("Identity name: %s %s" % (identity, emoji)); print("Working directory: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = "[default]" if is_default else "" + print("- Agent ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("Identity name: %s %s" % (identity, emoji)) + print("Model: %s" % model) + print("Working directory: %s" % ws) + print("Number of bindings: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +15037,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw multi-agent - view routing bindings" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("There is no route binding yet."); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("There is no route binding yet.") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14938,14 +15088,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw Multi-Agent - Session Overview" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("There is no session data yet."); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("There is no session data yet.") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("Session summary:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15123,60 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "Check the configuration file: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ Configuration verification failed, please check the output above." - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ No configured agent found."); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ No configured agent found.") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("Number of route bindings=%s" % len(bindings)); print("✅Multi-agent health check completed")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("Number of route bindings=%s" % len(bindings)) +print("✅Multi-agent health check completed") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "Run a security audit..." + openclaw security audit 2>/dev/null || echo "⚠️ Security audit command is not available" + } + + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "Enter the ID of the agent whose identity you want to modify:" agent_id + [ -z "$agent_id" ] && { echo "ID cannot be empty"; return 1; } + echo "Modify options (leave blank to skip):" + read -e -p "New name:" new_name + read -e -p "New Emoji:" new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "Identity information can also be read automatically from IDENTITY.md." + read -e -p "Read from IDENTITY.md? (y/n):" from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "Cleaning up expired/redundant session data soon..." + read -e -p "Enter yes to confirm:" confirm + [ "$confirm" != "yes" ] && { echo "Canceled"; return 0; } + openclaw sessions cleanup } openclaw_multiagent_menu() { @@ -14979,6 +15195,8 @@ print("Number of route bindings=%s" % len(bindings)); print("✅Multi-agent heal echo "5. Remove route binding" echo "6. View session overview" echo "7. Run multi-agent health checks" + echo "8. Modify the agent’s identity (name/Emoji)" + echo "9. Clean up expired sessions" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" multi_choice @@ -14990,6 +15208,8 @@ print("Number of route bindings=%s" % len(bindings)); print("✅Multi-agent heal 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "Invalid selection, please try again."; sleep 1 ;; esac @@ -15293,7 +15513,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15663,7 +15883,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -15767,7 +15987,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -15821,7 +16041,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -15919,7 +16139,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16805,7 +17025,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17032,7 +17252,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17084,7 +17304,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17125,7 +17345,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17188,7 +17408,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17402,7 +17622,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -17516,7 +17736,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17737,7 +17957,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17787,7 +18007,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17923,7 +18143,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18150,7 +18370,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18288,7 +18508,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18342,7 +18562,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18575,7 +18795,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18646,7 +18866,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18715,7 +18935,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18856,7 +19076,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18926,7 +19146,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19049,7 +19269,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "File transferred to remote server/root directory." + echo "文件已传送至远程服务器/根目录。" else echo "The file to be transferred was not found." fi @@ -19130,7 +19350,7 @@ linux_work() { echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." - echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" + echo -e "${gl_huang}hint:${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" echo -e "${gl_kjlan}------------------------" @@ -19140,7 +19360,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -20296,7 +20516,7 @@ EOF echo "------------------------" echo "Europe" echo "11. London, UK time 12. Paris, France time" - echo "13. Berlin, Germany time 14. Moscow, Russia time" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" echo "15. Utracht Time, Netherlands 16. Madrid Time, Spain" echo "------------------------" echo "America" @@ -21178,7 +21398,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21423,10 +21643,13 @@ while true; do echo "All logs:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # Only download the first 5 lines to get the version number to avoid downloading the entire script + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}Unable to obtain the latest version information, please check the network connection${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}You are already on the latest version!${gl_huang}v$sh_v${gl_bai}" send_stats "The script is already up to date and does not need to be updated" else @@ -21452,37 +21675,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # Back up current script + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # Download to temporary file, verify and then replace + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "The script is up to date$sh_v_new" + else + rm -f "$tmp_file" + # Restore backup + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}Update failed! There was an error in downloading or the file verification failed. The original version has been restored.${gl_bai}" + send_stats "Script update failed" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}The script has been updated to the latest version!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "The script is up to date$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" + fi + + # Build a robust auto-update command: Download to temporary file → Verify → Backup → Replace → Restore local settings → Deploy + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # Additional settings recovery + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi + # Restore permission_granted and ENABLE_STATS settings from old script + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # Deploy to /usr/local/bin/k and /usr/bin/k + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # Clean temporary files when download fails + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" send_stats "Enable automatic script updates" break_end diff --git a/jp/kejilion.sh b/jp/kejilion.sh index b31f86a9d..a11669c59 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -61,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } @@ -861,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -1189,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1744,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2231,7 +2237,7 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -2318,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2614,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2631,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2887,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3010,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3215,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -4773,7 +4779,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5802,7 +5808,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6296,7 +6302,7 @@ Kernel_optimize() { echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6594,9 +6600,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6638,7 +6644,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7095,7 +7101,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7207,7 +7213,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -8312,7 +8318,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -9181,7 +9187,7 @@ linux_ldnmp() { echo "バックエンドのログイン パス: /admin" echo "------------------------" echo "ユーザー名: 管理者" - echo "密码: admin" + echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" @@ -10090,38 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10277,7 +10251,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10356,7 +10330,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10493,10 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true - # ヒント: 構成を変更してすぐに有効にする必要がある場合は、ゲートウェイを再起動します: openclaw ゲートウェイの再起動 - configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10764,7 +10734,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11154,7 +11124,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行が完了しました" + echo "✅ 同期実行完了" start_gateway ;; 2) @@ -12238,7 +12208,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." start_gateway fi break_end @@ -12247,7 +12217,7 @@ PYTHON_EOF install_skill() { - send_stats "スキルマネジメント" + send_stats "スキル管理" while true; do clear echo "========================================" @@ -12268,8 +12238,8 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンを制御する" + echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12356,7 +12326,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." start_gateway fi break_end @@ -13366,27 +13336,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "ステータスの取得に失敗しました" - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^プロバイダ: /基礎となるソリューション: /' -e 's/^Vector: /Vector ライブラリのステータス: /' -e 's/^インデックス付き: /含まれるファイル: /' -e 's/^ワークスペース: /ワークスペース: /' -e 's/^ストア: /index ライブラリ: /') - if [ -z "$status_lines" ]; then - echo "インストールされていない/起動されていない" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "メモリステータスの取得に失敗しました (openclaw メモリステータス --json 出力なし)" + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("メモリステータスの取得に失敗しました(JSON解析エラー)") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("エージェントのメモリ状態が検出されませんでした。") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print("基本的なソリューション: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "はい" if dirty else "いいえ" + print("更新対象: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "準備ができて" if vec.get("available") else "有効 (利用不可)" + else: + vec_str = "有効になっていません" + print("ベクター ライブラリ: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print("ワークスペース: %s" % ws) + db = s.get("dbPath") or "-" + print("インデックス ライブラリ: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -13932,7 +13935,7 @@ EOF } openclaw_memory_offer_restart() { - echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14096,7 +14099,7 @@ EOF echo "書類:$file" echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14162,6 +14165,22 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "検索キーワードを入力してください:" query + if [ -z "$query" ]; then + echo "キーワードを空にすることはできません。" + return 1 + fi + echo "記憶を検索中..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "埋め込みモデルの準備ステータスを検出しています..." + openclaw memory status --deep + } + openclaw_memory_menu() { send_stats "OpenClaw のメモリ管理" while true; do @@ -14174,6 +14193,8 @@ EOF echo "2. メモリファイルを表示する" echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" + echo "5. 検索テスト (インデックスが機能していることを確認します)" + echo "6. ディープステート検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14220,6 +14241,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14421,75 +14450,111 @@ PY mkdir -p "$HOME/.openclaw" - # Python セキュリティ更新プログラムを使用するか、exec-approvals.json を作成します。 - python3 -c " + # JSON を生成し、openclaw 承認セット --stdin 経由で書き込みます (推奨) + # CLI がこれをサポートしていない場合は、ファイルの直接書き込みに戻ります。 + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # フォールバック: ファイルを直接書き込む + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "アプリケーション層の構成: ~/.openclaw/openclaw.json" echo "ホストの承認: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # Null値をクリーンアップする + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="不明 / カスタム" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32m標準セーフモード\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m全開モード\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m開発拡張モード\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then + current_mode="\033[1;32m標準セーフモード\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m公式サンドボックスが真実を語る\033[0m" fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ プロファイル (デフォルト): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ 実行制限: /' || echo "実行制限: (未設定)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 承認プロンプト: /' || echo "承認プロンプト: (未設定)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 権限昇格スイッチ: /' || echo "権限昇格スイッチ: (未設定)" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" + echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" + echo "実行制限: ${current_sec:-(未設定)}" + echo "承認プロンプト: ${current_ask:-(unset)}" + echo "特権昇格スイッチ: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[基本的な幹部の承認ステータス]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print('傍受戦略 (セキュリティ):' + str(d.get('security', '(unset)'))) - print('即時戦略 (質問):' + str(d.get('ask', '(unset)'))) - print('UI カバーなし (AskFallback):' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print("傍受戦略 (セキュリティ):" + str(sec)) + print("即時戦略 (質問):" + str(ask)) + print("UI カバーなし (AskFallback):" + str(fb)) + print("自動許可スキル:" + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print("(承認文書は存在しません。システムに組み込まれたセーフティネットを使用してください)") +except Exception as e: + print("(解析に失敗しました:" + str(e) + ")") +' "$approvals_json" + else + echo "(openclaw の承認では --json が出力されません)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print("傍受戦略 (セキュリティ):" + str(d.get("security", "(unset)"))) + print("即時戦略 (質問):" + str(d.get("ask", "(unset)"))) + print("UI カバーなし (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print('(設定ファイルの解析に失敗しました)') -" + print("(設定ファイルの解析に失敗しました)") +' else echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi @@ -14511,7 +14576,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14548,7 +14613,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14563,7 +14628,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "クリーンなホストインターセプト構成..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # CLI を介して承認設定をクリアすることを優先し、ファイルの直接削除に戻ります。 + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ OpenClaw 公式セキュリティ サンドボックス防御メカニズムに戻しました${gl_bai}" @@ -14584,6 +14654,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo "実行コマンドのホワイトリスト管理" + echo "=======================================" + echo "現在のホワイトリスト:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print("エージェント [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print("(空、ホワイトリスト ルールが設定されていません)") +except Exception as e: + print("(解析に失敗しました:" + str(e) + ")") +' "$allowlist_json" + else + echo "(入手不可)" + fi + echo "---------------------------------------" + echo "1. ホワイトリストルールを追加する" + echo "2. ホワイトリスト ルールを削除する" + echo "0.戻る" + echo "---------------------------------------" + read -e -p "選択してください:" al_choice + case "$al_choice" in + 1) + read -e -p "解放するコマンド パスを入力します (/usr/bin/git などの glob をサポートします)。" pattern + [ -z "$pattern" ] && { echo "空にすることはできません"; break_end; continue; } + read -e -p "エージェント ID を指定します (空白のまま = すべてのエージェント *):" agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "削除するコマンド パスを入力します。" pattern + [ -z "$pattern" ] && { echo "空にすることはできません"; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "無効な選択"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw権限管理" while true; do @@ -14598,6 +14728,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}ハイリスク!すべてのホストインターセプトを完全に削除します${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}公式のデフォルトのサンドボックス防御戦略を復元する" echo -e "${gl_kjlan}5.${gl_bai}基盤となるセキュリティ監査と自動修復を実行する" + echo -e "${gl_kjlan}6.${gl_bai}Execコマンドのホワイトリストを管理する" echo -e "${gl_kjlan}0.${gl_bai}前のレベルに戻る" echo "---------------------------------------" read -e -p "選択肢を入力してください:" perm_choice @@ -14605,30 +14736,33 @@ except Exception: 1) echo "適用の準備: 標準セーフ モード" read -e -p "確認するには「yes」と入力します。" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "キャンセル" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "キャンセル"; fi break_end ;; 2) echo "アプリの準備: 拡張モードの開発" read -e -p "確認するには「yes」と入力します。" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "キャンセル" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "キャンセル"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ フルオープンモードでは、実行承認が完全に崩壊し、高リスクコードが自動的にリリースされます。${gl_bai}" read -e -p "続行することを確認するには「FULL」と入力します。" confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "キャンセル" + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "キャンセル"; fi break_end ;; 4) echo "すべてのカスタム オーバーライドがクリアされ、OpenClaw が最初にインストールされたときの厳密にサンドボックス化された状態に戻ります。" read -e -p "確認するには「yes」と入力します。" confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "キャンセル" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "キャンセル"; fi break_end ;; 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -14705,6 +14839,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # フォールバック: 構成ファイルからの読み取り local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14866,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # フォールバック: 構成ファイルからの読み取り local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # フォールバック: ファイル システムからの読み取り + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14935,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14953,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "設定ファイル: ${config_file:-$(openclaw_permission_config_file)}" echo "デフォルトのエージェント:$default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("構成されたエージェントの数: %s" % len(agents)); print("ルート バインディングの数: %s" % len(bindings)); print("合計セッション数: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("現在、マルチエージェントは構成されていません。") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("構成されたエージェントの数: %s" % len(agents)) +print("ルート バインディングの数: %s" % len(bindings)) +print("合計セッション数: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("現在、マルチエージェントは構成されていません。") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- エージェント ID: [1;36m%s [0m" % item.get("id","?")); print("アイデンティティ名: %s %s" % (identity, emoji)); print("作業ディレクトリ: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = "[デフォルト]" if is_default else "" + print("- エージェント ID: \033[1;36m%s\033[0m%s]" % (aid, default_tag)) + print("アイデンティティ名: %s %s" % (identity, emoji)) + print("モデル: %s" % model) + print("作業ディレクトリ: %s" % ws) + print("バインディングの数: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +15037,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw マルチエージェント - ルーティング バインディングの表示" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("まだルート バインディングはありません。"); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("まだルート バインディングはありません。") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14938,14 +15088,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw マルチエージェント - セッションの概要" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("まだセッション データがありません。"); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("まだセッション データがありません。") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("セッションの概要:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15123,60 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "設定ファイルを確認します: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 構成の検証に失敗しました。上記の出力を確認してください。" - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 設定されたエージェントが見つかりません。"); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ 設定されたエージェントが見つかりません。") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("ルート バインディングの数 = %s" % len(bindings)); print("✅マルチエージェントのヘルスチェックが完了しました")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("ルート バインディングの数 = %s" % len(bindings)) +print("✅マルチエージェントのヘルスチェックが完了しました") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "セキュリティ監査を実行します..." + openclaw security audit 2>/dev/null || echo "⚠️ セキュリティ監査コマンドは使用できません" + } + + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "ID を変更するエージェントの ID を入力します。" agent_id + [ -z "$agent_id" ] && { echo "ID を空にすることはできません"; return 1; } + echo "オプションを変更します (スキップするには空白のままにします):" + read -e -p "新しい名前:" new_name + read -e -p "新しい絵文字:" new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "IDENTITY.md から ID 情報を自動的に読み取ることもできます。" + read -e -p "IDENTITY.md から読み取りますか? (y/n):" from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "期限切れ/冗長セッション データを間もなくクリーンアップします..." + read -e -p "確認するには「yes」と入力します。" confirm + [ "$confirm" != "yes" ] && { echo "キャンセル"; return 0; } + openclaw sessions cleanup } openclaw_multiagent_menu() { @@ -14979,6 +15195,8 @@ print("ルート バインディングの数 = %s" % len(bindings)); print("✅ echo "5.ルートバインディングを削除する" echo "6. セッションの概要を表示する" echo "7. マルチエージェントのヘルスチェックを実行する" + echo "8. エージェントのアイデンティティ (名前/絵文字) を変更します" + echo "9. 期限切れのセッションをクリーンアップする" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" multi_choice @@ -14990,6 +15208,8 @@ print("ルート バインディングの数 = %s" % len(bindings)); print("✅ 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "選択が無効です。もう一度お試しください。"; sleep 1 ;; esac @@ -15223,7 +15443,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期構成ウィザード" + 11) send_stats "初期設定ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15293,7 +15513,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15583,7 +15803,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "ネザ監視$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -16528,7 +16748,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -17160,7 +17380,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17677,7 +17897,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18016,7 +18236,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -18951,7 +19171,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19130,7 +19350,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19140,7 +19360,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19696,7 +19916,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集します" + echo "4. ~/.bashrc を編集する" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -21178,7 +21398,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21207,7 +21427,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21252,7 +21472,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -21423,10 +21643,13 @@ while true; do echo "すべてのログ:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # スクリプト全体をダウンロードしないように、最初の 5 行のみをダウンロードしてバージョン番号を取得します。 + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}最新バージョン情報を取得できません。ネットワーク接続を確認してください。${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}すでに最新バージョンを使用しています。${gl_huang}v$sh_v${gl_bai}" send_stats "スクリプトはすでに最新であるため、更新する必要はありません" else @@ -21452,37 +21675,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # 現在のスクリプトをバックアップする + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # 一時ファイルにダウンロードし、確認してから置き換えます + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}スクリプトが最新バージョンに更新されました。${gl_huang}v$sh_v_new${gl_bai}" + send_stats "スクリプトは最新です$sh_v_new" + else + rm -f "$tmp_file" + # バックアップを復元する + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}アップデートに失敗しました!ダウンロード中にエラーが発生したか、ファイルの検証に失敗しました。オリジナルのバージョンが復元されました。${gl_bai}" + send_stats "スクリプトの更新に失敗しました" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}スクリプトが最新バージョンに更新されました。${gl_huang}v$sh_v_new${gl_bai}" - send_stats "スクリプトは最新です$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" + fi + + # 堅牢な自動更新コマンドを作成します: 一時ファイルにダウンロード → 検証 → バックアップ → 置換 → ローカル設定の復元 → 導入 + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # 追加設定の回復 + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi + # 古いスクリプトからpermission_grantedおよびENABLE_STATS設定を復元します + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # /usr/local/bin/k および /usr/bin/k にデプロイします + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # ダウンロードが失敗した場合に一時ファイルを消去する + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}自動更新がオンになっており、スクリプトは毎日午前 2 時に自動的に更新されます。${gl_bai}" send_stats "スクリプトの自動更新を有効にする" break_end @@ -21574,7 +21836,7 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" @@ -21808,7 +22070,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index e9ab02b61..2615ac69a 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } @@ -1093,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1200,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1262,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1846,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -2318,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -2783,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2799,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3215,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3414,10 +3420,10 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3427,7 +3433,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3503,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3767,7 +3773,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4100,7 +4106,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4162,7 +4168,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4409,7 +4415,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4773,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5631,7 +5637,7 @@ bbrv3() { apt update -y apt install -y linux-xanmod-x64v$version - echo "XanMod 커널이 업데이트되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* @@ -5641,7 +5647,7 @@ bbrv3() { 2) apt purge -y 'linux-*xanmod1*' update-grub - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot ;; @@ -5695,7 +5701,7 @@ bbrv3() { bbr_on - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f check_x86-64_psabi.sh* server_reboot @@ -5784,7 +5790,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5802,7 +5808,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6538,7 +6544,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7207,7 +7213,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8271,7 +8277,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8471,7 +8477,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -10090,38 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10493,10 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true - # 팁: 즉시 적용되도록 구성을 수정해야 하는 경우 게이트웨이를 다시 시작할 수 있습니다. openclaw Gateway restart - configure_openclaw_session_policy start_gateway add_app_id break_end @@ -12042,7 +12012,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -12149,7 +12119,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12190,7 +12160,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12277,7 +12247,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -13079,7 +13049,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw 백업 파일 삭제" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13366,27 +13336,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "상태를 가져오지 못했습니다." - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^공급자: /기본 솔루션: /' -e 's/^벡터: /벡터 라이브러리 상태: /' -e 's/^색인: /포함된 파일: /' -e 's/^작업 공간: /작업 공간: /' -e 's/^저장소: /색인 라이브러리: /') - if [ -z "$status_lines" ]; then - echo "설치되지 않음/시작되지 않음" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "메모리 상태를 가져오지 못했습니다(openclaw 메모리 상태 --json 출력 없음)." + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("메모리 상태를 가져오지 못했습니다(JSON 구문 분석 오류).") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("에이전트 메모리 상태가 감지되지 않았습니다.") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print("기본 솔루션: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print("포함됨: %s개 파일 / %s개 블록" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "예" if dirty else "아니요" + print("새로 고칠 예정: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "준비가 된" if vec.get("available") else "활성화됨(사용할 수 없음)" + else: + vec_str = "활성화되지 않음" + print("벡터 라이브러리: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print("작업공간: %s" % ws) + db = s.get("dbPath") or "-" + print("인덱스 라이브러리: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -13461,7 +13464,7 @@ EOF OPENCLAW_MEMORY_RECOMMEND_REASON=() if [ "$qmd_ok" = "true" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") else OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") fi @@ -13587,7 +13590,7 @@ EOF elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13732,7 +13735,7 @@ EOF openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다." + echo "✅ memory.qmd.command가 정확합니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -13978,7 +13981,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14162,6 +14165,22 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "검색 키워드를 입력하세요:" query + if [ -z "$query" ]; then + echo "키워드는 비워둘 수 없습니다." + return 1 + fi + echo "기억을 찾는 중..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "내장된 모델 준비 상태 감지 중..." + openclaw memory status --deep + } + openclaw_memory_menu() { send_stats "OpenClaw 메모리 관리" while true; do @@ -14174,6 +14193,8 @@ EOF echo "2. 메모리 파일 보기" echo "3. 인덱스 복구(인덱스 예외)" echo "4. 메모리 솔루션(QMD/Local/Auto)" + echo "5. 검색 테스트(색인이 작동하는지 확인)" + echo "6. 심층 상태 감지(임베디드 모델 확인)" echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" memory_choice @@ -14190,7 +14211,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14220,6 +14241,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14421,75 +14450,111 @@ PY mkdir -p "$HOME/.openclaw" - # Python 보안 업데이트를 사용하거나 exec-approvals.json을 생성하세요. - python3 -c " + # JSON을 생성하고 openclaw 승인 세트 --stdin을 통해 작성(선호) + # CLI가 이를 지원하지 않으면 파일을 직접 작성하는 것으로 대체됩니다. + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # 대체: 파일 직접 쓰기 + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "애플리케이션 계층 구성: ~/.openclaw/openclaw.json" echo "호스트 승인: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # Null 값 정리 + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="알 수 없음/커스텀" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32m표준 안전 모드\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m완전 개방 모드\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m향상된 모드 개발\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then + current_mode="\033[1;32m표준 안전 모드\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m공식 샌드박스가 진실을 말해줍니다\033[0m" fi echo -e "현재 포괄적인 보안 수준:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[애플리케이션 레이어 도구 정책 현황]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ 프로필(기본값): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ 실행 제한: /' || echo "실행 한도: (설정되지 않음)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 승인 메시지: /' || echo "승인 메시지: (설정되지 않음)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 권한 상승 스위치: /' || echo "권한 에스컬레이션 스위치: (설정되지 않음)" + echo "프로필(기본값): ${current_profile:-(unset)}" + echo "실행 제한: ${current_sec:-(unset)}" + echo "승인 프롬프트: ${current_ask:-(unset)}" + echo "권한 상승 스위치: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[기본 Exec 승인 상태]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print('차단 전략(보안):' + str(d.get('security', '(unset)'))) - print('신속한 전략(질문):' + str(d.get('ask', '(unset)'))) - print('UI 커버 없음(AskFallback):' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print("차단 전략(보안):" + str(sec)) + print("신속한 전략(질문):" + str(ask)) + print("UI 커버 없음(AskFallback):" + str(fb)) + print("AutoAllowSkills:" + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print("(승인문서가 존재하지 않으므로 시스템에 내장된 안전망을 이용하세요)") +except Exception as e: + print("(구문 분석 실패:" + str(e) + ")") +' "$approvals_json" + else + echo "(openclaw 승인은 --json 출력 없음)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print("차단 전략(보안):" + str(d.get("security", "(unset)"))) + print("신속한 전략(질문):" + str(d.get("ask", "(unset)"))) + print("UI 커버 없음(AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print('(구성 파일 구문 분석 실패)') -" + print("(구성 파일 구문 분석 실패)") +' else echo "(구성되지 않음, 시스템에 내장된 보안 정책을 강제로 사용함)" fi @@ -14499,7 +14564,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14518,7 +14583,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14536,7 +14601,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14563,7 +14628,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "호스트 차단 구성을 정리합니다..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # CLI를 통해 승인 구성을 지우는 데 우선순위를 두고 파일을 직접 삭제하는 방법으로 대체합니다. + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ OpenClaw 공식 보안 샌드박스 방어 메커니즘으로 복귀${gl_bai}" @@ -14584,6 +14654,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo "실행 명령 화이트리스트 관리" + echo "=======================================" + echo "현재 허용 목록:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print("에이전트 [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print("(비어 있음, 화이트리스트 규칙이 구성되지 않음)") +except Exception as e: + print("(구문 분석 실패:" + str(e) + ")") +' "$allowlist_json" + else + echo "(얻을 수 없음)" + fi + echo "---------------------------------------" + echo "1. 화이트리스트 규칙 추가" + echo "2. 화이트리스트 규칙 제거" + echo "0. 반품" + echo "---------------------------------------" + read -e -p "선택하세요:" al_choice + case "$al_choice" in + 1) + read -e -p "해제할 명령 경로를 입력하십시오(/usr/bin/git와 같은 glob 지원)." pattern + [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } + read -e -p "에이전트 ID 지정(비워 두기 = 모든 에이전트 *):" agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "제거할 명령 경로를 입력하십시오:" pattern + [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "잘못된 선택"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw 권한 관리" while true; do @@ -14598,6 +14728,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai}완전 개방 모드로 전환(${gl_hong}위험! 모든 호스트 차단을 완전히 제거합니다.${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}공식 기본 샌드박스 방어 전략 복원" echo -e "${gl_kjlan}5.${gl_bai}기본 보안 감사 및 자동 복구 실행" + echo -e "${gl_kjlan}6.${gl_bai}Exec 명령 화이트리스트 관리" echo -e "${gl_kjlan}0.${gl_bai}이전 레벨로 돌아가기" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" perm_choice @@ -14605,30 +14736,33 @@ except Exception: 1) echo "적용 준비: 표준 안전 모드" read -e -p "확인하려면 yes를 입력하세요." confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "취소" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "취소"; fi break_end ;; 2) echo "앱 준비: 고급 모드 개발" read -e -p "확인하려면 yes를 입력하세요." confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "취소" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "취소"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 완전 개방 모드는 실행 승인을 완전히 무너뜨리고 고위험 코드를 자동으로 공개합니다.${gl_bai}" read -e -p "계속하려면 FULL을 입력하여 확인하세요." confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "취소" + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "취소"; fi break_end ;; 4) echo "모든 사용자 정의 재정의가 지워지고 OpenClaw를 처음 설치할 때 엄격한 샌드박스 상태로 복원됩니다." read -e -p "확인하려면 yes를 입력하세요." confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "취소" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "취소"; fi break_end ;; 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -14705,6 +14839,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 대체: 구성 파일에서 읽기 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14866,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 대체: 구성 파일에서 읽기 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 대체: 파일 시스템에서 읽기 + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14935,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14953,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "구성 파일: ${config_file:-$(openclaw_permission_config_file)}" echo "기본 에이전트:$default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("구성된 에이전트 수: %s" % len(agents)); print("경로 바인딩 수: %s" % len(bindings)); print("총 세션: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("현재 다중 에이전트가 구성되어 있지 않습니다.") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("구성된 에이전트 수: %s" % len(agents)) +print("경로 바인딩 수: %s" % len(bindings)) +print("총 세션: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("현재 다중 에이전트가 구성되어 있지 않습니다.") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 에이전트 ID: [1;36m%s [0m" % item.get("id","?")); print("ID 이름: %s %s" % (identity, emoji)); print("작업 디렉터리: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = "[기본]" if is_default else "" + print("- 에이전트 ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("ID 이름: %s %s" % (identity, emoji)) + print("모델: %s" % model) + print("작업 디렉터리: %s" % ws) + print("바인딩 수: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +15037,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 보기" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("아직 경로 바인딩이 없습니다."); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("아직 경로 바인딩이 없습니다.") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14938,14 +15088,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw 다중 에이전트 - 세션 개요" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("아직 세션 데이터가 없습니다."); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("아직 세션 데이터가 없습니다.") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("세션 요약:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15123,60 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "구성 파일을 확인하세요: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 구성 확인에 실패했습니다. 위의 출력을 확인하세요." - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 구성된 에이전트를 찾을 수 없습니다."); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ 구성된 에이전트를 찾을 수 없습니다.") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("경로 바인딩 수=%s" % len(bindings)); print("✅멀티에이전트 헬스체크 완료")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("경로 바인딩 수=%s" % len(bindings)) +print("✅멀티에이전트 헬스체크 완료") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "보안 감사를 실행하세요..." + openclaw security audit 2>/dev/null || echo "⚠️ 보안 감사 명령을 사용할 수 없습니다." + } + + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "ID를 수정하려는 상담원의 ID를 입력하세요." agent_id + [ -z "$agent_id" ] && { echo "ID는 비워둘 수 없습니다."; return 1; } + echo "옵션 수정(건너뛰려면 비워 두세요):" + read -e -p "새 이름:" new_name + read -e -p "새로운 이모티콘:" new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "IDENTITY.md에서 신원 정보를 자동으로 읽을 수도 있습니다." + read -e -p "IDENTITY.md에서 읽으시겠습니까? (예/아니요):" from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "만료되거나 중복된 세션 데이터를 곧 정리합니다..." + read -e -p "확인하려면 yes를 입력하세요." confirm + [ "$confirm" != "yes" ] && { echo "취소"; return 0; } + openclaw sessions cleanup } openclaw_multiagent_menu() { @@ -14979,6 +15195,8 @@ print("경로 바인딩 수=%s" % len(bindings)); print("✅멀티에이전트 echo "5. 경로 바인딩 제거" echo "6. 세션 개요 보기" echo "7. 다중 에이전트 상태 확인 실행" + echo "8. 상담원 신원(이름/이모지) 수정" + echo "9. 만료된 세션 정리" echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" multi_choice @@ -14990,6 +15208,8 @@ print("경로 바인딩 수=%s" % len(bindings)); print("✅멀티에이전트 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "선택이 잘못되었습니다. 다시 시도해 주세요."; sleep 1 ;; esac @@ -15293,7 +15513,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15305,7 +15525,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15353,7 +15573,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15663,7 +15883,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17096,7 +17316,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -19140,7 +19360,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19587,7 +19807,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한합니다." + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19693,7 +19913,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -19812,10 +20032,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20297,7 +20517,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -21170,7 +21390,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 순회하고 명령을 실행합니다. + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -21178,7 +21398,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21423,10 +21643,13 @@ while true; do echo "모든 로그:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # 전체 스크립트를 다운로드하지 않으려면 처음 5줄만 다운로드하여 버전 번호를 확인하세요. + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}최신 버전 정보를 얻을 수 없습니다. 네트워크 연결을 확인하십시오.${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}이미 최신 버전을 사용하고 있습니다!${gl_huang}v$sh_v${gl_bai}" send_stats "스크립트가 이미 최신 상태이므로 업데이트할 필요가 없습니다." else @@ -21452,37 +21675,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # 현재 스크립트 백업 + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # 임시 파일로 다운로드 후 확인 후 교체 + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}스크립트가 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "스크립트가 최신 상태입니다.$sh_v_new" + else + rm -f "$tmp_file" + # 백업 복원 + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}업데이트 실패! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" + send_stats "스크립트 업데이트 실패" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}스크립트가 최신 버전으로 업데이트되었습니다!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "스크립트가 최신 상태입니다.$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" + fi + + # 강력한 자동 업데이트 명령 구축: 임시 파일로 다운로드 → 확인 → 백업 → 교체 → 로컬 설정 복원 → 배포 + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # 추가 설정 복구 + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi + # 이전 스크립트에서Permission_granted 및 ENABLE_STATS 설정을 복원합니다. + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # /usr/local/bin/k 및 /usr/bin/k에 배포 + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # 다운로드 실패 시 임시 파일 정리 + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}자동 업데이트가 켜져 있고 매일 새벽 2시에 스크립트가 자동으로 업데이트됩니다!${gl_bai}" send_stats "자동 스크립트 업데이트 활성화" break_end diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 5af72ae36..d196239ed 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -47,6 +47,8 @@ run_command() { canshu_v6() { if grep -q '^canshu="V6"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh + elif grep -q '^canshu="V6"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^canshu="default"/canshu="V6"/' ~/kejilion.sh fi } @@ -54,6 +56,8 @@ canshu_v6() { CheckFirstRun_true() { if grep -q '^permission_granted="true"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh + elif grep -q '^permission_granted="true"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh fi } @@ -88,6 +92,8 @@ yinsiyuanquan2() { if grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh +elif grep -q '^ENABLE_STATS="false"' ~/kejilion.sh.bak > /dev/null 2>&1; then + sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh fi } @@ -1221,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1492,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "網站資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1555,9 +1561,9 @@ certs_status() { ;; 2) - send_stats "導入已有證書" + send_stats "导入已有证书" - # 定義檔案路徑 + # 定义文件路径 local cert_file="/home/web/certs/${yuming}_cert.pem" local key_file="/home/web/certs/${yuming}_key.pem" @@ -2783,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 清除封鎖所有其他 IP 存取的規則 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -3268,7 +3274,7 @@ EOF fail2ban-client status $jail_name || true } -# 直接開啟主配置/覆蓋配置編輯(nano) +# 直接打开主配置/覆盖配置编辑(nano) # 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 f2b_edit_config() { root_use @@ -3694,11 +3700,11 @@ stream_panel() { ;; 5) send_stats "編輯轉送配置" - read -e -p "请输入你要编辑的服务名: " stream_name + read -e -p "請輸入你要編輯的服務名稱:" stream_name install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四层代理" + send_stats "修改四層代理" ;; 6) send_stats "刪除轉送配置" @@ -3724,8 +3730,8 @@ ldnmp_Proxy_backend_stream() { send_stats "安裝$webname" echo "開始部署$webname" - # 获取代理名称 - read -erp "请输入代理转发名称 (如 mysql_proxy): " proxy_name + # 取得代理名稱 + read -erp "請輸入代理轉發名稱 (如 mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then echo "名稱不能為空"; return 1 fi @@ -3873,7 +3879,7 @@ ldnmp_web_status() { case $sub_choice in 1) send_stats "申請網域證書" - read -e -p "請輸入你的網域名稱:" yuming + read -e -p "请输入你的域名: " yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -3884,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3925,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -4078,8 +4084,8 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" - # 生成随机端口和凭证 + send_stats "安裝frp服務端" + # 產生隨機連接埠和憑證 local bind_port=8055 local dashboard_port=8056 local token=$(openssl rand -hex 16) @@ -4773,7 +4779,7 @@ linux_clean() { bbr_on() { -# 統一寫入到 sysctl.d 以防與核心調優模組打架 +# 统一写入到 sysctl.d 以防与内核调优模块打架 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5037,7 +5043,7 @@ fetch_remote_ssh_keys() { return 1 fi - # 检查内容是否有效 + # 檢查內容是否有效 if [[ ! -s "${temp_file}" ]]; then echo "錯誤:下載到的檔案為空,URL 可能不包含任何公鑰" >&2 rm -f "${temp_file}" @@ -5132,7 +5138,7 @@ sshkey_panel() { echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" - echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5209,7 +5215,7 @@ add_sshpasswd() { # 回車不輸入,預設 root target_user=${target_user:-root} - # 校验用户是否存在 + # 校驗用戶是否存在 if ! id "$target_user" >/dev/null 2>&1; then echo "錯誤:用戶$target_user不存在" return 1 @@ -6297,7 +6303,7 @@ Kernel_optimize() { echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" echo -e "3. 網站最佳化模式: 針對網站伺服器最佳化,超高並發連線佇列。" echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" - echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" + echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" echo "--------------------" @@ -6334,21 +6340,21 @@ Kernel_optimize() { cd ~ clear _kernel_optimize_core "遊戲服優化模式" "game" - send_stats "游戏服优化" + send_stats "遊戲服優化" ;; 6) cd ~ clear restore_defaults curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh -o /tmp/network-optimize.sh && source /tmp/network-optimize.sh && restore_network_defaults - send_stats "还原默认设置" + send_stats "還原預設設定" ;; 7) cd ~ clear curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash - send_stats "内核自动调优" + send_stats "核心自動調優" ;; *) @@ -6378,7 +6384,7 @@ update_locale() { locale-gen echo "LANG=${lang}" > /etc/default/locale export LANG=${lang} - echo -e "${gl_lv}系統語言已經修改為:$lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" hash -r break_end @@ -6387,17 +6393,17 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}系統語言已經修改為:$lang 重新连接SSH生效。${gl_bai}" + echo -e "${gl_lv}系統語言已經修改為:$lang重新連線SSH生效。${gl_bai}" hash -r break_end ;; *) - echo "不支持的系统: $ID" + echo "不支援的系統:$ID" break_end ;; esac else - echo "不支持的系统,无法识别系统类型。" + echo "不支援的系統,無法辨識系統類型。" break_end fi } @@ -6451,7 +6457,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" +echo -e "${gl_lv}變更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -6604,7 +6610,7 @@ create_backup() { echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用預設目錄 (/etc /usr /home)" - read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input + read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input # 如果使用者沒有輸入目錄,則使用預設目錄 if [ -z "$input" ]; then @@ -6685,7 +6691,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -6699,7 +6705,7 @@ delete_backup() { if [ $? -eq 0 ]; then echo "備份刪除成功!" else - echo "備份刪除失敗!" + echo "备份删除失败!" exit 1 fi } @@ -6910,7 +6916,7 @@ add_connection() { send_stats "新增連接" echo "建立新連接範例:" echo "- 連線名稱: my_server" - echo " - IP地址: 192.168.1.100" + echo "- IP位址: 192.168.1.100" echo "- 使用者名稱: root" echo "- 連接埠: 22" echo "------------------------" @@ -6930,7 +6936,7 @@ add_connection() { # 刪除連接 delete_connection() { send_stats "刪除連接" - read -e -p "请输入要删除的连接编号: " num + read -e -p "請輸入要刪除的連接編號:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -6975,7 +6981,7 @@ use_connection() { else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "错误:未安装 sshpass,请先安装 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7011,7 +7017,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -7095,14 +7101,14 @@ mount_partition() { # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "/etc/fstab 中已存在該分區記錄,跳過寫入" + echo "/etc/fstab 中已存在该分区记录,跳过写入" return 0 fi - # 写入 /etc/fstab + # 寫入 /etc/fstab echo "UUID=$UUID $MOUNT_POINT $FSTYPE defaults,nofail 0 2" >> /etc/fstab - echo "已写入 /etc/fstab,实现持久化挂载" + echo "已寫入 /etc/fstab,實現持久化掛載" } @@ -7125,7 +7131,7 @@ unmount_partition() { echo "分割區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分區卸載失敗!" + echo "分区卸载失败!" fi } @@ -7168,7 +7174,7 @@ format_partition() { *) echo "無效的選擇!"; return ;; esac - # 確認格式化 + # 确认格式化 read -e -p "確認格式化分割區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" @@ -8107,8 +8113,8 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker還原" - read -e -p "請輸入要還原的備份目錄:" BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } + read -e -p "请输入要还原的备份目录: " BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } echo -e "${gl_kjlan}開始執行還原操作...${gl_bai}" @@ -8271,7 +8277,7 @@ docker_ssh_migration() { echo -e "1. 備份docker項目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" - echo -e "4. 删除docker项目的备份文件" + echo -e "4. 刪除docker專案的備份文件" echo "------------------------" echo -e "0. 返回上一級選單" echo "------------------------" @@ -8785,8 +8791,8 @@ linux_Oracle() { case $sub_choice in 1) clear - echo "活跃脚本: CPU占用10-20% 内存占用20% " - read -e -p "確定安裝嗎? (Y/N):" choice + echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" + read -e -p "确定安装吗? (Y/N):" choice case "$choice" in [Yy]) @@ -9425,7 +9431,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 資料庫管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有資料庫備份:" use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo @@ -9659,7 +9665,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "请输入index.html的路径,类似(/home/web/html/$yuming/index/): " index_lujing + read -e -p "請輸入index.html的路徑,類似(/home/web/html/$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -9789,7 +9795,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "沒有找到壓縮包。" + echo "没有找到压缩包。" fi ;; @@ -9987,7 +9993,7 @@ moltbot_menu() { return 1 fi - # 加上 --no-update-notifier,并确保错误重定向位置正确 + # 加上 --no-update-notifier,並確保錯誤重定向位置正確 local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10003,7 +10009,7 @@ moltbot_menu() { if [ "$local_version" != "$remote_version" ]; then echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" fi } @@ -10090,38 +10096,6 @@ moltbot_menu() { fi } - configure_openclaw_session_policy() { - local config_file - config_file=$(openclaw_get_config_file) - - [ ! -f "$config_file" ] && return 1 - - python3 - "$config_file" <<'PY' -import json, sys -path = sys.argv[1] -with open(path, 'r', encoding='utf-8') as f: - obj = json.load(f) - -session = obj.setdefault('session', {}) -session['dmScope'] = session.get('dmScope', 'per-channel-peer') -session['resetTriggers'] = ['/new', '/reset'] -session['reset'] = { - 'mode': 'idle', - 'idleMinutes': 10080 -} -session['resetByType'] = { - 'direct': {'mode': 'idle', 'idleMinutes': 10080}, - 'thread': {'mode': 'idle', 'idleMinutes': 1440}, - 'group': {'mode': 'idle', 'idleMinutes': 120} -} - -with open(path, 'w', encoding='utf-8') as f: - json.dump(obj, f, ensure_ascii=False, indent=2) - f.write('\n') -PY - } - - sync_openclaw_api_models() { local config_file config_file=$(openclaw_get_config_file) @@ -10417,7 +10391,7 @@ for name, provider in list(providers.items()): if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): set_primary_ref(defaults, first_ref) changed = True - summary.append(f'🔁 預設模型已兜底替換: {primary_ref} -> {first_ref}') + summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) @@ -10493,10 +10467,6 @@ PY npm install -g openclaw@latest openclaw onboard --install-daemon - openclaw config set tools.profile full - openclaw config set tools.elevated.enabled true - # 提示:修改配置後如需立即生效,可重新啟動 gateway:openclaw gateway restart - configure_openclaw_session_policy start_gateway add_app_id break_end @@ -10709,7 +10679,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11049,7 +11019,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 目前 api={api},但腳本已不再探測/修正協定;請手動設定為 openai-completions 或 openai-responses') + print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') protocol_msg = None @@ -11161,7 +11131,7 @@ PY2 echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失败:provider 配置不完整或类型不支持" + echo "❌ 同步失敗:provider 配置不完整或類型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11370,7 +11340,7 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + print('❌ 刪除中止:預設主模型指向該 provider,且無可用替代模型') raise SystemExit(3) set_primary_ref(defaults, replacement) print(f'🔁 預設主模型切換: {primary_ref} -> {replacement}') @@ -12107,7 +12077,7 @@ PYTHON_EOF fi fi - echo "⚠️ plugins.allow 移除失敗,請手動檢查:$config_file" + echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" return 1 } @@ -12143,7 +12113,7 @@ PYTHON_EOF echo "" echo "⚙️ 功能擴充:" echo "- [lobster] # 審批流 (附人工確認)" - echo "- [voice-call] # 語音通話能力" + echo " - [voice-call] # 语音通话能力" echo "- [nostr] # 加密隱私聊天" echo "--------------------------------------------------------" @@ -12173,12 +12143,12 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 正在检查插件状态: $plugin_id" + echo "🔍 正在檢查插件狀態:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) if echo "$plugin_list" | grep -qw "$plugin_id" && echo "$plugin_list" | grep "$plugin_id" | grep -q "disabled"; then - echo "💡 插件 [$plugin_id] 已预装,正在激活..." + echo "💡 插件 [$plugin_id] 已預先安裝,正在啟動..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12218,12 +12188,12 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在刪除/停用插件:$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ 已卸載:$plugin_id" else - echo "⚠️ 卸載失敗,可能為預先安裝插件,僅停用:$plugin_id" + echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12276,7 +12246,7 @@ PYTHON_EOF echo "----------------------------------------" echo "1) 安裝技能" - echo "2) 删除技能" + echo "2) 刪除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -12868,7 +12838,7 @@ if os.path.isdir(agents_root): fi echo "備份模式:" - echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多狀態,敏感風險較高)" read -e -p "請選擇備份模式(預設 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -13119,7 +13089,7 @@ if os.path.isdir(agents_root): fi if [ ! -f "$target_path" ]; then - echo "❌ 目标文件不存在: $target_path" + echo "❌ 目標檔案不存在:$target_path" break_end return 1 fi @@ -13366,27 +13336,60 @@ EOF } openclaw_memory_render_status() { - local agent_lines agent_id workspace status_output status_lines first="true" - agent_lines=$(openclaw_memory_list_agents) - while IFS=$'\t' read -r agent_id workspace; do - [ -z "$agent_id" ] && continue - status_output=$(openclaw memory status --agent "$agent_id" 2>/dev/null) - [ "$first" = "true" ] || echo "" - first="false" - echo "Agent: $agent_id" - if [ $? -ne 0 ] || [ -z "$status_output" ]; then - echo "獲取狀態失敗" - continue - fi - status_lines=$(echo "$status_output" | grep -E "^(Provider|Vector|Indexed|Workspace|Store)" | head -n 5 | sed -e 's/^Provider: /底層方案: /' -e 's/^Vector: /向量庫狀態: /' -e 's/^Indexed: /已收錄文件: /' -e 's/^Workspace: /工作區: /' -e 's/^Store: /索引庫: /') - if [ -z "$status_lines" ]; then - echo "未安裝/未啟動" - else - echo "$status_lines" - fi - done </dev/null) + if [ -z "$json_output" ]; then + echo "取得記憶狀態失敗(openclaw memory status --json 無輸出)" + return 1 + fi + python3 - "$json_output" <<'PY' +import json, sys +raw = sys.argv[1] +try: + data = json.loads(raw) +except Exception: + print("取得記憶狀態失敗(JSON 解析錯誤)") + raise SystemExit(1) +if not isinstance(data, list) or len(data) == 0: + print("未檢測到任何智能體記憶狀態。") + raise SystemExit(0) +first = True +for entry in data: + if not isinstance(entry, dict): + continue + agent_id = entry.get("agentId", "?") + s = entry.get("status", {}) + if not isinstance(s, dict): + s = {} + if not first: + print("") + first = False + print("Agent: %s" % agent_id) + backend = s.get("backend") or s.get("provider") or "-" + print("底層方案: %s" % backend) + files = s.get("files", 0) + chunks = s.get("chunks", 0) + print("已收錄: %s 檔案 / %s 區塊" % (files, chunks)) + dirty = s.get("dirty") + dirty_str = "是" if dirty else "否" + print("待刷新: %s" % dirty_str) + vec = s.get("vector", {}) + if isinstance(vec, dict) and vec.get("enabled"): + vec_str = "就緒" if vec.get("available") else "已啟用(不可用)" + else: + vec_str = "未啟用" + print("向量庫: %s" % vec_str) + ws = s.get("workspaceDir") or "-" + print("工作區: %s" % ws) + db = s.get("dbPath") or "-" + print("索引庫: %s" % db) + scan = entry.get("scan", {}) + if isinstance(scan, dict): + issues = scan.get("issues", []) + if issues: + for issue in issues[:3]: + print(" ⚠️ %s" % issue) +PY } openclaw_memory_get_backend() { @@ -13463,7 +13466,7 @@ EOF if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("未檢測到 QMD") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路徑:$model_path") @@ -13656,7 +13659,7 @@ EOF echo "地區:$OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then - echo "下載來源:$OPENCLAW_MEMORY_HF_BASE" + echo "下载源: $OPENCLAW_MEMORY_HF_BASE" fi echo "最終狀態:" openclaw_memory_render_status @@ -13724,7 +13727,7 @@ EOF echo "✅ memory.backend 已是 qmd" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ 已设置 memory.backend=qmd" + echo "✅ 已設定 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") @@ -13978,7 +13981,7 @@ EOF fi else echo "includeDefaultMemory 配置正常。" - echo "將執行:清理舊索引 → 全量重建所有智能體索引" + echo "将执行:清理旧索引 → 全量重建所有智能体索引" echo "" read -e -p "確認執行? (Y/n):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14162,18 +14165,36 @@ EOF done } + + openclaw_memory_search_test() { + read -e -p "輸入搜尋關鍵字:" query + if [ -z "$query" ]; then + echo "關鍵字不能為空。" + return 1 + fi + echo "正在搜尋記憶..." + openclaw memory search "$query" --max-results 5 + } + + openclaw_memory_deep_status() { + echo "正在探測嵌入模型就緒狀態..." + openclaw memory status --deep + } + openclaw_memory_menu() { - send_stats "OpenClaw记忆管理" + send_stats "OpenClaw記憶管理" while true; do clear echo "=======================================" - echo "OpenClaw 记忆管理" + echo "OpenClaw 記憶管理" echo "=======================================" openclaw_memory_render_status echo "1. 更新記憶索引" echo "2. 檢視記憶文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" + echo "5. 搜尋測試(驗證索引是否運作)" + echo "6. 深度狀態探測(檢查嵌入模型)" echo "0. 返回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" memory_choice @@ -14220,6 +14241,14 @@ EOF 4) openclaw_memory_scheme_menu ;; + 5) + openclaw_memory_search_test + break_end + ;; + 6) + openclaw_memory_deep_status + break_end + ;; 0) return 0 ;; @@ -14285,7 +14314,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ 未偵測到 openclaw,無法重新啟動 OpenClaw Gateway。" + echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" return 1 fi echo "正在重啟 OpenClaw Gateway..." @@ -14421,75 +14450,111 @@ PY mkdir -p "$HOME/.openclaw" - # 使用 Python 安全性更新或建立 exec-approvals.json - python3 -c " + # 產生 JSON 並透過 openclaw approvals set --stdin 寫入(優先) + # 若 CLI 不支援則回退直接寫文件 + local json_payload + json_payload=$(python3 -c ' import json, sys, os path = sys.argv[1] try: if os.path.exists(path): - with open(path, 'r') as f: + with open(path, "r") as f: data = json.load(f) else: - data = {'version': 1, 'defaults': {}} + data = {"version": 1, "defaults": {}} except Exception: - data = {'version': 1, 'defaults': {}} - -if 'defaults' not in data: - data['defaults'] = {} - -data['defaults']['security'] = sys.argv[2] -data['defaults']['ask'] = sys.argv[3] -data['defaults']['askFallback'] = sys.argv[4] -data['defaults']['autoAllowSkills'] = True - -with open(path, 'w') as f: - json.dump(data, f, indent=2) -" "$approvals_file" "$sec" "$ask" "$fallback" + data = {"version": 1, "defaults": {}} +if "defaults" not in data: + data["defaults"] = {} +data["defaults"]["security"] = sys.argv[2] +data["defaults"]["ask"] = sys.argv[3] +data["defaults"]["askFallback"] = sys.argv[4] +data["defaults"]["autoAllowSkills"] = True +print(json.dumps(data, indent=2)) +' "$approvals_file" "$sec" "$ask" "$fallback") + + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then + return 0 + fi + # 回退:直接寫文件 + echo "$json_payload" > "$approvals_file" } openclaw_permission_render_status() { echo "應用層配置: ~/.openclaw/openclaw.json" echo "宿主機核准: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" - local current_profile=$(openclaw config get tools.profile 2>/dev/null) - local sec_val - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - sec_val=$(python3 -c "import json, sys; print(json.load(open('$HOME/.openclaw/exec-approvals.json')).get('defaults', {}).get('security', 'unset'))" 2>/dev/null || echo "unset") - else - sec_val="unset" - fi + local current_profile current_sec current_ask current_elevated + current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_sec=$(openclaw config get tools.exec.security 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_ask=$(openclaw config get tools.exec.ask 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + current_elevated=$(openclaw config get tools.elevated.enabled 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') + # 清理空值 + [ -z "$current_profile" ] || echo "$current_profile" | grep -qi "config path not found" && current_profile="" + [ -z "$current_sec" ] || echo "$current_sec" | grep -qi "config path not found" && current_sec="" + [ -z "$current_ask" ] || echo "$current_ask" | grep -qi "config path not found" && current_ask="" + [ -z "$current_elevated" ] || echo "$current_elevated" | grep -qi "config path not found" && current_elevated="" local current_mode="未知 / 自訂" - if [ "$current_profile" = "coding" ] && [ "$sec_val" = "allowlist" ]; then - current_mode="\033[1;32m標準安全模式\033[0m" - elif [ "$current_profile" = "full" ] && [ "$sec_val" = "full" ]; then + if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m完全開放模式\033[0m" - elif [ "$current_profile" = "coding" ] && [ "$sec_val" = "full" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then current_mode="\033[1;33m開發增強模式\033[0m" - elif [ -z "$current_profile" ] && [ "$sec_val" = "unset" ]; then + elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then + current_mode="\033[1;32m標準安全模式\033[0m" + elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" fi echo -e "當前綜合安全等級:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" - openclaw config get tools.profile 2>/dev/null | sed 's/^/ Profile (預設): /' || echo " Profile: (unset)" - openclaw config get tools.exec.security 2>/dev/null | sed 's/^/ Exec 限制: /' || echo "Exec 限制: (unset)" - openclaw config get tools.exec.ask 2>/dev/null | sed 's/^/ 審核提示: /' || echo "審核提示: (unset)" - openclaw config get tools.elevated.enabled 2>/dev/null | sed 's/^/ 提權開關: /' || echo "提權開關: (unset)" + echo " Profile (预设): ${current_profile:-(unset)}" + echo "Exec 限制: ${current_sec:-(unset)}" + echo "審核提示: ${current_ask:-(unset)}" + echo "提權開關: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" - if [ -f "$HOME/.openclaw/exec-approvals.json" ]; then - python3 -c " + if openclaw_has_command openclaw; then + local approvals_json + approvals_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$approvals_json" ]; then + python3 -c ' import json, sys try: - with open('$HOME/.openclaw/exec-approvals.json') as f: - d = json.load(f).get('defaults', {}) - print('攔截策略 (Security):' + str(d.get('security', '(unset)'))) - print('提示策略 (Ask):' + str(d.get('ask', '(unset)'))) - print('無UI兜底 (AskFallback):' + str(d.get('askFallback', '(unset)'))) + d = json.loads(sys.argv[1]) + defaults = d.get("file", {}).get("defaults", {}) + if not defaults: + defaults = d.get("defaults", {}) + sec = defaults.get("security", "(unset)") + ask = defaults.get("ask", "(unset)") + fb = defaults.get("askFallback", "(unset)") + auto = defaults.get("autoAllowSkills", False) + print("攔截策略 (Security):" + str(sec)) + print("提示策略 (Ask):" + str(ask)) + print("無UI兜底 (AskFallback):" + str(fb)) + print("自動放行技能 (autoAllowSkills):" + ("on" if auto else "off")) + exists = d.get("exists", True) + if not exists: + print("(審核文件不存在,使用系統內建安全兜底)") +except Exception as e: + print("(解析失敗:" + str(e) + ")") +' "$approvals_json" + else + echo "(openclaw approvals get --json 無輸出)" + fi + elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then + python3 -c ' +import json, os +path = os.path.expanduser("~/.openclaw/exec-approvals.json") +try: + with open(path) as f: + d = json.load(f).get("defaults", {}) + print("攔截策略 (Security):" + str(d.get("security", "(unset)"))) + print("提示策略 (Ask):" + str(d.get("ask", "(unset)"))) + print("無UI兜底 (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print('(設定檔解析失敗)') -" + print("(設定檔解析失敗)") +' else echo "(未配置,強制使用系統內建安全兜底策略)" fi @@ -14563,7 +14628,12 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "清理宿主機攔截配置..." - rm -f "$HOME/.openclaw/exec-approvals.json" + # 優先透過 CLI 清空審核配置,回退直接刪文件 + if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then + true + else + rm -f "$HOME/.openclaw/exec-approvals.json" + fi openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢復到 OpenClaw 官方安全沙盒防禦機制${gl_bai}" @@ -14584,6 +14654,66 @@ except Exception: read -n 1 -s } + + openclaw_permission_manage_allowlist() { + while true; do + clear + echo "=======================================" + echo "Exec 指令白名單管理" + echo "=======================================" + echo "目前白名單:" + local allowlist_json + allowlist_json=$(openclaw approvals get --json 2>/dev/null) + if [ -n "$allowlist_json" ]; then + python3 -c ' +import json, sys +try: + d = json.loads(sys.argv[1]) + f = d.get("file", {}) + agents = f.get("agents", {}) + found = False + for agent_id, agent_data in agents.items(): + al = agent_data.get("allowlist", []) + if al: + found = True + print("智能體 [%s]:" % agent_id) + for item in al: + print(" - %s" % item) + if not found: + print("(空,未配置任何白名單規則)") +except Exception as e: + print("(解析失敗:" + str(e) + ")") +' "$allowlist_json" + else + echo "(無法取得)" + fi + echo "---------------------------------------" + echo "1. 新增白名單規則" + echo "2. 移除白名單規則" + echo "0. 返回" + echo "---------------------------------------" + read -e -p "請選擇:" al_choice + case "$al_choice" in + 1) + read -e -p "輸入要放行的命令路徑 (支援 glob,如 /usr/bin/git):" pattern + [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } + read -e -p "指定智能體ID (留空=所有智能體 *):" agent_id + agent_id="${agent_id:-*}" + openclaw approvals allowlist add --agent "$agent_id" "$pattern" + break_end + ;; + 2) + read -e -p "輸入要移除的命令路徑:" pattern + [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } + openclaw approvals allowlist remove "$pattern" + break_end + ;; + 0) return 0 ;; + *) echo "無效選擇"; sleep 1 ;; + esac + done + } + openclaw_permission_menu() { send_stats "OpenClaw權限管理" while true; do @@ -14598,6 +14728,7 @@ except Exception: echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" + echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" perm_choice @@ -14605,30 +14736,33 @@ except Exception: 1) echo "準備應用:標準安全模式" read -e -p "輸入 yes 確認:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_standard || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "已取消"; fi break_end ;; 2) echo "準備應用:開發增強模式" read -e -p "輸入 yes 確認:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_apply_developer || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" - read -e -p "输入 FULL 确认继续: " confirm - [ "$confirm" = "FULL" ] && openclaw_permission_apply_full || echo "已取消" + read -e -p "輸入 FULL 確認繼續:" confirm + if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end ;; 4) - echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" + echo "將清除所有自訂覆蓋,恢復 OpenClaw 剛安裝時的嚴格沙盒狀態。" read -e -p "輸入 yes 確認:" confirm - [ "$confirm" = "yes" ] && openclaw_permission_restore_official_defaults || echo "已取消" + if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "已取消"; fi break_end ;; 5) openclaw_permission_run_audit ;; + 6) + openclaw_permission_manage_allowlist + ;; 0) return 0 ;; @@ -14705,6 +14839,15 @@ except Exception: } openclaw_multiagent_agents_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents list --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:從設定檔讀取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -14723,82 +14866,65 @@ except Exception: PY return 0 fi - openclaw agents list --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_bindings_json() { + local result + if openclaw_has_command openclaw; then + result=$(openclaw agents bindings --json 2>/dev/null) + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:從設定檔讀取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then python3 - "$config_file" <<'PY' -import json,sys,os +import json,sys path=sys.argv[1] -results=[] - -def add_item(item): - if not isinstance(item,dict): - return - bind=item.get("bind") or item.get("binding") or item.get("scope") or item.get("route") - agent=item.get("agentId") or item.get("agent") - if agent or bind: - results.append({"agentId": agent or "?", "bind": bind or "-"}) - -def walk(obj): - if isinstance(obj,dict): - if "agentId" in obj and any(k in obj for k in ("bind","binding","scope","route")): - add_item(obj) - for v in obj.values(): - walk(v) - elif isinstance(obj,list): - for v in obj: - walk(v) - try: with open(path) as f: data=json.load(f) - bindings=data.get("agents",{}).get("bindings") if isinstance(data,dict) else None - if isinstance(bindings,list): - for item in bindings: - add_item(item) - walk(data) + bindings=data.get("agents",{}).get("bindings",[]) + if not isinstance(bindings,list): + bindings=[] + results=[] + for item in bindings: + if not isinstance(item,dict): + continue + results.append({"agentId": item.get("agentId") or item.get("agent") or "?", "description": item.get("description") or "-"}) print(json.dumps(results, ensure_ascii=False)) except Exception: print("[]") PY return 0 fi - openclaw agents bindings --json 2>/dev/null || echo '[]' + echo '[]' } openclaw_multiagent_sessions_json() { - local config_file - config_file=$(openclaw_permission_config_file) - python3 - "$config_file" <<'PY' -import json,sys,os -config_path=sys.argv[1] if len(sys.argv)>1 else "" - -def load_agents(path): - if path and os.path.exists(path): - try: - with open(path) as f: - data=json.load(f) - agents=data.get("agents",{}).get("list",[]) - if isinstance(agents,list) and agents: - ids=[a.get("id") for a in agents if isinstance(a,dict) and a.get("id")] - if ids: - return ids - except Exception: - pass - base=os.path.expanduser("~/.openclaw/agents") - try: - return [d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] - except Exception: - return [] - -agent_ids=load_agents(config_path) + local result + if openclaw_has_command openclaw; then + result=$(openclaw sessions --json 2>/dev/null | grep -v '^\[') + if [ -n "$result" ] && python3 -c "import json,sys; json.loads(sys.argv[1])" "$result" 2>/dev/null; then + echo "$result" + return 0 + fi + fi + # 回退:從檔案系統讀取 + python3 <<'PY' +import json,os +base=os.path.expanduser("~/.openclaw/agents") sessions=[] -for agent_id in agent_ids: - path=os.path.expanduser(f"~/.openclaw/agents/{agent_id}/sessions/sessions.json") +try: + agent_dirs=[d for d in os.listdir(base) if os.path.isdir(os.path.join(base,d))] +except Exception: + agent_dirs=[] +for agent_id in agent_dirs: + path=os.path.join(base,agent_id,"sessions","sessions.json") if not os.path.exists(path): continue try: @@ -14809,19 +14935,15 @@ for agent_id in agent_ids: if isinstance(data,dict): items=data.items() elif isinstance(data,list): - items=[(item.get("key") or item.get("sessionKey") or "?", item) for item in data if isinstance(item,dict)] + items=[(item.get("key") or "?", item) for item in data if isinstance(item,dict)] else: continue for key,item in items: if not isinstance(item,dict): continue - model=item.get("model") - if not model: - report=item.get("systemPromptReport") or {} - if isinstance(report,dict): - model=report.get("model") or report.get("modelProvider") or report.get("provider") - sessions.append({"agentId": agent_id, "key": key, "model": model or "-"}) -print(json.dumps({"sessions": sessions}, ensure_ascii=False)) + model=item.get("model") or "-" + sessions.append({"agentId": agent_id, "key": key, "model": model}) +print(json.dumps({"path":"(filesystem)","count":len(sessions),"sessions":sessions}, ensure_ascii=False)) PY } @@ -14831,12 +14953,34 @@ PY default_agent=$(openclaw_multiagent_default_agent) echo "設定檔: ${config_file:-$(openclaw_permission_config_file)}" echo "預設智能體:$default_agent" - python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); obj=json.loads(sys.argv[3] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; print("已配置智能體數: %s" % len(agents)); print("路由綁定數: %s" % len(bindings)); print("會話總數: %s" % len(sessions)); print("---------------------------------------"); -if not agents: print("目前未配置任何多智能體。") + python3 -c ' +import json,sys +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +sess_obj=json.loads(sys.argv[3] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +print("已配置智能體數: %s" % len(agents)) +print("路由綁定數: %s" % len(bindings)) +print("會話總數: %s" % len(sessions)) +print("---------------------------------------") +if not agents: + print("目前未配置任何多智能體。") else: - import itertools - for item in itertools.islice(agents, 8): - ident_obj=item.get("identity") if isinstance(item.get("identity"),dict) else {}; identity=ident_obj.get("name") or item.get("identityName") or item.get("name") or "-"; emoji=item.get("identityEmoji") or ""; ws=item.get("workspace") or "-"; print("- 智能體ID: [1;36m%s [0m" % item.get("id","?")); print("身份名稱: %s %s" % (identity, emoji)); print("工作目錄: %s" % ws)' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" + for item in agents[:8]: + aid = item.get("id","?") + identity = item.get("identityName") or item.get("name") or "-" + emoji = item.get("identityEmoji") or "" + ws = item.get("workspace") or "-" + model = item.get("model") or "-" + is_default = item.get("isDefault", False) + bcount = item.get("bindings", 0) + default_tag = "[預設]" if is_default else "" + print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("身份名稱: %s %s" % (identity, emoji)) + print("模型: %s" % model) + print("工作目錄: %s" % ws) + print("綁定數: %s" % bcount) +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_list_agents() { @@ -14893,10 +15037,16 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_list_bindings() { send_stats "OpenClaw多智能體-檢視路由綁定" - python3 -c 'import json,sys; bindings=json.loads(sys.argv[1] or "[]"); -if not bindings: print("暫無路由綁定。"); raise SystemExit(0) + python3 -c ' +import json,sys +bindings=json.loads(sys.argv[1] or "[]") +if not bindings: + print("暫無路由綁定。") + raise SystemExit(0) for idx,item in enumerate(bindings,1): - bind=item.get("bind") or item.get("binding") or item.get("scope") or "-"; print("%s. agent=%s | bind=%s" % (idx, item.get("agentId","?"), bind))' "$(openclaw_multiagent_bindings_json)" + desc = item.get("description") or "-" + print("%s. agent=%s | %s" % (idx, item.get("agentId","?"), desc)) +' "$(openclaw_multiagent_bindings_json)" } openclaw_multiagent_add_binding() { @@ -14928,9 +15078,9 @@ for idx,item in enumerate(bindings,1): read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由綁定移除成功" + echo "✅ 路由绑定移除成功" else - echo "❌ 路由綁定移除失敗" + echo "❌ 路由绑定移除失败" return 1 fi } @@ -14938,14 +15088,32 @@ for idx,item in enumerate(bindings,1): openclaw_multiagent_show_sessions() { send_stats "OpenClaw多智能體-會話概況" - python3 -c 'import json,sys; obj=json.loads(sys.argv[1] or "{}"); sessions=obj.get("sessions",[]) if isinstance(obj,dict) else []; -if not sessions: print("暫無 session 資料。"); raise SystemExit(0) + python3 -c ' +import json,sys +sess_obj=json.loads(sys.argv[1] or "{}") +sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] +if not sessions: + print("暫無 session 資料。") + raise SystemExit(0) by_agent={} -for item in sessions: by_agent[item.get("agentId","?")]=by_agent.get(item.get("agentId","?"),0)+1 +for item in sessions: + aid = item.get("agentId","?") + by_agent[aid] = by_agent.get(aid, 0) + 1 print("會話匯總:") -for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) +for agent_id,count in sorted(by_agent.items()): + print("- %s: %s" % (agent_id, count)) print("---------------------------------------") -for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item.get("key","-"), item.get("model") or "-"))' "$(openclaw_multiagent_sessions_json)" +for item in sessions[:10]: + key = item.get("key","-") + model = item.get("model") or "-" + aid = item.get("agentId","?") + tokens = "" + it = item.get("inputTokens") + ot = item.get("outputTokens") + if it is not None: + tokens = " | in=%s out=%s" % (it, ot or 0) + print("%s | %s | %s%s" % (aid, key, model, tokens)) +' "$(openclaw_multiagent_sessions_json)" } openclaw_multiagent_health_check() { @@ -14955,12 +15123,60 @@ for item in sessions[:10]: print("%s | %s | %s" % (item.get("agentId","?"), item config_file=$(openclaw_multiagent_config_file) echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" - python3 -c 'import json,sys,os; agents=json.loads(sys.argv[1] or "[]"); bindings=json.loads(sys.argv[2] or "[]"); print("---------------------------------------"); -if not agents: print("⚠️ 未發現配置智能體。"); + python3 -c ' +import json,sys,os +agents=json.loads(sys.argv[1] or "[]") +bindings=json.loads(sys.argv[2] or "[]") +print("---------------------------------------") +if not agents: + print("⚠️ 未發現配置智能體。") else: - for item in agents: - ws=item.get("workspace") or ""; aid=item.get("id","?"); state="OK" if ws and os.path.isdir(os.path.expanduser(ws)) else ("OK" if aid=="main" else "MISSING"); print("agent=%s workspace=%s [%s]" % (aid, ws or "-", state)) -print("路由綁定數=%s" % len(bindings)); print("✅ 多智能體健康檢查完成")' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + for item in agents: + ws = item.get("workspace") or "" + aid = item.get("id","?") + if ws and os.path.isdir(os.path.expanduser(ws)): + state = "OK" + elif aid == "main": + state = "OK" + else: + state = "MISSING" + model = item.get("model") or "-" + bcount = item.get("bindings", 0) + print("agent=%s workspace=%s model=%s bindings=%s [%s]" % (aid, ws or "-", model, bcount, state)) +print("路由綁定數=%s" % len(bindings)) +print("✅ 多智能體健康檢查完成") +' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" + echo "" + echo "運行安全審計..." + openclaw security audit 2>/dev/null || echo "⚠️ 安全審計命令不可用" + } + + + openclaw_multiagent_set_identity() { + openclaw_multiagent_require_openclaw || return 1 + openclaw_multiagent_list_agents + read -e -p "輸入要修改身分的智能體ID:" agent_id + [ -z "$agent_id" ] && { echo "ID 不能為空"; return 1; } + echo "修改選項(留空跳過):" + read -e -p "新名稱:" new_name + read -e -p "新 Emoji:" new_emoji + local cmd="openclaw agents set-identity --agent $agent_id" + [ -n "$new_name" ] && cmd="$cmd --name $new_name" + [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" + echo "也可以從 IDENTITY.md 自動讀取身分資訊。" + read -e -p "是否從 IDENTITY.md 讀取? (y/n):" from_id + if [ "$from_id" = "y" ]; then + cmd="openclaw agents set-identity --agent $agent_id --from-identity" + fi + eval "$cmd" + } + + openclaw_multiagent_cleanup_sessions() { + openclaw_multiagent_require_openclaw || return 1 + echo "即將清理過期/冗餘會話資料..." + read -e -p "輸入 yes 確認:" confirm + [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } + openclaw sessions cleanup } openclaw_multiagent_menu() { @@ -14979,6 +15195,8 @@ print("路由綁定數=%s" % len(bindings)); print("✅ 多智能體健康檢查 echo "5. 移除路由綁定" echo "6. 查看會話概況" echo "7. 執行多智能體健康檢查" + echo "8. 修改智能體身分(名稱/Emoji)" + echo "9. 清理過期會話" echo "0. 返回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" multi_choice @@ -14990,6 +15208,8 @@ print("路由綁定數=%s" % len(bindings)); print("✅ 多智能體健康檢查 5) openclaw_multiagent_remove_binding; break_end ;; 6) openclaw_multiagent_show_sessions; break_end ;; 7) openclaw_multiagent_health_check; break_end ;; + 8) openclaw_multiagent_set_identity; break_end ;; + 9) openclaw_multiagent_cleanup_sessions; break_end ;; 0) return 0 ;; *) echo "無效的選擇,請重試。"; sleep 1 ;; esac @@ -15055,7 +15275,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15111,7 +15331,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15147,14 +15367,14 @@ openclaw_backup_restore_menu() { if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}已將域名${yuming} 加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi openclaw devices list - read -e -p "請輸入 Request_Key:" Request_Key + read -e -p "请输入 Request_Key: " Request_Key [ -z "$Request_Key" ] && { echo "Request_Key 不能為空" @@ -15303,7 +15523,7 @@ while true; do echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma监控工具" + echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" @@ -15324,7 +15544,7 @@ while true; do echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" @@ -15351,13 +15571,13 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" + echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大內網穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" @@ -16743,7 +16963,7 @@ while true; do } - local docker_describe="Docker Registry 是一個用於儲存和分發 Docker 映像的服務。" + local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" local docker_url="官網介紹: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" @@ -17402,7 +17622,7 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_describe="是一個輕量、高效能的音樂串流伺服器" local docker_url="官網介紹: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -18533,7 +18753,7 @@ while true; do local app_id="99" local app_name="dsm群暉虛擬機" - local app_text="Docker容器中的虛擬DSM" + local app_text="Docker容器中的虚拟DSM" local app_url="官網:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" @@ -18616,7 +18836,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -18898,7 +19118,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" local app_name="karakeep書籤管理" - local app_text="是一款可自行託管的書籤應用,具有人工智慧功能,專為資料囤積者而設計。" + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" local app_url="官方網站:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" @@ -19464,7 +19684,7 @@ net_menu() { send_stats "啟用網卡" read -erp "請輸入要啟用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" + ip link set "$nic" up && echo "✔ 网卡 $nic已啟用" else echo "✘ 網路卡不存在" fi @@ -19587,7 +19807,7 @@ log_menu() { echo "⚠️ 清理 journal 日誌(安全方式)" echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" - echo "3) 限制日誌最大 500M" + echo "3) 限制日志最大 500M" read -erp "請選擇清理方式:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19684,16 +19904,16 @@ env_menu() { send_stats "正在重新載入環境變數" source "$BASHRC" source "$PROFILE" - echo "✔ 环境变量已重新加载" + echo "✔ 環境變數已重新載入" read -erp "按回車繼續..." } while true; do clear - echo "=========== 系统环境变量管理 ==========" + echo "=========== 系統環境變數管理 ==========" echo "目前使用者:$USER" echo "--------------------------------------" - echo "1. 查看当前常用环境变量" + echo "1. 查看目前常用環境變數" echo "2. 查看 ~/.bashrc" echo "3. 查看 ~/.profile" echo "4. 編輯 ~/.bashrc" @@ -19741,7 +19961,7 @@ create_user_with_sshkey() { local sshkey_vl if [[ -z "$new_username" ]]; then - echo "用法:create_user_with_sshkey <用户名>" + echo "用法:create_user_with_sshkey <使用者名稱>" return 1 fi @@ -19831,7 +20051,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}切換系統語言${gl_kjlan}32. ${gl_bai}命令列美化工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}設定係統回收站${gl_kjlan}34. ${gl_bai}系統備份與復原" - echo -e "${gl_kjlan}35. ${gl_bai}ssh遠端連線工具${gl_kjlan}36. ${gl_bai}硬盘分区管理工具" + echo -e "${gl_kjlan}35. ${gl_bai}ssh遠端連線工具${gl_kjlan}36. ${gl_bai}硬碟分割區管理工具" echo -e "${gl_kjlan}37. ${gl_bai}命令列歷史記錄${gl_kjlan}38. ${gl_bai}rsync遠端同步工具" echo -e "${gl_kjlan}39. ${gl_bai}命令收藏夾${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}網路卡管理工具" echo -e "${gl_kjlan}------------------------" @@ -19885,7 +20105,7 @@ linux_Settings() { echo "---------------------------------------" echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" + echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" echo "查詢更多版本: https://www.python.org/downloads/" @@ -19995,7 +20215,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH連接埠修改" + send_stats "退出SSH埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20509,7 +20729,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 新增新的解析 2. 刪除解析位址" + echo "1. 添加新的解析 2. 删除解析地址" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20622,7 +20842,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -20781,7 +21001,7 @@ EOF echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" + echo -e "10. 設定網路為${gl_huang}ipv4优先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" @@ -20973,7 +21193,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" + echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21036,7 +21256,7 @@ linux_file() { read -e -p "請輸入目前檔名:" current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" - send_stats "重命名文件" + send_stats "重新命名文件" ;; 15) # 删除文件 read -e -p "請輸入要刪除的檔名:" filename @@ -21050,7 +21270,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21060,7 +21280,7 @@ linux_file() { read -e -p "請輸入要移動的檔案或目錄路徑:" src_path if [ ! -e "$src_path" ]; then echo "錯誤: 檔案或目錄不存在。" - send_stats "移動檔案或目錄失敗: 檔案或目錄不存在" + send_stats "移动文件或目录失败: 文件或目录不存在" continue fi @@ -21222,7 +21442,7 @@ while true; do 1) send_stats "新增叢集伺服器" read -e -p "伺服器名稱:" server_name - read -e -p "伺服器IP:" server_ip + read -e -p "服务器IP: " server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} read -e -p "伺服器使用者名稱(root):" server_username @@ -21326,7 +21546,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G記憶體 20G硬碟 800G流量每月${gl_bai}" echo -e "${gl_bai}網址: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 6.9刀每月 东京软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" +echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" @@ -21336,7 +21556,7 @@ echo "" echo -e "網域優惠" echo "------------------------" echo -e "${gl_lan}GNAME 8.8刀首年COM域名 6.68刀首年CC域名${gl_bai}" -echo -e "${gl_bai}網址: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" +echo -e "${gl_bai}网址: https://www.gname.com/register?tt=86836&ttcode=KEJILION86836&ttbj=sh${gl_bai}" echo "------------------------" echo "" echo -e "科技lion週邊" @@ -21423,10 +21643,13 @@ while true; do echo "全部日誌:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" - curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - local sh_v_new=$(curl -s ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | cut -d '"' -f 2) + curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 + # 只下載前5行取得版本號,避免下載整個腳本 + local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) - if [ "$sh_v" = "$sh_v_new" ]; then + if [ -z "$sh_v_new" ]; then + echo -e "${gl_hong}無法獲取最新版本信息,請檢查網絡連接${gl_bai}" + elif [ "$sh_v" = "$sh_v_new" ]; then echo -e "${gl_lv}你已經是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "腳本已經最新了,無需更新" else @@ -21452,37 +21675,76 @@ while true; do case "$choice" in 1) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) + local download_url if [ "$country" = "CN" ]; then - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/cn/kejilion.sh" else - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh + download_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh" + fi + + # 備份當前腳本 + cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null + + # 下载到临时文件,校验后再替换 + local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) + if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ + [ -s "$tmp_file" ] && \ + head -1 "$tmp_file" | grep -q '^#!/bin/bash'; then + chmod +x "$tmp_file" + mv -f "$tmp_file" ~/kejilion.sh + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + send_stats "腳本已經最新$sh_v_new" + else + rm -f "$tmp_file" + # 恢復備份 + if [ -f ~/kejilion.sh.bak ]; then + mv -f ~/kejilion.sh.bak ~/kejilion.sh + fi + echo -e "${gl_hong}更新失敗!下载出错或文件校验不通过,已恢复原版本${gl_bai}" + send_stats "腳本更新失敗" fi - canshu_v6 - CheckFirstRun_true - yinsiyuanquan2 - cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "腳本已經最新$sh_v_new" break_end ~/kejilion.sh exit ;; 2) clear - local country=$(curl -s ipinfo.io/country) + local country=$(curl -s --max-time 5 ipinfo.io/country) local ipv6_address=$(curl -s --max-time 1 ipv6.ip.sb) + local cron_proxy cron_sed_cmd if [ "$country" = "CN" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"CN\"/g' ~/kejilion.sh" elif [ -n "$ipv6_address" ]; then - SH_Update_task="curl -sS -O https://gh.kejilion.pro/raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh && sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ./kejilion.sh" + cron_proxy="https://gh.kejilion.pro/" + cron_sed_cmd="sed -i 's/canshu=\"default\"/canshu=\"V6\"/g' ~/kejilion.sh" else - SH_Update_task="curl -sS -O https://raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && chmod +x kejilion.sh" + cron_proxy="https://" + cron_sed_cmd="" + fi + + # 建置健全的自動更新指令:下載到暫存檔案 → 校驗 → 備份 → 取代 → 還原本機設定 → 部署 + SH_Update_task="cd ~ && tmp=\$(mktemp ~/kejilion_tmp.XXXXXX) && curl -sS --max-time 60 --fail -o \"\$tmp\" ${cron_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh && [ -s \"\$tmp\" ] && head -1 \"\$tmp\" | grep -q '^#!/bin/bash' && cp -f ~/kejilion.sh ~/kejilion.sh.bak 2>/dev/null && chmod +x \"\$tmp\" && mv -f \"\$tmp\" ~/kejilion.sh" + # 追加設定恢復 + if [ -n "$cron_sed_cmd" ]; then + SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi + # 從舊腳本恢復 permission_granted 和 ENABLE_STATS 設置 + SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" + # 部署到 /usr/local/bin/k 和 /usr/bin/k + SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" + # 下載失敗時清理暫存文件 + SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" + check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - - # (crontab -l 2>/dev/null; echo "0 2 * * * bash -c \"$SH_Update_task\"") | crontab - - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c \"$SH_Update_task\"") | crontab - + (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - echo -e "${gl_lv}自動更新已開啟,每天凌晨2點腳本會自動更新!${gl_bai}" send_stats "開啟腳本自動更新" break_end @@ -21604,7 +21866,7 @@ echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安裝負載平衡 k loadbalance |k 負載平衡" +echo "安装负载均衡 k loadbalance |k 负载均衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" @@ -21614,7 +21876,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" +echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統資訊 k info" echo "ROOT金鑰管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " @@ -21808,7 +22070,7 @@ else shift case $1 in install|安装) - send_stats "快捷安装docker" + send_stats "快速安裝docker" install_docker ;; ps|容器) From b8949aa3932a0afcc31e6b2304b5d6fe08fcc167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:13:05 +0800 Subject: [PATCH 1145/1285] Add files via upload --- hermes_manager.sh | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 hermes_manager.sh diff --git a/hermes_manager.sh b/hermes_manager.sh new file mode 100644 index 000000000..6f2137b57 --- /dev/null +++ b/hermes_manager.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# Hermes Agent 终端管理脚本 (轻量版) +# 设计哲学:极简、直观、调用原生功能 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +# 确保 hermes 命令可用 (处理环境变量未加载的情况) +if ! command -v hermes >/dev/null 2>&1; then + if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then + export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" + fi +fi + +# 检查是否安装 +check_installed() { + if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi +} + +# 获取版本号 +get_version() { + if check_installed; then + hermes --version | head -n 1 + else + echo "未安装" + fi +} + +# 获取网关状态 +get_gateway_status() { + if check_installed; then + # 匹配后台 gateway 进程或 systemd 服务 + if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then + echo -e "${GREEN}运行中${NC}" + else + echo -e "${RED}已停止${NC}" + fi + else + echo -e "${RED}未安装${NC}" + fi +} + +# 主菜单UI +show_menu() { + clear + echo -e "${CYAN}=================================================${NC}" + echo -e "${YELLOW} Hermes Agent 终端管理工具 ${NC}" + echo -e "${CYAN}=================================================${NC}" + echo -e " 运行状态 : $(get_gateway_status)" + echo -e " 当前版本 : $(get_version)" + echo -e "${CYAN}-------------------------------------------------${NC}" + echo -e "${GREEN}1.${NC} 安装 Hermes Agent" + echo -e "${GREEN}2.${NC} 启动 Gateway (消息网关/后台服务)" + echo -e "${GREEN}3.${NC} 停止 Gateway" + echo -e "${GREEN}4.${NC} API/模型管理 (提供商与模型切换)" + echo -e "${GREEN}5.${NC} 启动终端对话UI (Interactive Chat)" + echo -e "${GREEN}6.${NC} 运行初始化配置向导 (Setup Wizard)" + echo -e "${GREEN}7.${NC} 检查并更新 Hermes" + echo -e "${GREEN}8.${NC} 卸载 Hermes" + echo -e "${GREEN}0.${NC} 退出" + echo -e "${CYAN}=================================================${NC}" + if ! read -p " 请输入数字 [0-8]: " choice; then + echo -e "\n${GREEN}退出脚本。${NC}" + exit 0 + fi + echo "" + + case $choice in + 1) + echo -e "${YELLOW}开始安装 Hermes Agent...${NC}" + curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash + ;; + 2) + if check_installed; then + echo -e "${YELLOW}正在启动 Gateway...${NC}" + hermes gateway start + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 3) + if check_installed; then + echo -e "${YELLOW}正在停止 Gateway...${NC}" + hermes gateway stop + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 4) + if check_installed; then + echo -e "${YELLOW}进入模型配置向导...${NC}" + hermes model + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 5) + if check_installed; then + echo -e "${YELLOW}即将进入交互式终端,输入 /exit 即可退出返回。${NC}" + sleep 1 + hermes + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 6) + if check_installed; then + echo -e "${YELLOW}正在启动初始化配置向导...${NC}" + hermes setup + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 7) + if check_installed; then + echo -e "${YELLOW}正在检查更新...${NC}" + hermes update + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 8) + if check_installed; then + read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + hermes uninstall + else echo "已取消。"; fi + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 0) + echo -e "${GREEN}感谢使用,再见!${NC}" + exit 0 + ;; + *) + echo -e "${RED}输入错误,请重新选择。${NC}" + ;; + esac + echo "" + read -p "按回车键返回主菜单..." +} + +# 主循环 +while true; do + show_menu +done From 20fcfebf1493c994836f478c63f08d6bcf1ca12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:21:27 +0800 Subject: [PATCH 1146/1285] Update kejilion.sh --- cn/kejilion.sh | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b32043b4e..c97a56779 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "换模型" @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "插件管理" while true; do @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) # 若 CLI 不支持则回退直接写文件 local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14512,7 +14512,7 @@ print(json.dumps(data, indent=2)) echo " Exec 限制: ${current_sec:-(unset)}" echo " 审批提示: ${current_ask:-(unset)}" echo " 提权开关: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14563,7 +14563,7 @@ except Exception: openclaw_permission_apply_standard() { send_stats "OpenClaw权限-标准安全模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 @@ -14571,10 +14571,10 @@ except Exception: openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "正在配置宿主机审批拦截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" } @@ -14582,17 +14582,17 @@ except Exception: openclaw_permission_apply_developer() { send_stats "OpenClaw权限-开发增强模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在配置宿主机审批拦截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } @@ -14600,18 +14600,18 @@ except Exception: openclaw_permission_apply_full() { send_stats "OpenClaw权限-完全开放模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在瓦解宿主机拦截防御..." # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" } @@ -14619,14 +14619,14 @@ except Exception: openclaw_permission_restore_official_defaults() { send_stats "OpenClaw权限-恢复官方默认" openclaw_permission_require_openclaw || return 1 - + echo "清理应用层强制覆盖..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "清理宿主机拦截配置..." # 优先通过 CLI 清空审批配置,回退直接删文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,7 +14634,7 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" } @@ -15579,6 +15579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -19246,6 +19247,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear From d353ed129cf7109a7ae07b8fef0e20916a1b9800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:22:19 +0800 Subject: [PATCH 1147/1285] Bump version to 4.4.10 and remove extra whitespace Update version from 4.4.9 to 4.4.10 and clean up whitespace. --- kejilion.sh | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 1061b8bfc..57493096e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "换模型" @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # 若 gum 不存在,降级为原始手动输入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "插件管理" while true; do @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) # 若 CLI 不支持则回退直接写文件 local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14512,7 +14512,7 @@ print(json.dumps(data, indent=2)) echo " Exec 限制: ${current_sec:-(unset)}" echo " 审批提示: ${current_ask:-(unset)}" echo " 提权开关: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[底层 Exec Approvals 状态]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14563,7 +14563,7 @@ except Exception: openclaw_permission_apply_standard() { send_stats "OpenClaw权限-标准安全模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 @@ -14571,10 +14571,10 @@ except Exception: openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "正在配置宿主机审批拦截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" } @@ -14582,17 +14582,17 @@ except Exception: openclaw_permission_apply_developer() { send_stats "OpenClaw权限-开发增强模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在配置宿主机审批拦截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } @@ -14600,18 +14600,18 @@ except Exception: openclaw_permission_apply_full() { send_stats "OpenClaw权限-完全开放模式" openclaw_permission_require_openclaw || return 1 - + echo "正在配置应用层策略..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在瓦解宿主机拦截防御..." # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" } @@ -14619,14 +14619,14 @@ except Exception: openclaw_permission_restore_official_defaults() { send_stats "OpenClaw权限-恢复官方默认" openclaw_permission_require_openclaw || return 1 - + echo "清理应用层强制覆盖..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "清理宿主机拦截配置..." # 优先通过 CLI 清空审批配置,回退直接删文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,7 +14634,7 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" } @@ -15579,6 +15579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -19246,6 +19247,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear From 1e7536b02ad6c8777b3df31cec09713cd53a5584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:25:51 +0800 Subject: [PATCH 1148/1285] Update kejilion_sh_log.txt with new features --- kejilion_sh_log.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index c347233d3..7ddf370a0 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1504,4 +1504,7 @@ OpenClaw菜单新增 k claw 快捷入口。 OpenClaw菜单新增权限管理,多智能体管理。 OpenClaw菜单对接机器人管理 新增微信官方接入与状态显示。 OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入方式。 +------------------------ +2026-04-09 v4.4.10 +应用市场新增 Hermes Agent 项目安装与管理的工具。快捷命令 k app 115 From dd18971267f95c72ebae0b11caa8fea16bf5d617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:32:00 +0800 Subject: [PATCH 1149/1285] Update hermes_manager.sh --- hermes_manager.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 6f2137b57..30df476be 100644 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -78,13 +78,17 @@ show_menu() { if check_installed; then echo -e "${YELLOW}正在启动 Gateway...${NC}" hermes gateway start - else echo -e "${RED}请先安装 Hermes。${NC}"; fi + else + hermes gateway install + fi ;; 3) if check_installed; then echo -e "${YELLOW}正在停止 Gateway...${NC}" hermes gateway stop - else echo -e "${RED}请先安装 Hermes。${NC}"; fi + else + hermes gateway install + fi ;; 4) if check_installed; then From e671cea5e26b1db2032c8882786f61c1875a418b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:34:40 +0800 Subject: [PATCH 1150/1285] Update hermes_manager.sh --- hermes_manager.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 30df476be..6f2137b57 100644 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -78,17 +78,13 @@ show_menu() { if check_installed; then echo -e "${YELLOW}正在启动 Gateway...${NC}" hermes gateway start - else - hermes gateway install - fi + else echo -e "${RED}请先安装 Hermes。${NC}"; fi ;; 3) if check_installed; then echo -e "${YELLOW}正在停止 Gateway...${NC}" hermes gateway stop - else - hermes gateway install - fi + else echo -e "${RED}请先安装 Hermes。${NC}"; fi ;; 4) if check_installed; then From 3503765a5142807f109993796c8ab0b94590a89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:46:25 +0800 Subject: [PATCH 1151/1285] Start hermes-gateway service before running gateway --- hermes_manager.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/hermes_manager.sh b/hermes_manager.sh index 6f2137b57..5b8be8a83 100644 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -77,6 +77,7 @@ show_menu() { 2) if check_installed; then echo -e "${YELLOW}正在启动 Gateway...${NC}" + systemctl --user start hermes-gateway hermes gateway start else echo -e "${RED}请先安装 Hermes。${NC}"; fi ;; From 8f4fe212172b953c29f7e575627c919697df39ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:50:56 +0800 Subject: [PATCH 1152/1285] =?UTF-8?q?Remove=20'=E6=9C=AA=E5=AE=89=E8=A3=85?= =?UTF-8?q?'=20message=20from=20get=5Fversion=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hermes_manager.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 5b8be8a83..27d4c547f 100644 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -25,8 +25,6 @@ check_installed() { get_version() { if check_installed; then hermes --version | head -n 1 - else - echo "未安装" fi } From 5697abff2239f32cd73d16313bbbe00af4cc92c9 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 9 Apr 2026 21:45:23 +0800 Subject: [PATCH 1153/1285] feat: upgrade hermes_manager.sh to v2.0 with OpenClaw logic and fix curl headers --- hermes_manager.sh | 637 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 501 insertions(+), 136 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 27d4c547f..b243a0d32 100644 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -1,136 +1,501 @@ -#!/bin/bash -# Hermes Agent 终端管理脚本 (轻量版) -# 设计哲学:极简、直观、调用原生功能 - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -CYAN='\033[0;36m' -NC='\033[0m' - -# 确保 hermes 命令可用 (处理环境变量未加载的情况) -if ! command -v hermes >/dev/null 2>&1; then - if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then - export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" - fi -fi - -# 检查是否安装 -check_installed() { - if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi -} - -# 获取版本号 -get_version() { - if check_installed; then - hermes --version | head -n 1 - fi -} - -# 获取网关状态 -get_gateway_status() { - if check_installed; then - # 匹配后台 gateway 进程或 systemd 服务 - if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then - echo -e "${GREEN}运行中${NC}" - else - echo -e "${RED}已停止${NC}" - fi - else - echo -e "${RED}未安装${NC}" - fi -} - -# 主菜单UI -show_menu() { - clear - echo -e "${CYAN}=================================================${NC}" - echo -e "${YELLOW} Hermes Agent 终端管理工具 ${NC}" - echo -e "${CYAN}=================================================${NC}" - echo -e " 运行状态 : $(get_gateway_status)" - echo -e " 当前版本 : $(get_version)" - echo -e "${CYAN}-------------------------------------------------${NC}" - echo -e "${GREEN}1.${NC} 安装 Hermes Agent" - echo -e "${GREEN}2.${NC} 启动 Gateway (消息网关/后台服务)" - echo -e "${GREEN}3.${NC} 停止 Gateway" - echo -e "${GREEN}4.${NC} API/模型管理 (提供商与模型切换)" - echo -e "${GREEN}5.${NC} 启动终端对话UI (Interactive Chat)" - echo -e "${GREEN}6.${NC} 运行初始化配置向导 (Setup Wizard)" - echo -e "${GREEN}7.${NC} 检查并更新 Hermes" - echo -e "${GREEN}8.${NC} 卸载 Hermes" - echo -e "${GREEN}0.${NC} 退出" - echo -e "${CYAN}=================================================${NC}" - if ! read -p " 请输入数字 [0-8]: " choice; then - echo -e "\n${GREEN}退出脚本。${NC}" - exit 0 - fi - echo "" - - case $choice in - 1) - echo -e "${YELLOW}开始安装 Hermes Agent...${NC}" - curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash - ;; - 2) - if check_installed; then - echo -e "${YELLOW}正在启动 Gateway...${NC}" - systemctl --user start hermes-gateway - hermes gateway start - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 3) - if check_installed; then - echo -e "${YELLOW}正在停止 Gateway...${NC}" - hermes gateway stop - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 4) - if check_installed; then - echo -e "${YELLOW}进入模型配置向导...${NC}" - hermes model - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 5) - if check_installed; then - echo -e "${YELLOW}即将进入交互式终端,输入 /exit 即可退出返回。${NC}" - sleep 1 - hermes - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 6) - if check_installed; then - echo -e "${YELLOW}正在启动初始化配置向导...${NC}" - hermes setup - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 7) - if check_installed; then - echo -e "${YELLOW}正在检查更新...${NC}" - hermes update - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 8) - if check_installed; then - read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm - if [[ "$confirm" =~ ^[Yy]$ ]]; then - hermes uninstall - else echo "已取消。"; fi - else echo -e "${RED}请先安装 Hermes。${NC}"; fi - ;; - 0) - echo -e "${GREEN}感谢使用,再见!${NC}" - exit 0 - ;; - *) - echo -e "${RED}输入错误,请重新选择。${NC}" - ;; - esac - echo "" - read -p "按回车键返回主菜单..." -} - -# 主循环 -while true; do - show_menu -done + 1|<<<<<<< HEAD + 2|#!/bin/bash + 3|# Hermes Agent 终端管理脚本 (轻量版) + 4|# 设计哲学:极简、直观、调用原生功能 + 5| + 6|# 颜色定义 + 7|RED='\033[0;31m' + 8|GREEN='\033[0;32m' + 9|YELLOW='\033[1;33m' + 10|CYAN='\033[0;36m' + 11|NC='\033[0m' + 12| + 13|# 确保 hermes 命令可用 (处理环境变量未加载的情况) + 14|if ! command -v hermes >/dev/null 2>&1; then + 15| if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then + 16| export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" + 17| fi + 18|fi + 19| + 20|# 检查是否安装 + 21|check_installed() { + 22| if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi + 23|} + 24| + 25|# 获取版本号 + 26|get_version() { + 27| if check_installed; then + 28| hermes --version | head -n 1 + 29| fi + 30|} + 31| + 32|# 获取网关状态 + 33|get_gateway_status() { + 34| if check_installed; then + 35| # 匹配后台 gateway 进程或 systemd 服务 + 36| if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then + 37| echo -e "${GREEN}运行中${NC}" + 38| else + 39| echo -e "${RED}已停止${NC}" + 40| fi + 41| else + 42| echo -e "${RED}未安装${NC}" + 43| fi + 44|} + 45| + 46|# 主菜单UI + 47|show_menu() { + 48| clear + 49| echo -e "${CYAN}=================================================${NC}" + 50| echo -e "${YELLOW} Hermes Agent 终端管理工具 ${NC}" + 51| echo -e "${CYAN}=================================================${NC}" + 52| echo -e " 运行状态 : $(get_gateway_status)" + 53| echo -e " 当前版本 : $(get_version)" + 54| echo -e "${CYAN}-------------------------------------------------${NC}" + 55| echo -e "${GREEN}1.${NC} 安装 Hermes Agent" + 56| echo -e "${GREEN}2.${NC} 启动 Gateway (消息网关/后台服务)" + 57| echo -e "${GREEN}3.${NC} 停止 Gateway" + 58| echo -e "${GREEN}4.${NC} API/模型管理 (提供商与模型切换)" + 59| echo -e "${GREEN}5.${NC} 启动终端对话UI (Interactive Chat)" + 60| echo -e "${GREEN}6.${NC} 运行初始化配置向导 (Setup Wizard)" + 61| echo -e "${GREEN}7.${NC} 检查并更新 Hermes" + 62| echo -e "${GREEN}8.${NC} 卸载 Hermes" + 63| echo -e "${GREEN}0.${NC} 退出" + 64| echo -e "${CYAN}=================================================${NC}" + 65| if ! read -p " 请输入数字 [0-8]: " choice; then + 66| echo -e "\n${GREEN}退出脚本。${NC}" + 67| exit 0 + 68| fi + 69| echo "" + 70| + 71| case $choice in + 72| 1) + 73| echo -e "${YELLOW}开始安装 Hermes Agent...${NC}" + 74| curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash + 75| source ~/.bashrc + 76| hermes gateway install + 77| hermes gateway start + 78| + 79| ;; + 80| 2) + 81| if check_installed; then + 82| echo -e "${YELLOW}正在启动 Gateway...${NC}" + 83| hermes gateway stop + 84| hermes gateway start + 85| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 86| ;; + 87| 3) + 88| if check_installed; then + 89| echo -e "${YELLOW}正在停止 Gateway...${NC}" + 90| hermes gateway stop + 91| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 92| ;; + 93| 4) + 94| if check_installed; then + 95| echo -e "${YELLOW}进入模型配置向导...${NC}" + 96| hermes model + 97| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 98| ;; + 99| 5) + 100| if check_installed; then + 101| echo -e "${YELLOW}即将进入交互式终端,输入 /exit 即可退出返回。${NC}" + 102| sleep 1 + 103| hermes + 104| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 105| ;; + 106| 6) + 107| if check_installed; then + 108| echo -e "${YELLOW}正在启动初始化配置向导...${NC}" + 109| hermes setup + 110| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 111| ;; + 112| 7) + 113| if check_installed; then + 114| echo -e "${YELLOW}正在检查更新...${NC}" + 115| hermes update + 116| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 117| ;; + 118| 8) + 119| if check_installed; then + 120| read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm + 121| if [[ "$confirm" =~ ^[Yy]$ ]]; then + 122| hermes uninstall + 123| else echo "已取消。"; fi + 124| else echo -e "${RED}请先安装 Hermes。${NC}"; fi + 125| ;; + 126| 0) + 127| echo -e "${GREEN}感谢使用,再见!${NC}" + 128| exit 0 + 129| ;; + 130| *) + 131| echo -e "${RED}输入错误,请重新选择。${NC}" + 132| ;; + 133| esac + 134| echo "" + 135| read -p "按回车键返回主菜单..." + 136|} + 137| + 138|# 主循环 + 139|while true; do + 140| show_menu + 141|done + 142|======= + 143| 1|#!/bin/bash + 144| 2|# Hermes Agent 终端管理脚本 v2.1 + 145| 3|# 借鉴 OpenClaw 管理模块,适配 Hermes Agent 配置体系 + 146| 4|# 设计哲学:极简、直观、Python yaml 安全读写(不依赖 yq) + 147| 5| + 148| 6|# 颜色定义 + 149| 7|RED='\033[0;31m' + 150| 8|GREEN='\033[0;32m' + 151| 9|YELLOW='\033[1;33m' + 152| 10|CYAN='\033[0;36m' + 153| 11|PURPLE='\033[0;35m' + 154| 12|DIM='\033[2m' + 155| 13|NC='\033[0m' + 156| 14| + 157| 15|# 确保 hermes 命令可用 (处理环境变量未加载的情况) + 158| 16|if ! command -v hermes >/dev/null 2>&1; then + 159| 17| if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then + 160| 18| export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" + 161| 19| fi + 162| 20|fi + 163| 21| + 164| 22|# 配置文件路径 + 165| 23|HERMES_CONFIG="${HOME}/.hermes/config.yaml" + 166| 24| + 167| 25|# ============================================================ + 168| 26|# 通用工具函数 + 169| 27|# ============================================================ + 170| 28| + 171| 29|check_installed() { + 172| 30| if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi + 173| 31|} + 174| 32| + 175| 33|get_version() { + 176| 34| if check_installed; then + 177| 35| hermes --version 2>/dev/null | head -n 1 + 178| 36| fi + 179| 37|} + 180| 38| + 181| 39|get_gateway_status() { + 182| 40| if check_installed; then + 183| 41| if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then + 184| 42| echo -e "${GREEN}运行中${NC}" + 185| 43| else + 186| 44| echo -e "${RED}已停止${NC}" + 187| 45| fi + 188| 46| else + 189| 47| echo -e "${RED}未安装${NC}" + 190| 48| fi + 191| 49|} + 192| 50| + 193| 51|# 获取当前模型 + 194| 52|get_current_model() { + 195| 53| if [ ! -f "$HERMES_CONFIG" ]; then echo -e "${DIM}(未知)${NC}"; return; fi + 196| 54| python3 - "$HERMES_CONFIG" <<'PY' + 197| 55|import sys, yaml + 198| 56|with open(sys.argv[1], 'r') as f: + 199| 57| cfg = yaml.safe_load(f) + 200| 58|m = cfg.get('model', {}) + 201| 59|default = m.get('default', '') if isinstance(m, dict) else '' + 202| 60|if default: + 203| 61| print(f'\033[0;32m{default}\033[0m') + 204| 62|else: + 205| 63| print('\033[2m(未设置)\033[0m') + 206| 64|PY + 207| 65|} + 208| 66| + 209| 67|# 检查 python3 + yaml 可用 + 210| 68|ensure_python_yaml() { + 211| 69| if ! python3 -c "import yaml" 2>/dev/null; then + 212| 70| pip3 install pyyaml -q 2>/dev/null || pip install pyyaml -q 2>/dev/null + 213| 71| fi + 214| 72|} + 215| 73| + 216| 74|# 安装 jq(若缺失) + 217| 75|ensure_jq() { + 218| 76| if ! command -v jq >/dev/null 2>&1; then + 219| 77| echo -e "${YELLOW}正在安装 jq...${NC}" + 220| 78| if command -v apt >/dev/null 2>&1; then + 221| 79| apt update -qq && apt install -y -qq jq + 222| 80| elif command -v dnf >/dev/null 2>&1; then + 223| 81| dnf install -y jq + 224| 82| elif command -v yum >/dev/null 2>&1; then + 225| 83| yum install -y jq + 226| 84| fi + 227| 85| fi + 228| 86|} + 229| 87| + 230| 88|# 用 Python 读取 custom_providers,输出 JSON 数组 + 231| 89|read_providers_json() { + 232| 90| ensure_python_yaml + 233| 91| python3 - "$HERMES_CONFIG" <<'PY' + 234| 92|import sys, json, yaml + 235| 93|with open(sys.argv[1], 'r') as f: + 236| 94| cfg = yaml.safe_load(f) + 237| 95|providers = cfg.get('custom_providers', []) + 238| 96|json.dump(providers, sys.stdout, ensure_ascii=False) + 239| 97|PY + 240| 98|} + 241| 99| + 242| 100|# 重启 Gateway + 243| 101|restart_gateway() { + 244| 102| echo -e "${YELLOW}正在重启 Gateway...${NC}" + 245| 103| hermes gateway stop 2>/dev/null + 246| 104| sleep 1 + 247| 105| systemctl --user start hermes-gateway 2>/dev/null + 248| 106| hermes gateway start 2>/dev/null + 249| 107| echo -e "${GREEN}Gateway 已重启${NC}" + 250| 108|} + 251| 109| + 252| 110|# ============================================================ + 253| 111|# API 管理子菜单 + 254| 112|# ============================================================ + 255| 113| + 256| 114|hermes_api_list() { + 257| 115| echo "" + 258| 116| echo -e "${CYAN}--- 已配置 API 列表 ---${NC}" + 259| 117| + 260| 118| if [ ! -f "$HERMES_CONFIG" ]; then + 261| 119| echo -e "${RED}未找到配置文件: $HERMES_CONFIG${NC}" + 262| 120| return 1 + 263| 121| fi + 264| 122| + 265| 123| python3 - "$HERMES_CONFIG" <<'PY' + 266| 124|import sys, yaml, json, time, urllib.request + 267| 125| + 268| 126|GREEN = '\033[0;32m' + 269| 127|YELLOW = '\033[1;33m' + 270| 128|RED = '\033[0;31m' + 271| 129|DIM = '\033[2m' + 272| 130|NC = '\033[0m' + 273| 131| + 274| 132|with open(sys.argv[1], 'r') as f: + 275| 133| cfg = yaml.safe_load(f) + 276| 134| + 277| 135|providers = cfg.get('custom_providers', []) + 278| 136|if not providers: + 279| 137| print(f'{DIM}当前未配置任何 API provider。{NC}') + 280| 138| sys.exit(0) + 281| 139| + 282| 140|for idx, p in enumerate(providers, start=1): + 283| 141| name = p.get('name', '-') + 284| 142| base_url = p.get('base_url', '-') + 285| 143| model = p.get('model', '-') + 286| 144| api_key = p.get('api_key', '') + 287| 145| masked_key = f"{api_key[:8]}****" if len(str(api_key)) > 8 else "****" + 288| 146| + 289| 147| # Ping 延迟 + 290| 148| latency_raw = "未检测" + 291| 149| latency_level = "unchecked" + 292| 150| if base_url and base_url != '-' and api_key: + 293| 151| try: + 294| 152| url = base_url.rstrip('/') + '/models' + 295| 153| req = urllib.request.Request(url, headers={ + 296| 154| 'Authorization': f'Bearer {api_key}', + 297| 155| 'User-Agent': 'Hermes-Manager/1.0', + 298| 156| }) + 299| 157| start = time.perf_counter() + 300| 158| with urllib.request.urlopen(req, timeout=4) as resp: + 301| 159| resp.read(2048) + 302| 160| ms = int((time.perf_counter() - start) * 1000) + 303| 161| latency_raw = f"{ms}ms" + 304| 162| latency_level = 'low' if ms <= 800 else ('medium' if ms <= 2000 else 'high') + 305| 163| except Exception: + 306| 164| latency_raw = "不可用" + 307| 165| latency_level = "unavailable" + 308| 166| + 309| 167| if latency_level == 'low': latency_color = GREEN + 310| 168| elif latency_level == 'medium': latency_color = YELLOW + 311| 169| elif latency_level == 'unavailable': latency_color = RED + 312| 170| else: latency_color = DIM + 313| 171| + 314| 172| print(f" [{idx}] {name}") + 315| 173| print(f" URL: {base_url} Key: {masked_key} 模型: {YELLOW}{model}{NC} 延迟: {latency_color}{latency_raw}{NC}") + 316| 174| + 317| 175|PY + 318| 176|} + 319| 177| + 320| 178|# 添加 API Provider + 321| 179|hermes_api_add() { + 322| 180| echo "" + 323| 181| echo -e "${CYAN}=== 交互式添加 Hermes API Provider ===${NC}" + 324| 182| + 325| 183| # Provider 名称 + 326| 184| read -erp "请输入 Provider 名称 (如: deepseek): " provider_name + 327| 185| while [[ -z "$provider_name" ]]; do + 328| 186| echo -e "${RED}Provider 名称不能为空${NC}" + 329| 187| read -erp "请输入 Provider 名称: " provider_name + 330| 188| done + 331| 189| + 332| 190| # Base URL + 333| 191| read -erp "请输入 Base URL (如: https://api.deepseek.com/v1): " base_url + 334| 192| while [[ -z "$base_url" ]]; do + 335| 193| echo -e "${RED}Base URL 不能为空${NC}" + 336| 194| read -erp "请输入 Base URL: " base_url + 337| 195| done + 338| 196| base_url="${base_url%/}" + 339| 197| + 340| 198| # API Key + 341| 199| stty -echo + 342| 200| read -r -p "请输入 API Key (输入不显示): " api_key + 343| 201| stty echo + 344| 202| echo + 345| 203| while [[ -z "$api_key" ]]; do + 346| 204| echo -e "${RED}API Key 不能为空${NC}" + 347| 205| stty -echo + 348| 206| read -r -p "请输入 API Key: " api_key + 349| 207| stty echo + 350| 208| echo + 351| 209| done + 352| 210| + 353| 211| # 获取模型列表 + 354| 212| echo -e "${YELLOW}正在获取可用模型列表...${NC}" + 355| 213| models_json=$(curl -s -m 10 \ + 356| 214| -H "Authorization: Bearer *** \ + 357| 215| "${base_url}/models" 2>/dev/null) + 358| 216| + 359| 217| available_models="" + 360| 218| model_count=0 + 361| 219| model_list=() + 362| 220| if [[ -n "$models_json" ]]; then + 363| 221| ensure_jq + 364| 222| available_models=$(echo "$models_json" | jq -r '.data[]?.id // empty' 2>/dev/null | sort) + 365| 223| if [[ -n "$available_models" ]]; then + 366| 224| model_count=$(echo "$available_models" | wc -l | tr -d ' ') + 367| 225| echo -e "${GREEN}发现 ${model_count} 个可用模型:${NC}" + 368| 226| echo "--------------------------------" + 369| 227| i=1 + 370| 228| while read -r model; do + 371| 229| echo "[$i] $model" + 372| 230| model_list+=("$model") + 373| 231| ((i++)) + 374| 232| done <<< "$available_models" + 375| 233| echo "--------------------------------" + 376| 234| fi + 377| 235| fi + 378| 236| + 379| 237| # 如果获取失败,手动输入 + 380| 238| if [[ $model_count -eq 0 ]]; then + 381| 239| echo -e "${YELLOW}未能自动获取模型列表,请手动输入。${NC}" + 382| 240| read -erp "请输入默认 Model ID: " default_model + 383| 241| while [[ -z "$default_model" ]]; do + 384| 242| echo -e "${RED}Model ID 不能为空${NC}" + 385| 243| read -erp "请输入 Model ID: " default_model + 386| 244| done + 387| 245| else + 388| 246| # 选择默认模型 + 389| 247| echo + 390| 248| read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model + 391| 249| if [[ -z "$input_model" ]]; then + 392| 250| default_model=$(echo "$available_models" | head -1) + 393| 251| echo -e "使用第一个模型: ${GREEN}${default_model}${NC}" + 394| 252| elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then + 395| 253| default_model="${model_list[$((input_model-1))]}" + 396| 254| echo -e "已选择模型: ${GREEN}${default_model}${NC}" + 397| 255| else + 398| 256| default_model="$input_model" + 399| 257| fi + 400| 258| fi + 401| 259| + 402| 260| # 确认信息 + 403| 261| echo + 404| 262| echo "====== 确认信息 ======" + 405| 263| echo "Provider : $provider_name" + 406| 264| echo "Base URL : $base_url" + 407| 265| echo "API Key : ${api_key:0:8}****" + 408| 266| echo "默认模型 : $default_model" + 409| 267| echo "======================" + 410| 268| + 411| 269| # 写入配置 + 412| 270| echo -e "${YELLOW}正在写入配置...${NC}" + 413| 271| + 414| 272| python3 - "$HERMES_CONFIG" "$provider_name" "$base_url" "$api_key" "$default_model" <<'PY' + 415| 273|import sys, yaml, shutil + 416| 274| + 417| 275|path = sys.argv[1] + 418| 276|name = sys.argv[2] + 419| 277|base_url = sys.argv[3] + 420| 278|api_key = sys.argv[4] + 421| 279|model = sys.argv[5] + 422| 280| + 423| 281|with open(path, 'r', encoding='utf-8') as f: + 424| 282| cfg = yaml.safe_load(f) + 425| 283| + 426| 284|providers = cfg.get('custom_providers', []) + 427| 285| + 428| 286|# 检查是否已存在同名 provider + 429| 287|existing_idx = None + 430| 288|for i, p in enumerate(providers): + 431| 289| if p.get('name') == name: + 432| 290| existing_idx = i + 433| 291| break + 434| 292| + 435| 293|new_provider = { + 436| 294| 'name': name, + 437| 295| 'base_url': base_url, + 438| 296| 'api_key': api_key, + 439| 297| 'model': model, + 440| 298|} + 441| 299| + 442| 300|if existing_idx is not None: + 443| 301| providers[existing_idx] = new_provider + 444| 302| print(f'已更新同名 provider: {name}') + 445| 303|else: + 446| 304| providers.append(new_provider) + 447| 305| print(f'已添加 provider: {name}') + 448| 306| + 449| 307|cfg['custom_providers'] = providers + 450| 308| + 451| 309|# 备份 + 452| 310|shutil.copy2(path, path + '.bak') + 453| 311| + 454| 312|with open(path, 'w', encoding='utf-8') as f: + 455| 313| yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True, sort_keys=False) + 456| 314| + 457| 315|print('OK') + 458| 316|PY + 459| 317| + 460| 318| if [ $? -eq 0 ]; then + 461| 319| echo -e "${GREEN}已成功添加 provider: ${provider_name}${NC}" + 462| 320| + 463| 321| # 询问是否切换为当前使用 + 464| 322| echo + 465| 323| read -erp "是否立即切换到该 provider?(y/N): " switch_now + 466| 324| if [[ "$switch_now" =~ ^[Yy]$ ]]; then + 467| 325| hermes_switch_to_provider "$provider_name" + 468| 326| fi + 469| 327| else + 470| 328| echo -e "${RED}配置写入失败${NC}" + 471| 329| fi + 472| 330|} + 473| 331| + 474| 332|# 切换到指定 provider + 475| 333|hermes_switch_to_provider() { + 476| 334| local target_name="$1" + 477| 335| + 478| 336| if [ -z "$target_name" ]; then + 479| 337| read -erp "请输入要切换的 Provider 名称: " target_name + 480| 338| fi + 481| 339| + 482| 340| python3 - "$HERMES_CONFIG" "$target_name" <<'PY' + 483| 341|import sys, yaml, shutil + 484| 342| + 485| 343|path = sys.argv[1] + 486| 344|target = sys.argv[2] + 487| 345| + 488| 346|with open(path, 'r', encoding='utf-8') as f: + 489| 347| cfg = yaml.safe_load(f) + 490| 348| + 491| 349|providers = cfg.get('custom_providers', []) + 492| 350|target_p = None + 493| 351|for p in providers: + 494| 352| if p.get('name') == target: + 495| 353| target_p = p + 496| 354| break + 497| 355| + 498| 356|if target_p is None: + 499| 357| print(f'ERROR: 未找到 provider: {target}') + 500| 358| sys.exit(1) + 501| \ No newline at end of file From 2c572917f033a863133008e2e257eb308b13accd Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 23 Apr 2026 12:04:27 +0800 Subject: [PATCH 1154/1285] chore: remove redundant sync_openclaw_api_models logic in health check --- cn/kejilion.sh | 8 +- en/kejilion.sh | 7 +- hermes_manager.sh | 1132 +++++++++++++++++++++++++-------------------- jp/kejilion.sh | 7 +- kejilion.sh | 10 +- kr/kejilion.sh | 7 +- tw/kejilion.sh | 7 +- 7 files changed, 638 insertions(+), 540 deletions(-) mode change 100644 => 100755 hermes_manager.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index c97a56779..3506f4670 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -15449,14 +15449,8 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "健康检测与修复" openclaw doctor --fix - send_stats "OpenClaw API同步触发" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" - fi break_end - ;; + ;; 13) openclaw_webui_menu ;; 14) send_stats "TUI命令行对话" openclaw tui diff --git a/en/kejilion.sh b/en/kejilion.sh index 93e3e7fe5..540214306 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -15449,12 +15449,7 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "Health detection and repair" openclaw doctor --fix - send_stats "OpenClaw API synchronous triggering" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API model synchronization failed, restarting the gateway has been aborted. Please check provider /models and try again after returning." - fi + break_end ;; 13) openclaw_webui_menu ;; diff --git a/hermes_manager.sh b/hermes_manager.sh old mode 100644 new mode 100755 index b243a0d32..913b5f278 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -1,501 +1,631 @@ - 1|<<<<<<< HEAD - 2|#!/bin/bash - 3|# Hermes Agent 终端管理脚本 (轻量版) - 4|# 设计哲学:极简、直观、调用原生功能 - 5| - 6|# 颜色定义 - 7|RED='\033[0;31m' - 8|GREEN='\033[0;32m' - 9|YELLOW='\033[1;33m' - 10|CYAN='\033[0;36m' - 11|NC='\033[0m' - 12| - 13|# 确保 hermes 命令可用 (处理环境变量未加载的情况) - 14|if ! command -v hermes >/dev/null 2>&1; then - 15| if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then - 16| export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" - 17| fi - 18|fi - 19| - 20|# 检查是否安装 - 21|check_installed() { - 22| if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi - 23|} - 24| - 25|# 获取版本号 - 26|get_version() { - 27| if check_installed; then - 28| hermes --version | head -n 1 - 29| fi - 30|} - 31| - 32|# 获取网关状态 - 33|get_gateway_status() { - 34| if check_installed; then - 35| # 匹配后台 gateway 进程或 systemd 服务 - 36| if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then - 37| echo -e "${GREEN}运行中${NC}" - 38| else - 39| echo -e "${RED}已停止${NC}" - 40| fi - 41| else - 42| echo -e "${RED}未安装${NC}" - 43| fi - 44|} - 45| - 46|# 主菜单UI - 47|show_menu() { - 48| clear - 49| echo -e "${CYAN}=================================================${NC}" - 50| echo -e "${YELLOW} Hermes Agent 终端管理工具 ${NC}" - 51| echo -e "${CYAN}=================================================${NC}" - 52| echo -e " 运行状态 : $(get_gateway_status)" - 53| echo -e " 当前版本 : $(get_version)" - 54| echo -e "${CYAN}-------------------------------------------------${NC}" - 55| echo -e "${GREEN}1.${NC} 安装 Hermes Agent" - 56| echo -e "${GREEN}2.${NC} 启动 Gateway (消息网关/后台服务)" - 57| echo -e "${GREEN}3.${NC} 停止 Gateway" - 58| echo -e "${GREEN}4.${NC} API/模型管理 (提供商与模型切换)" - 59| echo -e "${GREEN}5.${NC} 启动终端对话UI (Interactive Chat)" - 60| echo -e "${GREEN}6.${NC} 运行初始化配置向导 (Setup Wizard)" - 61| echo -e "${GREEN}7.${NC} 检查并更新 Hermes" - 62| echo -e "${GREEN}8.${NC} 卸载 Hermes" - 63| echo -e "${GREEN}0.${NC} 退出" - 64| echo -e "${CYAN}=================================================${NC}" - 65| if ! read -p " 请输入数字 [0-8]: " choice; then - 66| echo -e "\n${GREEN}退出脚本。${NC}" - 67| exit 0 - 68| fi - 69| echo "" - 70| - 71| case $choice in - 72| 1) - 73| echo -e "${YELLOW}开始安装 Hermes Agent...${NC}" - 74| curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash - 75| source ~/.bashrc - 76| hermes gateway install - 77| hermes gateway start - 78| - 79| ;; - 80| 2) - 81| if check_installed; then - 82| echo -e "${YELLOW}正在启动 Gateway...${NC}" - 83| hermes gateway stop - 84| hermes gateway start - 85| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 86| ;; - 87| 3) - 88| if check_installed; then - 89| echo -e "${YELLOW}正在停止 Gateway...${NC}" - 90| hermes gateway stop - 91| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 92| ;; - 93| 4) - 94| if check_installed; then - 95| echo -e "${YELLOW}进入模型配置向导...${NC}" - 96| hermes model - 97| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 98| ;; - 99| 5) - 100| if check_installed; then - 101| echo -e "${YELLOW}即将进入交互式终端,输入 /exit 即可退出返回。${NC}" - 102| sleep 1 - 103| hermes - 104| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 105| ;; - 106| 6) - 107| if check_installed; then - 108| echo -e "${YELLOW}正在启动初始化配置向导...${NC}" - 109| hermes setup - 110| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 111| ;; - 112| 7) - 113| if check_installed; then - 114| echo -e "${YELLOW}正在检查更新...${NC}" - 115| hermes update - 116| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 117| ;; - 118| 8) - 119| if check_installed; then - 120| read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm - 121| if [[ "$confirm" =~ ^[Yy]$ ]]; then - 122| hermes uninstall - 123| else echo "已取消。"; fi - 124| else echo -e "${RED}请先安装 Hermes。${NC}"; fi - 125| ;; - 126| 0) - 127| echo -e "${GREEN}感谢使用,再见!${NC}" - 128| exit 0 - 129| ;; - 130| *) - 131| echo -e "${RED}输入错误,请重新选择。${NC}" - 132| ;; - 133| esac - 134| echo "" - 135| read -p "按回车键返回主菜单..." - 136|} - 137| - 138|# 主循环 - 139|while true; do - 140| show_menu - 141|done - 142|======= - 143| 1|#!/bin/bash - 144| 2|# Hermes Agent 终端管理脚本 v2.1 - 145| 3|# 借鉴 OpenClaw 管理模块,适配 Hermes Agent 配置体系 - 146| 4|# 设计哲学:极简、直观、Python yaml 安全读写(不依赖 yq) - 147| 5| - 148| 6|# 颜色定义 - 149| 7|RED='\033[0;31m' - 150| 8|GREEN='\033[0;32m' - 151| 9|YELLOW='\033[1;33m' - 152| 10|CYAN='\033[0;36m' - 153| 11|PURPLE='\033[0;35m' - 154| 12|DIM='\033[2m' - 155| 13|NC='\033[0m' - 156| 14| - 157| 15|# 确保 hermes 命令可用 (处理环境变量未加载的情况) - 158| 16|if ! command -v hermes >/dev/null 2>&1; then - 159| 17| if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then - 160| 18| export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" - 161| 19| fi - 162| 20|fi - 163| 21| - 164| 22|# 配置文件路径 - 165| 23|HERMES_CONFIG="${HOME}/.hermes/config.yaml" - 166| 24| - 167| 25|# ============================================================ - 168| 26|# 通用工具函数 - 169| 27|# ============================================================ - 170| 28| - 171| 29|check_installed() { - 172| 30| if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi - 173| 31|} - 174| 32| - 175| 33|get_version() { - 176| 34| if check_installed; then - 177| 35| hermes --version 2>/dev/null | head -n 1 - 178| 36| fi - 179| 37|} - 180| 38| - 181| 39|get_gateway_status() { - 182| 40| if check_installed; then - 183| 41| if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then - 184| 42| echo -e "${GREEN}运行中${NC}" - 185| 43| else - 186| 44| echo -e "${RED}已停止${NC}" - 187| 45| fi - 188| 46| else - 189| 47| echo -e "${RED}未安装${NC}" - 190| 48| fi - 191| 49|} - 192| 50| - 193| 51|# 获取当前模型 - 194| 52|get_current_model() { - 195| 53| if [ ! -f "$HERMES_CONFIG" ]; then echo -e "${DIM}(未知)${NC}"; return; fi - 196| 54| python3 - "$HERMES_CONFIG" <<'PY' - 197| 55|import sys, yaml - 198| 56|with open(sys.argv[1], 'r') as f: - 199| 57| cfg = yaml.safe_load(f) - 200| 58|m = cfg.get('model', {}) - 201| 59|default = m.get('default', '') if isinstance(m, dict) else '' - 202| 60|if default: - 203| 61| print(f'\033[0;32m{default}\033[0m') - 204| 62|else: - 205| 63| print('\033[2m(未设置)\033[0m') - 206| 64|PY - 207| 65|} - 208| 66| - 209| 67|# 检查 python3 + yaml 可用 - 210| 68|ensure_python_yaml() { - 211| 69| if ! python3 -c "import yaml" 2>/dev/null; then - 212| 70| pip3 install pyyaml -q 2>/dev/null || pip install pyyaml -q 2>/dev/null - 213| 71| fi - 214| 72|} - 215| 73| - 216| 74|# 安装 jq(若缺失) - 217| 75|ensure_jq() { - 218| 76| if ! command -v jq >/dev/null 2>&1; then - 219| 77| echo -e "${YELLOW}正在安装 jq...${NC}" - 220| 78| if command -v apt >/dev/null 2>&1; then - 221| 79| apt update -qq && apt install -y -qq jq - 222| 80| elif command -v dnf >/dev/null 2>&1; then - 223| 81| dnf install -y jq - 224| 82| elif command -v yum >/dev/null 2>&1; then - 225| 83| yum install -y jq - 226| 84| fi - 227| 85| fi - 228| 86|} - 229| 87| - 230| 88|# 用 Python 读取 custom_providers,输出 JSON 数组 - 231| 89|read_providers_json() { - 232| 90| ensure_python_yaml - 233| 91| python3 - "$HERMES_CONFIG" <<'PY' - 234| 92|import sys, json, yaml - 235| 93|with open(sys.argv[1], 'r') as f: - 236| 94| cfg = yaml.safe_load(f) - 237| 95|providers = cfg.get('custom_providers', []) - 238| 96|json.dump(providers, sys.stdout, ensure_ascii=False) - 239| 97|PY - 240| 98|} - 241| 99| - 242| 100|# 重启 Gateway - 243| 101|restart_gateway() { - 244| 102| echo -e "${YELLOW}正在重启 Gateway...${NC}" - 245| 103| hermes gateway stop 2>/dev/null - 246| 104| sleep 1 - 247| 105| systemctl --user start hermes-gateway 2>/dev/null - 248| 106| hermes gateway start 2>/dev/null - 249| 107| echo -e "${GREEN}Gateway 已重启${NC}" - 250| 108|} - 251| 109| - 252| 110|# ============================================================ - 253| 111|# API 管理子菜单 - 254| 112|# ============================================================ - 255| 113| - 256| 114|hermes_api_list() { - 257| 115| echo "" - 258| 116| echo -e "${CYAN}--- 已配置 API 列表 ---${NC}" - 259| 117| - 260| 118| if [ ! -f "$HERMES_CONFIG" ]; then - 261| 119| echo -e "${RED}未找到配置文件: $HERMES_CONFIG${NC}" - 262| 120| return 1 - 263| 121| fi - 264| 122| - 265| 123| python3 - "$HERMES_CONFIG" <<'PY' - 266| 124|import sys, yaml, json, time, urllib.request - 267| 125| - 268| 126|GREEN = '\033[0;32m' - 269| 127|YELLOW = '\033[1;33m' - 270| 128|RED = '\033[0;31m' - 271| 129|DIM = '\033[2m' - 272| 130|NC = '\033[0m' - 273| 131| - 274| 132|with open(sys.argv[1], 'r') as f: - 275| 133| cfg = yaml.safe_load(f) - 276| 134| - 277| 135|providers = cfg.get('custom_providers', []) - 278| 136|if not providers: - 279| 137| print(f'{DIM}当前未配置任何 API provider。{NC}') - 280| 138| sys.exit(0) - 281| 139| - 282| 140|for idx, p in enumerate(providers, start=1): - 283| 141| name = p.get('name', '-') - 284| 142| base_url = p.get('base_url', '-') - 285| 143| model = p.get('model', '-') - 286| 144| api_key = p.get('api_key', '') - 287| 145| masked_key = f"{api_key[:8]}****" if len(str(api_key)) > 8 else "****" - 288| 146| - 289| 147| # Ping 延迟 - 290| 148| latency_raw = "未检测" - 291| 149| latency_level = "unchecked" - 292| 150| if base_url and base_url != '-' and api_key: - 293| 151| try: - 294| 152| url = base_url.rstrip('/') + '/models' - 295| 153| req = urllib.request.Request(url, headers={ - 296| 154| 'Authorization': f'Bearer {api_key}', - 297| 155| 'User-Agent': 'Hermes-Manager/1.0', - 298| 156| }) - 299| 157| start = time.perf_counter() - 300| 158| with urllib.request.urlopen(req, timeout=4) as resp: - 301| 159| resp.read(2048) - 302| 160| ms = int((time.perf_counter() - start) * 1000) - 303| 161| latency_raw = f"{ms}ms" - 304| 162| latency_level = 'low' if ms <= 800 else ('medium' if ms <= 2000 else 'high') - 305| 163| except Exception: - 306| 164| latency_raw = "不可用" - 307| 165| latency_level = "unavailable" - 308| 166| - 309| 167| if latency_level == 'low': latency_color = GREEN - 310| 168| elif latency_level == 'medium': latency_color = YELLOW - 311| 169| elif latency_level == 'unavailable': latency_color = RED - 312| 170| else: latency_color = DIM - 313| 171| - 314| 172| print(f" [{idx}] {name}") - 315| 173| print(f" URL: {base_url} Key: {masked_key} 模型: {YELLOW}{model}{NC} 延迟: {latency_color}{latency_raw}{NC}") - 316| 174| - 317| 175|PY - 318| 176|} - 319| 177| - 320| 178|# 添加 API Provider - 321| 179|hermes_api_add() { - 322| 180| echo "" - 323| 181| echo -e "${CYAN}=== 交互式添加 Hermes API Provider ===${NC}" - 324| 182| - 325| 183| # Provider 名称 - 326| 184| read -erp "请输入 Provider 名称 (如: deepseek): " provider_name - 327| 185| while [[ -z "$provider_name" ]]; do - 328| 186| echo -e "${RED}Provider 名称不能为空${NC}" - 329| 187| read -erp "请输入 Provider 名称: " provider_name - 330| 188| done - 331| 189| - 332| 190| # Base URL - 333| 191| read -erp "请输入 Base URL (如: https://api.deepseek.com/v1): " base_url - 334| 192| while [[ -z "$base_url" ]]; do - 335| 193| echo -e "${RED}Base URL 不能为空${NC}" - 336| 194| read -erp "请输入 Base URL: " base_url - 337| 195| done - 338| 196| base_url="${base_url%/}" - 339| 197| - 340| 198| # API Key - 341| 199| stty -echo - 342| 200| read -r -p "请输入 API Key (输入不显示): " api_key - 343| 201| stty echo - 344| 202| echo - 345| 203| while [[ -z "$api_key" ]]; do - 346| 204| echo -e "${RED}API Key 不能为空${NC}" - 347| 205| stty -echo - 348| 206| read -r -p "请输入 API Key: " api_key - 349| 207| stty echo - 350| 208| echo - 351| 209| done - 352| 210| - 353| 211| # 获取模型列表 - 354| 212| echo -e "${YELLOW}正在获取可用模型列表...${NC}" - 355| 213| models_json=$(curl -s -m 10 \ - 356| 214| -H "Authorization: Bearer *** \ - 357| 215| "${base_url}/models" 2>/dev/null) - 358| 216| - 359| 217| available_models="" - 360| 218| model_count=0 - 361| 219| model_list=() - 362| 220| if [[ -n "$models_json" ]]; then - 363| 221| ensure_jq - 364| 222| available_models=$(echo "$models_json" | jq -r '.data[]?.id // empty' 2>/dev/null | sort) - 365| 223| if [[ -n "$available_models" ]]; then - 366| 224| model_count=$(echo "$available_models" | wc -l | tr -d ' ') - 367| 225| echo -e "${GREEN}发现 ${model_count} 个可用模型:${NC}" - 368| 226| echo "--------------------------------" - 369| 227| i=1 - 370| 228| while read -r model; do - 371| 229| echo "[$i] $model" - 372| 230| model_list+=("$model") - 373| 231| ((i++)) - 374| 232| done <<< "$available_models" - 375| 233| echo "--------------------------------" - 376| 234| fi - 377| 235| fi - 378| 236| - 379| 237| # 如果获取失败,手动输入 - 380| 238| if [[ $model_count -eq 0 ]]; then - 381| 239| echo -e "${YELLOW}未能自动获取模型列表,请手动输入。${NC}" - 382| 240| read -erp "请输入默认 Model ID: " default_model - 383| 241| while [[ -z "$default_model" ]]; do - 384| 242| echo -e "${RED}Model ID 不能为空${NC}" - 385| 243| read -erp "请输入 Model ID: " default_model - 386| 244| done - 387| 245| else - 388| 246| # 选择默认模型 - 389| 247| echo - 390| 248| read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model - 391| 249| if [[ -z "$input_model" ]]; then - 392| 250| default_model=$(echo "$available_models" | head -1) - 393| 251| echo -e "使用第一个模型: ${GREEN}${default_model}${NC}" - 394| 252| elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then - 395| 253| default_model="${model_list[$((input_model-1))]}" - 396| 254| echo -e "已选择模型: ${GREEN}${default_model}${NC}" - 397| 255| else - 398| 256| default_model="$input_model" - 399| 257| fi - 400| 258| fi - 401| 259| - 402| 260| # 确认信息 - 403| 261| echo - 404| 262| echo "====== 确认信息 ======" - 405| 263| echo "Provider : $provider_name" - 406| 264| echo "Base URL : $base_url" - 407| 265| echo "API Key : ${api_key:0:8}****" - 408| 266| echo "默认模型 : $default_model" - 409| 267| echo "======================" - 410| 268| - 411| 269| # 写入配置 - 412| 270| echo -e "${YELLOW}正在写入配置...${NC}" - 413| 271| - 414| 272| python3 - "$HERMES_CONFIG" "$provider_name" "$base_url" "$api_key" "$default_model" <<'PY' - 415| 273|import sys, yaml, shutil - 416| 274| - 417| 275|path = sys.argv[1] - 418| 276|name = sys.argv[2] - 419| 277|base_url = sys.argv[3] - 420| 278|api_key = sys.argv[4] - 421| 279|model = sys.argv[5] - 422| 280| - 423| 281|with open(path, 'r', encoding='utf-8') as f: - 424| 282| cfg = yaml.safe_load(f) - 425| 283| - 426| 284|providers = cfg.get('custom_providers', []) - 427| 285| - 428| 286|# 检查是否已存在同名 provider - 429| 287|existing_idx = None - 430| 288|for i, p in enumerate(providers): - 431| 289| if p.get('name') == name: - 432| 290| existing_idx = i - 433| 291| break - 434| 292| - 435| 293|new_provider = { - 436| 294| 'name': name, - 437| 295| 'base_url': base_url, - 438| 296| 'api_key': api_key, - 439| 297| 'model': model, - 440| 298|} - 441| 299| - 442| 300|if existing_idx is not None: - 443| 301| providers[existing_idx] = new_provider - 444| 302| print(f'已更新同名 provider: {name}') - 445| 303|else: - 446| 304| providers.append(new_provider) - 447| 305| print(f'已添加 provider: {name}') - 448| 306| - 449| 307|cfg['custom_providers'] = providers - 450| 308| - 451| 309|# 备份 - 452| 310|shutil.copy2(path, path + '.bak') - 453| 311| - 454| 312|with open(path, 'w', encoding='utf-8') as f: - 455| 313| yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True, sort_keys=False) - 456| 314| - 457| 315|print('OK') - 458| 316|PY - 459| 317| - 460| 318| if [ $? -eq 0 ]; then - 461| 319| echo -e "${GREEN}已成功添加 provider: ${provider_name}${NC}" - 462| 320| - 463| 321| # 询问是否切换为当前使用 - 464| 322| echo - 465| 323| read -erp "是否立即切换到该 provider?(y/N): " switch_now - 466| 324| if [[ "$switch_now" =~ ^[Yy]$ ]]; then - 467| 325| hermes_switch_to_provider "$provider_name" - 468| 326| fi - 469| 327| else - 470| 328| echo -e "${RED}配置写入失败${NC}" - 471| 329| fi - 472| 330|} - 473| 331| - 474| 332|# 切换到指定 provider - 475| 333|hermes_switch_to_provider() { - 476| 334| local target_name="$1" - 477| 335| - 478| 336| if [ -z "$target_name" ]; then - 479| 337| read -erp "请输入要切换的 Provider 名称: " target_name - 480| 338| fi - 481| 339| - 482| 340| python3 - "$HERMES_CONFIG" "$target_name" <<'PY' - 483| 341|import sys, yaml, shutil - 484| 342| - 485| 343|path = sys.argv[1] - 486| 344|target = sys.argv[2] - 487| 345| - 488| 346|with open(path, 'r', encoding='utf-8') as f: - 489| 347| cfg = yaml.safe_load(f) - 490| 348| - 491| 349|providers = cfg.get('custom_providers', []) - 492| 350|target_p = None - 493| 351|for p in providers: - 494| 352| if p.get('name') == target: - 495| 353| target_p = p - 496| 354| break - 497| 355| - 498| 356|if target_p is None: - 499| 357| print(f'ERROR: 未找到 provider: {target}') - 500| 358| sys.exit(1) - 501| \ No newline at end of file +#!/bin/bash +# Hermes Agent 终端管理脚本 (轻量版) +# 设计哲学:极简、直观、调用原生功能 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +# 确保 hermes 命令可用 (处理环境变量未加载的情况) +if ! command -v hermes >/dev/null 2>&1; then + if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then + export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" + fi +fi + +# 检查是否安装 + +# --- 科技lion 增强版 API 管理核心 --- +CONFIG_FILE="$HOME/.hermes/config.yaml" + +config_tool() { + python3 - "$CONFIG_FILE" "$@" <<'EOF' +import sys, yaml, json, os + +path = sys.argv[1] +action = sys.argv[2] + +def load(): + if not os.path.exists(path): + return {} + try: + with open(path, 'r', encoding='utf-8') as f: + return yaml.safe_load(f) or {} + except: + return {} + +def save(d): + with open(path, 'w', encoding='utf-8') as f: + yaml.dump(d, f, sort_keys=False, allow_unicode=True) + +try: + data = load() + if action == "get_info": + m = data.get('model', {}) + res = {"m": m.get('default', '-'), "p": m.get('provider', '-'), "u": m.get('base_url', '-')} + print(json.dumps(res)) + + elif action == "list_p": + print(json.dumps(data.get('custom_providers', []))) + + elif action == "add_p": + n, u, k, m = sys.argv[3:7] + ps = data.get('custom_providers', []) + if not isinstance(ps, list): ps = [] + ps = [p for p in ps if p.get('name') != n] + ps.append({"name": n, "base_url": u, "api_key": k, "model": m}) + data['custom_providers'] = ps + save(data) + + elif action == "bulk_add": + n_base, u, k, models_json = sys.argv[3:7] + new_m_ids = json.loads(models_json) + ps = data.get('custom_providers', []) + if not isinstance(ps, list): ps = [] + # 移除旧的同前缀条目 + ps = [p for p in ps if not (isinstance(p, dict) and p.get('name', '').startswith(n_base + "/"))] + # 移除可能存在的同名根条目 + ps = [p for p in ps if p.get('name') != n_base] + for m_id in new_m_ids: + ps.append({"name": f"{n_base}/{m_id}", "base_url": u, "api_key": k, "model": m_id}) + data['custom_providers'] = ps + save(data) + + elif action == "del_p": + n = sys.argv[3] + ps = data.get('custom_providers', []) + if isinstance(ps, list): + data['custom_providers'] = [p for p in ps if p.get('name') != n and not p.get('name', '').startswith(n + "/")] + save(data) + + elif action == "list_groups": + ps = data.get('custom_providers', []) + groups = [] + seen = set() + for p in (ps if isinstance(ps, list) else []): + name = p.get('name', '') + g = name.split('/')[0] if '/' in name else name + if g and g not in seen: + seen.add(g) + cnt = sum(1 for x in ps if x.get('name', '') == g or x.get('name', '').startswith(g + '/')) + groups.append({"name": g, "count": cnt}) + print(json.dumps(groups)) + + elif action == "switch": + n, u, k, m = sys.argv[3:7] + data['model'] = {"default": m, "provider": "custom", "base_url": u, "api_key": k} + save(data) + +except Exception as e: + # 确保出错时返回合法的 JSON 避免 Bash 报错 + print(json.dumps([])) + sys.exit(1) +EOF +} + +install_gum() { + if command -v gum >/dev/null 2>&1; then + return 0 + fi + echo -e "${YELLOW}正在安装 gum (交互式选择器)...${NC}" + if command -v apt >/dev/null 2>&1; then + mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg 2>/dev/null + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list > /dev/null + apt update -qq && apt install -y -qq gum + elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + cat > /etc/yum.repos.d/charm.repo <<'REPO' +[charm] +name=Charm +baseurl=https://repo.charm.sh/yum/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.charm.sh/yum/gpg.key +REPO + rpm --import https://repo.charm.sh/yum/gpg.key + if command -v dnf >/dev/null 2>&1; then dnf install -y gum; else yum install -y gum; fi + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive install gum + fi +} + +hermes_model_probe() { + local target_model="$1" + local ps_json="$2" + local probe_timeout=15 + local provider_name request_model base_url api_key + + # 从 custom_providers 中查找对应条目 + provider_name="$target_model" + local entry=$(echo "$ps_json" | jq -c --arg n "$provider_name" '.[] | select(.name == $n)' 2>/dev/null) + if [ -z "$entry" ]; then + HERMES_PROBE_STATUS="ERROR" + HERMES_PROBE_MESSAGE="未找到模型配置" + HERMES_PROBE_LATENCY="-" + HERMES_PROBE_REPLY="-" + return 1 + fi + + base_url=$(echo "$entry" | jq -r .base_url) + api_key=$(echo "$entry" | jq -r .api_key) + request_model=$(echo "$entry" | jq -r .model) + base_url="${base_url%/}" + + local tmp_response + tmp_response=$(mktemp) + + # 使用 Python 探测,精确计时 + local probe_result + probe_result=$(python3 - "$base_url" "$api_key" "$request_model" "$tmp_response" "$probe_timeout" <<'PYEOF' +import sys, time, json +try: + import urllib.request, urllib.error +except ImportError: + print("1|0|0") + sys.exit(0) + +base_url, api_key, model, resp_path, timeout = sys.argv[1:6] +timeout = int(timeout) +url = base_url + "/chat/completions" +payload = json.dumps({"model": model, "messages": [{"role": "user", "content": "hi"}], "temperature": 0, "max_tokens": 16}).encode() +req = urllib.request.Request(url, data=payload, headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", +}, method="POST") + +start = time.time() +body = b"" +status = 0 +exit_code = 0 +try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + status = getattr(resp, "status", 200) + body = resp.read() +except urllib.error.HTTPError as e: + status = getattr(e, "code", 0) or 0 + body = e.read() + exit_code = 22 +except Exception as e: + body = str(e).encode("utf-8", errors="replace") + exit_code = 1 + +elapsed = int((time.time() - start) * 1000) +with open(resp_path, "wb") as f: + f.write(body) +print(f"{exit_code}|{status}|{elapsed}") +PYEOF +) + + local p_exit p_http p_latency + p_exit=${probe_result%%|*} + p_http=${probe_result#*|} + p_http=${p_http%%|*} + p_latency=${probe_result##*|} + + # 提取回复摘要 + local reply_preview + reply_preview=$(python3 - "$tmp_response" <<'PYEOF' +import json, sys +from pathlib import Path +raw = Path(sys.argv[1]).read_text(encoding="utf-8", errors="replace").strip() +reply = "" +if raw: + try: + data = json.loads(raw) + if isinstance(data, dict): + choices = data.get("choices") or [] + if choices and isinstance(choices[0], dict): + msg = choices[0].get("message") or {} + if isinstance(msg, dict): + reply = msg.get("content") or "" + if not reply: + for key in ("error", "message", "detail"): + v = data.get(key) + if isinstance(v, str) and v.strip(): + reply = v.strip(); break + if isinstance(v, dict): + n = v.get("message") + if isinstance(n, str) and n.strip(): + reply = n.strip(); break + except: + reply = raw +reply = " ".join(str(reply).split())[:120] +print(reply if reply else "(空返回)") +PYEOF +) + rm -f "$tmp_response" + + if [ "$p_exit" = "0" ] && [ "$p_http" -ge 200 ] 2>/dev/null && [ "$p_http" -lt 300 ] 2>/dev/null; then + HERMES_PROBE_STATUS="OK" + HERMES_PROBE_MESSAGE="HTTP ${p_http}" + HERMES_PROBE_LATENCY="${p_latency}ms" + HERMES_PROBE_REPLY="$reply_preview" + return 0 + else + HERMES_PROBE_STATUS="FAIL" + HERMES_PROBE_MESSAGE="HTTP ${p_http:-0} / exit ${p_exit:-1}" + HERMES_PROBE_LATENCY="${p_latency:-?}ms" + HERMES_PROBE_REPLY="$reply_preview" + return 1 + fi +} + +hermes_probe_status_line() { + local status_text="$1" + local color_ok='\033[32m' color_fail='\033[31m' reset='\033[0m' + if [ "$status_text" = "可用" ]; then + printf "%b最小检测结果:%s%b\n" "$color_ok" "$status_text" "$reset" + else + printf "%b最小检测结果:%s%b\n" "$color_fail" "$status_text" "$reset" + fi +} + +api_management_submenu() { + while true; do + clear + info=$(config_tool get_info) + echo -e "${BLUE}=======================================${NC}" + echo -e " ${PURPLE}API & 模型管理 (OpenClaw 风格)${NC}" + echo -e "${BLUE}=======================================${NC}" + echo -e "${CYAN}当前激活模型:${NC} ${GREEN}$(echo $info | jq -r .m)${NC}" + echo -e "---------------------------------------" + echo -e "${CYAN}已配置 API 列表:${NC}" + ps_list=$(config_tool list_p) + if [ "$(echo "$ps_list" | jq '. | length')" -eq 0 ]; then + echo -e " ${YELLOW}(暂无配置)${NC}" + else + echo "$ps_list" | jq -r '.[] | " ● [\(.name)] \(.model) | \(.base_url)"' + fi + echo -e "---------------------------------------" + echo -e "1. ${YELLOW}切换模型 (带测速)${NC}" + echo -e "2. 添加 API 供应商 (自动同步)${NC}" + echo -e "3. 删除 API 供应商" + echo -e "0. 返回主菜单" + echo -e "---------------------------------------" + read -p "选择序号: " sub_choice + case "$sub_choice" in + 1) + local orange="#FF8C00" + local ps_json models_list model_count default_model selected_model confirm_switch + + ps_json=$(config_tool list_p) + model_count=$(echo "$ps_json" | jq '. | length') + + if [ "$model_count" -eq 0 ] 2>/dev/null || [ -z "$model_count" ]; then + echo -e "${RED}无 API 配置! 请先添加供应商。${NC}" + sleep 1 + continue + fi + + # 构建带编号的模型列表 + models_list=$(echo "$ps_json" | jq -r '.[].name' | awk '{print "(" NR ") " $0}') + default_model=$(config_tool get_info | jq -r .m) + + while true; do + clear + install_gum + + # 若 gum 不可用,降级为手动输入 + if ! command -v gum >/dev/null 2>&1; then + echo "--- 模型管理 ---" + echo "当前可用模型:" + echo "$models_list" + echo "当前默认:${default_model}" + echo "----------------" + read -e -p "请输入模型编号或名称 (输入 0 退出): " selected_model + + if [ "$selected_model" = "0" ]; then + break + fi + if [ -z "$selected_model" ]; then + echo "错误:不能为空,请重试。" + sleep 1 + continue + fi + # 如果输入的是纯数字,从列表中取名称 + if [[ "$selected_model" =~ ^[0-9]+$ ]]; then + selected_model=$(echo "$ps_json" | jq -r --argjson i "$((selected_model-1))" '.[$i].name // empty') + if [ -z "$selected_model" ]; then + echo "序号无效,请重试。" + sleep 1 + continue + fi + fi + else + # gum 模式 — 完全复刻 openclaw 风格 + gum style --foreground "$orange" --bold "模型管理" + gum style --foreground "$orange" "可用模型:${model_count}" + gum style --foreground "$orange" "当前默认:${default_model}" + echo "" + gum style --faint "↑↓ 选择 / 输入搜索 / Enter 测试 / Esc 退出" + echo "" + + selected_model=$(echo "$models_list" | gum filter \ + --placeholder "搜索模型(如 cli-api/gpt-4o)" \ + --prompt "选择模型 > " \ + --indicator "➜ " \ + --prompt.foreground "$orange" \ + --indicator.foreground "$orange" \ + --cursor-text.foreground "$orange" \ + --match.foreground "$orange" \ + --header "" \ + --height 35) + + if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then + echo "操作已取消,正在退出..." + break + fi + fi + + # 去掉编号前缀 "(N) " + selected_model=$(echo "$selected_model" | sed -E 's/^\([0-9]+\)[[:space:]]+//') + + echo "" + echo "正在检测模型: $selected_model" + if hermes_model_probe "$selected_model" "$ps_json"; then + hermes_probe_status_line "可用" + else + hermes_probe_status_line "不可用" + fi + echo "状态:$HERMES_PROBE_MESSAGE" + echo "延迟:$HERMES_PROBE_LATENCY" + echo "摘要:$HERMES_PROBE_REPLY" + echo "" + + printf "是否切换到该模型?[y/N,Esc 返回列表]: " + IFS= read -rsn1 confirm_switch + echo "" + if [ "$confirm_switch" = $'\x1b' ]; then + confirm_switch="no" + else + case "$confirm_switch" in + [yY]) + IFS= read -rsn1 -t 5 _enter_key + confirm_switch="yes" + ;; + *) confirm_switch="no" ;; + esac + fi + + if [ "$confirm_switch" != "yes" ]; then + echo "已返回模型选择列表。" + sleep 1 + continue + fi + + # 执行切换 + local entry_data + entry_data=$(echo "$ps_json" | jq -c --arg n "$selected_model" '.[] | select(.name == $n)') + local sw_u sw_k sw_m + sw_u=$(echo "$entry_data" | jq -r .base_url) + sw_k=$(echo "$entry_data" | jq -r .api_key) + sw_m=$(echo "$entry_data" | jq -r .model) + + echo "正在切换模型为: $selected_model ..." + config_tool switch "$selected_model" "$sw_u" "$sw_k" "$sw_m" + + # 重启 gateway + echo -e "${YELLOW}正在重启 Gateway...${NC}" + hermes gateway stop >/dev/null 2>&1 + hermes gateway start >/dev/null 2>&1 + echo -e "${GREEN}✅ 模型已切换为: $sw_m${NC}" + sleep 2 + break + done + ;; + 2) + echo -e "${CYAN}--- 添加新 API 供应商 ---${NC}" + read -p "请输入供应商名称 (如: DeepSeek): " n + [ -z "$n" ] && continue + read -p "请输入 Base URL (如: https://api.deepseek.com/v1): " u + [ -z "$u" ] && continue + u="${u%/}" + echo -ne "${YELLOW}请输入 API Key (输入隐藏): ${NC}" + read -s k + echo "" + [ -z "$k" ] && continue + + echo -e "${YELLOW}🔍 正在获取完整模型列表...${NC}" + m_json=$(curl -s -m 10 -H "Authorization: Bearer $k" "$u/models") + # 提取所有 ID + m_list_str=$(echo "$m_json" | jq -r '.data[].id' 2>/dev/null | sort) + + if [ -n "$m_list_str" ]; then + # 转换为数组 + m_array=() + while read -r line; do m_array+=("$line"); done <<< "$m_list_str" + m_count=${#m_array[@]} + + echo -e "${GREEN}✅ 发现 $m_count 个模型。请选择一个作为当前默认:${NC}" + PS3="请输入序号: " + select m_default in "${m_array[@]}"; do + [ -n "$m_default" ] && break + done + + echo -e "---------------------------------------" + read -p "是否同时添加该供应商的所有 $m_count 个模型?(y/N): " bulk_confirm + if [[ "$bulk_confirm" =~ ^[Yy]$ ]]; then + # 转换数组为 JSON + m_json_list=$(echo "$m_list_str" | jq -R . | jq -s -c .) + config_tool bulk_add "$n" "$u" "$k" "$m_json_list" + config_tool switch "$n/$m_default" "$u" "$k" "$m_default" + echo -e "${GREEN}✅ 已全量导入 $m_count 个模型。${NC}" + else + config_tool add_p "$n" "$u" "$k" "$m_default" + echo -e "${GREEN}✅ 已添加单个模型: $m_default${NC}" + fi + else + echo -e "${RED}❌ 无法获取列表。${NC}" + read -p "请手动输入模型 ID: " m_manual + [ -n "$m_manual" ] && config_tool add_p "$n" "$u" "$k" "$m_manual" + fi + sleep 2 + ;; + 3) + echo -e "${CYAN}已配置的供应商分组:${NC}" + groups_json=$(config_tool list_groups) + g_count=$(echo "$groups_json" | jq '. | length') + if [ "$g_count" -eq 0 ]; then + echo -e " ${YELLOW}(暂无配置)${NC}" + sleep 1 + continue + fi + # 列出供应商分组 + g_names=() + while read -r row; do + g_name=$(echo "$row" | jq -r .name) + g_cnt=$(echo "$row" | jq -r .count) + g_names+=("$g_name") + echo -e " ${GREEN}${#g_names[@]}.${NC} $g_name (${g_cnt} 个模型)" + done < <(echo "$groups_json" | jq -c '.[]') + echo -e " ${GREEN}0.${NC} 取消" + read -p "选择要删除的供应商序号: " d_idx + if [ "$d_idx" == "0" ] || [ -z "$d_idx" ]; then continue; fi + d_name="${g_names[$((d_idx-1))]}" + if [ -n "$d_name" ]; then + read -p "确认删除 [$d_name] 及其所有模型? (y/N): " del_confirm + if [[ "$del_confirm" =~ ^[Yy]$ ]]; then + config_tool del_p "$d_name" + echo -e "${RED}🗑️ 已删除 $d_name${NC}" + sleep 1 + fi + fi + ;; + 0) break ;; + esac + done +} +check_installed() { + if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi +} + +# 获取版本号 +get_version() { + if check_installed; then + hermes --version | head -n 1 + fi +} + +# 获取网关状态 +get_gateway_status() { + if check_installed; then + # 匹配后台 gateway 进程或 systemd 服务 + if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then + echo -e "${GREEN}运行中${NC}" + else + echo -e "${RED}已停止${NC}" + fi + else + echo -e "${RED}未安装${NC}" + fi +} + + +refresh_hermes_path() { + if ! command -v hermes >/dev/null 2>&1; then + if [ -d "$HOME/.hermes/hermes-agent/venv/bin" ]; then + export PATH="$HOME/.hermes/hermes-agent/venv/bin:$PATH" + fi + fi +} + + +# 主菜单UI +show_menu() { + clear + echo -e "${CYAN}=================================================${NC}" + echo -e "${YELLOW} Hermes Agent 终端管理工具 ${NC}" + echo -e "${CYAN}=================================================${NC}" + echo -e " 运行状态 : $(get_gateway_status)" + echo -e " 当前版本 : $(get_version)" + echo -e "${CYAN}-------------------------------------------------${NC}" + echo -e "${GREEN}1.${NC} 安装 Hermes Agent" + echo -e "${GREEN}2.${NC} 启动 Gateway (消息网关/后台服务)" + echo -e "${GREEN}3.${NC} 停止 Gateway" + echo -e "${GREEN}4.${NC} API/模型管理 (提供商与模型切换)" + echo -e "${GREEN}5.${NC} 启动终端对话UI (Interactive Chat)" + echo -e "${GREEN}6.${NC} 运行初始化配置向导 (Setup Wizard)" + echo -e "${GREEN}7.${NC} 检查并更新 Hermes" + echo -e "${GREEN}8.${NC} 卸载 Hermes" + echo -e "${GREEN}0.${NC} 退出" + echo -e "${CYAN}=================================================${NC}" + if ! read -p " 请输入数字 [0-8]: " choice; then + echo -e "\n${GREEN}退出脚本。${NC}" + exit 0 + fi + echo "" + + case $choice in + 1) + echo -e "${YELLOW}开始安装 Hermes Agent...${NC}" + curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash + refresh_hermes_path + hermes gateway install + hermes gateway start + ;; + 2) + if check_installed; then + echo -e "${YELLOW}正在启动 Gateway...${NC}" + systemctl --user start hermes-gateway + hermes gateway stop + hermes gateway start + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 3) + if check_installed; then + echo -e "${YELLOW}正在停止 Gateway...${NC}" + hermes gateway stop + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 4) + if check_installed; then + echo -e "${YELLOW}进入模型配置向导...${NC}" + api_management_submenu + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 5) + if check_installed; then + echo -e "${YELLOW}即将进入交互式终端,输入 /exit 即可退出返回。${NC}" + sleep 1 + hermes + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 6) + if check_installed; then + echo -e "${YELLOW}正在启动初始化配置向导...${NC}" + hermes setup + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 7) + if check_installed; then + echo -e "${YELLOW}正在检查更新...${NC}" + hermes update + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 8) + if check_installed; then + read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + hermes uninstall + else echo "已取消。"; fi + else echo -e "${RED}请先安装 Hermes。${NC}"; fi + ;; + 0) + echo -e "${GREEN}感谢使用,再见!${NC}" + exit 0 + ;; + *) + echo -e "${RED}输入错误,请重新选择。${NC}" + ;; + esac + echo "" + read -p "按回车键返回主菜单..." +} + +# 主循环 +while true; do + show_menu +done diff --git a/jp/kejilion.sh b/jp/kejilion.sh index a11669c59..183fee604 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -15449,12 +15449,7 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "健全性の検出と修復" openclaw doctor --fix - send_stats "OpenClaw API の同期トリガー" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API モデルの同期に失敗しました。ゲートウェイの再起動は中止されました。プロバイダー/モデルを確認し、戻ってからもう一度お試しください。" - fi + break_end ;; 13) openclaw_webui_menu ;; diff --git a/kejilion.sh b/kejilion.sh index 57493096e..3506f4670 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -15449,14 +15449,8 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "健康检测与修复" openclaw doctor --fix - send_stats "OpenClaw API同步触发" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" - fi break_end - ;; + ;; 13) openclaw_webui_menu ;; 14) send_stats "TUI命令行对话" openclaw tui diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 2615ac69a..c48ed9cc8 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -15449,12 +15449,7 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "상태 감지 및 복구" openclaw doctor --fix - send_stats "OpenClaw API 동기식 트리거링" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." - fi + break_end ;; 13) openclaw_webui_menu ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index d196239ed..8cd095983 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -15449,12 +15449,7 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "健康檢測與修復" openclaw doctor --fix - send_stats "OpenClaw API同步觸發" - if sync_openclaw_api_models; then - start_gateway - else - echo "❌ API 模型同步失敗,已中止重新啟動網關。請檢查 provider /models 返回後重試。" - fi + break_end ;; 13) openclaw_webui_menu ;; From aee694131bc020b9cdb88bb398a2f4a7bc644b32 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 26 Apr 2026 05:47:12 +0000 Subject: [PATCH 1155/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-04-26=2005:47:12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 137 ++++++------ jp/kejilion.sh | 223 ++++++++++--------- kr/kejilion.sh | 233 +++++++++---------- tw/kejilion.sh | 589 +++++++++++++++++++++++++------------------------ 4 files changed, 597 insertions(+), 585 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 540214306..5f1a7e512 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -5094,7 +5094,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5250,7 +5250,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion } @@ -5530,7 +5530,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6328,7 +6328,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -7609,7 +7609,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" tools=( @@ -8083,7 +8083,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8244,7 +8244,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8611,7 +8611,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -10051,7 +10051,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API Management" + echo "6. API management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10475,8 +10475,8 @@ PY start_bot() { - echo "Starting OpenClaw..." - send_stats "Starting OpenClaw..." + echo "Start OpenClaw..." + send_stats "Start OpenClaw..." start_gateway break_end } @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API List" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "Change model" @@ -11748,7 +11748,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "Failed to get list of models: agents.defaults.models not found in configuration file." + echo "Failed to get model list: agents.defaults.models not found in configuration file." break_end return 1 fi @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # If gum does not exist, it will be downgraded to the original manual input process. if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "---Model Management ---" @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "Plug-in management" while true; do @@ -12119,13 +12119,13 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue - read -e -p "Please enter plugin IDs (separated by spaces, enter 0 to exit):" raw_input + read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue @@ -12247,7 +12247,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -12986,7 +12986,7 @@ if os.path.isdir(agents_root): echo "Backup directory:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "No backup files yet" + echo "No backup file yet" return 0 fi @@ -13778,7 +13778,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ The model file already exists:$model_path" + echo "✅ Model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14099,7 +14099,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count + read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14116,7 +14116,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ Number of rows must be greater than 0." + echo "❌ The number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # Generate JSON and write via openclaw approvals set --stdin (preferred) # If the CLI does not support it, it will fall back to writing the file directly. local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14512,7 +14512,7 @@ print(json.dumps(data, indent=2)) echo "Exec limit: ${current_sec:-(unset)}" echo "Approval prompt: ${current_ask:-(unset)}" echo "Privilege elevation switch: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[Underlying Exec Approvals status]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14563,7 +14563,7 @@ except Exception: openclaw_permission_apply_standard() { send_stats "OpenClaw Permissions - Standard Security Mode" openclaw_permission_require_openclaw || return 1 - + echo "Configuring application layer policy..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 @@ -14571,10 +14571,10 @@ except Exception: openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "Configuring host approval interception..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ Switched to standard safety mode (all dangerous commands will ask for your approval through UI/TG)${gl_bai}" } @@ -14582,17 +14582,17 @@ except Exception: openclaw_permission_apply_developer() { send_stats "OpenClaw Permissions - Development Enhanced Mode" openclaw_permission_require_openclaw || return 1 - + echo "Configuring application layer policy..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "Configuring host approval interception..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ Switched to development enhancement mode (privilege escalation is allowed, but common dangerous commands still require approval)${gl_bai}" } @@ -14600,33 +14600,33 @@ except Exception: openclaw_permission_apply_full() { send_stats "OpenClaw Permissions - Fully Open Mode" openclaw_permission_require_openclaw || return 1 - + echo "Configuring application layer policy..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "Disintegrating host interception defense..." # The full and off here will completely bypass the exec approval system of the underlying host. openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ Has been switched to fully open mode (Warning: All host command interceptions have expired, and the agent has the highest permissions)${gl_bai}" + echo -e "${gl_lv}✅ Switched to fully open mode (Warning: All host command interceptions have expired, and the agent has the highest permissions)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw permissions-restore official default" openclaw_permission_require_openclaw || return 1 - + echo "Clean application layer force coverage..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "Clean host interception configuration..." # Prioritize clearing the approval configuration through the CLI, and fall back to directly deleting the file. if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,7 +14634,7 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ Reverted to OpenClaw official security sandbox defense mechanism${gl_bai}" } @@ -15004,7 +15004,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ The agent was created successfully:$agent_id" + echo "✅The agent is created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -15449,9 +15449,8 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "Health detection and repair" openclaw doctor --fix - break_end - ;; + ;; 13) openclaw_webui_menu ;; 14) send_stats "TUI command line conversation" openclaw tui @@ -15574,6 +15573,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}Multi-format file conversion tool${gl_kjlan}112. ${color112}Lucky large intranet penetration tool" echo -e "${gl_kjlan}113. ${color113}Firefox browser${gl_kjlan}114. ${color114}OpenClaw bot management tool${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes robot management tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}Third-party application list" echo -e "${gl_kjlan}Want your app to appear here? Check out the developer guide:${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -15878,7 +15878,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17644,7 +17644,7 @@ while true; do } - local docker_describe="A password manager that puts you in control of your data" + local docker_describe="A password manager where you can control your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18832,7 +18832,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19241,6 +19241,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear @@ -19264,7 +19267,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "File transferred to remote server/root directory." else echo "The file to be transferred was not found." fi @@ -19345,7 +19348,7 @@ linux_work() { echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." - echo -e "${gl_huang}hint:${gl_bai}进入工作区后使用Ctrl+b再单独按d,退出工作区!" + echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" echo -e "${gl_kjlan}------------------------" @@ -19355,7 +19358,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19741,7 +19744,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. View the latest system log (journal)" + echo "1. Check the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -19753,7 +19756,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -19831,7 +19834,7 @@ env_menu() { show_env_vars() { clear - send_stats "Currently in effect environment variables" + send_stats "Environment variables currently in effect" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -20511,13 +20514,13 @@ EOF echo "------------------------" echo "Europe" echo "11. London, UK time 12. Paris, France time" - echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" + echo "13. Berlin, Germany time 14. Moscow, Russia time" echo "15. Utracht Time, Netherlands 16. Madrid Time, Spain" echo "------------------------" echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil time 26. Argentina time" + echo "25. Brazil Time 26. Argentina Time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -20775,7 +20778,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -20996,7 +20999,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" @@ -21044,7 +21047,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -21295,7 +21298,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Copying file or directory failed: File or directory does not exist" + send_stats "Failed to copy file or directory: File or directory does not exist" continue fi @@ -21825,7 +21828,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 183fee604..8aa63569e 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -930,12 +930,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1750,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4838,7 +4838,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5250,7 +5250,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには、root ユーザーが必要です。" && break_end && kejilion } @@ -5474,7 +5474,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -6300,9 +6300,9 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6328,7 +6328,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -7030,7 +7030,7 @@ ssh_manager() { 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "選択が無効です。もう一度お試しください。" ;; + *) echo "无效的选择,请重试。" ;; esac done } @@ -7055,7 +7055,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -7232,7 +7232,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7491,7 +7491,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7609,7 +7609,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" tools=( @@ -8045,7 +8045,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8244,7 +8244,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8318,7 +8318,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8461,7 +8461,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8988,8 +8988,8 @@ linux_ldnmp() { echo -e "${gl_huang}9. ${gl_bai}LinkStack 共有リンク プラットフォームをインストールする${gl_huang}20. ${gl_bai}カスタム動的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" + echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" echo -e "${gl_huang}29. ${gl_bai}ストリーム 4 層プロキシ転送${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" @@ -10330,7 +10330,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10350,7 +10350,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10475,8 +10475,8 @@ PY start_bot() { - echo "OpenClaw を開始しています..." - send_stats "OpenClaw を開始しています..." + echo "OpenClaw を開始します..." + send_stats "OpenClaw を開始します..." start_gateway break_end } @@ -10734,7 +10734,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API リスト" @@ -11124,7 +11124,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行完了" + echo "✅ 同期実行が完了しました" start_gateway ;; 2) @@ -11450,7 +11450,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入り口" + send_stats "OpenClaw APIの入口" while true; do clear echo "=======================================" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "機種変更" @@ -11560,7 +11560,7 @@ REPO oc_config=$(openclaw_get_config_file) [ ! -f "$oc_config" ] && { OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="openclaw 設定ファイルが見つかりません" + OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 @@ -11698,7 +11698,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空のリターン)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11748,7 +11748,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "モデルのリストを取得できませんでした: 構成ファイルに Agents.defaults.models が見つかりません。" + echo "モデル リストの取得に失敗しました: 構成ファイルに Agents.defaults.models が見つかりません。" break_end return 1 fi @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # ガムが存在しない場合は、元の手入力プロセスにダウングレードされます。 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "---モデル管理---" @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "プラグイン管理" while true; do @@ -12193,7 +12193,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12238,8 +12238,8 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンの制御" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "openhue # Philips Hue スマート照明シーンを制御する" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12591,7 +12591,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -12986,7 +12986,7 @@ if os.path.isdir(agents_root): echo "バックアップディレクトリ:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "バックアップファイルはまだありません" + echo "まだバックアップファイルがありません" return 0 fi @@ -13685,7 +13685,7 @@ PY echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -14097,9 +14097,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "総行数:$total_lines" + echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示される行数を入力してください (Enter を押してデフォルトにします)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14194,7 +14194,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステート検出 (組み込みモデルのチェック)" + echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # JSON を生成し、openclaw 承認セット --stdin 経由で書き込みます (推奨) # CLI がこれをサポートしていない場合は、ファイルの直接書き込みに戻ります。 local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14507,12 +14507,12 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" echo "特権昇格スイッチ: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[基本的な幹部の承認ステータス]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14556,14 +14556,14 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } openclaw_permission_apply_standard() { send_stats "OpenClaw 権限 - 標準セキュリティ モード" openclaw_permission_require_openclaw || return 1 - + echo "アプリケーション層ポリシーを構成しています..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 @@ -14571,28 +14571,28 @@ except Exception: openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "ホスト承認インターセプトを構成しています..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw 権限 - 開発拡張モード" openclaw_permission_require_openclaw || return 1 - + echo "アプリケーション層ポリシーを構成しています..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "ホスト承認インターセプトを構成しています..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには引き続き承認が必要です)${gl_bai}" } @@ -14600,18 +14600,18 @@ except Exception: openclaw_permission_apply_full() { send_stats "OpenClaw 権限 - 完全オープン モード" openclaw_permission_require_openclaw || return 1 - + echo "アプリケーション層ポリシーを構成しています..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "ホストの迎撃防御が崩壊中..." # ここでの full と off は、基礎となるホストの実行承認システムを完全にバイパスします。 openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } @@ -14619,14 +14619,14 @@ except Exception: openclaw_permission_restore_official_defaults() { send_stats "OpenClaw 権限 - 公式のデフォルトに戻す" openclaw_permission_require_openclaw || return 1 - + echo "クリーンなアプリケーション層の適用範囲を強化します..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "クリーンなホストインターセプト構成..." # CLI を介して承認設定をクリアすることを優先し、ファイルの直接削除に戻ります。 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,7 +14634,7 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ OpenClaw 公式セキュリティ サンドボックス防御メカニズムに戻しました${gl_bai}" } @@ -14719,13 +14719,13 @@ except Exception as e: while true; do clear echo "=======================================" - echo "OpenClaw 権限管理 (デュアルレイヤー アーキテクチャの高度な適応)" + echo " OpenClaw 权限管理 (双层架构深度适配)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" echo -e "${gl_kjlan}1.${gl_bai}標準セキュリティ モードに切り替える (毎日の推奨事項、ポップアップ カードの承認)" echo -e "${gl_kjlan}2.${gl_bai}開発拡張モードに切り替える (エージェントが権限昇格を申請できるようにする)" - echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}ハイリスク!すべてのホストインターセプトを完全に削除します${gl_bai})" + echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}High risk!すべてのホストインターセプトを完全に削除します${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}公式のデフォルトのサンドボックス防御戦略を復元する" echo -e "${gl_kjlan}5.${gl_bai}基盤となるセキュリティ監査と自動修復を実行する" echo -e "${gl_kjlan}6.${gl_bai}Execコマンドのホワイトリストを管理する" @@ -15001,10 +15001,10 @@ for idx,item in enumerate(agents,1): [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました:$agent_id" + echo "✅ エージェントが正常に作成されました。$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15057,7 +15057,7 @@ for idx,item in enumerate(bindings,1): read -e -p "ルート バインディング値 (telegram:ops / discord:guild-a など) を入力してください。" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントをバインドします [$agent_id] -> [$bind_value]" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に追加されました" @@ -15075,7 +15075,7 @@ for idx,item in enumerate(bindings,1): read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に削除されました" @@ -15283,7 +15283,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 構成ファイルを編集する" + send_stats "OpenClaw 設定ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15443,15 +15443,14 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期設定ウィザード" + 11) send_stats "初期構成ウィザード" openclaw onboard --install-daemon break_end ;; 12) send_stats "健全性の検出と修復" openclaw doctor --fix - break_end - ;; + ;; 13) openclaw_webui_menu ;; 14) send_stats "TUI コマンドラインでの会話" openclaw tui @@ -15556,7 +15555,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -15574,6 +15573,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール${gl_kjlan}112. ${color112}Lucky 大規模イントラネット侵入ツール" echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ${gl_kjlan}114. ${color114}OpenClaw ボット管理ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}ヘルメスロボット管理ツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" echo -e "${gl_kjlan}あなたのアプリをここに表示したいですか?開発者ガイドを確認してください。${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -15798,7 +15798,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザ監視$check_docker $update_status" + echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15807,7 +15807,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -17375,7 +17375,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17644,7 +17644,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18107,7 +18107,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチピクチャービデオマネージャー" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18689,7 +18689,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -18832,7 +18832,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19241,6 +19241,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear @@ -19345,7 +19348,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19355,7 +19358,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19683,7 +19686,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19693,7 +19696,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19705,7 +19708,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19741,7 +19744,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を表示する" + echo "1. 最新のシステムログ(ジャーナル)を確認する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -19753,10 +19756,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19766,7 +19769,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19781,7 +19784,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19869,7 +19872,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -19884,7 +19887,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -19900,7 +19903,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -19911,7 +19914,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集する" + echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -20028,7 +20031,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20492,7 +20495,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -20775,7 +20778,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" fi echo @@ -21825,13 +21828,13 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index c48ed9cc8..a069102c3 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -508,22 +508,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker restart $dockername ;; 6) @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3725,7 +3725,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4106,7 +4106,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4168,7 +4168,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4983,7 +4983,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5058,7 +5058,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원래 Authorized_keys 파일이 백업되었습니다." + echo "원본 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5808,7 +5808,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5844,7 +5844,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -5957,7 +5957,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정합니다── + # ──장면에 따라 매개변수를 설정하세요── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6328,7 +6328,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -8003,7 +8003,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -8142,7 +8142,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8244,7 +8244,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8431,7 +8431,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8477,7 +8477,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9189,7 +9189,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9527,7 +9527,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -10475,8 +10475,8 @@ PY start_bot() { - echo "OpenClaw를 시작하는 중..." - send_stats "OpenClaw를 시작하는 중..." + echo "OpenClaw를 시작하세요..." + send_stats "OpenClaw를 시작하세요..." start_gateway break_end } @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API 목록" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "모델 변경" @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # 껌이 존재하지 않을 경우 기존의 수동 입력 과정으로 다운그레이드됩니다. if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "---모델 관리 ---" @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "플러그인 관리" while true; do @@ -12119,7 +12119,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12247,7 +12247,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12591,7 +12591,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -12929,7 +12929,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -12986,7 +12986,7 @@ if os.path.isdir(agents_root): echo "백업 디렉터리:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "아직 백업 파일이 없습니다." + echo "아직 백업 파일이 없습니다" return 0 fi @@ -13299,7 +13299,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." + echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -13572,7 +13572,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." return 0 } @@ -13590,7 +13590,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13735,7 +13735,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command가 정확합니다." fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -14099,7 +14099,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14109,7 +14109,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 숫자를 입력하세요." + echo "❌ 유효한 번호를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14211,7 +14211,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14225,7 +14225,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # JSON을 생성하고 openclaw 승인 세트 --stdin을 통해 작성(선호) # CLI가 이를 지원하지 않으면 파일을 직접 작성하는 것으로 대체됩니다. local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14512,7 +14512,7 @@ print(json.dumps(data, indent=2)) echo "실행 제한: ${current_sec:-(unset)}" echo "승인 프롬프트: ${current_ask:-(unset)}" echo "권한 상승 스위치: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[기본 Exec 승인 상태]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14563,18 +14563,18 @@ except Exception: openclaw_permission_apply_standard() { send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - - echo "애플리케이션 계층 정책 구성 중..." + + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "호스트 승인 차단 구성 중..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 명령은 모두 UI/TG를 통해 승인을 요청합니다)${gl_bai}" } @@ -14582,17 +14582,17 @@ except Exception: openclaw_permission_apply_developer() { send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - - echo "애플리케이션 계층 정책 구성 중..." + + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "호스트 승인 차단 구성 중..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" } @@ -14600,33 +14600,33 @@ except Exception: openclaw_permission_apply_full() { send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - - echo "애플리케이션 계층 정책 구성 중..." + + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "호스트 차단 방어 붕괴…" # 여기서 전체 및 해제는 기본 호스트의 실행 승인 시스템을 완전히 우회합니다. openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 완전 개방 모드로 전환되었습니다. (경고: 모든 호스트 명령 차단이 만료되었으며 에이전트는 가장 높은 권한을 가집니다.)${gl_bai}" + echo -e "${gl_lv}✅ 완전 개방 모드로 전환됨(경고: 모든 호스트 명령 차단이 만료되었으며 에이전트가 가장 높은 권한을 가짐)${gl_bai}" } openclaw_permission_restore_official_defaults() { send_stats "OpenClaw 권한-공식 기본값 복원" openclaw_permission_require_openclaw || return 1 - + echo "깨끗한 애플리케이션 레이어 힘 범위..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "호스트 차단 구성을 정리합니다..." # CLI를 통해 승인 구성을 지우는 데 우선순위를 두고 파일을 직접 삭제하는 방법으로 대체합니다. if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,7 +14634,7 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ OpenClaw 공식 보안 샌드박스 방어 메커니즘으로 복귀${gl_bai}" } @@ -14703,7 +14703,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15004,7 +15004,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15447,11 +15447,10 @@ openclaw_backup_restore_menu() { openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "상태 감지 및 수리" openclaw doctor --fix - break_end - ;; + ;; 13) openclaw_webui_menu ;; 14) send_stats "TUI 명령줄 대화" openclaw tui @@ -15548,7 +15547,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15568,15 +15567,16 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15778,7 +15778,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -15878,7 +15878,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -15910,7 +15910,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16478,7 +16478,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16617,7 +16617,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -16644,7 +16644,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17311,7 +17311,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17644,7 +17644,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18260,7 +18260,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -18832,7 +18832,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19181,7 +19181,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -19241,6 +19241,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear @@ -19355,7 +19358,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19741,7 +19744,7 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 보기" + echo "1. 최신 시스템 로그(일지) 확인" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" @@ -19753,7 +19756,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -20027,10 +20030,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20040,7 +20043,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20328,7 +20331,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -20492,7 +20495,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간을 가져옵니다 + # 현재 시스템 시간 가져오기 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -20512,7 +20515,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20580,7 +20583,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20775,7 +20778,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -20791,7 +20794,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -20835,7 +20838,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21295,7 +21298,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -21468,7 +21471,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21541,7 +21544,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21701,7 +21704,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}업데이트 실패! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" + echo -e "${gl_hong}업데이트에 실패했습니다! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" send_stats "스크립트 업데이트 실패" fi break_end @@ -21825,7 +21828,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21859,7 +21862,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 8cd095983..59d0b8a5f 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.9" +sh_v="4.4.10" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="default" +canshu="CN" permission_granted="false" ENABLE_STATS="true" @@ -36,7 +36,7 @@ quanju_canshu -# 定義一個函數來執行命令 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -63,7 +63,7 @@ CheckFirstRun_true() { -# 收集功能埋藏資訊的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! +# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!請相信我! # 為什麼要設計這個功能,目的更好的了解使用者喜歡使用的功能,進一步優化功能推出更多符合使用者需求的功能。 # 全文可搜尋 send_stats 函數呼叫位置,透明開源,如有顧慮可拒絕使用。 @@ -234,7 +234,7 @@ check_disk_space() { echo -e "${gl_huang}提示:${gl_bai}磁碟空間不足!" echo "目前可用空間: $((available_space_mb/1024))G" echo "最小需求空間:${required_gb}G" - echo "無法繼續安裝,請清理磁碟空間後重試。" + echo "无法继续安装,请清理磁盘空间后重试。" send_stats "磁碟空間不足" break_end kejilion @@ -302,7 +302,7 @@ systemctl() { restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1服務已重啟。" + echo "$1 服务已重启。" else echo "錯誤:重啟$1服務失敗。" fi @@ -312,7 +312,7 @@ restart() { start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1服務已啟動。" + echo "$1 服务已启动。" else echo "錯誤:啟動$1服務失敗。" fi @@ -497,7 +497,7 @@ while true; do echo "------------------------" echo "15. 開啟容器連接埠存取 16. 關閉容器連接埠訪問" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -508,7 +508,7 @@ while true; do ;; 2) send_stats "啟動指定容器" - read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) @@ -623,9 +623,9 @@ while true; do echo "Docker映像列表" docker image ls echo "" - echo "鏡像操作" + echo "镜像操作" echo "------------------------" - echo "1. 取得指定鏡像 3. 刪除指定鏡像" + echo "1. 获取指定镜像 3. 删除指定镜像" echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" @@ -1096,7 +1096,7 @@ iptables_panel() { echo "防火牆管理" echo "------------------------" echo "1. 開放指定連接埠 2. 關閉指定連接埠" - echo "3. 開放所有連接埠 4. 關閉所有連接埠" + echo "3. 开放所有端口 4. 关闭所有端口" echo "------------------------" echo "5. IP白名單 6. IP黑名單" echo "7. 清除指定IP" @@ -1115,7 +1115,7 @@ iptables_panel() { 1) read -e -p "請輸入開放的連接埠號碼:" o_port open_port $o_port - send_stats "開放指定連接埠" + send_stats "开放指定端口" ;; 2) read -e -p "請輸入關閉的連接埠號碼:" c_port @@ -1139,7 +1139,7 @@ iptables_panel() { send_stats "開放所有連接埠" ;; 4) - # 關閉所有連接埠 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1157,7 +1157,7 @@ iptables_panel() { 5) # IP 白名單 - read -e -p "請輸入放行的IP或IP段:" o_ip + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) @@ -1200,13 +1200,13 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; 17) - read -e -p "請輸入清除的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code + read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules unblock $country_code send_stats "清除國家$country_code的IP" ;; @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1430,7 +1430,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "續簽任務已更新" + echo "续签任务已更新" } @@ -1472,7 +1472,7 @@ install_ssltls_text() { echo "" echo -e "${gl_huang}證書存放路徑${gl_bai}" echo "公鑰: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私鑰: /etc/letsencrypt/live/$yuming/privkey.pem" + echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1561,9 +1561,9 @@ certs_status() { ;; 2) - send_stats "导入已有证书" + send_stats "導入已有證書" - # 定义文件路径 + # 定義檔案路徑 local cert_file="/home/web/certs/${yuming}_cert.pem" local key_file="/home/web/certs/${yuming}_key.pem" @@ -1578,7 +1578,7 @@ certs_status() { done # 2. 輸入私鑰 (相容 RSA, ECC, PKCS#8) - echo "請貼上 憑證私鑰 (Private Key) 內容 (按兩次回車結束):" + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1744,11 +1744,11 @@ cf_purge_cache() { if [ -f "$CONFIG_FILE" ]; then # 從設定檔讀取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 將 ZONE_IDS 轉換為數組 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else # 提示使用者是否清理快取 - read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer + read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer if [[ "$answer" == "y" ]]; then echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN @@ -1762,7 +1762,7 @@ cf_purge_cache() { # 循環遍歷每個 zone_id 並執行清除快取命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除快取 for zone_id:$ZONE_ID" + echo "正在清除缓存 for zone_id: $ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1788,7 +1788,7 @@ web_del() { send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1801,7 +1801,7 @@ web_del() { rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 將網域名稱轉換為資料庫名 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') @@ -2119,7 +2119,7 @@ web_security() { echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" - echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" echo "7. 檢視防禦規則清單 8. 查看日誌即時監控" echo "------------------------" echo "11. 設定攔截參數 12. 清除所有拉黑的IP" @@ -2237,7 +2237,7 @@ web_security() { ;; 22) - send_stats "高負載開啟5秒盾" + send_stats "高负载开启5秒盾" echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" @@ -2336,7 +2336,7 @@ check_nginx_compression() { br_status="" fi - # 檢查 gzip 是否開啟且未被註釋 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2403,7 +2403,7 @@ web_optimization() { optimize_balanced - echo "LDNMP環境已設定成 標準模式" + echo "LDNMP环境已设置成 标准模式" ;; 2) @@ -2566,7 +2566,7 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想透過 GitHub Release 判斷) --- + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2647,7 +2647,7 @@ block_container_port() { fi - echo "已阻止IP+連接埠存取該服務" + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2722,7 +2722,7 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供連接埠號碼和允許存取的 IP。" + echo "错误:请提供端口号和允许访问的 IP。" echo "用法: block_host_port <連接埠號碼> <允許的IP>" return 1 fi @@ -2781,7 +2781,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "錯誤:請提供連接埠號碼和允許存取的 IP。" + echo "错误:请提供端口号和允许访问的 IP。" echo "用法: clear_host_port_rules <連接埠號碼> <允許的IP>" return 1 fi @@ -2789,12 +2789,12 @@ clear_host_port_rules() { install iptables - # 清除封禁所有其他 IP 访问的规则 + # 清除封鎖所有其他 IP 存取的規則 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允許本機存取的規則 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2810,7 +2810,7 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允許本機存取的規則 + # 清除允许本机访问的规则 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -3219,10 +3219,10 @@ f2b_sshd() { fi } -# 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) # 說明: # - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) -# - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 +# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 f2b_basic_config() { root_use install nano @@ -3243,7 +3243,7 @@ f2b_basic_config() { echo "即將配置 SSH jail:$jail_name" read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime - read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry + read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry bantime=${bantime:-1h} findtime=${findtime:-10m} @@ -3275,7 +3275,7 @@ EOF } # 直接打开主配置/覆盖配置编辑(nano) -# 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 +# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 f2b_edit_config() { root_use install nano @@ -3551,7 +3551,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-負載平衡" + webname="反向代理-负载均衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四層代理轉送工具$check_docker $update_status" + echo -e "Stream四层代理转发工具 $check_docker $update_status" echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模組,用於實現高效能的 傳輸層流量轉送和負載平衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3865,9 +3865,9 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申請/更新網域憑證 2. 克隆站點域名" + echo "1. 申请/更新域名证书 2. 克隆站点域名" echo "3. 清理站點快取 4. 建立關聯站點" - echo "5. 查看訪問日誌 6. 查看錯誤日誌" + echo "5. 查看访问日志 6. 查看错误日志" echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" @@ -3879,7 +3879,7 @@ ldnmp_web_status() { case $sub_choice in 1) send_stats "申請網域證書" - read -e -p "请输入你的域名: " yuming + read -e -p "請輸入你的網域名稱:" yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null install_ssltls @@ -4084,7 +4084,7 @@ donlond_frp() { generate_frps_config() { - send_stats "安裝frp服務端" + send_stats "安装frp服务端" # 產生隨機連接埠和憑證 local bind_port=8055 local dashboard_port=8056 @@ -4150,7 +4150,7 @@ EOF add_forwarding_service() { send_stats "新增frp內網服務" # 提示使用者輸入服務名稱和轉發訊息 - read -e -p "請輸入服務名稱:" service_name + read -e -p "请输入服务名称: " service_name read -e -p "請輸入轉送類型 (tcp/udp) [回​​車預設tcp]:" service_type local service_type=${service_type:-tcp} read -e -p "請輸入內網IP [回車預設127.0.0.1]:" local_ip @@ -4180,10 +4180,10 @@ EOF delete_forwarding_service() { - send_stats "刪除frp內網服務" + send_stats "删除frp内网服务" # 提示使用者輸入需要刪除的服務名稱 read -e -p "請輸入需要刪除的服務名稱:" service_name - # 使用 sed 刪除該服務及其相關配置 + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "服務$service_name已成功從 frpc.toml 刪除" @@ -4196,7 +4196,7 @@ list_forwarding_services() { local config_file="$1" # 列印表頭 - printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" + printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "内网地址" "外網位址" "協定" awk ' BEGIN { @@ -4271,7 +4271,7 @@ list_forwarding_services() { -# 取得 FRP 服務端端口 +# 获取 FRP 服务端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } @@ -4355,11 +4355,11 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" - echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" echo "00. 刷新服務狀態 0. 返回上一級選單" echo "------------------------" @@ -4395,7 +4395,7 @@ frps_panel() { echo "應用程式已解除安裝" ;; 5) - echo "將內網穿透服務反代成域名訪問" + echo "将内网穿透服务反代成域名访问" send_stats "FRP對外域名訪問" add_yuming read -e -p "請輸入你的內部網路穿透服務埠:" frps_port @@ -4543,7 +4543,7 @@ yt_menu_pro() { echo "已下載影片清單:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" echo "5. 單一影片下載 6. 大量影片下載 7. 自訂參數下載" echo "8. 下載為MP3音訊 9.刪除影片目錄 10. Cookie管理(開發中)" @@ -4779,13 +4779,13 @@ linux_clean() { bbr_on() { -# 统一写入到 sysctl.d 以防与内核调优模块打架 +# 統一寫入到 sysctl.d 以防與核心調優模組打架 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4953,7 +4953,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5096,7 +5096,7 @@ fetch_github_ssh_keys() { echo "操作前,請確保您已在 GitHub 帳戶中新增了 SSH 公鑰:" echo "1. 登入${gh_https_url}github.com/settings/keys" echo "2. 點選 New SSH key 或 Add SSH key" - echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" + echo " 3. Title 可随意填写(例如:Home Laptop 2026)" echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" echo "5. 點選 Add SSH key 完成新增" echo "" @@ -5123,7 +5123,7 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "使用者密鑰登入" + send_stats "用户密钥登录" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5137,8 +5137,8 @@ sshkey_panel() { echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" - echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "1. 生成新密钥对 2. 手动输入已有公钥" + echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5276,7 +5276,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" + echo -e "重装后初始用户名: ${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" @@ -5338,7 +5338,7 @@ dd_xitong() { echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "請選擇要重裝的系統:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in @@ -5393,7 +5393,7 @@ dd_xitong() { exit ;; 14) - send_stats "重裝ubuntu 18.04" + send_stats "重装ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -5418,7 +5418,7 @@ dd_xitong() { ;; 23) - send_stats "重裝alma10" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5522,7 +5522,7 @@ dd_xitong() { ;; 36) - send_stats "重裝飛牛" + send_stats "重装飞牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -5726,7 +5726,7 @@ elrepo_install() { # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 確保我們在一個支援的作業系統上運行 + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "不支援的作業系統:$os_name" break_end @@ -5865,7 +5865,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 執行 Docker 命令 + # 执行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5937,12 +5937,12 @@ clamav() { # ============================================================================ -# Linux 核心調優模組(重構版) +# Linux 内核调优模块(重构版) # 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 # 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ -# 取得記憶體大小(MB) +# 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo } @@ -5957,7 +5957,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}切換到${mode_name}...${gl_bai}" - # ── 根據場景設定參數 ── + # ── 根据场景设定参数 ── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6073,7 +6073,7 @@ net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 遊戲服場景額外:低延遲優先 ── + # ── 游戏服场景额外:低延迟优先 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" @@ -6102,14 +6102,14 @@ net.ipv4.tcp_slow_start_after_idle = 0" QDISC="fq_codel" fi - # ── 備份已有設定 ── + # ── 备份已有配置 ── [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL # kejilion 核心調優配置 -# 模式: $mode_name | 場景: $scene +# 模式: $mode_name | 场景: $scene # 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') # ── TCP 擁塞控制 ── @@ -6232,7 +6232,7 @@ LIMITS fi echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" - echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 拥塞算法: ${CC}| 隊列:${QDISC}${gl_bai}" } # ── 各模式入口函數(保持原有呼叫介面不變) ── @@ -6262,7 +6262,7 @@ restore_defaults() { # 清理 sysctl.conf 裡可能殘留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新載入系統預設配置 + # 重新加载系统默认配置 sysctl --system 2>/dev/null | tail -1 # 還原透明大頁面 @@ -6303,9 +6303,9 @@ Kernel_optimize() { echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" echo -e "3. 網站最佳化模式: 針對網站伺服器最佳化,超高並發連線佇列。" echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" - echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" + echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" - echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" + echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -6457,7 +6457,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}變更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" hash -r break_end @@ -6607,7 +6607,7 @@ create_backup() { # 提示使用者輸入備份目錄 echo "建立備份範例:" - echo "- 備份單一目錄: /var/www" + echo " - 备份单个目录: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input @@ -6624,10 +6624,10 @@ create_backup() { IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 產生備份檔案前綴 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目錄名稱並去除斜杠 + # 提取目录名称并去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done @@ -6691,7 +6691,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -6705,7 +6705,7 @@ delete_backup() { if [ $? -eq 0 ]; then echo "備份刪除成功!" else - echo "备份删除失败!" + echo "備份刪除失敗!" exit 1 fi } @@ -6744,7 +6744,7 @@ linux_backup() { -# SSH 輸入標準化函數 +# SSH 输入标准化函数 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -6837,7 +6837,7 @@ kj_ssh_read_auth() { echo "請選擇身份驗證方式:" echo "1. 密碼" echo "2. 密鑰" - read -e -p "請輸入選擇 (1/2):" auth_choice + read -e -p "请输入选择 (1/2): " auth_choice case $auth_choice in 1) @@ -6958,7 +6958,7 @@ delete_connection() { # 使用連接 use_connection() { send_stats "使用連接" - read -e -p "請輸入要使用的連接編號:" num + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -6975,13 +6975,13 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" echo "1. 密鑰檔案路徑是否正確:$password_or_key" - echo "2. 密鑰檔案權限是否正確(應為 600)。" + echo "2. 密钥文件权限是否正确(应为 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7020,7 +7020,7 @@ ssh_manager() { echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections - echo "1. 建立新連接 2. 使用連接 3. 刪除連接" + echo "1. 创建新连接 2. 使用连接 3. 删除连接" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7101,7 +7101,7 @@ mount_partition() { # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "/etc/fstab 中已存在该分区记录,跳过写入" + echo "/etc/fstab 中已存在該分區記錄,跳過寫入" return 0 fi @@ -7131,11 +7131,11 @@ unmount_partition() { echo "分割區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "分區卸載失敗!" fi } -# 列出已掛載的分割區 +# 列出已挂载的分区 list_mounted_partitions() { echo "已掛載的分割區:" df -h | grep -v "tmpfs\|udev\|overlay" @@ -7174,8 +7174,8 @@ format_partition() { *) echo "無效的選擇!"; return ;; esac - # 确认格式化 - read -e -p "確認格式化分割區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM + # 確認格式化 + read -e -p "确认格式化分区 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return @@ -7252,7 +7252,7 @@ add_task() { send_stats "新增同步任務" echo "建立新同步任務範例:" echo "- 任務名稱: backup_www" - echo "- 本機目錄: /var/www" + echo " - 本地目录: /var/www" echo "- 遠端位址: user@192.168.1.100" echo "- 遠端目錄: /backup/www" echo "- 連接埠號碼 (預設 22)" @@ -7299,7 +7299,7 @@ add_task() { # 刪除任務 delete_task() { send_stats "刪除同步任務" - read -e -p "請輸入要刪除的任務編號:" num + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then @@ -7325,7 +7325,7 @@ run_task() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析參數 + # 解析参数 local direction="push" # 默认是推送到远端 local num @@ -7336,7 +7336,7 @@ run_task() { num="$1" fi - # 如果沒有傳入任務編號,提示使用者輸入 + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then read -e -p "請輸入要執行的任務編號:" num fi @@ -7351,7 +7351,7 @@ run_task() { # 根據同步方向調整來源和目標路徑 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -7668,11 +7668,11 @@ linux_tools() { echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文字編輯器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI程式設計助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}駭客任務螢幕保${gl_kjlan}22. ${gl_bai}跑火車屏保" @@ -7919,7 +7919,7 @@ linux_tools() { ;; *) - echo "無效的輸入!" + echo "无效的输入!" ;; esac break_end @@ -8045,7 +8045,7 @@ docker_ssh_migration() { # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}Compose 項目 [$project_name] 已備份過,跳過重複打包...${gl_bai}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" continue fi @@ -8056,7 +8056,7 @@ docker_ssh_migration() { echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${gl_lv}Compose 項目 [$project_name] 已打包:${project_dir}${gl_bai}" + echo -e "${gl_lv}Compose 項目 [$project_name] 已打包: ${project_dir}${gl_bai}" else echo -e "${gl_hong}未找到 docker-compose.yml,跳過此容器...${gl_bai}" fi @@ -8113,8 +8113,8 @@ docker_ssh_migration() { restore_docker() { send_stats "Docker還原" - read -e -p "请输入要还原的备份目录: " BACKUP_DIR - [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}备份目录不存在${gl_bai}"; return; } + read -e -p "請輸入要還原的備份目錄:" BACKUP_DIR + [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } echo -e "${gl_kjlan}開始執行還原操作...${gl_bai}" @@ -8232,10 +8232,10 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker遷移" install jq - read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR + read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } - kj_ssh_read_host_user_port "目標伺服器IP:" "目標伺服器SSH用戶名 [預設root]:" "目標伺服器SSH連接埠 [預設22]:" "root" "22" + kj_ssh_read_host_user_port "目標伺服器IP:" "目标服务器SSH用户名 [默认root]: " "目標伺服器SSH連接埠 [預設22]:" "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" @@ -8255,7 +8255,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker備份檔案刪除" - read -e -p "請輸入要刪除的備份目錄:" BACKUP_DIR + read -e -p "请输入要删除的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" echo -e "${gl_lv}已刪除備份:${BACKUP_DIR}${gl_bai}" @@ -8265,7 +8265,7 @@ docker_ssh_migration() { # 主選單 # ---------------------------- main_menu() { - send_stats "Docker備份遷移還原" + send_stats "Docker备份迁移还原" while true; do clear echo "------------------------" @@ -8315,18 +8315,18 @@ linux_docker() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}Docker映像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker網路管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker磁碟區管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和映像網路資料卷" + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更換Docker源" + echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" echo -e "${gl_kjlan}9. ${gl_bai}編輯daemon.json文件" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}解除安裝Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -8407,7 +8407,7 @@ linux_docker() { echo "1. 建立網絡" echo "2. 加入網絡" echo "3. 退出網絡" - echo "4. 刪除網絡" + echo "4. 删除网络" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -8422,7 +8422,7 @@ linux_docker() { 2) send_stats "加入網路" read -e -p "加入網路名稱:" dockernetwork - read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername @@ -8441,7 +8441,7 @@ linux_docker() { 4) send_stats "刪除網絡" - read -e -p "請輸入要刪除的網路名稱:" dockernetwork + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -8606,7 +8606,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" @@ -8792,7 +8792,7 @@ linux_Oracle() { 1) clear echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" - read -e -p "确定安装吗? (Y/N):" choice + read -e -p "確定安裝嗎? (Y/N):" choice case "$choice" in [Yy]) @@ -8993,7 +8993,7 @@ linux_ldnmp() { echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" + echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" @@ -9186,11 +9186,11 @@ linux_ldnmp() { echo "網址url: https://$yuming" echo "後台登入路徑: /admin" echo "------------------------" - echo "使用者名稱: admin" + echo "用户名: admin" echo "密碼: admin" echo "------------------------" echo "登入時右上角如果出現紅色error0請使用下列指令:" - echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9368,7 +9368,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9431,13 +9431,13 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 資料庫管理" echo "-------------" - read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有資料庫備份:" use_db case $use_db in 1) echo ;; 2) - echo "資料庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" + echo "資料庫備份必須是.gz結尾的壓縮包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ @@ -9468,7 +9468,7 @@ linux_ldnmp() { echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo "表前綴:$prefix" - echo "管理員登入資訊自行設定" + echo "管理员登录信息自行设置" ;; @@ -9650,7 +9650,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download + read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9699,7 +9699,7 @@ linux_ldnmp() { while true; do clear echo "備份檔案已建立: /home/$backup_filename" - read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice + read -e -p "要传送备份数据到远程服务器吗? (Y/N):" choice case "$choice" in [Yy]) kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" @@ -9730,7 +9730,7 @@ linux_ldnmp() { clear send_stats "定時遠端備份" read -e -p "輸入遠端伺服器IP:" useip - read -e -p "輸入遠端伺服器密碼:" usepasswd + read -e -p "输入远程服务器密码: " usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -10054,7 +10054,7 @@ moltbot_menu() { echo "6. API管理" echo "7. 機器人連線對接" echo "8. 插件管理(安裝/刪除)" - echo "9. 技能管理(安裝/刪除)" + echo "9. 技能管理(安装/删除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" echo "12. 健康檢測與修復" @@ -10304,7 +10304,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳過 {name}: provider 結構非法') + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') continue api = provider.get('api', '') @@ -10313,7 +10313,7 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳過 {name}: 無 baseUrl/apiKey/models') + summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: @@ -10340,7 +10340,7 @@ for name, provider in list(providers.items()): summary.append(f'🔁 {name}: /models 第 {attempts} 次重試後成功') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳過 {name}: /models 回傳結構不可識別') + summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') continue remote_ids = [] @@ -10362,7 +10362,7 @@ for name, provider in list(providers.items()): template = copy.deepcopy(m) break if template is None: - summary.append(f'⚠️ 跳過 {name}: 本地 models 無有效模板模型') + summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') continue removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -10391,7 +10391,7 @@ for name, provider in list(providers.items()): if isinstance(primary_ref, str) and primary_ref in (local_refs - expected_refs): set_primary_ref(defaults, first_ref) changed = True - summary.append(f'🔁 默认模型已兜底替换: {primary_ref} -> {first_ref}') + summary.append(f'🔁 預設模型已兜底替換: {primary_ref} -> {first_ref}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) @@ -10444,7 +10444,7 @@ if changed: else: for line in summary: print(line) - print('ℹ️ 無需同步:配置已與上游 /models 保持一致') + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -10608,7 +10608,7 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" } - # 核心函數:取得並加入所有模型 + # 核心函数:获取并添加所有模型 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" @@ -10679,7 +10679,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10720,7 +10720,7 @@ EOF model_count=$(echo "$available_models" | wc -l) echo "✅ 發現$model_count個可用模型:" echo "--------------------------------" - # 全部顯示,附序號 + # 全部显示,带序号 i=1 model_list=() while read -r model; do @@ -10783,7 +10783,7 @@ EOF } - + openclaw_api_manage_list() { local config_file="${HOME}/.openclaw/openclaw.json" send_stats "OpenClaw API列表" @@ -10849,7 +10849,7 @@ try: with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,請先完成安裝/初始化。') + print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') raise SystemExit(0) except Exception as e: print(f'MSG\t❌ 讀取設定失敗: {type(e).__name__}: {e}') @@ -11019,7 +11019,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') + print(f'ℹ️ provider {target} 目前 api={api},但腳本已不再探測/修正協定;請手動設定為 openai-completions 或 openai-responses') protocol_msg = None @@ -11242,7 +11242,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API刪除入口" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11382,7 +11382,7 @@ PY echo "❌ 刪除失敗:無可用替代模型,已保持原始配置" ;; *) - echo "❌ 刪除失敗:請檢查設定檔結構或日誌輸出" + echo "❌ 删除失败:请检查配置文件结构或日志输出" ;; esac @@ -11390,7 +11390,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API廠商推薦" + send_stats "OpenClaw API厂商推荐" clear echo "" @@ -11500,7 +11500,7 @@ PY if command -v gum >/dev/null 2>&1; then return 0 fi - + if command -v apt >/dev/null 2>&1; then mkdir -p /etc/apt/keyrings curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg @@ -11528,7 +11528,7 @@ REPO } - + change_model() { send_stats "換模型" @@ -11748,7 +11748,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi @@ -11765,7 +11765,7 @@ PYTHON_EOF install_gum install gum - + # 若 gum 不存在,降級為原始手動輸入流程 if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then echo "--- 模型管理 ---" @@ -11787,7 +11787,7 @@ PYTHON_EOF echo "正在切換模型為:$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "切換失敗:openclaw models set 回傳錯誤。" + echo "切换失败:openclaw models set 返回错误。" break_end return 1 fi @@ -11831,7 +11831,7 @@ PYTHON_EOF echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" - printf "是否切換到該模型? [y/N,Esc 返回列表]:" + printf "是否切换到该模型?[y/N,Esc 返回列表]: " IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12077,7 +12077,7 @@ PYTHON_EOF fi fi - echo "⚠️ plugins.allow 移除失败,请手动检查: $config_file" + echo "⚠️ plugins.allow 移除失敗,請手動檢查:$config_file" return 1 } @@ -12085,7 +12085,7 @@ PYTHON_EOF - + install_plugin() { send_stats "外掛管理" while true; do @@ -12113,7 +12113,7 @@ PYTHON_EOF echo "" echo "⚙️ 功能擴充:" echo "- [lobster] # 審批流 (附人工確認)" - echo " - [voice-call] # 语音通话能力" + echo "- [voice-call] # 語音通話能力" echo "- [nostr] # 加密隱私聊天" echo "--------------------------------------------------------" @@ -12193,7 +12193,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ 已卸載:$plugin_id" else - echo "⚠️ 卸载失败,可能为预装插件,仅禁用: $plugin_id" + echo "⚠️ 卸載失敗,可能為預先安裝插件,僅停用:$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12245,7 +12245,7 @@ PYTHON_EOF echo "coding-agent # 自動運行 Claude Code/Codex 等程式設計助手" echo "----------------------------------------" - echo "1) 安裝技能" + echo "1) 安装技能" echo "2) 刪除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -12264,7 +12264,7 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "二次確認:刪除僅影響使用者目錄 ~/.openclaw/workspace/skills,確認繼續? (y/N):" confirm_del + read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续? (y/N):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then echo "已取消刪除。" break_end @@ -12568,9 +12568,9 @@ openclaw_json_get_bool() { echo "----------------------------------------" echo "1. Telegram 機器人對接" echo "2. 飛書 (Lark) 機器人對接" - echo "3. WhatsApp 機器人對接" + echo "3. WhatsApp 机器人对接" echo "4. QQ 機器人對接" - echo "5. 微信機器人對接" + echo "5. 微信机器人对接" echo "----------------------------------------" echo "0. 返回上一級選單" echo "----------------------------------------" @@ -12719,7 +12719,7 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 文件不存在:$archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } mkdir -p "$unpack_root" tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 備份包解壓縮失敗"; return 1; } @@ -12742,7 +12742,7 @@ EOF ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 校驗失敗,拒絕還原"; return 1; } + ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } echo "$pkg_dir" return 0 @@ -12777,7 +12777,7 @@ PY mkdir -p "$backup_root" local tmp_payload=$(mktemp -d) || return 1 local workspaces_json=$(openclaw_get_all_agent_workspaces) - python3 -c "import json, sys, os, shutil; + python3 -c "import json, sys, os, shutil; workspaces = json.loads(sys.argv[1]); tmp_payload = sys.argv[2] for item in workspaces: aid = item['id']; ws = item['ws'] @@ -12826,7 +12826,7 @@ if os.path.isdir(agents_root): openclaw_project_backup_export() { - send_stats "OpenClaw專案備份" + send_stats "OpenClaw项目备份" local config_file config_file=$(openclaw_get_config_file) local openclaw_root @@ -12838,7 +12838,7 @@ if os.path.isdir(agents_root): fi echo "備份模式:" - echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多狀態,敏感風險較高)" read -e -p "請選擇備份模式(預設 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -13059,7 +13059,7 @@ if os.path.isdir(agents_root): return 0 fi - read -e -p "請輸入要刪除的檔案名稱或完整路徑(0 取消):" user_input + read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input if [ "$user_input" = "0" ]; then echo "已取消刪除。" break_end @@ -13271,7 +13271,7 @@ PY if mv "$store_file" "$backup_file"; then echo "✅ [$agent_id] 已備份索引:$backup_file" else - echo "⚠️ [$agent_id] 索引備份失敗,繼續重建。" + echo "⚠️ [$agent_id] 索引备份失败,继续重建。" fi fi openclaw memory index --agent "$agent_id" --force @@ -13314,7 +13314,7 @@ EOF fi memory_dir="$workspace/memory" if [ ! -d "$memory_dir" ]; then - echo "🔧 [$agent_id] 記憶目錄不存在,已自動建立:$memory_dir" + echo "🔧 [$agent_id] 记忆目录不存在,已自动创建: $memory_dir" mkdir -p "$memory_dir" fi return 0 @@ -13339,7 +13339,7 @@ EOF local json_output json_output=$(openclaw memory status --json 2>/dev/null) if [ -z "$json_output" ]; then - echo "取得記憶狀態失敗(openclaw memory status --json 無輸出)" + echo "获取记忆状态失败(openclaw memory status --json 无输出)" return 1 fi python3 - "$json_output" <<'PY' @@ -13466,7 +13466,7 @@ PY if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未檢測到 QMD") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路徑:$model_path") @@ -13560,7 +13560,7 @@ PY wget -O "$dest" "$url" return $? fi - echo "❌ 未偵測到 curl 或 wget,無法下載。" + echo "❌ 未检测到 curl 或 wget,无法下载。" return 1 } @@ -13659,7 +13659,7 @@ PY echo "地區:$OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then - echo "下载源: $OPENCLAW_MEMORY_HF_BASE" + echo "下載來源:$OPENCLAW_MEMORY_HF_BASE" fi echo "最終狀態:" openclaw_memory_render_status @@ -13671,21 +13671,21 @@ PY OPENCLAW_MEMORY_PREHEAT="true" OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" - echo "即將執行自動部署(詳細模式)" + echo "即将执行自动部署(详细模式)" echo "目標方案:$scheme_label" echo "地區: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" echo "鏡像來源探測: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下載來源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then - echo "預計下載路徑:$OPENCLAW_MEMORY_EXPECT_PATH" + echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" fi if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then echo "可能流量/磁碟佔用:$OPENCLAW_MEMORY_EXPECT_SIZE" else - echo "可能流量/磁碟佔用: 視實際情況而定" + echo "可能流量/磁盘占用: 视实际情况而定" fi echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" - echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" + echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step case "$confirm_step" in yes|YES) @@ -13981,7 +13981,7 @@ EOF fi else echo "includeDefaultMemory 配置正常。" - echo "将执行:清理旧索引 → 全量重建所有智能体索引" + echo "將執行:清理舊索引 → 全量重建所有智能體索引" echo "" read -e -p "確認執行? (Y/n):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14012,7 +14012,7 @@ EOF echo "Local: 本機向量檢索,依賴 embedding 模型文件" echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" - echo "1. 切換 QMD(自動部署/已安裝則跳過)" + echo "1. 切换 QMD(自动部署/已装则跳过)" echo "2. 切換 Local(自動部署/已安裝則跳過)" echo "3. Auto(自動推薦並自動部署)" echo "0. 返回上一級" @@ -14098,8 +14098,8 @@ EOF local start_line count echo "文件:$file" echo "總行數:$total_lines" - read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line - read -e -p "請輸入顯示行數(回車預設$default_lines): " count + read -e -p "请输入起始行(回车默认末尾 $default_lines行):" start_line + read -e -p "请输入显示行数(回车默认 $default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14169,7 +14169,7 @@ EOF openclaw_memory_search_test() { read -e -p "輸入搜尋關鍵字:" query if [ -z "$query" ]; then - echo "關鍵字不能為空。" + echo "关键词不能为空。" return 1 fi echo "正在搜尋記憶..." @@ -14190,7 +14190,7 @@ EOF echo "=======================================" openclaw_memory_render_status echo "1. 更新記憶索引" - echo "2. 檢視記憶文件" + echo "2. 查看记忆文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" echo "5. 搜尋測試(驗證索引是否運作)" @@ -14314,7 +14314,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + echo "❌ 未偵測到 openclaw,無法重新啟動 OpenClaw Gateway。" return 1 fi echo "正在重啟 OpenClaw Gateway..." @@ -14447,9 +14447,9 @@ PY local ask="$2" local fallback="$3" local approvals_file="$HOME/.openclaw/exec-approvals.json" - + mkdir -p "$HOME/.openclaw" - + # 產生 JSON 並透過 openclaw approvals set --stdin 寫入(優先) # 若 CLI 不支援則回退直接寫文件 local json_payload @@ -14472,7 +14472,7 @@ data["defaults"]["askFallback"] = sys.argv[4] data["defaults"]["autoAllowSkills"] = True print(json.dumps(data, indent=2)) ' "$approvals_file" "$sec" "$ask" "$fallback") - + if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi @@ -14482,7 +14482,7 @@ print(json.dumps(data, indent=2)) openclaw_permission_render_status() { echo "應用層配置: ~/.openclaw/openclaw.json" - echo "宿主機核准: ~/.openclaw/exec-approvals.json" + echo "宿主机审批: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" local current_profile current_sec current_ask current_elevated current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') @@ -14508,11 +14508,11 @@ print(json.dumps(data, indent=2)) echo -e "當前綜合安全等級:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" - echo " Profile (预设): ${current_profile:-(unset)}" - echo "Exec 限制: ${current_sec:-(unset)}" + echo "Profile (預設): ${current_profile:-(unset)}" + echo " Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" - + echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" if openclaw_has_command openclaw; then local approvals_json @@ -14563,7 +14563,7 @@ except Exception: openclaw_permission_apply_standard() { send_stats "OpenClaw權限-標準安全模式" openclaw_permission_require_openclaw || return 1 - + echo "正在設定應用層策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 @@ -14571,10 +14571,10 @@ except Exception: openclaw config set tools.elevated.enabled false >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval true >/dev/null 2>&1 # 拦截危险的内联代码 openclaw config unset commands.bash >/dev/null 2>&1 # 废弃旧版参数 - + echo "正在設定宿主機審批攔截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切換為標準安全模式 (所有危險命令將透過UI/TG請求你的批准)${gl_bai}" } @@ -14582,36 +14582,36 @@ except Exception: openclaw_permission_apply_developer() { send_stats "OpenClaw權限-開發增強模式" openclaw_permission_require_openclaw || return 1 - + echo "正在設定應用層策略..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 # 允许智能体申请提权 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在設定宿主機審批攔截..." openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" - + openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切換為開發增強模式 (允許提權,但常規危險命令仍需審批)${gl_bai}" + echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } openclaw_permission_apply_full() { - send_stats "OpenClaw權限-完全開放模式" + send_stats "OpenClaw权限-完全开放模式" openclaw_permission_require_openclaw || return 1 - + echo "正在設定應用層策略..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 openclaw config set tools.elevated.enabled true >/dev/null 2>&1 openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 - + echo "正在瓦解宿主機攔截防禦..." # 這裡的 full 和 off 將徹底繞過底層宿主機的 exec 審批系統 openclaw_permission_update_exec_approvals "full" "off" "full" - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已切換為完全開放模式 (警告:所有宿主機指令攔截已失效,智能體具有最高權限)${gl_bai}" } @@ -14619,14 +14619,14 @@ except Exception: openclaw_permission_restore_official_defaults() { send_stats "OpenClaw權限-恢復官方默認" openclaw_permission_require_openclaw || return 1 - + echo "清理應用層強制覆蓋..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - + echo "清理宿主機攔截配置..." # 優先透過 CLI 清空審核配置,回退直接刪文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then @@ -14634,14 +14634,14 @@ except Exception: else rm -f "$HOME/.openclaw/exec-approvals.json" fi - + openclaw_permission_restart_gateway echo -e "${gl_lv}✅ 已恢復到 OpenClaw 官方安全沙盒防禦機制${gl_bai}" } openclaw_permission_run_audit() { echo "=======================================" - echo "運行 OpenClaw 官方安全審計與體檢..." + echo "运行 OpenClaw 官方安全审计与体检..." echo "=======================================" openclaw security audit echo "---------------------------------------" @@ -14697,7 +14697,7 @@ except Exception as e: 1) read -e -p "輸入要放行的命令路徑 (支援 glob,如 /usr/bin/git):" pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } - read -e -p "指定智能體ID (留空=所有智能體 *):" agent_id + read -e -p "指定智能体ID (留空=所有智能体 *): " agent_id agent_id="${agent_id:-*}" openclaw approvals allowlist add --agent "$agent_id" "$pattern" break_end @@ -14723,12 +14723,12 @@ except Exception as e: echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" + echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" - echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" + echo -e "${gl_kjlan}6.${gl_bai} 管理 Exec 命令白名单" echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" perm_choice @@ -14976,7 +14976,7 @@ else: bcount = item.get("bindings", 0) default_tag = "[預設]" if is_default else "" print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) - print("身份名稱: %s %s" % (identity, emoji)) + print(" 身份名称: %s %s" % (identity, emoji)) print("模型: %s" % model) print("工作目錄: %s" % ws) print("綁定數: %s" % bcount) @@ -14995,7 +14995,7 @@ for idx,item in enumerate(agents,1): send_stats "OpenClaw多智能體-新增Agent" openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm - read -e -p "請輸入新的 Agent ID:" agent_id + read -e -p "请输入新的 Agent ID: " agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 read -e -p "請輸入 workspace 路徑(預設為 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" @@ -15006,14 +15006,14 @@ for idx,item in enumerate(agents,1): if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ 智能體創建成功:$agent_id" local name theme - read -e -p "請輸入智能體身分名稱 (如: 代碼專家):" name + read -e -p "请输入智能体身份名称 (如: 代码专家): " name [ -z "$name" ] && name="$agent_id" read -e -p "請輸入智能體性格主題 (如: 嚴謹、有效率):" theme [ -z "$theme" ] && theme="助理" echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體創建失敗" + echo "❌ 智能體建立失敗" return 1 fi } @@ -15062,7 +15062,7 @@ for idx,item in enumerate(bindings,1): if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ 路由綁定新增成功" else - echo "❌ 路由綁定新增失敗" + echo "❌ 路由绑定添加失败" return 1 fi } @@ -15074,13 +15074,13 @@ for idx,item in enumerate(bindings,1): read -e -p "請輸入智能體 ID:" agent_id read -e -p "請輸入要移除的路由綁定值:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 - echo "將移除智能體 [$agent_id] 的路由綁定 [$bind_value]" + echo "将移除智能体 [$agent_id] 的路由綁定 [$bind_value]" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由绑定移除成功" + echo "✅ 路由綁定移除成功" else - echo "❌ 路由绑定移除失败" + echo "❌ 路由綁定移除失敗" return 1 fi } @@ -15121,7 +15121,7 @@ for item in sessions[:10]: openclaw_multiagent_require_openclaw || return 1 local config_file config_file=$(openclaw_multiagent_config_file) - echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" + echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" python3 -c ' import json,sys,os @@ -15129,7 +15129,7 @@ agents=json.loads(sys.argv[1] or "[]") bindings=json.loads(sys.argv[2] or "[]") print("---------------------------------------") if not agents: - print("⚠️ 未發現配置智能體。") + print("⚠️ 未发现已配置智能体。") else: for item in agents: ws = item.get("workspace") or "" @@ -15156,15 +15156,15 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_require_openclaw || return 1 openclaw_multiagent_list_agents read -e -p "輸入要修改身分的智能體ID:" agent_id - [ -z "$agent_id" ] && { echo "ID 不能為空"; return 1; } - echo "修改選項(留空跳過):" + [ -z "$agent_id" ] && { echo "ID 不能为空"; return 1; } + echo "修改选项(留空跳过):" read -e -p "新名稱:" new_name read -e -p "新 Emoji:" new_emoji local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" echo "也可以從 IDENTITY.md 自動讀取身分資訊。" - read -e -p "是否從 IDENTITY.md 讀取? (y/n):" from_id + read -e -p "是否从 IDENTITY.md 读取? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" fi @@ -15367,14 +15367,14 @@ openclaw_backup_restore_menu() { if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已將域名${yuming} 加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi openclaw devices list - read -e -p "请输入 Request_Key: " Request_Key + read -e -p "請輸入 Request_Key:" Request_Key [ -z "$Request_Key" ] && { echo "Request_Key 不能為空" @@ -15449,11 +15449,10 @@ openclaw_backup_restore_menu() { ;; 12) send_stats "健康檢測與修復" openclaw doctor --fix - break_end - ;; + ;; 13) openclaw_webui_menu ;; - 14) send_stats "TUI命令列對話" + 14) send_stats "TUI命令行对话" openclaw tui break_end ;; @@ -15539,7 +15538,7 @@ while true; do echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" echo -e "${gl_kjlan}55. ${color55}FRP內網穿透(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRP內網穿透(客戶端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型 ${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}57. ${color57}Deepseek聊天AI大模型${gl_kjlan}58. ${color58}Dify大模型知識庫${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI大模型資產管理${gl_kjlan}60. ${color60}JumpServer開源堡壘機" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" @@ -15572,11 +15571,12 @@ while true; do echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大內網穿透工具" + echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw機器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" - echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}想要让你的应用出现在这里?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -16616,7 +16616,7 @@ while true; do } - local docker_describe="photoprism非常強大的私有相簿系統" + local docker_describe="photoprism非常强大的私有相册系统" local docker_url="官網介紹: https://www.photoprism.app/" local docker_use="echo \"帳號: admin 密碼:$rootpasswd\"" local docker_passwd="" @@ -16958,7 +16958,7 @@ while true; do } - local docker_describe="Docker Registry 是一个用于存储和分发 Docker 镜像的服务。" + local docker_describe="Docker Registry 是一個用於儲存和分發 Docker 映像的服務。" local docker_url="官網介紹: https://hub.docker.com/_/registry" local docker_use="" local docker_passwd="" @@ -17002,7 +17002,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼均為: admin" + echo "初始使用者名稱密碼皆為: admin" } docker_app_update() { @@ -17893,7 +17893,7 @@ while true; do local app_id="80" local app_name="linkwarden書籤管理" local app_text="一個開源的自架書籤管理平台,支援標籤、搜尋和團隊協作。" - local app_url="官方網站: https://linkwarden.app/" + local app_url="官方网站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -18748,7 +18748,7 @@ while true; do local app_id="99" local app_name="dsm群暉虛擬機" - local app_text="Docker容器中的虚拟DSM" + local app_text="Docker容器中的虛擬DSM" local app_url="官網:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" @@ -18756,7 +18756,7 @@ while true; do docker_app_install() { - read -e -p "設定 CPU 核數 (預設 2):" CPU_CORES + read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES local CPU_CORES=${CPU_CORES:-2} read -e -p "設定記憶體大小 (預設 4G):" RAM_SIZE @@ -19113,7 +19113,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" local app_name="karakeep書籤管理" - local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" + local app_text="是一款可自行託管的書籤應用,具有人工智慧功能,專為資料囤積者而設計。" local app_url="官方網站:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" @@ -19241,6 +19241,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ moltbot_menu ;; + 115|hermes) + bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) + ;; b) clear @@ -19467,7 +19470,7 @@ linux_work() { install tmux local SESSION_NAME="sshd" send_stats "啟動工作區$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自動進入 tmux 會話\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -19618,7 +19621,7 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH防禦基礎參數配置" + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; @@ -19679,7 +19682,7 @@ net_menu() { send_stats "啟用網卡" read -erp "請輸入要啟用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 网卡 $nic已啟用" + ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else echo "✘ 網路卡不存在" fi @@ -19802,7 +19805,7 @@ log_menu() { echo "⚠️ 清理 journal 日誌(安全方式)" echo "1) 保留最近 7 天" echo "2) 保留最近 3 天" - echo "3) 限制日志最大 500M" + echo "3) 限制日誌最大 500M" read -erp "請選擇清理方式:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -20100,7 +20103,7 @@ linux_Settings() { echo "---------------------------------------" echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') - echo -e "当前python版本号: ${gl_huang}$VERSION${gl_bai}" + echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" echo "查詢更多版本: https://www.python.org/downloads/" @@ -20210,7 +20213,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH埠修改" + send_stats "退出SSH連接埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20380,7 +20383,7 @@ EOF echo "------------------------" echo "1. 建立普通用戶 2. 建立進階用戶" echo "------------------------" - echo "3. 賦予最高權限 4. 取消最高權限" + echo "3. 赋予最高权限 4. 取消最高权限" echo "------------------------" echo "5. 刪除帳號" echo "------------------------" @@ -20391,7 +20394,7 @@ EOF case $sub_choice in 1) # 提示使用者輸入新使用者名稱 - read -e -p "請輸入新用戶名:" new_username + read -e -p "请输入新用户名: " new_username create_user_with_sshkey $new_username false ;; @@ -20512,11 +20515,11 @@ EOF echo "歐洲" echo "11. 英國倫敦時間 12. 法國巴黎時間" echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" - echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" + echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" echo "------------------------" echo "美洲" echo "21. 美國西部時間 22. 美國東部時間" - echo "23. 加拿大時間 24. 墨西哥時間" + echo "23. 加拿大时间 24. 墨西哥时间" echo "25. 巴西時間 26. 阿根廷時間" echo "------------------------" echo "31. UTC全球標準時間" @@ -20615,7 +20618,7 @@ EOF echo "選擇更新來源區域" echo "接入LinuxMirrors切換系統更新來源" echo "------------------------" - echo "1. 中國大陸【預設】 2. 中國大陸【教育網】 3. 海外地區 4. 智慧切換更新源" + echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20658,7 +20661,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 新增定時任務 2. 刪除定時任務 3. 編輯定時任務" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20669,7 +20672,7 @@ EOF read -e -p "請輸入新任務的執行指令:" newquest echo "------------------------" echo "1. 每月任務 2. 每週任務" - echo "3. 每天任務 4. 每小時任務" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" read -e -p "請輸入你的選擇:" dingshi @@ -20683,7 +20686,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "選擇每天幾點執行任務? (小時,0-23):" hour + read -e -p "選擇每天幾點執行任務? (小时,0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -20724,7 +20727,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 添加新的解析 2. 删除解析地址" + echo "1. 新增新的解析 2. 刪除解析位址" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20760,14 +20763,14 @@ EOF while true; do clear echo "限流關機功能" - echo "影片介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" echo "目前流量使用情況,重啟伺服器流量計算會清除!" output_status echo -e "${gl_kjlan}總接收:${gl_bai}$rx" echo -e "${gl_kjlan}總發送:${gl_bai}$tx" - # 檢查是否存在 Limiting_Shut_down.sh 文件 + # 检查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then # 取得 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) @@ -20780,7 +20783,7 @@ EOF echo echo "------------------------------------------------" - echo "系統每分鐘會偵測實際流量是否到達閾值,到達後會自動關閉伺服器!" + echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" echo "------------------------" echo "1. 開啟限流關機功能 2. 停用限流關機功能" echo "------------------------" @@ -20833,18 +20836,18 @@ EOF 25) root_use - send_stats "電報預警" + send_stats "电报预警" echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" - echo "到達閾值後會向用戶發送預警訊息" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "到达阈值后会向用户发预警消息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) - send_stats "電報預警啟用" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -20891,7 +20894,7 @@ EOF 26) root_use - send_stats "修復SSH高風險漏洞" + send_stats "修复SSH高危漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -20991,12 +20994,12 @@ EOF echo "2. 清理系統垃圾文件" echo -e "3. 設定虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" - echo -e "5. 啟動fail2ban防禦SSH暴力破解" - echo -e "6. 開放所有端口" + echo -e "5. 启动fail2ban防御SSH暴力破解" + echo -e "6. 开放所有端口" echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 設定網路為${gl_huang}ipv4优先${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" @@ -21086,7 +21089,7 @@ EOF fi echo "隱私與安全" - echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" + echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" echo -e "目前狀態:$status_message" @@ -21109,7 +21112,7 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已關閉採集" + echo "已关闭采集" send_stats "隱私與安全已關閉採集" ;; *) @@ -21191,7 +21194,7 @@ linux_file() { echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" - echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" + echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" echo "25. 傳文件至其他伺服器" echo "------------------------" echo "0. 返回上一級選單" @@ -21212,7 +21215,7 @@ linux_file() { 3) # 修改目录权限 read -e -p "請輸入目錄名:" dirname read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失敗" send_stats "修改目錄權限" ;; 4) # 重命名目录 @@ -21267,7 +21270,7 @@ linux_file() { 22) # 解压文件/目录 read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" + tar -xzvf "$filename" && echo "已解压 $filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" ;; @@ -21275,7 +21278,7 @@ linux_file() { read -e -p "請輸入要移動的檔案或目錄路徑:" src_path if [ ! -e "$src_path" ]; then echo "錯誤: 檔案或目錄不存在。" - send_stats "移动文件或目录失败: 文件或目录不存在" + send_stats "移動檔案或目錄失敗: 檔案或目錄不存在" continue fi @@ -21287,12 +21290,12 @@ linux_file() { fi mv "$src_path" "$dest_path" && echo "檔案或目錄已移動到$dest_path" || echo "移動檔案或目錄失敗" - send_stats "移動檔案或目錄" + send_stats "移动文件或目录" ;; 24) # 复制文件目录 - read -e -p "請輸入要複製的檔案或目錄路徑:" src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then echo "錯誤: 檔案或目錄不存在。" send_stats "複製檔案或目錄失敗: 檔案或目錄不存在" @@ -21316,7 +21319,7 @@ linux_file() { read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "錯誤: 文件不存在。" - send_stats "傳送文件失敗: 文件不存在" + send_stats "传送文件失败: 文件不存在" continue fi @@ -21332,7 +21335,7 @@ linux_file() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp傳輸文件 + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" </dev/null - # 下载到临时文件,校验后再替换 + # 下載到臨時文件,校驗後再替換 local tmp_file=$(mktemp ~/kejilion_tmp.XXXXXX) if curl -sS --max-time 60 --fail -o "$tmp_file" "$download_url" && \ [ -s "$tmp_file" ] && \ @@ -21693,7 +21696,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" @@ -21701,7 +21704,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下载出错或文件校验不通过,已恢复原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21730,7 +21733,7 @@ while true; do if [ -n "$cron_sed_cmd" ]; then SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi - # 從舊腳本恢復 permission_granted 和 ENABLE_STATS 設置 + # 从旧脚本恢复 permission_granted 和 ENABLE_STATS 设置 SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # 部署到 /usr/local/bin/k 和 /usr/bin/k SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21846,7 +21849,7 @@ echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" -echo "軟體啟動 k start sshd | k 啟動 sshd" +echo "软件启动 k start sshd | k 启动 sshd " echo "軟體停止 k stop sshd | k 停止 sshd" echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" @@ -21861,17 +21864,17 @@ echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" -echo "安装负载均衡 k loadbalance |k 负载均衡" +echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" -echo "防火牆面板 k fhq |k 防火牆" -echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" -echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" +echo "防火墙面板 k fhq |k 防火墙" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" +echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統資訊 k info" echo "ROOT金鑰管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " @@ -21882,7 +21885,7 @@ echo "SSH公鑰導入(GitHub) k sshkey github " if [ "$#" -eq 0 ]; then - # 如果沒有參數,運行互動式邏輯 + # 如果没有参数,运行交互式逻辑 kejilion_sh else # 如果有參數,執行對應函數 From e6064fb153379b10daad5fce1206489cf5ea6918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:01:13 +0800 Subject: [PATCH 1156/1285] Fix regex in get_running_status function --- kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 3506f4670..0b3bbff28 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10022,8 +10022,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" else echo "${gl_hui}未运行${gl_bai}" From 44c6e629d72734b91e4ab10592e9d05c74c28671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:02:25 +0800 Subject: [PATCH 1157/1285] Fix regex in get_running_status function --- cn/kejilion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3506f4670..0b3bbff28 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -10022,8 +10022,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}运行中${gl_bai}" else echo "${gl_hui}未运行${gl_bai}" From 22d054393d3bc50206017b5fc2c6a60d4db70a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:04:15 +0800 Subject: [PATCH 1158/1285] Change 'canshu' value from 'CN' to 'default' --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 0b3bbff28..233858432 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" From d9a56a962a455a753caa70a52428426f95b6b05c Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 1 May 2026 23:10:47 +0800 Subject: [PATCH 1159/1285] fix: refine BBRv3 XanMod lifecycle logic --- cn/kejilion.sh | 159 ++++++++++++++++++++++++++++--------------------- kejilion.sh | 159 ++++++++++++++++++++++++++++--------------------- 2 files changed, 182 insertions(+), 136 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 0b3bbff28..6b6c48d4b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5597,6 +5597,76 @@ bbrv3() { root_use send_stats "bbrv3管理" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o "$keyring" --yes || return 1 + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" + } + + xanmod_detect_package() { + local psabi_output="" + local psabi_level="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + psabi_level=$(printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1) + [ -n "$psabi_level" ] || return 1 + printf 'linux-xanmod-x64v%s\n' "$psabi_level" + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod官方仓库配置失败,请稍后重试" + return 1 + } + + package=$(xanmod_detect_package) || { + echo "无法识别当前CPU的x86-64 psABI等级,已取消安装" + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" + else + apt install -y "$package" + fi + + bbr_on + echo "XanMod BBRv3内核处理完成。重启后生效" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "XanMod内核已卸载。重启后生效" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5674,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "当前环境不支持,仅支持Debian和Ubuntu系统" + break_end + linux_Settings + fi + else + echo "无法确定操作系统类型" + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5705,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步骤3:添加存储库 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod内核已更新。重启后生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "XanMod内核已卸载。重启后生效" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5729,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" - break_end - linux_Settings - fi - else - echo "无法确定操作系统类型" - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步骤3:添加存储库 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "XanMod内核安装并BBR3启用成功。重启后生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "已取消" @@ -5718,7 +5742,6 @@ bbrv3() { } - elrepo_install() { # 导入 ELRepo GPG 公钥 echo "导入 ELRepo GPG 公钥..." diff --git a/kejilion.sh b/kejilion.sh index 233858432..423388df2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5597,6 +5597,76 @@ bbrv3() { root_use send_stats "bbrv3管理" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o "$keyring" --yes || return 1 + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" + } + + xanmod_detect_package() { + local psabi_output="" + local psabi_level="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + psabi_level=$(printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1) + [ -n "$psabi_level" ] || return 1 + printf 'linux-xanmod-x64v%s\n' "$psabi_level" + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod官方仓库配置失败,请稍后重试" + return 1 + } + + package=$(xanmod_detect_package) || { + echo "无法识别当前CPU的x86-64 psABI等级,已取消安装" + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" + else + apt install -y "$package" + fi + + bbr_on + echo "XanMod BBRv3内核处理完成。重启后生效" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "XanMod内核已卸载。重启后生效" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5674,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "当前环境不支持,仅支持Debian和Ubuntu系统" + break_end + linux_Settings + fi + else + echo "无法确定操作系统类型" + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5705,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步骤3:添加存储库 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod内核已更新。重启后生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "XanMod内核已卸载。重启后生效" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5729,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" - break_end - linux_Settings - fi - else - echo "无法确定操作系统类型" - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步骤3:添加存储库 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "XanMod内核安装并BBR3启用成功。重启后生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "已取消" @@ -5718,7 +5742,6 @@ bbrv3() { } - elrepo_install() { # 导入 ELRepo GPG 公钥 echo "导入 ELRepo GPG 公钥..." From 1139a3d3971832cd80f3f3d5ebd0de069393b996 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Fri, 1 May 2026 23:33:45 +0800 Subject: [PATCH 1160/1285] fix: keep CN fallback for XanMod key download --- cn/kejilion.sh | 7 ++++++- kejilion.sh | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6b6c48d4b..61ef850a6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5600,10 +5600,15 @@ bbrv3() { xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d - wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o "$keyring" --yes || return 1 + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "官方密钥下载失败,尝试备用下载源..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi chmod 644 "$keyring" echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" } diff --git a/kejilion.sh b/kejilion.sh index 423388df2..7cb378956 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5600,10 +5600,15 @@ bbrv3() { xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d - wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o "$keyring" --yes || return 1 + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "官方密钥下载失败,尝试备用下载源..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi chmod 644 "$keyring" echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" } From 6268b2ea04b38b1d7aef594debefb6a13bf5a181 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 2 May 2026 10:41:07 +0800 Subject: [PATCH 1161/1285] fix(bbrv3): update XanMod repo logic and add package fallback --- cn/kejilion.sh | 72 +++++++++++++++++++++++++++++++++++++++++++------- kejilion.sh | 72 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 126 insertions(+), 18 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 61ef850a6..d5e6d9f37 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5602,6 +5602,18 @@ bbrv3() { local list_file="/etc/apt/sources.list.d/xanmod-release.list" local key_url="https://dl.xanmod.org/archive.key" local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + if [ -z "$os_codename" ]; then + echo "无法获取系统代号,无法配置XanMod源" + return 1 + fi install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d @@ -5610,12 +5622,11 @@ bbrv3() { wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" - echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" } - xanmod_detect_package() { + xanmod_detect_psabi_level() { local psabi_output="" - local psabi_level="" psabi_output=$(awk 'BEGIN { while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 @@ -5625,9 +5636,43 @@ bbrv3() { if (level > 0) { print level; exit } exit 1 }' /proc/cpuinfo 2>/dev/null) || return 1 - psabi_level=$(printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1) + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 [ -n "$psabi_level" ] || return 1 - printf 'linux-xanmod-x64v%s\n' "$psabi_level" + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "已自动匹配合适安装包: $package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "软件源中未找到适配此CPU的XanMod内核包" >&2 + return 1 } xanmod_installed() { @@ -5646,18 +5691,27 @@ bbrv3() { } package=$(xanmod_detect_package) || { - echo "无法识别当前CPU的x86-64 psABI等级,已取消安装" + echo "无法识别当前CPU或找不到匹配内核包,已取消安装" return 1 } apt update -y if [ "$action" = "update" ]; then - apt install -y --only-upgrade "$package" || apt install -y "$package" + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod内核更新失败,请检查软件源或稍后重试" + return 1 + } else - apt install -y "$package" + apt install -y "$package" || { + echo "XanMod内核安装失败,请检查软件源或稍后重试" + return 1 + } fi - bbr_on + bbr_on || { + echo "BBR3参数写入失败,请检查系统配置" + return 1 + } echo "XanMod BBRv3内核处理完成。重启后生效" server_reboot } diff --git a/kejilion.sh b/kejilion.sh index 7cb378956..af536c707 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5602,6 +5602,18 @@ bbrv3() { local list_file="/etc/apt/sources.list.d/xanmod-release.list" local key_url="https://dl.xanmod.org/archive.key" local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + if [ -z "$os_codename" ]; then + echo "无法获取系统代号,无法配置XanMod源" + return 1 + fi install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d @@ -5610,12 +5622,11 @@ bbrv3() { wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" - echo "deb [signed-by=$keyring] http://deb.xanmod.org releases main" > "$list_file" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" } - xanmod_detect_package() { + xanmod_detect_psabi_level() { local psabi_output="" - local psabi_level="" psabi_output=$(awk 'BEGIN { while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 @@ -5625,9 +5636,43 @@ bbrv3() { if (level > 0) { print level; exit } exit 1 }' /proc/cpuinfo 2>/dev/null) || return 1 - psabi_level=$(printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1) + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 [ -n "$psabi_level" ] || return 1 - printf 'linux-xanmod-x64v%s\n' "$psabi_level" + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "已自动匹配合适安装包: $package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "软件源中未找到适配此CPU的XanMod内核包" >&2 + return 1 } xanmod_installed() { @@ -5646,18 +5691,27 @@ bbrv3() { } package=$(xanmod_detect_package) || { - echo "无法识别当前CPU的x86-64 psABI等级,已取消安装" + echo "无法识别当前CPU或找不到匹配内核包,已取消安装" return 1 } apt update -y if [ "$action" = "update" ]; then - apt install -y --only-upgrade "$package" || apt install -y "$package" + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod内核更新失败,请检查软件源或稍后重试" + return 1 + } else - apt install -y "$package" + apt install -y "$package" || { + echo "XanMod内核安装失败,请检查软件源或稍后重试" + return 1 + } fi - bbr_on + bbr_on || { + echo "BBR3参数写入失败,请检查系统配置" + return 1 + } echo "XanMod BBRv3内核处理完成。重启后生效" server_reboot } From 5c233aee695864ba385d51f188a777e1b3d41528 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sat, 2 May 2026 11:09:11 +0800 Subject: [PATCH 1162/1285] fix(bbrv3): keep fallback to 'releases' repo for unsupported legacy OS versions --- cn/kejilion.sh | 5 +++++ kejilion.sh | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d5e6d9f37..51affb3a0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5610,6 +5610,11 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi + # 兼容官方已移除的老系统代号(回退使用 releases 尝试旧包库) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + if [ -z "$os_codename" ]; then echo "无法获取系统代号,无法配置XanMod源" return 1 diff --git a/kejilion.sh b/kejilion.sh index af536c707..15c855de4 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5610,6 +5610,11 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi + # 兼容官方已移除的老系统代号(回退使用 releases 尝试旧包库) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + if [ -z "$os_codename" ]; then echo "无法获取系统代号,无法配置XanMod源" return 1 From f83c21b7c511421549018d2116b95716bd1d2cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 2 May 2026 11:39:35 +0800 Subject: [PATCH 1163/1285] Update shell version from 4.4.10 to 4.5.0 --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 51affb3a0..b3949c6d6 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' From 2a4f16da164a3bbc1b2d1ba860f847a0dee12948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 2 May 2026 11:40:02 +0800 Subject: [PATCH 1164/1285] Update shell version from 4.4.10 to 4.5.0 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 15c855de4..0266693e6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' From 0637bf61495944a3f8b14ea4d2a4774705a83d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Sat, 2 May 2026 11:42:03 +0800 Subject: [PATCH 1165/1285] Fix punctuation in kejilion_sh_log.txt Corrected punctuation and added a period for clarity. --- kejilion_sh_log.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 7ddf370a0..6934e8943 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1506,5 +1506,8 @@ OpenClaw菜单对接机器人管理 新增微信官方接入与状态显示。 OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入方式。 ------------------------ 2026-04-09 v4.4.10 -应用市场新增 Hermes Agent 项目安装与管理的工具。快捷命令 k app 115 +应用市场新增 Hermes Agent 项目安装与管理的工具。快捷命令 k app 115。 +------------------------ +2026-05-02 v4.5.0 +系统工具BBRv3更新linux-xanmod官方部署方法。 From 17bb0463200a23dca37061734fd4dcf82cbd47ef Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 3 May 2026 06:03:50 +0000 Subject: [PATCH 1166/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-05-03=2006:03:50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 351 ++++++++++++++--------- jp/kejilion.sh | 415 +++++++++++++++++----------- kr/kejilion.sh | 417 +++++++++++++++++----------- tw/kejilion.sh | 735 +++++++++++++++++++++++++++---------------------- 4 files changed, 1133 insertions(+), 785 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 5f1a7e512..4a32cfb82 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1258,7 +1258,7 @@ add_swap() { rc-update add local fi - echo -e "The virtual memory size has been adjusted to${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3602,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream four-layer proxy forwarding tool$check_docker $update_status" + echo -e "Stream四层代理转发工具 $check_docker $update_status" echo "NGINX Stream is the TCP/UDP proxy module of NGINX, which is used to achieve high-performance transport layer traffic forwarding and load balancing." echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3661,9 +3661,9 @@ stream_panel() { fi echo "" echo "------------------------" - echo "1. Install 2. Update 3. Uninstall" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" - echo "4. Add forwarding service 5. Modify forwarding service 6. Delete forwarding service" + echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -5250,7 +5250,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This feature requires root user to run!" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}hint:${gl_bai}This function requires root user to run!" && break_end && kejilion } @@ -5530,7 +5530,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5597,6 +5597,140 @@ bbrv3() { root_use send_stats "bbrv3 management" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + # Compatible with the old system codenames that have been officially removed (fall back to using releases to try the old package library) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + + if [ -z "$os_codename" ]; then + echo "Unable to obtain system codename, unable to configure XanMod source" + return 1 + fi + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "Official key download failed, try alternate download source..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" + } + + xanmod_detect_psabi_level() { + local psabi_output="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 + [ -n "$psabi_level" ] || return 1 + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "The appropriate installation package has been automatically matched:$package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "The XanMod kernel package adapted to this CPU was not found in the software source." >&2 + return 1 + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod official warehouse configuration failed, please try again later." + return 1 + } + + package=$(xanmod_detect_package) || { + echo "The current CPU cannot be recognized or a matching kernel package cannot be found. The installation has been cancelled." + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod kernel update failed, please check the software source or try again later" + return 1 + } + else + apt install -y "$package" || { + echo "XanMod kernel installation failed, please check the software source or try again later" + return 1 + } + fi + + bbr_on || { + echo "BBR3 parameter writing failed, please check the system configuration" + return 1 + } + echo "XanMod BBRv3 kernel processing completed. Take effect after restart" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "The XanMod kernel has been uninstalled. Take effect after restart" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5738,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "The current environment does not support it. Only Debian and Ubuntu systems are supported." + break_end + linux_Settings + fi + else + echo "Unable to determine operating system type" + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5769,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # Step 3: Add repository - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod kernel has been updated. Take effect after restart" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "The XanMod kernel has been uninstalled. Take effect after restart" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5793,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "The current environment does not support it. Only Debian and Ubuntu systems are supported." - break_end - linux_Settings - fi - else - echo "Unable to determine operating system type" - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # Step 3: Add repository - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "The XanMod kernel is installed and BBR3 is enabled successfully. Take effect after restart" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "Canceled" @@ -5718,7 +5806,6 @@ bbrv3() { } - elrepo_install() { # Import the ELRepo GPG public key echo "Import the ELRepo GPG public key..." @@ -6328,7 +6415,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -6600,9 +6687,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6644,7 +6731,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7097,7 +7184,7 @@ mount_partition() { return 1 fi - echo "The partition was successfully mounted to$MOUNT_POINT" + echo "Partition successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7213,7 +7300,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7253,7 +7340,7 @@ add_task() { echo "Example of creating a new sync task:" echo "- Task name: backup_www" echo "- Local directory: /var/www" - echo "- Remote address: user@192.168.1.100" + echo " - 远程地址: user@192.168.1.100" echo "- Remote directory: /backup/www" echo "- Port number (default 22)" echo "---------------------------------" @@ -7292,7 +7379,7 @@ add_task() { install rsync rsync - echo "Mission saved!" + echo "任务已保存!" } @@ -7609,7 +7696,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -8083,7 +8170,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8244,7 +8331,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8421,7 +8508,7 @@ linux_docker() { ;; 2) send_stats "Join the network" - read -e -p "Add network name:" dockernetwork + read -e -p "加入网络名: " dockernetwork read -e -p "Which containers join the network (please separate multiple container names with spaces):" dockernames for dockername in $dockernames; do @@ -8611,7 +8698,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -10022,8 +10109,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}Running${gl_bai}" else echo "${gl_hui}Not running${gl_bai}" @@ -10051,7 +10138,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API management" + echo "6. API Management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10475,8 +10562,8 @@ PY start_bot() { - echo "Start OpenClaw..." - send_stats "Start OpenClaw..." + echo "Starting OpenClaw..." + send_stats "Starting OpenClaw..." start_gateway break_end } @@ -11252,7 +11339,7 @@ PY read -erp "Please enter the API name (provider) to be deleted:" provider_name if [ -z "$provider_name" ]; then - send_stats "OpenClaw API Delete Cancel" + send_stats "OpenClaw API删除取消" echo "❌ provider name cannot be empty" break_end return 1 @@ -11748,7 +11835,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "Failed to get model list: agents.defaults.models not found in configuration file." + echo "Failed to get list of models: agents.defaults.models not found in configuration file." break_end return 1 fi @@ -12119,13 +12206,13 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue - read -e -p "请输入插件 ID(空格分隔,输入 0 退出): " raw_input + read -e -p "Please enter plugin IDs (separated by spaces, enter 0 to exit):" raw_input [ "$raw_input" = "0" ] && break [ -z "$raw_input" ] && continue @@ -12247,7 +12334,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -12821,7 +12908,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ Agent memory restored: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ Full memory restoration completed"; break_end + rm -rf "$tmp_unpack"; echo "✅ 记忆全量还原完成"; break_end } @@ -13778,7 +13865,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ Model file already exists:$model_path" + echo "✅ The model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14099,7 +14186,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count + read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14116,7 +14203,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ The number of rows must be greater than 0." + echo "❌ Number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14288,7 +14375,7 @@ EOF fi mkdir -p "$(dirname "$backup_file")" cp -f "$config_file" "$backup_file" >/dev/null 2>&1 || { - echo "⚠️ Permission backup failed:$backup_file" + echo "⚠️ 权限备份失败:$backup_file" return 1 } echo "✅ Current permission configuration has been backed up:$backup_file" @@ -14476,7 +14563,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: write file directly + # Fallback: Write the file directly echo "$json_payload" > "$approvals_file" } @@ -14613,7 +14700,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ Switched to fully open mode (Warning: All host command interceptions have expired, and the agent has the highest permissions)${gl_bai}" + echo -e "${gl_lv}✅ Has been switched to fully open mode (Warning: All host command interceptions have expired, and the agent has the highest permissions)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14645,7 +14732,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "Attempt to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice + read -e -p "Do you want to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ Automatic repair completed.${gl_bai}" @@ -15004,7 +15091,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅The agent is created successfully:$agent_id" + echo "✅ The agent was created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -15507,7 +15594,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -17312,7 +17399,7 @@ while true; do local app_id="60" local app_name="JumpServer open source bastion machine" local app_text="It is an open source privileged access management (PAM) tool. This program occupies port 80 and does not support adding domain names for access." - local app_url="Official introduction:${gh_https_url}github.com/jumpserver/jumpserver" + local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -17644,7 +17731,7 @@ while true; do } - local docker_describe="A password manager where you can control your data" + local docker_describe="A password manager that puts you in control of your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18201,7 +18288,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18396,7 +18483,7 @@ while true; do } local docker_describe="Is a web-based file manager" - local docker_url="Official website introduction: https://filebrowser.org/" + local docker_url="官网介绍: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -18832,7 +18919,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19358,14 +19445,14 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" echo -e "${gl_kjlan}24. ${gl_bai}Delete specified workspace" @@ -19744,7 +19831,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. Check the latest system log (journal)" + echo "1. View the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -19756,7 +19843,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -19834,7 +19921,7 @@ env_menu() { show_env_vars() { clear - send_stats "Environment variables currently in effect" + send_stats "Currently in effect environment variables" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -20101,7 +20188,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20520,7 +20607,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil Time 26. Argentina Time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -20778,7 +20865,7 @@ EOF echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}Current limiting shutdown function is not currently enabled${gl_bai}" + echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" fi echo @@ -20999,7 +21086,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" @@ -21047,7 +21134,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker @@ -21298,7 +21385,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Failed to copy file or directory: File or directory does not exist" + send_stats "Copying file or directory failed: File or directory does not exist" continue fi @@ -21430,7 +21517,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21828,7 +21915,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 8aa63569e..6e7708fc2 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -125,7 +125,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -260,7 +260,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -806,7 +806,7 @@ docker_ipv6_off() { # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}IPv6アクセスは現在停止中です${gl_bai}" + echo -e "${gl_huang}現在IPv6アクセスは停止中です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1540,8 +1540,8 @@ certs_status() { send_stats "ドメイン名証明書の申請が成功しました" else send_stats "ドメイン名証明書の申請に失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" + echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、もう一度試してください。" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -1991,7 +1991,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2237,7 +2237,7 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3290,7 +3290,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5250,7 +5250,7 @@ add_sshpasswd() { root_use() { clear -[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには、root ユーザーが必要です。" && break_end && kejilion +[ "$EUID" -ne 0 ] && echo -e "${gl_huang}ヒント:${gl_bai}この機能を実行するには root ユーザーが必要です。" && break_end && kejilion } @@ -5474,7 +5474,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5597,6 +5597,140 @@ bbrv3() { root_use send_stats "bbrv3管理" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + + if [ -z "$os_codename" ]; then + echo "システムコードネームを取得できません、XanMod ソースを構成できません" + return 1 + fi + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "公式キーのダウンロードに失敗しました。別のダウンロード ソースを試してください..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" + } + + xanmod_detect_psabi_level() { + local psabi_output="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 + [ -n "$psabi_level" ] || return 1 + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "適切なインストール パッケージが自動的に照合されます。$package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "この CPU に適合する XanMod カーネル パッケージがソフトウェア ソースに見つかりませんでした。" >&2 + return 1 + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod 公式ウェアハウスの構成に失敗しました。後でもう一度試してください。" + return 1 + } + + package=$(xanmod_detect_package) || { + echo "現在の CPU が認識されないか、一致するカーネル パッケージが見つかりません。インストールはキャンセルされました。" + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod カーネルの更新に失敗しました。ソフトウェア ソースを確認するか、後でもう一度試してください。" + return 1 + } + else + apt install -y "$package" || { + echo "XanMod カーネルのインストールに失敗しました。ソフトウェア ソースを確認するか、後でもう一度試してください。" + return 1 + } + fi + + bbr_on || { + echo "BBR3 パラメータの書き込みに失敗しました。システム構成を確認してください。" + return 1 + } + echo "XanMod BBRv3 カーネル処理が完了しました。再起動後に有効になります" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5738,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "現在の環境では対応しておりません。 Debian および Ubuntu システムのみがサポートされています。" + break_end + linux_Settings + fi + else + echo "オペレーティング システムの種類を特定できません" + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5769,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # ステップ 3: リポジトリを追加する - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod カーネルが更新されました。再起動後に有効になります" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5793,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境では対応しておりません。 Debian および Ubuntu システムのみがサポートされています。" - break_end - linux_Settings - fi - else - echo "オペレーティング システムの種類を特定できません" - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # ステップ 3: リポジトリを追加する - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "XanMod カーネルがインストールされ、BBR3 が正常に有効になります。再起動後に有効になります" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "キャンセル" @@ -5718,7 +5806,6 @@ bbrv3() { } - elrepo_install() { # ELRepo GPG 公開キーをインポートする echo "ELRepo GPG 公開キーをインポートします..." @@ -5808,7 +5895,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5921,7 +6008,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6285,7 +6372,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" + send_stats "Linux カーネルのチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6302,7 +6389,7 @@ Kernel_optimize() { echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6328,7 +6415,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6427,7 +6514,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6600,9 +6687,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6644,7 +6731,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7030,7 +7117,7 @@ ssh_manager() { 2) use_connection ;; 3) delete_connection ;; 0) break ;; - *) echo "无效的选择,请重试。" ;; + *) echo "選択が無効です。もう一度お試しください。" ;; esac done } @@ -7097,7 +7184,7 @@ mount_partition() { return 1 fi - echo "パーティションは正常にマウントされました$MOUNT_POINT" + echo "パーティションが正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7213,7 +7300,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7232,7 +7319,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7269,7 +7356,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" + kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7401,7 +7488,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7491,7 +7578,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7553,7 +7640,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7609,7 +7696,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7733,7 +7820,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -8035,7 +8122,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8045,7 +8132,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8212,7 +8299,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8244,7 +8331,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8988,8 +9075,8 @@ linux_ldnmp() { echo -e "${gl_huang}9. ${gl_bai}LinkStack 共有リンク プラットフォームをインストールする${gl_huang}20. ${gl_bai}カスタム動的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" - echo -e "${gl_huang}23. ${gl_bai}站点反向代理-IP+端口 ${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" - echo -e "${gl_huang}25. ${gl_bai}安装Bitwarden密码管理平台 ${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" + echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" echo -e "${gl_huang}29. ${gl_bai}ストリーム 4 層プロキシ転送${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" @@ -10022,8 +10109,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}ランニング${gl_bai}" else echo "${gl_hui}稼働していない${gl_bai}" @@ -10330,7 +10417,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10475,8 +10562,8 @@ PY start_bot() { - echo "OpenClaw を開始します..." - send_stats "OpenClaw を開始します..." + echo "OpenClaw を開始しています..." + send_stats "OpenClaw を開始しています..." start_gateway break_end } @@ -10568,7 +10655,7 @@ EOF local config_file config_file=$(openclaw_get_config_file) - # API プロトコルを自動的に検出/修正しなくなりました。ユーザー構成を維持します + # API プロトコルを自動的に検出/修正しなくなりました。ユーザー設定を維持します DETECTED_API="openai-completions" [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" @@ -11171,7 +11258,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "セットアップする API タイプを選択してください:" + echo "設定したい API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -11560,7 +11647,7 @@ REPO oc_config=$(openclaw_get_config_file) [ ! -f "$oc_config" ] && { OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="未找到 openclaw 配置文件" + OPENCLAW_PROBE_MESSAGE="openclaw 設定ファイルが見つかりません" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 @@ -11698,7 +11785,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空のリターン)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11748,7 +11835,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "モデル リストの取得に失敗しました: 構成ファイルに Agents.defaults.models が見つかりません。" + echo "モデルのリストを取得できませんでした: 構成ファイルに Agents.defaults.models が見つかりません。" break_end return 1 fi @@ -12193,7 +12280,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12239,7 +12326,7 @@ PYTHON_EOF echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンを制御する" + echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12570,7 +12657,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5.WeChatロボットのドッキング" + echo "5. WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -13685,7 +13772,7 @@ PY echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -14099,7 +14186,7 @@ EOF echo "書類:$file" echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示される行数を入力してください (Enter を押してデフォルトにします)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14507,7 +14594,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14576,7 +14663,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14613,7 +14700,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14645,7 +14732,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "発見されたセキュリティ脆弱性を自動的に修復してみますか? (y/n):" fix_choice + read -e -p "発見されたセキュリティ脆弱性を自動的に修復しますか? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復が完了しました。${gl_bai}" @@ -14719,13 +14806,13 @@ except Exception as e: while true; do clear echo "=======================================" - echo " OpenClaw 权限管理 (双层架构深度适配)" + echo "OpenClaw 権限管理 (デュアルレイヤー アーキテクチャの高度な適応)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" echo -e "${gl_kjlan}1.${gl_bai}標準セキュリティ モードに切り替える (毎日の推奨事項、ポップアップ カードの承認)" echo -e "${gl_kjlan}2.${gl_bai}開発拡張モードに切り替える (エージェントが権限昇格を申請できるようにする)" - echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}High risk!すべてのホストインターセプトを完全に削除します${gl_bai})" + echo -e "${gl_kjlan}3.${gl_bai}全開モードに切り替えます(${gl_hong}ハイリスク!すべてのホストインターセプトを完全に削除します${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}公式のデフォルトのサンドボックス防御戦略を復元する" echo -e "${gl_kjlan}5.${gl_bai}基盤となるセキュリティ監査と自動修復を実行する" echo -e "${gl_kjlan}6.${gl_bai}Execコマンドのホワイトリストを管理する" @@ -15004,7 +15091,7 @@ for idx,item in enumerate(agents,1): read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました。$agent_id" + echo "✅ エージェントが正常に作成されました:$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15443,7 +15530,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期構成ウィザード" + 11) send_stats "初期設定ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15507,7 +15594,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -16743,7 +16830,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -17644,7 +17731,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18201,7 +18288,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -18832,7 +18919,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19348,7 +19435,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19358,7 +19445,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19686,7 +19773,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19696,7 +19783,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19708,7 +19795,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19744,7 +19831,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を確認する" + echo "1. 最新のシステムログ(ジャーナル)を表示する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -19756,10 +19843,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19769,7 +19856,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19784,7 +19871,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19872,7 +19959,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -19887,7 +19974,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -19903,7 +19990,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -19914,7 +20001,7 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集します" + echo "4. ~/.bashrc を編集する" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -20106,7 +20193,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -20778,7 +20865,7 @@ EOF echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません${gl_bai}" + echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" fi echo @@ -20990,7 +21077,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21282,7 +21369,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21302,7 +21389,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21430,7 +21517,7 @@ while true; do echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21828,14 +21915,14 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21844,7 +21931,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index a069102c3..e96dae560 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -508,22 +508,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1543,10 +1543,10 @@ certs_status() { echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -1838,7 +1838,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2011,7 +2011,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2068,7 +2068,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하세요. + # nginx 이미지를 확인하고 그에 따라 처리하십시오. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3420,7 +3420,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -3433,7 +3433,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3773,7 +3773,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname지어졌습니다!" + echo "당신의$webname건설되었습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4983,7 +4983,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5597,6 +5597,140 @@ bbrv3() { root_use send_stats "bbrv3 관리" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + # 공식적으로 제거된 이전 시스템 코드명과 호환 가능(이전 패키지 라이브러리를 사용해 보려면 릴리스를 사용하도록 대체) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + + if [ -z "$os_codename" ]; then + echo "시스템 코드명을 얻을 수 없으며 XanMod 소스를 구성할 수 없습니다." + return 1 + fi + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "공식 키 다운로드에 실패했습니다. 다른 다운로드 소스를 사용해 보세요..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" + } + + xanmod_detect_psabi_level() { + local psabi_output="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 + [ -n "$psabi_level" ] || return 1 + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "적절한 설치 패키지가 자동으로 일치되었습니다.$package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "이 CPU에 적합한 XanMod 커널 패키지를 소프트웨어 소스에서 찾을 수 없습니다." >&2 + return 1 + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod 공식 창고 구성에 실패했습니다. 나중에 다시 시도해 주세요." + return 1 + } + + package=$(xanmod_detect_package) || { + echo "현재 CPU를 인식할 수 없거나 일치하는 커널 패키지를 찾을 수 없습니다. 설치가 취소되었습니다." + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod 커널 업데이트에 실패했습니다. 소프트웨어 소스를 확인하거나 나중에 다시 시도하십시오." + return 1 + } + else + apt install -y "$package" || { + echo "XanMod 커널 설치에 실패했습니다. 소프트웨어 소스를 확인하거나 나중에 다시 시도하십시오." + return 1 + } + fi + + bbr_on || { + echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." + return 1 + } + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5738,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." + break_end + linux_Settings + fi + else + echo "운영 체제 유형을 확인할 수 없습니다." + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5769,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 3단계: 저장소 추가 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod 커널이 업데이트되었습니다. 재시작 후 적용" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5793,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." - break_end - linux_Settings - fi - else - echo "운영 체제 유형을 확인할 수 없습니다." - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 3단계: 저장소 추가 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "XanMod 커널이 설치되고 BBR3이 성공적으로 활성화되었습니다. 재시작 후 적용" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "취소" @@ -5718,7 +5806,6 @@ bbrv3() { } - elrepo_install() { # ELRepo GPG 공개 키 가져오기 echo "ELRepo GPG 공개 키 가져오기..." @@ -5957,7 +6044,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정하세요── + # ──장면에 따라 매개변수를 설정합니다── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6328,7 +6415,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6544,7 +6631,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7213,7 +7300,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8244,7 +8331,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8277,7 +8364,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -9189,7 +9276,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9527,7 +9614,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -10022,8 +10109,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}달리기${gl_bai}" else echo "${gl_hui}실행되지 않음${gl_bai}" @@ -10475,8 +10562,8 @@ PY start_bot() { - echo "OpenClaw를 시작하세요..." - send_stats "OpenClaw를 시작하세요..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_gateway break_end } @@ -10621,7 +10708,7 @@ EOF "${base_url}/models") if [[ -z "$models_json" ]]; then - echo "❌ 모델 목록을 가져올 수 없습니다" + echo "❌ 모델 목록을 얻을 수 없습니다" return 1 fi @@ -11787,7 +11874,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11855,7 +11942,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12012,7 +12099,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -12096,7 +12183,7 @@ PYTHON_EOF echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안의 ID만 복사):" echo "--------------------------------------------------------" echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" @@ -12119,7 +12206,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반환" + echo "0) 반품" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12247,7 +12334,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반환" + echo "0) 반품" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12591,7 +12678,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12821,7 +12908,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end } @@ -13049,7 +13136,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 백업 파일 삭제" + send_stats "OpenClaw 삭제 백업 파일" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13684,7 +13771,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -13843,7 +13930,7 @@ EOF OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 알 수 없는 해결 방법:$scheme" return 1 ;; esac @@ -13927,7 +14014,7 @@ EOF openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 알 수 없는 해결 방법:$scheme" return 1 esac echo "✅ 메모리 체계 구성이 업데이트되었습니다." @@ -14099,7 +14186,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count + read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14109,7 +14196,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 번호를 입력하세요." + echo "❌ 유효한 숫자를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14476,7 +14563,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일 직접 쓰기 + # 대체: 파일을 직접 작성 echo "$json_payload" > "$approvals_file" } @@ -14564,7 +14651,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14583,7 +14670,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14601,7 +14688,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14613,7 +14700,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 완전 개방 모드로 전환됨(경고: 모든 호스트 명령 차단이 만료되었으며 에이전트가 가장 높은 권한을 가짐)${gl_bai}" + echo -e "${gl_lv}✅ 완전 개방 모드로 전환되었습니다. (경고: 모든 호스트 명령 차단이 만료되었으며 에이전트는 가장 높은 권한을 가집니다.)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14645,7 +14732,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "발견된 보안 취약점을 자동으로 해결하려고 합니까? (예/아니요):" fix_choice + read -e -p "발견된 보안 취약점을 자동으로 해결하시겠습니까? (예/아니요):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 자동 복구가 완료되었습니다.${gl_bai}" @@ -14703,7 +14790,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15004,7 +15091,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15053,7 +15140,7 @@ for idx,item in enumerate(bindings,1): send_stats "OpenClaw 다중 에이전트-새 라우팅 바인딩" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "상담원 ID를 입력하세요:" agent_id + read -e -p "에이전트 ID를 입력하세요:" agent_id read -e -p "경로 바인딩 값을 입력하세요(예: telegram:ops / discord:guild-a):" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 echo "에이전트를 바인딩합니다 [$agent_id] -> [$bind_value]" @@ -15071,7 +15158,7 @@ for idx,item in enumerate(bindings,1): send_stats "OpenClaw 다중 에이전트 - 경로 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "상담원 ID를 입력하세요:" agent_id + read -e -p "에이전트 ID를 입력하세요:" agent_id read -e -p "제거할 경로 바인딩 값을 입력하세요." bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 echo "에이전트를 제거합니다. [$agent_id] 경로 바인딩 [$bind_value]" @@ -15447,7 +15534,7 @@ openclaw_backup_restore_menu() { openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 수리" + 12) send_stats "상태 감지 및 복구" openclaw doctor --fix break_end ;; @@ -15507,7 +15594,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15547,7 +15634,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15576,7 +15663,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15778,7 +15865,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -15798,7 +15885,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15910,7 +15997,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16288,7 +16375,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16478,7 +16565,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -17149,7 +17236,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17644,7 +17731,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18201,7 +18288,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -18233,7 +18320,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -18832,7 +18919,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19181,7 +19268,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -19358,7 +19445,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19744,7 +19831,7 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 확인" + echo "1. 최신 시스템 로그(일지) 보기" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" echo "4. 실시간 추적 로그" @@ -19756,7 +19843,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -19805,7 +19892,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "3) 최대 로그 크기를 500M로 제한합니다." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -20030,10 +20117,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20043,7 +20130,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20331,7 +20418,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다." + send_stats "1G 가상 메모리가 설정되었습니다" add_swap 1024 ;; @@ -20515,7 +20602,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20583,7 +20670,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20778,7 +20865,7 @@ EOF echo -e "${gl_lv}현재 설정된 인바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}현재 설정된 아웃바운드 트래픽 제한 임계값은 다음과 같습니다.${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else - echo -e "${gl_hui}현재 제한 종료 기능이 활성화되어 있지 않습니다.${gl_bai}" + echo -e "${gl_hui}현재 제한 종료 기능이 현재 활성화되어 있지 않습니다.${gl_bai}" fi echo @@ -21298,7 +21385,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -21430,7 +21517,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21472,7 +21559,7 @@ while true; do clear send_stats "클러스터 복원" echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "귀하의${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21544,7 +21631,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21828,12 +21915,12 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -21867,12 +21954,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 59d0b8a5f..72ac44706 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.4.10" +sh_v="4.5.0" gl_hui='\e[37m' @@ -12,7 +12,7 @@ gl_zi='\033[35m' gl_kjlan='\033[96m' -canshu="CN" +canshu="default" permission_granted="false" ENABLE_STATS="true" @@ -36,7 +36,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# 定義一個函數來執行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -63,7 +63,7 @@ CheckFirstRun_true() { -# 收集功能埋点信息的函数,记录当前脚本版本号,使用时间,系统版本,CPU架构,机器所在国家和用户使用的功能名称,绝对不涉及任何敏感信息,请放心!請相信我! +# 收集功能埋藏資訊的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! # 為什麼要設計這個功能,目的更好的了解使用者喜歡使用的功能,進一步優化功能推出更多符合使用者需求的功能。 # 全文可搜尋 send_stats 函數呼叫位置,透明開源,如有顧慮可拒絕使用。 @@ -234,7 +234,7 @@ check_disk_space() { echo -e "${gl_huang}提示:${gl_bai}磁碟空間不足!" echo "目前可用空間: $((available_space_mb/1024))G" echo "最小需求空間:${required_gb}G" - echo "无法继续安装,请清理磁盘空间后重试。" + echo "無法繼續安裝,請清理磁碟空間後重試。" send_stats "磁碟空間不足" break_end kejilion @@ -302,7 +302,7 @@ systemctl() { restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1 服务已重启。" + echo "$1服務已重啟。" else echo "錯誤:重啟$1服務失敗。" fi @@ -312,7 +312,7 @@ restart() { start() { systemctl start "$1" if [ $? -eq 0 ]; then - echo "$1 服务已启动。" + echo "$1服務已啟動。" else echo "錯誤:啟動$1服務失敗。" fi @@ -497,7 +497,7 @@ while true; do echo "------------------------" echo "15. 開啟容器連接埠存取 16. 關閉容器連接埠訪問" echo "------------------------" - echo "0. 返回上一级选单" + echo "0. 返回上一級選單" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -508,7 +508,7 @@ while true; do ;; 2) send_stats "啟動指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker start $dockername ;; 3) @@ -623,9 +623,9 @@ while true; do echo "Docker映像列表" docker image ls echo "" - echo "镜像操作" + echo "鏡像操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" + echo "1. 取得指定鏡像 3. 刪除指定鏡像" echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" @@ -1096,7 +1096,7 @@ iptables_panel() { echo "防火牆管理" echo "------------------------" echo "1. 開放指定連接埠 2. 關閉指定連接埠" - echo "3. 开放所有端口 4. 关闭所有端口" + echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" echo "5. IP白名單 6. IP黑名單" echo "7. 清除指定IP" @@ -1115,7 +1115,7 @@ iptables_panel() { 1) read -e -p "請輸入開放的連接埠號碼:" o_port open_port $o_port - send_stats "开放指定端口" + send_stats "開放指定連接埠" ;; 2) read -e -p "請輸入關閉的連接埠號碼:" c_port @@ -1139,7 +1139,7 @@ iptables_panel() { send_stats "開放所有連接埠" ;; 4) - # 关闭所有端口 + # 關閉所有連接埠 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1157,7 +1157,7 @@ iptables_panel() { 5) # IP 白名單 - read -e -p "请输入放行的IP或IP段: " o_ip + read -e -p "請輸入放行的IP或IP段:" o_ip allow_ip $o_ip ;; 6) @@ -1200,13 +1200,13 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; 17) - read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "請輸入清除的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules unblock $country_code send_stats "清除國家$country_code的IP" ;; @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1430,7 +1430,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "续签任务已更新" + echo "續簽任務已更新" } @@ -1472,7 +1472,7 @@ install_ssltls_text() { echo "" echo -e "${gl_huang}證書存放路徑${gl_bai}" echo "公鑰: /etc/letsencrypt/live/$yuming/fullchain.pem" - echo "私钥: /etc/letsencrypt/live/$yuming/privkey.pem" + echo "私鑰: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1481,7 +1481,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "網站資訊 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1578,7 +1578,7 @@ certs_status() { done # 2. 輸入私鑰 (相容 RSA, ECC, PKCS#8) - echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" + echo "請貼上 憑證私鑰 (Private Key) 內容 (按兩次回車結束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1748,7 +1748,7 @@ cf_purge_cache() { ZONE_IDS=($ZONE_IDS) else # 提示使用者是否清理快取 - read -e -p "需要清理 Cloudflare 的缓存吗?(y/n): " answer + read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN @@ -1762,7 +1762,7 @@ cf_purge_cache() { # 循環遍歷每個 zone_id 並執行清除快取命令 for ZONE_ID in "${ZONE_IDS[@]}"; do - echo "正在清除缓存 for zone_id: $ZONE_ID" + echo "正在清除快取 for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_TOKEN" \ @@ -1788,7 +1788,7 @@ web_del() { send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1801,7 +1801,7 @@ web_del() { rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 - # 将域名转换为数据库名 + # 將網域名稱轉換為資料庫名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') @@ -2119,7 +2119,7 @@ web_security() { echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" - echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" + echo "5. 查看SSH攔截記錄 6. 查看網站攔截記錄" echo "7. 檢視防禦規則清單 8. 查看日誌即時監控" echo "------------------------" echo "11. 設定攔截參數 12. 清除所有拉黑的IP" @@ -2237,7 +2237,7 @@ web_security() { ;; 22) - send_stats "高负载开启5秒盾" + send_stats "高負載開啟5秒盾" echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" @@ -2336,7 +2336,7 @@ check_nginx_compression() { br_status="" fi - # 检查 gzip 是否开启且未被注释 + # 檢查 gzip 是否開啟且未被註釋 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2403,7 +2403,7 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境已設定成 標準模式" ;; 2) @@ -2566,7 +2566,7 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- + # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想透過 GitHub Release 判斷) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2647,7 +2647,7 @@ block_container_port() { fi - echo "已阻止IP+端口访问该服务" + echo "已阻止IP+連接埠存取該服務" save_iptables_rules } @@ -2722,7 +2722,7 @@ block_host_port() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" + echo "錯誤:請提供連接埠號碼和允許存取的 IP。" echo "用法: block_host_port <連接埠號碼> <允許的IP>" return 1 fi @@ -2781,7 +2781,7 @@ clear_host_port_rules() { local allowed_ip=$2 if [[ -z "$port" || -z "$allowed_ip" ]]; then - echo "错误:请提供端口号和允许访问的 IP。" + echo "錯誤:請提供連接埠號碼和允許存取的 IP。" echo "用法: clear_host_port_rules <連接埠號碼> <允許的IP>" return 1 fi @@ -2794,7 +2794,7 @@ clear_host_port_rules() { iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 清除允許本機存取的規則 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2810,7 +2810,7 @@ clear_host_port_rules() { iptables -D INPUT -p udp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 清除允許本機存取的規則 if iptables -C INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2882,8 +2882,8 @@ while true; do echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 新增網域存取 6. 刪除網域存取" - echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" + echo "5. 添加域名访问 6. 删除域名访问" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3219,10 +3219,10 @@ f2b_sshd() { fi } -# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) +# 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) # 說明: # - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) -# - 若是 Alpine 且 jail 名称不同,依然写 sshd.local;Fail2Ban 会按 jail 名称匹配 +# - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 f2b_basic_config() { root_use install nano @@ -3243,7 +3243,7 @@ f2b_basic_config() { echo "即將配置 SSH jail:$jail_name" read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime - read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry + read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry bantime=${bantime:-1h} findtime=${findtime:-10m} @@ -3274,8 +3274,8 @@ EOF fail2ban-client status $jail_name || true } -# 直接打开主配置/覆盖配置编辑(nano) -# 优先编辑 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在则创建 +# 直接開啟主配置/覆蓋配置編輯(nano) +# 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 f2b_edit_config() { root_use install nano @@ -3551,7 +3551,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="反向代理-負載平衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3865,9 +3865,9 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申请/更新域名证书 2. 克隆站点域名" + echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" - echo "5. 查看访问日志 6. 查看错误日志" + echo "5. 查看訪問日誌 6. 查看錯誤日誌" echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" @@ -4084,7 +4084,7 @@ donlond_frp() { generate_frps_config() { - send_stats "安装frp服务端" + send_stats "安裝frp服務端" # 產生隨機連接埠和憑證 local bind_port=8055 local dashboard_port=8056 @@ -4150,7 +4150,7 @@ EOF add_forwarding_service() { send_stats "新增frp內網服務" # 提示使用者輸入服務名稱和轉發訊息 - read -e -p "请输入服务名称: " service_name + read -e -p "請輸入服務名稱:" service_name read -e -p "請輸入轉送類型 (tcp/udp) [回​​車預設tcp]:" service_type local service_type=${service_type:-tcp} read -e -p "請輸入內網IP [回車預設127.0.0.1]:" local_ip @@ -4169,7 +4169,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4180,10 +4180,10 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" + send_stats "刪除frp內網服務" # 提示使用者輸入需要刪除的服務名稱 read -e -p "請輸入需要刪除的服務名稱:" service_name - # 使用 sed 删除该服务及其相关配置 + # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "服務$service_name已成功從 frpc.toml 刪除" @@ -4196,7 +4196,7 @@ list_forwarding_services() { local config_file="$1" # 列印表頭 - printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "内网地址" "外網位址" "協定" + printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" awk ' BEGIN { @@ -4271,7 +4271,7 @@ list_forwarding_services() { -# 获取 FRP 服务端端口 +# 取得 FRP 服務端端口 get_frp_ports() { mapfile -t ports < <(ss -tulnape | grep frps | awk '{print $5}' | awk -F':' '{print $NF}' | sort -u) } @@ -4355,11 +4355,11 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "00. 刷新服務狀態 0. 返回上一級選單" echo "------------------------" @@ -4395,7 +4395,7 @@ frps_panel() { echo "應用程式已解除安裝" ;; 5) - echo "将内网穿透服务反代成域名访问" + echo "將內網穿透服務反代成域名訪問" send_stats "FRP對外域名訪問" add_yuming read -e -p "請輸入你的內部網路穿透服務埠:" frps_port @@ -4543,7 +4543,7 @@ yt_menu_pro() { echo "已下載影片清單:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" echo "5. 單一影片下載 6. 大量影片下載 7. 自訂參數下載" echo "8. 下載為MP3音訊 9.刪除影片目錄 10. Cookie管理(開發中)" @@ -4953,7 +4953,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私钥信息已生成,务必复制保存,可保存成 ${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5096,7 +5096,7 @@ fetch_github_ssh_keys() { echo "操作前,請確保您已在 GitHub 帳戶中新增了 SSH 公鑰:" echo "1. 登入${gh_https_url}github.com/settings/keys" echo "2. 點選 New SSH key 或 Add SSH key" - echo " 3. Title 可随意填写(例如:Home Laptop 2026)" + echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" echo "5. 點選 Add SSH key 完成新增" echo "" @@ -5123,7 +5123,7 @@ fetch_github_ssh_keys() { sshkey_panel() { root_use - send_stats "用户密钥登录" + send_stats "使用者密鑰登入" while true; do clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') @@ -5137,8 +5137,8 @@ sshkey_panel() { echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 生成新密钥对 2. 手动输入已有公钥" - echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" + echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5276,7 +5276,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重装后初始用户名: ${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" @@ -5338,7 +5338,7 @@ dd_xitong() { echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "请选择要重装的系统: " sys_choice + read -e -p "請選擇要重裝的系統:" sys_choice case "$sys_choice" in @@ -5393,7 +5393,7 @@ dd_xitong() { exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "重裝ubuntu 18.04" dd_xitong_1 bash InstallNET.sh -ubuntu 18.04 reboot @@ -5418,7 +5418,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "重裝alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5522,7 +5522,7 @@ dd_xitong() { ;; 36) - send_stats "重装飞牛" + send_stats "重裝飛牛" dd_xitong_3 bash reinstall.sh fnos reboot @@ -5597,6 +5597,140 @@ bbrv3() { root_use send_stats "bbrv3管理" + xanmod_add_repo() { + local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" + local list_file="/etc/apt/sources.list.d/xanmod-release.list" + local key_url="https://dl.xanmod.org/archive.key" + local fallback_key_url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key" + local os_codename="" + + if command -v lsb_release >/dev/null 2>&1; then + os_codename=$(lsb_release -sc) + elif [ -r /etc/os-release ]; then + os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") + fi + + # 相容官方已移除的老系統代號(回退使用 releases 嘗試舊包庫) + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + os_codename="releases" + fi + + if [ -z "$os_codename" ]; then + echo "無法取得系統代號,無法設定XanMod來源" + return 1 + fi + + install wget gnupg ca-certificates + mkdir -p /usr/share/keyrings /etc/apt/sources.list.d + if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then + echo "官方金鑰下載失敗,嘗試備用下載來源..." + wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 + fi + chmod 644 "$keyring" + echo "deb [signed-by=$keyring] http://deb.xanmod.org $os_codename main" > "$list_file" + } + + xanmod_detect_psabi_level() { + local psabi_output="" + psabi_output=$(awk 'BEGIN { + while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1 + if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1 + if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2 + if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3 + if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4 + if (level > 0) { print level; exit } + exit 1 + }' /proc/cpuinfo 2>/dev/null) || return 1 + printf '%s' "$psabi_output" | tr -dc '0-9' | head -c 1 + } + + xanmod_package_available() { + local package="$1" + apt-cache policy "$package" 2>/dev/null | grep -q 'Candidate: [^ ]' + } + + xanmod_detect_package() { + local psabi_level="" + local level="" + local package="" + local prefix_list="linux-xanmod linux-xanmod-lts" + + psabi_level=$(xanmod_detect_psabi_level) || return 1 + [ -n "$psabi_level" ] || return 1 + [ "$psabi_level" -gt 3 ] && psabi_level=3 + + apt update -y >/dev/null 2>&1 + + for prefix in $prefix_list; do + level="$psabi_level" + while [ "$level" -ge 1 ]; do + package="${prefix}-x64v${level}" + if xanmod_package_available "$package"; then + if [ "$level" != "$psabi_level" ] || [ "$prefix" = "linux-xanmod-lts" ]; then + echo "已自動配對合適安裝包:$package" >&2 + fi + printf '%s\n' "$package" + return 0 + fi + level=$((level - 1)) + done + done + + echo "軟體來源中找不到適合此CPU的XanMod核心包" >&2 + return 1 + } + + xanmod_installed() { + dpkg-query -W -f='${Package}\n' 'linux-*xanmod*' 2>/dev/null | grep -q '^linux-.*xanmod' + } + + xanmod_install_or_update() { + local action="$1" + local package="" + + check_disk_space 3 + check_swap + xanmod_add_repo || { + echo "XanMod官方倉庫配置失敗,請稍後重試" + return 1 + } + + package=$(xanmod_detect_package) || { + echo "無法辨識目前CPU或找不到匹配核心包,已取消安裝" + return 1 + } + + apt update -y + if [ "$action" = "update" ]; then + apt install -y --only-upgrade "$package" || apt install -y "$package" || { + echo "XanMod核心更新失敗,請檢查軟體來源或稍後重試" + return 1 + } + else + apt install -y "$package" || { + echo "XanMod核心安裝失敗,請檢查軟體來源或稍後重試" + return 1 + } + fi + + bbr_on || { + echo "BBR3參數寫入失敗,請檢查系統配置" + return 1 + } + echo "XanMod BBRv3内核处理完成。重啟後生效" + server_reboot + } + + xanmod_uninstall() { + apt purge -y 'linux-*xanmod*' + apt autoremove -y + update-grub 2>/dev/null || true + rm -f /etc/apt/sources.list.d/xanmod-release.list + rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg + echo "XanMod核心已卸載。重啟後生效" + server_reboot + } + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5604,7 +5738,20 @@ bbrv3() { linux_Settings fi - if dpkg -l | grep -q 'linux-xanmod'; then + if [ -r /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then + echo "目前環境不支持,僅支援Debian和Ubuntu系統" + break_end + linux_Settings + fi + else + echo "無法確定作業系統類型" + break_end + linux_Settings + fi + + if xanmod_installed; then while true; do clear local kernel_version=$(uname -r) @@ -5622,38 +5769,14 @@ bbrv3() { case $sub_choice in 1) - apt purge -y 'linux-*xanmod1*' - update-grub - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步驟3:新增儲存庫 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - echo "XanMod核心已更新。重啟後生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - - server_reboot - - ;; + xanmod_install_or_update update + ;; 2) - apt purge -y 'linux-*xanmod1*' - update-grub - echo "XanMod核心已卸載。重啟後生效" - server_reboot - ;; - + xanmod_uninstall + ;; *) - break # 跳出循环,退出菜单 - ;; + break + ;; esac done @@ -5670,42 +5793,7 @@ bbrv3() { case "$choice" in [Yy]) - check_disk_space 3 - if [ -r /etc/os-release ]; then - . /etc/os-release - if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "目前環境不支持,僅支援Debian和Ubuntu系統" - break_end - linux_Settings - fi - else - echo "無法確定作業系統類型" - break_end - linux_Settings - fi - - check_swap - install wget gnupg - - # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes - - # 步驟3:新增儲存庫 - echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list - - # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') - - apt update -y - apt install -y linux-xanmod-x64v$version - - bbr_on - - echo "XanMod核心安裝並BBR3啟用成功。重啟後生效" - rm -f /etc/apt/sources.list.d/xanmod-release.list - rm -f check_x86-64_psabi.sh* - server_reboot - + xanmod_install_or_update install ;; [Nn]) echo "已取消" @@ -5718,7 +5806,6 @@ bbrv3() { } - elrepo_install() { # 導入 ELRepo GPG 公鑰 echo "導入 ELRepo GPG 公鑰..." @@ -5726,7 +5813,7 @@ elrepo_install() { # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 確保我們在一個支援的作業系統上運行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "不支援的作業系統:$os_name" break_end @@ -5865,7 +5952,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # 執行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5937,12 +6024,12 @@ clamav() { # ============================================================================ -# Linux 内核调优模块(重构版) +# Linux 核心調優模組(重構版) # 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 # 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ -# 获取内存大小(MB) +# 取得記憶體大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo } @@ -5957,7 +6044,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}切換到${mode_name}...${gl_bai}" - # ── 根据场景设定参数 ── + # ── 根據場景設定參數 ── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6073,7 +6160,7 @@ net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 游戏服场景额外:低延迟优先 ── + # ── 遊戲服場景額外:低延遲優先 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" @@ -6102,14 +6189,14 @@ net.ipv4.tcp_slow_start_after_idle = 0" QDISC="fq_codel" fi - # ── 备份已有配置 ── + # ── 備份已有設定 ── [ -f "$CONF" ] && cp "$CONF" "${CONF}.bak.$(date +%s)" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL # kejilion 核心調優配置 -# 模式: $mode_name | 场景: $scene +# 模式: $mode_name | 場景: $scene # 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') # ── TCP 擁塞控制 ── @@ -6232,7 +6319,7 @@ LIMITS fi echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" - echo -e "${gl_lv}記憶體:${MEM_MB}MB | 拥塞算法: ${CC}| 隊列:${QDISC}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" } # ── 各模式入口函數(保持原有呼叫介面不變) ── @@ -6262,7 +6349,7 @@ restore_defaults() { # 清理 sysctl.conf 裡可能殘留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新加载系统默认配置 + # 重新載入系統預設配置 sysctl --system 2>/dev/null | tail -1 # 還原透明大頁面 @@ -6305,7 +6392,7 @@ Kernel_optimize() { echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" - echo -e "7. 自动调优: 根据测试数据自动调优内核参数。${gl_huang}★${gl_bai}" + echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -6607,12 +6694,12 @@ create_backup() { # 提示使用者輸入備份目錄 echo "建立備份範例:" - echo " - 备份单个目录: /var/www" + echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" - echo "- 直接回車將使用預設目錄 (/etc /usr /home)" - read -e -p "请输入要备份的目录(多个目录用空格分隔,直接回车则使用默认目录):" input + echo " - 直接回车将使用默认目录 (/etc /usr /home)" + read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input - # 如果使用者沒有輸入目錄,則使用預設目錄 + # 如果用户没有输入目录,则使用默认目录 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6624,10 +6711,10 @@ create_backup() { IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 產生備份檔案前綴 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do - # 提取目录名称并去除斜杠 + # 提取目錄名稱並去除斜杠 dir_name=$(basename "$path") PREFIX+="${dir_name}_" done @@ -6645,7 +6732,7 @@ create_backup() { done # 建立備份 - echo "正在建立備份$BACKUP_NAME..." + echo "正在创建备份 $BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6716,7 +6803,7 @@ linux_backup() { mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系統備份功能" + send_stats "系统备份功能" echo "系統備份功能" echo "------------------------" list_backups @@ -6744,7 +6831,7 @@ linux_backup() { -# SSH 输入标准化函数 +# SSH 輸入標準化函數 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -6837,7 +6924,7 @@ kj_ssh_read_auth() { echo "請選擇身份驗證方式:" echo "1. 密碼" echo "2. 密鑰" - read -e -p "请输入选择 (1/2): " auth_choice + read -e -p "請輸入選擇 (1/2):" auth_choice case $auth_choice in 1) @@ -6917,7 +7004,7 @@ add_connection() { echo "建立新連接範例:" echo "- 連線名稱: my_server" echo "- IP位址: 192.168.1.100" - echo "- 使用者名稱: root" + echo " - 用户名: root" echo "- 連接埠: 22" echo "------------------------" read -e -p "請輸入連線名稱:" name @@ -6928,7 +7015,7 @@ add_connection() { fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "連線已儲存!" + echo "连接已保存!" } @@ -6958,7 +7045,7 @@ delete_connection() { # 使用連接 use_connection() { send_stats "使用連接" - read -e -p "请输入要使用的连接编号: " num + read -e -p "請輸入要使用的連接編號:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -6970,12 +7057,12 @@ use_connection() { echo "正在連接到$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密鑰連接 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" echo "1. 密鑰檔案路徑是否正確:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" + echo "2. 密鑰檔案權限是否正確(應為 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else @@ -7004,7 +7091,7 @@ ssh_manager() { CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 檢查設定檔和金鑰目錄是否存在,如果不存在則創建 + # 检查配置文件和密钥目录是否存在,如果不存在则创建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -7020,7 +7107,7 @@ ssh_manager() { echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections - echo "1. 创建新连接 2. 使用连接 3. 删除连接" + echo "1. 建立新連接 2. 使用連接 3. 刪除連接" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7097,7 +7184,7 @@ mount_partition() { return 1 fi - echo "分割區已成功掛載到$MOUNT_POINT" + echo "分區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7135,7 +7222,7 @@ unmount_partition() { fi } -# 列出已挂载的分区 +# 列出已掛載的分割區 list_mounted_partitions() { echo "已掛載的分割區:" df -h | grep -v "tmpfs\|udev\|overlay" @@ -7175,7 +7262,7 @@ format_partition() { esac # 確認格式化 - read -e -p "确认格式化分区 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM + read -e -p "確認格式化分割區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return @@ -7241,7 +7328,7 @@ disk_manager() { # 顯示任務列表 list_tasks() { - echo "已儲存的同步任務:" + echo "已保存的同步任务:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" @@ -7252,7 +7339,7 @@ add_task() { send_stats "新增同步任務" echo "建立新同步任務範例:" echo "- 任務名稱: backup_www" - echo " - 本地目录: /var/www" + echo "- 本機目錄: /var/www" echo "- 遠端位址: user@192.168.1.100" echo "- 遠端目錄: /backup/www" echo "- 連接埠號碼 (預設 22)" @@ -7299,7 +7386,7 @@ add_task() { # 刪除任務 delete_task() { send_stats "刪除同步任務" - read -e -p "请输入要删除的任务编号: " num + read -e -p "請輸入要刪除的任務編號:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then @@ -7325,7 +7412,7 @@ run_task() { CONFIG_FILE="$HOME/.rsync_tasks" CRON_FILE="$HOME/.rsync_cron" - # 解析参数 + # 解析參數 local direction="push" # 默认是推送到远端 local num @@ -7336,7 +7423,7 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 如果沒有傳入任務編號,提示使用者輸入 if [[ -z "$num" ]]; then read -e -p "請輸入要執行的任務編號:" num fi @@ -7351,7 +7438,7 @@ run_task() { # 根據同步方向調整來源和目標路徑 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -7668,11 +7755,11 @@ linux_tools() { echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" - echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文字編輯器${gl_kjlan}16. ${gl_bai}nano 文字編輯器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}git 版本控制系統${gl_kjlan}18. ${gl_bai}opencode AI程式設計助手${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}駭客任務螢幕保${gl_kjlan}22. ${gl_bai}跑火車屏保" @@ -7919,7 +8006,7 @@ linux_tools() { ;; *) - echo "无效的输入!" + echo "無效的輸入!" ;; esac break_end @@ -8045,7 +8132,7 @@ docker_ssh_migration() { # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}Compose 項目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已備份過,跳過重複打包...${gl_bai}" continue fi @@ -8056,7 +8143,7 @@ docker_ssh_migration() { echo "# docker-compose 恢復:$project_name" >> "$RESTORE_SCRIPT" echo "cd \"$project_dir\" && docker compose up -d" >> "$RESTORE_SCRIPT" PACKED_COMPOSE_PATHS["$project_dir"]=1 - echo -e "${gl_lv}Compose 項目 [$project_name] 已打包: ${project_dir}${gl_bai}" + echo -e "${gl_lv}Compose 項目 [$project_name] 已打包:${project_dir}${gl_bai}" else echo -e "${gl_hong}未找到 docker-compose.yml,跳過此容器...${gl_bai}" fi @@ -8232,10 +8319,10 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker遷移" install jq - read -e -p "请输入要迁移的备份目录: " BACKUP_DIR + read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } - kj_ssh_read_host_user_port "目標伺服器IP:" "目标服务器SSH用户名 [默认root]: " "目標伺服器SSH連接埠 [預設22]:" "root" "22" + kj_ssh_read_host_user_port "目標伺服器IP:" "目標伺服器SSH用戶名 [預設root]:" "目標伺服器SSH連接埠 [預設22]:" "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" @@ -8255,7 +8342,7 @@ docker_ssh_migration() { # ---------------------------- delete_backup() { send_stats "Docker備份檔案刪除" - read -e -p "请输入要删除的备份目录: " BACKUP_DIR + read -e -p "請輸入要刪除的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } rm -rf "$BACKUP_DIR" echo -e "${gl_lv}已刪除備份:${BACKUP_DIR}${gl_bai}" @@ -8265,7 +8352,7 @@ docker_ssh_migration() { # 主選單 # ---------------------------- main_menu() { - send_stats "Docker备份迁移还原" + send_stats "Docker備份遷移還原" while true; do clear echo "------------------------" @@ -8315,18 +8402,18 @@ linux_docker() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}Docker容器管理${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}Docker映像管理" - echo -e "${gl_kjlan}5. ${gl_bai}Docker网络管理" + echo -e "${gl_kjlan}5. ${gl_bai}Docker網路管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker磁碟區管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" + echo -e "${gl_kjlan}7. ${gl_bai}清理無用的docker容器和映像網路資料卷" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}8. ${gl_bai}更换Docker源" + echo -e "${gl_kjlan}8. ${gl_bai}更換Docker源" echo -e "${gl_kjlan}9. ${gl_bai}編輯daemon.json文件" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}解除安裝Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -8407,7 +8494,7 @@ linux_docker() { echo "1. 建立網絡" echo "2. 加入網絡" echo "3. 退出網絡" - echo "4. 删除网络" + echo "4. 刪除網絡" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -8422,7 +8509,7 @@ linux_docker() { 2) send_stats "加入網路" read -e -p "加入網路名稱:" dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername @@ -8441,7 +8528,7 @@ linux_docker() { 4) send_stats "刪除網絡" - read -e -p "请输入要删除的网络名: " dockernetwork + read -e -p "請輸入要刪除的網路名稱:" dockernetwork docker network rm $dockernetwork ;; @@ -8606,7 +8693,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" @@ -8993,7 +9080,7 @@ linux_ldnmp() { echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}31. ${gl_bai}站点数据管理 ${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" + echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" @@ -9186,11 +9273,11 @@ linux_ldnmp() { echo "網址url: https://$yuming" echo "後台登入路徑: /admin" echo "------------------------" - echo "用户名: admin" + echo "使用者名稱: admin" echo "密碼: admin" echo "------------------------" echo "登入時右上角如果出現紅色error0請使用下列指令:" - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9368,7 +9455,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9437,7 +9524,7 @@ linux_ldnmp() { echo ;; 2) - echo "資料庫備份必須是.gz結尾的壓縮包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + echo "資料庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ @@ -9468,7 +9555,7 @@ linux_ldnmp() { echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" echo "表前綴:$prefix" - echo "管理员登录信息自行设置" + echo "管理員登入資訊自行設定" ;; @@ -9650,7 +9737,7 @@ linux_ldnmp() { echo -e "[${gl_huang}1/2${gl_bai}] 上傳靜態原始碼" echo "-------------" echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" - read -e -p "也可以输入下载链接,远程下载源码包,直接回车将跳过远程下载: " url_download + read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then wget "$url_download" @@ -9699,7 +9786,7 @@ linux_ldnmp() { while true; do clear echo "備份檔案已建立: /home/$backup_filename" - read -e -p "要传送备份数据到远程服务器吗? (Y/N):" choice + read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" @@ -9730,7 +9817,7 @@ linux_ldnmp() { clear send_stats "定時遠端備份" read -e -p "輸入遠端伺服器IP:" useip - read -e -p "输入远程服务器密码: " usepasswd + read -e -p "輸入遠端伺服器密碼:" usepasswd cd ~ wget -O ${useip}_beifen.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/beifen.sh > /dev/null 2>&1 @@ -9795,7 +9882,7 @@ linux_ldnmp() { install_certbot install_ldnmp else - echo "没有找到压缩包。" + echo "沒有找到壓縮包。" fi ;; @@ -10022,8 +10109,8 @@ moltbot_menu() { fi } - get_running_status() { - if pgrep -f "openclaw-gatewa" >/dev/null 2>&1; then + get_running_status() { + if pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then echo "${gl_lv}運作中${gl_bai}" else echo "${gl_hui}未運行${gl_bai}" @@ -10054,7 +10141,7 @@ moltbot_menu() { echo "6. API管理" echo "7. 機器人連線對接" echo "8. 插件管理(安裝/刪除)" - echo "9. 技能管理(安装/删除)" + echo "9. 技能管理(安裝/刪除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" echo "12. 健康檢測與修復" @@ -10304,7 +10391,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + summary.append(f'ℹ️ 跳過 {name}: provider 結構非法') continue api = provider.get('api', '') @@ -10313,7 +10400,7 @@ for name, provider in list(providers.items()): model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - summary.append(f'ℹ️ 跳过 {name}: 无 baseUrl/apiKey/models') + summary.append(f'ℹ️ 跳過 {name}: 無 baseUrl/apiKey/models') continue if api not in SUPPORTED_APIS: @@ -10340,7 +10427,7 @@ for name, provider in list(providers.items()): summary.append(f'🔁 {name}: /models 第 {attempts} 次重試後成功') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - summary.append(f'⚠️ 跳过 {name}: /models 返回结构不可识别') + summary.append(f'⚠️ 跳過 {name}: /models 回傳結構不可識別') continue remote_ids = [] @@ -10362,7 +10449,7 @@ for name, provider in list(providers.items()): template = copy.deepcopy(m) break if template is None: - summary.append(f'⚠️ 跳过 {name}: 本地 models 无有效模板模型') + summary.append(f'⚠️ 跳過 {name}: 本地 models 無有效模板模型') continue removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -10444,7 +10531,7 @@ if changed: else: for line in summary: print(line) - print('ℹ️ 无需同步:配置已与上游 /models 保持一致') + print('ℹ️ 無需同步:配置已與上游 /models 保持一致') PY } @@ -10608,7 +10695,7 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" } - # 核心函数:获取并添加所有模型 + # 核心函數:取得並加入所有模型 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" @@ -10679,7 +10766,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10720,7 +10807,7 @@ EOF model_count=$(echo "$available_models" | wc -l) echo "✅ 發現$model_count個可用模型:" echo "--------------------------------" - # 全部显示,带序号 + # 全部顯示,附序號 i=1 model_list=() while read -r model; do @@ -10849,7 +10936,7 @@ try: with open(path, 'r', encoding='utf-8') as f: obj = json.load(f) except FileNotFoundError: - print('MSG\tℹ️ 未找到 openclaw.json,请先完成安装/初始化。') + print('MSG\tℹ️ 未找到 openclaw.json,請先完成安裝/初始化。') raise SystemExit(0) except Exception as e: print(f'MSG\t❌ 讀取設定失敗: {type(e).__name__}: {e}') @@ -11242,7 +11329,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API删除入口" + send_stats "OpenClaw API刪除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11382,7 +11469,7 @@ PY echo "❌ 刪除失敗:無可用替代模型,已保持原始配置" ;; *) - echo "❌ 删除失败:请检查配置文件结构或日志输出" + echo "❌ 刪除失敗:請檢查設定檔結構或日誌輸出" ;; esac @@ -11390,7 +11477,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API厂商推荐" + send_stats "OpenClaw API廠商推薦" clear echo "" @@ -11748,7 +11835,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" + echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" break_end return 1 fi @@ -11787,7 +11874,7 @@ PYTHON_EOF echo "正在切換模型為:$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "切换失败:openclaw models set 返回错误。" + echo "切換失敗:openclaw models set 回傳錯誤。" break_end return 1 fi @@ -11831,7 +11918,7 @@ PYTHON_EOF echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" - printf "是否切换到该模型?[y/N,Esc 返回列表]: " + printf "是否切換到該模型? [y/N,Esc 返回列表]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12188,7 +12275,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在删除/禁用插件: $plugin_id" + echo "🗑️ 正在刪除/停用插件:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ 已卸載:$plugin_id" @@ -12245,7 +12332,7 @@ PYTHON_EOF echo "coding-agent # 自動運行 Claude Code/Codex 等程式設計助手" echo "----------------------------------------" - echo "1) 安装技能" + echo "1) 安裝技能" echo "2) 刪除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -12264,7 +12351,7 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续? (y/N):" confirm_del + read -e -p "二次確認:刪除僅影響使用者目錄 ~/.openclaw/workspace/skills,確認繼續? (y/N):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then echo "已取消刪除。" break_end @@ -12568,9 +12655,9 @@ openclaw_json_get_bool() { echo "----------------------------------------" echo "1. Telegram 機器人對接" echo "2. 飛書 (Lark) 機器人對接" - echo "3. WhatsApp 机器人对接" + echo "3. WhatsApp 機器人對接" echo "4. QQ 機器人對接" - echo "5. 微信机器人对接" + echo "5. 微信機器人對接" echo "----------------------------------------" echo "0. 返回上一級選單" echo "----------------------------------------" @@ -12591,7 +12678,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12719,7 +12806,7 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在:$archive_path"; return 1; } mkdir -p "$unpack_root" tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 備份包解壓縮失敗"; return 1; } @@ -12742,7 +12829,7 @@ EOF ( cd "$pkg_dir/payload" || exit 1 sha256sum -c ../manifest.sha256 >/dev/null - ) || { echo "❌ sha256 校验失败,拒绝还原"; return 1; } + ) || { echo "❌ sha256 校驗失敗,拒絕還原"; return 1; } echo "$pkg_dir" return 0 @@ -12826,7 +12913,7 @@ if os.path.isdir(agents_root): openclaw_project_backup_export() { - send_stats "OpenClaw项目备份" + send_stats "OpenClaw專案備份" local config_file config_file=$(openclaw_get_config_file) local openclaw_root @@ -13059,7 +13146,7 @@ if os.path.isdir(agents_root): return 0 fi - read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input + read -e -p "請輸入要刪除的檔案名稱或完整路徑(0 取消):" user_input if [ "$user_input" = "0" ]; then echo "已取消刪除。" break_end @@ -13271,7 +13358,7 @@ PY if mv "$store_file" "$backup_file"; then echo "✅ [$agent_id] 已備份索引:$backup_file" else - echo "⚠️ [$agent_id] 索引备份失败,继续重建。" + echo "⚠️ [$agent_id] 索引備份失敗,繼續重建。" fi fi openclaw memory index --agent "$agent_id" --force @@ -13339,7 +13426,7 @@ EOF local json_output json_output=$(openclaw memory status --json 2>/dev/null) if [ -z "$json_output" ]; then - echo "获取记忆状态失败(openclaw memory status --json 无输出)" + echo "取得記憶狀態失敗(openclaw memory status --json 無輸出)" return 1 fi python3 - "$json_output" <<'PY' @@ -13560,7 +13647,7 @@ PY wget -O "$dest" "$url" return $? fi - echo "❌ 未检测到 curl 或 wget,无法下载。" + echo "❌ 未偵測到 curl 或 wget,無法下載。" return 1 } @@ -13671,21 +13758,21 @@ PY OPENCLAW_MEMORY_PREHEAT="true" OPENCLAW_MEMORY_RESTARTED="false" OPENCLAW_MEMORY_CONFIG_ONLY="false" - echo "即将执行自动部署(详细模式)" + echo "即將執行自動部署(詳細模式)" echo "目標方案:$scheme_label" echo "地區: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" echo "鏡像來源探測: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下載來源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then - echo "预计下载路径: $OPENCLAW_MEMORY_EXPECT_PATH" + echo "預計下載路徑:$OPENCLAW_MEMORY_EXPECT_PATH" fi if [ -n "$OPENCLAW_MEMORY_EXPECT_SIZE" ]; then echo "可能流量/磁碟佔用:$OPENCLAW_MEMORY_EXPECT_SIZE" else - echo "可能流量/磁盘占用: 视实际情况而定" + echo "可能流量/磁碟佔用: 視實際情況而定" fi - echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" - echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step case "$confirm_step" in yes|YES) @@ -13709,7 +13796,7 @@ PY } openclaw_memory_auto_setup_qmd() { - echo "🔍 檢測 QMD 環境" + echo "🔍 检测 QMD 环境" openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then @@ -13735,7 +13822,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正確" + echo "✅ memory.qmd.command 已正确" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -14012,7 +14099,7 @@ EOF echo "Local: 本機向量檢索,依賴 embedding 模型文件" echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" - echo "1. 切换 QMD(自动部署/已装则跳过)" + echo "1. 切換 QMD(自動部署/已安裝則跳過)" echo "2. 切換 Local(自動部署/已安裝則跳過)" echo "3. Auto(自動推薦並自動部署)" echo "0. 返回上一級" @@ -14098,8 +14185,8 @@ EOF local start_line count echo "文件:$file" echo "總行數:$total_lines" - read -e -p "请输入起始行(回车默认末尾 $default_lines行):" start_line - read -e -p "请输入显示行数(回车默认 $default_lines): " count + read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line + read -e -p "請輸入顯示行數(回車預設$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14169,7 +14256,7 @@ EOF openclaw_memory_search_test() { read -e -p "輸入搜尋關鍵字:" query if [ -z "$query" ]; then - echo "关键词不能为空。" + echo "關鍵字不能為空。" return 1 fi echo "正在搜尋記憶..." @@ -14190,7 +14277,7 @@ EOF echo "=======================================" openclaw_memory_render_status echo "1. 更新記憶索引" - echo "2. 查看记忆文件" + echo "2. 檢視記憶文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" echo "5. 搜尋測試(驗證索引是否運作)" @@ -14225,7 +14312,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14482,7 +14569,7 @@ print(json.dumps(data, indent=2)) openclaw_permission_render_status() { echo "應用層配置: ~/.openclaw/openclaw.json" - echo "宿主机审批: ~/.openclaw/exec-approvals.json" + echo "宿主機核准: ~/.openclaw/exec-approvals.json" echo "---------------------------------------" local current_profile current_sec current_ask current_elevated current_profile=$(openclaw config get tools.profile 2>/dev/null | head -n 1 | sed 's/^"//;s/"$//') @@ -14509,8 +14596,8 @@ print(json.dumps(data, indent=2)) echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" echo "Profile (預設): ${current_profile:-(unset)}" - echo " Exec 限制: ${current_sec:-(unset)}" - echo "審核提示: ${current_ask:-(unset)}" + echo "Exec 限制: ${current_sec:-(unset)}" + echo " 审批提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" @@ -14594,11 +14681,11 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" + echo -e "${gl_lv}✅ 已切換為開發增強模式 (允許提權,但常規危險命令仍需審批)${gl_bai}" } openclaw_permission_apply_full() { - send_stats "OpenClaw权限-完全开放模式" + send_stats "OpenClaw權限-完全開放模式" openclaw_permission_require_openclaw || return 1 echo "正在設定應用層策略..." @@ -14697,7 +14784,7 @@ except Exception as e: 1) read -e -p "輸入要放行的命令路徑 (支援 glob,如 /usr/bin/git):" pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } - read -e -p "指定智能体ID (留空=所有智能体 *): " agent_id + read -e -p "指定智能體ID (留空=所有智能體 *):" agent_id agent_id="${agent_id:-*}" openclaw approvals allowlist add --agent "$agent_id" "$pattern" break_end @@ -14723,7 +14810,7 @@ except Exception as e: echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" + echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" @@ -14734,13 +14821,13 @@ except Exception as e: read -e -p "請輸入你的選擇:" perm_choice case "$perm_choice" in 1) - echo "準備應用:標準安全模式" + echo "准备应用:标准安全模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "已取消"; fi break_end ;; 2) - echo "準備應用:開發增強模式" + echo "准备应用:开发增强模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end @@ -14975,8 +15062,8 @@ else: is_default = item.get("isDefault", False) bcount = item.get("bindings", 0) default_tag = "[預設]" if is_default else "" - print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) - print(" 身份名称: %s %s" % (identity, emoji)) + print("- 智能體ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("身份名稱: %s %s" % (identity, emoji)) print("模型: %s" % model) print("工作目錄: %s" % ws) print("綁定數: %s" % bcount) @@ -14995,7 +15082,7 @@ for idx,item in enumerate(agents,1): send_stats "OpenClaw多智能體-新增Agent" openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm - read -e -p "请输入新的 Agent ID: " agent_id + read -e -p "請輸入新的 Agent ID:" agent_id [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 read -e -p "請輸入 workspace 路徑(預設為 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" @@ -15006,14 +15093,14 @@ for idx,item in enumerate(agents,1): if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ 智能體創建成功:$agent_id" local name theme - read -e -p "请输入智能体身份名称 (如: 代码专家): " name + read -e -p "請輸入智能體身分名稱 (如: 代碼專家):" name [ -z "$name" ] && name="$agent_id" read -e -p "請輸入智能體性格主題 (如: 嚴謹、有效率):" theme [ -z "$theme" ] && theme="助理" echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體建立失敗" + echo "❌ 智能體創建失敗" return 1 fi } @@ -15062,7 +15149,7 @@ for idx,item in enumerate(bindings,1): if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ 路由綁定新增成功" else - echo "❌ 路由绑定添加失败" + echo "❌ 路由綁定新增失敗" return 1 fi } @@ -15074,7 +15161,7 @@ for idx,item in enumerate(bindings,1): read -e -p "請輸入智能體 ID:" agent_id read -e -p "請輸入要移除的路由綁定值:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 - echo "将移除智能体 [$agent_id] 的路由綁定 [$bind_value]" + echo "將移除智能體 [$agent_id] 的路由綁定 [$bind_value]" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15121,7 +15208,7 @@ for item in sessions[:10]: openclaw_multiagent_require_openclaw || return 1 local config_file config_file=$(openclaw_multiagent_config_file) - echo "检查配置文件: ${config_file:-$(openclaw_permission_config_file)}" + echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" python3 -c ' import json,sys,os @@ -15129,7 +15216,7 @@ agents=json.loads(sys.argv[1] or "[]") bindings=json.loads(sys.argv[2] or "[]") print("---------------------------------------") if not agents: - print("⚠️ 未发现已配置智能体。") + print("⚠️ 未發現配置智能體。") else: for item in agents: ws = item.get("workspace") or "" @@ -15156,15 +15243,15 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_require_openclaw || return 1 openclaw_multiagent_list_agents read -e -p "輸入要修改身分的智能體ID:" agent_id - [ -z "$agent_id" ] && { echo "ID 不能为空"; return 1; } - echo "修改选项(留空跳过):" + [ -z "$agent_id" ] && { echo "ID 不能為空"; return 1; } + echo "修改選項(留空跳過):" read -e -p "新名稱:" new_name read -e -p "新 Emoji:" new_emoji local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" echo "也可以從 IDENTITY.md 自動讀取身分資訊。" - read -e -p "是否从 IDENTITY.md 读取? (y/n):" from_id + read -e -p "是否從 IDENTITY.md 讀取? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" fi @@ -15229,7 +15316,7 @@ openclaw_backup_restore_menu() { echo "---------------------------------------" echo "1. 備份記憶全量" echo "2. 還原記憶全量" - echo "3. 備份 OpenClaw 專案(預設安全模式)" + echo "3. 备份 OpenClaw 项目(默认安全模式)" echo "4. 還原 OpenClaw 專案(進階/高風險)" echo "5. 刪除備份文件" echo "0. 返回上一級" @@ -15275,7 +15362,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15452,7 +15539,7 @@ openclaw_backup_restore_menu() { break_end ;; 13) openclaw_webui_menu ;; - 14) send_stats "TUI命令行对话" + 14) send_stats "TUI命令列對話" openclaw tui break_end ;; @@ -15517,7 +15604,7 @@ while true; do echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" + echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" @@ -15525,7 +15612,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" + echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" @@ -15565,7 +15652,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -15576,7 +15663,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" - echo -e "${gl_kjlan}想要让你的应用出现在这里?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15588,7 +15675,7 @@ while true; do # 這裡假設 appno.txt 中記錄的是 base_name (即檔名) if echo "$app_numbers" | grep -q "^$base_name$"; then # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) - echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" else # 如果未安裝:正常顯示 echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" @@ -16616,7 +16703,7 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" + local docker_describe="photoprism非常強大的私有相簿系統" local docker_url="官網介紹: https://www.photoprism.app/" local docker_use="echo \"帳號: admin 密碼:$rootpasswd\"" local docker_passwd="" @@ -17893,7 +17980,7 @@ while true; do local app_id="80" local app_name="linkwarden書籤管理" local app_text="一個開源的自架書籤管理平台,支援標籤、搜尋和團隊協作。" - local app_url="官方网站: https://linkwarden.app/" + local app_url="官方網站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -18756,7 +18843,7 @@ while true; do docker_app_install() { - read -e -p "设置 CPU 核数 (默认 2): " CPU_CORES + read -e -p "設定 CPU 核數 (預設 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} read -e -p "設定記憶體大小 (預設 4G):" RAM_SIZE @@ -18831,7 +18918,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19470,7 +19557,7 @@ linux_work() { install tmux local SESSION_NAME="sshd" send_stats "啟動工作區$SESSION_NAME" - grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自动进入 tmux 会话\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc + grep -q "tmux attach-session -t sshd" ~/.bashrc || echo -e "\n# 自動進入 tmux 會話\nif [[ -z \"\$TMUX\" ]]; then\n tmux attach-session -t sshd || tmux new-session -s sshd\nfi" >> ~/.bashrc source ~/.bashrc tmux_run ;; @@ -19621,7 +19708,7 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH防御基础参数配置" + send_stats "SSH防禦基礎參數配置" f2b_basic_config break_end ;; @@ -20077,7 +20164,7 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快速鍵已設定" + echo "快捷键已设置" send_stats "腳本快捷鍵已設定" break_end linux_Settings @@ -20213,7 +20300,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH連接埠修改" + send_stats "退出SSH埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20383,7 +20470,7 @@ EOF echo "------------------------" echo "1. 建立普通用戶 2. 建立進階用戶" echo "------------------------" - echo "3. 赋予最高权限 4. 取消最高权限" + echo "3. 賦予最高權限 4. 取消最高權限" echo "------------------------" echo "5. 刪除帳號" echo "------------------------" @@ -20394,7 +20481,7 @@ EOF case $sub_choice in 1) # 提示使用者輸入新使用者名稱 - read -e -p "请输入新用户名: " new_username + read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false ;; @@ -20515,11 +20602,11 @@ EOF echo "歐洲" echo "11. 英國倫敦時間 12. 法國巴黎時間" echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" - echo "15. 荷兰尤特赖赫特时间 16. 西班牙马德里时间" + echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" echo "------------------------" echo "美洲" echo "21. 美國西部時間 22. 美國東部時間" - echo "23. 加拿大时间 24. 墨西哥时间" + echo "23. 加拿大時間 24. 墨西哥時間" echo "25. 巴西時間 26. 阿根廷時間" echo "------------------------" echo "31. UTC全球標準時間" @@ -20618,7 +20705,7 @@ EOF echo "選擇更新來源區域" echo "接入LinuxMirrors切換系統更新來源" echo "------------------------" - echo "1. 中国大陆【默认】 2. 中国大陆【教育网】 3. 海外地区 4. 智能切换更新源" + echo "1. 中國大陸【預設】 2. 中國大陸【教育網】 3. 海外地區 4. 智慧切換更新源" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20661,7 +20748,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 新增定時任務 2. 刪除定時任務 3. 編輯定時任務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20672,7 +20759,7 @@ EOF read -e -p "請輸入新任務的執行指令:" newquest echo "------------------------" echo "1. 每月任務 2. 每週任務" - echo "3. 每天任务 4. 每小时任务" + echo "3. 每天任務 4. 每小時任務" echo "------------------------" read -e -p "請輸入你的選擇:" dingshi @@ -20686,7 +20773,7 @@ EOF (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) - read -e -p "選擇每天幾點執行任務? (小时,0-23):" hour + read -e -p "選擇每天幾點執行任務? (小時,0-23):" hour (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) @@ -20763,14 +20850,14 @@ EOF while true; do clear echo "限流關機功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "影片介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" echo "目前流量使用情況,重啟伺服器流量計算會清除!" output_status echo -e "${gl_kjlan}總接收:${gl_bai}$rx" echo -e "${gl_kjlan}總發送:${gl_bai}$tx" - # 检查是否存在 Limiting_Shut_down.sh 文件 + # 檢查是否存在 Limiting_Shut_down.sh 文件 if [ -f ~/Limiting_Shut_down.sh ]; then # 取得 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) @@ -20783,7 +20870,7 @@ EOF echo echo "------------------------------------------------" - echo "系统每分钟会检测实际流量是否到达阈值,到达后会自动关闭服务器!" + echo "系統每分鐘會偵測實際流量是否到達閾值,到達後會自動關閉伺服器!" echo "------------------------" echo "1. 開啟限流關機功能 2. 停用限流關機功能" echo "------------------------" @@ -20836,18 +20923,18 @@ EOF 25) root_use - send_stats "电报预警" + send_stats "電報預警" echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" - echo "到达阈值后会向用户发预警消息" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in [Yy]) - send_stats "电报预警启用" + send_stats "電報預警啟用" cd ~ install nano tmux bc jq check_crontab_installed @@ -20894,7 +20981,7 @@ EOF 26) root_use - send_stats "修复SSH高危漏洞" + send_stats "修復SSH高風險漏洞" cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/upgrade_openssh9.8p1.sh chmod +x ~/upgrade_openssh9.8p1.sh @@ -20994,12 +21081,12 @@ EOF echo "2. 清理系統垃圾文件" echo -e "3. 設定虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" - echo -e "5. 启动fail2ban防御SSH暴力破解" - echo -e "6. 开放所有端口" + echo -e "5. 啟動fail2ban防禦SSH暴力破解" + echo -e "6. 開放所有端口" echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 设置网络为${gl_huang}ipv4優先${gl_bai}" + echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" @@ -21020,7 +21107,7 @@ EOF echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設定虛擬內存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 @@ -21089,7 +21176,7 @@ EOF fi echo "隱私與安全" - echo "脚本将收集用户使用功能的数据,优化脚本体验,制作更多好玩好用的功能" + echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" echo -e "目前狀態:$status_message" @@ -21112,7 +21199,7 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh - echo "已关闭采集" + echo "已關閉採集" send_stats "隱私與安全已關閉採集" ;; *) @@ -21191,10 +21278,10 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" - echo "21. 压缩文件目录 22. 解压文件目录 23. 移动文件目录 24. 复制文件目录" + echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" echo "25. 傳文件至其他伺服器" echo "------------------------" echo "0. 返回上一級選單" @@ -21215,7 +21302,7 @@ linux_file() { 3) # 修改目录权限 read -e -p "請輸入目錄名:" dirname read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失敗" + chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" send_stats "修改目錄權限" ;; 4) # 重命名目录 @@ -21270,7 +21357,7 @@ linux_file() { 22) # 解压文件/目录 read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar - tar -xzvf "$filename" && echo "已解压 $filename" || echo "解壓縮失敗" + tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" ;; @@ -21290,12 +21377,12 @@ linux_file() { fi mv "$src_path" "$dest_path" && echo "檔案或目錄已移動到$dest_path" || echo "移動檔案或目錄失敗" - send_stats "移动文件或目录" + send_stats "移動檔案或目錄" ;; 24) # 复制文件目录 - read -e -p "请输入要复制的文件或目录路径: " src_path + read -e -p "請輸入要複製的檔案或目錄路徑:" src_path if [ ! -e "$src_path" ]; then echo "錯誤: 檔案或目錄不存在。" send_stats "複製檔案或目錄失敗: 檔案或目錄不存在" @@ -21319,7 +21406,7 @@ linux_file() { read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "錯誤: 文件不存在。" - send_stats "传送文件失败: 文件不存在" + send_stats "傳送文件失敗: 文件不存在" continue fi @@ -21335,7 +21422,7 @@ linux_file() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # 使用scp传输文件 + # 使用scp傳輸文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" </dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # 部署到 /usr/local/bin/k 和 /usr/bin/k SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21849,9 +21936,9 @@ echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" -echo "软件启动 k start sshd | k 启动 sshd " +echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "軟體重啟 k restart sshd | k 重啟 sshd" +echo "软件重启 k restart sshd | k 重启 sshd " echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" @@ -21866,11 +21953,11 @@ echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" -echo "防火墙面板 k fhq |k 防火墙" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "防火牆面板 k fhq |k 防火牆" +echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" +echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" -echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" +echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" @@ -21885,7 +21972,7 @@ echo "SSH公鑰導入(GitHub) k sshkey github " if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 如果沒有參數,運行互動式邏輯 kejilion_sh else # 如果有參數,執行對應函數 From 3cf20f16352fbef99323793c2c4f3e3e019fdefc Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Sun, 3 May 2026 18:57:48 +0800 Subject: [PATCH 1167/1285] fix(bbr3): add explicit error for dropped xanmod distributions like jammy --- kejilion.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 0266693e6..069d1714f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5611,9 +5611,15 @@ bbrv3() { fi # 兼容官方已移除的老系统代号(回退使用 releases 尝试旧包库) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + + # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod 官方已停止对当前系统($os_codename)的 APT 源支持,请升级至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" + return 1 + fi if [ -z "$os_codename" ]; then echo "无法获取系统代号,无法配置XanMod源" From 2f7418978cec5e42812d4cdf06717b112b0af0e6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 10 May 2026 05:58:54 +0000 Subject: [PATCH 1168/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-05-10=2005:58:54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 126 +++++++++++++++--------------- jp/kejilion.sh | 198 ++++++++++++++++++++++++----------------------- kr/kejilion.sh | 182 ++++++++++++++++++++++--------------------- tw/kejilion.sh | 204 +++++++++++++++++++++++++------------------------ 4 files changed, 367 insertions(+), 343 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 4a32cfb82..5b715571e 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1258,7 +1258,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "The virtual memory size has been adjusted to${gl_huang}${new_swap}${gl_bai}M" } @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3221,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo -e "Stream four-layer proxy forwarding tool$check_docker $update_status" echo "NGINX Stream is the TCP/UDP proxy module of NGINX, which is used to achieve high-performance transport layer traffic forwarding and load balancing." echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3661,9 +3661,9 @@ stream_panel() { fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. Install 2. Update 3. Uninstall" echo "------------------------" - echo "4. 添加转发服务 5. 修改转发服务 6. 删除转发服务" + echo "4. Add forwarding service 5. Modify forwarding service 6. Delete forwarding service" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -4392,7 +4392,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4489,7 +4489,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -5611,9 +5611,15 @@ bbrv3() { fi # Compatible with the old system codenames that have been officially removed (fall back to using releases to try the old package library) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + + # Officially, apt support for jammy, focal, bullseye and other old systems has been completely removed. + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod has officially stopped supporting the current system ($os_codename), please upgrade to Debian12/Ubuntu24 or higher.${gl_bai}" + return 1 + fi if [ -z "$os_codename" ]; then echo "Unable to obtain system codename, unable to configure XanMod source" @@ -6386,7 +6392,7 @@ Kernel_optimize() { echo "Provides a variety of system parameter tuning modes, and users can choose to switch according to their own usage scenarios." echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in production environment!" echo -e "--------------------" - echo -e "1. High-performance optimization mode: Maximize system performance, aggressive memory and network parameters." + echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" echo -e "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." echo -e "3. Website optimization mode: Optimized for website servers, ultra-high concurrent connection queue." echo -e "4. Live broadcast optimization mode: For live streaming optimization, the UDP buffer is enlarged to reduce delays." @@ -7184,7 +7190,7 @@ mount_partition() { return 1 fi - echo "Partition successfully mounted to$MOUNT_POINT" + echo "The partition was successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7340,7 +7346,7 @@ add_task() { echo "Example of creating a new sync task:" echo "- Task name: backup_www" echo "- Local directory: /var/www" - echo " - 远程地址: user@192.168.1.100" + echo "- Remote address: user@192.168.1.100" echo "- Remote directory: /backup/www" echo "- Port number (default 22)" echo "---------------------------------" @@ -7379,7 +7385,7 @@ add_task() { install rsync rsync - echo "任务已保存!" + echo "Mission saved!" } @@ -7479,14 +7485,14 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi } -# Create a scheduled task +# 创建定时任务 schedule_task() { send_stats "Add synchronization scheduled tasks" @@ -7696,7 +7702,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" tools=( @@ -8170,7 +8176,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8508,7 +8514,7 @@ linux_docker() { ;; 2) send_stats "Join the network" - read -e -p "加入网络名: " dockernetwork + read -e -p "Add network name:" dockernetwork read -e -p "Which containers join the network (please separate multiple container names with spaces):" dockernames for dockername in $dockernames; do @@ -10138,7 +10144,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API Management" + echo "6. API management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -11339,7 +11345,7 @@ PY read -erp "Please enter the API name (provider) to be deleted:" provider_name if [ -z "$provider_name" ]; then - send_stats "OpenClaw API删除取消" + send_stats "OpenClaw API Delete Cancel" echo "❌ provider name cannot be empty" break_end return 1 @@ -12206,7 +12212,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12334,7 +12340,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -12908,7 +12914,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ Agent memory restored: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 记忆全量还原完成"; break_end + rm -rf "$tmp_unpack"; echo "✅ Full memory restoration completed"; break_end } @@ -13073,7 +13079,7 @@ if os.path.isdir(agents_root): echo "Backup directory:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "No backup file yet" + echo "No backup files yet" return 0 fi @@ -14186,7 +14192,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count + read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14375,7 +14381,7 @@ EOF fi mkdir -p "$(dirname "$backup_file")" cp -f "$config_file" "$backup_file" >/dev/null 2>&1 || { - echo "⚠️ 权限备份失败:$backup_file" + echo "⚠️ Permission backup failed:$backup_file" return 1 } echo "✅ Current permission configuration has been backed up:$backup_file" @@ -14732,7 +14738,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "Do you want to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice + read -e -p "Attempt to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ Automatic repair completed.${gl_bai}" @@ -15965,7 +15971,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16069,7 +16075,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -16123,7 +16129,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -16154,7 +16160,7 @@ while true; do } local docker_describe="ZenTao is a universal project management software" - local docker_url="Official website introduction: https://www.zentao.net/" + local docker_url="官网介绍: https://www.zentao.net/" local docker_use="echo \"Initial username: admin\"" local docker_passwd="echo \"Initial password: 123456\"" local app_size="2" @@ -16194,7 +16200,7 @@ while true; do local app_id="13" local app_name="cloudreve network disk" - local app_text="cloudreve is a network disk system that supports multiple cloud storages" + local app_text="cloudreve是一个支持多家云存储的网盘系统" local app_url="Video introduction: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" @@ -16221,7 +16227,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17107,7 +17113,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17334,7 +17340,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17386,7 +17392,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17399,7 +17405,7 @@ while true; do local app_id="60" local app_name="JumpServer open source bastion machine" local app_text="It is an open source privileged access management (PAM) tool. This program occupies port 80 and does not support adding domain names for access." - local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" + local app_url="Official introduction:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -17427,7 +17433,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17490,7 +17496,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17818,7 +17824,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18039,7 +18045,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18089,7 +18095,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18225,7 +18231,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18452,7 +18458,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18483,7 +18489,7 @@ while true; do } local docker_describe="Is a web-based file manager" - local docker_url="官网介绍: https://filebrowser.org/" + local docker_url="Official website introduction: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" local app_size="1" @@ -18590,7 +18596,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18644,7 +18650,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18877,7 +18883,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18948,7 +18954,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19017,7 +19023,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19158,7 +19164,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19228,7 +19234,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19452,7 +19458,7 @@ linux_work() { echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" echo -e "${gl_kjlan}10. ${gl_bai}Workspace 10" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}21. ${gl_bai}SSH resident mode${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}Create/enter workspace" echo -e "${gl_kjlan}23. ${gl_bai}Inject commands into the background workspace" echo -e "${gl_kjlan}24. ${gl_bai}Delete specified workspace" @@ -20188,7 +20194,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20374,8 +20380,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -21517,7 +21523,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21634,7 +21640,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 6e7708fc2..30d5095a8 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -125,7 +125,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -260,7 +260,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1540,7 +1540,7 @@ certs_status() { send_stats "ドメイン名証明書の申請が成功しました" else send_stats "ドメイン名証明書の申請に失敗しました" - echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、もう一度試してください。" + echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" @@ -1750,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1991,7 +1991,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2215,7 +2215,7 @@ web_security() { 21) send_stats "クラウドフレアモード" - echo "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択し、グローバル API キーを取得します。" + echo "cf バックエンドの右上隅にある私のプロフィールに移動し、左側の API トークンを選択して、グローバル API キーを取得します。" echo "https://dash.cloudflare.com/login" read -e -p "CF の口座番号を入力してください:" cfuser read -e -p "CF のグローバル API キーを入力します。" cftoken @@ -2240,8 +2240,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -3221,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3275,7 +3275,7 @@ EOF } # メイン構成/オーバーレイ構成エディター (nano) を直接開きます。 -# /etc/fail2ban/jail.d/sshd.local を最初に編集し (より安全です)、存在しない場合は作成します +# 最初に /etc/fail2ban/jail.d/sshd.local を編集し (より安全です)、存在しない場合は作成します f2b_edit_config() { root_use install nano @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4153,7 +4153,7 @@ add_forwarding_service() { read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -5045,7 +5045,7 @@ fetch_remote_ssh_keys() { # コンテンツが有効かどうかを確認する if [[ ! -s "${temp_file}" ]]; then - echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります" >&2 + echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります。" >&2 rm -f "${temp_file}" return 1 fi @@ -5474,7 +5474,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5611,12 +5611,18 @@ bbrv3() { fi # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + + # 公式には、jammy、focal、bulseye、その他の古いシステムの apt サポートは完全に削除されました。 + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod は現在のシステムのサポートを正式に停止しました ($os_codename) の場合は、Debian12/Ubuntu24 以降にアップグレードしてください。${gl_bai}" + return 1 + fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません、XanMod ソースを構成できません" + echo "システムコードネームを取得できません。XanMod ソースを構成できません" return 1 fi @@ -5756,7 +5762,7 @@ bbrv3() { clear local kernel_version=$(uname -r) echo "xanmod の BBRv3 カーネルがインストールされている" - echo "現在のカーネル バージョン:$kernel_version" + echo "現在のカーネルのバージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5854,7 +5860,7 @@ elrepo() { clear kernel_version=$(uname -r) echo "elrepo カーネルがインストールされています" - echo "現在のカーネル バージョン:$kernel_version" + echo "現在のカーネルのバージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5895,7 +5901,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5943,7 +5949,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6008,7 +6014,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6035,7 +6041,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6318,7 +6324,7 @@ LIMITS sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name}最適化が完了しました!構成は永続化されています${CONF}${gl_bai}" + echo -e "${gl_lv}${mode_name}最適化が完了しました!設定は永続化されています${CONF}${gl_bai}" echo -e "${gl_lv}メモリ:${MEM_MB}MB |輻輳アルゴリズム:${CC}|列:${QDISC}${gl_bai}" } @@ -6372,7 +6378,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6648,7 +6654,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "ごみ箱が有効になっていると、削除されたファイルはごみ箱に移動されます。" + echo "ごみ箱が有効になっている場合、削除されたファイルはごみ箱に移動されます。" sleep 2 ;; 2) @@ -6819,7 +6825,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7167,7 +7173,7 @@ mount_partition() { return 1 fi - # ファイルシステムの種類を取得する + # ファイルシステムのタイプを取得する FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then echo "ファイル システム タイプを取得できません!" @@ -7184,7 +7190,7 @@ mount_partition() { return 1 fi - echo "パーティションが正常にマウントされました$MOUNT_POINT" + echo "パーティションは正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7319,7 +7325,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7479,7 +7485,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモートホストはアクセス可能ですか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7578,7 +7584,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7640,7 +7646,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7696,7 +7702,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" tools=( @@ -7878,7 +7884,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncdu をインストールする" + send_stats "ncduをインストールする" ;; 14) clear @@ -8132,7 +8138,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8449,7 +8455,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8548,7 +8554,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8891,7 +8897,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9277,7 +9283,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -10338,7 +10344,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10417,7 +10423,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10437,7 +10443,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11116,7 +11122,7 @@ if err is not None: raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返された構造は認識されません') + print(f'❌ {target}: /models 返された構造体は認識されません') raise SystemExit(4) remote_ids = [] @@ -11227,7 +11233,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11258,7 +11264,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "設定したい API タイプを選択してください:" + echo "セットアップする API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -12304,7 +12310,7 @@ PYTHON_EOF install_skill() { - send_stats "スキル管理" + send_stats "スキルマネジメント" while true; do clear echo "========================================" @@ -12325,7 +12331,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12367,7 +12373,7 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" + echo "💡 スキル [$skill_name]がユーザーディレクトリにインストールされます。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" @@ -12657,7 +12663,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5. WeChatロボットのドッキング" + echo "5.WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12678,7 +12684,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12926,7 +12932,7 @@ if os.path.isdir(agents_root): echo "バックアップモード:" echo "1. セーフ モード (デフォルト、推奨): ワークスペース + openclaw.json + 拡張機能/スキル/プロンプト/ツール (存在する場合)" - echo "2. 完全モード (より多くの状態が含まれ、機密性のリスクが高くなります)" + echo "2. 完全モード (より多くの状態が含まれ、機密リスクが高くなります)" read -e -p "バックアップ モードを選択してください (デフォルト 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -13073,7 +13079,7 @@ if os.path.isdir(agents_root): echo "バックアップディレクトリ:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "まだバックアップファイルがありません" + echo "バックアップファイルはまだありません" return 0 fi @@ -13453,7 +13459,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("基本的なソリューション: %s" % backend) + print("基礎となるソリューション: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) @@ -13724,7 +13730,7 @@ PY echo "✅ 環境準備完了" echo "スキーム: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "モード: 設定の書き込みのみ (インストールされない/ダウンロードされない)" + echo "モード: 構成の書き込みのみ (インストールされない/ダウンロードされない)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "インデックス: 実行されました" @@ -14186,7 +14192,7 @@ EOF echo "書類:$file" echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示される行数を入力してください (Enter を押してデフォルトにします)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14643,7 +14649,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14700,7 +14706,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14732,7 +14738,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "発見されたセキュリティ脆弱性を自動的に修復しますか? (y/n):" fix_choice + read -e -p "発見されたセキュリティ脆弱性を自動的に修復してみますか? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復が完了しました。${gl_bai}" @@ -15083,7 +15089,7 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm read -e -p "新しいエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 read -e -p "ワークスペースのパスを入力してください (デフォルトは ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" @@ -15110,7 +15116,7 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id confirm read -e -p "削除するエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 echo "⚠️ エージェントを削除すると、その作業ディレクトリ、ルート バインディング、およびセッション ルーティングに影響する可能性があります。" read -e -p "「DELETE」と入力して削除を確認します${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "キャンセル"; return 1; } @@ -15161,7 +15167,7 @@ for idx,item in enumerate(bindings,1): read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" + echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15370,7 +15376,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 設定ファイルを編集する" + send_stats "OpenClaw 構成ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15445,7 +15451,7 @@ openclaw_backup_restore_menu() { echo "https://${yuming}/#token=$token" echo "まず URL にアクセスしてデバイス ID をトリガーし、Enter キーを押してペアリングを続行します。" read - echo -e "${gl_kjlan}デバイスリストをロード中...${gl_bai}" + echo -e "${gl_kjlan}デバイスリストを読み込んでいます...${gl_bai}" # ドメイン名を allowedOrigins に自動的に追加する config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then @@ -15530,7 +15536,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期設定ウィザード" + 11) send_stats "初期構成ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15624,7 +15630,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" @@ -15632,7 +15638,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -15894,7 +15900,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -16830,7 +16836,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -17160,7 +17166,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -17979,7 +17985,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -19253,7 +19259,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19773,7 +19779,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19783,7 +19789,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19795,7 +19801,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19846,7 +19852,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19856,7 +19862,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19871,7 +19877,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19959,7 +19965,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -19974,7 +19980,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -19990,7 +19996,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -20001,9 +20007,9 @@ env_menu() { echo "1. 現在一般的に使用されている環境変数を確認します。" echo "2. ~/.bashrc を表示する" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集する" + echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数(ソース)をリロードします。" + echo "6. 環境変数 (ソース) をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20374,8 +20380,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -20597,7 +20603,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9.タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -21512,12 +21518,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21557,7 +21563,7 @@ while true; do 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -21634,7 +21640,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21931,7 +21937,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21954,7 +21960,7 @@ echo "リバース プロキシをインストールします k fd |k rp |k リ echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -22155,7 +22161,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index e96dae560..117b0bcca 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -123,7 +123,7 @@ CheckFirstRun_false() { # 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear - echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다.${gl_bai}" echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -508,22 +508,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker restart $dockername ;; 6) @@ -1546,7 +1546,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -1838,7 +1838,7 @@ nginx_waf() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2011,7 +2011,7 @@ nginx_br() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2068,7 +2068,7 @@ nginx_zstd() { return 1 fi - # nginx 이미지를 확인하고 그에 따라 처리하십시오. + # nginx 이미지를 확인하고 그에 따라 처리하세요. if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3725,7 +3725,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4983,7 +4983,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5611,9 +5611,15 @@ bbrv3() { fi # 공식적으로 제거된 이전 시스템 코드명과 호환 가능(이전 패키지 라이브러리를 사용해 보려면 릴리스를 사용하도록 대체) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + + # 공식적으로 jammy, focus, Bullseye 및 기타 기존 시스템에 대한 적절한 지원이 완전히 제거되었습니다. + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod는 공식적으로 현재 시스템 지원을 중단했습니다($os_codename), Debian12/Ubuntu24 이상으로 업그레이드하세요.${gl_bai}" + return 1 + fi if [ -z "$os_codename" ]; then echo "시스템 코드명을 얻을 수 없으며 XanMod 소스를 구성할 수 없습니다." @@ -5717,7 +5723,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5727,7 +5733,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5787,7 +5793,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5877,7 +5883,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -6044,7 +6050,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정합니다── + # ──장면에 따라 매개변수를 설정하세요── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -7479,7 +7485,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -8090,7 +8096,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -8518,7 +8524,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -9518,7 +9524,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db case $use_db in 1) echo @@ -9614,7 +9620,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -10501,7 +10507,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10708,7 +10714,7 @@ EOF "${base_url}/models") if [[ -z "$models_json" ]]; then - echo "❌ 모델 목록을 얻을 수 없습니다" + echo "❌ 모델 목록을 가져올 수 없습니다" return 1 fi @@ -10776,7 +10782,7 @@ EOF done # 2. Base URL - read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url + read -erp "기본 URL을 입력하십시오(예: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ 기본 URL은 비워둘 수 없습니다." read -erp "기본 URL을 입력하세요:" base_url @@ -11477,7 +11483,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장 사항" + send_stats "OpenClaw API 공급업체 권장사항" clear echo "" @@ -11840,7 +11846,7 @@ PYTHON_EOF return 1 fi - # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 빠른 찾기를 위해 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -11874,7 +11880,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11942,7 +11948,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12183,7 +12189,7 @@ PYTHON_EOF echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안의 ID만 복사):" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" echo "--------------------------------------------------------" echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" @@ -12206,7 +12212,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12334,7 +12340,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12908,7 +12914,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end } @@ -12992,7 +12998,7 @@ if os.path.isdir(agents_root): fi local archive_path - archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요") + archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요.") [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } local tmp_unpack @@ -13016,7 +13022,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13073,7 +13079,7 @@ if os.path.isdir(agents_root): echo "백업 디렉터리:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "아직 백업 파일이 없습니다" + echo "아직 백업 파일이 없습니다." return 0 fi @@ -13136,7 +13142,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw 백업 파일 삭제" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13570,7 +13576,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없습니다(국내/제한된 네트워크로 의심됨).") fi if [ "$qmd_ok" = "true" ]; then @@ -13677,7 +13683,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13822,7 +13828,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다." + echo "✅ memory.qmd.command가 정확합니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -13930,7 +13936,7 @@ EOF OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" ;; *) - echo "❌ 알 수 없는 해결 방법:$scheme" + echo "❌ 알 수 없는 해결책:$scheme" return 1 ;; esac @@ -14014,7 +14020,7 @@ EOF openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 알 수 없는 해결 방법:$scheme" + echo "❌ 알 수 없는 해결책:$scheme" return 1 esac echo "✅ 메모리 체계 구성이 업데이트되었습니다." @@ -14097,7 +14103,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14186,7 +14192,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14299,7 +14305,7 @@ EOF if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." - read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 + read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. Enter를 눌러 수직력을 계속 사용합니다." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all else @@ -14681,7 +14687,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { @@ -14732,7 +14738,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "발견된 보안 취약점을 자동으로 해결하시겠습니까? (예/아니요):" fix_choice + read -e -p "발견된 보안 취약점을 자동으로 해결하려고 합니까? (예/아니요):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 자동 복구가 완료되었습니다.${gl_bai}" @@ -14790,7 +14796,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15140,7 +15146,7 @@ for idx,item in enumerate(bindings,1): send_stats "OpenClaw 다중 에이전트-새 라우팅 바인딩" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "에이전트 ID를 입력하세요:" agent_id + read -e -p "상담원 ID를 입력하세요:" agent_id read -e -p "경로 바인딩 값을 입력하세요(예: telegram:ops / discord:guild-a):" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 echo "에이전트를 바인딩합니다 [$agent_id] -> [$bind_value]" @@ -15158,7 +15164,7 @@ for idx,item in enumerate(bindings,1): send_stats "OpenClaw 다중 에이전트 - 경로 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm - read -e -p "에이전트 ID를 입력하세요:" agent_id + read -e -p "상담원 ID를 입력하세요:" agent_id read -e -p "제거할 경로 바인딩 값을 입력하세요." bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "취소됨: 매개변수는 비워둘 수 없습니다." && return 1 echo "에이전트를 제거합니다. [$agent_id] 경로 바인딩 [$bind_value]" @@ -15885,7 +15891,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15965,7 +15971,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16375,7 +16381,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16704,7 +16710,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -16731,7 +16737,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17398,7 +17404,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17979,7 +17985,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18320,7 +18326,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -18347,7 +18353,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -18919,7 +18925,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19892,7 +19898,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한합니다." + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19998,7 +20004,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20120,7 +20126,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20374,8 +20380,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -20418,7 +20424,7 @@ EOF case "$choice" in 1) - send_stats "1G 가상 메모리가 설정되었습니다" + send_stats "1G 가상 메모리가 설정되었습니다." add_swap 1024 ;; @@ -20602,7 +20608,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20670,7 +20676,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20765,7 +20771,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -21200,7 +21206,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." + send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" ;; *) break @@ -21396,7 +21402,7 @@ linux_file() { continue fi - # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -21517,7 +21523,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21558,8 +21564,8 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" - echo -e "귀하의${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21631,10 +21637,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21954,12 +21960,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 72ac44706..4d7bcf032 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1093,7 +1093,7 @@ iptables_panel() { echo "------------------------" iptables -L INPUT echo "" - echo "防火牆管理" + echo "防火墙管理" echo "------------------------" echo "1. 開放指定連接埠 2. 關閉指定連接埠" echo "3. 開放所有連接埠 4. 關閉所有連接埠" @@ -1464,7 +1464,7 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming公鑰資訊${gl_bai}" + echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" echo -e "${gl_huang}$yuming私鑰資訊${gl_bai}" @@ -1481,7 +1481,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1744,7 +1744,7 @@ cf_purge_cache() { if [ -f "$CONFIG_FILE" ]; then # 從設定檔讀取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 将 ZONE_IDS 转换为数组 + # 將 ZONE_IDS 轉換為數組 ZONE_IDS=($ZONE_IDS) else # 提示使用者是否清理快取 @@ -2264,7 +2264,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負載自動開盾腳本已新增" + echo "高负载自动开盾脚本已添加" else echo "自動開盾腳本已存在,無需添加" fi @@ -2882,8 +2882,8 @@ while true; do echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "5. 新增網域存取 6. 刪除網域存取" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -2913,7 +2913,7 @@ while true; do add_app_id clear - echo "$docker_name已經安裝完成" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo -e "Stream四層代理轉送工具$check_docker $update_status" echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模組,用於實現高效能的 傳輸層流量轉送和負載平衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3868,7 +3868,7 @@ ldnmp_web_status() { echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" echo "5. 查看訪問日誌 6. 查看錯誤日誌" - echo "7. 編輯全域配置 8. 編輯站點配置" + echo "7. 编辑全局配置 8. 编辑站点配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" echo "20. 刪除指定站點數據" @@ -3890,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3931,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -4169,7 +4169,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入 frpc.toml" + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4182,8 +4182,8 @@ EOF delete_forwarding_service() { send_stats "刪除frp內網服務" # 提示使用者輸入需要刪除的服務名稱 - read -e -p "請輸入需要刪除的服務名稱:" service_name - # 使用 sed 刪除該服務及其相關配置 + read -e -p "请输入需要删除的服务名称: " service_name + # 使用 sed 删除该服务及其相关配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "服務$service_name已成功從 frpc.toml 刪除" @@ -4785,7 +4785,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版本 sysctl.conf 殘留 +# 清理可能導致衝突的舊版 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4826,7 +4826,7 @@ root_use send_stats "優化DNS" while true; do clear - echo "優化DNS位址" + echo "优化DNS地址" echo "------------------------" echo "目前DNS地址" cat /etc/resolv.conf @@ -5138,7 +5138,7 @@ sshkey_panel() { echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" - echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5276,7 +5276,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" @@ -5310,7 +5310,7 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" + echo -e "${gl_hong}注意:${gl_bai}重装有风险失联,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" @@ -5530,7 +5530,7 @@ dd_xitong() { ;; 41) - send_stats "重裝windows11" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5611,9 +5611,15 @@ bbrv3() { fi # 相容官方已移除的老系統代號(回退使用 releases 嘗試舊包庫) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + + # 官方已徹底移除對 jammy, focal, bullseye 等舊系統的 apt 支持 + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod 官方已停止對目前系統($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" + return 1 + fi if [ -z "$os_codename" ]; then echo "無法取得系統代號,無法設定XanMod來源" @@ -5717,7 +5723,7 @@ bbrv3() { echo "BBR3參數寫入失敗,請檢查系統配置" return 1 } - echo "XanMod BBRv3内核处理完成。重啟後生效" + echo "XanMod BBRv3內核處理完成。重啟後生效" server_reboot } @@ -5877,7 +5883,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo核心已卸載。重啟後生效" + echo "elrepo内核已卸载。重啟後生效" send_stats "解除安裝紅帽內核" server_reboot @@ -6693,13 +6699,13 @@ create_backup() { local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # 提示使用者輸入備份目錄 - echo "建立備份範例:" + echo "创建备份示例:" echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" + echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input - # 如果用户没有输入目录,则使用默认目录 + # 如果使用者沒有輸入目錄,則使用預設目錄 if [ -z "$input" ]; then BACKUP_PATHS=( "/etc" # 配置文件和软件包配置 @@ -6732,7 +6738,7 @@ create_backup() { done # 建立備份 - echo "正在创建备份 $BACKUP_NAME..." + echo "正在建立備份$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6803,7 +6809,7 @@ linux_backup() { mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系统备份功能" + send_stats "系統備份功能" echo "系統備份功能" echo "------------------------" list_backups @@ -7004,7 +7010,7 @@ add_connection() { echo "建立新連接範例:" echo "- 連線名稱: my_server" echo "- IP位址: 192.168.1.100" - echo " - 用户名: root" + echo "- 使用者名稱: root" echo "- 連接埠: 22" echo "------------------------" read -e -p "請輸入連線名稱:" name @@ -7015,7 +7021,7 @@ add_connection() { fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "連線已儲存!" } @@ -7057,7 +7063,7 @@ use_connection() { echo "正在連接到$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 使用密鑰連接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" @@ -7091,7 +7097,7 @@ ssh_manager() { CONFIG_FILE="$HOME/.ssh_connections" KEY_DIR="$HOME/.ssh/ssh_manager_keys" - # 检查配置文件和密钥目录是否存在,如果不存在则创建 + # 檢查設定檔和金鑰目錄是否存在,如果不存在則創建 if [[ ! -f "$CONFIG_FILE" ]]; then touch "$CONFIG_FILE" fi @@ -7184,7 +7190,7 @@ mount_partition() { return 1 fi - echo "分區已成功掛載到$MOUNT_POINT" + echo "分割區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7328,7 +7334,7 @@ disk_manager() { # 顯示任務列表 list_tasks() { - echo "已保存的同步任务:" + echo "已儲存的同步任務:" echo "---------------------------------" awk -F'|' '{print NR " - " $1 " ( " $2 " -> " $3":"$4 " )"}' "$CONFIG_FILE" echo "---------------------------------" @@ -7349,7 +7355,7 @@ add_task() { read -e -p "請輸入遠端目錄:" remote_path while true; do - read -e -p "請輸入遠端使用者@IP:" remote + read -e -p "请输入远程用户@IP: " remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break @@ -7402,7 +7408,7 @@ delete_task() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "任務已刪除!" + echo "任务已删除!" } @@ -7869,7 +7875,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安裝ranger" + send_stats "安装ranger" ;; 13) clear @@ -7992,7 +7998,7 @@ linux_tools() { clear read -e -p "請輸入已安裝的工具名稱(wget curl sudo htop):" installname install $installname - send_stats "安裝指定軟體" + send_stats "安装指定软件" ;; 42) clear @@ -8449,7 +8455,7 @@ linux_docker() { echo -e "Docker磁碟區:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker網路:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8767,10 +8773,10 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京電信: 219.141.136.12" + echo "北京电信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" - echo "上海電信: 202.96.209.133" + echo "上海电信: 202.96.209.133" echo "上海聯通: 210.22.97.1" echo "上海移動: 211.136.112.200" echo "廣州電信: 58.60.188.222" @@ -9064,14 +9070,14 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建置站" + # send_stats "LDNMP建站" echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" - echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" - echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" + echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" @@ -9084,7 +9090,7 @@ linux_ldnmp() { echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}解除安裝LDNMP環境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主選單" echo -e "${gl_huang}------------------------${gl_bai}" @@ -9221,7 +9227,7 @@ linux_ldnmp() { echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "資料庫前綴: mac_" + echo "数据库前缀: mac_" echo "------------------------" echo "安裝成功後登入後台位址" echo "https://$yuming/vip.php" @@ -10137,7 +10143,7 @@ moltbot_menu() { echo "3. 停止" echo "--------------------" echo "4. 狀態日誌查看" - echo "5. 換模型" + echo "5. 换模型" echo "6. API管理" echo "7. 機器人連線對接" echo "8. 插件管理(安裝/刪除)" @@ -10766,7 +10772,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10805,9 +10811,9 @@ EOF if [[ -n "$available_models" ]]; then model_count=$(echo "$available_models" | wc -l) - echo "✅ 發現$model_count個可用模型:" + echo "✅ 發現$model_count 个可用模型:" echo "--------------------------------" - # 全部顯示,附序號 + # 全部显示,带序号 i=1 model_list=() while read -r model; do @@ -10825,7 +10831,7 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) - echo "🎯 使用第一個模型:$default_model" + echo "🎯 使用第一个模型: $default_model" elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then default_model="${model_list[$((input_model-1))]}" echo "🎯 已選擇模型:$default_model" @@ -10849,7 +10855,7 @@ EOF if [[ "$confirm" =~ ^[Yy]$ ]]; then add-all-models-from-provider "$provider_name" "$base_url" "$api_key" add_result=$? - finish_msg="✅ 完成!所有$model_count個模型已載入" + finish_msg="✅ 完成!所有$model_count 个模型已加载" else add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" add_result=$? @@ -11116,7 +11122,7 @@ if err is not None: raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 回傳結構不可識別') + print(f'❌ {target}: /models 返回结构不可识别') raise SystemExit(4) remote_ids = [] @@ -12678,7 +12684,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13401,7 +13407,7 @@ EOF fi memory_dir="$workspace/memory" if [ ! -d "$memory_dir" ]; then - echo "🔧 [$agent_id] 记忆目录不存在,已自动创建: $memory_dir" + echo "🔧 [$agent_id] 記憶目錄不存在,已自動建立:$memory_dir" mkdir -p "$memory_dir" fi return 0 @@ -13771,7 +13777,7 @@ PY else echo "可能流量/磁碟佔用: 視實際情況而定" fi - echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step case "$confirm_step" in @@ -13796,7 +13802,7 @@ PY } openclaw_memory_auto_setup_qmd() { - echo "🔍 检测 QMD 环境" + echo "🔍 檢測 QMD 環境" openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then @@ -13822,7 +13828,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正确" + echo "✅ memory.qmd.command 已正確" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -14288,7 +14294,7 @@ EOF case "$memory_choice" in 1) echo "即將更新記憶索引。" - read -e -p "第一次確認:輸入 yes 繼續:" confirm_step1 + read -e -p "第一次确认:输入 yes 继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消。" break_end @@ -14312,7 +14318,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14401,7 +14407,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ 未偵測到 openclaw,無法重新啟動 OpenClaw Gateway。" + echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" return 1 fi echo "正在重啟 OpenClaw Gateway..." @@ -14597,7 +14603,7 @@ print(json.dumps(data, indent=2)) echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" echo "Profile (預設): ${current_profile:-(unset)}" echo "Exec 限制: ${current_sec:-(unset)}" - echo " 审批提示: ${current_ask:-(unset)}" + echo "審核提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" @@ -14640,7 +14646,7 @@ try: print("提示策略 (Ask):" + str(d.get("ask", "(unset)"))) print("無UI兜底 (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print("(設定檔解析失敗)") + print(" (配置文件解析失败)") ' else echo "(未配置,強制使用系統內建安全兜底策略)" @@ -14704,7 +14710,7 @@ except Exception: } openclaw_permission_restore_official_defaults() { - send_stats "OpenClaw權限-恢復官方默認" + send_stats "OpenClaw权限-恢复官方默认" openclaw_permission_require_openclaw || return 1 echo "清理應用層強制覆蓋..." @@ -14728,7 +14734,7 @@ except Exception: openclaw_permission_run_audit() { echo "=======================================" - echo "运行 OpenClaw 官方安全审计与体检..." + echo "運行 OpenClaw 官方安全審計與體檢..." echo "=======================================" openclaw security audit echo "---------------------------------------" @@ -14815,19 +14821,19 @@ except Exception as e: echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" - echo -e "${gl_kjlan}6.${gl_bai} 管理 Exec 命令白名单" + echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" perm_choice case "$perm_choice" in 1) - echo "准备应用:标准安全模式" + echo "準備應用:標準安全模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_standard; else echo "已取消"; fi break_end ;; 2) - echo "准备应用:开发增强模式" + echo "準備應用:開發增強模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end @@ -15235,7 +15241,7 @@ print("✅ 多智能體健康檢查完成") ' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" echo "" echo "運行安全審計..." - openclaw security audit 2>/dev/null || echo "⚠️ 安全審計命令不可用" + openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" } @@ -15246,7 +15252,7 @@ print("✅ 多智能體健康檢查完成") [ -z "$agent_id" ] && { echo "ID 不能為空"; return 1; } echo "修改選項(留空跳過):" read -e -p "新名稱:" new_name - read -e -p "新 Emoji:" new_emoji + read -e -p " 新 Emoji: " new_emoji local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" @@ -15316,7 +15322,7 @@ openclaw_backup_restore_menu() { echo "---------------------------------------" echo "1. 備份記憶全量" echo "2. 還原記憶全量" - echo "3. 备份 OpenClaw 项目(默认安全模式)" + echo "3. 備份 OpenClaw 專案(預設安全模式)" echo "4. 還原 OpenClaw 專案(進階/高風險)" echo "5. 刪除備份文件" echo "0. 返回上一級" @@ -15418,7 +15424,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15604,7 +15610,7 @@ while true; do echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}21. ${color21}VScode网页版 ${gl_kjlan}22. ${color22}UptimeKuma監控工具" + echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" @@ -15612,7 +15618,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合网站" + echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" @@ -15675,7 +15681,7 @@ while true; do # 這裡假設 appno.txt 中記錄的是 base_name (即檔名) if echo "$app_numbers" | grep -q "^$base_name$"; then # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) - echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text [已安装]${gl_bai}" + echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" else # 如果未安裝:正常顯示 echo -e "${gl_kjlan}$base_name${gl_bai} - $app_text" @@ -16524,7 +16530,7 @@ while true; do } - local docker_describe="Memos是一款輕量、自架的備忘錄中心" + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -17089,7 +17095,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼皆為: admin" + echo "初始使用者名稱密碼均為: admin" } docker_app_update() { @@ -18403,7 +18409,7 @@ while true; do } - local docker_describe="Matrix是一個去中心化的聊天協議" + local docker_describe="Matrix是一个去中心化的聊天协议" local docker_url="官網介紹: https://matrix.org/" local docker_use="" local docker_passwd="" @@ -19434,7 +19440,7 @@ linux_work() { send_stats "後台工作區" echo -e "後台工作區" echo -e "系統將為你提供可以後台常駐運作的工作區,你可以用來執行長時間的任務" - echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" + echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" echo "目前已存在的工作區列表" @@ -20126,7 +20132,7 @@ linux_Settings() { echo -e "${gl_kjlan}13. ${gl_bai}使用者管理${gl_kjlan}14. ${gl_bai}使用者/密碼產生器" echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設定BBR3加速" echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主機名" - echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新來源${gl_kjlan}20. ${gl_bai}定時任務管理" + echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" @@ -20164,7 +20170,7 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快捷键已设置" + echo "快速鍵已設定" send_stats "腳本快捷鍵已設定" break_end linux_Settings @@ -20300,7 +20306,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH埠修改" + send_stats "退出SSH連接埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20784,7 +20790,7 @@ EOF break # 跳出 ;; esac - send_stats "新增定時任務" + send_stats "添加定时任务" ;; 2) read -e -p "請輸入需要刪除任務的關鍵字:" kquest @@ -20927,7 +20933,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21107,7 +21113,7 @@ EOF echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設定虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 @@ -21351,11 +21357,11 @@ linux_file() { 21) # 压缩文件/目录 read -e -p "請輸入要壓縮的檔案/目錄名稱:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "壓縮失敗" - send_stats "壓縮檔案/目錄" + tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "压缩失败" + send_stats "压缩文件/目录" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21514,7 +21520,7 @@ while true; do echo -e "${gl_kjlan}1. ${gl_bai}新增伺服器${gl_kjlan}2. ${gl_bai}刪除伺服器${gl_kjlan}3. ${gl_bai}編輯伺服器" echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}批量执行任务${gl_bai}" + echo -e "${gl_kjlan}批次執行任務${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" @@ -21525,8 +21531,8 @@ while true; do case $sub_choice in 1) - send_stats "新增叢集伺服器" - read -e -p "伺服器名稱:" server_name + send_stats "添加集群服务器" + read -e -p "服务器名称: " server_name read -e -p "伺服器IP:" server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} @@ -21729,7 +21735,7 @@ while true; do echo "------------------------" curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - # 只下載前5行取得版本號,避免下載整個腳本 + # 只下载前5行获取版本号,避免下载整个脚本 local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) if [ -z "$sh_v_new" ]; then @@ -21783,7 +21789,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" @@ -21791,7 +21797,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21938,7 +21944,7 @@ echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "软件重启 k restart sshd | k 重启 sshd " +echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" @@ -22212,8 +22218,8 @@ else shift case "$1" in "" ) - # sshkey → 互動選單 - send_stats "SSHKey 互動選單" + # sshkey → 交互菜单 + send_stats "SSHKey 交互菜单" sshkey_panel ;; github ) @@ -22233,7 +22239,7 @@ else echo "錯誤:未知參數 '$1'" echo "用法:" echo "k sshkey 進入互動選單" - echo "k sshkey \"\" 直接導入 SSH 公鑰" + echo " k sshkey \"\" 直接导入 SSH 公钥" echo "k sshkey 從 URL 匯入 SSH 公鑰" echo "k sshkey github 從 GitHub 匯入 SSH 公鑰" ;; From 3f8bc3aac65a495094f9e69fb06c528c88f45eb5 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 11 May 2026 10:25:56 +0800 Subject: [PATCH 1169/1285] feat: add Ubuntu 26.04 reinstall option --- cn/kejilion.sh | 23 +++++++++++------------ kejilion.sh | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b3949c6d6..994e6d129 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5318,8 +5318,8 @@ dd_xitong() { echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "重装ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "重装ubuntu 26.04" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "重装ubuntu 24.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "重装ubuntu 22.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "重装ubuntu 20.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "重装rockylinux10" dd_xitong_3 diff --git a/kejilion.sh b/kejilion.sh index 069d1714f..5b651163d 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5318,8 +5318,8 @@ dd_xitong() { echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "重装ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "重装ubuntu 26.04" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "重装ubuntu 22.04" + send_stats "重装ubuntu 24.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "重装ubuntu 20.04" + send_stats "重装ubuntu 22.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "重装ubuntu 18.04" + send_stats "重装ubuntu 20.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "重装rockylinux10" dd_xitong_3 From 5f41873b60b195051395de4916d9fc935e786c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 May 2026 10:31:15 +0800 Subject: [PATCH 1170/1285] Add one-click system reinstall feature for Ubuntu 26.04 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增Ubuntu26.04安装的一键重装系统功能。 --- kejilion_sh_log.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 6934e8943..4200e757f 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1510,4 +1510,5 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 ------------------------ 2026-05-02 v4.5.0 系统工具BBRv3更新linux-xanmod官方部署方法。 +系统工具一键重装系统功能新增Ubuntu26.04安装。 From 8dee090abfb6c64ba5b4904c9c3b50fe1222a1d4 Mon Sep 17 00:00:00 2001 From: Kejilion Assistant Date: Mon, 11 May 2026 10:38:12 +0800 Subject: [PATCH 1171/1285] feat: update Fedora reinstall versions --- cn/kejilion.sh | 10 +++++----- kejilion.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 994e6d129..e1f290431 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5324,7 +5324,7 @@ dd_xitong() { echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" @@ -5449,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "重装fedora44" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "重装fedora41" + send_stats "重装fedora43" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; diff --git a/kejilion.sh b/kejilion.sh index 5b651163d..c48516021 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5324,7 +5324,7 @@ dd_xitong() { echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" @@ -5449,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "重装fedora42" + send_stats "重装fedora44" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "重装fedora41" + send_stats "重装fedora43" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; From 969cc7aeafb5a9233faf2115ce3b88f00ff1f1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Mon, 11 May 2026 10:40:26 +0800 Subject: [PATCH 1172/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4200e757f..1b7d05b11 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1510,5 +1510,5 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 ------------------------ 2026-05-02 v4.5.0 系统工具BBRv3更新linux-xanmod官方部署方法。 -系统工具一键重装系统功能新增Ubuntu26.04安装。 +系统工具一键重装系统功能新增Ubuntu26.04安装和Fedora44/43版本安装。 From 5510fa8f439c77838e0dcae42f66547994843134 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 17 May 2026 06:09:02 +0000 Subject: [PATCH 1173/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-05-17=2006:09:02?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 151 +++++++++-------- jp/kejilion.sh | 251 ++++++++++++++-------------- kr/kejilion.sh | 195 +++++++++++----------- tw/kejilion.sh | 431 ++++++++++++++++++++++++------------------------- 4 files changed, 512 insertions(+), 516 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 5b715571e..ee329d712 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -2310,7 +2310,7 @@ check_ldnmp_mode() { if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="High performance mode" else - mode_info="Standard mode" + mode_info=" 标准模式" fi @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3221,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -4392,7 +4392,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4489,7 +4489,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -5094,7 +5094,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5318,13 +5318,13 @@ dd_xitong() { echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "Reinstall ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "Reinstall ubuntu 26.04" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "Reinstall ubuntu 22.04" + send_stats "Reinstall ubuntu 24.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "Reinstall ubuntu 20.04" + send_stats "Reinstall ubuntu 22.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "Reinstall ubuntu 18.04" + send_stats "Reinstall ubuntu 20.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "Reinstall rockylinux10" dd_xitong_3 @@ -5450,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "Reinstall fedora42" + send_stats "Reinstall fedora44" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "Reinstall fedora41" + send_stats "Reinstall fedora43" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; @@ -5530,7 +5529,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6298,7 +6297,7 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}Applied${applied}Item parameter ${skipped:+, skip${skipped}Item unsupported parameter}${gl_bai}" + echo -e "${gl_lv}Applied${applied}Item parameter ${skipped:+, skip${skipped} 项不支持的参数}${gl_bai}" # ── Transparent large page ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then @@ -6392,7 +6391,7 @@ Kernel_optimize() { echo "Provides a variety of system parameter tuning modes, and users can choose to switch according to their own usage scenarios." echo -e "${gl_huang}hint:${gl_bai}Please use it with caution in production environment!" echo -e "--------------------" - echo -e "1. 高性能优化模式: 最大化系统性能,激进的内存和网络参数。" + echo -e "1. High-performance optimization mode: Maximize system performance, aggressive memory and network parameters." echo -e "2. Balanced optimization mode: strikes a balance between performance and resource consumption, suitable for daily use." echo -e "3. Website optimization mode: Optimized for website servers, ultra-high concurrent connection queue." echo -e "4. Live broadcast optimization mode: For live streaming optimization, the UDP buffer is enlarged to reduce delays." @@ -6693,9 +6692,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6737,7 +6736,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7306,7 +7305,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7485,14 +7484,14 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi } -# 创建定时任务 +# Create a scheduled task schedule_task() { send_stats "Add synchronization scheduled tasks" @@ -8337,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -10568,8 +10567,8 @@ PY start_bot() { - echo "Starting OpenClaw..." - send_stats "Starting OpenClaw..." + echo "Start OpenClaw..." + send_stats "Start OpenClaw..." start_gateway break_end } @@ -13079,7 +13078,7 @@ if os.path.isdir(agents_root): echo "Backup directory:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "No backup files yet" + echo "No backup file yet" return 0 fi @@ -13871,7 +13870,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ The model file already exists:$model_path" + echo "✅ Model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14192,7 +14191,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count + read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14569,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: Write the file directly + # Fallback: write file directly echo "$json_payload" > "$approvals_file" } @@ -15161,7 +15160,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw multi-agent - remove route binding" + send_stats "OpenClaw multi-agent - remove routing binding" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "Please enter the agent ID:" agent_id @@ -15600,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -16075,7 +16074,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -16129,7 +16128,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16160,7 +16159,7 @@ while true; do } local docker_describe="ZenTao is a universal project management software" - local docker_url="官网介绍: https://www.zentao.net/" + local docker_url="Official website introduction: https://www.zentao.net/" local docker_use="echo \"Initial username: admin\"" local docker_passwd="echo \"Initial password: 123456\"" local app_size="2" @@ -16200,7 +16199,7 @@ while true; do local app_id="13" local app_name="cloudreve network disk" - local app_text="cloudreve是一个支持多家云存储的网盘系统" + local app_text="cloudreve is a network disk system that supports multiple cloud storages" local app_url="Video introduction: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" @@ -16227,7 +16226,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16302,7 +16301,7 @@ while true; do } - local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -17113,7 +17112,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17340,7 +17339,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17392,7 +17391,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17433,7 +17432,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17496,7 +17495,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17710,7 +17709,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -17824,7 +17823,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18045,7 +18044,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18095,7 +18094,7 @@ while true; do cd "$(ls -dt */ | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18231,7 +18230,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18294,7 +18293,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18458,7 +18457,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18596,7 +18595,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18650,7 +18649,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18883,7 +18882,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18954,7 +18953,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19023,7 +19022,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19164,7 +19163,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19234,7 +19233,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19378,7 +19377,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -19451,7 +19450,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19849,7 +19848,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -20194,7 +20193,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21523,7 +21522,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21640,7 +21639,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21921,7 +21920,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 30d5095a8..ac3371b0d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -260,7 +260,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -806,7 +806,7 @@ docker_ipv6_off() { # 元の構成と新しい構成を比較する if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}現在IPv6アクセスは停止中です${gl_bai}" + echo -e "${gl_huang}IPv6アクセスは現在停止中です${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -872,7 +872,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1750,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1991,7 +1991,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Brotliを閉じる: コメントを追加 + # ブロトリを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2215,7 +2215,7 @@ web_security() { 21) send_stats "クラウドフレアモード" - echo "cf バックエンドの右上隅にある私のプロフィールに移動し、左側の API トークンを選択して、グローバル API キーを取得します。" + echo "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択し、グローバル API キーを取得します。" echo "https://dash.cloudflare.com/login" read -e -p "CF の口座番号を入力してください:" cfuser read -e -p "CF のグローバル API キーを入力します。" cftoken @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4153,7 +4153,7 @@ add_forwarding_service() { read -e -p "サービス名を入力してください:" service_name read -e -p "転送タイプ (tcp/udp) を入力してください [デフォルトで tcp を入力する]:" service_type local service_type=${service_type:-tcp} - read -e -p "イントラネット IP を入力してください [Enter キーを押した場合のデフォルトは 127.0.0.1]:" local_ip + read -e -p "イントラネット IP を入力してください [Enter キーを押すときのデフォルトは 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "イントラネット ポートを入力してください:" local_port read -e -p "外部ネットワーク ポートを入力してください:" remote_port @@ -4195,7 +4195,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーを印刷します + # ヘッダーの印刷 printf "%-20s %-25s %-30s %-10s\n" "サービス名" "イントラネットアドレス" "外部ネットワークアドレス" "プロトコル" awk ' @@ -4310,7 +4310,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5045,7 +5045,7 @@ fetch_remote_ssh_keys() { # コンテンツが有効かどうかを確認する if [[ ! -s "${temp_file}" ]]; then - echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります。" >&2 + echo "エラー: ダウンロードされたファイルは空であり、URL には公開キーが含まれていない可能性があります" >&2 rm -f "${temp_file}" return 1 fi @@ -5318,13 +5318,13 @@ dd_xitong() { echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "ubuntu 24.04を再インストールします" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "ubuntu 26.04を再インストールします" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "ubuntu 22.04を再インストールします" + send_stats "ubuntu 24.04を再インストールします" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "ubuntu 20.04を再インストールします" + send_stats "ubuntu 22.04を再インストールします" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "ubuntu 18.04を再インストールします" + send_stats "ubuntu 20.04を再インストールします" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "Rockylinux10を再インストールする" dd_xitong_3 @@ -5450,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "fedora42を再インストールする" + send_stats "fedora44を再インストールする" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "fedora41を再インストールする" + send_stats "fedora43を再インストールする" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; @@ -5762,7 +5761,7 @@ bbrv3() { clear local kernel_version=$(uname -r) echo "xanmod の BBRv3 カーネルがインストールされている" - echo "現在のカーネルのバージョン:$kernel_version" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5860,7 +5859,7 @@ elrepo() { clear kernel_version=$(uname -r) echo "elrepo カーネルがインストールされています" - echo "現在のカーネルのバージョン:$kernel_version" + echo "現在のカーネル バージョン:$kernel_version" echo "" echo "カーネル管理" @@ -5901,7 +5900,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6014,7 +6013,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6041,7 +6040,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6324,7 +6323,7 @@ LIMITS sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name}最適化が完了しました!設定は永続化されています${CONF}${gl_bai}" + echo -e "${gl_lv}${mode_name}最適化が完了しました!構成は永続化されています${CONF}${gl_bai}" echo -e "${gl_lv}メモリ:${MEM_MB}MB |輻輳アルゴリズム:${CC}|列:${QDISC}${gl_bai}" } @@ -6379,7 +6378,7 @@ Kernel_optimize() { while true; do clear send_stats "Linuxカーネルチューニング管理" - local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) + local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" if [ -n "$current_mode" ]; then @@ -6825,7 +6824,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "Enter キーを押して続行します..." done } @@ -7173,7 +7172,7 @@ mount_partition() { return 1 fi - # ファイルシステムのタイプを取得する + # ファイルシステムの種類を取得する FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then echo "ファイル システム タイプを取得できません!" @@ -7306,7 +7305,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7325,7 +7324,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "Enter キーを押して続行します..." done } @@ -7485,7 +7484,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストはアクセス可能ですか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7584,7 +7583,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "Enter キーを押して続行します..." done } @@ -7646,7 +7645,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7702,7 +7701,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7766,7 +7765,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7884,7 +7883,7 @@ linux_tools() { clear ncdu cd ~ - send_stats "ncduをインストールする" + send_stats "ncdu をインストールする" ;; 14) clear @@ -8138,7 +8137,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8158,7 +8157,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包量:$path" + echo "梱包体積:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8223,7 +8222,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8337,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8411,7 +8410,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8455,7 +8454,7 @@ linux_docker() { echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -9083,7 +9082,7 @@ linux_ldnmp() { echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" - echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" + echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" echo -e "${gl_huang}29. ${gl_bai}ストリーム 4 層プロキシ転送${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイト全体のデータをバックアップする" @@ -10344,7 +10343,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10443,7 +10442,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10568,8 +10567,8 @@ PY start_bot() { - echo "OpenClaw を開始しています..." - send_stats "OpenClaw を開始しています..." + echo "OpenClaw を開始します..." + send_stats "OpenClaw を開始します..." start_gateway break_end } @@ -11122,7 +11121,7 @@ if err is not None: raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返された構造体は認識されません') + print(f'❌ {target}: /models 返された構造は認識されません') raise SystemExit(4) remote_ids = [] @@ -11217,7 +11216,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行が完了しました" + echo "✅ 同期実行完了" start_gateway ;; 2) @@ -11264,7 +11263,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "セットアップする API タイプを選択してください:" + echo "設定したい API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -11846,7 +11845,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12310,7 +12309,7 @@ PYTHON_EOF install_skill() { - send_stats "スキルマネジメント" + send_stats "スキル管理" while true; do clear echo "========================================" @@ -12331,7 +12330,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12373,7 +12372,7 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name]がユーザーディレクトリにインストールされます。" + echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" @@ -12663,7 +12662,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5.WeChatロボットのドッキング" + echo "5. WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12684,7 +12683,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12932,7 +12931,7 @@ if os.path.isdir(agents_root): echo "バックアップモード:" echo "1. セーフ モード (デフォルト、推奨): ワークスペース + openclaw.json + 拡張機能/スキル/プロンプト/ツール (存在する場合)" - echo "2. 完全モード (より多くの状態が含まれ、機密リスクが高くなります)" + echo "2. 完全モード (より多くの状態が含まれ、機密性のリスクが高くなります)" read -e -p "バックアップ モードを選択してください (デフォルト 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -13079,7 +13078,7 @@ if os.path.isdir(agents_root): echo "バックアップディレクトリ:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "バックアップファイルはまだありません" + echo "まだバックアップファイルがありません" return 0 fi @@ -13730,7 +13729,7 @@ PY echo "✅ 環境準備完了" echo "スキーム: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then - echo "モード: 構成の書き込みのみ (インストールされない/ダウンロードされない)" + echo "モード: 設定の書き込みのみ (インストールされない/ダウンロードされない)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "インデックス: 実行されました" @@ -14028,7 +14027,7 @@ EOF } openclaw_memory_offer_restart() { - echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14103,7 +14102,7 @@ EOF echo "" echo "QMD: qmd コマンドに依存する軽量インデックス (ネットワーク制約に適しています)" echo "ローカル: 埋め込みモデル ファイルに依存するローカル ベクトル取得" - echo "自動: 自動推奨 (可用性 + ネットワーク検出に基づく)" + echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" echo "1. QMD の切り替え (自動展開/既にインストールされている場合はスキップ)" echo "2. ローカルに切り替えます (自動展開/既にインストールされている場合はスキップ)" @@ -14286,7 +14285,7 @@ EOF echo "2. メモリファイルを表示する" echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" - echo "5. 検索テスト (インデックスが機能していることを確認します)" + echo "5. 検索テスト (インデックスが機能していることを確認する)" echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" @@ -14669,7 +14668,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -15089,12 +15088,12 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm read -e -p "新しいエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 read -e -p "ワークスペースのパスを入力してください (デフォルトは ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ エージェントが正常に作成されました:$agent_id" @@ -15116,7 +15115,7 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id confirm read -e -p "削除するエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 echo "⚠️ エージェントを削除すると、その作業ディレクトリ、ルート バインディング、およびセッション ルーティングに影響する可能性があります。" read -e -p "「DELETE」と入力して削除を確認します${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "キャンセル"; return 1; } @@ -15150,7 +15149,7 @@ for idx,item in enumerate(bindings,1): read -e -p "ルート バインディング値 (telegram:ops / discord:guild-a など) を入力してください。" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントをバインドします [$agent_id] -> [$bind_value]" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に追加されました" @@ -15168,7 +15167,7 @@ for idx,item in enumerate(bindings,1): read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に削除されました" @@ -15376,7 +15375,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 構成ファイルを編集する" + send_stats "OpenClaw 設定ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15451,7 +15450,7 @@ openclaw_backup_restore_menu() { echo "https://${yuming}/#token=$token" echo "まず URL にアクセスしてデバイス ID をトリガーし、Enter キーを押してペアリングを続行します。" read - echo -e "${gl_kjlan}デバイスリストを読み込んでいます...${gl_bai}" + echo -e "${gl_kjlan}デバイスリストをロード中...${gl_bai}" # ドメイン名を allowedOrigins に自動的に追加する config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then @@ -15600,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15630,7 +15629,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" @@ -15648,7 +15647,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -16737,7 +16736,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、分割マージ、変換、再編成、画像の追加、回転、圧縮など、PDF ファイルに対してさまざまな操作を実行できます。" + local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、PDF ファイルに対して分割マージ、変換、再編成、画像の追加、回転、圧縮などのさまざまな操作を実行できます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17166,7 +17165,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -17737,7 +17736,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -17985,7 +17984,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18200,7 +18199,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18294,7 +18293,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -19259,7 +19258,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19779,7 +19778,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19789,7 +19788,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19801,7 +19800,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19827,7 +19826,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記ログ職業】" + echo "【日記帳の職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -19852,7 +19851,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19862,7 +19861,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19877,7 +19876,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19965,7 +19964,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." } @@ -19980,7 +19979,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." } edit_file() { @@ -19996,7 +19995,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "Enter キーを押して続行します..." } while true; do @@ -20009,7 +20008,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数 (ソース) をリロードします。" + echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20588,7 +20587,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -20603,7 +20602,7 @@ EOF echo "3. 東京、日本時間 4. ソウル、韓国時間" echo "5. シンガポール時間 6. インド、コルカタ時間" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9.タイ・バンコク時間" + echo "9. タイ・バンコク時間" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -21375,7 +21374,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21395,7 +21394,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21518,10 +21517,10 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21556,7 +21555,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -21637,10 +21636,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21888,7 +21887,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -21921,14 +21920,14 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21937,7 +21936,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21956,7 +21955,7 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" @@ -22161,7 +22160,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 117b0bcca..32a13edb2 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -123,7 +123,7 @@ CheckFirstRun_false() { # 사용자에게 약관에 동의하라는 메시지를 표시합니다. UserLicenseAgreement() { clear - echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다.${gl_bai}" + echo -e "${gl_kjlan}기술 사자 스크립트 도구 상자에 오신 것을 환영합니다${gl_bai}" echo "스크립트를 처음 사용하는 경우 사용자 라이센스 계약을 읽고 동의하십시오." echo "사용자 라이센스 계약: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -508,7 +508,7 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1543,7 +1543,7 @@ certs_status() { echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" - echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하시기 바랍니다" + echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5318,13 +5318,13 @@ dd_xitong() { echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "우분투 24.04 다시 설치" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "우분투 26.04 다시 설치" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "우분투 22.04 다시 설치" + send_stats "우분투 24.04 다시 설치" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "우분투 20.04 다시 설치" + send_stats "우분투 22.04 다시 설치" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "우분투 18.04 다시 설치" + send_stats "우분투 20.04 다시 설치" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "rockylinux10 재설치" dd_xitong_3 @@ -5450,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "fedora42 재설치" + send_stats "fedora44 재설치" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "fedora41 재설치" + send_stats "fedora43 재설치" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; @@ -5793,7 +5792,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6637,7 +6636,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7485,7 +7484,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -8337,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8370,7 +8369,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8524,7 +8523,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8885,7 +8884,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9524,7 +9523,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db case $use_db in 1) echo @@ -9620,7 +9619,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -10507,7 +10506,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10568,8 +10567,8 @@ PY start_bot() { - echo "OpenClaw를 시작하는 중..." - send_stats "OpenClaw를 시작하는 중..." + echo "OpenClaw를 시작하세요..." + send_stats "OpenClaw를 시작하세요..." start_gateway break_end } @@ -10782,7 +10781,7 @@ EOF done # 2. Base URL - read -erp "기본 URL을 입력하십시오(예: https://api.xxx.com/v1):" base_url + read -erp "기본 URL을 입력하세요(예: https://api.xxx.com/v1):" base_url while [[ -z "$base_url" ]]; do echo "❌ 기본 URL은 비워둘 수 없습니다." read -erp "기본 URL을 입력하세요:" base_url @@ -11041,7 +11040,7 @@ if not isinstance(providers, dict) or not providers: provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 제공자: {target}을(를) 찾을 수 없습니다') + print(f'❌ 未找到 provider: {target}') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11483,7 +11482,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장사항" + send_stats "OpenClaw API 공급업체 권장 사항" clear echo "" @@ -11880,7 +11879,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11948,7 +11947,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12105,7 +12104,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -12253,7 +12252,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12264,7 +12263,7 @@ PYTHON_EOF continue fi - echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요.$plugin_full" + echo "📥 本地未发现,尝试下载安装: $plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -12320,7 +12319,7 @@ PYTHON_EOF openclaw skills list echo "----------------------------------------" - # 추천 실기 목록 출력 + # 输出推荐的实用技能列表 echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" echo "github # GitHub 문제/PR/CI 관리(gh CLI)" echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." @@ -12686,7 +12685,7 @@ openclaw_json_get_bool() { 3) read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" break_end ;; @@ -12998,7 +12997,7 @@ if os.path.isdir(agents_root): fi local archive_path - archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요.") + archive_path=$(openclaw_read_import_path "OpenClaw 프로젝트 백업 패키지 경로를 입력해주세요") [ -z "$archive_path" ] && { echo "❌ 백업 경로가 입력되지 않았습니다."; break_end; return 1; } local tmp_unpack @@ -13022,7 +13021,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13079,7 +13078,7 @@ if os.path.isdir(agents_root): echo "백업 디렉터리:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "아직 백업 파일이 없습니다." + echo "아직 백업 파일이 없습니다" return 0 fi @@ -13576,7 +13575,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없습니다(국내/제한된 네트워크로 의심됨).") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") fi if [ "$qmd_ok" = "true" ]; then @@ -13665,7 +13664,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." return 0 } @@ -13683,7 +13682,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13777,7 +13776,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -13828,7 +13827,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command가 정확합니다." fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -13936,7 +13935,7 @@ EOF OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 알 수 없는 해결 방법:$scheme" return 1 ;; esac @@ -14020,7 +14019,7 @@ EOF openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 알 수 없는 해결책:$scheme" + echo "❌ 알 수 없는 해결 방법:$scheme" return 1 esac echo "✅ 메모리 체계 구성이 업데이트되었습니다." @@ -14074,7 +14073,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14192,7 +14191,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count + read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14202,7 +14201,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 숫자를 입력하세요." + echo "❌ 유효한 번호를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14305,7 +14304,7 @@ EOF if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." - read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. Enter를 눌러 수직력을 계속 사용합니다." confirm_step3 + read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all else @@ -14318,7 +14317,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -14569,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일을 직접 작성 + # 대체: 파일 직접 쓰기 echo "$json_payload" > "$approvals_file" } @@ -14721,7 +14720,7 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "호스트 차단 구성을 정리합니다..." - # CLI를 통해 승인 구성을 지우는 데 우선순위를 두고 파일을 직접 삭제하는 방법으로 대체합니다. + # CLI를 통해 승인 구성을 지우는 데 우선 순위를 두고 파일을 직접 삭제하는 것으로 대체합니다. if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then true else @@ -15277,7 +15276,7 @@ print("✅멀티에이전트 헬스체크 완료") while true; do clear echo "=======================================" - echo "OpenClaw 다중 에이전트 관리" + echo "OpenClaw 多智能体管理" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" @@ -15600,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15612,7 +15611,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15871,7 +15870,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16003,7 +16002,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16381,7 +16380,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16571,7 +16570,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16737,7 +16736,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17404,7 +17403,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17737,7 +17736,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18294,7 +18293,7 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -18925,7 +18924,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19849,7 +19848,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -19992,7 +19991,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드 중" + send_stats "환경 변수 다시 로드" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -20136,7 +20135,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20608,7 +20607,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20676,7 +20675,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20771,7 +20770,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -20887,7 +20886,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -21206,7 +21205,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." ;; *) break @@ -21402,7 +21401,7 @@ linux_file() { continue fi - # 디렉토리를 재귀적으로 복사하려면 -r 옵션을 사용하십시오. + # 디렉토리를 반복적으로 복사하려면 -r 옵션을 사용하십시오. cp -r "$src_path" "$dest_path" && echo "복사된 파일 또는 디렉터리$dest_path" || echo "파일 또는 디렉터리를 복사하지 못했습니다." send_stats "파일 또는 디렉터리 복사" ;; @@ -21637,10 +21636,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21921,7 +21920,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21955,7 +21954,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" @@ -21965,7 +21964,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 4d7bcf032..d3c9b3a1e 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -124,7 +124,7 @@ CheckFirstRun_false() { UserLicenseAgreement() { clear echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" - echo "首次使用腳本,請先閱讀並同意使用者授權協議。" + echo "首次使用脚本,请先阅读并同意用户许可协议。" echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "是否同意以上條款? (y/n):" user_input @@ -334,7 +334,7 @@ status() { if [ $? -eq 0 ]; then echo "$1服務狀態已顯示。" else - echo "錯誤:無法顯示$1服務狀態。" + echo "錯誤:無法顯示$1 服务状态。" fi } @@ -634,7 +634,7 @@ while true; do case $sub_choice in 1) send_stats "拉取鏡像" - read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames + read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames for name in $imagenames; do echo -e "${gl_kjlan}正在取得鏡像:$name${gl_bai}" docker pull $name @@ -754,12 +754,12 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 檢查設定檔是否存在,如果不存在則建立檔案並寫入預設設定 + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq處理設定檔的更新 + # 使用jq处理配置文件的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # 檢查目前配置是否已經有 ipv6 設定 @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}設定檔不存在${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi @@ -849,7 +849,7 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "請提供至少一個連接埠號" + echo "请提供至少一个端口号" return 1 fi @@ -924,10 +924,10 @@ allow_ip() { install iptables for ip in "${ips[@]}"; do - # 刪除已存在的阻止規則 + # 删除已存在的阻止规则 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 新增允許規則 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "已放行IP$ip" @@ -1088,12 +1088,12 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "進階防火牆管理" + echo "高级防火墙管理" send_stats "進階防火牆管理" echo "------------------------" iptables -L INPUT echo "" - echo "防火墙管理" + echo "防火牆管理" echo "------------------------" echo "1. 開放指定連接埠 2. 關閉指定連接埠" echo "3. 開放所有連接埠 4. 關閉所有連接埠" @@ -1106,7 +1106,7 @@ iptables_panel() { echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" echo "------------------------" echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" - echo "17. 解除指定國家IP限制" + echo "17. 解除指定国家IP限制" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -1162,7 +1162,7 @@ iptables_panel() { ;; 6) # IP 黑名單 - read -e -p "請輸入封鎖的IP或IP段:" c_ip + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) @@ -1200,7 +1200,7 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; @@ -1240,7 +1240,7 @@ add_swap() { # 確保 /swapfile 不再被使用 swapoff /swapfile - # 刪除舊的 /swapfile + # 删除旧的 /swapfile rm -f /swapfile # 建立新的 swap 分割區 @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判斷是否需要建立虛擬記憶體 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1464,7 +1464,7 @@ install_ssltls() { install_ssltls_text() { - echo -e "${gl_huang}$yuming 公钥信息${gl_bai}" + echo -e "${gl_huang}$yuming公鑰資訊${gl_bai}" cat /etc/letsencrypt/live/$yuming/fullchain.pem echo "" echo -e "${gl_huang}$yuming私鑰資訊${gl_bai}" @@ -1545,7 +1545,7 @@ certs_status() { echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" - echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" echo "------------------------" echo "1. 重新申請 2. 匯入已有憑證 0. 退出" @@ -1570,7 +1570,7 @@ certs_status() { mkdir -p /home/web/certs # 1. 輸入憑證 (ECC 和 RSA 憑證開頭都是 BEGIN CERTIFICATE) - echo "請貼上 證書 (CRT/PEM) 內容 (以兩次回車結束):" + echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break @@ -1638,7 +1638,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "請輸入訪問/監聽端口,回車預設使用 80:" access_port + read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port access_port=${access_port:-80} fi } @@ -1889,7 +1889,7 @@ patch_wp_memory_limit() { sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定義,放在含 "Happy publishing" 的行前 + # 插入新定义,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1977,7 +1977,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 開啟 Brotli:去掉註釋 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2048,7 +2048,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 關閉 Zstd:加上註釋 + # 关闭 Zstd:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) @@ -2264,7 +2264,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高负载自动开盾脚本已添加" + echo "高負載自動開盾腳本已新增" else echo "自動開盾腳本已存在,無需添加" fi @@ -2329,7 +2329,7 @@ check_nginx_compression() { zstd_status="" fi - # 檢查 brotli 是否開啟且未被註釋 + # 检查 brotli 是否开启且未被注释 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status="br壓縮已開啟" else @@ -2366,7 +2366,7 @@ web_optimization() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "站點標準模式" + send_stats "站点标准模式" local cpu_cores=$(nproc) local connections=$((1024 * ${cpu_cores})) @@ -2730,7 +2730,7 @@ block_host_port() { install iptables - # 拒絕其他所有 IP 訪問 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -2880,7 +2880,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" echo "5. 新增網域存取 6. 刪除網域存取" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}連接埠:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -2913,7 +2913,7 @@ while true; do add_app_id clear - echo "$docker_name 已经安装完成" + echo "$docker_name已經安裝完成" check_docker_app_ip echo "" $docker_use @@ -3219,7 +3219,7 @@ f2b_sshd() { fi } -# 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) # 說明: # - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) # - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 @@ -3551,7 +3551,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-負載平衡" + webname="反向代理-负载均衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3562,7 +3562,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "請輸入你的多個反代IP+埠以空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -3602,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服務名" "通訊類型" "本機地址" "後端地址" + printf "%-25s %-18s %-25s %-20s\n" "服务名" "通訊類型" "本机地址" "後端地址" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3707,7 +3707,7 @@ stream_panel() { send_stats "修改四層代理" ;; 6) - send_stats "刪除轉送配置" + send_stats "删除转发配置" read -e -p "請輸入你要刪除的服務名稱:" stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx @@ -3737,7 +3737,7 @@ ldnmp_Proxy_backend_stream() { fi # 取得監聽埠 - read -erp "請輸入本機監聽埠 (如 3306):" listen_port + read -erp "请输入本机监听端口 (如 3306): " listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "連接埠必須是數字"; return 1 fi @@ -3878,7 +3878,7 @@ ldnmp_web_status() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "申請網域證書" + send_stats "申请域名证书" read -e -p "請輸入你的網域名稱:" yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null @@ -3890,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3931,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -4009,7 +4009,7 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款時下流行且強大的維運管理面板。" + echo "${panelname}是一款时下流行且强大的运维管理面板。" echo "官網介紹:$panelurl " echo "" @@ -4182,8 +4182,8 @@ EOF delete_forwarding_service() { send_stats "刪除frp內網服務" # 提示使用者輸入需要刪除的服務名稱 - read -e -p "请输入需要删除的服务名称: " service_name - # 使用 sed 删除该服务及其相关配置 + read -e -p "請輸入需要刪除的服務名稱:" service_name + # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml echo "服務$service_name已成功從 frpc.toml 刪除" @@ -4216,7 +4216,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服務訊息,在處理新服務之前列印目前服務 + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4225,7 +4225,7 @@ list_forwarding_services() { type } - # 更新目前服務名稱 + # 更新当前服务名称 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -4572,8 +4572,8 @@ yt_menu_pro() { echo "更新完成。按任意鍵繼續..." read ;; 3) - send_stats "正在卸載 yt-dlp..." - echo "正在卸載 yt-dlp..." + send_stats "正在卸载 yt-dlp..." + echo "正在卸载 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt @@ -4624,11 +4624,11 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音訊下載完成,按任意鍵繼續..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) send_stats "刪除影片" - read -e -p "請輸入刪除影片名稱:" rmdir + read -e -p "请输入删除视频名称: " rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4664,7 +4664,7 @@ set_timedate() { -# 修復dpkg中斷問題 +# 修复dpkg中断问题 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4673,7 +4673,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_kjlan}正在系統更新...${gl_bai}" + echo -e "${gl_kjlan}正在系统更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4826,7 +4826,7 @@ root_use send_stats "優化DNS" while true; do clear - echo "优化DNS地址" + echo "優化DNS位址" echo "------------------------" echo "目前DNS地址" cat /etc/resolv.conf @@ -4974,7 +4974,7 @@ import_sshkey() { local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then - read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key fi if [[ -z "$public_key" ]]; then @@ -5015,7 +5015,7 @@ fetch_remote_ssh_keys() { read -e -p "請輸入您的遠端公鑰URL:" keys_url fi - echo "此腳本將從遠端 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" + echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" echo "" echo "遠端公鑰地址:" echo " ${keys_url}" @@ -5106,11 +5106,11 @@ fetch_github_ssh_keys() { if [[ -z "${username}" ]]; then - read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username fi if [[ -z "${username}" ]]; then - echo "錯誤:GitHub 使用者名稱不能為空" >&2 + echo "错误:GitHub 用户名不能为空" >&2 return 1 fi @@ -5135,7 +5135,7 @@ sshkey_panel() { echo -e "使用者密鑰登入模式${IS_KEY_ENABLED}" echo "進階玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "將會產生金鑰對,更安全的方式SSH登錄" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" @@ -5276,7 +5276,7 @@ dd_xitong() { } dd_xitong_1() { - echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai} 初始密码: ${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" @@ -5310,26 +5310,26 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重装有风险失联,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" - echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" + echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" echo "------------------------" - echo "11. Ubuntu 24.04 12. Ubuntu 22.04" - echo "13. Ubuntu 20.04 14. Ubuntu 18.04" + echo "11. Ubuntu 26.04 12. Ubuntu 24.04" + echo "13. Ubuntu 22.04 14. Ubuntu 20.04" echo "------------------------" echo "21. Rocky Linux 10 22. Rocky Linux 9" echo "23. Alma Linux 10 24. Alma Linux 9" echo "25. oracle Linux 10 26. oracle Linux 9" - echo "27. Fedora Linux 42 28. Fedora Linux 41" + echo "27. Fedora Linux 44 28. Fedora Linux 43" echo "29. CentOS 10 30. CentOS 9" echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" + echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" @@ -5372,35 +5372,34 @@ dd_xitong() { exit ;; 11) - send_stats "重裝ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + send_stats "重裝ubuntu 26.04" + dd_xitong_3 + bash reinstall.sh ubuntu 26.04 reboot exit ;; 12) - send_stats "重裝ubuntu 22.04" + send_stats "重裝ubuntu 24.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + bash InstallNET.sh -ubuntu 24.04 reboot exit ;; 13) - send_stats "重裝ubuntu 20.04" + send_stats "重裝ubuntu 22.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + bash InstallNET.sh -ubuntu 22.04 reboot exit ;; 14) - send_stats "重裝ubuntu 18.04" + send_stats "重裝ubuntu 20.04" dd_xitong_1 - bash InstallNET.sh -ubuntu 18.04 + bash InstallNET.sh -ubuntu 20.04 reboot exit ;; - 21) send_stats "重裝rockylinux10" dd_xitong_3 @@ -5450,17 +5449,17 @@ dd_xitong() { ;; 27) - send_stats "重裝fedora42" + send_stats "重裝fedora44" dd_xitong_3 - bash reinstall.sh fedora + bash reinstall.sh fedora 44 reboot exit ;; 28) - send_stats "重裝fedora41" + send_stats "重裝fedora43" dd_xitong_3 - bash reinstall.sh fedora 41 + bash reinstall.sh fedora 43 reboot exit ;; @@ -5530,7 +5529,7 @@ dd_xitong() { ;; 41) - send_stats "重装windows11" + send_stats "重裝windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5723,7 +5722,7 @@ bbrv3() { echo "BBR3參數寫入失敗,請檢查系統配置" return 1 } - echo "XanMod BBRv3內核處理完成。重啟後生效" + echo "XanMod BBRv3内核处理完成。重啟後生效" server_reboot } @@ -5838,12 +5837,12 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支援的系統版本:$os_version" + echo "不支持的系统版本:$os_version" break_end linux_Settings fi # 啟用 ELRepo 內核倉庫並安裝最新的主線內核 - echo "啟用 ELRepo 核心倉庫並安裝最新的主線核心..." + echo "启用 ELRepo 内核仓库并安装最新的主线内核..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml echo "已安裝 ELRepo 倉庫配置並更新至最新主線核心。" @@ -5865,7 +5864,7 @@ elrepo() { echo "" echo "核心管理" echo "------------------------" - echo "1. 更新elrepo內核 2. 卸載elrepo內核" + echo "1. 更新elrepo内核 2. 卸载elrepo内核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5883,7 +5882,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo内核已卸载。重啟後生效" + echo "elrepo核心已卸載。重啟後生效" send_stats "解除安裝紅帽內核" server_reboot @@ -5958,7 +5957,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 執行 Docker 命令 + # 执行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -6041,7 +6040,7 @@ _get_mem_mb() { } # 統一內核調優核心函數 -# 參數: $1 = 模式名稱, $2 = 場景 (high/balanced/web/stream/game) +# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6201,7 +6200,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 核心調優配置 +# kejilion 内核调优配置 # 模式: $mode_name | 場景: $scene # 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') @@ -6271,7 +6270,7 @@ net.ipv6.conf.default.accept_redirects = 0 fs.file-max = 1048576 fs.nr_open = 1048576 -# ── 連結追蹤 ── +# ── 连接跟踪 ── $(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" @@ -6342,7 +6341,7 @@ optimize_web_server() { _kernel_optimize_core "網站建置優化模式" "web" } -# ── 還原預設設定(完全清理) ── +# ── 还原默认设置(完全清理) ── restore_defaults() { echo -e "${gl_lv}還原到預設值...${gl_bai}" @@ -6699,7 +6698,7 @@ create_backup() { local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # 提示使用者輸入備份目錄 - echo "创建备份示例:" + echo "建立備份範例:" echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用預設目錄 (/etc /usr /home)" @@ -6784,7 +6783,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -7048,7 +7047,7 @@ delete_connection() { echo "連線已刪除!" } -# 使用連接 +# 使用连接 use_connection() { send_stats "使用連接" read -e -p "請輸入要使用的連接編號:" num @@ -7085,7 +7084,7 @@ use_connection() { echo "連線失敗!請檢查以下內容:" echo "1. 使用者名稱和密碼是否正確。" echo "2. 目標伺服器是否允許密碼登入。" - echo "3. 目標伺服器的 SSH 服務是否正常運作。" + echo "3. 目标服务器的 SSH 服务是否正常运行。" fi fi } @@ -7275,7 +7274,7 @@ format_partition() { fi # 格式化分割區 - echo "正在格式化分割區 /dev/$PARTITION為$FS_TYPE ..." + echo "正在格式化分区 /dev/$PARTITION為$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then @@ -7312,7 +7311,7 @@ disk_manager() { list_partitions echo "------------------------" echo "1. 掛載分割區 2. 卸載分割區 3. 檢視已掛載分割區" - echo "4. 格式化分割區 5. 檢查分割區狀態" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7355,7 +7354,7 @@ add_task() { read -e -p "請輸入遠端目錄:" remote_path while true; do - read -e -p "请输入远程用户@IP: " remote + read -e -p "請輸入遠端使用者@IP:" remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break @@ -7408,7 +7407,7 @@ delete_task() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "任务已删除!" + echo "任務已刪除!" } @@ -7448,12 +7447,12 @@ run_task() { source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到遠端:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 新增 SSH 連線通用參數 + # 添加 SSH 连接通用参数 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then @@ -7466,9 +7465,9 @@ run_task() { fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 檢查密鑰檔案是否存在和權限是否正確 + # 检查密钥文件是否存在和权限是否正确 if [[ ! -f "$password_or_key" ]]; then - echo "錯誤:密鑰檔案不存在:$password_or_key" + echo "错误:密钥文件不存在:$password_or_key" return fi @@ -7686,7 +7685,7 @@ linux_info() { echo -e "${gl_kjlan}IPv6位址:${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNS位址:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" + echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" @@ -7728,7 +7727,7 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未識別的套件管理器" + echo "❌ 未识别的包管理器" exit 1 fi @@ -7875,7 +7874,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "安裝ranger" ;; 13) clear @@ -7998,7 +7997,7 @@ linux_tools() { clear read -e -p "請輸入已安裝的工具名稱(wget curl sudo htop):" installname install $installname - send_stats "安装指定软件" + send_stats "安裝指定軟體" ;; 42) clear @@ -8244,7 +8243,7 @@ docker_ssh_migration() { fi done - # --------- 繼續還原一般容器 --------- + # --------- 继续还原普通容器 --------- echo -e "${gl_kjlan}檢查並還原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do @@ -8303,7 +8302,7 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8325,7 +8324,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker遷移" install jq - read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR + read -e -p "请输入要迁移的备份目录: " BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } kj_ssh_read_host_user_port "目標伺服器IP:" "目標伺服器SSH用戶名 [預設root]:" "目標伺服器SSH連接埠 [預設22]:" "root" "22" @@ -8455,7 +8454,7 @@ linux_docker() { echo -e "Docker磁碟區:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" + echo -e "Docker網路:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8704,7 +8703,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8773,10 +8772,10 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京电信: 219.141.136.12" + echo "北京電信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" - echo "上海电信: 202.96.209.133" + echo "上海電信: 202.96.209.133" echo "上海聯通: 210.22.97.1" echo "上海移動: 211.136.112.200" echo "廣州電信: 58.60.188.222" @@ -8966,7 +8965,7 @@ linux_Oracle() { read -e -p "請輸入你重裝後的密碼:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文雲端重裝系統腳本" + send_stats "甲骨文云重装系统脚本" ;; [Nn]) echo "已取消" @@ -9042,7 +9041,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}環境已安裝${gl_bai}站點:$output資料庫:$db_output" + echo -e "${gl_lv}环境已安装${gl_bai}站點:$output資料庫:$db_output" fi fi @@ -9070,14 +9069,14 @@ linux_ldnmp() { while true; do clear - # send_stats "LDNMP建站" + # send_stats "LDNMP建置站" echo -e "${gl_huang}LDNMP建站" ldnmp_tato echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" - echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安装独角数发卡网" - echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" + echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" + echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" @@ -9090,7 +9089,7 @@ linux_ldnmp() { echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸载LDNMP环境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}解除安裝LDNMP環境" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主選單" echo -e "${gl_huang}------------------------${gl_bai}" @@ -9108,7 +9107,7 @@ linux_ldnmp() { 3) clear - # Discuz論壇 + # Discuz论坛 webname="Discuz論壇" send_stats "安裝$webname" echo "開始部署$webname" @@ -9227,7 +9226,7 @@ linux_ldnmp() { echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" - echo "数据库前缀: mac_" + echo "資料庫前綴: mac_" echo "------------------------" echo "安裝成功後登入後台位址" echo "https://$yuming/vip.php" @@ -9460,7 +9459,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目录下" read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then @@ -9863,7 +9862,7 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename + read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -10143,10 +10142,10 @@ moltbot_menu() { echo "3. 停止" echo "--------------------" echo "4. 狀態日誌查看" - echo "5. 换模型" + echo "5. 換模型" echo "6. API管理" echo "7. 機器人連線對接" - echo "8. 插件管理(安裝/刪除)" + echo "8. 插件管理(安装/删除)" echo "9. 技能管理(安裝/刪除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" @@ -10309,7 +10308,7 @@ def collect_available_refs(exclude_provider=None): def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 偵測連續失敗 3 次。是否刪除該 API 供應商及其全部相關模型? [y/N]:" + prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型? [y/N]:" try: ans = input(prompt).strip().lower() except EOFError: @@ -10337,7 +10336,7 @@ def rebind_defaults_before_delete(name): return False set_primary_ref(defaults, repl) changed = True - summary.append(f'🔁 刪除前已切換預設主模型: {primary_ref} -> {repl}') + summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) @@ -10397,7 +10396,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳過 {name}: provider 結構非法') + summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') continue api = provider.get('api', '') @@ -10751,7 +10750,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 預設模型不能為空" + echo "❌ 默认模型不能为空" return 1 fi @@ -10761,8 +10760,8 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 已新增 provider:$provider_name" - echo "✅ 僅寫入預設模型:$default_model" + echo "✅ 已添加 provider:$provider_name" + echo "✅ 仅写入默认模型:$default_model" return 0 else echo "❌ 配置注入失敗" @@ -10811,9 +10810,9 @@ EOF if [[ -n "$available_models" ]]; then model_count=$(echo "$available_models" | wc -l) - echo "✅ 發現$model_count 个可用模型:" + echo "✅ 發現$model_count個可用模型:" echo "--------------------------------" - # 全部显示,带序号 + # 全部顯示,附序號 i=1 model_list=() while read -r model; do @@ -10831,7 +10830,7 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) - echo "🎯 使用第一个模型: $default_model" + echo "🎯 使用第一個模型:$default_model" elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then default_model="${model_list[$((input_model-1))]}" echo "🎯 已選擇模型:$default_model" @@ -10855,7 +10854,7 @@ EOF if [[ "$confirm" =~ ^[Yy]$ ]]; then add-all-models-from-provider "$provider_name" "$base_url" "$api_key" add_result=$? - finish_msg="✅ 完成!所有$model_count 个模型已加载" + finish_msg="✅ 完成!所有$model_count個模型已載入" else add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" add_result=$? @@ -11122,7 +11121,7 @@ if err is not None: raise SystemExit(4) if not (isinstance(data, dict) and isinstance(data.get('data'), list)): - print(f'❌ {target}: /models 返回结构不可识别') + print(f'❌ {target}: /models 回傳結構不可識別') raise SystemExit(4) remote_ids = [] @@ -11140,7 +11139,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 無有效模板模型,無法補全新增模型') + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -11210,7 +11209,7 @@ if removed_ids: print(f' - {mid}') if changed: - print('✅ 指定 provider 模型一致性同步完成並已寫入配置') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: print('ℹ️ 無需同步:此 provider 配置已與上游 /models 保持一致') PY2 @@ -11224,7 +11223,7 @@ PY2 echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失敗:provider 配置不完整或類型不支持" + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11267,7 +11266,7 @@ fix-openclaw-provider-protocol-interactive() { echo "請選擇要設定的 API 類型:" echo "1. openai-completions" echo "2. openai-responses" - read -erp "請輸入你的選擇 (1/2):" proto_choice + read -erp "请输入你的选择 (1/2): " proto_choice local new_api="" case "$proto_choice" in @@ -11504,7 +11503,7 @@ PY echo -e " ${gl_lv}● 超算互聯網${gl_bai}" echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" echo "" - echo -e " ${gl_huang}● 優雲智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" echo -e " ${gl_huang}● 矽基流動${gl_bai} ${gl_zi}[AFF]${gl_bai}" @@ -11841,7 +11840,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi @@ -11891,7 +11890,7 @@ PYTHON_EOF return 0 else if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 不可用,傳回舊版輸入模式。" + echo "gum 不可用,返回旧版输入模式。" sleep 1 continue fi @@ -12264,7 +12263,7 @@ PYTHON_EOF continue fi - echo "📥 本機未發現,嘗試下載安裝:$plugin_full" + echo "📥 本地未发现,尝试下载安装: $plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -12376,7 +12375,7 @@ PYTHON_EOF echo "💡 技能 [$skill_name] 已在使用者目錄安裝。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系統目錄安裝。" + echo "💡 技能 [$skill_name] 已在系统目录安装。" skill_found=true fi @@ -12476,7 +12475,7 @@ openclaw_json_get_bool() { # 相容於兩種常見目錄命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 + # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12661,7 +12660,7 @@ openclaw_json_get_bool() { echo "----------------------------------------" echo "1. Telegram 機器人對接" echo "2. 飛書 (Lark) 機器人對接" - echo "3. WhatsApp 機器人對接" + echo "3. WhatsApp 机器人对接" echo "4. QQ 機器人對接" echo "5. 微信機器人對接" echo "----------------------------------------" @@ -12801,7 +12800,7 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "可使用以下方式下載備份檔:" + echo "可使用以下方式下载备份文件:" echo "- 本地路徑:$file_path" echo "- scp 範例: scp root@你的伺服器:$file_path ./" echo "- 或使用 SFTP 用戶端下載" @@ -12812,7 +12811,7 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 文件不存在:$archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } mkdir -p "$unpack_root" tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 備份包解壓縮失敗"; return 1; } @@ -12925,7 +12924,7 @@ if os.path.isdir(agents_root): local openclaw_root openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then - echo "❌ 未找到 OpenClaw 根目錄:$openclaw_root" + echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" break_end return 1 fi @@ -13152,7 +13151,7 @@ if os.path.isdir(agents_root): return 0 fi - read -e -p "請輸入要刪除的檔案名稱或完整路徑(0 取消):" user_input + read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input if [ "$user_input" = "0" ]; then echo "已取消刪除。" break_end @@ -13202,7 +13201,7 @@ if os.path.isdir(agents_root): break_end return 0 fi - read -e -p "二次確認:輸入 DELETE 執行刪除:" confirm_step2 + read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then echo "已取消刪除。" break_end @@ -13444,7 +13443,7 @@ except Exception: print("取得記憶狀態失敗(JSON 解析錯誤)") raise SystemExit(1) if not isinstance(data, list) or len(data) == 0: - print("未檢測到任何智能體記憶狀態。") + print("未检测到任何智能体记忆状态。") raise SystemExit(0) first = True for entry in data: @@ -13459,7 +13458,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("底層方案: %s" % backend) + print(" 底层方案: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("已收錄: %s 檔案 / %s 區塊" % (files, chunks)) @@ -13559,7 +13558,7 @@ PY if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("未檢測到 QMD") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路徑:$model_path") @@ -13572,7 +13571,7 @@ PY *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可訪問") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else @@ -13659,7 +13658,7 @@ PY openclaw_memory_check_sqlite() { if ! command -v sqlite3 >/dev/null 2>&1; then - echo "⚠️ 未偵測到 sqlite3,QMD 可能無法正常運作。" + echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" return 1 fi local ver @@ -13677,7 +13676,7 @@ PY echo "✅ bun 已存在" return 0 fi - echo "⬇️ 安裝 bun..." + echo "⬇️ 安装 bun..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then @@ -13690,7 +13689,7 @@ PY export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 安裝完成" + echo "✅ bun 安装完成" return 0 fi echo "❌ bun 安裝失敗" @@ -13831,7 +13830,7 @@ PY echo "✅ memory.qmd.command 已正確" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 預熱索引(可能下載模型)" + echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace_all local preh_agent_lines preh_agent_id preh_workspace preh_agent_lines=$(openclaw_memory_list_agents) @@ -13863,7 +13862,7 @@ EOF echo "✅ memorySearch.provider 已是 local" else openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" - echo "✅ 已設定 agents.defaults.memorySearch.provider=local" + echo "✅ 已设置 agents.defaults.memorySearch.provider=local" fi local model_path model_status @@ -13908,7 +13907,7 @@ EOF else echo "⏭️ 已跳過預熱" fi - echo "✅ Local 自動部署完成" + echo "✅ Local 自动部署完成" } openclaw_memory_auto_setup_run() { @@ -13927,7 +13926,7 @@ EOF case "$scheme" in qmd) scheme_label="QMD" - OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安裝目錄)" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安装目录)" OPENCLAW_MEMORY_EXPECT_SIZE="約 20-50MB" ;; local) @@ -13971,7 +13970,7 @@ EOF echo "=======================================" echo "1. QMD" echo "2. Local" - echo "3. Auto(自動選擇)" + echo "3. Auto(自动选择)" echo "0. 返回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" auto_choice @@ -14059,7 +14058,7 @@ EOF echo "這會導致預設記憶檔案(MEMORY.md + memory/*.md)不被索引" echo "所以 Indexed 會一直顯示 0/N" echo "" - read -e -p "是否恢復為 true 並重建索引? (Y/n):" fix_choice + read -e -p "是否恢复为 true 并重建索引? (Y/n):" fix_choice if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true if [ $? -ne 0 ]; then @@ -14106,7 +14105,7 @@ EOF echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" echo "1. 切換 QMD(自動部署/已安裝則跳過)" - echo "2. 切換 Local(自動部署/已安裝則跳過)" + echo "2. 切换 Local(自动部署/已装则跳过)" echo "3. Auto(自動推薦並自動部署)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14167,7 +14166,7 @@ EOF echo "未找到記憶文件。" return 0 fi - echo "編號 | 歸屬 | 大小 | 修改時間" + echo "编号 | 归属 | 大小 | 修改时间" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do @@ -14286,7 +14285,7 @@ EOF echo "2. 檢視記憶文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" - echo "5. 搜尋測試(驗證索引是否運作)" + echo "5. 搜索测试(验证索引是否工作)" echo "6. 深度狀態探測(檢查嵌入模型)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14294,7 +14293,7 @@ EOF case "$memory_choice" in 1) echo "即將更新記憶索引。" - read -e -p "第一次确认:输入 yes 继续: " confirm_step1 + read -e -p "第一次確認:輸入 yes 繼續:" confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消。" break_end @@ -14303,7 +14302,7 @@ EOF openclaw_memory_prepare_workspace_all read -e -p "二次確認:輸入 force 使用全量(留空為增量):" confirm_step2 if [ "$confirm_step2" = "force" ]; then - echo "⚠️ 全量重建更徹底,但耗時更長。" + echo "⚠️ 全量重建更彻底,但耗时更长。" echo "建議:輸入 rebuild 進行安全重建(先備份索引庫)。" read -e -p "第三次確認:輸入 rebuild 執行安全重建;直接回車繼續普通 force:" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then @@ -14365,7 +14364,7 @@ EOF openclaw_permission_require_openclaw() { if ! openclaw_has_command openclaw; then - echo "❌ 未偵測到 openclaw 指令,請先安裝或初始化 OpenClaw。" + echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" return 1 fi return 0 @@ -14407,7 +14406,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ 未检测到 openclaw,无法重启 OpenClaw Gateway。" + echo "❌ 未偵測到 openclaw,無法重新啟動 OpenClaw Gateway。" return 1 fi echo "正在重啟 OpenClaw Gateway..." @@ -14544,7 +14543,7 @@ PY mkdir -p "$HOME/.openclaw" # 產生 JSON 並透過 openclaw approvals set --stdin 寫入(優先) - # 若 CLI 不支援則回退直接寫文件 + # 若 CLI 不支持则回退直接写文件 local json_payload json_payload=$(python3 -c ' import json, sys, os @@ -14569,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 回退:直接寫文件 + # 回退:直接写文件 echo "$json_payload" > "$approvals_file" } @@ -14646,7 +14645,7 @@ try: print("提示策略 (Ask):" + str(d.get("ask", "(unset)"))) print("無UI兜底 (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print(" (配置文件解析失败)") + print("(設定檔解析失敗)") ' else echo "(未配置,強制使用系統內建安全兜底策略)" @@ -14710,7 +14709,7 @@ except Exception: } openclaw_permission_restore_official_defaults() { - send_stats "OpenClaw权限-恢复官方默认" + send_stats "OpenClaw權限-恢復官方默認" openclaw_permission_require_openclaw || return 1 echo "清理應用層強制覆蓋..." @@ -14818,7 +14817,7 @@ except Exception as e: echo "---------------------------------------" echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" - echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" + echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" @@ -15007,7 +15006,7 @@ PY return 0 fi fi - # 回退:從檔案系統讀取 + # 回退:从文件系统读取 python3 <<'PY' import json,os base=os.path.expanduser("~/.openclaw/agents") @@ -15052,7 +15051,7 @@ agents=json.loads(sys.argv[1] or "[]") bindings=json.loads(sys.argv[2] or "[]") sess_obj=json.loads(sys.argv[3] or "{}") sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] -print("已配置智能體數: %s" % len(agents)) +print("已配置智能体数: %s" % len(agents)) print("路由綁定數: %s" % len(bindings)) print("會話總數: %s" % len(sessions)) print("---------------------------------------") @@ -15068,9 +15067,9 @@ else: is_default = item.get("isDefault", False) bcount = item.get("bindings", 0) default_tag = "[預設]" if is_default else "" - print("- 智能體ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) print("身份名稱: %s %s" % (identity, emoji)) - print("模型: %s" % model) + print(" 模型: %s" % model) print("工作目錄: %s" % ws) print("綁定數: %s" % bcount) ' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" @@ -15123,7 +15122,7 @@ for idx,item in enumerate(agents,1): if openclaw agents delete "$agent_id"; then echo "✅ 智能體刪除成功:$agent_id" else - echo "❌ 智能體刪除失敗" + echo "❌ 智能体删除失败" return 1 fi } @@ -15134,7 +15133,7 @@ for idx,item in enumerate(agents,1): import json,sys bindings=json.loads(sys.argv[1] or "[]") if not bindings: - print("暫無路由綁定。") + print("暂无路由绑定。") raise SystemExit(0) for idx,item in enumerate(bindings,1): desc = item.get("description") or "-" @@ -15241,7 +15240,7 @@ print("✅ 多智能體健康檢查完成") ' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" echo "" echo "運行安全審計..." - openclaw security audit 2>/dev/null || echo "⚠️ 安全审计命令不可用" + openclaw security audit 2>/dev/null || echo "⚠️ 安全審計命令不可用" } @@ -15252,7 +15251,7 @@ print("✅ 多智能體健康檢查完成") [ -z "$agent_id" ] && { echo "ID 不能為空"; return 1; } echo "修改選項(留空跳過):" read -e -p "新名稱:" new_name - read -e -p " 新 Emoji: " new_emoji + read -e -p "新 Emoji:" new_emoji local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" @@ -15273,7 +15272,7 @@ print("✅ 多智能體健康檢查完成") } openclaw_multiagent_menu() { - send_stats "OpenClaw多智能體管理" + send_stats "OpenClaw多智能体管理" while true; do clear echo "=======================================" @@ -15658,7 +15657,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -16530,7 +16529,7 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_describe="Memos是一款輕量、自架的備忘錄中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -18188,7 +18187,7 @@ while true; do } - local docker_describe="開源個人訂閱追蹤器,可用於財務管理" + local docker_describe="开源个人订阅追踪器,可用于财务管理" local docker_url="官網介紹:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" @@ -18327,7 +18326,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" - local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" local app_size="1" docker_app @@ -18409,7 +18408,7 @@ while true; do } - local docker_describe="Matrix是一个去中心化的聊天协议" + local docker_describe="Matrix是一個去中心化的聊天協議" local docker_url="官網介紹: https://matrix.org/" local docker_use="" local docker_passwd="" @@ -18924,7 +18923,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19440,7 +19439,7 @@ linux_work() { send_stats "後台工作區" echo -e "後台工作區" echo -e "系統將為你提供可以後台常駐運作的工作區,你可以用來執行長時間的任務" - echo -e "即使你断开SSH,工作区中的任务也不会中断,后台常驻任务。" + echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" echo "目前已存在的工作區列表" @@ -19592,7 +19591,7 @@ linux_work() { ;; 24) - read -e -p "請輸入要刪除的工作區名稱:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name send_stats "刪除工作區" ;; @@ -20132,7 +20131,7 @@ linux_Settings() { echo -e "${gl_kjlan}13. ${gl_bai}使用者管理${gl_kjlan}14. ${gl_bai}使用者/密碼產生器" echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設定BBR3加速" echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主機名" - echo -e "${gl_kjlan}19. ${gl_bai}切换系统更新源 ${gl_kjlan}20. ${gl_bai}定時任務管理" + echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新來源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" @@ -20790,7 +20789,7 @@ EOF break # 跳出 ;; esac - send_stats "添加定时任务" + send_stats "新增定時任務" ;; 2) read -e -p "請輸入需要刪除任務的關鍵字:" kquest @@ -21105,15 +21104,15 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系統垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設定虛擬內存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 @@ -21183,7 +21182,7 @@ EOF echo "隱私與安全" echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" - echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," + echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," echo "------------------------------------------------" echo -e "目前狀態:$status_message" echo "--------------------" @@ -21276,7 +21275,7 @@ linux_file() { clear echo "文件管理器" echo "------------------------" - echo "目前路徑" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x @@ -21324,7 +21323,7 @@ linux_file() { ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一層選單目錄" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 read -e -p "請輸入要建立的檔案名稱:" filename @@ -21357,8 +21356,8 @@ linux_file() { 21) # 压缩文件/目录 read -e -p "請輸入要壓縮的檔案/目錄名稱:" name install tar - tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "压缩失败" - send_stats "压缩文件/目录" + tar -czvf "$name.tar.gz" "$name" && echo "已壓縮為$name.tar.gz" || echo "壓縮失敗" + send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename @@ -21403,7 +21402,7 @@ linux_file() { fi # 使用 -r 選項以遞歸方式複製目錄 - cp -r "$src_path" "$dest_path" && echo "檔案或目錄已複製到$dest_path" || echo "複製檔案或目錄失敗" + cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "複製檔案或目錄失敗" send_stats "複製檔案或目錄" ;; @@ -21521,7 +21520,7 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}批次執行任務${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" + echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系统" echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21531,8 +21530,8 @@ while true; do case $sub_choice in 1) - send_stats "添加集群服务器" - read -e -p "服务器名称: " server_name + send_stats "新增叢集伺服器" + read -e -p "伺服器名稱:" server_name read -e -p "伺服器IP:" server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} @@ -21641,7 +21640,7 @@ echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流 echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" -echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_bai}网址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "網域優惠" @@ -21735,7 +21734,7 @@ while true; do echo "------------------------" curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 - # 只下载前5行获取版本号,避免下载整个脚本 + # 只下載前5行取得版本號,避免下載整個腳本 local sh_v_new=$(curl -s --max-time 15 -r 0-200 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion.sh | grep -o 'sh_v="[0-9.]*"' | head -1 | cut -d '"' -f 2) if [ -z "$sh_v_new" ]; then @@ -21944,18 +21943,18 @@ echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "軟體重啟 k restart sshd | k 重啟 sshd" +echo "软件重启 k restart sshd | k 重启 sshd " echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" echo "網域名稱憑證到期查詢 k ssl ps" echo "docker管理平面 k docker" -echo "docker環境安裝 k docker install |k docker 安裝" +echo "docker环境安装 k docker install |k docker 安装" echo "docker容器管理 k docker ps |k docker 容器" echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" -echo "安裝WordPress k wp |k wordpress |k wp xxx.com" +echo "安装WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" @@ -21969,7 +21968,7 @@ echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統資訊 k info" -echo "ROOT金鑰管理 k sshkey" +echo "ROOT密钥管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " echo "SSH公鑰導入(GitHub) k sshkey github " @@ -22218,8 +22217,8 @@ else shift case "$1" in "" ) - # sshkey → 交互菜单 - send_stats "SSHKey 交互菜单" + # sshkey → 互動選單 + send_stats "SSHKey 互動選單" sshkey_panel ;; github ) @@ -22239,7 +22238,7 @@ else echo "錯誤:未知參數 '$1'" echo "用法:" echo "k sshkey 進入互動選單" - echo " k sshkey \"\" 直接导入 SSH 公钥" + echo "k sshkey \"\" 直接導入 SSH 公鑰" echo "k sshkey 從 URL 匯入 SSH 公鑰" echo "k sshkey github 從 GitHub 匯入 SSH 公鑰" ;; From ee7c7e00d3804d08241306b146514629e5a16d18 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 16:41:15 +0800 Subject: [PATCH 1174/1285] feat: add Hermes update notice --- hermes_manager.sh | 48 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 913b5f278..624493d33 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -509,14 +509,58 @@ get_version() { fi } +# 提取语义版本号,例如 v0.13.0 / 0.13.0 +extract_semver() { + echo "$1" | grep -Eo 'v?[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 +} + +# 比较两个版本号:$1 < $2 返回 0 +version_lt() { + [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n 1)" != "$2" ] && [ "$1" != "$2" ] +} + +# 获取 PyPI 最新版本,失败时静默,避免影响主菜单显示 +get_latest_version() { + python3 - <<'PY' 2>/dev/null +import json +import urllib.request + +try: + with urllib.request.urlopen('https://pypi.org/pypi/hermes-agent/json', timeout=3) as response: + data = json.load(response) + version = (data.get('info') or {}).get('version') or '' + if version: + print('v' + version.lstrip('v')) +except Exception: + pass +PY +} + +# 检查是否有新版本 +get_update_notice() { + if ! check_installed; then + return + fi + + local current_version latest_version current_plain latest_plain + current_version="$(extract_semver "$(get_version)")" + latest_version="$(extract_semver "$(get_latest_version)")" + current_plain="${current_version#v}" + latest_plain="${latest_version#v}" + + if [ -n "$current_plain" ] && [ -n "$latest_plain" ] && version_lt "$current_plain" "$latest_plain"; then + echo -e " ${YELLOW}有新版本 ${latest_version^^}${NC}" + fi +} + # 获取网关状态 get_gateway_status() { if check_installed; then # 匹配后台 gateway 进程或 systemd 服务 if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then - echo -e "${GREEN}运行中${NC}" + echo -e "${GREEN}运行中${NC}$(get_update_notice)" else - echo -e "${RED}已停止${NC}" + echo -e "${RED}已停止${NC}$(get_update_notice)" fi else echo -e "${RED}未安装${NC}" From 9a2e11ed8b44f079d11e4b0f47682c8343900ce5 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 16:47:08 +0800 Subject: [PATCH 1175/1285] fix: suppress Hermes version pipe errors --- hermes_manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 624493d33..e85df7477 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -505,7 +505,7 @@ check_installed() { # 获取版本号 get_version() { if check_installed; then - hermes --version | head -n 1 + hermes --version 2>/dev/null | sed -n '1p' fi } From 79460c0a7f710cb918c208f58639de2febf09edf Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 18:12:09 +0800 Subject: [PATCH 1176/1285] feat: add Hermes API model sync menu --- hermes_manager.sh | 119 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index e85df7477..1e762cac2 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -263,6 +263,105 @@ hermes_probe_status_line() { fi } +sync_single_api_provider_models() { + local provider_name="$1" + local ps_json="$2" + + local entry base_url api_key m_json m_list_str old_list added_list deleted_list + entry=$(echo "$ps_json" | jq -c --arg n "$provider_name" '[.[] | select(.name == $n or (.name | startswith($n + "/")))] | .[0] // empty' 2>/dev/null) + if [ -z "$entry" ] || [ "$entry" = "null" ]; then + echo -e "${RED}❌ $provider_name: 未找到供应商配置${NC}" + return 1 + fi + + base_url=$(echo "$entry" | jq -r '.base_url // empty') + api_key=$(echo "$entry" | jq -r '.api_key // empty') + base_url="${base_url%/}" + if [ -z "$base_url" ]; then + echo -e "${RED}❌ $provider_name: Base URL 为空${NC}" + return 1 + fi + + m_json=$(curl -s -m 20 -H "Authorization: Bearer ${api_key}" "$base_url/models") + m_list_str=$(echo "$m_json" | jq -r '.data[]?.id' 2>/dev/null | sed '/^$/d' | sort -u) + if [ -z "$m_list_str" ]; then + echo -e "${RED}❌ $provider_name: 无法获取模型列表${NC}" + return 1 + fi + + old_list=$(echo "$ps_json" | jq -r --arg n "$provider_name" ' + .[] + | select(.name == $n or (.name | startswith($n + "/"))) + | if .name == $n then (.model // empty) else ((.name | sub("^" + $n + "/"; "")) // .model // empty) end + ' 2>/dev/null | sed '/^$/d' | sort -u) + + added_list=$(comm -13 <(printf '%s\n' "$old_list") <(printf '%s\n' "$m_list_str")) + deleted_list=$(comm -23 <(printf '%s\n' "$old_list") <(printf '%s\n' "$m_list_str")) + + local added_count deleted_count current_count m_json_list + added_count=$(printf '%s\n' "$added_list" | sed '/^$/d' | wc -l | tr -d ' ') + deleted_count=$(printf '%s\n' "$deleted_list" | sed '/^$/d' | wc -l | tr -d ' ') + current_count=$(printf '%s\n' "$m_list_str" | sed '/^$/d' | wc -l | tr -d ' ') + + m_json_list=$(printf '%s\n' "$m_list_str" | jq -R . | jq -s -c .) + config_tool bulk_add "$provider_name" "$base_url" "$api_key" "$m_json_list" + + echo -e "${GREEN}✅ $provider_name: 新增 $added_count 个,删除 $deleted_count 个,当前 $current_count 个${NC}" + if [ "$added_count" -gt 0 ]; then + echo -e "${GREEN}+ 新增模型($added_count):${NC}" + printf '%s\n' "$added_list" | sed '/^$/d' | sed 's/^/ + /' + fi + if [ "$deleted_count" -gt 0 ]; then + echo -e "${YELLOW}- 删除模型($deleted_count):${NC}" + printf '%s\n' "$deleted_list" | sed '/^$/d' | sed 's/^/ - /' + fi + return 0 +} + +sync_api_provider_models() { + local target_provider="$1" + local ps_json groups_json g_count synced_count failed_count provider_name + + ps_json=$(config_tool list_p) + if [ "$(echo "$ps_json" | jq '. | length' 2>/dev/null)" -eq 0 ] 2>/dev/null; then + echo -e "${RED}无 API 配置! 请先添加供应商。${NC}" + return 1 + fi + + groups_json=$(config_tool list_groups) + g_count=$(echo "$groups_json" | jq '. | length' 2>/dev/null) + if [ "$g_count" -eq 0 ] 2>/dev/null || [ -z "$g_count" ]; then + echo -e "${RED}无 API 供应商分组可同步。${NC}" + return 1 + fi + + synced_count=0 + failed_count=0 + if [ -n "$target_provider" ]; then + if sync_single_api_provider_models "$target_provider" "$ps_json"; then + synced_count=$((synced_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + else + while read -r provider_name; do + [ -z "$provider_name" ] && continue + ps_json=$(config_tool list_p) + if sync_single_api_provider_models "$provider_name" "$ps_json"; then + synced_count=$((synced_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + done < <(echo "$groups_json" | jq -r '.[].name') + fi + + if [ "$failed_count" -eq 0 ]; then + echo -e "${GREEN}✅ API 供应商模型列表同步完成并已写入配置${NC}" + else + echo -e "${YELLOW}⚠️ API 供应商模型列表同步完成:成功 $synced_count 个,失败 $failed_count 个${NC}" + fi +} + api_management_submenu() { while true; do clear @@ -282,7 +381,8 @@ api_management_submenu() { echo -e "---------------------------------------" echo -e "1. ${YELLOW}切换模型 (带测速)${NC}" echo -e "2. 添加 API 供应商 (自动同步)${NC}" - echo -e "3. 删除 API 供应商" + echo -e "3. ${YELLOW}同步 API 供应商模型列表${NC}" + echo -e "4. 删除 API 供应商" echo -e "0. 返回主菜单" echo -e "---------------------------------------" read -p "选择序号: " sub_choice @@ -465,6 +565,23 @@ api_management_submenu() { sleep 2 ;; 3) + echo -e "${CYAN}--- 同步 API 供应商模型列表 ---${NC}" + echo -e "${CYAN}已配置的供应商分组:${NC}" + groups_json=$(config_tool list_groups) + g_count=$(echo "$groups_json" | jq '. | length' 2>/dev/null) + if [ "$g_count" -eq 0 ] 2>/dev/null || [ -z "$g_count" ]; then + echo -e " ${YELLOW}(暂无配置)${NC}" + sleep 1 + continue + fi + echo "$groups_json" | jq -r '.[] | " ● \(.name) (\(.count) 个模型)"' + echo "" + read -p "请输入要同步的 API 名称(provider),直接回车同步全部: " sync_provider + sync_api_provider_models "$sync_provider" + echo "" + read -p "按回车键继续..." + ;; + 4) echo -e "${CYAN}已配置的供应商分组:${NC}" groups_json=$(config_tool list_groups) g_count=$(echo "$groups_json" | jq '. | length') From 18afc4fce347354401e5dde72f312a1fe6c2520d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 May 2026 18:29:08 +0800 Subject: [PATCH 1177/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e1f290431..7c6365942 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' From 6a8bd496ae4a84a7e3bf4ccc482ead737405f5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 May 2026 18:29:45 +0800 Subject: [PATCH 1178/1285] Update kejilion.sh --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index c48516021..4c068fce6 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' From 8e69c76b3f989fe898d68669bef62c1e21f635b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Wed, 20 May 2026 18:32:08 +0800 Subject: [PATCH 1179/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 1b7d05b11..4933be98a 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1511,4 +1511,6 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 2026-05-02 v4.5.0 系统工具BBRv3更新linux-xanmod官方部署方法。 系统工具一键重装系统功能新增Ubuntu26.04安装和Fedora44/43版本安装。 - +------------------------ +2026-05-20 v4.5.1 +应用市场 Hermes 管理增加新版本检测和API模型列表一致性同步功能。 From 4fd2abd1e83b83794173c63fbfec6603d8d23208 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 18:42:12 +0800 Subject: [PATCH 1180/1285] fix: resolve PyYAML ModuleNotFoundError by prioritizing hermes venv python --- hermes_manager.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 1e762cac2..d94732eef 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -22,7 +22,14 @@ fi CONFIG_FILE="$HOME/.hermes/config.yaml" config_tool() { - python3 - "$CONFIG_FILE" "$@" <<'EOF' + # 优先使用 Hermes Agent 自身的虚拟环境 Python,以确保 PyYAML (yaml) 依赖可用 + local python_bin="python3" + if [ -f "$HOME/.hermes/hermes-agent/venv/bin/python3" ]; then + python_bin="$HOME/.hermes/hermes-agent/venv/bin/python3" + elif [ -f "$HOME/.hermes/hermes-agent/venv/bin/python" ]; then + python_bin="$HOME/.hermes/hermes-agent/venv/bin/python" + fi + $python_bin - "$CONFIG_FILE" "$@" <<'EOF' import sys, yaml, json, os path = sys.argv[1] From 0d87ea43651c0606ab7e7a548fecc61c18bd4c14 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 21:10:08 +0800 Subject: [PATCH 1181/1285] feat: group API display in submenu with model count and latency --- hermes_manager.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index d94732eef..ce9a4278e 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -101,6 +101,40 @@ try: groups.append({"name": g, "count": cnt}) print(json.dumps(groups)) + elif action == "list_groups_latency": + import threading, urllib.request, time + ps = data.get('custom_providers', []) + groups = {} + for p in (ps if isinstance(ps, list) else []): + name = p.get('name', '') + g = name.split('/')[0] if '/' in name else name + if g not in groups: + groups[g] = {'name': g, 'base_url': p.get('base_url', ''), 'api_key': p.get('api_key', ''), 'count': 0} + groups[g]['count'] += 1 + results = {} + def worker(g, url, key): + start = time.time() + try: + url = url.rstrip('/') + '/models' + req = urllib.request.Request(url, headers={'Authorization': f'Bearer {key}'} if key else {}) + with urllib.request.urlopen(req, timeout=1.5) as r: + r.read() + results[g] = f"{int((time.time() - start) * 1000)}ms" + except urllib.error.HTTPError: + results[g] = f"{int((time.time() - start) * 1000)}ms" + except Exception: + results[g] = "timeout" + threads = [] + for g, info in groups.items(): + t = threading.Thread(target=worker, args=(g, info['base_url'], info['api_key'])) + t.start() + threads.append(t) + for t in threads: + t.join() + out = [] + for g, info in groups.items(): + out.append({'name': g, 'base_url': info['base_url'], 'count': info['count'], 'latency': results.get(g, 'N/A')}) + print(json.dumps(out)) elif action == "switch": n, u, k, m = sys.argv[3:7] data['model'] = {"default": m, "provider": "custom", "base_url": u, "api_key": k} @@ -379,11 +413,30 @@ api_management_submenu() { echo -e "${CYAN}当前激活模型:${NC} ${GREEN}$(echo $info | jq -r .m)${NC}" echo -e "---------------------------------------" echo -e "${CYAN}已配置 API 列表:${NC}" - ps_list=$(config_tool list_p) - if [ "$(echo "$ps_list" | jq '. | length')" -eq 0 ]; then + local groups_lat_json + groups_lat_json=$(config_tool list_groups_latency) + if [ "$(echo "$groups_lat_json" | jq '. | length' 2>/dev/null)" -eq 0 ] 2>/dev/null || [ -z "$groups_lat_json" ]; then echo -e " ${YELLOW}(暂无配置)${NC}" else - echo "$ps_list" | jq -r '.[] | " ● [\(.name)] \(.model) | \(.base_url)"' + while read -r row; do + local g_name g_url g_count g_latency lat_color lat_num + g_name=$(echo "$row" | jq -r .name) + g_url=$(echo "$row" | jq -r .base_url) + g_count=$(echo "$row" | jq -r .count) + g_latency=$(echo "$row" | jq -r .latency) + lat_color="${GREEN}" + if [ "$g_latency" = "timeout" ] || [ "$g_latency" = "N/A" ]; then + lat_color="${RED}" + elif [[ "$g_latency" =~ ^[0-9]+ms$ ]]; then + lat_num=$(echo "$g_latency" | tr -d 'ms') + if [ "$lat_num" -gt 800 ]; then + lat_color="${RED}" + elif [ "$lat_num" -gt 300 ]; then + lat_color="${YELLOW}" + fi + fi + echo -e " ● [${g_name}] (${g_count} 个模型) | 延迟: ${lat_color}${g_latency}${NC} | ${g_url}" + done < <(echo "$groups_lat_json" | jq -c '.[]') fi echo -e "---------------------------------------" echo -e "1. ${YELLOW}切换模型 (带测速)${NC}" From e9ea1abe94d85cf90ef524b474b1a004b4daaa16 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 21:24:48 +0800 Subject: [PATCH 1182/1285] fix: bulletproof virtualenv python and config.yaml detection to prevent ModuleNotFoundError: No module named 'yaml' --- hermes_manager.sh | 69 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index ce9a4278e..e87708e30 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -22,13 +22,70 @@ fi CONFIG_FILE="$HOME/.hermes/config.yaml" config_tool() { - # 优先使用 Hermes Agent 自身的虚拟环境 Python,以确保 PyYAML (yaml) 依赖可用 - local python_bin="python3" - if [ -f "$HOME/.hermes/hermes-agent/venv/bin/python3" ]; then - python_bin="$HOME/.hermes/hermes-agent/venv/bin/python3" - elif [ -f "$HOME/.hermes/hermes-agent/venv/bin/python" ]; then - python_bin="$HOME/.hermes/hermes-agent/venv/bin/python" + # 自动适配 CONFIG_FILE 路径 + if [ ! -f "$CONFIG_FILE" ]; then + local p + for p in "/root/.hermes/config.yaml" /home/*/.hermes/config.yaml; do + if [ -f "$p" ]; then + CONFIG_FILE="$p" + break + fi + done + fi + + # 寻找可用的 Python 解释器,优先使用带有 pyyaml (yaml) 的环境 + local python_bin="" + + # 1. 尝试从 command -v hermes 指向的文件的 shebang 中提取 python 路径 + local hermes_cmd + hermes_cmd=$(command -v hermes) + if [ -n "$hermes_cmd" ] && [ -f "$hermes_cmd" ]; then + local shebang + shebang=$(head -n 1 "$hermes_cmd" 2>/dev/null) + if [[ "$shebang" =~ ^#\! ]]; then + local potential_py="${shebang#\#!}" + if [ -f "$potential_py" ]; then + # 检查该 interpreter 是否有 yaml 模块 + if "$potential_py" -c "import yaml" >/dev/null 2>&1; then + python_bin="$potential_py" + fi + fi + fi + fi + + # 2. 尝试从常见绝对路径查找 + if [ -z "$python_bin" ]; then + local paths=( + "$HOME/.hermes/hermes-agent/venv/bin/python3" + "$HOME/.hermes/hermes-agent/venv/bin/python" + "/root/.hermes/hermes-agent/venv/bin/python3" + "/root/.hermes/hermes-agent/venv/bin/python" + "$HOME/.hermes/hermes-agent/.venv/bin/python3" + "/root/.hermes/hermes-agent/.venv/bin/python3" + /home/*/.hermes/hermes-agent/venv/bin/python3 + /home/*/.hermes/hermes-agent/venv/bin/python + /home/*/.hermes/hermes-agent/.venv/bin/python3 + ) + local p + for p in "${paths[@]}"; do + if [ -f "$p" ]; then + if "$p" -c "import yaml" >/dev/null 2>&1; then + python_bin="$p" + break + fi + fi + done + fi + + # 3. 兜底退回到系统全局 python3 或 python + if [ -z "$python_bin" ]; then + if command -v python3 >/dev/null 2>&1; then + python_bin="python3" + else + python_bin="python" + fi fi + $python_bin - "$CONFIG_FILE" "$@" <<'EOF' import sys, yaml, json, os From 90940650d98bd29e3861ec9b47430abd760c4098 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 21:29:24 +0800 Subject: [PATCH 1183/1285] perf: skip URL probe and set to N/A if API base_url is invalid or empty --- hermes_manager.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hermes_manager.sh b/hermes_manager.sh index e87708e30..c94f2824f 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -170,6 +170,9 @@ try: groups[g]['count'] += 1 results = {} def worker(g, url, key): + if not url or not (url.startswith('http://') or url.startswith('https://')): + results[g] = "N/A" + return start = time.time() try: url = url.rstrip('/') + '/models' From 80d6ee7d59e39ea85d7b68a57a9e489d92eb5d75 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 20 May 2026 21:43:19 +0800 Subject: [PATCH 1184/1285] fix: trace bash wrappers for hermes cmd and add /usr/local/lib/hermes-agent paths for python detection --- hermes_manager.sh | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index c94f2824f..48235598f 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -36,21 +36,45 @@ config_tool() { # 寻找可用的 Python 解释器,优先使用带有 pyyaml (yaml) 的环境 local python_bin="" - # 1. 尝试从 command -v hermes 指向的文件的 shebang 中提取 python 路径 + # 1. 尝试从 command -v hermes 指向的文件的 shebang/内容中提取 python 路径 local hermes_cmd hermes_cmd=$(command -v hermes) if [ -n "$hermes_cmd" ] && [ -f "$hermes_cmd" ]; then + # A. 检查第一行是否是 shebang local shebang shebang=$(head -n 1 "$hermes_cmd" 2>/dev/null) if [[ "$shebang" =~ ^#\! ]]; then local potential_py="${shebang#\#!}" if [ -f "$potential_py" ]; then - # 检查该 interpreter 是否有 yaml 模块 if "$potential_py" -c "import yaml" >/dev/null 2>&1; then python_bin="$potential_py" fi fi fi + # B. 检查是否是 Bash wrapper,追踪其实际指向的 bin 并提取 python3 + if [ -z "$python_bin" ]; then + local wrapped_bin + wrapped_bin=$(grep -Eo '"/[^"]+/venv/bin/hermes"' "$hermes_cmd" | tr -d '"' | head -n 1) + if [ -z "$wrapped_bin" ]; then + wrapped_bin=$(grep -Eo '/[a-zA-Z0-9_\.\-]+/hermes-agent/venv/bin/hermes' "$hermes_cmd" | head -n 1) + fi + if [ -n "$wrapped_bin" ] && [ -f "$wrapped_bin" ]; then + local wrapped_shebang + wrapped_shebang=$(head -n 1 "$wrapped_bin" 2>/dev/null) + if [[ "$wrapped_shebang" =~ ^#\! ]]; then + local potential_py="${wrapped_shebang#\#!}" + if [ -f "$potential_py" ] && "$potential_py" -c "import yaml" >/dev/null 2>&1; then + python_bin="$potential_py" + fi + fi + if [ -z "$python_bin" ]; then + local potential_py="${wrapped_bin%/hermes}/python3" + if [ -f "$potential_py" ] && "$potential_py" -c "import yaml" >/dev/null 2>&1; then + python_bin="$potential_py" + fi + fi + fi + fi fi # 2. 尝试从常见绝对路径查找 @@ -60,8 +84,14 @@ config_tool() { "$HOME/.hermes/hermes-agent/venv/bin/python" "/root/.hermes/hermes-agent/venv/bin/python3" "/root/.hermes/hermes-agent/venv/bin/python" + "/usr/local/lib/hermes-agent/venv/bin/python3" + "/usr/local/lib/hermes-agent/venv/bin/python" + "/usr/lib/hermes-agent/venv/bin/python3" + "/usr/lib/hermes-agent/venv/bin/python" "$HOME/.hermes/hermes-agent/.venv/bin/python3" "/root/.hermes/hermes-agent/.venv/bin/python3" + "/usr/local/lib/hermes-agent/.venv/bin/python3" + "/usr/lib/hermes-agent/.venv/bin/python3" /home/*/.hermes/hermes-agent/venv/bin/python3 /home/*/.hermes/hermes-agent/venv/bin/python /home/*/.hermes/hermes-agent/.venv/bin/python3 From 8031eb7105c54ddd974c7309ee188a18b8d8efb1 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 21 May 2026 01:11:31 +0800 Subject: [PATCH 1185/1285] perf: speed up hermes manager status checks --- hermes_manager.sh | 111 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 48235598f..38d6c3c53 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -769,11 +769,34 @@ check_installed() { if command -v hermes >/dev/null 2>&1; then return 0; else return 1; fi } -# 获取版本号 +# 获取版本号(优先直接读取安装元数据,避免启动 hermes CLI 导致菜单变慢) get_version() { - if check_installed; then - hermes --version 2>/dev/null | sed -n '1p' + if ! check_installed; then + return + fi + + local hermes_bin python_bin venv_dir metadata version + hermes_bin="$(command -v hermes 2>/dev/null)" + + # pip/venv 生成的 hermes 入口第一行通常指向 venv/bin/python3。 + # 直接读 dist-info/METADATA,比执行 `hermes --version` 更快。 + if [ -n "$hermes_bin" ] && [ -r "$hermes_bin" ]; then + python_bin="$(sed -n '1s/^#!//p' "$hermes_bin" 2>/dev/null)" + if [ -n "$python_bin" ] && [ -x "$python_bin" ]; then + venv_dir="$(dirname "$(dirname "$python_bin")")" + for metadata in "$venv_dir"/lib/python*/site-packages/hermes_agent-*.dist-info/METADATA; do + [ -r "$metadata" ] || continue + version="$(sed -n 's/^Version: //p' "$metadata" 2>/dev/null | sed -n '1p')" + if [ -n "$version" ]; then + echo "Hermes Agent v${version#v}" + return + fi + done + fi fi + + # 兜底:兼容非标准安装方式。 + hermes --version 2>/dev/null | sed -n '1p' } # 提取语义版本号,例如 v0.13.0 / 0.13.0 @@ -786,21 +809,64 @@ version_lt() { [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n 1)" != "$2" ] && [ "$1" != "$2" ] } -# 获取 PyPI 最新版本,失败时静默,避免影响主菜单显示 +# 获取 PyPI 最新版本:优先读缓存,过期后后台刷新,避免拖慢主菜单显示 get_latest_version() { - python3 - <<'PY' 2>/dev/null + local cache_dir cache_file lock_dir now cache_mtime lock_mtime ttl lock_ttl version + cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/hermes-manager" + cache_file="$cache_dir/hermes-agent-latest-version" + lock_dir="$cache_dir/hermes-agent-latest-version.lock" + ttl=21600 # 6 小时内不重复联网检查 + lock_ttl=300 # 后台刷新失败时,5 分钟内不重复启动刷新任务 + now="$(date +%s 2>/dev/null || echo 0)" + + mkdir -p "$cache_dir" 2>/dev/null || true + + # 缓存未过期:直接返回,菜单无网络等待。 + if [ -r "$cache_file" ]; then + cache_mtime="$(stat -c %Y "$cache_file" 2>/dev/null || echo 0)" + if [ $((now - cache_mtime)) -lt "$ttl" ]; then + sed -n '1p' "$cache_file" 2>/dev/null + return + fi + # 缓存过期也先返回旧值,刷新放后台做,避免卡界面。 + version="$(sed -n '1p' "$cache_file" 2>/dev/null)" + fi + + # 后台刷新:用锁避免每次打开菜单都发起 PyPI 请求。 + if mkdir "$lock_dir" 2>/dev/null; then + ( + python3 - "$cache_file" <<'PY' 2>/dev/null import json +import sys +import tempfile import urllib.request +from pathlib import Path +cache_file = Path(sys.argv[1]) try: - with urllib.request.urlopen('https://pypi.org/pypi/hermes-agent/json', timeout=3) as response: + with urllib.request.urlopen('https://pypi.org/pypi/hermes-agent/json', timeout=2) as response: data = json.load(response) version = (data.get('info') or {}).get('version') or '' if version: - print('v' + version.lstrip('v')) + cache_file.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile('w', dir=str(cache_file.parent), delete=False) as f: + f.write('v' + version.lstrip('v') + '\n') + tmp = f.name + Path(tmp).replace(cache_file) except Exception: pass PY + rmdir "$lock_dir" 2>/dev/null || true + ) >/dev/null 2>&1 & + elif [ -d "$lock_dir" ]; then + lock_mtime="$(stat -c %Y "$lock_dir" 2>/dev/null || echo "$now")" + if [ $((now - lock_mtime)) -gt "$lock_ttl" ]; then + rmdir "$lock_dir" 2>/dev/null || true + fi + fi + + # 首次无缓存时不输出,不阻塞菜单;下次打开菜单会读到后台刷新结果。 + [ -n "$version" ] && echo "$version" } # 检查是否有新版本 @@ -822,15 +888,30 @@ get_update_notice() { # 获取网关状态 get_gateway_status() { - if check_installed; then - # 匹配后台 gateway 进程或 systemd 服务 - if pgrep -f "hermes_cli.main gateway" > /dev/null || pgrep -f "hermes gateway run" > /dev/null || pgrep -f "hermes-gateway" > /dev/null; then - echo -e "${GREEN}运行中${NC}$(get_update_notice)" - else - echo -e "${RED}已停止${NC}$(get_update_notice)" - fi - else + if ! check_installed; then echo -e "${RED}未安装${NC}" + return + fi + + # 优先检查 Hermes 安装的 user systemd 服务,速度快且比扫进程更准。 + if command -v systemctl >/dev/null 2>&1; then + case "$(systemctl --user is-active hermes-gateway.service 2>/dev/null)" in + active) + echo -e "${GREEN}运行中${NC}$(get_update_notice)" + return + ;; + inactive|failed|activating|deactivating) + echo -e "${RED}已停止${NC}$(get_update_notice)" + return + ;; + esac + fi + + # 兜底:兼容非 systemd 或手动启动的 gateway。 + if pgrep -u "$(id -u)" -f "(^|[[:space:]])(([^[:space:]]*/)?python[0-9.]*[[:space:]]+-m[[:space:]]+hermes_cli\.main[[:space:]]+gateway[[:space:]]+run|([^[:space:]]*/)?hermes[[:space:]]+gateway[[:space:]]+run|hermes-gateway)([[:space:]]|$)" >/dev/null 2>&1; then + echo -e "${GREEN}运行中${NC}$(get_update_notice)" + else + echo -e "${RED}已停止${NC}$(get_update_notice)" fi } From a820bef565c46894ff3d21100f40681263b8484a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 21 May 2026 09:35:30 +0800 Subject: [PATCH 1186/1285] Update hermes_manager.sh --- hermes_manager.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hermes_manager.sh b/hermes_manager.sh index 38d6c3c53..169ce0364 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -924,6 +924,14 @@ refresh_hermes_path() { fi } +add_app_id() { +mkdir -p /home/docker +touch /home/docker/appno.txt +grep -qxF "115" /home/docker/appno.txt || echo "115" >> /home/docker/appno.txt + +} + + # 主菜单UI show_menu() { @@ -957,6 +965,7 @@ show_menu() { refresh_hermes_path hermes gateway install hermes gateway start + add_app_id ;; 2) if check_installed; then @@ -995,6 +1004,7 @@ show_menu() { if check_installed; then echo -e "${YELLOW}正在检查更新...${NC}" hermes update + add_app_id else echo -e "${RED}请先安装 Hermes。${NC}"; fi ;; 8) @@ -1002,6 +1012,7 @@ show_menu() { read -p "确定要卸载 Hermes 吗?所有数据将被清除。(y/N): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then hermes uninstall + sed -i "/\b115\b/d" /home/docker/appno.txt else echo "已取消。"; fi else echo -e "${RED}请先安装 Hermes。${NC}"; fi ;; From 7b13859a8006bcd3b6a6408001a88a8ec2904f5b Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 23 May 2026 22:20:12 +0800 Subject: [PATCH 1187/1285] Update Windows 7 reinstall ISO source --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7c6365942..f505456cf 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重装windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='Windows 7 PROFESSIONAL' reboot exit ;; diff --git a/kejilion.sh b/kejilion.sh index 4c068fce6..2a5f55774 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重装windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='Windows 7 PROFESSIONAL' reboot exit ;; From 27c8e801f19bfaa8ce88ebb1cb8d3d39c3de69b2 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 24 May 2026 08:10:19 +0800 Subject: [PATCH 1188/1285] Fix Windows 7 reinstall image name --- cn/kejilion.sh | 2 +- en/kejilion.sh | 2 +- ir/kejilion.sh | 2 +- jp/kejilion.sh | 2 +- kejilion.sh | 2 +- kr/kejilion.sh | 2 +- ru/kejilion.sh | 2 +- tw/kejilion.sh | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f505456cf..82be62a98 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重装windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/en/kejilion.sh b/en/kejilion.sh index ee329d712..1b19b9d3a 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Reinstall windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/ir/kejilion.sh b/ir/kejilion.sh index 184aecff1..354b351ca 100644 --- a/ir/kejilion.sh +++ b/ir/kejilion.sh @@ -4128,7 +4128,7 @@ dd_xitong() { 43) send_stats "نصب ویندوز 7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index ac3371b0d..11715c3d3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Windows7を再インストールする" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/kejilion.sh b/kejilion.sh index 2a5f55774..5dfb0eb3b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重装windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 32a13edb2..d56b03ff7 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Windows7을 다시 설치하세요." dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/ru/kejilion.sh b/ru/kejilion.sh index 4be495e0f..622d63220 100644 --- a/ru/kejilion.sh +++ b/ru/kejilion.sh @@ -4155,7 +4155,7 @@ dd_xitong() { 43) send_stats "Переустановите Windows 7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index d3c9b3a1e..1ecc0d2ed 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重裝windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='Windows 7 PROFESSIONAL' + bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' reboot exit ;; From f353e45d54ac7a6938c3cd41fe58c3ec73668879 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 24 May 2026 06:19:57 +0000 Subject: [PATCH 1189/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-05-24=2006:19:57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 74 +++--- jp/kejilion.sh | 166 +++++++------- kr/kejilion.sh | 172 +++++++------- tw/kejilion.sh | 606 ++++++++++++++++++++++++------------------------- 4 files changed, 509 insertions(+), 509 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 1b19b9d3a..0808bcbb0 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2310,7 +2310,7 @@ check_ldnmp_mode() { if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="High performance mode" else - mode_info=" 标准模式" + mode_info="Standard mode" fi @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3349,7 +3349,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear send_stats "Unable to install LDNMP environment again" - echo -e "${gl_huang}hint:${gl_bai}The website building environment has been installed. No need to install again!" + echo -e "${gl_huang}hint:${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -5094,7 +5094,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5529,7 +5529,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Reinstall windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; @@ -6297,7 +6297,7 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}Applied${applied}Item parameter ${skipped:+, skip${skipped} 项不支持的参数}${gl_bai}" + echo -e "${gl_lv}Applied${applied}Item parameter ${skipped:+, skip${skipped}Item unsupported parameter}${gl_bai}" # ── Transparent large page ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then @@ -7189,7 +7189,7 @@ mount_partition() { return 1 fi - echo "The partition was successfully mounted to$MOUNT_POINT" + echo "Partition successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7701,7 +7701,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -8175,7 +8175,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8336,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -10567,8 +10567,8 @@ PY start_bot() { - echo "Start OpenClaw..." - send_stats "Start OpenClaw..." + echo "Starting OpenClaw..." + send_stats "Starting OpenClaw..." start_gateway break_end } @@ -12211,7 +12211,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12339,7 +12339,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -13078,7 +13078,7 @@ if os.path.isdir(agents_root): echo "Backup directory:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "No backup file yet" + echo "No backup files yet" return 0 fi @@ -13870,7 +13870,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ Model file already exists:$model_path" + echo "✅ The model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14568,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: write file directly + # Fallback: Write the file directly echo "$json_payload" > "$approvals_file" } @@ -15160,7 +15160,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw multi-agent - remove routing binding" + send_stats "OpenClaw multi-agent - remove route binding" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "Please enter the agent ID:" agent_id @@ -15599,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15970,7 +15970,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16301,7 +16301,7 @@ while true; do } - local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -18293,7 +18293,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -19377,7 +19377,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -19450,7 +19450,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19848,7 +19848,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -20193,7 +20193,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21132,7 +21132,7 @@ EOF echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. Set time zone to${gl_huang}Shanghai${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" auto_optimize_dns @@ -21488,7 +21488,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21522,7 +21522,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21639,7 +21639,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21920,7 +21920,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 11715c3d3..b9a4b4048 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' @@ -867,7 +867,7 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2678,7 +2678,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2697,7 +2697,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3275,7 +3275,7 @@ EOF } # メイン構成/オーバーレイ構成エディター (nano) を直接開きます。 -# 最初に /etc/fail2ban/jail.d/sshd.local を編集し (より安全です)、存在しない場合は作成します +# /etc/fail2ban/jail.d/sshd.local を最初に編集し (より安全です)、存在しない場合は作成します f2b_edit_config() { root_use install nano @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4838,7 +4838,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Windows7を再インストールする" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; @@ -5621,7 +5621,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません。XanMod ソースを構成できません" + echo "システムコードネームを取得できません、XanMod ソースを構成できません" return 1 fi @@ -6013,7 +6013,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6377,8 +6377,8 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" - local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) + send_stats "Linux カーネルのチューニング管理" + local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" if [ -n "$current_mode" ]; then @@ -6653,7 +6653,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "ごみ箱が有効になっている場合、削除されたファイルはごみ箱に移動されます。" + echo "ごみ箱が有効になっていると、削除されたファイルはごみ箱に移動されます。" sleep 2 ;; 2) @@ -6692,9 +6692,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6736,7 +6736,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6824,7 +6824,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "Enter を押して続行します..." done } @@ -7172,7 +7172,7 @@ mount_partition() { return 1 fi - # ファイルシステムの種類を取得する + # ファイルシステムのタイプを取得する FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then echo "ファイル システム タイプを取得できません!" @@ -7189,7 +7189,7 @@ mount_partition() { return 1 fi - echo "パーティションは正常にマウントされました$MOUNT_POINT" + echo "パーティションが正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7324,7 +7324,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "Enter を押して続行します..." done } @@ -7583,7 +7583,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter キーを押して続行します..." + read -e -p "Enter を押して続行します..." done } @@ -8137,7 +8137,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8336,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -9082,7 +9082,7 @@ linux_ldnmp() { echo -e "${gl_huang}21. ${gl_bai}nginxのみをインストールする${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}サイトリダイレクト" echo -e "${gl_huang}23. ${gl_bai}サイト リバース プロキシ - IP+ポート${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}サイト リバース プロキシ ドメイン名" echo -e "${gl_huang}25. ${gl_bai}Bitwarden パスワード管理プラットフォームをインストールする${gl_huang}26. ${gl_bai}Halo ブログ サイトをインストールする" - echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}站点反向代理-负载均衡" + echo -e "${gl_huang}27. ${gl_bai}AI絵画プロンプトワードジェネレーターをインストールする${gl_huang}28. ${gl_bai}サイト リバース プロキシ負荷分散" echo -e "${gl_huang}29. ${gl_bai}ストリーム 4 層プロキシ転送${gl_huang}30. ${gl_bai}カスタム静的サイト" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}サイトデータ管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}サイト全体のデータをバックアップする" @@ -9282,7 +9282,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9757,7 +9757,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/ のような、index.html へのパスを入力してください)$yuming/index/): " index_lujing + read -e -p "(/home/web/html/ のような)index.html へのパスを入力してください。$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -10442,7 +10442,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10567,8 +10567,8 @@ PY start_bot() { - echo "OpenClaw を開始します..." - send_stats "OpenClaw を開始します..." + echo "OpenClaw を開始しています..." + send_stats "OpenClaw を開始しています..." start_gateway break_end } @@ -10826,7 +10826,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにします) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11550,7 +11550,7 @@ PY echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. APIの追加" + echo "1. APIを追加する" echo "2. APIプロバイダーモデルリストを同期する" echo "3. API タイプの切り替え (完了/応答)" echo "4. APIの削除" @@ -12285,7 +12285,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12330,7 +12330,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12803,7 +12803,7 @@ EOF echo "バックアップ ファイルは次の方法でダウンロードできます。" echo "- ローカルパス:$file_path" echo "- scp の例: scp root@yourserver:$file_path ./" - echo "- またはSFTPクライアントを使用してダウンロード" + echo "- またはSFTPクライアントを使用してダウンロードします" } openclaw_prepare_import_archive() { @@ -13078,7 +13078,7 @@ if os.path.isdir(agents_root): echo "バックアップディレクトリ:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "まだバックアップファイルがありません" + echo "バックアップファイルはまだありません" return 0 fi @@ -13458,7 +13458,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("基礎となるソリューション: %s" % backend) + print("基本的なソリューション: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) @@ -13777,7 +13777,7 @@ PY echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -14027,7 +14027,7 @@ EOF } openclaw_memory_offer_restart() { - echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14102,7 +14102,7 @@ EOF echo "" echo "QMD: qmd コマンドに依存する軽量インデックス (ネットワーク制約に適しています)" echo "ローカル: 埋め込みモデル ファイルに依存するローカル ベクトル取得" - echo "Auto : 自动推荐(基于可用性 + 网络探测)" + echo "自動: 自動推奨 (可用性 + ネットワーク検出に基づく)" echo "---------------------------------------" echo "1. QMD の切り替え (自動展開/既にインストールされている場合はスキップ)" echo "2. ローカルに切り替えます (自動展開/既にインストールされている場合はスキップ)" @@ -14191,7 +14191,7 @@ EOF echo "書類:$file" echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示される行数を入力してください (Enter を押してデフォルトにします)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14285,8 +14285,8 @@ EOF echo "2. メモリファイルを表示する" echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" - echo "5. 検索テスト (インデックスが機能していることを確認する)" - echo "6. ディープステートの検出 (組み込みモデルのチェック)" + echo "5. 検索テスト (インデックスが機能していることを確認します)" + echo "6. ディープステート検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14668,7 +14668,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14705,7 +14705,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -15535,7 +15535,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期構成ウィザード" + 11) send_stats "初期設定ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15599,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15629,7 +15629,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" @@ -15647,7 +15647,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -15899,7 +15899,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -16736,7 +16736,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、PDF ファイルに対して分割マージ、変換、再編成、画像の追加、回転、圧縮などのさまざまな操作を実行できます。" + local docker_describe="これは、Docker を使用してローカルでホストされる強力な Web ベースの PDF 操作ツールで、分割マージ、変換、再編成、画像の追加、回転、圧縮など、PDF ファイルに対してさまざまな操作を実行できます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -16835,7 +16835,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -17736,7 +17736,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -17984,7 +17984,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18199,7 +18199,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチピクチャービデオマネージャー" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18293,7 +18293,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -18669,7 +18669,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -19440,7 +19440,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19778,7 +19778,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19788,7 +19788,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19800,7 +19800,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19851,7 +19851,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19861,7 +19861,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19876,7 +19876,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19964,7 +19964,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." } @@ -19979,7 +19979,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -19995,7 +19995,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter キーを押して続行します..." + read -erp "Enter を押して続行します..." } while true; do @@ -20008,7 +20008,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数(ソース)をリロードします。" + echo "6. 環境変数 (ソース) をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20587,7 +20587,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -21374,7 +21374,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21394,7 +21394,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21488,7 +21488,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21517,7 +21517,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21639,7 +21639,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21757,7 +21757,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" + echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -21920,14 +21920,14 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21959,7 +21959,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -22160,7 +22160,7 @@ else shift case $1 in install|安装) - send_stats "Docker をすばやくインストールする" + send_stats "Dockerを素早くインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d56b03ff7..95ea0538f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -513,17 +513,17 @@ while true; do ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 재정의하며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3725,7 +3725,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5058,7 +5058,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원본 Authorized_keys 파일이 백업되었습니다." + echo "원래 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "Windows7을 다시 설치하세요." dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; @@ -5722,7 +5722,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" server_reboot } @@ -5732,7 +5732,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot } @@ -5882,7 +5882,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5900,7 +5900,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5936,7 +5936,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6636,7 +6636,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8336,7 +8336,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8569,7 +8569,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8884,7 +8884,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9619,7 +9619,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -10506,7 +10506,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10567,8 +10567,8 @@ PY start_bot() { - echo "OpenClaw를 시작하세요..." - send_stats "OpenClaw를 시작하세요..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_gateway break_end } @@ -11040,7 +11040,7 @@ if not isinstance(providers, dict) or not providers: provider = providers.get(target) if not isinstance(provider, dict): - print(f'❌ 未找到 provider: {target}') + print(f'❌ 제공자: {target}을(를) 찾을 수 없습니다') raise SystemExit(2) agents = work.setdefault('agents', {}) @@ -11482,7 +11482,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장 사항" + send_stats "OpenClaw API 공급업체 권장사항" clear echo "" @@ -11845,7 +11845,7 @@ PYTHON_EOF return 1 fi - # 빠른 찾기를 위해 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -11879,7 +11879,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11947,7 +11947,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12104,7 +12104,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -12188,7 +12188,7 @@ PYTHON_EOF echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안의 ID만 복사):" echo "--------------------------------------------------------" echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" @@ -12211,7 +12211,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반환" + echo "0) 반품" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12235,7 +12235,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인 중:$plugin_id" + echo "🔍 플러그인 상태 확인:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12263,7 +12263,7 @@ PYTHON_EOF continue fi - echo "📥 本地未发现,尝试下载安装: $plugin_full" + echo "📥 로컬에서 찾을 수 없습니다. 다운로드하여 설치해 보세요.$plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -12319,7 +12319,7 @@ PYTHON_EOF openclaw skills list echo "----------------------------------------" - # 输出推荐的实用技能列表 + # 추천 실기 목록 출력 echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" echo "github # GitHub 문제/PR/CI 관리(gh CLI)" echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." @@ -12339,7 +12339,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반환" + echo "0) 반품" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12683,9 +12683,9 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi + if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" break_end ;; @@ -12913,7 +12913,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end } @@ -13078,7 +13078,7 @@ if os.path.isdir(agents_root): echo "백업 디렉터리:$backup_root" if [ ${#OPENCLAW_BACKUP_FILES[@]} -eq 0 ]; then - echo "아직 백업 파일이 없습니다" + echo "아직 백업 파일이 없습니다." return 0 fi @@ -13776,7 +13776,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -13827,7 +13827,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다." + echo "✅ memory.qmd.command가 정확합니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -13935,7 +13935,7 @@ EOF OPENCLAW_MEMORY_EXPECT_SIZE="약 350-600MB" ;; *) - echo "❌ 알 수 없는 해결 방법:$scheme" + echo "❌ 알 수 없는 해결책:$scheme" return 1 ;; esac @@ -14019,7 +14019,7 @@ EOF openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" >/dev/null 2>&1 ;; *) - echo "❌ 알 수 없는 해결 방법:$scheme" + echo "❌ 알 수 없는 해결책:$scheme" return 1 esac echo "✅ 메모리 체계 구성이 업데이트되었습니다." @@ -14073,7 +14073,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14568,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일 직접 쓰기 + # 대체: 파일을 직접 작성 echo "$json_payload" > "$approvals_file" } @@ -14656,7 +14656,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14675,7 +14675,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14686,14 +14686,14 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14720,7 +14720,7 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "호스트 차단 구성을 정리합니다..." - # CLI를 통해 승인 구성을 지우는 데 우선 순위를 두고 파일을 직접 삭제하는 것으로 대체합니다. + # CLI를 통해 승인 구성을 지우는 데 우선순위를 두고 파일을 직접 삭제하는 방법으로 대체합니다. if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then true else @@ -15276,7 +15276,7 @@ print("✅멀티에이전트 헬스체크 완료") while true; do clear echo "=======================================" - echo "OpenClaw 多智能体管理" + echo "OpenClaw 다중 에이전트 관리" echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" @@ -15599,7 +15599,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15659,7 +15659,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15870,7 +15870,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -15890,7 +15890,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15970,7 +15970,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16002,7 +16002,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16380,7 +16380,7 @@ while true; do check_docker_app clear echo -e "썬더 풀 서비스$check_docker" - echo "레이치(Leichi)는 창팅테크놀로지가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." + echo "레이치(Leichi)는 창팅테크놀로지(Changting Technology)가 개발한 WAF 사이트 방화벽 프로그램 패널로, 자동화된 방어를 위해 사이트를 반전시킬 수 있다." echo "영상 소개: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16570,7 +16570,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16736,7 +16736,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17241,7 +17241,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17403,7 +17403,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17736,7 +17736,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18293,7 +18293,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -18924,7 +18924,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19848,7 +19848,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -19991,7 +19991,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드" + send_stats "환경 변수 다시 로드 중" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -20003,7 +20003,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20886,7 +20886,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -20930,7 +20930,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21488,7 +21488,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21563,8 +21563,8 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21636,10 +21636,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21920,7 +21920,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21959,7 +21959,7 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 1ecc0d2ed..b63a9489c 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.0" +sh_v="4.5.1" gl_hui='\e[37m' @@ -123,8 +123,8 @@ CheckFirstRun_false() { # 提示使用者同意條款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" - echo "首次使用脚本,请先阅读并同意用户许可协议。" + echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo "首次使用腳本,請先閱讀並同意使用者授權協議。" echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "是否同意以上條款? (y/n):" user_input @@ -179,7 +179,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供軟體包參數!" + echo "未提供软件包参数!" return 1 fi @@ -334,7 +334,7 @@ status() { if [ $? -eq 0 ]; then echo "$1服務狀態已顯示。" else - echo "錯誤:無法顯示$1 服务状态。" + echo "錯誤:無法顯示$1服務狀態。" fi } @@ -535,7 +535,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "刪除所有容器" + send_stats "删除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -634,7 +634,7 @@ while true; do case $sub_choice in 1) send_stats "拉取鏡像" - read -e -p "请输入镜像名(多个镜像名请用空格分隔): " imagenames + read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do echo -e "${gl_kjlan}正在取得鏡像:$name${gl_bai}" docker pull $name @@ -759,7 +759,7 @@ docker_ipv6_on() { echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker else - # 使用jq处理配置文件的更新 + # 使用jq處理設定檔的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") # 檢查目前配置是否已經有 ipv6 設定 @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}設定檔不存在${gl_bai}" return fi @@ -806,7 +806,7 @@ docker_ipv6_off() { # 比較原始配置與新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}目前已關閉ipv6訪問${gl_bai}" + echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -849,7 +849,7 @@ iptables_open() { open_port() { local ports=($@) # 将传入的参数转换为数组 if [ ${#ports[@]} -eq 0 ]; then - echo "请提供至少一个端口号" + echo "請提供至少一個連接埠號" return 1 fi @@ -860,7 +860,7 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 新增開啟規則 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi @@ -924,10 +924,10 @@ allow_ip() { install iptables for ip in "${ips[@]}"; do - # 删除已存在的阻止规则 + # 刪除已存在的阻止規則 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 添加允许规则 + # 新增允許規則 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "已放行IP$ip" @@ -1088,7 +1088,7 @@ iptables_panel() { save_iptables_rules while true; do clear - echo "高级防火墙管理" + echo "進階防火牆管理" send_stats "進階防火牆管理" echo "------------------------" iptables -L INPUT @@ -1106,7 +1106,7 @@ iptables_panel() { echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" echo "------------------------" echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" - echo "17. 解除指定国家IP限制" + echo "17. 解除指定國家IP限制" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -1162,7 +1162,7 @@ iptables_panel() { ;; 6) # IP 黑名單 - read -e -p "请输入封锁的IP或IP段: " c_ip + read -e -p "請輸入封鎖的IP或IP段:" c_ip block_ip $c_ip ;; 7) @@ -1174,11 +1174,11 @@ iptables_panel() { send_stats "清除指定IP" ;; 11) - # 允許 PING + # 允许 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允許PING" + send_stats "允许PING" ;; 12) # 禁用 PING @@ -1200,7 +1200,7 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; @@ -1240,7 +1240,7 @@ add_swap() { # 確保 /swapfile 不再被使用 swapoff /swapfile - # 删除旧的 /swapfile + # 刪除舊的 /swapfile rm -f /swapfile # 建立新的 swap 分割區 @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 判斷是否需要建立虛擬記憶體 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1311,7 +1311,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 建立必要的目錄和文件 + # 创建必要的目录和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "站点信息 证书到期时间" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1537,15 +1537,15 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "網域證書申請成功" + send_stats "域名证书申请成功" else send_stats "網域證書申請失敗" - echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + echo -e "${gl_hong}注意: ${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" - echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" + echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" echo "------------------------" echo "1. 重新申請 2. 匯入已有憑證 0. 退出" @@ -1570,7 +1570,7 @@ certs_status() { mkdir -p /home/web/certs # 1. 輸入憑證 (ECC 和 RSA 憑證開頭都是 BEGIN CERTIFICATE) - echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" + echo "請貼上 證書 (CRT/PEM) 內容 (以兩次回車結束):" local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break @@ -1638,7 +1638,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port + read -e -p "請輸入訪問/監聽端口,回車預設使用 80:" access_port access_port=${access_port:-80} fi } @@ -1788,7 +1788,7 @@ web_del() { send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1829,7 +1829,7 @@ nginx_waf() { sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 關閉 WAF:加上註釋 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -1889,7 +1889,7 @@ patch_wp_memory_limit() { sed -i "/define(['\"]WP_MEMORY_LIMIT['\"].*/d" "$FILE" sed -i "/define(['\"]WP_MAX_MEMORY_LIMIT['\"].*/d" "$FILE" - # 插入新定义,放在含 "Happy publishing" 的行前 + # 插入新定義,放在含 "Happy publishing" 的行前 awk -v insert="define('WP_MEMORY_LIMIT', '$MEMORY_LIMIT');\ndefine('WP_MAX_MEMORY_LIMIT', '$MAX_MEMORY_LIMIT');" \ ' /Happy publishing/ { @@ -1977,7 +1977,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # 開啟 Brotli:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2048,7 +2048,7 @@ nginx_zstd() { elif [ "$mode" == "off" ]; then - # 关闭 Zstd:加上注释 + # 關閉 Zstd:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) @@ -2279,7 +2279,7 @@ web_security() { 32) nginx_waf off - echo "站點WAF已關閉" + echo "站点WAF已关闭" send_stats "站點WAF已關閉" ;; @@ -2329,7 +2329,7 @@ check_nginx_compression() { zstd_status="" fi - # 检查 brotli 是否开启且未被注释 + # 檢查 brotli 是否開啟且未被註釋 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then br_status="br壓縮已開啟" else @@ -2366,7 +2366,7 @@ web_optimization() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "站点标准模式" + send_stats "站點標準模式" local cpu_cores=$(nproc) local connections=$((1024 * ${cpu_cores})) @@ -2403,11 +2403,11 @@ web_optimization() { optimize_balanced - echo "LDNMP環境已設定成 標準模式" + echo "LDNMP环境已设置成 标准模式" ;; 2) - send_stats "站點高效能模式" + send_stats "站点高性能模式" # nginx調優 local cpu_cores=$(nproc) @@ -2502,7 +2502,7 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker="${gl_lv}已安裝${gl_bai}" +# check_docker="${gl_lv}已安装${gl_bai}" # else # check_docker="${gl_hui}未安裝${gl_bai}" # fi @@ -2615,7 +2615,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 檢查並放行指定 IP + # 检查并放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2730,7 +2730,7 @@ block_host_port() { install iptables - # 拒绝其他所有 IP 访问 + # 拒絕其他所有 IP 訪問 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -2794,7 +2794,7 @@ clear_host_port_rules() { iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允許本機存取的規則 + # 清除允许本机访问的规则 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2880,7 +2880,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "5. 新增網域存取 6. 刪除網域存取" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}連接埠:" app_port + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3005,7 +3005,7 @@ docker_app_plus() { echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "5. 新增網域存取 6. 刪除網域存取" - echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" + echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3219,7 +3219,7 @@ f2b_sshd() { fi } -# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) +# 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) # 說明: # - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) # - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 @@ -3495,7 +3495,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+埠" + webname="反向代理-IP+端口" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3551,7 +3551,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="反向代理-負載平衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3562,7 +3562,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port + read -e -p "請輸入你的多個反代IP+埠以空格隔開(例如 127.0.0.1:3000 127.0.0.1:3002):" reverseproxy_port fi nginx_install_status @@ -3602,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "服务名" "通訊類型" "本机地址" "後端地址" + printf "%-25s %-18s %-25s %-20s\n" "服務名" "通訊類型" "本機地址" "後端地址" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四層代理轉送工具$check_docker $update_status" + echo -e "Stream四层代理转发工具 $check_docker $update_status" echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模組,用於實現高效能的 傳輸層流量轉送和負載平衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3696,7 +3696,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "新增四層代理" + send_stats "添加四层代理" ;; 5) send_stats "編輯轉送配置" @@ -3707,7 +3707,7 @@ stream_panel() { send_stats "修改四層代理" ;; 6) - send_stats "删除转发配置" + send_stats "刪除轉送配置" read -e -p "請輸入你要刪除的服務名稱:" stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx @@ -3737,7 +3737,7 @@ ldnmp_Proxy_backend_stream() { fi # 取得監聽埠 - read -erp "请输入本机监听端口 (如 3306): " listen_port + read -erp "請輸入本機監聽埠 (如 3306):" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "連接埠必須是數字"; return 1 fi @@ -3868,7 +3868,7 @@ ldnmp_web_status() { echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" echo "5. 查看訪問日誌 6. 查看錯誤日誌" - echo "7. 编辑全局配置 8. 编辑站点配置" + echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" echo "20. 刪除指定站點數據" @@ -3878,7 +3878,7 @@ ldnmp_web_status() { read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in 1) - send_stats "申请域名证书" + send_stats "申請網域證書" read -e -p "請輸入你的網域名稱:" yuming install_certbot docker run --rm -v /etc/letsencrypt/:/etc/letsencrypt certbot/certbot delete --cert-name "$yuming" -n 2>/dev/null @@ -3890,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3931,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -4009,7 +4009,7 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "${panelname}是一款時下流行且強大的維運管理面板。" echo "官網介紹:$panelurl " echo "" @@ -4158,7 +4158,7 @@ add_forwarding_service() { read -e -p "請輸入內部網路連接埠:" local_port read -e -p "請輸入外網埠:" remote_port - # 將使用者輸入寫入設定檔 + # 将用户输入写入配置文件 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -4169,7 +4169,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name 已成功添加到 frpc.toml" docker restart frpc @@ -4180,8 +4180,8 @@ EOF delete_forwarding_service() { - send_stats "刪除frp內網服務" - # 提示使用者輸入需要刪除的服務名稱 + send_stats "删除frp内网服务" + # 提示用户输入需要删除的服务名称 read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml @@ -4216,7 +4216,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 如果已有服務訊息,在處理新服務之前列印目前服務 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4225,7 +4225,7 @@ list_forwarding_services() { type } - # 更新当前服务名称 + # 更新目前服務名稱 if ($1 != "[common]") { gsub(/[\[\]]/, "", $1) current_service=$1 @@ -4258,7 +4258,7 @@ list_forwarding_services() { } END { - # 列印最後一個服務的訊息 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4348,7 +4348,7 @@ frps_panel() { echo -e "FRP服務端$check_frp $update_status" echo "建構FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports @@ -4361,7 +4361,7 @@ frps_panel() { echo "------------------------" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" - echo "00. 刷新服務狀態 0. 返回上一級選單" + echo "00. 刷新服务状态 0. 返回上一级选单" echo "------------------------" read -e -p "輸入你的選擇:" choice case $choice in @@ -4421,7 +4421,7 @@ frps_panel() { ;; 00) - send_stats "重新整理FRP服務狀態" + send_stats "刷新FRP服务状态" echo "已經刷新FRP服務狀態" ;; @@ -4572,8 +4572,8 @@ yt_menu_pro() { echo "更新完成。按任意鍵繼續..." read ;; 3) - send_stats "正在卸载 yt-dlp..." - echo "正在卸载 yt-dlp..." + send_stats "正在卸載 yt-dlp..." + echo "正在卸載 yt-dlp..." rm -f /usr/local/bin/yt-dlp sed -i "/\b${app_id}\b/d" /home/docker/appno.txt @@ -4590,7 +4590,7 @@ yt_menu_pro() { --no-overwrites --no-post-overwrites "$url" read -e -p "下載完成,按任何鍵繼續..." ;; 6) - send_stats "大量影片下載" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then echo -e "# 輸入多個視訊連結位址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" @@ -4624,11 +4624,11 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "音訊下載完成,按任意鍵繼續..." ;; 9) send_stats "刪除影片" - read -e -p "请输入删除视频名称: " rmdir + read -e -p "請輸入刪除影片名稱:" rmdir rm -rf "$VIDEO_DIR/$rmdir" ;; *) @@ -4664,7 +4664,7 @@ set_timedate() { -# 修复dpkg中断问题 +# 修復dpkg中斷問題 fix_dpkg() { pkill -9 -f 'apt|dpkg' rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock @@ -4673,7 +4673,7 @@ fix_dpkg() { linux_update() { - echo -e "${gl_kjlan}正在系统更新...${gl_bai}" + echo -e "${gl_kjlan}正在系統更新...${gl_bai}" if command -v dnf &>/dev/null; then dnf -y update elif command -v yum &>/dev/null; then @@ -4935,7 +4935,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}使用者金鑰登入模式已開啟,已關閉密碼登入模式,重連將會生效${gl_bai}" + echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" } @@ -4974,7 +4974,7 @@ import_sshkey() { local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then - read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key + read -e -p "請輸入您的SSH公鑰內容(通常以 'ssh-rsa' 或 'ssh-ed25519' 開頭):" public_key fi if [[ -z "$public_key" ]]; then @@ -5015,7 +5015,7 @@ fetch_remote_ssh_keys() { read -e -p "請輸入您的遠端公鑰URL:" keys_url fi - echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" + echo "此腳本將從遠端 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" echo "" echo "遠端公鑰地址:" echo " ${keys_url}" @@ -5061,7 +5061,7 @@ fetch_remote_ssh_keys() { echo "已備份原有 authorized_keys 文件" fi - # 追加公鑰(避免重複) + # 追加公钥(避免重复) local added=0 while IFS= read -r line; do [[ -z "${line}" || "${line}" =~ ^# ]] && continue @@ -5106,11 +5106,11 @@ fetch_github_ssh_keys() { if [[ -z "${username}" ]]; then - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username fi if [[ -z "${username}" ]]; then - echo "错误:GitHub 用户名不能为空" >&2 + echo "錯誤:GitHub 使用者名稱不能為空" >&2 return 1 fi @@ -5135,7 +5135,7 @@ sshkey_panel() { echo -e "使用者密鑰登入模式${IS_KEY_ENABLED}" echo "進階玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "将会生成密钥对,更安全的方式SSH登录" + echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" @@ -5310,8 +5310,8 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" - echo -e "${gl_hui}感谢bin456789大佬和leitbogioro大佬的脚本支持!${gl_bai} " + echo -e "${gl_hong}注意: ${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" + echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" @@ -5329,7 +5329,7 @@ dd_xitong() { echo "------------------------" echo "31. Alpine Linux 32. Arch Linux" echo "33. Kali Linux 34. openEuler" - echo "35. openSUSE Tumbleweed 36. fnos飞牛公测版" + echo "35. openSUSE Tumbleweed 36. fnos飛牛公測版" echo "------------------------" echo "41. Windows 11 42. Windows 10" echo "43. Windows 7 44. Windows Server 2025" @@ -5547,7 +5547,7 @@ dd_xitong() { 43) send_stats "重裝windows7" dd_xitong_4 - bash reinstall.sh windows --iso="https://drive.massgrave.dev/cn_windows_7_professional_with_sp1_x64_dvd_u_677031.iso" --image-name='windows 7 professional' + bash reinstall.sh windows --iso="https://archive.org/download/en_windows_7_professional_with_sp1_x64_dvd_u_676939_201906/en_windows_7_professional_with_sp1_x64_dvd_u_676939.iso" --image-name='windows 7 professional' reboot exit ;; @@ -5722,7 +5722,7 @@ bbrv3() { echo "BBR3參數寫入失敗,請檢查系統配置" return 1 } - echo "XanMod BBRv3内核处理完成。重啟後生效" + echo "XanMod BBRv3內核處理完成。重啟後生效" server_reboot } @@ -5813,12 +5813,12 @@ bbrv3() { elrepo_install() { # 導入 ELRepo GPG 公鑰 - echo "導入 ELRepo GPG 公鑰..." + echo "导入 ELRepo GPG 公钥..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 確保我們在一個支援的作業系統上運行 + # 确保我们在一个支持的操作系统上运行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "不支援的作業系統:$os_name" break_end @@ -5837,12 +5837,12 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else - echo "不支持的系统版本:$os_version" + echo "不支援的系統版本:$os_version" break_end linux_Settings fi # 啟用 ELRepo 內核倉庫並安裝最新的主線內核 - echo "启用 ELRepo 内核仓库并安装最新的主线内核..." + echo "啟用 ELRepo 核心倉庫並安裝最新的主線核心..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml echo "已安裝 ELRepo 倉庫配置並更新至最新主線核心。" @@ -5948,7 +5948,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 建構 clamscan 指令參數 + # 构建 clamscan 命令参数 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5957,7 +5957,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # 執行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -5982,13 +5982,13 @@ clamav() { send_stats "病毒掃描管理" while true; do clear - echo "clamav病毒掃描工具" - echo "影片介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒扫描工具" + echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "是一個開源的防毒軟體工具,主要用於偵測和刪除各種類型的惡意軟體。" echo "包括病毒、木馬、間諜軟體、惡意腳本和其他有害軟體。" echo "------------------------" - echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自訂目錄掃描${gl_bai}" + echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6200,9 +6200,9 @@ net.ipv4.tcp_slow_start_after_idle = 0" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 内核调优配置 +# kejilion 核心調優配置 # 模式: $mode_name | 場景: $scene -# 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') +# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') # ── TCP 擁塞控制 ── net.core.default_qdisc = $QDISC @@ -6270,7 +6270,7 @@ net.ipv6.conf.default.accept_redirects = 0 fs.file-max = 1048576 fs.nr_open = 1048576 -# ── 连接跟踪 ── +# ── 連結追蹤 ── $(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" @@ -6327,21 +6327,21 @@ LIMITS echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" } -# ── 各模式入口函數(保持原有呼叫介面不變) ── +# ── 各模式入口函数(保持原有调用接口不变) ── optimize_high_performance() { _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" } optimize_balanced() { - _kernel_optimize_core "均衡最佳化模式" "balanced" + _kernel_optimize_core "均衡优化模式" "balanced" } optimize_web_server() { _kernel_optimize_core "網站建置優化模式" "web" } -# ── 还原默认设置(完全清理) ── +# ── 還原預設設定(完全清理) ── restore_defaults() { echo -e "${gl_lv}還原到預設值...${gl_bai}" @@ -6380,9 +6380,9 @@ Kernel_optimize() { send_stats "Linux核心調優管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" - echo "Linux系統核心參數優化" + echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then - echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" + echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" else echo -e "當前模式:${gl_hui}未最佳化${gl_bai}" fi @@ -6783,7 +6783,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -6908,7 +6908,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "錯誤: SSH 使用者名稱格式不正確。" + echo "错误: SSH 用户名格式不正确。" return 1 fi @@ -7047,7 +7047,7 @@ delete_connection() { echo "連線已刪除!" } -# 使用连接 +# 使用連接 use_connection() { send_stats "使用連接" read -e -p "請輸入要使用的連接編號:" num @@ -7082,9 +7082,9 @@ use_connection() { sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" - echo "1. 使用者名稱和密碼是否正確。" + echo "1. 用户名和密码是否正确。" echo "2. 目標伺服器是否允許密碼登入。" - echo "3. 目标服务器的 SSH 服务是否正常运行。" + echo "3. 目標伺服器的 SSH 服務是否正常運作。" fi fi } @@ -7179,7 +7179,7 @@ mount_partition() { return 1 fi - # 建立掛載點 + # 创建挂载点 mkdir -p "$MOUNT_POINT" # 掛載 @@ -7274,7 +7274,7 @@ format_partition() { fi # 格式化分割區 - echo "正在格式化分区 /dev/$PARTITION為$FS_TYPE ..." + echo "正在格式化分割區 /dev/$PARTITION為$FS_TYPE ..." mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then @@ -7354,7 +7354,7 @@ add_task() { read -e -p "請輸入遠端目錄:" remote_path while true; do - read -e -p "請輸入遠端使用者@IP:" remote + read -e -p "请输入远程用户@IP: " remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break @@ -7391,11 +7391,11 @@ add_task() { # 刪除任務 delete_task() { send_stats "刪除同步任務" - read -e -p "請輸入要刪除的任務編號:" num + read -e -p "请输入要删除的任务编号: " num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "錯誤:未找到對應的任務。" + echo "错误:未找到对应的任务。" return fi @@ -7447,12 +7447,12 @@ run_task() { source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到远端: $local_path -> $remote:$remote_path" + echo "正在推送同步到遠端:$local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi - # 添加 SSH 连接通用参数 + # 新增 SSH 連線通用參數 local ssh_options="-p $port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" if [[ "$auth_method" == "password" ]]; then @@ -7465,9 +7465,9 @@ run_task() { fi sshpass -p "$password_or_key" rsync $options -e "ssh $ssh_options" "$source" "$destination" else - # 检查密钥文件是否存在和权限是否正确 + # 檢查密鑰檔案是否存在和權限是否正確 if [[ ! -f "$password_or_key" ]]; then - echo "错误:密钥文件不存在:$password_or_key" + echo "錯誤:密鑰檔案不存在:$password_or_key" return fi @@ -7519,7 +7519,7 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 檢查是否已存在相同任務 + # 检查是否已存在相同任务 if crontab -l | grep -q "k rsync_run $num"; then echo "錯誤: 該任務的定時同步已存在!" return @@ -7568,7 +7568,7 @@ rsync_manager() { echo echo "1. 建立新任務 2. 刪除任務" echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" - echo "5. 建立定時任務 6. 刪除定時任務" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" echo "0. 返回上一級選單" echo "---------------------------------" @@ -7660,14 +7660,14 @@ linux_info() { echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系統負載:${gl_bai}$load" - echo -e "${gl_kjlan}TCP|UDP連線數:${gl_bai}$tcp_count|$udp_count" - echo -e "${gl_kjlan}實體記憶體:${gl_bai}$mem_info" + echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" echo -e "${gl_kjlan}虛擬記憶體:${gl_bai}$swap_info" echo -e "${gl_kjlan}硬碟佔用:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" @@ -7685,7 +7685,7 @@ linux_info() { echo -e "${gl_kjlan}IPv6位址:${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNS位址:${gl_bai}$dns_addresses" - echo -e "${gl_kjlan}地理位置: ${gl_bai}$country $city" + echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" echo -e "${gl_kjlan}系統時間:${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}運行時長:${gl_bai}$runtime" @@ -7727,7 +7727,7 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未识别的包管理器" + echo "❌ 未識別的套件管理器" exit 1 fi @@ -7795,7 +7795,7 @@ linux_tools() { clear echo "工具已安裝,使用方法如下:" wget --help - send_stats "安裝wget" + send_stats "安装wget" ;; 3) clear @@ -8137,7 +8137,7 @@ docker_ssh_migration() { # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}Compose 項目 [$project_name] 已備份過,跳過重複打包...${gl_bai}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" continue fi @@ -8243,7 +8243,7 @@ docker_ssh_migration() { fi done - # --------- 继续还原普通容器 --------- + # --------- 繼續還原一般容器 --------- echo -e "${gl_kjlan}檢查並還原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do @@ -8298,11 +8298,11 @@ docker_ssh_migration() { fi # 啟動容器 - echo "執行還原指令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8324,7 +8324,7 @@ docker_ssh_migration() { migrate_docker() { send_stats "Docker遷移" install jq - read -e -p "请输入要迁移的备份目录: " BACKUP_DIR + read -e -p "請輸入要遷移的備份目錄:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}備份目錄不存在${gl_bai}"; return; } kj_ssh_read_host_user_port "目標伺服器IP:" "目標伺服器SSH用戶名 [預設root]:" "目標伺服器SSH連接埠 [預設22]:" "root" "22" @@ -8497,7 +8497,7 @@ linux_docker() { echo "網路操作" echo "------------------------" echo "1. 建立網絡" - echo "2. 加入網絡" + echo "2. 加入网络" echo "3. 退出網絡" echo "4. 刪除網絡" echo "------------------------" @@ -8523,7 +8523,7 @@ linux_docker() { 3) send_stats "加入網路" read -e -p "退出網路名稱:" dockernetwork - read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8533,7 +8533,7 @@ linux_docker() { 4) send_stats "刪除網絡" - read -e -p "請輸入要刪除的網路名稱:" dockernetwork + read -e -p "请输入要删除的网络名: " dockernetwork docker network rm $dockernetwork ;; @@ -8686,24 +8686,24 @@ linux_test() { while true; do clear - # send_stats "測試腳本集合" + # send_stats "测试脚本合集" echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP及解鎖狀態偵測" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" - echo -e "${gl_kjlan}2. ${gl_bai}Region 串流解鎖測試" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 串流媒體解鎖偵測" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP品質體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" + echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -8773,7 +8773,7 @@ linux_test() { echo "可參考的IP列表" echo "------------------------" echo "北京電信: 219.141.136.12" - echo "北京聯通: 202.106.50.1" + echo "北京联通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" echo "上海聯通: 210.22.97.1" @@ -8865,7 +8865,7 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文雲腳本合集" + send_stats "甲骨文云脚本合集" echo -e "甲骨文雲腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}安裝閒置機器活躍腳本" @@ -8965,7 +8965,7 @@ linux_Oracle() { read -e -p "請輸入你重裝後的密碼:" vpspasswd install wget bash <(wget --no-check-certificate -qO- "${gh_proxy}raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh") $xitong -v 64 -p $vpspasswd -port 22 - send_stats "甲骨文云重装系统脚本" + send_stats "甲骨文雲端重裝系統腳本" ;; [Nn]) echo "已取消" @@ -9041,7 +9041,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}环境已安装${gl_bai}站點:$output資料庫:$db_output" + echo -e "${gl_lv}環境已安裝${gl_bai}站點:$output資料庫:$db_output" fi fi @@ -9107,7 +9107,7 @@ linux_ldnmp() { 3) clear - # Discuz论坛 + # Discuz論壇 webname="Discuz論壇" send_stats "安裝$webname" echo "開始部署$webname" @@ -9459,7 +9459,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目录下" + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then @@ -9543,7 +9543,7 @@ linux_ldnmp() { echo "資料庫匯入的表數據" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "資料庫導入完成" + echo "数据库导入完成" ;; *) echo @@ -9832,7 +9832,7 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每週備份 2. 每天備份" + echo "1. 每周备份 2. 每天备份" read -e -p "請輸入你的選擇:" dingshi case $dingshi in @@ -9843,7 +9843,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "選擇每天備份的時間(小時,0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -9862,7 +9862,7 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回车键还原最新的备份,输入备份文件名还原指定的备份,输入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -9961,7 +9961,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車取得最新版):" version + read -e -p "請輸入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -10141,11 +10141,11 @@ moltbot_menu() { echo "2. 啟動" echo "3. 停止" echo "--------------------" - echo "4. 狀態日誌查看" + echo "4. 状态日志查看" echo "5. 換模型" echo "6. API管理" echo "7. 機器人連線對接" - echo "8. 插件管理(安装/删除)" + echo "8. 插件管理(安裝/刪除)" echo "9. 技能管理(安裝/刪除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" @@ -10162,7 +10162,7 @@ moltbot_menu() { echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" - printf "請輸入選項並回車:" + printf "请输入选项并回车: " } @@ -10240,7 +10240,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未偵測到 API providers,跳過模型同步') + print('ℹ️ 未检测到 API providers,跳过模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10308,7 +10308,7 @@ def collect_available_refs(exclude_provider=None): def prompt_delete_provider(name): - prompt = f"⚠️ {name} /models 探测连续失败 3 次。是否删除该 API 供应商及其全部相关模型? [y/N]:" + prompt = f"⚠️ {name} /models 偵測連續失敗 3 次。是否刪除該 API 供應商及其全部相關模型? [y/N]:" try: ans = input(prompt).strip().lower() except EOFError: @@ -10336,7 +10336,7 @@ def rebind_defaults_before_delete(name): return False set_primary_ref(defaults, repl) changed = True - summary.append(f'🔁 删除前已切换默认主模型: {primary_ref} -> {repl}') + summary.append(f'🔁 刪除前已切換預設主模型: {primary_ref} -> {repl}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) @@ -10396,7 +10396,7 @@ def fetch_remote_models_with_retry(name, base_url, api_key, retries=3): for name, provider in list(providers.items()): if not isinstance(provider, dict): - summary.append(f'ℹ️ 跳过 {name}: provider 结构非法') + summary.append(f'ℹ️ 跳過 {name}: provider 結構非法') continue api = provider.get('api', '') @@ -10733,7 +10733,7 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 成功添加$model_count個模型到$provider_name" + echo "✅ 成功添加$model_count 个模型到 $provider_name" echo "📦 模型引用格式:$provider_name/" return 0 else @@ -10750,7 +10750,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 默认模型不能为空" + echo "❌ 預設模型不能為空" return 1 fi @@ -10760,8 +10760,8 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 已添加 provider:$provider_name" - echo "✅ 仅写入默认模型:$default_model" + echo "✅ 已新增 provider:$provider_name" + echo "✅ 僅寫入預設模型:$default_model" return 0 else echo "❌ 配置注入失敗" @@ -11139,7 +11139,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + print(f'❌ {target}: 本地 models 無有效模板模型,無法補全新增模型') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -11209,7 +11209,7 @@ if removed_ids: print(f' - {mid}') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 指定 provider 模型一致性同步完成並已寫入配置') else: print('ℹ️ 無需同步:此 provider 配置已與上游 /models 保持一致') PY2 @@ -11223,7 +11223,7 @@ PY2 echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失败:provider 配置不完整或类型不支持" + echo "❌ 同步失敗:provider 配置不完整或類型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11266,7 +11266,7 @@ fix-openclaw-provider-protocol-interactive() { echo "請選擇要設定的 API 類型:" echo "1. openai-completions" echo "2. openai-responses" - read -erp "请输入你的选择 (1/2): " proto_choice + read -erp "請輸入你的選擇 (1/2):" proto_choice local new_api="" case "$proto_choice" in @@ -11503,7 +11503,7 @@ PY echo -e " ${gl_lv}● 超算互聯網${gl_bai}" echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" echo "" - echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 優雲智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" echo -e " ${gl_huang}● 矽基流動${gl_bai} ${gl_zi}[AFF]${gl_bai}" @@ -11840,7 +11840,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" + echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" break_end return 1 fi @@ -11890,7 +11890,7 @@ PYTHON_EOF return 0 else if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 不可用,返回旧版输入模式。" + echo "gum 不可用,傳回舊版輸入模式。" sleep 1 continue fi @@ -12263,7 +12263,7 @@ PYTHON_EOF continue fi - echo "📥 本地未发现,尝试下载安装: $plugin_full" + echo "📥 本機未發現,嘗試下載安裝:$plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -12319,10 +12319,10 @@ PYTHON_EOF openclaw skills list echo "----------------------------------------" - # 輸出建議的實用技能列表 - echo "建議的實用技能(可直接複製名稱輸入):" + # 输出推荐的实用技能列表 + echo "推荐的实用技能(可直接复制名称输入):" echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 頁面、資料庫和區塊" + echo "notion # 操作 Notion 页面、数据库和块" echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" echo "1password # 自動化讀取和注入 1Password 金鑰" @@ -12375,7 +12375,7 @@ PYTHON_EOF echo "💡 技能 [$skill_name] 已在使用者目錄安裝。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then - echo "💡 技能 [$skill_name] 已在系统目录安装。" + echo "💡 技能 [$skill_name] 已在系統目錄安裝。" skill_found=true fi @@ -12475,7 +12475,7 @@ openclaw_json_get_bool() { # 相容於兩種常見目錄命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 + # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12659,9 +12659,9 @@ openclaw_json_get_bool() { openclaw_show_bot_local_status_block echo "----------------------------------------" echo "1. Telegram 機器人對接" - echo "2. 飛書 (Lark) 機器人對接" + echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 机器人对接" - echo "4. QQ 機器人對接" + echo "4. QQ 机器人对接" echo "5. 微信機器人對接" echo "----------------------------------------" echo "0. 返回上一級選單" @@ -12800,7 +12800,7 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "可使用以下方式下载备份文件:" + echo "可使用以下方式下載備份檔:" echo "- 本地路徑:$file_path" echo "- scp 範例: scp root@你的伺服器:$file_path ./" echo "- 或使用 SFTP 用戶端下載" @@ -12811,7 +12811,7 @@ EOF local archive_path="$2" local unpack_root="$3" - [ ! -f "$archive_path" ] && { echo "❌ 文件不存在: $archive_path"; return 1; } + [ ! -f "$archive_path" ] && { echo "❌ 文件不存在:$archive_path"; return 1; } mkdir -p "$unpack_root" tar -xzf "$archive_path" -C "$unpack_root" || { echo "❌ 備份包解壓縮失敗"; return 1; } @@ -12827,7 +12827,7 @@ EOF local real_type real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) if [ "$real_type" != "$expected_type" ]; then - echo "❌ 備份類型不匹配,期望:$expected_type,實際: ${real_type:-未知}" + echo "❌ 备份类型不匹配,期望: $expected_type,實際: ${real_type:-未知}" return 1 fi @@ -12883,7 +12883,7 @@ for item in workspaces: else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) " "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可備份的記憶文件"; rm -rf "$tmp_payload"; break_end; return 1 + echo "❌ 未找到可备份的记忆文件"; rm -rf "$tmp_payload"; break_end; return 1 fi if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then echo "✅ 記憶全量備份完成 (含多智能體):$out_file"; openclaw_offer_transfer_hint "$out_file" @@ -12924,7 +12924,7 @@ if os.path.isdir(agents_root): local openclaw_root openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then - echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" + echo "❌ 未找到 OpenClaw 根目錄:$openclaw_root" break_end return 1 fi @@ -13151,7 +13151,7 @@ if os.path.isdir(agents_root): return 0 fi - read -e -p "请输入要删除的文件名或完整路径(0 取消): " user_input + read -e -p "請輸入要刪除的檔案名稱或完整路徑(0 取消):" user_input if [ "$user_input" = "0" ]; then echo "已取消刪除。" break_end @@ -13201,7 +13201,7 @@ if os.path.isdir(agents_root): break_end return 0 fi - read -e -p "二次确认:输入 DELETE 执行删除: " confirm_step2 + read -e -p "二次確認:輸入 DELETE 執行刪除:" confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then echo "已取消刪除。" break_end @@ -13443,7 +13443,7 @@ except Exception: print("取得記憶狀態失敗(JSON 解析錯誤)") raise SystemExit(1) if not isinstance(data, list) or len(data) == 0: - print("未检测到任何智能体记忆状态。") + print("未檢測到任何智能體記憶狀態。") raise SystemExit(0) first = True for entry in data: @@ -13458,7 +13458,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print(" 底层方案: %s" % backend) + print("底層方案: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("已收錄: %s 檔案 / %s 區塊" % (files, chunks)) @@ -13558,7 +13558,7 @@ PY if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 可用") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未檢測到 QMD") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路徑:$model_path") @@ -13571,7 +13571,7 @@ PY *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可訪問") elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else @@ -13658,7 +13658,7 @@ PY openclaw_memory_check_sqlite() { if ! command -v sqlite3 >/dev/null 2>&1; then - echo "⚠️ 未检测到 sqlite3,QMD 可能无法正常运行。" + echo "⚠️ 未偵測到 sqlite3,QMD 可能無法正常運作。" return 1 fi local ver @@ -13676,7 +13676,7 @@ PY echo "✅ bun 已存在" return 0 fi - echo "⬇️ 安装 bun..." + echo "⬇️ 安裝 bun..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then @@ -13689,7 +13689,7 @@ PY export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 安装完成" + echo "✅ bun 安裝完成" return 0 fi echo "❌ bun 安裝失敗" @@ -13716,11 +13716,11 @@ PY return 1 fi if ! qmd --version >/dev/null 2>&1; then - echo "❌ qmd 安裝後仍無法運作" + echo "❌ qmd 安装后仍无法运行" return 1 fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - echo "✅ qmd 安裝完成:$qmd_path" + echo "✅ qmd 安装完成: $qmd_path" return 0 } @@ -13830,7 +13830,7 @@ PY echo "✅ memory.qmd.command 已正確" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 预热索引(可能下载模型)" + echo "🔥 預熱索引(可能下載模型)" openclaw_memory_prepare_workspace_all local preh_agent_lines preh_agent_id preh_workspace preh_agent_lines=$(openclaw_memory_list_agents) @@ -13843,11 +13843,11 @@ EOF else echo "⏭️ 已跳過預熱" fi - echo "✅ QMD 自動部署完成" + echo "✅ QMD 自动部署完成" } openclaw_memory_auto_setup_local() { - echo "🔍 偵測 Local 環境" + echo "🔍 检测 Local 环境" openclaw_memory_cleanup_legacy_keys local backend provider backend=$(openclaw_memory_get_backend) @@ -13870,7 +13870,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ 模型檔已存在:$model_path" + echo "✅ 模型文件已存在: $model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -13884,14 +13884,14 @@ EOF if [ -f "$model_dest" ]; then echo "✅ 已發現預設模型檔:$model_dest" else - echo "⬇️ 下載模型:$model_url" + echo "⬇️ 下载模型: $model_url" openclaw_memory_download_file "$model_url" "$model_dest" || return 1 echo "✅ 模型已下載:$model_dest" fi OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" - echo "✅ 已寫入模型路徑" + echo "✅ 已写入模型路径" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -13907,7 +13907,7 @@ EOF else echo "⏭️ 已跳過預熱" fi - echo "✅ Local 自动部署完成" + echo "✅ Local 自動部署完成" } openclaw_memory_auto_setup_run() { @@ -13926,7 +13926,7 @@ EOF case "$scheme" in qmd) scheme_label="QMD" - OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安装目录)" + OPENCLAW_MEMORY_EXPECT_PATH="$HOME/.bun (qmd 安裝目錄)" OPENCLAW_MEMORY_EXPECT_SIZE="約 20-50MB" ;; local) @@ -13951,7 +13951,7 @@ EOF openclaw_memory_render_auto_summary return 0 fi - echo "♻️ 重啟 OpenClaw 網關" + echo "♻️ 重启 OpenClaw 网关" if declare -F start_gateway >/dev/null 2>&1; then start_gateway else @@ -13966,11 +13966,11 @@ EOF while true; do clear echo "=======================================" - echo "記憶方案自動部署" + echo "记忆方案自动部署" echo "=======================================" echo "1. QMD" echo "2. Local" - echo "3. Auto(自动选择)" + echo "3. Auto(自動選擇)" echo "0. 返回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" auto_choice @@ -14044,7 +14044,7 @@ EOF local backend include_dm backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then - echo "⚠️ 偵測到目前方案為 QMD,但未安裝 qmd 指令。" + echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" echo "可切換 Local,或安裝 bun + qmd 後再試。" fi include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) @@ -14058,7 +14058,7 @@ EOF echo "這會導致預設記憶檔案(MEMORY.md + memory/*.md)不被索引" echo "所以 Indexed 會一直顯示 0/N" echo "" - read -e -p "是否恢复为 true 并重建索引? (Y/n):" fix_choice + read -e -p "是否恢復為 true 並重建索引? (Y/n):" fix_choice if [[ ! "$fix_choice" =~ ^[Nn]$ ]]; then openclaw_memory_config_set "memory.qmd.includeDefaultMemory" true if [ $? -ne 0 ]; then @@ -14098,14 +14098,14 @@ EOF builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac - echo "當前方案:$current_label" + echo "当前方案: $current_label" echo "" echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" echo "1. 切換 QMD(自動部署/已安裝則跳過)" - echo "2. 切换 Local(自动部署/已装则跳过)" + echo "2. 切換 Local(自動部署/已安裝則跳過)" echo "3. Auto(自動推薦並自動部署)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14166,7 +14166,7 @@ EOF echo "未找到記憶文件。" return 0 fi - echo "编号 | 归属 | 大小 | 修改时间" + echo "編號 | 歸屬 | 大小 | 修改時間" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do @@ -14189,7 +14189,7 @@ EOF local default_lines=120 local start_line count echo "文件:$file" - echo "總行數:$total_lines" + echo "总行数: $total_lines" read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line read -e -p "請輸入顯示行數(回車預設$default_lines): " count [ -z "$count" ] && count=$default_lines @@ -14201,7 +14201,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 請輸入有效的數字。" + echo "❌ 请输入有效的数字。" return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14283,9 +14283,9 @@ EOF openclaw_memory_render_status echo "1. 更新記憶索引" echo "2. 檢視記憶文件" - echo "3. 索引修復(Indexed 異常)" + echo "3. 索引修复(Indexed 异常)" echo "4. 記憶方案(QMD/Local/Auto)" - echo "5. 搜索测试(验证索引是否工作)" + echo "5. 搜尋測試(驗證索引是否運作)" echo "6. 深度狀態探測(檢查嵌入模型)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14302,7 +14302,7 @@ EOF openclaw_memory_prepare_workspace_all read -e -p "二次確認:輸入 force 使用全量(留空為增量):" confirm_step2 if [ "$confirm_step2" = "force" ]; then - echo "⚠️ 全量重建更彻底,但耗时更长。" + echo "⚠️ 全量重建更徹底,但耗時更長。" echo "建議:輸入 rebuild 進行安全重建(先備份索引庫)。" read -e -p "第三次確認:輸入 rebuild 執行安全重建;直接回車繼續普通 force:" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then @@ -14317,7 +14317,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14396,7 +14396,7 @@ EOF return 1 fi cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { - echo "❌ 權限恢復失敗:$backup_file" + echo "❌ 权限恢复失败:$backup_file" return 1 } echo "✅ 已恢復切換前權限配置" @@ -14526,7 +14526,7 @@ try: elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": print("開發增強模式") elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": - print("完全開放模式") + print("完全开放模式") else: print("自訂模式") except Exception: @@ -14542,8 +14542,8 @@ PY mkdir -p "$HOME/.openclaw" - # 產生 JSON 並透過 openclaw approvals set --stdin 寫入(優先) - # 若 CLI 不支持则回退直接写文件 + # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) + # 若 CLI 不支援則回退直接寫文件 local json_payload json_payload=$(python3 -c ' import json, sys, os @@ -14568,7 +14568,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 回退:直接写文件 + # 回退:直接寫文件 echo "$json_payload" > "$approvals_file" } @@ -14589,18 +14589,18 @@ print(json.dumps(data, indent=2)) local current_mode="未知 / 自訂" if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then - current_mode="\033[1;31m完全開放模式\033[0m" + current_mode="\033[1;31m完全开放模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then - current_mode="\033[1;33m開發增強模式\033[0m" + current_mode="\033[1;33m开发增强模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then - current_mode="\033[1;32m標準安全模式\033[0m" + current_mode="\033[1;32m标准安全模式\033[0m" elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" fi - echo -e "當前綜合安全等級:${current_mode}" + echo -e " 当前综合安全等级: ${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" - echo "Profile (預設): ${current_profile:-(unset)}" + echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" + echo " Profile (预设): ${current_profile:-(unset)}" echo "Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" @@ -14719,7 +14719,7 @@ except Exception: openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - echo "清理宿主機攔截配置..." + echo "清理宿主机拦截配置..." # 優先透過 CLI 清空審核配置,回退直接刪文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then true @@ -14817,9 +14817,9 @@ except Exception as e: echo "---------------------------------------" echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" - echo -e "${gl_kjlan}3.${gl_bai} 切换为完全开放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" + echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" - echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" + echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" @@ -15006,7 +15006,7 @@ PY return 0 fi fi - # 回退:从文件系统读取 + # 回退:從檔案系統讀取 python3 <<'PY' import json,os base=os.path.expanduser("~/.openclaw/agents") @@ -15044,7 +15044,7 @@ PY config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) echo "設定檔: ${config_file:-$(openclaw_permission_config_file)}" - echo "預設智能體:$default_agent" + echo "默认智能体: $default_agent" python3 -c ' import json,sys agents=json.loads(sys.argv[1] or "[]") @@ -15052,7 +15052,7 @@ bindings=json.loads(sys.argv[2] or "[]") sess_obj=json.loads(sys.argv[3] or "{}") sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] print("已配置智能体数: %s" % len(agents)) -print("路由綁定數: %s" % len(bindings)) +print("路由绑定数: %s" % len(bindings)) print("會話總數: %s" % len(sessions)) print("---------------------------------------") if not agents: @@ -15067,9 +15067,9 @@ else: is_default = item.get("isDefault", False) bcount = item.get("bindings", 0) default_tag = "[預設]" if is_default else "" - print("- 智能体ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) + print("- 智能體ID: \033[1;36m%s\033[0m%s" % (aid, default_tag)) print("身份名稱: %s %s" % (identity, emoji)) - print(" 模型: %s" % model) + print("模型: %s" % model) print("工作目錄: %s" % ws) print("綁定數: %s" % bcount) ' "$(openclaw_multiagent_agents_json)" "$(openclaw_multiagent_bindings_json)" "$(openclaw_multiagent_sessions_json)" @@ -15122,7 +15122,7 @@ for idx,item in enumerate(agents,1): if openclaw agents delete "$agent_id"; then echo "✅ 智能體刪除成功:$agent_id" else - echo "❌ 智能体删除失败" + echo "❌ 智能體刪除失敗" return 1 fi } @@ -15133,7 +15133,7 @@ for idx,item in enumerate(agents,1): import json,sys bindings=json.loads(sys.argv[1] or "[]") if not bindings: - print("暂无路由绑定。") + print("暫無路由綁定。") raise SystemExit(0) for idx,item in enumerate(bindings,1): desc = item.get("description") or "-" @@ -15152,7 +15152,7 @@ for idx,item in enumerate(bindings,1): read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由綁定新增成功" + echo "✅ 路由绑定添加成功" else echo "❌ 路由綁定新增失敗" return 1 @@ -15172,7 +15172,7 @@ for idx,item in enumerate(bindings,1): if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ 路由綁定移除成功" else - echo "❌ 路由綁定移除失敗" + echo "❌ 路由绑定移除失败" return 1 fi } @@ -15191,7 +15191,7 @@ by_agent={} for item in sessions: aid = item.get("agentId","?") by_agent[aid] = by_agent.get(aid, 0) + 1 -print("會話匯總:") +print("会话汇总:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") @@ -15255,7 +15255,7 @@ print("✅ 多智能體健康檢查完成") local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" - echo "也可以從 IDENTITY.md 自動讀取身分資訊。" + echo "也可以从 IDENTITY.md 自动读取身份信息。" read -e -p "是否從 IDENTITY.md 讀取? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" @@ -15272,7 +15272,7 @@ print("✅ 多智能體健康檢查完成") } openclaw_multiagent_menu() { - send_stats "OpenClaw多智能体管理" + send_stats "OpenClaw多智能體管理" while true; do clear echo "=======================================" @@ -15280,7 +15280,7 @@ print("✅ 多智能體健康檢查完成") echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 新增智能體" + echo "1. 新增智能体" echo "2. 刪除智能體" echo "3. 查看路由綁定" echo "4. 新增路由綁定" @@ -15315,7 +15315,7 @@ openclaw_backup_restore_menu() { while true; do clear echo "=======================================" - echo "OpenClaw 備份與還原" + echo "OpenClaw 备份与还原" echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" @@ -15367,7 +15367,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15434,7 +15434,7 @@ openclaw_backup_restore_menu() { - # 新增網域(呼叫你給的函數) + # 添加域名(调用你给的函数) openclaw_domain_webui() { add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 18789 @@ -15459,7 +15459,7 @@ openclaw_backup_restore_menu() { if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}已将域名 ${yuming}加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi @@ -15491,7 +15491,7 @@ openclaw_backup_restore_menu() { clear openclaw_show_webui_addr echo - echo "1. 添加網域訪問" + echo "1. 添加域名访问" echo "2. 刪除網域名稱訪問" echo "0. 退出" echo @@ -15657,7 +15657,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -15677,7 +15677,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") # 檢查安裝狀態 (匹配 appno.txt 中的 ID) - # 這裡假設 appno.txt 中記錄的是 base_name (即檔名) + # 这里假设 appno.txt 中记录的是 base_name (即文件名) if echo "$app_numbers" | grep -q "^$base_name$"; then # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" @@ -15797,7 +15797,7 @@ while true; do local docker_describe="一個Nginx反向代理工具面板,不支援新增網域存取。" local docker_url="官網介紹: https://nginxproxymanager.com/" local docker_use="echo \"初始使用者名稱: admin@example.com\"" - local docker_passwd="echo \"初始密碼: changeme\"" + local docker_passwd="echo \"初始密码: changeme\"" local app_size="1" docker_app @@ -16002,7 +16002,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "請設定郵箱網域名稱 例如 mail.yuming.com :" yuming + read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16591,7 +16591,7 @@ while true; do } - local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" local docker_url="官網介紹: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" @@ -16835,7 +16835,7 @@ while true; do local docker_describe="極簡朋友圈,高仿微信朋友圈,記錄你的美好生活" local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"帳號: admin 密碼: a123456\"" + local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -17188,7 +17188,7 @@ while true; do } - local docker_describe="這是一個網站變更偵測、補貨監控和通知的小工具" + local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" local docker_url="官網介紹:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" @@ -18187,7 +18187,7 @@ while true; do } - local docker_describe="开源个人订阅追踪器,可用于财务管理" + local docker_describe="開源個人訂閱追蹤器,可用於財務管理" local docker_url="官網介紹:${gh_https_url}github.com/ellite/Wallos" local docker_use="" local docker_passwd="" @@ -18326,7 +18326,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" local app_size="1" docker_app @@ -18840,7 +18840,7 @@ while true; do local app_id="99" local app_name="dsm群暉虛擬機" - local app_text="Docker容器中的虛擬DSM" + local app_text="Docker容器中的虚拟DSM" local app_url="官網:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" @@ -18851,7 +18851,7 @@ while true; do read -e -p "設定 CPU 核數 (預設 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "設定記憶體大小 (預設 4G):" RAM_SIZE + read -e -p "设置内存大小 (默认 4G): " RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -18923,7 +18923,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19292,7 +19292,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local docker_describe="Lucky 是一個大內部網路穿透及連接埠轉送管理工具,支援 DDNS、反向代理、WOL 等功能。" local docker_url="項目地址:${gh_https_url}github.com/gdy666/lucky" - local docker_use="echo \"預設帳號密碼: 666\"" + local docker_use="echo \"默认账号密码: 666\"" local docker_passwd="" local app_size="1" docker_app @@ -19320,7 +19320,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支援透過網頁直接存取桌面版瀏覽器介面。" + local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" local docker_url="項目地址:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -19550,7 +19550,7 @@ linux_work() { fi send_stats "SSH常駐模式" echo -e "SSH常駐模式${tmux_sshd_status}" - echo "開啟後SSH連線後會直接進入常駐模式,直接回到先前的工作狀態。" + echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" echo "------------------------" echo "1. 開啟 2. 關閉" echo "------------------------" @@ -19591,7 +19591,7 @@ linux_work() { ;; 24) - read -e -p "请输入要删除的工作区名称: " gongzuoqu_name + read -e -p "請輸入要刪除的工作區名稱:" gongzuoqu_name tmux kill-window -t $gongzuoqu_name send_stats "刪除工作區" ;; @@ -19767,7 +19767,7 @@ net_menu() { echo "4. 刷新網卡資訊" echo "0. 返回上一級選單" echo "====================================" - read -erp "請選擇操作:" choice + read -erp "请选择操作: " choice case $choice in 1) @@ -19984,7 +19984,7 @@ env_menu() { edit_file() { local file="$1" - send_stats "編輯變數文件$file" + send_stats "编辑变量文件 $file" install nano nano "$file" } @@ -20367,7 +20367,7 @@ EOF echo "" echo "------------------------" - echo "1. IPv4 優先 2. IPv6 優先權 3. IPv6 修復工具" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20514,7 +20514,7 @@ EOF sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "請輸入要刪除的使用者名稱:" username + read -e -p "请输入要删除的用户名: " username userdel -r "$username" ;; @@ -20598,7 +20598,7 @@ EOF echo "時區切換" echo "------------------------" echo "亞洲" - echo "1. 中國上海時間 2. 中國香港時間" + echo "1. 中国上海时间 2. 中国香港时间" echo "3. 日本東京時間 4. 韓國首爾時間" echo "5. 新加坡時間 6. 印度加爾各答時間" echo "7. 阿聯酋杜拜時間 8. 澳洲雪梨時間" @@ -20814,7 +20814,7 @@ EOF while true; do clear echo "本機host解析列表" - echo "如果你在這裡添加解析匹配,將不再使用動態解析了" + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" echo "操作" @@ -20891,7 +20891,7 @@ EOF rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "請輸入出站流量閾值(單位為G,預設100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "請輸入流量重置日期(預設每月1日重設):" cz_day + read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} cd ~ @@ -20932,9 +20932,9 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" - echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" + echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in @@ -21104,15 +21104,15 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" echo "------------------------------------------------" linux_clean - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" + echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系統垃圾文件" echo "------------------------------------------------" add_swap 1024 - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 3/12. 設定虛擬內存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" new_ssh_port 5522 @@ -21173,7 +21173,7 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在採集數據${gl_bai}" + local status_message="${gl_lv}正在采集数据${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then local status_message="${gl_hui}採集已關閉${gl_bai}" else @@ -21182,7 +21182,7 @@ EOF echo "隱私與安全" echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" - echo "将收集脚本版本号,使用的时间,系统版本,CPU架构,机器所属国家和使用的功能的名称," + echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" echo -e "目前狀態:$status_message" echo "--------------------" @@ -21275,7 +21275,7 @@ linux_file() { clear echo "文件管理器" echo "------------------------" - echo "当前路径" + echo "目前路徑" pwd echo "------------------------" ls --color=auto -x @@ -21307,7 +21307,7 @@ linux_file() { 3) # 修改目录权限 read -e -p "請輸入目錄名:" dirname read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" + chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失敗" send_stats "修改目錄權限" ;; 4) # 重命名目录 @@ -21323,7 +21323,7 @@ linux_file() { ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "返回上一層選單目錄" ;; 11) # 创建文件 read -e -p "請輸入要建立的檔案名稱:" filename @@ -21344,7 +21344,7 @@ linux_file() { ;; 14) # 重命名文件 read -e -p "請輸入目前檔名:" current_name - read -e -p "請輸入新檔名:" new_name + read -e -p "请输入新文件名: " new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" ;; @@ -21360,7 +21360,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21402,7 +21402,7 @@ linux_file() { fi # 使用 -r 選項以遞歸方式複製目錄 - cp -r "$src_path" "$dest_path" && echo "文件或目录已复制到 $dest_path" || echo "複製檔案或目錄失敗" + cp -r "$src_path" "$dest_path" && echo "檔案或目錄已複製到$dest_path" || echo "複製檔案或目錄失敗" send_stats "複製檔案或目錄" ;; @@ -21410,7 +21410,7 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "錯誤: 文件不存在。" + echo "错误: 文件不存在。" send_stats "傳送文件失敗: 文件不存在" continue fi @@ -21520,7 +21520,7 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}批次執行任務${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系统" + echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21640,7 +21640,7 @@ echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流 echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" -echo -e "${gl_bai}网址: https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "網域優惠" @@ -21730,7 +21730,7 @@ while true; do clear echo "更新日誌" echo "------------------------" - echo "全部日誌:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" + echo "全部日志: ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 @@ -21789,7 +21789,7 @@ while true; do cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "腳本已經最新$sh_v_new" + send_stats "脚本已经最新$sh_v_new" else rm -f "$tmp_file" # 恢復備份 @@ -21923,7 +21923,7 @@ k_info() { send_stats "k指令參考用例" echo "-------------------" echo "影片介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令參考用例:" +echo "以下是k命令参考用例:" echo "啟動腳本 k" echo "安裝軟體包 k install nano wget | k add nano wget | k 安裝 nano wget" echo "卸載軟體包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" @@ -21943,24 +21943,24 @@ echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "软件重启 k restart sshd | k 重启 sshd " +echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" echo "網域名稱憑證到期查詢 k ssl ps" echo "docker管理平面 k docker" -echo "docker环境安装 k docker install |k docker 安装" +echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" -echo "安装WordPress k wp |k wordpress |k wp xxx.com" +echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" -echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" -echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" @@ -21968,7 +21968,7 @@ echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b" echo "顯示系統資訊 k info" -echo "ROOT密钥管理 k sshkey" +echo "ROOT金鑰管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " echo "SSH公鑰導入(GitHub) k sshkey github " @@ -22223,7 +22223,7 @@ else ;; github ) shift - send_stats "從 GitHub 導入 SSH 公鑰" + send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From 195c79f8ac01de6acf829476474ad117ea7f8760 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 30 May 2026 08:55:20 +0800 Subject: [PATCH 1190/1285] =?UTF-8?q?feat:=20=E5=8F=AF=E9=81=93=E4=BA=91(k?= =?UTF-8?q?odbox)=E9=83=A8=E7=BD=B2=E6=94=B9=E4=B8=BA=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 3 ++- kejilion.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 82be62a98..f3fd351d5 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9164,7 +9164,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox diff --git a/kejilion.sh b/kejilion.sh index 5dfb0eb3b..cecf5c32c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9170,7 +9170,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox From 7b4cac18ef26cf5ec3828c2d5135595f95c2dc3f Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 30 May 2026 09:01:57 +0800 Subject: [PATCH 1191/1285] =?UTF-8?q?feat:=20Discuz=E8=AE=BA=E5=9D=9B?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=94=B9=E4=B8=BA=E4=BB=8EGitee=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E6=BA=90=E5=8A=A8=E6=80=81=E8=8E=B7=E5=8F=96=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cn/kejilion.sh | 7 +++++-- kejilion.sh | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f3fd351d5..adeb807fc 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9124,8 +9124,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp diff --git a/kejilion.sh b/kejilion.sh index cecf5c32c..82825cfea 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9130,8 +9130,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp From 64358abff191305fd5053e8df957bb77be14a641 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 31 May 2026 05:58:40 +0000 Subject: [PATCH 1192/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-05-31=2005:58:40?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 52 ++-- jp/kejilion.sh | 156 ++++++------ kr/kejilion.sh | 138 +++++----- tw/kejilion.sh | 670 +++++++++++++++++++++++++------------------------ 4 files changed, 516 insertions(+), 500 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 0808bcbb0..303451e7f 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is on" + zstd_status="zstd compression is enabled" else zstd_status="" fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -3349,7 +3349,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear send_stats "Unable to install LDNMP environment again" - echo -e "${gl_huang}hint:${gl_bai}建站环境已安装。无需再次安装!" + echo -e "${gl_huang}hint:${gl_bai}The website building environment has been installed. No need to install again!" break_end linux_ldnmp fi @@ -3602,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -6549,7 +6549,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}Change completed. Reconnect to SSH to see the changes!${gl_bai}" +echo -e "${gl_lv}Change completed.重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -6692,9 +6692,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6736,7 +6736,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7071,7 +7071,7 @@ use_connection() { echo "3. Whether the target server allows login using a key." fi else - # Connect using password + # 使用密码连接 if ! command -v sshpass &> /dev/null; then echo "Error: sshpass is not installed, please install sshpass first." echo "Installation method:" @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -9130,8 +9130,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp @@ -9170,7 +9173,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox @@ -10143,7 +10147,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API management" + echo "6. API Management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10567,8 +10571,8 @@ PY start_bot() { - echo "Starting OpenClaw..." - send_stats "Starting OpenClaw..." + echo "Start OpenClaw..." + send_stats "Start OpenClaw..." start_gateway break_end } @@ -15096,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ The agent was created successfully:$agent_id" + echo "✅The agent is created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -19377,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available application backups" + echo "Available app backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -20379,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -21132,7 +21136,7 @@ EOF echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}Shanghai${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. Set time zone to${gl_huang}Shanghai${gl_bai}" echo "------------------------------------------------" auto_optimize_dns @@ -21488,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21639,7 +21643,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21920,7 +21924,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index b9a4b4048..d5affeaf7 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -2240,7 +2240,7 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" + echo "CFパラメータを取得します。" echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮がオンになっています" + zstd_status="zstd圧縮が有効になっています" else zstd_status="" fi @@ -2678,7 +2678,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2697,7 +2697,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします。 + # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3221,7 +3221,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -4195,7 +4195,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # ヘッダーの印刷 + # ヘッダーを印刷します printf "%-20s %-25s %-30s %-10s\n" "サービス名" "イントラネットアドレス" "外部ネットワークアドレス" "プロトコル" awk ' @@ -4838,7 +4838,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5609,7 +5609,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) + # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5621,7 +5621,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません、XanMod ソースを構成できません" + echo "システムコードネームを取得できません。XanMod ソースを構成できません" return 1 fi @@ -6013,7 +6013,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6379,7 +6379,7 @@ Kernel_optimize() { clear send_stats "Linux カーネルのチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) - [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" echo "Linuxシステムのカーネルパラメータの最適化" if [ -n "$current_mode" ]; then echo -e "現在のモード:${gl_lv}${current_mode}${gl_bai}" @@ -6692,9 +6692,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6736,7 +6736,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6824,7 +6824,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7172,7 +7172,7 @@ mount_partition() { return 1 fi - # ファイルシステムのタイプを取得する + # ファイルシステムの種類を取得する FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then echo "ファイル システム タイプを取得できません!" @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7324,7 +7324,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7583,7 +7583,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -8127,7 +8127,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8222,7 +8222,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8304,7 +8304,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -9130,8 +9130,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp @@ -9170,7 +9173,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox @@ -9282,7 +9286,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9757,7 +9761,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.html" -print find "$(realpath .)" -name "index.html" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/ のような)index.html へのパスを入力してください。$yuming/index/): " index_lujing + read -e -p "(/home/web/html/ のような、index.html へのパスを入力してください)$yuming/index/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -10417,7 +10421,7 @@ for name, provider in list(providers.items()): data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models の検出に失敗しました。{attempts} 回再試行しました ({type(err).__name__}: {err})') - send_stat('OpenClaw API は介入を確認しました') + send_stat('OpenClaw API确认介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: @@ -10442,7 +10446,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10567,8 +10571,8 @@ PY start_bot() { - echo "OpenClaw を開始しています..." - send_stats "OpenClaw を開始しています..." + echo "OpenClaw を開始します..." + send_stats "OpenClaw を開始します..." start_gateway break_end } @@ -10826,7 +10830,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにします) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11542,7 +11546,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入口" + send_stats "OpenClaw APIの入り口" while true; do clear echo "=======================================" @@ -11550,7 +11554,7 @@ PY echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. APIを追加する" + echo "1. APIの追加" echo "2. APIプロバイダーモデルリストを同期する" echo "3. API タイプの切り替え (完了/応答)" echo "4. APIの削除" @@ -11845,7 +11849,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12199,7 +12203,7 @@ PYTHON_EOF echo "- [whatsapp] #WhatsApp オートメーション" echo "" echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル検索)" + echo "- [memory-core] # 基本メモリ (ファイル取得)" echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" @@ -12331,7 +12335,7 @@ PYTHON_EOF echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンの制御" + echo "openhue # Philips Hue スマート照明シーンを制御する" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12803,7 +12807,7 @@ EOF echo "バックアップ ファイルは次の方法でダウンロードできます。" echo "- ローカルパス:$file_path" echo "- scp の例: scp root@yourserver:$file_path ./" - echo "- またはSFTPクライアントを使用してダウンロードします" + echo "- またはSFTPクライアントを使用してダウンロード" } openclaw_prepare_import_archive() { @@ -13777,7 +13781,7 @@ PY echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -14027,7 +14031,7 @@ EOF } openclaw_memory_offer_restart() { - echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14286,7 +14290,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステート検出 (組み込みモデルのチェック)" + echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14648,7 +14652,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14705,7 +14709,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -15096,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました:$agent_id" + echo "✅ エージェントが正常に作成されました。$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15629,7 +15633,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVEオープンチックパネル${gl_kjlan}52. ${color52}DPanel コンテナ管理パネル" echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" - echo -e "${gl_kjlan}55. ${color55}FRPイントラネット浸透(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" @@ -17984,7 +17988,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18669,7 +18673,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -19258,7 +19262,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19377,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリケーションのバックアップ" + echo "利用可能なアプリのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -19778,7 +19782,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19788,7 +19792,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19800,7 +19804,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19851,7 +19855,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19861,7 +19865,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19876,7 +19880,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19964,7 +19968,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -19979,7 +19983,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -19995,7 +19999,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -20008,7 +20012,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数 (ソース) をリロードします。" + echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20379,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -21128,11 +21132,11 @@ EOF echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}】7/12。開ける${gl_huang}BBR${gl_bai}加速する" + echo -e "[${gl_lv}OK${gl_bai}] 7/12.開ける${gl_huang}BBR${gl_bai}加速する" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}】8/12。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns @@ -21175,7 +21179,7 @@ EOF if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then local status_message="${gl_lv}データの収集${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}コレクションは終了しました${gl_bai}" + local status_message="${gl_hui}采集已关闭${gl_bai}" else local status_message="不確実なステータス" fi @@ -21374,7 +21378,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21394,7 +21398,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21488,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21517,7 +21521,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21555,7 +21559,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -21639,7 +21643,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21757,7 +21761,7 @@ while true; do fi echo "------------------------" - echo "1. 今すぐ更新します 2. 自動更新をオンにします 3. 自動更新をオフにします" + echo "1. 今すぐ更新します。 2. 自動更新をオンにします。 3. 自動更新をオフにします。" echo "------------------------" echo "0. メインメニューに戻る" echo "------------------------" @@ -21920,7 +21924,7 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -21959,7 +21963,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 95ea0538f..1aef2c766 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -508,22 +508,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker restart $dockername ;; 6) @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 켜져 있습니다" + zstd_status="zstd 압축이 활성화되었습니다" else zstd_status="" fi @@ -3221,7 +3221,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 재정의하며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3423,7 +3423,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3725,7 +3725,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4106,7 +4106,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4168,7 +4168,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4983,7 +4983,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5722,7 +5722,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5732,7 +5732,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5882,7 +5882,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5900,7 +5900,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5936,7 +5936,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8095,7 +8095,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -8369,7 +8369,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8569,7 +8569,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8884,7 +8884,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9130,8 +9130,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp @@ -9170,7 +9173,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox @@ -9281,7 +9285,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9619,7 +9623,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -10567,8 +10571,8 @@ PY start_bot() { - echo "OpenClaw를 시작하는 중..." - send_stats "OpenClaw를 시작하는 중..." + echo "OpenClaw를 시작하세요..." + send_stats "OpenClaw를 시작하세요..." start_gateway break_end } @@ -12104,7 +12108,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -12188,7 +12192,7 @@ PYTHON_EOF echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안의 ID만 복사):" + echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" echo "--------------------------------------------------------" echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" @@ -12235,7 +12239,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인:$plugin_id" + echo "🔍 플러그인 상태 확인 중:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12252,7 +12256,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12683,7 +12687,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12913,7 +12917,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end } @@ -13021,7 +13025,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -14102,7 +14106,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14303,7 +14307,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14686,7 +14690,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { @@ -14795,7 +14799,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15096,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15265,7 +15269,7 @@ print("✅멀티에이전트 헬스체크 완료") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "만료되거나 중복된 세션 데이터를 곧 정리합니다..." + echo "만료되었거나 중복된 세션 데이터를 곧 정리 중입니다..." read -e -p "확인하려면 yes를 입력하세요." confirm [ "$confirm" != "yes" ] && { echo "취소"; return 0; } openclaw sessions cleanup @@ -15639,7 +15643,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -16709,7 +16713,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -18352,7 +18356,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -18924,7 +18928,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19377,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 애플리케이션 백업" + echo "사용 가능한 앱 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -20122,7 +20126,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -20135,7 +20139,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20379,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -20587,7 +20591,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간 가져오기 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -20607,7 +20611,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20675,7 +20679,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20770,7 +20774,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -21480,7 +21484,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 탐색하고 명령을 실행합니다. + # 서버를 순회하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -21488,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21564,7 +21568,7 @@ while true; do clear send_stats "클러스터 복원" echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" - echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}에 파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" + echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21636,10 +21640,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21920,7 +21924,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21959,12 +21963,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index b63a9489c..c77d1d37b 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -123,7 +123,7 @@ CheckFirstRun_false() { # 提示使用者同意條款 UserLicenseAgreement() { clear - echo -e "${gl_kjlan}欢迎使用科技lion脚本工具箱${gl_bai}" + echo -e "${gl_kjlan}歡迎使用科技lion腳本工具箱${gl_bai}" echo "首次使用腳本,請先閱讀並同意使用者授權協議。" echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" @@ -179,7 +179,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "未提供軟體包參數!" return 1 fi @@ -522,7 +522,7 @@ while true; do docker rm -f $dockername ;; 5) - send_stats "重啟指定容器" + send_stats "重启指定容器" read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker restart $dockername ;; @@ -535,7 +535,7 @@ while true; do docker stop $(docker ps -q) ;; 8) - send_stats "删除所有容器" + send_stats "刪除所有容器" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定删除所有容器吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -754,7 +754,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 + # 檢查設定檔是否存在,如果不存在則建立檔案並寫入預設設定 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -762,17 +762,17 @@ docker_ipv6_on() { # 使用jq處理設定檔的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 檢查目前配置是否已經有 ipv6 設定 + # 检查当前配置是否已经有 ipv6 设置 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,開啟 IPv6 + # 更新配置,开启 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 比較原始配置與新配置 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}目前已開啟ipv6訪問${gl_bai}" else @@ -801,12 +801,12 @@ docker_ipv6_off() { # 使用jq處理設定檔的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 檢查目前的 ipv6 狀態 + # 检查当前的 ipv6 状态 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') # 比較原始配置與新配置 if [[ "$CURRENT_IPV6" == "false" ]]; then - echo -e "${gl_huang}当前已关闭ipv6访问${gl_bai}" + echo -e "${gl_huang}目前已關閉ipv6訪問${gl_bai}" else echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -860,7 +860,7 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # 添加打开规则 + # 新增開啟規則 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi @@ -1167,18 +1167,18 @@ iptables_panel() { ;; 7) # 清除指定 IP - read -e -p "請輸入清除的IP:" d_ip + read -e -p "请输入清除的IP: " d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 send_stats "清除指定IP" ;; 11) - # 允许 PING + # 允許 PING iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "允许PING" + send_stats "允許PING" ;; 12) # 禁用 PING @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判斷是否需要建立虛擬記憶體 +# 判断是否需要创建虚拟内存 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1311,7 +1311,7 @@ ldnmp_v() { install_ldnmp_conf() { - # 创建必要的目录和文件 + # 建立必要的目錄和文件 cd /home && mkdir -p web/html web/mysql web/certs web/conf.d web/stream.d web/redis web/log/nginx web/letsencrypt && touch web/docker-compose.yml wget -O /home/web/nginx.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/nginx10.conf wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default10.conf @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站点信息 证书到期时间" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1537,10 +1537,10 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "域名证书申请成功" + send_stats "網域證書申請成功" else send_stats "網域證書申請失敗" - echo -e "${gl_hong}注意: ${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" @@ -1577,8 +1577,8 @@ certs_status() { cert_content+="${line}"$'\n' done - # 2. 輸入私鑰 (相容 RSA, ECC, PKCS#8) - echo "請貼上 憑證私鑰 (Private Key) 內容 (按兩次回車結束):" + # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1594,15 +1594,15 @@ certs_status() { chmod 644 "$cert_file" chmod 600 "$key_file" - # 識別目前證書類型並顯示 + # 识别当前证书类型并显示 if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then echo "偵測到 ECC 憑證已成功儲存。" else - echo "偵測到 RSA 憑證已成功儲存。" + echo "检测到 RSA 证书已成功保存。" fi auth_method="ssl_imported" else - echo "錯誤:無效的憑證或私鑰格式!" + echo "错误:无效的证书或私钥格式!" certs_status fi ;; @@ -1617,7 +1617,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "網域重複使用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1626,8 +1626,8 @@ fi add_yuming() { ip_address - echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "請輸入你的IP或解析過的網域名稱:" yuming + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "请输入你的IP或者解析过的域名: " yuming } @@ -1638,7 +1638,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "請輸入訪問/監聽端口,回車預設使用 80:" access_port + read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port access_port=${access_port:-80} fi } @@ -1650,13 +1650,13 @@ update_nginx_listen_port() { local access_port="$2" local conf="/home/web/conf.d/${yuming}.conf" - # 如果 access_port 為空,則跳過 + # 如果 access_port 为空,则跳过 [ -z "$access_port" ] && return 0 - # 刪除所有 listen 行 + # 删除所有 listen 行 sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" - # 在 server { 後插入新的 l​​isten + # 在 server { 后插入新的 listen sed -i "/server {/a\\ listen ${access_port};\\ listen [::]:${access_port}; @@ -1788,7 +1788,7 @@ web_del() { send_stats "刪除站點數據" yuming_list="${1:-}" if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list + read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list if [[ -z "$yuming_list" ]]; then return fi @@ -1829,7 +1829,7 @@ nginx_waf() { sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # 關閉 WAF:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2033,7 +2033,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 開啟 Zstd:去掉註釋 + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2233,11 +2233,11 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" ;; 22) - send_stats "高負載開啟5秒盾" + send_stats "高负载开启5秒盾" echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" @@ -2279,7 +2279,7 @@ web_security() { 32) nginx_waf off - echo "站点WAF已关闭" + echo "站點WAF已關閉" send_stats "站點WAF已關閉" ;; @@ -2403,11 +2403,11 @@ web_optimization() { optimize_balanced - echo "LDNMP环境已设置成 标准模式" + echo "LDNMP環境已設定成 標準模式" ;; 2) - send_stats "站点高性能模式" + send_stats "站點高效能模式" # nginx調優 local cpu_cores=$(nproc) @@ -2502,7 +2502,7 @@ check_docker_app() { # check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then -# check_docker="${gl_lv}已安装${gl_bai}" +# check_docker="${gl_lv}已安裝${gl_bai}" # else # check_docker="${gl_hui}未安裝${gl_bai}" # fi @@ -2566,12 +2566,12 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想透過 GitHub Release 判斷) --- + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) else - # --- 場景 C: 標準 Docker Hub --- + # --- 场景 C: 标准 Docker Hub --- local image_repo=${full_image_name%%:*} local image_tag=${full_image_name##*:} [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" @@ -2615,7 +2615,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 检查并放行指定 IP + # 檢查並放行指定 IP if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2794,7 +2794,7 @@ clear_host_port_rules() { iptables -D INPUT -p tcp --dport "$port" -j DROP fi - # 清除允许本机访问的规则 + # 清除允許本機存取的規則 if iptables -C INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi @@ -2913,7 +2913,7 @@ while true; do add_app_id clear - echo "$docker_name已經安裝完成" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use @@ -2928,7 +2928,7 @@ while true; do add_app_id clear - echo "$docker_name已經安裝完成" + echo "$docker_name 已经安装完成" check_docker_app_ip echo "" $docker_use @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "應用程式已解除安裝" + echo "应用已卸载" send_stats "解除安裝$docker_name" ;; @@ -3005,7 +3005,7 @@ docker_app_plus() { echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" echo "5. 新增網域存取 6. 刪除網域存取" - echo "7. 允许IP+端口访问 8. 阻止IP+端口访问" + echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3241,7 +3241,7 @@ f2b_basic_config() { fi echo "即將配置 SSH jail:$jail_name" - read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry @@ -3359,10 +3359,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安裝LDNMP環境" +send_stats "安装LDNMP环境" root_use clear -echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" +echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" check_disk_space 3 /home install_dependency install_docker @@ -3375,7 +3375,7 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安裝nginx環境" +send_stats "安装nginx环境" root_use clear echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" @@ -3495,7 +3495,7 @@ ldnmp_wp() { ldnmp_Proxy() { clear - webname="反向代理-IP+端口" + webname="反向代理-IP+埠" yuming="${1:-}" reverseproxy="${2:-}" port="${3:-}" @@ -3653,7 +3653,7 @@ stream_panel() { clear check_docker_app check_docker_image_update $docker_name - echo -e "Stream四层代理转发工具 $check_docker $update_status" + echo -e "Stream四層代理轉送工具$check_docker $update_status" echo "NGINX Stream 是 NGINX 的 TCP/UDP 代理模組,用於實現高效能的 傳輸層流量轉送和負載平衡。" echo "------------------------" if [ -d "/home/web/stream.d" ]; then @@ -3696,7 +3696,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "添加四层代理" + send_stats "新增四層代理" ;; 5) send_stats "編輯轉送配置" @@ -3704,7 +3704,7 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四層代理" + send_stats "修改四层代理" ;; 6) send_stats "刪除轉送配置" @@ -3871,7 +3871,7 @@ ldnmp_web_status() { echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" - echo "20. 刪除指定站點數據" + echo "20. 删除指定站点数据" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4009,12 +4009,12 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款時下流行且強大的維運管理面板。" - echo "官網介紹:$panelurl " + echo "${panelname}是一款时下流行且强大的运维管理面板。" + echo "官网介绍: $panelurl " echo "" echo "------------------------" - echo "1. 安裝 2. 管理 3. 卸載" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4158,7 +4158,7 @@ add_forwarding_service() { read -e -p "請輸入內部網路連接埠:" local_port read -e -p "請輸入外網埠:" remote_port - # 将用户输入写入配置文件 + # 將使用者輸入寫入設定檔 cat <> /home/frp/frpc.toml [$service_name] type = ${service_type} @@ -4169,7 +4169,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name 已成功添加到 frpc.toml" + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4180,12 +4180,12 @@ EOF delete_forwarding_service() { - send_stats "删除frp内网服务" - # 提示用户输入需要删除的服务名称 + send_stats "刪除frp內網服務" + # 提示使用者輸入需要刪除的服務名稱 read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服務$service_name已成功從 frpc.toml 刪除" + echo "服務$service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -4195,7 +4195,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 列印表頭 + # 打印表头 printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" awk ' @@ -4258,7 +4258,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 列印最後一個服務的訊息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4348,7 +4348,7 @@ frps_panel() { echo -e "FRP服務端$check_frp $update_status" echo "建構FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" + echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then check_docker_app_ip frps_main_ports @@ -4361,7 +4361,7 @@ frps_panel() { echo "------------------------" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" - echo "00. 刷新服务状态 0. 返回上一级选单" + echo "00. 刷新服務狀態 0. 返回上一級選單" echo "------------------------" read -e -p "輸入你的選擇:" choice case $choice in @@ -4421,7 +4421,7 @@ frps_panel() { ;; 00) - send_stats "刷新FRP服务状态" + send_stats "重新整理FRP服務狀態" echo "已經刷新FRP服務狀態" ;; @@ -4537,16 +4537,16 @@ yt_menu_pro() { clear send_stats "yt-dlp 下載工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一個功能強大的影片下載工具,支援 YouTube、Bilibili、Twitter 等數千網站。" + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下載影片清單:" + echo "已下载视频列表:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "-------------------------" - echo "5. 單一影片下載 6. 大量影片下載 7. 自訂參數下載" - echo "8. 下載為MP3音訊 9.刪除影片目錄 10. Cookie管理(開發中)" + echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" + echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" echo "-------------------------" echo "0. 返回上一級選單" echo "-------------------------" @@ -4590,7 +4590,7 @@ yt_menu_pro() { --no-overwrites --no-post-overwrites "$url" read -e -p "下載完成,按任何鍵繼續..." ;; 6) - send_stats "批量视频下载" + send_stats "大量影片下載" install nano if [ ! -f "$URL_FILE" ]; then echo -e "# 輸入多個視訊連結位址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" @@ -4935,7 +4935,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" + echo -e "${gl_lv}使用者金鑰登入模式已開啟,已關閉密碼登入模式,重連將會生效${gl_bai}" } @@ -5021,7 +5021,7 @@ fetch_remote_ssh_keys() { echo " ${keys_url}" echo "" - # 建立臨時文件 + # 创建临时文件 temp_file=$(mktemp) # 下載公鑰 @@ -5038,7 +5038,7 @@ fetch_remote_ssh_keys() { return 1 } else - echo "錯誤:系統中未找到 curl 或 wget,無法下載公鑰" >&2 + echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 rm -f "${temp_file}" return 1 fi @@ -5061,7 +5061,7 @@ fetch_remote_ssh_keys() { echo "已備份原有 authorized_keys 文件" fi - # 追加公钥(避免重复) + # 追加公鑰(避免重複) local added=0 while IFS= read -r line; do [[ -z "${line}" || "${line}" =~ ^# ]] && continue @@ -5098,19 +5098,19 @@ fetch_github_ssh_keys() { echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" - echo "5. 點選 Add SSH key 完成新增" + echo " 5. 点击 Add SSH key 完成添加" echo "" - echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" - echo " ${gh_https_url}github.com/您的使用者名稱.keys" + echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" + echo " ${gh_https_url}github.com/您的用户名.keys" echo "" if [[ -z "${username}" ]]; then - read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username fi if [[ -z "${username}" ]]; then - echo "錯誤:GitHub 使用者名稱不能為空" >&2 + echo "错误:GitHub 用户名不能为空" >&2 return 1 fi @@ -5133,7 +5133,7 @@ sshkey_panel() { IS_KEY_ENABLED="${gl_hui}未啟用${gl_bai}" fi echo -e "使用者密鑰登入模式${IS_KEY_ENABLED}" - echo "進階玩法: https://blog.kejilion.pro/ssh-key" + echo "进阶玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" @@ -5168,14 +5168,14 @@ sshkey_panel() { ;; 5) - send_stats "編輯公鑰文件" + send_stats "编辑公钥文件" install nano nano ${HOME}/.ssh/authorized_keys break_end ;; 6) - send_stats "查看本機密鑰" + send_stats "查看本机密钥" echo "------------------------" echo "公鑰資訊" cat ${HOME}/.ssh/authorized_keys @@ -5310,9 +5310,9 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意: ${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" + echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " - echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" @@ -5417,7 +5417,7 @@ dd_xitong() { ;; 23) - send_stats "重裝alma10" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5708,7 +5708,7 @@ bbrv3() { apt update -y if [ "$action" = "update" ]; then apt install -y --only-upgrade "$package" || apt install -y "$package" || { - echo "XanMod核心更新失敗,請檢查軟體來源或稍後重試" + echo "XanMod内核更新失败,请检查软件源或稍后重试" return 1 } else @@ -5732,7 +5732,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod核心已卸載。重啟後生效" + echo "XanMod内核已卸载。重啟後生效" server_reboot } @@ -5746,7 +5746,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "目前環境不支持,僅支援Debian和Ubuntu系統" + echo "当前环境不支持,仅支持Debian和Ubuntu系统" break_end linux_Settings fi @@ -5813,12 +5813,12 @@ bbrv3() { elrepo_install() { # 導入 ELRepo GPG 公鑰 - echo "导入 ELRepo GPG 公钥..." + echo "導入 ELRepo GPG 公鑰..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org # 檢測系統版本 local os_version=$(rpm -q --qf "%{VERSION}" $(rpm -qf /etc/os-release) 2>/dev/null | awk -F '.' '{print $1}') local os_name=$(awk -F= '/^NAME/{print $2}' /etc/os-release) - # 确保我们在一个支持的操作系统上运行 + # 確保我們在一個支援的作業系統上運行 if [[ "$os_name" != *"Red Hat"* && "$os_name" != *"AlmaLinux"* && "$os_name" != *"Rocky"* && "$os_name" != *"Oracle"* && "$os_name" != *"CentOS"* ]]; then echo "不支援的作業系統:$os_name" break_end @@ -5864,7 +5864,7 @@ elrepo() { echo "" echo "核心管理" echo "------------------------" - echo "1. 更新elrepo内核 2. 卸载elrepo内核" + echo "1. 更新elrepo內核 2. 卸載elrepo內核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5948,7 +5948,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # 构建 clamscan 命令参数 + # 建構 clamscan 指令參數 local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -5967,7 +5967,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜尋FOUND關鍵字確認病毒位置${gl_bai}" + echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" } @@ -5982,13 +5982,13 @@ clamav() { send_stats "病毒掃描管理" while true; do clear - echo "clamav病毒扫描工具" - echo "视频介绍: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" + echo "clamav病毒掃描工具" + echo "影片介紹: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "是一個開源的防毒軟體工具,主要用於偵測和刪除各種類型的惡意軟體。" echo "包括病毒、木馬、間諜軟體、惡意腳本和其他有害軟體。" echo "------------------------" - echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan} 3. 自定义目录扫描 ${gl_bai}" + echo -e "${gl_lv}1. 全盤掃描${gl_bai} ${gl_huang}2. 重要目錄掃描${gl_bai} ${gl_kjlan}3. 自訂目錄掃描${gl_bai}" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6040,7 +6040,7 @@ _get_mem_mb() { } # 統一內核調優核心函數 -# 参数: $1 = 模式名称, $2 = 场景 (high/balanced/web/stream/game) +# 參數: $1 = 模式名稱, $2 = 場景 (high/balanced/web/stream/game) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6202,7 +6202,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" cat > "$CONF" << SYSCTL # kejilion 核心調優配置 # 模式: $mode_name | 場景: $scene -# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') +# 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') # ── TCP 擁塞控制 ── net.core.default_qdisc = $QDISC @@ -6327,14 +6327,14 @@ LIMITS echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" } -# ── 各模式入口函数(保持原有调用接口不变) ── +# ── 各模式入口函數(保持原有呼叫介面不變) ── optimize_high_performance() { _kernel_optimize_core "${tiaoyou_moshi:-高性能优化模式}" "high" } optimize_balanced() { - _kernel_optimize_core "均衡优化模式" "balanced" + _kernel_optimize_core "均衡最佳化模式" "balanced" } optimize_web_server() { @@ -6380,9 +6380,9 @@ Kernel_optimize() { send_stats "Linux核心調優管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" - echo "Linux系统内核参数优化" + echo "Linux系統核心參數優化" if [ -n "$current_mode" ]; then - echo -e "当前模式: ${gl_lv}${current_mode}${gl_bai}" + echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" else echo -e "當前模式:${gl_hui}未最佳化${gl_bai}" fi @@ -6432,7 +6432,7 @@ Kernel_optimize() { cd ~ clear _kernel_optimize_core "遊戲服優化模式" "game" - send_stats "遊戲服優化" + send_stats "游戏服优化" ;; 6) cd ~ @@ -6674,7 +6674,7 @@ linux_trash() { fi ;; 4) - read -e -p "確認清空回收站? [y/n]:" confirm + read -e -p "确认清空回收站?[y/n]: " confirm if [[ "$confirm" == "y" ]]; then trash-empty echo "回收站已清空。" @@ -6783,7 +6783,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME + read -e -p "请输入要删除的备份文件名: " BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -6908,7 +6908,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "错误: SSH 用户名格式不正确。" + echo "錯誤: SSH 使用者名稱格式不正確。" return 1 fi @@ -7050,7 +7050,7 @@ delete_connection() { # 使用連接 use_connection() { send_stats "使用連接" - read -e -p "請輸入要使用的連接編號:" num + read -e -p "请输入要使用的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -7082,7 +7082,7 @@ use_connection() { sshpass -p "$password_or_key" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" - echo "1. 用户名和密码是否正确。" + echo "1. 使用者名稱和密碼是否正確。" echo "2. 目標伺服器是否允許密碼登入。" echo "3. 目標伺服器的 SSH 服務是否正常運作。" fi @@ -7145,7 +7145,7 @@ list_partitions() { } -# 持久化掛載分區 +# 持久化挂载分区 mount_partition() { send_stats "掛載分割區" read -e -p "請輸入要掛載的分割區名稱(例如 sda1):" PARTITION @@ -7179,7 +7179,7 @@ mount_partition() { return 1 fi - # 创建挂载点 + # 建立掛載點 mkdir -p "$MOUNT_POINT" # 掛載 @@ -7223,7 +7223,7 @@ unmount_partition() { echo "分割區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分區卸載失敗!" + echo "分区卸载失败!" fi } @@ -7296,7 +7296,7 @@ check_partition() { fi # 檢查分區狀態 - echo "檢查分割區 /dev/$PARTITION的狀態:" + echo "检查分区 /dev/$PARTITION的狀態:" fsck "/dev/$PARTITION" } @@ -7311,7 +7311,7 @@ disk_manager() { list_partitions echo "------------------------" echo "1. 掛載分割區 2. 卸載分割區 3. 檢視已掛載分割區" - echo "4. 格式化分区 5. 检查分区状态" + echo "4. 格式化分割區 5. 檢查分割區狀態" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7354,7 +7354,7 @@ add_task() { read -e -p "請輸入遠端目錄:" remote_path while true; do - read -e -p "请输入远程用户@IP: " remote + read -e -p "請輸入遠端使用者@IP:" remote if kj_ssh_parse_remote "$remote" "root"; then remote="$KJ_SSH_REMOTE" break @@ -7391,11 +7391,11 @@ add_task() { # 刪除任務 delete_task() { send_stats "刪除同步任務" - read -e -p "请输入要删除的任务编号: " num + read -e -p "請輸入要刪除的任務編號:" num local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误:未找到对应的任务。" + echo "錯誤:未找到對應的任務。" return fi @@ -7519,13 +7519,13 @@ schedule_task() { local cron_job="$cron_time k rsync_run $num" local cron_job="$cron_time k rsync_run $num" - # 检查是否已存在相同任务 + # 檢查是否已存在相同任務 if crontab -l | grep -q "k rsync_run $num"; then - echo "錯誤: 該任務的定時同步已存在!" + echo "错误: 该任务的定时同步已存在!" return fi - # 建立到使用者的 crontab + # 创建到用户的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - echo "定時任務已建立:$cron_job" } @@ -7568,7 +7568,7 @@ rsync_manager() { echo echo "1. 建立新任務 2. 刪除任務" echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" - echo "5. 创建定时任务 6. 删除定时任务" + echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" echo "---------------------------------" @@ -7660,14 +7660,14 @@ linux_info() { echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" - echo -e "${gl_kjlan}CPU核心数: ${gl_bai}$cpu_cores" + echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU佔用:${gl_bai}$cpu_usage_percent%" - echo -e "${gl_kjlan}系统负载: ${gl_bai}$load" - echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" - echo -e "${gl_kjlan}物理内存: ${gl_bai}$mem_info" + echo -e "${gl_kjlan}系統負載:${gl_bai}$load" + echo -e "${gl_kjlan}TCP|UDP連線數:${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}實體記憶體:${gl_bai}$mem_info" echo -e "${gl_kjlan}虛擬記憶體:${gl_bai}$swap_info" echo -e "${gl_kjlan}硬碟佔用:${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" @@ -7757,8 +7757,8 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" @@ -7795,7 +7795,7 @@ linux_tools() { clear echo "工具已安裝,使用方法如下:" wget --help - send_stats "安装wget" + send_stats "安裝wget" ;; 3) clear @@ -8137,7 +8137,7 @@ docker_ssh_migration() { # 如果該 Compose 項目已經打包過,跳過 if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}Compose 項目 [$project_name] 已备份过,跳过重复打包...${gl_bai}" + echo -e "${gl_huang}Compose 項目 [$project_name] 已備份過,跳過重複打包...${gl_bai}" continue fi @@ -8298,7 +8298,7 @@ docker_ssh_migration() { fi # 啟動容器 - echo "执行还原命令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" + echo "執行還原指令: docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done @@ -8334,7 +8334,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${gl_huang}傳輸備份中...${gl_bai}" + echo -e "${gl_huang}传输备份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then # 使用密鑰登入 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -8418,7 +8418,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" + echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" echo -e "${gl_kjlan}20. ${gl_bai}解除安裝Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -8497,7 +8497,7 @@ linux_docker() { echo "網路操作" echo "------------------------" echo "1. 建立網絡" - echo "2. 加入网络" + echo "2. 加入網絡" echo "3. 退出網絡" echo "4. 刪除網絡" echo "------------------------" @@ -8523,7 +8523,7 @@ linux_docker() { 3) send_stats "加入網路" read -e -p "退出網路名稱:" dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8533,7 +8533,7 @@ linux_docker() { 4) send_stats "刪除網絡" - read -e -p "请输入要删除的网络名: " dockernetwork + read -e -p "請輸入要刪除的網路名稱:" dockernetwork docker network rm $dockernetwork ;; @@ -8686,19 +8686,19 @@ linux_test() { while true; do clear - # send_stats "测试脚本合集" + # send_stats "測試腳本集合" echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP及解鎖狀態偵測" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" - echo -e "${gl_kjlan}2. ${gl_bai}Region 流媒体解锁测试" - echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 流媒体解锁检测" - echo -e "${gl_kjlan}4. ${gl_bai}xykt IP质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" + echo -e "${gl_kjlan}2. ${gl_bai}Region 串流解鎖測試" + echo -e "${gl_kjlan}3. ${gl_bai}yeahwu 串流媒體解鎖偵測" + echo -e "${gl_kjlan}4. ${gl_bai}xykt IP品質體檢腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" - echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三网回程线路测试" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" + echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" @@ -8773,7 +8773,7 @@ linux_test() { echo "可參考的IP列表" echo "------------------------" echo "北京電信: 219.141.136.12" - echo "北京联通: 202.106.50.1" + echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" echo "上海聯通: 210.22.97.1" @@ -8865,7 +8865,7 @@ linux_Oracle() { while true; do clear - send_stats "甲骨文云脚本合集" + send_stats "甲骨文雲腳本合集" echo -e "甲骨文雲腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}安裝閒置機器活躍腳本" @@ -9130,8 +9130,11 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/main/Discuz_X3.5_SC_UTF8_20250901.zip - unzip latest.zip + LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) + wget -O latest.zip ${LATEST_URL} + unzip -q latest.zip + mv upload/* . + rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip restart_ldnmp @@ -9170,7 +9173,8 @@ linux_ldnmp() { cd /home/web/html mkdir $yuming cd $yuming - wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/1.50.02.zip + LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox @@ -9459,7 +9463,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" + echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目錄下" read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then @@ -9543,7 +9547,7 @@ linux_ldnmp() { echo "資料庫匯入的表數據" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql - echo "数据库导入完成" + echo "資料庫導入完成" ;; *) echo @@ -9794,7 +9798,7 @@ linux_ldnmp() { read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" + kj_ssh_read_host_port "请输入远端服务器IP: " "目標伺服器SSH連接埠 [預設22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -9832,7 +9836,7 @@ linux_ldnmp() { sed -i "s/123456/$usepasswd/g" ${useip}_beifen.sh echo "------------------------" - echo "1. 每周备份 2. 每天备份" + echo "1. 每週備份 2. 每天備份" read -e -p "請輸入你的選擇:" dingshi case $dingshi in @@ -9843,7 +9847,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "選擇每天備份的時間(小時,0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -10101,7 +10105,7 @@ moltbot_menu() { if [ "$local_version" != "$remote_version" ]; then echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" fi } @@ -10141,7 +10145,7 @@ moltbot_menu() { echo "2. 啟動" echo "3. 停止" echo "--------------------" - echo "4. 状态日志查看" + echo "4. 狀態日誌查看" echo "5. 換模型" echo "6. API管理" echo "7. 機器人連線對接" @@ -10162,7 +10166,7 @@ moltbot_menu() { echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" - printf "请输入选项并回车: " + printf "請輸入選項並回車:" } @@ -10240,7 +10244,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') + print('ℹ️ 未偵測到 API providers,跳過模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10422,7 +10426,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API刪失敗Provider-確認') - summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') else: send_stat('OpenClaw API刪失敗Provider-拒絕') summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') @@ -10582,8 +10586,8 @@ PY } view_logs() { - echo "查看 OpenClaw 狀態日誌" - send_stats "查看 OpenClaw 日誌" + echo "查看 OpenClaw 状态日志" + send_stats "查看 OpenClaw 日志" openclaw status openclaw gateway status openclaw logs @@ -10594,7 +10598,7 @@ PY - # OpenClaw API 協定偵測邏輯已移除:不再自動偵測/判定 API 類型。 + # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 # 說明:API 類型由使用者明確配置(models.providers..api),腳本不再嘗試呼叫 /responses 做推論。 # 建構模型配置 JSON @@ -10733,7 +10737,7 @@ EOF write-openclaw-provider-models "$provider_name" "$base_url" "$api_key" "$models_array" if [[ $? -eq 0 ]]; then - echo "✅ 成功添加$model_count 个模型到 $provider_name" + echo "✅ 成功添加$model_count個模型到$provider_name" echo "📦 模型引用格式:$provider_name/" return 0 else @@ -10998,12 +11002,12 @@ sync-openclaw-provider-interactive() { send_stats "OpenClaw API按Provider同步" if [ ! -f "$config_file" ]; then - echo "❌ 未找到設定檔:$config_file" + echo "❌ 未找到配置文件: $config_file" break_end return 1 fi - read -erp "請輸入要同步的 API 名稱(provider),直接回車同步全部:" provider_name + read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway @@ -11220,10 +11224,10 @@ PY2 start_gateway ;; 2) - echo "❌ 同步失敗:provider 不存在或未配置" + echo "❌ 同步失败:provider 不存在或未配置" ;; 3) - echo "❌ 同步失敗:provider 配置不完整或類型不支持" + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11266,14 +11270,14 @@ fix-openclaw-provider-protocol-interactive() { echo "請選擇要設定的 API 類型:" echo "1. openai-completions" echo "2. openai-responses" - read -erp "請輸入你的選擇 (1/2):" proto_choice + read -erp "请输入你的选择 (1/2): " proto_choice local new_api="" case "$proto_choice" in 1) new_api="openai-completions" ;; 2) new_api="openai-responses" ;; *) - echo "❌ 無效選擇" + echo "❌ 无效选择" break_end return 1 ;; @@ -11334,7 +11338,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API刪除入口" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11534,7 +11538,7 @@ PY echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" - echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推薦入口${gl_bai}" + echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" echo "" echo -e "${gl_huang}提示:複製連結到瀏覽器開啟即可訪問${gl_bai}" echo "" @@ -11940,7 +11944,7 @@ PYTHON_EOF fi if [ "$confirm_switch" != "yes" ]; then - echo "已返回模型選擇清單。" + echo "已返回模型选择列表。" sleep 1 continue fi @@ -12205,11 +12209,11 @@ PYTHON_EOF echo "" echo "⚙️ 功能擴充:" echo "- [lobster] # 審批流 (附人工確認)" - echo "- [voice-call] # 語音通話能力" - echo "- [nostr] # 加密隱私聊天" + echo " - [voice-call] # 语音通话能力" + echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" - echo "1) 安裝/啟用插件" + echo "1) 安装/启用插件" echo "2) 刪除/停用插件" echo "0) 返回" read -e -p "請選擇操作:" plugin_action @@ -12319,10 +12323,10 @@ PYTHON_EOF openclaw skills list echo "----------------------------------------" - # 输出推荐的实用技能列表 - echo "推荐的实用技能(可直接复制名称输入):" + # 輸出建議的實用技能列表 + echo "建議的實用技能(可直接複製名稱輸入):" echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 页面、数据库和块" + echo "notion # 操作 Notion 頁面、資料庫和區塊" echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" echo "1password # 自動化讀取和注入 1Password 金鑰" @@ -12338,7 +12342,7 @@ PYTHON_EOF echo "----------------------------------------" echo "1) 安裝技能" - echo "2) 刪除技能" + echo "2) 删除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -12639,7 +12643,7 @@ openclaw_json_get_bool() { fi wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") - echo "本機狀態(僅本機配置/緩存,不做網路探測):" + echo "本地状态(仅本机配置/缓存,不做网络探测):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飛書(Lark)" "$feishu_status" openclaw_print_bot_status_line "WhatsApp" "$wa_status" @@ -12659,9 +12663,9 @@ openclaw_json_get_bool() { openclaw_show_bot_local_status_block echo "----------------------------------------" echo "1. Telegram 機器人對接" - echo "2. 飞书 (Lark) 机器人对接" - echo "3. WhatsApp 机器人对接" - echo "4. QQ 机器人对接" + echo "2. 飛書 (Lark) 機器人對接" + echo "3. WhatsApp 機器人對接" + echo "4. QQ 機器人對接" echo "5. 微信機器人對接" echo "----------------------------------------" echo "0. 返回上一級選單" @@ -12827,7 +12831,7 @@ EOF local real_type real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) if [ "$real_type" != "$expected_type" ]; then - echo "❌ 备份类型不匹配,期望: $expected_type,實際: ${real_type:-未知}" + echo "❌ 備份類型不匹配,期望:$expected_type,實際: ${real_type:-未知}" return 1 fi @@ -12883,7 +12887,7 @@ for item in workspaces: else: shutil.copytree(src, os.path.join(target_dir, f), dirs_exist_ok=True) " "$workspaces_json" "$tmp_payload" if ! find "$tmp_payload" -mindepth 1 -print -quit | grep -q .; then - echo "❌ 未找到可备份的记忆文件"; rm -rf "$tmp_payload"; break_end; return 1 + echo "❌ 未找到可備份的記憶文件"; rm -rf "$tmp_payload"; break_end; return 1 fi if openclaw_pack_backup_archive "memory-full" "multi-agent" "$tmp_payload" "$out_file"; then echo "✅ 記憶全量備份完成 (含多智能體):$out_file"; openclaw_offer_transfer_hint "$out_file" @@ -12896,7 +12900,7 @@ for item in workspaces: openclaw_memory_backup_import() { send_stats "OpenClaw記憶全量還原" local archive_path=$(openclaw_read_import_path "還原記憶全量 (支援多智能體)") - [ -z "$archive_path" ] && { echo "❌ 未輸入路徑"; break_end; return 1; } + [ -z "$archive_path" ] && { echo "❌ 未输入路径"; break_end; return 1; } local tmp_unpack=$(mktemp -d) || return 1 local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } local workspaces_json=$(openclaw_get_all_agent_workspaces) @@ -13355,13 +13359,13 @@ PY store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then echo "⚠️ [$agent_id] 未找到索引庫文件,可能為空或不存在。" - echo "Store 原始值: ${store_raw:-<空>}" - echo "仍將執行重建索引。" + echo " Store 原始值: ${store_raw:-<空>}" + echo " 仍将执行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ [$agent_id] 已備份索引:$backup_file" + echo "✅ [$agent_id] 已备份索引: $backup_file" else echo "⚠️ [$agent_id] 索引備份失敗,繼續重建。" fi @@ -13566,12 +13570,12 @@ PY OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路徑") fi case "$model_status" in - ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案存在") ;; + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型來自 HF 下載來源(國內可能慢/失敗)") ;; - *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可訪問") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else @@ -13716,11 +13720,11 @@ PY return 1 fi if ! qmd --version >/dev/null 2>&1; then - echo "❌ qmd 安装后仍无法运行" + echo "❌ qmd 安裝後仍無法運作" return 1 fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" - echo "✅ qmd 安装完成: $qmd_path" + echo "✅ qmd 安裝完成:$qmd_path" return 0 } @@ -13827,10 +13831,10 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正確" + echo "✅ memory.qmd.command 已正确" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 預熱索引(可能下載模型)" + echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace_all local preh_agent_lines preh_agent_id preh_workspace preh_agent_lines=$(openclaw_memory_list_agents) @@ -13843,11 +13847,11 @@ EOF else echo "⏭️ 已跳過預熱" fi - echo "✅ QMD 自动部署完成" + echo "✅ QMD 自動部署完成" } openclaw_memory_auto_setup_local() { - echo "🔍 检测 Local 环境" + echo "🔍 偵測 Local 環境" openclaw_memory_cleanup_legacy_keys local backend provider backend=$(openclaw_memory_get_backend) @@ -13862,7 +13866,7 @@ EOF echo "✅ memorySearch.provider 已是 local" else openclaw_memory_config_set "agents.defaults.memorySearch.provider" "local" - echo "✅ 已设置 agents.defaults.memorySearch.provider=local" + echo "✅ 已設定 agents.defaults.memorySearch.provider=local" fi local model_path model_status @@ -13870,7 +13874,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ 模型文件已存在: $model_path" + echo "✅ 模型檔已存在:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -13884,14 +13888,14 @@ EOF if [ -f "$model_dest" ]; then echo "✅ 已發現預設模型檔:$model_dest" else - echo "⬇️ 下载模型: $model_url" + echo "⬇️ 下載模型:$model_url" openclaw_memory_download_file "$model_url" "$model_dest" || return 1 echo "✅ 模型已下載:$model_dest" fi OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" - echo "✅ 已写入模型路径" + echo "✅ 已寫入模型路徑" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -13951,7 +13955,7 @@ EOF openclaw_memory_render_auto_summary return 0 fi - echo "♻️ 重启 OpenClaw 网关" + echo "♻️ 重啟 OpenClaw 網關" if declare -F start_gateway >/dev/null 2>&1; then start_gateway else @@ -13966,7 +13970,7 @@ EOF while true; do clear echo "=======================================" - echo "记忆方案自动部署" + echo "記憶方案自動部署" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14044,7 +14048,7 @@ EOF local backend include_dm backend=$(openclaw_memory_get_backend) if [ "$backend" = "qmd" ] && ! command -v qmd >/dev/null 2>&1; then - echo "⚠️ 检测到当前方案为 QMD,但未安装 qmd 命令。" + echo "⚠️ 偵測到目前方案為 QMD,但未安裝 qmd 指令。" echo "可切換 Local,或安裝 bun + qmd 後再試。" fi include_dm=$(openclaw config get memory.qmd.includeDefaultMemory 2>/dev/null) @@ -14098,11 +14102,11 @@ EOF builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac - echo "当前方案: $current_label" + echo "當前方案:$current_label" echo "" echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" - echo "Auto : 自動推薦(基於可用性 + 網路探測)" + echo "Auto : 自动推荐(基于可用性 + 网络探测)" echo "---------------------------------------" echo "1. 切換 QMD(自動部署/已安裝則跳過)" echo "2. 切換 Local(自動部署/已安裝則跳過)" @@ -14189,7 +14193,7 @@ EOF local default_lines=120 local start_line count echo "文件:$file" - echo "总行数: $total_lines" + echo "總行數:$total_lines" read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line read -e -p "請輸入顯示行數(回車預設$default_lines): " count [ -z "$count" ] && count=$default_lines @@ -14201,7 +14205,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 请输入有效的数字。" + echo "❌ 請輸入有效的數字。" return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14216,7 +14220,7 @@ EOF end_line=$total_lines fi if [ "$total_lines" -eq 0 ]; then - echo "(空白文件)" + echo "(空文件)" return 0 fi echo "---------------------------------------" @@ -14283,7 +14287,7 @@ EOF openclaw_memory_render_status echo "1. 更新記憶索引" echo "2. 檢視記憶文件" - echo "3. 索引修复(Indexed 异常)" + echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" echo "5. 搜尋測試(驗證索引是否運作)" echo "6. 深度狀態探測(檢查嵌入模型)" @@ -14293,7 +14297,7 @@ EOF case "$memory_choice" in 1) echo "即將更新記憶索引。" - read -e -p "第一次確認:輸入 yes 繼續:" confirm_step1 + read -e -p "第一次确认:输入 yes 继续: " confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消。" break_end @@ -14317,7 +14321,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14364,7 +14368,7 @@ EOF openclaw_permission_require_openclaw() { if ! openclaw_has_command openclaw; then - echo "❌ 未检测到 openclaw 命令,请先安装或初始化 OpenClaw。" + echo "❌ 未偵測到 openclaw 指令,請先安裝或初始化 OpenClaw。" return 1 fi return 0 @@ -14396,10 +14400,10 @@ EOF return 1 fi cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { - echo "❌ 权限恢复失败:$backup_file" + echo "❌ 權限恢復失敗:$backup_file" return 1 } - echo "✅ 已恢復切換前權限配置" + echo "✅ 已恢复切换前权限配置" openclaw_permission_restart_gateway || true return 0 } @@ -14526,7 +14530,7 @@ try: elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": print("開發增強模式") elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": - print("完全开放模式") + print("完全開放模式") else: print("自訂模式") except Exception: @@ -14542,7 +14546,7 @@ PY mkdir -p "$HOME/.openclaw" - # 生成 JSON 并通过 openclaw approvals set --stdin 写入(优先) + # 產生 JSON 並透過 openclaw approvals set --stdin 寫入(優先) # 若 CLI 不支援則回退直接寫文件 local json_payload json_payload=$(python3 -c ' @@ -14589,18 +14593,18 @@ print(json.dumps(data, indent=2)) local current_mode="未知 / 自訂" if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then - current_mode="\033[1;31m完全开放模式\033[0m" + current_mode="\033[1;31m完全開放模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then - current_mode="\033[1;33m开发增强模式\033[0m" + current_mode="\033[1;33m開發增強模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then - current_mode="\033[1;32m标准安全模式\033[0m" + current_mode="\033[1;32m標準安全模式\033[0m" elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then current_mode="\033[1;36m官方沙盒兜底\033[0m" fi - echo -e " 当前综合安全等级: ${current_mode}" + echo -e "當前綜合安全等級:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[应用层 Tool Policy 状态]${gl_bai}" - echo " Profile (预设): ${current_profile:-(unset)}" + echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" + echo "Profile (預設): ${current_profile:-(unset)}" echo "Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" @@ -14632,7 +14636,7 @@ except Exception as e: print("(解析失敗:" + str(e) + ")") ' "$approvals_json" else - echo "(openclaw approvals get --json 無輸出)" + echo " (openclaw approvals get --json 无输出)" fi elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then python3 -c ' @@ -14737,7 +14741,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "是否嘗試自動修復發現的安全隱患? (y/n):" fix_choice + read -e -p "是否尝试自动修复发现的安全隐患? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復完成。${gl_bai}" @@ -14781,13 +14785,13 @@ except Exception as e: fi echo "---------------------------------------" echo "1. 新增白名單規則" - echo "2. 移除白名單規則" + echo "2. 移除白名单规则" echo "0. 返回" echo "---------------------------------------" read -e -p "請選擇:" al_choice case "$al_choice" in 1) - read -e -p "輸入要放行的命令路徑 (支援 glob,如 /usr/bin/git):" pattern + read -e -p "输入要放行的命令路径 (支持 glob,如 /usr/bin/git): " pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } read -e -p "指定智能體ID (留空=所有智能體 *):" agent_id agent_id="${agent_id:-*}" @@ -14795,7 +14799,7 @@ except Exception as e: break_end ;; 2) - read -e -p "輸入要移除的命令路徑:" pattern + read -e -p "输入要移除的命令路径: " pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -14807,7 +14811,7 @@ except Exception as e: } openclaw_permission_menu() { - send_stats "OpenClaw權限管理" + send_stats "OpenClaw权限管理" while true; do clear echo "=======================================" @@ -14819,7 +14823,7 @@ except Exception as e: echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" - echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" + echo -e "${gl_kjlan}5.${gl_bai}運行底層安全審計與自動修復" echo -e "${gl_kjlan}6.${gl_bai}管理 Exec 指令白名單" echo -e "${gl_kjlan}0.${gl_bai}回上一級" echo "---------------------------------------" @@ -14832,14 +14836,14 @@ except Exception as e: break_end ;; 2) - echo "準備應用:開發增強模式" + echo "准备应用:开发增强模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" - read -e -p "輸入 FULL 確認繼續:" confirm + read -e -p "输入 FULL 确认继续: " confirm if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end ;; @@ -15044,15 +15048,15 @@ PY config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) echo "設定檔: ${config_file:-$(openclaw_permission_config_file)}" - echo "默认智能体: $default_agent" + echo "預設智能體:$default_agent" python3 -c ' import json,sys agents=json.loads(sys.argv[1] or "[]") bindings=json.loads(sys.argv[2] or "[]") sess_obj=json.loads(sys.argv[3] or "{}") sessions=sess_obj.get("sessions",[]) if isinstance(sess_obj,dict) else [] -print("已配置智能体数: %s" % len(agents)) -print("路由绑定数: %s" % len(bindings)) +print("已配置智能體數: %s" % len(agents)) +print("路由綁定數: %s" % len(bindings)) print("會話總數: %s" % len(sessions)) print("---------------------------------------") if not agents: @@ -15091,7 +15095,7 @@ for idx,item in enumerate(agents,1): [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 read -e -p "請輸入 workspace 路徑(預設為 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "將創建智能體:$agent_id" + echo "将创建智能体: $agent_id" echo "工作目錄:$workspace" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } @@ -15152,7 +15156,7 @@ for idx,item in enumerate(bindings,1): read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then - echo "✅ 路由绑定添加成功" + echo "✅ 路由綁定新增成功" else echo "❌ 路由綁定新增失敗" return 1 @@ -15172,7 +15176,7 @@ for idx,item in enumerate(bindings,1): if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ 路由綁定移除成功" else - echo "❌ 路由绑定移除失败" + echo "❌ 路由綁定移除失敗" return 1 fi } @@ -15191,7 +15195,7 @@ by_agent={} for item in sessions: aid = item.get("agentId","?") by_agent[aid] = by_agent.get(aid, 0) + 1 -print("会话汇总:") +print("會話匯總:") for agent_id,count in sorted(by_agent.items()): print("- %s: %s" % (agent_id, count)) print("---------------------------------------") @@ -15209,12 +15213,12 @@ for item in sessions[:10]: } openclaw_multiagent_health_check() { - send_stats "OpenClaw多智能體-健康檢查" + send_stats "OpenClaw多智能体-健康检查" openclaw_multiagent_require_openclaw || return 1 local config_file config_file=$(openclaw_multiagent_config_file) echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" - openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" + openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" python3 -c ' import json,sys,os agents=json.loads(sys.argv[1] or "[]") @@ -15255,7 +15259,7 @@ print("✅ 多智能體健康檢查完成") local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" - echo "也可以从 IDENTITY.md 自动读取身份信息。" + echo "也可以從 IDENTITY.md 自動讀取身分資訊。" read -e -p "是否從 IDENTITY.md 讀取? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" @@ -15265,7 +15269,7 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "即將清理過期/冗餘會話資料..." + echo "即将清理过期/冗余会话数据..." read -e -p "輸入 yes 確認:" confirm [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } openclaw sessions cleanup @@ -15280,13 +15284,13 @@ print("✅ 多智能體健康檢查完成") echo "=======================================" openclaw_multiagent_render_status echo "---------------------------------------" - echo "1. 新增智能体" + echo "1. 新增智能體" echo "2. 刪除智能體" echo "3. 查看路由綁定" echo "4. 新增路由綁定" echo "5. 移除路由綁定" echo "6. 查看會話概況" - echo "7. 執行多智能體健康檢查" + echo "7. 运行多智能体健康检查" echo "8. 修改智能體身分(名稱/Emoji)" echo "9. 清理過期會話" echo "0. 返回上一級" @@ -15315,7 +15319,7 @@ openclaw_backup_restore_menu() { while true; do clear echo "=======================================" - echo "OpenClaw 备份与还原" + echo "OpenClaw 備份與還原" echo "=======================================" openclaw_backup_render_file_list echo "---------------------------------------" @@ -15367,7 +15371,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15434,7 +15438,7 @@ openclaw_backup_restore_menu() { - # 添加域名(调用你给的函数) + # 新增網域(呼叫你給的函數) openclaw_domain_webui() { add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 18789 @@ -15459,7 +15463,7 @@ openclaw_backup_restore_menu() { if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已将域名 ${yuming}加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi @@ -15491,7 +15495,7 @@ openclaw_backup_restore_menu() { clear openclaw_show_webui_addr echo - echo "1. 添加域名访问" + echo "1. 添加網域訪問" echo "2. 刪除網域名稱訪問" echo "0. 退出" echo @@ -15603,11 +15607,11 @@ while true; do echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" + echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" @@ -15623,9 +15627,9 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" - echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" + echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}補貨監控工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" @@ -15635,12 +15639,12 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自架AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp影片下載工具" + echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo檔案傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影視" echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}線上DOS老遊戲" echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智慧文件管理系統" echo -e "${gl_kjlan}79. ${color79}Beszel伺服器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" @@ -15649,15 +15653,15 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari伺服器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" echo -e "${gl_kjlan}85. ${color85}immich圖片影片管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自架直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox檔案快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -15677,7 +15681,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") # 檢查安裝狀態 (匹配 appno.txt 中的 ID) - # 这里假设 appno.txt 中记录的是 base_name (即文件名) + # 這裡假設 appno.txt 中記錄的是 base_name (即檔名) if echo "$app_numbers" | grep -q "^$base_name$"; then # 如果已安裝:顯示 base_name - 描述 [已安裝] (綠色) echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[已安裝]${gl_bai}" @@ -15797,7 +15801,7 @@ while true; do local docker_describe="一個Nginx反向代理工具面板,不支援新增網域存取。" local docker_url="官網介紹: https://nginxproxymanager.com/" local docker_use="echo \"初始使用者名稱: admin@example.com\"" - local docker_passwd="echo \"初始密码: changeme\"" + local docker_passwd="echo \"初始密碼: changeme\"" local app_size="1" docker_app @@ -15950,8 +15954,8 @@ while true; do } - local docker_describe="qbittorrent離線BT磁力下載服務" - local docker_url="官網介紹: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent离线BT磁力下载服务" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -16002,7 +16006,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "请设置邮箱域名 例如 mail.yuming.com : " yuming + read -e -p "請設定郵箱網域名稱 例如 mail.yuming.com :" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16159,8 +16163,8 @@ while true; do } local docker_describe="禪道是通用的專案管理軟體" - local docker_url="官網介紹: https://www.zentao.net/" - local docker_use="echo \"初始使用者名稱: admin\"" + local docker_url="官网介绍: https://www.zentao.net/" + local docker_use="echo \"初始用户名: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -16187,7 +16191,7 @@ while true; do } - local docker_describe="青龍面板是一個定時任務管理平台" + local docker_describe="青龙面板是一个定时任务管理平台" local docker_url="官網介紹:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" @@ -16333,7 +16337,7 @@ while true; do local docker_describe="AdGuardHome是一款全網廣告攔截與反追蹤軟體,未來不只一個DNS伺服器。" - local docker_url="官網介紹: https://hub.docker.com/r/adguard/adguardhome" + local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -16362,7 +16366,7 @@ while true; do } local docker_describe="onlyoffice是一款開源的線上office工具,太強大了!" - local docker_url="官網介紹: https://www.onlyoffice.com/" + local docker_url="官网介绍: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -16379,9 +16383,9 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" - echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服务 $check_docker" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi @@ -16402,7 +16406,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已經安裝完成" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -16415,7 +16419,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已經更新完成" + echo "雷池WAF面板已经更新完成" check_docker_app_ip ;; 3) @@ -16426,7 +16430,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是預設安裝目錄那現在項目已經卸載。如果你是自訂安裝目錄你需要到安裝目錄下自行執行:" + echo "如果你是預設安裝目錄那現在項目已經卸載。如果你是自定义安装目录你需要到安装目录下自行执行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -16529,7 +16533,7 @@ while true; do } - local docker_describe="Memos是一款輕量、自架的備忘錄中心" + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -16591,7 +16595,7 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" local docker_url="官網介紹: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" @@ -16835,7 +16839,7 @@ while true; do local docker_describe="極簡朋友圈,高仿微信朋友圈,記錄你的美好生活" local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"账号: admin 密码: a123456\"" + local docker_use="echo \"帳號: admin 密碼: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -16941,7 +16945,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 原耗子麵板" + local panelname="AcePanel 原耗子面板" local panelurl="官方地址:${gh_proxy}github.com/acepanel/panel" panel_app_install() { @@ -17135,7 +17139,7 @@ while true; do } - local docker_describe="這是一個普羅米修斯的主機資料擷取元件,請部署在被監控主機上。" + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" @@ -17188,7 +17192,7 @@ while true; do } - local docker_describe="这是一款网站变化检测、补货监控和通知的小工具" + local docker_describe="這是一個網站變更偵測、補貨監控和通知的小工具" local docker_url="官網介紹:${gh_https_url}github.com/dgtlmoon/changedetection.io" local docker_use="" local docker_passwd="" @@ -17467,7 +17471,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow知識庫" - local app_text="基於深度文件理解的開源 RAG(檢索增強生成)引擎" + local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" local app_url="官方網站:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17877,7 +17881,7 @@ while true; do } - local docker_describe="是一個中文DOS遊戲收藏網站" + local docker_describe="是一个中文DOS游戏合集网站" local docker_url="官網介紹:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" @@ -18112,7 +18116,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -18124,7 +18128,7 @@ while true; do } local docker_describe="高效能AI介面透明代理服務" - local docker_url="官網介紹: https://www.gpt-load.com/" + local docker_url="官网介绍: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18156,9 +18160,9 @@ while true; do } - local docker_describe="輕量級的自架伺服器監控工具" + local docker_describe="轻量级的自托管服务器监控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -18561,8 +18565,8 @@ while true; do local app_id="95" local app_name="paperless文件管理平台" - local app_text="開源的電子文件管理系統,它的主要用途是把你的紙本文件數位化並管理起來。" - local app_url="影片介紹: https://docs.paperless-ngx.com/" + local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" + local app_url="视频介绍: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -18840,7 +18844,7 @@ while true; do local app_id="99" local app_name="dsm群暉虛擬機" - local app_text="Docker容器中的虚拟DSM" + local app_text="Docker容器中的虛擬DSM" local app_url="官網:${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" @@ -18923,7 +18927,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19320,7 +19324,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ${docker_img} } - local docker_describe="是一个运行在 Docker 中的 Firefox 浏览器,支持通过网页直接访问桌面版浏览器界面。" + local docker_describe="是一個運行在 Docker 中的 Firefox 瀏覽器,支援透過網頁直接存取桌面版瀏覽器介面。" local docker_url="項目地址:${gh_https_url}github.com/jlesage/docker-firefox" local docker_use="" local docker_passwd="" @@ -19550,7 +19554,7 @@ linux_work() { fi send_stats "SSH常駐模式" echo -e "SSH常駐模式${tmux_sshd_status}" - echo "开启后SSH连接后会直接进入常驻模式,直接回到之前的工作状态。" + echo "開啟後SSH連線後會直接進入常駐模式,直接回到先前的工作狀態。" echo "------------------------" echo "1. 開啟 2. 關閉" echo "------------------------" @@ -19767,7 +19771,7 @@ net_menu() { echo "4. 刷新網卡資訊" echo "0. 返回上一級選單" echo "====================================" - read -erp "请选择操作: " choice + read -erp "請選擇操作:" choice case $choice in 1) @@ -19776,7 +19780,7 @@ net_menu() { if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else - echo "✘ 網路卡不存在" + echo "✘ 网卡不存在" fi read -erp "按回車繼續..." ;; @@ -19984,7 +19988,7 @@ env_menu() { edit_file() { local file="$1" - send_stats "编辑变量文件 $file" + send_stats "編輯變數文件$file" install nano nano "$file" } @@ -20008,7 +20012,7 @@ env_menu() { echo "3. 查看 ~/.profile" echo "4. 編輯 ~/.bashrc" echo "5. 編輯 ~/.profile" - echo "6. 重新載入環境變數(source)" + echo "6. 重新加载环境变量(source)" echo "--------------------------------------" echo "0. 返回上一級選單" echo "--------------------------------------" @@ -20135,7 +20139,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高風險漏洞" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux核心升級${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" @@ -20276,7 +20280,7 @@ EOF send_stats "開放埠" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "連接埠已全部開放" + echo "端口已全部开放" ;; 6) @@ -20367,7 +20371,7 @@ EOF echo "" echo "------------------------" - echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" + echo "1. IPv4 優先 2. IPv6 優先權 3. IPv6 修復工具" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20514,7 +20518,7 @@ EOF sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "请输入要删除的用户名: " username + read -e -p "請輸入要刪除的使用者名稱:" username userdel -r "$username" ;; @@ -20598,7 +20602,7 @@ EOF echo "時區切換" echo "------------------------" echo "亞洲" - echo "1. 中国上海时间 2. 中国香港时间" + echo "1. 中國上海時間 2. 中國香港時間" echo "3. 日本東京時間 4. 韓國首爾時間" echo "5. 新加坡時間 6. 印度加爾各答時間" echo "7. 阿聯酋杜拜時間 8. 澳洲雪梨時間" @@ -20814,7 +20818,7 @@ EOF while true; do clear echo "本機host解析列表" - echo "如果你在这里添加解析匹配,将不再使用动态解析了" + echo "如果你在這裡添加解析匹配,將不再使用動態解析了" cat /etc/hosts echo "" echo "操作" @@ -20904,7 +20908,7 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流關機已設定" + echo "限流关机已设置" send_stats "限流關機已設定" ;; 2) @@ -20932,8 +20936,8 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" - echo "到達閾值後會向用戶發送預警訊息" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "到达阈值后会向用户发预警消息" echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21088,8 +21092,8 @@ EOF echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo -e "5. 啟動fail2ban防禦SSH暴力破解" echo -e "6. 開放所有端口" - echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" - echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" + echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" + echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" @@ -21173,7 +21177,7 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}正在采集数据${gl_bai}" + local status_message="${gl_lv}正在採集數據${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then local status_message="${gl_hui}採集已關閉${gl_bai}" else @@ -21187,7 +21191,7 @@ EOF echo -e "目前狀態:$status_message" echo "--------------------" echo "1. 開啟採集" - echo "2. 關閉採集" + echo "2. 关闭采集" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -21307,7 +21311,7 @@ linux_file() { 3) # 修改目录权限 read -e -p "請輸入目錄名:" dirname read -e -p "請輸入權限 (如 755):" perm - chmod "$perm" "$dirname" && echo "权限已修改" || echo "修改失敗" + chmod "$perm" "$dirname" && echo "權限已修改" || echo "修改失敗" send_stats "修改目錄權限" ;; 4) # 重命名目录 @@ -21344,7 +21348,7 @@ linux_file() { ;; 14) # 重命名文件 read -e -p "請輸入目前檔名:" current_name - read -e -p "请输入新文件名: " new_name + read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" ;; @@ -21360,7 +21364,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21410,7 +21414,7 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" + echo "錯誤: 文件不存在。" send_stats "傳送文件失敗: 文件不存在" continue fi @@ -21450,7 +21454,7 @@ EOF break ;; *) # 处理无效输入 - echo "無效的選擇,請重新輸入" + echo "无效的选择,请重新输入" send_stats "無效選擇" ;; esac @@ -21532,7 +21536,7 @@ while true; do 1) send_stats "新增叢集伺服器" read -e -p "伺服器名稱:" server_name - read -e -p "伺服器IP:" server_ip + read -e -p "服务器IP: " server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} read -e -p "伺服器使用者名稱(root):" server_username @@ -21639,7 +21643,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" +echo -e "${gl_kjlan}VPS更多热门优惠${gl_bai}" echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21730,7 +21734,7 @@ while true; do clear echo "更新日誌" echo "------------------------" - echo "全部日志: ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" + echo "全部日誌:${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt" echo "------------------------" curl -s --max-time 15 ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/kejilion_sh_log.txt | tail -n 30 @@ -21789,7 +21793,7 @@ while true; do cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" - send_stats "脚本已经最新$sh_v_new" + send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" # 恢復備份 @@ -21922,8 +21926,8 @@ done k_info() { send_stats "k指令參考用例" echo "-------------------" -echo "影片介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" -echo "以下是k命令参考用例:" +echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "以下是k命令參考用例:" echo "啟動腳本 k" echo "安裝軟體包 k install nano wget | k add nano wget | k 安裝 nano wget" echo "卸載軟體包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸載 nano wget" @@ -21953,14 +21957,14 @@ echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" -echo "LDNMP快取清理 k web cache" +echo "LDNMP缓存清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" +echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" @@ -22223,7 +22227,7 @@ else ;; github ) shift - send_stats "从 GitHub 导入 SSH 公钥" + send_stats "從 GitHub 導入 SSH 公鑰" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From 26d12d5a0860fb4d76b30d42096c6a8d4efbe8b5 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 4 Jun 2026 22:06:56 +0800 Subject: [PATCH 1193/1285] =?UTF-8?q?fix:=20SSH=E7=AB=AF=E5=8F=A3=E5=86=99?= =?UTF-8?q?=E5=85=A5=E4=BD=8D=E7=BD=AE=E4=BF=AE=E5=A4=8D=20=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E8=90=BD=E5=85=A5Match=E5=9D=97=E5=AF=BC=E8=87=B4sshd?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 部分系统(Debian 12 cloud/阿里云/腾讯云等)的sshd_config末尾 含有Match块, echo Port >> 追加会将Port写入Match块内部, 而OpenSSH不允许Match块内放Port指令, 导致sshd无法启动。 修复: 改用 sed -i '1i Port' 插入到文件首行, 确保在所有Match块之前。 --- cn/kejilion.sh | 2 +- en/kejilion.sh | 2 +- ir/kejilion.sh | 4 ++-- jp/kejilion.sh | 2 +- kejilion.sh | 2 +- kr/kejilion.sh | 2 +- ru/kejilion.sh | 4 ++-- tw/kejilion.sh | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index adeb807fc..5815f6b11 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config diff --git a/en/kejilion.sh b/en/kejilion.sh index 303451e7f..59c420d51 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config diff --git a/ir/kejilion.sh b/ir/kejilion.sh index 354b351ca..93c1fff20 100644 --- a/ir/kejilion.sh +++ b/ir/kejilion.sh @@ -3763,8 +3763,8 @@ new_ssh_port() { # از فایلهای پیکربندی SSH پشتیبان تهیه کنید cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* diff --git a/jp/kejilion.sh b/jp/kejilion.sh index d5affeaf7..316fb5d59 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config diff --git a/kejilion.sh b/kejilion.sh index 82825cfea..661b0e82c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 1aef2c766..fa5de0c0f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config diff --git a/ru/kejilion.sh b/ru/kejilion.sh index 622d63220..aa8505e4f 100644 --- a/ru/kejilion.sh +++ b/ru/kejilion.sh @@ -3790,8 +3790,8 @@ new_ssh_port() { # Резервное копирование файлов конфигурации SSH cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - sed -i "s/Port [0-9]\+/Port $new_port/g" /etc/ssh/sshd_config + sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* diff --git a/tw/kejilion.sh b/tw/kejilion.sh index c77d1d37b..fb0fe6d8d 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -4911,7 +4911,7 @@ new_ssh_port() { cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config - echo "Port $new_port" >> /etc/ssh/sshd_config + sed -i "1i Port $new_port" /etc/ssh/sshd_config correct_ssh_config From 05aa7335e9344ca1b9b321d8e45051f86929f995 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 7 Jun 2026 06:26:01 +0000 Subject: [PATCH 1194/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-06-07=2006:26:01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 38 ++-- jp/kejilion.sh | 132 ++++++------- kr/kejilion.sh | 126 ++++++------- tw/kejilion.sh | 488 ++++++++++++++++++++++++------------------------- 4 files changed, 392 insertions(+), 392 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 59c420d51..52b1d94f5 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -2324,7 +2324,7 @@ check_nginx_compression() { # Check whether zstd is on and uncommented (the whole line starts with zstd on;) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd compression is enabled" + zstd_status="zstd compression is on" else zstd_status="" fi @@ -3602,7 +3602,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -5094,7 +5094,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -6549,7 +6549,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}Change completed.重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}Change completed. Reconnect to SSH to see the changes!${gl_bai}" hash -r break_end @@ -7071,7 +7071,7 @@ use_connection() { echo "3. Whether the target server allows login using a key." fi else - # 使用密码连接 + # Connect using password if ! command -v sshpass &> /dev/null; then echo "Error: sshpass is not installed, please install sshpass first." echo "Installation method:" @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -10147,7 +10147,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API Management" + echo "6. API management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10571,8 +10571,8 @@ PY start_bot() { - echo "Start OpenClaw..." - send_stats "Start OpenClaw..." + echo "Starting OpenClaw..." + send_stats "Starting OpenClaw..." start_gateway break_end } @@ -12215,7 +12215,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12343,7 +12343,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -14572,7 +14572,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: Write the file directly + # Fallback: write file directly echo "$json_payload" > "$approvals_file" } @@ -15100,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅The agent is created successfully:$agent_id" + echo "✅ The agent was created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -15974,7 +15974,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -19381,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "Restore all apps" - echo "Available app backups" + echo "Available application backups" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -20197,7 +20197,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20383,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -21924,7 +21924,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 316fb5d59..f0b3856f3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1541,7 +1541,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2240,8 +2240,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd がオンでコメントが解除されているかどうかを確認します (行全体が zstd on で始まります)。 if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd圧縮が有効になっています" + zstd_status="zstd圧縮がオンになっています" else zstd_status="" fi @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4838,7 +4838,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5609,7 +5609,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) + # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5621,7 +5621,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません。XanMod ソースを構成できません" + echo "システムコードネームを取得できません、XanMod ソースを構成できません" return 1 fi @@ -5900,7 +5900,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6013,7 +6013,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6377,9 +6377,9 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) - [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自动调优模式" + [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" if [ -n "$current_mode" ]; then echo -e "現在のモード:${gl_lv}${current_mode}${gl_bai}" @@ -6824,7 +6824,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7324,7 +7324,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7583,7 +7583,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7645,7 +7645,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -8127,7 +8127,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8157,7 +8157,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包体積:$path" + echo "梱包量:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8304,7 +8304,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -10421,12 +10421,12 @@ for name, provider in list(providers.items()): data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: summary.append(f'⚠️ {name}: /models の検出に失敗しました。{attempts} 回再試行しました ({type(err).__name__}: {err})') - send_stat('OpenClaw API确认介入') + send_stat('OpenClaw API は介入を確認しました') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10571,8 +10571,8 @@ PY start_bot() { - echo "OpenClaw を開始します..." - send_stats "OpenClaw を開始します..." + echo "OpenClaw を開始しています..." + send_stats "OpenClaw を開始しています..." start_gateway break_end } @@ -10741,7 +10741,7 @@ EOF echo "📦 モデル参照形式:$provider_name/" return 0 else - echo "❌ 構成の挿入に失敗しました" + echo "❌ 配置注入失败" return 1 fi } @@ -10754,7 +10754,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ デフォルトのモデルを空にすることはできません" + echo "❌ 默认模型不能为空" return 1 fi @@ -10830,7 +10830,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -12203,7 +12203,7 @@ PYTHON_EOF echo "- [whatsapp] #WhatsApp オートメーション" echo "" echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル取得)" + echo "- [memory-core] # 基本メモリ (ファイル検索)" echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" @@ -12335,7 +12335,7 @@ PYTHON_EOF echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンを制御する" + echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12666,7 +12666,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5. WeChatロボットのドッキング" + echo "5.WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12687,7 +12687,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13970,7 +13970,7 @@ EOF while true; do clear echo "=======================================" - echo "メモリソリューションの自動導入" + echo "メモリソリューションの自動展開" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14031,7 +14031,7 @@ EOF } openclaw_memory_offer_restart() { - echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -15100,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました。$agent_id" + echo "✅ エージェントが正常に作成されました:$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -18327,7 +18327,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -18743,7 +18743,7 @@ while true; do sleep 2 echo - echo -e "${gl_huang}すべてのクライアント QR コード構成:${gl_bai}" + echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo @@ -19262,7 +19262,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19381,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "すべてのアプリを復元する" - echo "利用可能なアプリのバックアップ" + echo "利用可能なアプリケーションのバックアップ" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -19444,7 +19444,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19782,7 +19782,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19792,7 +19792,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19804,7 +19804,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19855,7 +19855,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19865,7 +19865,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19880,7 +19880,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19968,7 +19968,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -19983,7 +19983,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -19999,7 +19999,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -20127,7 +20127,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20383,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -21132,11 +21132,11 @@ EOF echo "------------------------------------------------" bbr_on - echo -e "[${gl_lv}OK${gl_bai}] 7/12.開ける${gl_huang}BBR${gl_bai}加速する" + echo -e "[${gl_lv}OK${gl_bai}】7/12。開ける${gl_huang}BBR${gl_bai}加速する" echo "------------------------------------------------" set_timedate Asia/Shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}】8/12。タイムゾーンを次のように設定します${gl_huang}上海${gl_bai}" echo "------------------------------------------------" auto_optimize_dns @@ -21179,7 +21179,7 @@ EOF if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then local status_message="${gl_lv}データの収集${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_hui}采集已关闭${gl_bai}" + local status_message="${gl_hui}コレクションは終了しました${gl_bai}" else local status_message="不確実なステータス" fi @@ -21378,7 +21378,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21398,7 +21398,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21924,7 +21924,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -21972,16 +21972,16 @@ echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" echo "システム情報を表示 k info" -echo "ROOT キー管理 k sshkey" +echo "ROOT密钥管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " -echo "SSH 公開キーのインポート (GitHub) k sshkey github " +echo "SSH公钥导入(GitHub) k sshkey github " } if [ "$#" -eq 0 ]; then - # 引数なしで対話型ロジックを実行します + # 如果没有参数,运行交互式逻辑 kejilion_sh else # パラメータがある場合は、対応する関数を実行します diff --git a/kr/kejilion.sh b/kr/kejilion.sh index fa5de0c0f..d13db781b 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -508,22 +508,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -2324,7 +2324,7 @@ check_nginx_compression() { # zstd가 켜져 있고 주석 처리가 해제되어 있는지 확인하세요. (전체 줄은 zstd on으로 시작됩니다.) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd 압축이 활성화되었습니다" + zstd_status="zstd 압축이 켜져 있습니다" else zstd_status="" fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3423,7 +3423,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4106,7 +4106,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4168,7 +4168,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4983,7 +4983,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5900,7 +5900,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6636,7 +6636,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7305,7 +7305,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8095,7 +8095,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -8569,7 +8569,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -10510,7 +10510,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10571,8 +10571,8 @@ PY start_bot() { - echo "OpenClaw를 시작하세요..." - send_stats "OpenClaw를 시작하세요..." + echo "OpenClaw를 시작하는 중..." + send_stats "OpenClaw를 시작하는 중..." start_gateway break_end } @@ -12108,7 +12108,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -12215,7 +12215,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12239,7 +12239,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인 중:$plugin_id" + echo "🔍 플러그인 상태 확인:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12256,7 +12256,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12343,7 +12343,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12687,7 +12687,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13025,7 +13025,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13145,7 +13145,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 백업 파일 삭제" + send_stats "OpenClaw 삭제 백업 파일" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13686,7 +13686,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13831,7 +13831,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command가 정확합니다." fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -14205,7 +14205,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 번호를 입력하세요." + echo "❌ 유효한 숫자를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14307,7 +14307,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14321,7 +14321,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -14572,7 +14572,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일을 직접 작성 + # 대체: 파일 직접 쓰기 echo "$json_payload" > "$approvals_file" } @@ -14799,7 +14799,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15100,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15269,7 +15269,7 @@ print("✅멀티에이전트 헬스체크 완료") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "만료되었거나 중복된 세션 데이터를 곧 정리 중입니다..." + echo "만료되거나 중복된 세션 데이터를 곧 정리합니다..." read -e -p "확인하려면 yes를 입력하세요." confirm [ "$confirm" != "yes" ] && { echo "취소"; return 0; } openclaw sessions cleanup @@ -15615,7 +15615,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15663,7 +15663,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15672,7 +15672,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15894,7 +15894,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15974,7 +15974,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16006,7 +16006,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -17245,7 +17245,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17407,7 +17407,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17988,7 +17988,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18928,7 +18928,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19277,7 +19277,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -19381,7 +19381,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "모든 앱 복원" - echo "사용 가능한 앱 백업" + echo "사용 가능한 애플리케이션 백업" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -20007,7 +20007,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20126,7 +20126,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -20383,8 +20383,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "먼저 IPv6로 전환됨" - send_stats "먼저 IPv6로 전환됨" + echo "IPv6 우선순위로 전환됨" + send_stats "IPv6 우선순위로 전환됨" ;; 3) @@ -20679,7 +20679,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20934,7 +20934,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21484,7 +21484,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 순회하고 명령을 실행합니다. + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -21924,7 +21924,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21958,17 +21958,17 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index fb0fe6d8d..bc84be599 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -522,7 +522,7 @@ while true; do docker rm -f $dockername ;; 5) - send_stats "重启指定容器" + send_stats "重啟指定容器" read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker restart $dockername ;; @@ -762,17 +762,17 @@ docker_ipv6_on() { # 使用jq處理設定檔的更新 local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # 检查当前配置是否已经有 ipv6 设置 + # 檢查目前配置是否已經有 ipv6 設定 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') - # 更新配置,开启 IPv6 + # 更新配置,開啟 IPv6 if [[ "$CURRENT_IPV6" == "false" ]]; then UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') else UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 比較原始配置與新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}目前已開啟ipv6訪問${gl_bai}" else @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}設定檔不存在${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi @@ -801,7 +801,7 @@ docker_ipv6_off() { # 使用jq處理設定檔的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') - # 检查当前的 ipv6 状态 + # 檢查目前的 ipv6 狀態 local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') # 比較原始配置與新配置 @@ -1167,7 +1167,7 @@ iptables_panel() { ;; 7) # 清除指定 IP - read -e -p "请输入清除的IP: " d_ip + read -e -p "請輸入清除的IP:" d_ip iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 判断是否需要创建虚拟内存 +# 判斷是否需要建立虛擬記憶體 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "網站資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1546,7 +1546,7 @@ certs_status() { echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" - echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" + echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" echo "------------------------" echo "1. 重新申請 2. 匯入已有憑證 0. 退出" echo "------------------------" @@ -1577,8 +1577,8 @@ certs_status() { cert_content+="${line}"$'\n' done - # 2. 输入私钥 (兼容 RSA, ECC, PKCS#8) - echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" + # 2. 輸入私鑰 (相容 RSA, ECC, PKCS#8) + echo "請貼上 憑證私鑰 (Private Key) 內容 (按兩次回車結束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1594,15 +1594,15 @@ certs_status() { chmod 644 "$cert_file" chmod 600 "$key_file" - # 识别当前证书类型并显示 + # 識別目前證書類型並顯示 if [[ "$key_content" == *"EC PRIVATE KEY"* ]]; then echo "偵測到 ECC 憑證已成功儲存。" else - echo "检测到 RSA 证书已成功保存。" + echo "偵測到 RSA 憑證已成功儲存。" fi auth_method="ssl_imported" else - echo "错误:无效的证书或私钥格式!" + echo "錯誤:無效的憑證或私鑰格式!" certs_status fi ;; @@ -1617,7 +1617,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "網域重複使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1626,8 +1626,8 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" - read -e -p "请输入你的IP或者解析过的域名: " yuming + echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + read -e -p "請輸入你的IP或解析過的網域名稱:" yuming } @@ -1638,7 +1638,7 @@ check_ip_and_get_access_port() { local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then - read -e -p "请输入访问/监听端口,回车默认使用 80: " access_port + read -e -p "請輸入訪問/監聽端口,回車預設使用 80:" access_port access_port=${access_port:-80} fi } @@ -1650,13 +1650,13 @@ update_nginx_listen_port() { local access_port="$2" local conf="/home/web/conf.d/${yuming}.conf" - # 如果 access_port 为空,则跳过 + # 如果 access_port 為空,則跳過 [ -z "$access_port" ] && return 0 - # 删除所有 listen 行 + # 刪除所有 listen 行 sed -i '/^[[:space:]]*listen[[:space:]]\+/d' "$conf" - # 在 server { 后插入新的 listen + # 在 server { 後插入新的 l​​isten sed -i "/server {/a\\ listen ${access_port};\\ listen [::]:${access_port}; @@ -1751,8 +1751,8 @@ cf_purge_cache() { read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" - read -e -p "請輸入你的 API_TOKEN:" API_TOKEN - read -e -p "請輸入你的CF用戶名:" EMAIL + read -e -p "请输入你的 API_TOKEN: " API_TOKEN + read -e -p "请输入你的CF用户名: " EMAIL read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS mkdir -p /home/web/config/ @@ -1977,7 +1977,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 開啟 Brotli:去掉註釋 + # 开启 Brotli:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2033,7 +2033,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # 开启 Zstd:去掉注释 + # 開啟 Zstd:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2233,11 +2233,11 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf后台,站点-安全性-事件中查看拦截记录" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) - send_stats "高负载开启5秒盾" + send_stats "高負載開啟5秒盾" echo -e "${gl_huang}網站每5分鐘自動偵測,當達偵測到高負載會自動開盾,低負載也會自動關閉5秒盾。${gl_bai}" echo "--------------" echo "取得CF參數:" @@ -2566,12 +2566,12 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- + # --- 場景 B: 特殊指定 (即便在 Docker Hub,也想透過 GitHub Release 判斷) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) else - # --- 场景 C: 标准 Docker Hub --- + # --- 場景 C: 標準 Docker Hub --- local image_repo=${full_image_name%%:*} local image_tag=${full_image_name##*:} [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" @@ -2600,7 +2600,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 取得容器的 IP 位址 + # 获取容器的 IP 地址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2913,7 +2913,7 @@ while true; do add_app_id clear - echo "$docker_name 已经安装完成" + echo "$docker_name已經安裝完成" check_docker_app_ip echo "" $docker_use @@ -2928,7 +2928,7 @@ while true; do add_app_id clear - echo "$docker_name 已经安装完成" + echo "$docker_name已經安裝完成" check_docker_app_ip echo "" $docker_use @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "应用已卸载" + echo "應用程式已解除安裝" send_stats "解除安裝$docker_name" ;; @@ -3234,14 +3234,14 @@ f2b_basic_config() { local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # Alpine 預設 jail 通常為 sshd;僅當偵測到自訂 alpine-sshd 規則時才切換 + # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi fi echo "即將配置 SSH jail:$jail_name" - read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime + read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry @@ -3359,10 +3359,10 @@ ldnmp_install_status_one() { ldnmp_install_all() { cd ~ -send_stats "安装LDNMP环境" +send_stats "安裝LDNMP環境" root_use clear -echo -e "${gl_huang}LDNMP环境未安装,开始安装LDNMP环境...${gl_bai}" +echo -e "${gl_huang}LDNMP環境未安裝,開始安裝LDNMP環境...${gl_bai}" check_disk_space 3 /home install_dependency install_docker @@ -3375,7 +3375,7 @@ install_ldnmp nginx_install_all() { cd ~ -send_stats "安装nginx环境" +send_stats "安裝nginx環境" root_use clear echo -e "${gl_huang}nginx未安裝,開始安裝nginx環境...${gl_bai}" @@ -3704,7 +3704,7 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四层代理" + send_stats "修改四層代理" ;; 6) send_stats "刪除轉送配置" @@ -3871,7 +3871,7 @@ ldnmp_web_status() { echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" - echo "20. 删除指定站点数据" + echo "20. 刪除指定站點數據" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -3890,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3931,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "編輯網站配置" - read -e -p "編輯網站配置,請輸入你要編輯的網域:" yuming + read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4009,12 +4009,12 @@ while true; do clear check_panel_app echo -e "$panelname $check_panel" - echo "${panelname}是一款时下流行且强大的运维管理面板。" - echo "官网介绍: $panelurl " + echo "${panelname}是一款時下流行且強大的維運管理面板。" + echo "官網介紹:$panelurl " echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 安裝 2. 管理 3. 卸載" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4169,7 +4169,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4185,7 +4185,7 @@ delete_forwarding_service() { read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服務$service_name 已成功从 frpc.toml 删除" + echo "服務$service_name已成功從 frpc.toml 刪除" docker restart frpc @@ -4195,7 +4195,7 @@ delete_forwarding_service() { list_forwarding_services() { local config_file="$1" - # 打印表头 + # 列印表頭 printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" awk ' @@ -4216,7 +4216,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服務訊息,在處理新服務之前列印目前服務 + # 如果已有服务信息,在处理新服务之前打印当前服务 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4292,7 +4292,7 @@ generate_access_urls() { # 只在有有效連接埠時顯示標題和內容 if [ "$has_valid_ports" = true ]; then - echo "FRP服務對外存取位址:" + echo "FRP服务对外访问地址:" # 處理 IPv4 位址 for port in "${ports[@]}"; do @@ -4301,7 +4301,7 @@ generate_access_urls() { fi done - # 處理 IPv6 位址(如果存在) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4446,7 +4446,7 @@ frpc_panel() { echo -e "FRP客戶端$check_frp $update_status" echo "與服務端對接,對接後可建立內網穿透服務到網際網路存取" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -4537,16 +4537,16 @@ yt_menu_pro() { clear send_stats "yt-dlp 下載工具" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" + echo -e "yt-dlp 是一個功能強大的影片下載工具,支援 YouTube、Bilibili、Twitter 等數千網站。" echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下载视频列表:" + echo "已下載影片清單:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" - echo "1. 安装 2. 更新 3. 卸载" + echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" - echo "5. 单个视频下载 6. 批量视频下载 7. 自定义参数下载" - echo "8. 下载为MP3音频 9. 删除视频目录 10. Cookie管理(开发中)" + echo "5. 單一影片下載 6. 大量影片下載 7. 自訂參數下載" + echo "8. 下載為MP3音訊 9.刪除影片目錄 10. Cookie管理(開發中)" echo "-------------------------" echo "0. 返回上一級選單" echo "-------------------------" @@ -4785,7 +4785,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4953,7 +4953,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5021,7 +5021,7 @@ fetch_remote_ssh_keys() { echo " ${keys_url}" echo "" - # 创建临时文件 + # 建立臨時文件 temp_file=$(mktemp) # 下載公鑰 @@ -5038,7 +5038,7 @@ fetch_remote_ssh_keys() { return 1 } else - echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + echo "錯誤:系統中未找到 curl 或 wget,無法下載公鑰" >&2 rm -f "${temp_file}" return 1 fi @@ -5098,19 +5098,19 @@ fetch_github_ssh_keys() { echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" - echo " 5. 点击 Add SSH key 完成添加" + echo "5. 點選 Add SSH key 完成新增" echo "" - echo "添加完成后,GitHub 会公开提供您的所有公钥,地址为:" - echo " ${gh_https_url}github.com/您的用户名.keys" + echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" + echo " ${gh_https_url}github.com/您的使用者名稱.keys" echo "" if [[ -z "${username}" ]]; then - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username fi if [[ -z "${username}" ]]; then - echo "错误:GitHub 用户名不能为空" >&2 + echo "錯誤:GitHub 使用者名稱不能為空" >&2 return 1 fi @@ -5133,7 +5133,7 @@ sshkey_panel() { IS_KEY_ENABLED="${gl_hui}未啟用${gl_bai}" fi echo -e "使用者密鑰登入模式${IS_KEY_ENABLED}" - echo "进阶玩法: https://blog.kejilion.pro/ssh-key" + echo "進階玩法: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" @@ -5168,14 +5168,14 @@ sshkey_panel() { ;; 5) - send_stats "编辑公钥文件" + send_stats "編輯公鑰文件" install nano nano ${HOME}/.ssh/authorized_keys break_end ;; 6) - send_stats "查看本机密钥" + send_stats "查看本機密鑰" echo "------------------------" echo "公鑰資訊" cat ${HOME}/.ssh/authorized_keys @@ -5312,7 +5312,7 @@ dd_xitong() { echo "--------------------------------" echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " - echo -e "${gl_hui}bin456789项目地址: ${gh_https_url}github.com/bin456789/reinstall${gl_bai}" + echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" @@ -5417,7 +5417,7 @@ dd_xitong() { ;; 23) - send_stats "重装alma10" + send_stats "重裝alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -5561,7 +5561,7 @@ dd_xitong() { ;; 45) - send_stats "重裝windows server 22" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -5696,7 +5696,7 @@ bbrv3() { check_disk_space 3 check_swap xanmod_add_repo || { - echo "XanMod官方倉庫配置失敗,請稍後重試" + echo "XanMod官方仓库配置失败,请稍后重试" return 1 } @@ -5708,7 +5708,7 @@ bbrv3() { apt update -y if [ "$action" = "update" ]; then apt install -y --only-upgrade "$package" || apt install -y "$package" || { - echo "XanMod内核更新失败,请检查软件源或稍后重试" + echo "XanMod核心更新失敗,請檢查軟體來源或稍後重試" return 1 } else @@ -5732,7 +5732,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod内核已卸载。重啟後生效" + echo "XanMod核心已卸載。重啟後生效" server_reboot } @@ -5746,7 +5746,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "当前环境不支持,仅支持Debian和Ubuntu系统" + echo "目前環境不支持,僅支援Debian和Ubuntu系統" break_end linux_Settings fi @@ -5831,7 +5831,7 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安裝 ELRepo 倉庫設定 (版本 9)..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "安裝 ELRepo 倉庫設定 (版本 10)..." @@ -5900,7 +5900,7 @@ elrepo() { echo "影片介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "僅支援紅帽系列發行 CentOS/RedHat/Alma/Rocky/oracle" - echo "升級Linux核心可提升系統效能與安全,建議有條件的嘗試,生產環境謹慎升級!" + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -5967,7 +5967,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜索FOUND关键字确认病毒位置 ${gl_bai}" + echo -e "${gl_lv}如果有病毒請在${gl_huang}scan.log${gl_lv}文件中搜尋FOUND關鍵字確認病毒位置${gl_bai}" } @@ -6432,7 +6432,7 @@ Kernel_optimize() { cd ~ clear _kernel_optimize_core "遊戲服優化模式" "game" - send_stats "游戏服优化" + send_stats "遊戲服優化" ;; 6) cd ~ @@ -6641,7 +6641,7 @@ linux_trash() { ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站為空" echo "------------------------" echo "1. 啟用回收站 2. 關閉回收站" - echo "3. 還原內容 4. 清空回收站" + echo "3. 还原内容 4. 清空回收站" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6674,7 +6674,7 @@ linux_trash() { fi ;; 4) - read -e -p "确认清空回收站?[y/n]: " confirm + read -e -p "確認清空回收站? [y/n]:" confirm if [[ "$confirm" == "y" ]]; then trash-empty echo "回收站已清空。" @@ -6783,7 +6783,7 @@ list_backups() { delete_backup() { send_stats "刪除備份" - read -e -p "请输入要删除的备份文件名: " BACKUP_NAME + read -e -p "請輸入要刪除的備份檔名:" BACKUP_NAME # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then @@ -6954,7 +6954,7 @@ kj_ssh_read_auth() { done if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then - echo "無效的密鑰內容!" + echo "无效的密钥内容!" return 1 fi @@ -7073,7 +7073,7 @@ use_connection() { else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "错误:未安装 sshpass,请先安装 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7145,7 +7145,7 @@ list_partitions() { } -# 持久化挂载分区 +# 持久化掛載分區 mount_partition() { send_stats "掛載分割區" read -e -p "請輸入要掛載的分割區名稱(例如 sda1):" PARTITION @@ -7189,7 +7189,7 @@ mount_partition() { return 1 fi - echo "分割區已成功掛載到$MOUNT_POINT" + echo "分區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7223,7 +7223,7 @@ unmount_partition() { echo "分割區卸載成功:$MOUNT_POINT" rmdir "$MOUNT_POINT" else - echo "分区卸载失败!" + echo "分區卸載失敗!" fi } @@ -7296,7 +7296,7 @@ check_partition() { fi # 檢查分區狀態 - echo "检查分区 /dev/$PARTITION的狀態:" + echo "檢查分割區 /dev/$PARTITION的狀態:" fsck "/dev/$PARTITION" } @@ -7521,11 +7521,11 @@ schedule_task() { # 檢查是否已存在相同任務 if crontab -l | grep -q "k rsync_run $num"; then - echo "错误: 该任务的定时同步已存在!" + echo "錯誤: 該任務的定時同步已存在!" return fi - # 创建到用户的 crontab + # 建立到使用者的 crontab (crontab -l 2>/dev/null; echo "$cron_job") | crontab - echo "定時任務已建立:$cron_job" } @@ -7560,7 +7560,7 @@ rsync_manager() { while true; do clear echo "Rsync 遠端同步工具" - echo "遠端目錄之間同步,支援增量同步,高效穩定。" + echo "远程目录之间同步,支持增量同步,高效稳定。" echo "---------------------------------" list_tasks echo @@ -7757,8 +7757,8 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" - echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" @@ -8132,7 +8132,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未偵測到 compose 目錄,請手動輸入路徑:" project_dir + read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -8302,7 +8302,7 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8334,7 +8334,7 @@ docker_ssh_migration() { local LATEST_TAR="$BACKUP_DIR" - echo -e "${gl_huang}传输备份中...${gl_bai}" + echo -e "${gl_huang}傳輸備份中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then # 使用密鑰登入 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" @@ -8418,7 +8418,7 @@ linux_docker() { echo -e "${gl_kjlan}11. ${gl_bai}開啟Docker-ipv6訪問" echo -e "${gl_kjlan}12. ${gl_bai}關閉Docker-ipv6訪問" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}19. ${gl_bai}备份/迁移/还原Docker环境" + echo -e "${gl_kjlan}19. ${gl_bai}備份/遷移/還原Docker環境" echo -e "${gl_kjlan}20. ${gl_bai}解除安裝Docker環境" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -8702,7 +8702,7 @@ linux_test() { echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" @@ -9463,7 +9463,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" - echo "目前只允许上传zip格式的源码包,请将源码包放到/home/web/html/${yuming}目錄下" + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then @@ -9798,7 +9798,7 @@ linux_ldnmp() { read -e -p "要傳送備份資料到遠端伺服器嗎? (Y/N):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "请输入远端服务器IP: " "目標伺服器SSH連接埠 [預設22]:" "22" + kj_ssh_read_host_port "請輸入遠端伺服器IP:" "目標伺服器SSH連接埠 [預設22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -9825,7 +9825,7 @@ linux_ldnmp() { 33) clear send_stats "定時遠端備份" - read -e -p "輸入遠端伺服器IP:" useip + read -e -p "输入远程服务器IP: " useip read -e -p "輸入遠端伺服器密碼:" usepasswd cd ~ @@ -9965,7 +9965,7 @@ linux_ldnmp() { ;; 3) local ldnmp_pods="php" - read -e -p "請輸入${ldnmp_pods}版本号 (如: 7.4 8.0 8.1 8.2 8.3)(回车获取最新版): " version + read -e -p "請輸入${ldnmp_pods}版本號 (如: 7.4 8.0 8.1 8.2 8.3)(回車取得最新版):" version local version=${version:-8.3} cd /home/web/ cp /home/web/docker-compose.yml /home/web/docker-compose1.yml @@ -10103,9 +10103,9 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else - echo "${gl_lv}当前版本已是最新:$local_version${gl_bai}" + echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" fi } @@ -10426,7 +10426,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API刪失敗Provider-確認') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') else: send_stat('OpenClaw API刪失敗Provider-拒絕') summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') @@ -10586,8 +10586,8 @@ PY } view_logs() { - echo "查看 OpenClaw 状态日志" - send_stats "查看 OpenClaw 日志" + echo "查看 OpenClaw 狀態日誌" + send_stats "查看 OpenClaw 日誌" openclaw status openclaw gateway status openclaw logs @@ -10775,7 +10775,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11002,12 +11002,12 @@ sync-openclaw-provider-interactive() { send_stats "OpenClaw API按Provider同步" if [ ! -f "$config_file" ]; then - echo "❌ 未找到配置文件: $config_file" + echo "❌ 未找到設定檔:$config_file" break_end return 1 fi - read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name + read -erp "請輸入要同步的 API 名稱(provider),直接回車同步全部:" provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway @@ -11224,10 +11224,10 @@ PY2 start_gateway ;; 2) - echo "❌ 同步失败:provider 不存在或未配置" + echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失败:provider 配置不完整或类型不支持" + echo "❌ 同步失敗:provider 配置不完整或類型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" @@ -11270,14 +11270,14 @@ fix-openclaw-provider-protocol-interactive() { echo "請選擇要設定的 API 類型:" echo "1. openai-completions" echo "2. openai-responses" - read -erp "请输入你的选择 (1/2): " proto_choice + read -erp "請輸入你的選擇 (1/2):" proto_choice local new_api="" case "$proto_choice" in 1) new_api="openai-completions" ;; 2) new_api="openai-responses" ;; *) - echo "❌ 无效选择" + echo "❌ 無效選擇" break_end return 1 ;; @@ -11314,7 +11314,7 @@ with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ 已更新 provider {name} 協定為: {new_api}') +print(f'✅ 已更新 provider {name} 协议为: {new_api}') PY local rc=$? case "$rc" in @@ -11338,7 +11338,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API删除入口" + send_stats "OpenClaw API刪除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11461,7 +11461,7 @@ with open(path, 'w', encoding='utf-8') as f: f.write('\n') print(f'🗑️ 已刪除 provider: {name}') -print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 個關聯模型引用') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') PY local rc=$? case "$rc" in @@ -11538,7 +11538,7 @@ PY echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" - echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" + echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推薦入口${gl_bai}" echo "" echo -e "${gl_huang}提示:複製連結到瀏覽器開啟即可訪問${gl_bai}" echo "" @@ -11894,7 +11894,7 @@ PYTHON_EOF return 0 else if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 不可用,傳回舊版輸入模式。" + echo "gum 不可用,返回旧版输入模式。" sleep 1 continue fi @@ -11944,7 +11944,7 @@ PYTHON_EOF fi if [ "$confirm_switch" != "yes" ]; then - echo "已返回模型选择列表。" + echo "已返回模型選擇清單。" sleep 1 continue fi @@ -12029,7 +12029,7 @@ PYTHON_EOF fi done - [ "$count" -gt 0 ] && echo "✅ 已同步$count個 agent 的會話模型為$model_ref" + [ "$count" -gt 0 ] && echo "✅ 已同步$count 个 agent 的会话模型为 $model_ref" return 0 } @@ -12208,12 +12208,12 @@ PYTHON_EOF echo "- [copilot-proxy] # Copilot 介面轉發" echo "" echo "⚙️ 功能擴充:" - echo "- [lobster] # 審批流 (附人工確認)" - echo " - [voice-call] # 语音通话能力" - echo " - [nostr] # 加密隐私聊天" + echo " - [lobster] # 审批流 (带人工确认)" + echo "- [voice-call] # 語音通話能力" + echo "- [nostr] # 加密隱私聊天" echo "--------------------------------------------------------" - echo "1) 安装/启用插件" + echo "1) 安裝/啟用插件" echo "2) 刪除/停用插件" echo "0) 返回" read -e -p "請選擇操作:" plugin_action @@ -12304,7 +12304,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重啟 OpenClaw 服務以載入變更..." + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway fi break_end @@ -12324,14 +12324,14 @@ PYTHON_EOF echo "----------------------------------------" # 輸出建議的實用技能列表 - echo "建議的實用技能(可直接複製名稱輸入):" + echo "推荐的实用技能(可直接复制名称输入):" echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" echo "notion # 操作 Notion 頁面、資料庫和區塊" echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" echo "1password # 自動化讀取和注入 1Password 金鑰" echo "gog # Google Workspace (Gmail/雲端盤/文件) 全能助手" - echo "things-mac # 深度整合 Things 3 任務管理" + echo "things-mac # 深度整合 Things 3 任务管理" echo "bluebubbles # 透過 BlueBubbles 完美收發 iMessage" echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" echo "summarize # 網頁/播客/YouTube 影片內容一鍵總結" @@ -12342,7 +12342,7 @@ PYTHON_EOF echo "----------------------------------------" echo "1) 安裝技能" - echo "2) 删除技能" + echo "2) 刪除技能" echo "0) 返回" read -e -p "請選擇操作:" skill_action @@ -12476,7 +12476,7 @@ openclaw_json_get_bool() { return 0 fi - # 相容於兩種常見目錄命名: + # 兼容两种常见目录命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 @@ -12643,7 +12643,7 @@ openclaw_json_get_bool() { fi wx_status=$(openclaw_bot_status_text "$wx_enabled" "$wx_cfg" "$wx_connected" "$wx_abnormal") - echo "本地状态(仅本机配置/缓存,不做网络探测):" + echo "本機狀態(僅本機配置/緩存,不做網路探測):" openclaw_print_bot_status_line "Telegram" "$tg_status" openclaw_print_bot_status_line "飛書(Lark)" "$feishu_status" openclaw_print_bot_status_line "WhatsApp" "$wa_status" @@ -12900,7 +12900,7 @@ for item in workspaces: openclaw_memory_backup_import() { send_stats "OpenClaw記憶全量還原" local archive_path=$(openclaw_read_import_path "還原記憶全量 (支援多智能體)") - [ -z "$archive_path" ] && { echo "❌ 未输入路径"; break_end; return 1; } + [ -z "$archive_path" ] && { echo "❌ 未輸入路徑"; break_end; return 1; } local tmp_unpack=$(mktemp -d) || return 1 local pkg_dir=$(openclaw_prepare_import_archive "memory-full" "$archive_path" "$tmp_unpack") || { rm -rf "$tmp_unpack"; break_end; return 1; } local workspaces_json=$(openclaw_get_all_agent_workspaces) @@ -13359,13 +13359,13 @@ PY store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then echo "⚠️ [$agent_id] 未找到索引庫文件,可能為空或不存在。" - echo " Store 原始值: ${store_raw:-<空>}" - echo " 仍将执行重建索引。" + echo "Store 原始值: ${store_raw:-<空>}" + echo "仍將執行重建索引。" else ts=$(date +%Y%m%d_%H%M%S) backup_file="${store_file}.bak.${ts}" if mv "$store_file" "$backup_file"; then - echo "✅ [$agent_id] 已备份索引: $backup_file" + echo "✅ [$agent_id] 已備份索引:$backup_file" else echo "⚠️ [$agent_id] 索引備份失敗,繼續重建。" fi @@ -13570,12 +13570,12 @@ PY OPENCLAW_MEMORY_RECOMMEND_REASON+=("未配置本地模型路徑") fi case "$model_status" in - ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案存在") ;; hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型來自 HF 下載來源(國內可能慢/失敗)") ;; - *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件不存在或不可用") ;; + *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可訪問") elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else @@ -13705,7 +13705,7 @@ PY qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then if qmd --version >/dev/null 2>&1; then - echo "✅ qmd 已存在且可用:$qmd_path" + echo "✅ qmd 已存在且可用: $qmd_path" OPENCLAW_MEMORY_QMD_PATH="$qmd_path" return 0 else @@ -13831,10 +13831,10 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正确" + echo "✅ memory.qmd.command 已正確" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 预热索引(可能下载模型)" + echo "🔥 預熱索引(可能下載模型)" openclaw_memory_prepare_workspace_all local preh_agent_lines preh_agent_id preh_workspace preh_agent_lines=$(openclaw_memory_list_agents) @@ -14059,7 +14059,7 @@ EOF echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ 偵測到 includeDefaultMemory=false" - echo "這會導致預設記憶檔案(MEMORY.md + memory/*.md)不被索引" + echo " 这会导致默认记忆文件(MEMORY.md + memory/*.md)不被索引" echo "所以 Indexed 會一直顯示 0/N" echo "" read -e -p "是否恢復為 true 並重建索引? (Y/n):" fix_choice @@ -14102,11 +14102,11 @@ EOF builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac - echo "當前方案:$current_label" + echo "当前方案: $current_label" echo "" echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" - echo "Auto : 自动推荐(基于可用性 + 网络探测)" + echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" echo "1. 切換 QMD(自動部署/已安裝則跳過)" echo "2. 切換 Local(自動部署/已安裝則跳過)" @@ -14220,7 +14220,7 @@ EOF end_line=$total_lines fi if [ "$total_lines" -eq 0 ]; then - echo "(空文件)" + echo "(空白文件)" return 0 fi echo "---------------------------------------" @@ -14297,7 +14297,7 @@ EOF case "$memory_choice" in 1) echo "即將更新記憶索引。" - read -e -p "第一次确认:输入 yes 继续: " confirm_step1 + read -e -p "第一次確認:輸入 yes 繼續:" confirm_step1 if [ "$confirm_step1" != "yes" ]; then echo "已取消。" break_end @@ -14321,7 +14321,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14403,7 +14403,7 @@ EOF echo "❌ 權限恢復失敗:$backup_file" return 1 } - echo "✅ 已恢复切换前权限配置" + echo "✅ 已恢復切換前權限配置" openclaw_permission_restart_gateway || true return 0 } @@ -14636,7 +14636,7 @@ except Exception as e: print("(解析失敗:" + str(e) + ")") ' "$approvals_json" else - echo " (openclaw approvals get --json 无输出)" + echo "(openclaw approvals get --json 無輸出)" fi elif [ -f "$HOME/.openclaw/exec-approvals.json" ]; then python3 -c ' @@ -14723,7 +14723,7 @@ except Exception: openclaw config unset tools.elevated.enabled >/dev/null 2>&1 openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 - echo "清理宿主机拦截配置..." + echo "清理宿主機攔截配置..." # 優先透過 CLI 清空審核配置,回退直接刪文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then true @@ -14741,7 +14741,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "是否尝试自动修复发现的安全隐患? (y/n):" fix_choice + read -e -p "是否嘗試自動修復發現的安全隱患? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復完成。${gl_bai}" @@ -14755,7 +14755,7 @@ except Exception: while true; do clear echo "=======================================" - echo "Exec 指令白名單管理" + echo " Exec 命令白名单管理" echo "=======================================" echo "目前白名單:" local allowlist_json @@ -14785,13 +14785,13 @@ except Exception as e: fi echo "---------------------------------------" echo "1. 新增白名單規則" - echo "2. 移除白名单规则" + echo "2. 移除白名單規則" echo "0. 返回" echo "---------------------------------------" read -e -p "請選擇:" al_choice case "$al_choice" in 1) - read -e -p "输入要放行的命令路径 (支持 glob,如 /usr/bin/git): " pattern + read -e -p "輸入要放行的命令路徑 (支援 glob,如 /usr/bin/git):" pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } read -e -p "指定智能體ID (留空=所有智能體 *):" agent_id agent_id="${agent_id:-*}" @@ -14799,7 +14799,7 @@ except Exception as e: break_end ;; 2) - read -e -p "输入要移除的命令路径: " pattern + read -e -p "輸入要移除的命令路徑:" pattern [ -z "$pattern" ] && { echo "不能為空"; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -14811,7 +14811,7 @@ except Exception as e: } openclaw_permission_menu() { - send_stats "OpenClaw权限管理" + send_stats "OpenClaw權限管理" while true; do clear echo "=======================================" @@ -14836,14 +14836,14 @@ except Exception as e: break_end ;; 2) - echo "准备应用:开发增强模式" + echo "準備應用:開發增強模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end ;; 3) echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" - read -e -p "输入 FULL 确认继续: " confirm + read -e -p "輸入 FULL 確認繼續:" confirm if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end ;; @@ -15095,7 +15095,7 @@ for idx,item in enumerate(agents,1): [ -z "$agent_id" ] && echo "已取消:Agent ID 不能為空。" && return 1 read -e -p "請輸入 workspace 路徑(預設為 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" - echo "将创建智能体: $agent_id" + echo "將創建智能體:$agent_id" echo "工作目錄:$workspace" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } @@ -15109,7 +15109,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體創建失敗" + echo "❌ 智能體建立失敗" return 1 fi } @@ -15213,12 +15213,12 @@ for item in sessions[:10]: } openclaw_multiagent_health_check() { - send_stats "OpenClaw多智能体-健康检查" + send_stats "OpenClaw多智能體-健康檢查" openclaw_multiagent_require_openclaw || return 1 local config_file config_file=$(openclaw_multiagent_config_file) echo "檢查設定檔: ${config_file:-$(openclaw_permission_config_file)}" - openclaw config validate || echo "⚠️ 配置校验未通过,请检查上方输出。" + openclaw config validate || echo "⚠️ 配置校驗未通過,請檢查上方輸出。" python3 -c ' import json,sys,os agents=json.loads(sys.argv[1] or "[]") @@ -15269,7 +15269,7 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "即将清理过期/冗余会话数据..." + echo "即將清理過期/冗餘會話資料..." read -e -p "輸入 yes 確認:" confirm [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } openclaw sessions cleanup @@ -15290,7 +15290,7 @@ print("✅ 多智能體健康檢查完成") echo "4. 新增路由綁定" echo "5. 移除路由綁定" echo "6. 查看會話概況" - echo "7. 运行多智能体健康检查" + echo "7. 執行多智能體健康檢查" echo "8. 修改智能體身分(名稱/Emoji)" echo "9. 清理過期會話" echo "0. 返回上一級" @@ -15427,7 +15427,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15455,7 +15455,7 @@ openclaw_backup_restore_menu() { echo "先造訪URL觸發設備ID,然後回車下一步進行配對。" read echo -e "${gl_kjlan}正在載入設備列表…${gl_bai}" - # 自動新增網域到 allowedOrigins + # 自动添加域名到 allowedOrigins config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" @@ -15607,11 +15607,11 @@ while true; do echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龙面板定时任务管理平台" + echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" echo -e "${gl_kjlan}15. ${color15}emby多媒體管理系統${gl_kjlan}16. ${color16}Speedtest測速板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome去廣告軟體${gl_kjlan}18. ${color18}onlyoffice線上辦公OFFICE" - echo -e "${gl_kjlan}19. ${color19}雷池WAF防火墙面板 ${gl_kjlan}20. ${color20}portainer容器管理面板" + echo -e "${gl_kjlan}19. ${color19}雷池WAF防火牆面板${gl_kjlan}20. ${color20}portainer容器管理面板" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" @@ -15619,7 +15619,7 @@ while true; do echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" echo -e "${gl_kjlan}29. ${color29}searxng聚合搜尋站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相簿系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" @@ -15627,9 +15627,9 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}45. ${color45}Docker加速站 ${gl_kjlan}46. ${color46}GitHub加速站 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}普罗米修斯监控 ${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" - echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}補貨監控工具" + echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" + echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" @@ -15639,12 +15639,12 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自架AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" - echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp影片下載工具" echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo檔案傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密码管理器 ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV私有影視" + echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}線上DOS老遊戲" echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智慧文件管理系統" echo -e "${gl_kjlan}79. ${color79}Beszel伺服器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" @@ -15653,9 +15653,9 @@ while true; do echo -e "${gl_kjlan}83. ${color83}komari伺服器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" echo -e "${gl_kjlan}85. ${color85}immich圖片影片管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自架直播平台" - echo -e "${gl_kjlan}89. ${color89}FileCodeBox文件快递 ${gl_kjlan}90. ${color90}matrix去中心化聊天协议" + echo -e "${gl_kjlan}89. ${color89}FileCodeBox檔案快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" @@ -15954,8 +15954,8 @@ while true; do } - local docker_describe="qbittorrent离线BT磁力下载服务" - local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_describe="qbittorrent離線BT磁力下載服務" + local docker_url="官網介紹: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -16163,8 +16163,8 @@ while true; do } local docker_describe="禪道是通用的專案管理軟體" - local docker_url="官网介绍: https://www.zentao.net/" - local docker_use="echo \"初始用户名: admin\"" + local docker_url="官網介紹: https://www.zentao.net/" + local docker_use="echo \"初始使用者名稱: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -16191,7 +16191,7 @@ while true; do } - local docker_describe="青龙面板是一个定时任务管理平台" + local docker_describe="青龍面板是一個定時任務管理平台" local docker_url="官網介紹:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" @@ -16337,7 +16337,7 @@ while true; do local docker_describe="AdGuardHome是一款全網廣告攔截與反追蹤軟體,未來不只一個DNS伺服器。" - local docker_url="官网介绍: https://hub.docker.com/r/adguard/adguardhome" + local docker_url="官網介紹: https://hub.docker.com/r/adguard/adguardhome" local docker_use="" local docker_passwd="" local app_size="1" @@ -16366,7 +16366,7 @@ while true; do } local docker_describe="onlyoffice是一款開源的線上office工具,太強大了!" - local docker_url="官网介绍: https://www.onlyoffice.com/" + local docker_url="官網介紹: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" local app_size="2" @@ -16383,9 +16383,9 @@ while true; do while true; do check_docker_app clear - echo -e "雷池服务 $check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" - echo "视频介绍: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" + echo -e "雷池服務$check_docker" + echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" + echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip fi @@ -16406,7 +16406,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已经安装完成" + echo "雷池WAF面板已經安裝完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -16419,7 +16419,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已经更新完成" + echo "雷池WAF面板已經更新完成" check_docker_app_ip ;; 3) @@ -16430,7 +16430,7 @@ while true; do docker compose down --rmi all sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "如果你是預設安裝目錄那現在項目已經卸載。如果你是自定义安装目录你需要到安装目录下自行执行:" + echo "如果你是預設安裝目錄那現在項目已經卸載。如果你是自訂安裝目錄你需要到安裝目錄下自行執行:" echo "docker compose down && docker compose down --rmi all" ;; *) @@ -16533,7 +16533,7 @@ while true; do } - local docker_describe="Memos是一款轻量级、自托管的备忘录中心" + local docker_describe="Memos是一款輕量、自架的備忘錄中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -16945,7 +16945,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 原耗子面板" + local panelname="AcePanel 原耗子麵板" local panelurl="官方地址:${gh_proxy}github.com/acepanel/panel" panel_app_install() { @@ -17098,7 +17098,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼均為: admin" + echo "初始使用者名稱密碼皆為: admin" } docker_app_update() { @@ -17139,7 +17139,7 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_describe="這是一個普羅米修斯的主機資料擷取元件,請部署在被監控主機上。" local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" @@ -17169,7 +17169,7 @@ while true; do } - local docker_describe="這是一個普羅米修斯的容器資料擷取元件,請部署在被監控主機上。" + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" local docker_url="官網介紹:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -17471,7 +17471,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow知識庫" - local app_text="基于深度文档理解的开源 RAG(检索增强生成)引擎" + local app_text="基於深度文件理解的開源 RAG(檢索增強生成)引擎" local app_url="官方網站:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17881,7 +17881,7 @@ while true; do } - local docker_describe="是一个中文DOS游戏合集网站" + local docker_describe="是一個中文DOS遊戲收藏網站" local docker_url="官網介紹:${gh_https_url}github.com/rwv/chinese-dos-games" local docker_use="" local docker_passwd="" @@ -18116,7 +18116,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -18128,7 +18128,7 @@ while true; do } local docker_describe="高效能AI介面透明代理服務" - local docker_url="官网介绍: https://www.gpt-load.com/" + local docker_url="官網介紹: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18160,9 +18160,9 @@ while true; do } - local docker_describe="轻量级的自托管服务器监控工具" + local docker_describe="輕量級的自架伺服器監控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -18330,7 +18330,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" - local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" + local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" local app_size="1" docker_app @@ -18565,8 +18565,8 @@ while true; do local app_id="95" local app_name="paperless文件管理平台" - local app_text="开源的电子文档管理系统,它的主要用途是把你的纸质文件数字化并管理起来。" - local app_url="视频介绍: https://docs.paperless-ngx.com/" + local app_text="開源的電子文件管理系統,它的主要用途是把你的紙本文件數位化並管理起來。" + local app_url="影片介紹: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" local app_size="2" @@ -18753,7 +18753,7 @@ while true; do echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可快速連接網絡${gl_bai}" echo -e "${gl_lv}2. Windows下載客戶端,複製設定碼連接網路。${gl_bai}" - echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製設定碼連接網路。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" echo -e "${gl_lv}官方客戶端下載方式: https://www.wireguard.com/install/${gl_bai}" break_end @@ -18855,7 +18855,7 @@ while true; do read -e -p "設定 CPU 核數 (預設 2):" CPU_CORES local CPU_CORES=${CPU_CORES:-2} - read -e -p "设置内存大小 (默认 4G): " RAM_SIZE + read -e -p "設定記憶體大小 (預設 4G):" RAM_SIZE local RAM_SIZE=${RAM_SIZE:-4} mkdir -p /home/docker/dsm @@ -19277,7 +19277,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) local docker_port=8112 docker_rum() { @@ -19294,9 +19294,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="Lucky 是一個大內部網路穿透及連接埠轉送管理工具,支援 DDNS、反向代理、WOL 等功能。" + local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" local docker_url="項目地址:${gh_https_url}github.com/gdy666/lucky" - local docker_use="echo \"默认账号密码: 666\"" + local docker_use="echo \"預設帳號密碼: 666\"" local docker_passwd="" local app_size="1" docker_app @@ -19446,7 +19446,7 @@ linux_work() { echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" - echo "目前已存在的工作區列表" + echo "当前已存在的工作区列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" @@ -19780,7 +19780,7 @@ net_menu() { if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else - echo "✘ 网卡不存在" + echo "✘ 網路卡不存在" fi read -erp "按回車繼續..." ;; @@ -19994,7 +19994,7 @@ env_menu() { } source_files() { - echo "正在重新載入環境變數..." + echo "正在重新加载环境变量..." send_stats "正在重新載入環境變數" source "$BASHRC" source "$PROFILE" @@ -20012,7 +20012,7 @@ env_menu() { echo "3. 查看 ~/.profile" echo "4. 編輯 ~/.bashrc" echo "5. 編輯 ~/.profile" - echo "6. 重新加载环境变量(source)" + echo "6. 重新載入環境變數(source)" echo "--------------------------------------" echo "0. 返回上一級選單" echo "--------------------------------------" @@ -20139,7 +20139,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" echo -e "${gl_kjlan}23. ${gl_bai}限流自動關機${gl_kjlan}24. ${gl_bai}使用者密鑰登入模式" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修复OpenSSH高危漏洞" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot系統監控預警${gl_kjlan}26. ${gl_bai}修復OpenSSH高風險漏洞" echo -e "${gl_kjlan}27. ${gl_bai}紅帽系Linux核心升級${gl_kjlan}28. ${gl_bai}Linux系統核心參數優化${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}病毒掃描工具${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}文件管理器" echo -e "${gl_kjlan}------------------------" @@ -20280,7 +20280,7 @@ EOF send_stats "開放埠" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "連接埠已全部開放" ;; 6) @@ -20294,7 +20294,7 @@ EOF # 讀取目前的 SSH 連接埠號 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 列印目前的 SSH 連接埠號碼 + # 打印当前的 SSH 端口号 echo -e "目前的 SSH 連接埠號碼是:${gl_huang}$current_port ${gl_bai}" echo "------------------------" @@ -20309,7 +20309,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH連接埠修改" + send_stats "退出SSH埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20364,7 +20364,7 @@ EOF if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "目前網路優先權設定:${gl_huang}IPv4${gl_bai}優先" + echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai}優先" else echo -e "目前網路優先權設定:${gl_huang}IPv6${gl_bai}優先" fi @@ -20701,7 +20701,7 @@ EOF send_stats "主機名稱已更改" sleep 1 else - echo "已退出,未更改主機名稱。" + echo "已退出,未更改主机名。" break fi done @@ -20895,7 +20895,7 @@ EOF rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "請輸入出站流量閾值(單位為G,預設100G):" tx_threshold_gb tx_threshold_gb=${tx_threshold_gb:-100} - read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day + read -e -p "請輸入流量重置日期(預設每月1日重設):" cz_day cz_day=${cz_day:-1} cd ~ @@ -20908,7 +20908,7 @@ EOF (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" + echo "限流關機已設定" send_stats "限流關機已設定" ;; 2) @@ -20936,9 +20936,9 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" - echo "到达阈值后会向用户发预警消息" - echo -e "${gl_hui}-关于流量,重启服务器将重新计算-${gl_bai}" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "到達閾值後會向用戶發送預警訊息" + echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in @@ -21092,8 +21092,8 @@ EOF echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" echo -e "5. 啟動fail2ban防禦SSH暴力破解" echo -e "6. 開放所有端口" - echo -e "7. 开启${gl_huang}BBR${gl_bai}加速" - echo -e "8. 设置时区到${gl_huang}上海${gl_bai}" + echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" + echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" @@ -21108,7 +21108,7 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean @@ -21191,7 +21191,7 @@ EOF echo -e "目前狀態:$status_message" echo "--------------------" echo "1. 開啟採集" - echo "2. 关闭采集" + echo "2. 關閉採集" echo "--------------------" echo "0. 返回上一級選單" echo "--------------------" @@ -21287,7 +21287,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" + echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21315,7 +21315,7 @@ linux_file() { send_stats "修改目錄權限" ;; 4) # 重命名目录 - read -e -p "請輸入目前目錄名稱:" current_name + read -e -p "请输入当前目录名: " current_name read -e -p "請輸入新目錄名稱:" new_name mv "$current_name" "$new_name" && echo "目錄已重新命名" || echo "重新命名失敗" send_stats "重新命名目錄" @@ -21364,7 +21364,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21454,7 +21454,7 @@ EOF break ;; *) # 处理无效输入 - echo "无效的选择,请重新输入" + echo "無效的選擇,請重新輸入" send_stats "無效選擇" ;; esac @@ -21536,7 +21536,7 @@ while true; do 1) send_stats "新增叢集伺服器" read -e -p "伺服器名稱:" server_name - read -e -p "服务器IP: " server_ip + read -e -p "伺服器IP:" server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} read -e -p "伺服器使用者名稱(root):" server_username @@ -21643,7 +21643,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}VPS更多热门优惠${gl_bai}" +echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21744,7 +21744,7 @@ while true; do if [ -z "$sh_v_new" ]; then echo -e "${gl_hong}無法獲取最新版本信息,請檢查網絡連接${gl_bai}" elif [ "$sh_v" = "$sh_v_new" ]; then - echo -e "${gl_lv}你已經是最新版本!${gl_huang}v$sh_v${gl_bai}" + echo -e "${gl_lv}你已经是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "腳本已經最新了,無需更新" else echo "發現新版本!" @@ -21792,7 +21792,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" @@ -21800,7 +21800,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21926,7 +21926,7 @@ done k_info() { send_stats "k指令參考用例" echo "-------------------" -echo "视频介绍: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" +echo "影片介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下是k命令參考用例:" echo "啟動腳本 k" echo "安裝軟體包 k install nano wget | k add nano wget | k 安裝 nano wget" @@ -21939,7 +21939,7 @@ echo "核心調優面板 k nhyh | k 核心最佳化" echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" echo "系統回收站 k trash | k hsz | k 回收站" -echo "系統備份功能 k backup | k bf | k 備份" +echo "系统备份功能 k backup | k bf | k 备份" echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" @@ -21957,7 +21957,7 @@ echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" -echo "LDNMP缓存清理 k web cache" +echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" From 43b831d2f3b643a05fb2099273ba8247114b5780 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 14 Jun 2026 06:49:28 +0000 Subject: [PATCH 1195/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-06-14=2006:49:28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 36 +++--- jp/kejilion.sh | 166 +++++++++++++-------------- kr/kejilion.sh | 246 +++++++++++++++++++-------------------- tw/kejilion.sh | 306 ++++++++++++++++++++++++------------------------- 4 files changed, 377 insertions(+), 377 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 52b1d94f5..869c791d4 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2331,12 +2331,12 @@ check_nginx_compression() { # Check if brotli is enabled and uncommented if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status="brCompression is on" + br_status=" br压缩已开启" else br_status="" fi - # Check if gzip is enabled and uncommented + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip compression is on" else @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow specified IPs + # Clear the rules that allow the specified IP if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -6420,7 +6420,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -6692,9 +6692,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6736,7 +6736,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7484,7 +7484,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Whether the remote host is accessible" + echo "2. Is the remote host accessible?" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -12215,7 +12215,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12343,7 +12343,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -14572,7 +14572,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: write file directly + # Fallback: Write the file directly echo "$json_payload" > "$approvals_file" } @@ -15603,7 +15603,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15974,7 +15974,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -20197,7 +20197,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21492,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21526,7 +21526,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index f0b3856f3..00e9ab2f3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -867,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -930,12 +930,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2241,7 +2241,7 @@ web_security() { echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3016,7 +3016,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4310,7 +4310,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" + echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4607,7 +4607,7 @@ yt_menu_pro() { read -e -p "バッチダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 7) send_stats "カスタムビデオのダウンロード" - read -e -p "完全な yt-dlp パラメータを入力してください (yt-dlp を除く)。" custom + read -e -p "完全な yt-dlp パラメータを入力してください (yt-dlp を除く):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4838,7 +4838,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4953,7 +4953,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" + echo -e "秘密鍵情報が生成されました。 Be sure to copy and save it.として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5609,7 +5609,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) + # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5900,7 +5900,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -5908,7 +5908,7 @@ elrepo() { [Yy]) check_swap elrepo_install - send_stats "Red Hat カーネルをアップグレードする" + send_stats "升级红帽内核" server_reboot ;; [Nn]) @@ -6013,7 +6013,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6040,7 +6040,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6323,7 +6323,7 @@ LIMITS sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name}最適化が完了しました!構成は永続化されています${CONF}${gl_bai}" + echo -e "${gl_lv}${mode_name}最適化が完了しました!設定は永続化されています${CONF}${gl_bai}" echo -e "${gl_lv}メモリ:${MEM_MB}MB |輻輳アルゴリズム:${CC}|列:${QDISC}${gl_bai}" } @@ -6392,7 +6392,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" @@ -6420,7 +6420,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6692,9 +6692,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6736,7 +6736,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7484,7 +7484,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストにアクセスできるかどうか" + echo "2. リモートホストはアクセス可能ですか?" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7645,7 +7645,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7765,7 +7765,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -8157,7 +8157,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包量:$path" + echo "梱包体積:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8222,7 +8222,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8410,7 +8410,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8451,10 +8451,10 @@ linux_docker() { echo -e "Docker コンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" + echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -8896,7 +8896,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9286,7 +9286,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -10347,7 +10347,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10426,7 +10426,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10741,7 +10741,7 @@ EOF echo "📦 モデル参照形式:$provider_name/" return 0 else - echo "❌ 配置注入失败" + echo "❌ 構成の挿入に失敗しました" return 1 fi } @@ -10754,7 +10754,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 默认模型不能为空" + echo "❌ デフォルトのモデルを空にすることはできません" return 1 fi @@ -11546,7 +11546,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入り口" + send_stats "OpenClaw APIの入口" while true; do clear echo "=======================================" @@ -11554,7 +11554,7 @@ PY echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. APIの追加" + echo "1. APIを追加する" echo "2. APIプロバイダーモデルリストを同期する" echo "3. API タイプの切り替え (完了/応答)" echo "4. APIの削除" @@ -11849,7 +11849,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12203,7 +12203,7 @@ PYTHON_EOF echo "- [whatsapp] #WhatsApp オートメーション" echo "" echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル検索)" + echo "- [memory-core] # 基本メモリ (ファイル取得)" echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" @@ -12334,7 +12334,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12376,7 +12376,7 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" + echo "💡 スキル [$skill_name]がユーザーディレクトリにインストールされます。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" @@ -12666,7 +12666,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5.WeChatロボットのドッキング" + echo "5. WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12687,7 +12687,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12807,7 +12807,7 @@ EOF echo "バックアップ ファイルは次の方法でダウンロードできます。" echo "- ローカルパス:$file_path" echo "- scp の例: scp root@yourserver:$file_path ./" - echo "- またはSFTPクライアントを使用してダウンロード" + echo "- またはSFTPクライアントを使用してダウンロードします" } openclaw_prepare_import_archive() { @@ -14195,7 +14195,7 @@ EOF echo "書類:$file" echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14289,7 +14289,7 @@ EOF echo "2. メモリファイルを表示する" echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" - echo "5. 検索テスト (インデックスが機能していることを確認します)" + echo "5. 検索テスト (インデックスが機能していることを確認する)" echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" @@ -14603,7 +14603,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14652,7 +14652,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14672,7 +14672,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14709,7 +14709,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -15080,7 +15080,7 @@ else: } openclaw_multiagent_list_agents() { - send_stats "OpenClaw マルチエージェント - エージェントのリスト" + send_stats "OpenClaw多智能体-列出Agent" python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); if not agents: print("エージェントはまだ構成されていません。"); raise SystemExit(0) for idx,item in enumerate(agents,1): @@ -15100,7 +15100,7 @@ for idx,item in enumerate(agents,1): read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました:$agent_id" + echo "✅ 智能体创建成功: $agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15539,7 +15539,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期設定ウィザード" + 11) send_stats "初期構成ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15603,7 +15603,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -16365,7 +16365,7 @@ while true; do } - local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" + local docker_describe="Onlyoffice は、非常に強力なオープンソースのオンライン オフィス ツールです。" local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -16839,7 +16839,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -17988,7 +17988,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18743,7 +18743,7 @@ while true; do sleep 2 echo - echo -e "${gl_huang}所有客户端二维码配置: ${gl_bai}" + echo -e "${gl_huang}すべてのクライアント QR コード構成:${gl_bai}" docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo @@ -19444,7 +19444,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19766,7 +19766,7 @@ net_menu() { echo echo "=========== ネットワークカード管理メニュー ===========" echo "1.ネットワークカードを有効にする" - echo "2.ネットワークカードを無効にする" + echo "2. 禁用网卡" echo "3. ネットワークカードの詳細を表示する" echo "4. ネットワークカード情報を更新する" echo "0. 前のメニューに戻る" @@ -20012,7 +20012,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数(ソース)をリロードします。" + echo "6. 環境変数 (ソース) をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20127,7 +20127,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20202,7 +20202,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -21086,7 +21086,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21378,7 +21378,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21398,7 +21398,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21492,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21526,7 +21526,7 @@ while true; do echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21640,7 +21640,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" @@ -21891,7 +21891,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -21930,8 +21930,8 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21940,7 +21940,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21963,7 +21963,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -21972,16 +21972,16 @@ echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" echo "システム情報を表示 k info" -echo "ROOT密钥管理 k sshkey" +echo "ROOT キー管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " -echo "SSH公钥导入(GitHub) k sshkey github " +echo "SSH 公開キーのインポート (GitHub) k sshkey github " } if [ "$#" -eq 0 ]; then - # 如果没有参数,运行交互式逻辑 + # 引数なしで対話型ロジックを実行します kejilion_sh else # パラメータがある場合は、対応する関数を実行します diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d13db781b..dbe709274 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 특정 IP를 허용하는 규칙 지우기 + # 지정된 IP를 허용하는 규칙을 지웁니다. if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3509,7 +3509,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3725,7 +3725,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4106,7 +4106,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4168,7 +4168,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4779,7 +4779,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5135,7 +5135,7 @@ sshkey_panel() { echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." + echo "SSH를 통해 로그인하는 보다 안전한 방법인 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." @@ -5936,7 +5936,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6049,7 +6049,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정하세요── + # ──장면에 따라 매개변수를 설정합니다── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -6420,7 +6420,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -7484,7 +7484,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근 가능한지 여부" + echo "2. 원격 호스트에 접근할 수 있나요?" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -8095,7 +8095,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -8234,7 +8234,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8369,7 +8369,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8523,7 +8523,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8569,7 +8569,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9285,7 +9285,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9623,7 +9623,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -10510,7 +10510,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10948,12 +10948,12 @@ except FileNotFoundError: print('MSG\tℹ️ openclaw.json을 찾을 수 없습니다. 먼저 설치/초기화를 완료하세요.') raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 구성을 읽지 못했습니다: {type(e).__name__}: {e}') + print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 현재 구성된 API 제공업체가 없습니다.') + print('MSG\tℹ️ 当前未配置任何 API provider。') raise SystemExit(0) print('MSG\t--- 구성된 API 목록 ---') @@ -10999,7 +10999,7 @@ PY } sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "공급자별 OpenClaw API 동기화" + send_stats "OpenClaw API按Provider同步" if [ ! -f "$config_file" ]; then echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" @@ -11007,12 +11007,12 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "동기화할 API 이름(공급자)을 입력하고 Enter를 눌러 모두 동기화하세요." provider_name + read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." + echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" return 1 fi break_end @@ -11039,7 +11039,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ API 제공업체가 감지되지 않아 동기화할 수 없습니다.') + print('❌ 未检测到 API providers,无法同步') raise SystemExit(2) provider = providers.get(target) @@ -11115,7 +11115,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ 공급자 {target}은 현재 api={api}이지만 스크립트는 더 이상 프로토콜을 감지/수정하지 않습니다. openai-completions 또는 openai-responses로 수동으로 설정하세요.') + print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') protocol_msg = None @@ -11134,7 +11134,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 업스트림 /models가 비어 있고 동기화가 중단되었습니다.') + print(f'❌ {target}: 上游 /models 为空,已中止同步') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11143,7 +11143,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 로컬 모델에 유효한 템플릿 모델이 없어 새 모델을 추가할 수 없습니다.') + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -11159,7 +11159,7 @@ for mid in added_ids: new_models.append(nm) if not new_models: - print(f'❌ {target}: 동기화 후 사용할 수 있는 모델이 없어 쓰기가 중단되었습니다.') + print(f'❌ {target}: 同步后无可用模型,已中止写入') raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -11201,7 +11201,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: {len(add_ids)} 추가, 삭제 {len(removed_ids)}, 현재 {len(new_models)}') +print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') if added_ids: print(f'➕ 새 모델 추가({len(add_ids)}):') @@ -11213,30 +11213,30 @@ if removed_ids: print(f' - {mid}') if changed: - print('✅ 지정된 공급자 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') + print('✅ 指定 provider 模型一致性同步完成并已写入配置') else: - print('ℹ️ 동기화가 필요하지 않습니다. 공급자 구성이 이미 업스트림/모델과 일치합니다.') + print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') PY2 local rc=$? case "$rc" in 0) - echo "✅ 동기 실행 완료" + echo "✅ 同步执行完成" start_gateway ;; 2) - echo "❌ 동기화 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." + echo "❌ 同步失败:provider 不存在或未配置" ;; 3) echo "❌ 동기화 실패: 공급자 구성이 불완전하거나 유형이 지원되지 않습니다." ;; 4) - echo "❌ 동기화 실패: 업스트림 /models 요청 실패" + echo "❌ 同步失败:上游 /models 请求失败" ;; 5) echo "❌ 동기화 실패: 업스트림 모델이 비어 있거나 동기화 후 사용 가능한 모델이 없습니다." ;; *) - echo "❌ 동기화 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + echo "❌ 同步失败:请检查配置文件结构或日志输出" ;; esac @@ -11244,9 +11244,9 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - # 프로토콜 감지 논리가 제거되었습니다. 스크립트는 더 이상 API 유형을 자동으로 감지/결정하지 않습니다. + # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 # 이 기능은 메뉴 호출과의 호환성을 위해 유지되지만 재작성은 수행되지 않습니다. - echo "ℹ️ 프로토콜 감지가 꺼졌습니다. 수동으로 감지하세요.${HOME}/.openclaw/openclaw.json의 공급자.api를 openai-completions 또는 openai-responses로 설정합니다." + echo "ℹ️ 프로토콜 감지가 꺼졌습니다. 수동으로 감지하세요.${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" return 0 } @@ -11448,7 +11448,7 @@ for fk in ('modelFallback', 'imageModelFallback'): print(f'❌ 삭제가 중단되었습니다. {fk}가 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 스위치: {val} -> {교체}') + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11461,12 +11461,12 @@ with open(path, 'w', encoding='utf-8') as f: f.write('\n') print(f'🗑️ 삭제된 제공자: {name}') -print(f'🧹 defaults.models에서 {len(removed_refs)} 관련 모델 참조를 정리했습니다.') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') PY local rc=$? case "$rc" in 0) - send_stats "OpenClaw API 삭제 확인" + send_stats "OpenClaw API删除确认" echo "✅삭제 완료" start_gateway ;; @@ -11475,10 +11475,10 @@ PY ;; 3) send_stats "OpenClaw API 삭제 취소" - echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." + echo "❌ 删除失败:无可用替代模型,已保持原配置" ;; *) - echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." + echo "❌ 删除失败:请检查配置文件结构或日志输出" ;; esac @@ -11486,12 +11486,12 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장사항" + send_stats "OpenClaw API 공급업체 권장 사항" clear echo "" echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 벤더 추천 목록${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}일부 입구에는 AFF가 포함되어 있습니다.${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" echo "" @@ -11504,13 +11504,13 @@ PY echo -e " ${gl_lv}● Kimi${gl_bai}" echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" echo "" - echo -e " ${gl_lv}● 슈퍼컴퓨팅 인터넷${gl_bai}" + echo -e " ${gl_lv}● 超算互联网${gl_bai}" echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" echo "" - echo -e " ${gl_huang}● Youyun 지능형 컴퓨팅${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" - echo -e " ${gl_huang}● 실리콘 기반 흐름${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" echo "" echo -e " ${gl_huang}● GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" @@ -11519,10 +11519,10 @@ PY echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" echo "" - echo -e " ${gl_huang}● 클라우드 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" echo "" - echo -e " ${gl_huang}● 플라톤 AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 柏拉图AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" @@ -11538,9 +11538,9 @@ PY echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" - echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 추천 입장${gl_bai}" + echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" echo "" - echo -e "${gl_huang}팁: 링크를 복사하고 브라우저에서 열어서 액세스하세요.${gl_bai}" + echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" echo "" read -erp "돌아가려면 Enter를 누르세요..." dummy } @@ -11550,7 +11550,7 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw API 관리" + echo "OpenClaw API 管理" echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" @@ -11626,7 +11626,7 @@ REPO change_model() { - send_stats "모델 변경" + send_stats "换模型" local orange="#FF8C00" @@ -11794,7 +11794,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11812,7 +11812,7 @@ PYTHON_EOF second_reply="$reply_preview" reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11824,7 +11824,7 @@ PYTHON_EOF reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" OPENCLAW_PROBE_STATUS="FAIL" OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" @@ -11838,22 +11838,22 @@ PYTHON_EOF while true; do local models_raw models_list default_model model_count selected_model confirm_switch - # 구성 파일에서 모델 키 읽기(openclaw 모델 목록을 호출하지 않고) + # 从配置文件读取模型键(不调用 openclaw models list) local oc_config oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "모델 목록을 가져오지 못했습니다. 구성 파일에서 Agent.defaults.models를 찾을 수 없습니다." + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi - # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # 구성 파일에서 기본 모델을 읽습니다(더 빠름). 실패 시 openclaw 명령으로 대체 + # Read default model from configuration file (faster); 실패 시 openclaw 명령으로 대체 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" @@ -11871,12 +11871,12 @@ PYTHON_EOF read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." selected_model if [ "$selected_model" = "0" ]; then - echo "작업이 취소되었습니다. 종료하는 중..." + echo "操作已取消,正在退出..." break fi if [ -z "$selected_model" ]; then - echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "Error: Model name cannot be empty. 다시 시도해 주세요." echo "" continue fi @@ -11902,10 +11902,10 @@ PYTHON_EOF gum style --foreground "$orange" "사용 가능한 모델(인증=예):${model_count}" gum style --foreground "$orange" "현재 기본값:${default_model}" echo "" - gum style --faint "↑↓ 테스트하려면 선택 / Enter / 종료하려면 Esc" + gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" echo "" - selected_model=$(echo "$models_list" | gum filter --placeholder "검색 모델(예: cli-api/gpt-5.2)" --prompt "모델 선택 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "검색 모델(예: cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "작업이 취소되었습니다. 종료하는 중..." @@ -11927,7 +11927,7 @@ PYTHON_EOF echo "요약:$OPENCLAW_PROBE_REPLY" echo "" - printf "이 모델로 전환하시겠습니까? [y/N, Esc가 목록으로 돌아갑니다]:" + printf "Switch to this model? [y/N, Esc가 목록으로 돌아갑니다]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12029,7 +12029,7 @@ PYTHON_EOF fi done - [ "$count" -gt 0 ] && echo "✅ 동기화됨$count에이전트의 세션 모델은 다음과 같습니다.$model_ref" + [ "$count" -gt 0 ] && echo "✅ 已同步 $count에이전트의 세션 모델은 다음과 같습니다.$model_ref" return 0 } @@ -12108,7 +12108,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" return 1 } @@ -12189,7 +12189,7 @@ PYTHON_EOF echo "========================================" echo "플러그인 관리(설치/제거)" echo "========================================" - echo "현재 플러그인 목록:" + echo "当前插件列表:" openclaw plugins list echo "--------------------------------------------------------" echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" @@ -12197,25 +12197,25 @@ PYTHON_EOF echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" echo "- [텔레그램] # 텔레그램 봇" - echo "- [slack] #Slack 기업 커뮤니케이션" + echo " - [slack] # Slack 企业通讯" echo " - [msteams] # Microsoft Teams" - echo "- [디스코드] # 디스코드 커뮤니티 관리" + echo " - [discord] # Discord 社区管理" echo "- [whatsapp] #WhatsApp 자동화" echo "" - echo "🧠 메모리와 AI:" - echo "- [memory-core] # 기본 메모리(파일 검색)" + echo "🧠 记忆与 AI:" + echo " - [memory-core] # 基础记忆 (文件检索)" echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" echo "- [copilot-proxy] # Copilot 인터페이스 전달" echo "" - echo "⚙️ 기능 확장:" + echo "⚙️ 功能扩展:" echo "- [랍스터] # 승인 흐름(수동 확인 포함)" echo "- [음성통화] # 음성통화 기능" - echo "- [nostr] # 암호화된 비공개 채팅" + echo " - [nostr] # 加密隐私聊天" echo "--------------------------------------------------------" - echo "1) 플러그인 설치/활성화" + echo "1) 安装/启用插件" echo "2) 플러그인 삭제/비활성화" - echo "0) 복귀" + echo "0) 返回" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12239,7 +12239,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인:$plugin_id" + echo "🔍 플러그인 상태 확인 중:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12256,7 +12256,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12280,14 +12280,14 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 설치 실패:$plugin_full" + echo "❌ 安装失败:$plugin_full" failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 플러그인 제거/비활성화:$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then - echo "✅ 제거됨:$plugin_id" + echo "✅ 已卸载: $plugin_id" else echo "⚠️ 제거에 실패했습니다. 사전 설치된 플러그인일 수 있습니다. 다음만 비활성화하세요.$plugin_id" fi @@ -12325,8 +12325,8 @@ PYTHON_EOF # 추천 실기 목록 출력 echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" - echo "github # GitHub 문제/PR/CI 관리(gh CLI)" - echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." + echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" + echo "notion # 操作 Notion 页面、数据库和块" echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" echo "1password # 1Password 키 읽기 및 삽입 자동화" @@ -12341,9 +12341,9 @@ PYTHON_EOF echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." echo "----------------------------------------" - echo "1) 설치 기술" + echo "1) 安装技能" echo "2) 스킬 삭제" - echo "0) 복귀" + echo "0) 返回" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12393,7 +12393,7 @@ PYTHON_EOF echo "기술 설치:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then - echo "✅ 스킬$skill_name설치가 성공했습니다." + echo "✅ 技能 $skill_name설치가 성공했습니다." success_list="$success_list $skill_name" changed=true else @@ -12479,7 +12479,7 @@ openclaw_json_get_bool() { # 두 가지 일반적인 디렉터리 이름과 호환됩니다. # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. + # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12687,7 +12687,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13025,7 +13025,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13145,7 +13145,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw 백업 파일 삭제" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13395,7 +13395,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." + echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -13668,7 +13668,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." return 0 } @@ -13686,7 +13686,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -14205,7 +14205,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 숫자를 입력하세요." + echo "❌ 유효한 번호를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14307,7 +14307,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14572,7 +14572,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일 직접 쓰기 + # 대체: 파일을 직접 작성 echo "$json_payload" > "$approvals_file" } @@ -14660,7 +14660,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14679,7 +14679,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14690,14 +14690,14 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14799,7 +14799,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15603,7 +15603,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15615,7 +15615,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15643,7 +15643,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15974,7 +15974,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16713,7 +16713,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -17245,7 +17245,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -19277,7 +19277,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -20611,7 +20611,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20890,7 +20890,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -20934,7 +20934,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21492,7 +21492,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21526,7 +21526,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21567,7 +21567,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21640,7 +21640,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21929,7 +21929,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -21963,12 +21963,12 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index bc84be599..7376ee895 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 收集功能埋藏資訊的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! # 為什麼要設計這個功能,目的更好的了解使用者喜歡使用的功能,進一步優化功能推出更多符合使用者需求的功能。 -# 全文可搜尋 send_stats 函數呼叫位置,透明開源,如有顧慮可拒絕使用。 +# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 @@ -131,7 +131,7 @@ UserLicenseAgreement() { if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "許可同意" + send_stats "许可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else @@ -507,8 +507,8 @@ while true; do $dockername ;; 2) - send_stats "啟動指定容器" - read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername + send_stats "启动指定容器" + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}設定檔不存在${gl_bai}" return fi @@ -1095,7 +1095,7 @@ iptables_panel() { echo "" echo "防火牆管理" echo "------------------------" - echo "1. 開放指定連接埠 2. 關閉指定連接埠" + echo "1. 开放指定端口 2. 关闭指定端口" echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" echo "5. IP白名單 6. IP黑名單" @@ -1157,7 +1157,7 @@ iptables_panel() { 5) # IP 白名單 - read -e -p "請輸入放行的IP或IP段:" o_ip + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "網站資訊 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1544,9 +1544,9 @@ certs_status() { echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" - echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" + echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" - echo -e "6. 国内备案限制 ➠ 中国大陆环境请确认域名是否备案" + echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" echo "------------------------" echo "1. 重新申請 2. 匯入已有憑證 0. 退出" echo "------------------------" @@ -1626,7 +1626,7 @@ fi add_yuming() { ip_address - echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "請輸入你的IP或解析過的網域名稱:" yuming } @@ -1751,8 +1751,8 @@ cf_purge_cache() { read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" - read -e -p "请输入你的 API_TOKEN: " API_TOKEN - read -e -p "请输入你的CF用户名: " EMAIL + read -e -p "請輸入你的 API_TOKEN:" API_TOKEN + read -e -p "請輸入你的CF用戶名:" EMAIL read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS mkdir -p /home/web/config/ @@ -1977,7 +1977,7 @@ nginx_br() { fi if [ "$mode" == "on" ]; then - # 开启 Brotli:去掉注释 + # 開啟 Brotli:去掉註釋 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2215,10 +2215,10 @@ web_security() { 21) send_stats "cloudflare模式" - echo "到cf後台右上角我的個人資料,選擇左側API令牌,取得Global API Key" + echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" echo "https://dash.cloudflare.com/login" read -e -p "輸入CF的帳號:" cfuser - read -e -p "輸入CF的Global API Key:" cftoken + read -e -p "输入CF的Global API Key: " cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2242,7 +2242,7 @@ web_security() { echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" - echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "輸入CF的帳號:" cfuser @@ -2600,7 +2600,7 @@ block_container_port() { local container_name_or_id=$1 local allowed_ip=$2 - # 获取容器的 IP 地址 + # 取得容器的 IP 位址 local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") if [ -z "$container_ip" ]; then @@ -2708,7 +2708,7 @@ clear_container_rules() { fi - echo "已允許IP+連接埠存取該服務" + echo "已允许IP+端口访问该服务" save_iptables_rules } @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 清除封鎖所有其他 IP 存取的規則 + # 清除封禁所有其他 IP 访问的规则 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -3158,7 +3158,7 @@ session_exists() { tmux has-session -t $1 2>/dev/null } -# 循環直到找到一個不存在的會話名稱 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done @@ -3234,7 +3234,7 @@ f2b_basic_config() { local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 + # Alpine 預設 jail 通常為 sshd;僅當偵測到自訂 alpine-sshd 規則時才切換 if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi @@ -3274,7 +3274,7 @@ EOF fail2ban-client status $jail_name || true } -# 直接開啟主配置/覆蓋配置編輯(nano) +# 直接打开主配置/覆盖配置编辑(nano) # 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 f2b_edit_config() { root_use @@ -3612,7 +3612,7 @@ list_stream_services() { # 服務名取檔名 service_name=$(basename "$conf" .conf) - # 取得 upstream 區塊中的 server 後端 IP:端口 + # 获取 upstream 块中的 server 后端 IP:端口 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) # 取得 listen 端口 @@ -3704,7 +3704,7 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四層代理" + send_stats "修改四层代理" ;; 6) send_stats "刪除轉送配置" @@ -3752,7 +3752,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無效選擇"; return 1 ;; esac - read -e -p "請輸入你的一個或多個後端IP+埠以空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3890,7 +3890,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3931,7 +3931,7 @@ ldnmp_web_status() { send_stats "建立關聯站點" echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3963,7 +3963,7 @@ ldnmp_web_status() { 8) send_stats "編輯網站配置" - read -e -p "编辑站点配置,请输入你要编辑的域名: " yuming + read -e -p "編輯網站配置,請輸入你要編輯的網域:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4126,7 +4126,7 @@ EOF configure_frpc() { - send_stats "安裝frp客戶端" + send_stats "安装frp客户端" read -e -p "請輸入外網對接IP:" server_addr read -e -p "請輸入外網對接token:" token echo @@ -4185,7 +4185,7 @@ delete_forwarding_service() { read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服務$service_name已成功從 frpc.toml 刪除" + echo "服務$service_name 已成功从 frpc.toml 删除" docker restart frpc @@ -4216,7 +4216,7 @@ list_forwarding_services() { } /^\[.*\]/ { - # 如果已有服务信息,在处理新服务之前打印当前服务 + # 如果已有服務訊息,在處理新服務之前列印目前服務 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4258,7 +4258,7 @@ list_forwarding_services() { } END { - # 列印最後一個服務的訊息 + # 打印最后一个服务的信息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4292,7 +4292,7 @@ generate_access_urls() { # 只在有有效連接埠時顯示標題和內容 if [ "$has_valid_ports" = true ]; then - echo "FRP服务对外访问地址:" + echo "FRP服務對外存取位址:" # 處理 IPv4 位址 for port in "${ports[@]}"; do @@ -4301,7 +4301,7 @@ generate_access_urls() { fi done - # 处理 IPv6 地址(如果存在) + # 處理 IPv6 位址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4415,7 +4415,7 @@ frps_panel() { 8) send_stats "阻止IP訪問" - echo "如果你已經反代域名訪問了,可用此功能阻止IP+端口訪問,這樣更安全。" + echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" read -e -p "請輸入需要阻止的連接埠:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4446,7 +4446,7 @@ frpc_panel() { echo -e "FRP客戶端$check_frp $update_status" echo "與服務端對接,對接後可建立內網穿透服務到網際網路存取" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" - echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -4590,10 +4590,10 @@ yt_menu_pro() { --no-overwrites --no-post-overwrites "$url" read -e -p "下載完成,按任何鍵繼續..." ;; 6) - send_stats "大量影片下載" + send_stats "批量视频下载" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 輸入多個視訊連結位址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE echo "現在開始批量下載..." @@ -4607,7 +4607,7 @@ yt_menu_pro() { read -e -p "批次下載完成,按任何鍵繼續..." ;; 7) send_stats "自訂影片下載" - read -e -p "請輸入完整 yt-dlp 參數(不含 yt-dlp):" custom + read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4785,7 +4785,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版本 sysctl.conf 殘留 +# 清理可能導致衝突的舊版 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -4953,7 +4953,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5038,7 +5038,7 @@ fetch_remote_ssh_keys() { return 1 } else - echo "錯誤:系統中未找到 curl 或 wget,無法下載公鑰" >&2 + echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 rm -f "${temp_file}" return 1 fi @@ -5561,7 +5561,7 @@ dd_xitong() { ;; 45) - send_stats "重装windows server 22" + send_stats "重裝windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -5616,7 +5616,7 @@ bbrv3() { # 官方已徹底移除對 jammy, focal, bullseye 等舊系統的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then - echo -e "${gl_hong}XanMod 官方已停止對目前系統($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" + echo -e "${gl_hong}XanMod 官方已停止对当前系统($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" return 1 fi @@ -5696,7 +5696,7 @@ bbrv3() { check_disk_space 3 check_swap xanmod_add_repo || { - echo "XanMod官方仓库配置失败,请稍后重试" + echo "XanMod官方倉庫配置失敗,請稍後重試" return 1 } @@ -5766,7 +5766,7 @@ bbrv3() { echo "" echo "核心管理" echo "------------------------" - echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" + echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5831,7 +5831,7 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安装 ELRepo 仓库配置 (版本 9)..." + echo "安裝 ELRepo 倉庫設定 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "安裝 ELRepo 倉庫設定 (版本 10)..." @@ -5845,7 +5845,7 @@ elrepo_install() { echo "啟用 ELRepo 核心倉庫並安裝最新的主線核心..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安裝 ELRepo 倉庫配置並更新至最新主線核心。" + echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" server_reboot } @@ -5858,7 +5858,7 @@ elrepo() { while true; do clear kernel_version=$(uname -r) - echo "您已安裝elrepo內核" + echo "您已安装elrepo内核" echo "當前核心版本:$kernel_version" echo "" @@ -5900,7 +5900,7 @@ elrepo() { echo "影片介紹: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "僅支援紅帽系列發行 CentOS/RedHat/Alma/Rocky/oracle" - echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" + echo "升級Linux核心可提升系統效能與安全,建議有條件的嘗試,生產環境謹慎升級!" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -6013,7 +6013,7 @@ clamav() { ;; 3) send_stats "自訂目錄掃描" - read -e -p "請輸入要掃描的目錄,用空格分隔(例如:/etc /var /usr /home /root):" directories + read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories install_docker clamav_freshclam clamav_scan $directories @@ -6058,7 +6058,7 @@ _kernel_optimize_core() { case "$scene" in high|stream|game) - # 高效能/直播/遊戲:激進參數 + # 高性能/直播/游戏:激进参数 SWAPPINESS=10 DIRTY_RATIO=15 DIRTY_BG_RATIO=5 @@ -6319,12 +6319,12 @@ LIMITS # ── BBR 持久化 ── if [ "$CC" = "bbr" ]; then echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null - # 清理舊的 sysctl.conf 裡的 bbr 設定(避免衝突) + # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" - echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 拥塞算法: ${CC}| 隊列:${QDISC}${gl_bai}" } # ── 各模式入口函數(保持原有呼叫介面不變) ── @@ -6354,10 +6354,10 @@ restore_defaults() { # 清理 sysctl.conf 裡可能殘留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新載入系統預設配置 + # 重新加载系统默认配置 sysctl --system 2>/dev/null | tail -1 - # 還原透明大頁面 + # 还原透明大页面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null @@ -6380,7 +6380,7 @@ Kernel_optimize() { send_stats "Linux核心調優管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" - echo "Linux系統核心參數優化" + echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" else @@ -6560,7 +6560,7 @@ break_end shell_bianse() { root_use - send_stats "命令列美化工具" + send_stats "命令行美化工具" while true; do clear echo "命令列美化工具" @@ -6641,7 +6641,7 @@ linux_trash() { ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "回收站為空" echo "------------------------" echo "1. 啟用回收站 2. 關閉回收站" - echo "3. 还原内容 4. 清空回收站" + echo "3. 還原內容 4. 清空回收站" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6653,7 +6653,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已啟用,刪除的檔案將移至回收站。" + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -6954,7 +6954,7 @@ kj_ssh_read_auth() { done if [[ "$password_or_key" != *"-----BEGIN"* || "$password_or_key" != *"PRIVATE KEY-----"* ]]; then - echo "无效的密钥内容!" + echo "無效的密鑰內容!" return 1 fi @@ -7007,7 +7007,7 @@ list_connections() { add_connection() { send_stats "新增連接" echo "建立新連接範例:" - echo "- 連線名稱: my_server" + echo " - 连接名称: my_server" echo "- IP位址: 192.168.1.100" echo "- 使用者名稱: root" echo "- 連接埠: 22" @@ -7050,7 +7050,7 @@ delete_connection() { # 使用連接 use_connection() { send_stats "使用連接" - read -e -p "请输入要使用的连接编号: " num + read -e -p "請輸入要使用的連接編號:" num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -7062,7 +7062,7 @@ use_connection() { echo "正在連接到$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密鑰連接 + # 使用密钥连接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" @@ -7073,7 +7073,7 @@ use_connection() { else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7483,7 +7483,7 @@ run_task() { echo "同步完成!" else echo "同步失敗! 請檢查以下內容:" - echo "1. 網路連線是否正常" + echo "1. 网络连接是否正常" echo "2. 遠端主機是否可存取" echo "3. 認證資訊是否正確" echo "4. 本機和遠端目錄是否有正確的存取權限" @@ -7567,7 +7567,7 @@ rsync_manager() { view_tasks echo echo "1. 建立新任務 2. 刪除任務" - echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" @@ -7742,7 +7742,7 @@ linux_tools() { left=$(printf "❌ %-12s 未安裝" "${tools[i]}") fi - # 右列(防止數組越界) + # 右列(防止数组越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then right=$(printf "✅ %-12s 已安裝" "${tools[i+1]}") @@ -7760,7 +7760,7 @@ linux_tools() { echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" @@ -8132,7 +8132,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -e -p "未偵測到 compose 目錄,請手動輸入路徑:" project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -8189,11 +8189,11 @@ docker_ssh_migration() { if [ -d "/home/docker" ]; then echo -e "${gl_kjlan}備份 /home/docker 下的檔案...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的檔案已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${gl_lv}備份完成:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" echo -e "${gl_lv}可用還原腳本:${RESTORE_SCRIPT}${gl_bai}" @@ -8302,7 +8302,7 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8367,7 +8367,7 @@ docker_ssh_migration() { echo -e "" echo "------------------------" echo -e "1. 備份docker項目" - echo -e "2. 遷移docker項目" + echo -e "2. 迁移docker项目" echo -e "3. 還原docker項目" echo -e "4. 刪除docker專案的備份文件" echo "------------------------" @@ -8697,12 +8697,12 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程測試腳本" - echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" + echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" @@ -8896,7 +8896,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示使用者輸入CPU核心數和占用百分比,如果回車則使用預設值 + # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 read -e -p "請輸入CPU核心數 [預設:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -8917,7 +8917,7 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文雲安裝活躍腳本" + send_stats "甲骨文云安装活跃脚本" ;; [Nn]) @@ -9866,7 +9866,7 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔名還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -10103,7 +10103,7 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" + echo "${gl_huang}偵測到新版本:$remote_version${gl_bai}" else echo "${gl_lv}目前版本已是最新:$local_version${gl_bai}" fi @@ -10598,7 +10598,7 @@ PY - # OpenClaw API 协议探测逻辑已移除:不再自动探测/判定 API 类型。 + # OpenClaw API 協定偵測邏輯已移除:不再自動偵測/判定 API 類型。 # 說明:API 類型由使用者明確配置(models.providers..api),腳本不再嘗試呼叫 /responses 做推論。 # 建構模型配置 JSON @@ -10754,7 +10754,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 預設模型不能為空" + echo "❌ 默认模型不能为空" return 1 fi @@ -10775,7 +10775,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11314,7 +11314,7 @@ with open(path, 'w', encoding='utf-8') as f: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ 已更新 provider {name} 协议为: {new_api}') +print(f'✅ 已更新 provider {name} 協定為: {new_api}') PY local rc=$? case "$rc" in @@ -11461,7 +11461,7 @@ with open(path, 'w', encoding='utf-8') as f: f.write('\n') print(f'🗑️ 已刪除 provider: {name}') -print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') +print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 個關聯模型引用') PY local rc=$? case "$rc" in @@ -11894,7 +11894,7 @@ PYTHON_EOF return 0 else if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "gum 不可用,返回旧版输入模式。" + echo "gum 不可用,傳回舊版輸入模式。" sleep 1 continue fi @@ -12029,7 +12029,7 @@ PYTHON_EOF fi done - [ "$count" -gt 0 ] && echo "✅ 已同步$count 个 agent 的会话模型为 $model_ref" + [ "$count" -gt 0 ] && echo "✅ 已同步$count個 agent 的會話模型為$model_ref" return 0 } @@ -12208,7 +12208,7 @@ PYTHON_EOF echo "- [copilot-proxy] # Copilot 介面轉發" echo "" echo "⚙️ 功能擴充:" - echo " - [lobster] # 审批流 (带人工确认)" + echo "- [lobster] # 審批流 (附人工確認)" echo "- [voice-call] # 語音通話能力" echo "- [nostr] # 加密隱私聊天" echo "--------------------------------------------------------" @@ -12304,7 +12304,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重启 OpenClaw 服务以加载变更..." + echo "🔄 正在重啟 OpenClaw 服務以載入變更..." start_gateway fi break_end @@ -12317,21 +12317,21 @@ PYTHON_EOF while true; do clear echo "========================================" - echo "技能管理 (安裝/刪除)" + echo " 技能管理 (安装/删除) " echo "========================================" echo "目前已安裝技能:" openclaw skills list echo "----------------------------------------" # 輸出建議的實用技能列表 - echo "推荐的实用技能(可直接复制名称输入):" + echo "建議的實用技能(可直接複製名稱輸入):" echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" echo "notion # 操作 Notion 頁面、資料庫和區塊" echo "apple-notes # macOS 原生筆記管理 (建立/編輯/搜尋)" echo "apple-reminders # macOS 提醒事項管理 (待辦事項清單)" echo "1password # 自動化讀取和注入 1Password 金鑰" echo "gog # Google Workspace (Gmail/雲端盤/文件) 全能助手" - echo "things-mac # 深度整合 Things 3 任务管理" + echo "things-mac # 深度整合 Things 3 任務管理" echo "bluebubbles # 透過 BlueBubbles 完美收發 iMessage" echo "himalaya # 終端郵件管理 (IMAP/SMTP 強力工具)" echo "summarize # 網頁/播客/YouTube 影片內容一鍵總結" @@ -12476,7 +12476,7 @@ openclaw_json_get_bool() { return 0 fi - # 兼容两种常见目录命名: + # 相容於兩種常見目錄命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 @@ -13705,7 +13705,7 @@ PY qmd_path=$(command -v qmd 2>/dev/null || true) if [ -n "$qmd_path" ]; then if qmd --version >/dev/null 2>&1; then - echo "✅ qmd 已存在且可用: $qmd_path" + echo "✅ qmd 已存在且可用:$qmd_path" OPENCLAW_MEMORY_QMD_PATH="$qmd_path" return 0 else @@ -13770,7 +13770,7 @@ PY echo "即將執行自動部署(詳細模式)" echo "目標方案:$scheme_label" echo "地區: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "鏡像來源探測: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下載來源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then echo "預計下載路徑:$OPENCLAW_MEMORY_EXPECT_PATH" @@ -13895,7 +13895,7 @@ EOF OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" - echo "✅ 已寫入模型路徑" + echo "✅ 已写入模型路径" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -14059,7 +14059,7 @@ EOF echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ 偵測到 includeDefaultMemory=false" - echo " 这会导致默认记忆文件(MEMORY.md + memory/*.md)不被索引" + echo "這會導致預設記憶檔案(MEMORY.md + memory/*.md)不被索引" echo "所以 Indexed 會一直顯示 0/N" echo "" read -e -p "是否恢復為 true 並重建索引? (Y/n):" fix_choice @@ -14102,7 +14102,7 @@ EOF builtin|local) current_label="Local" ;; *) current_label="未配置" ;; esac - echo "当前方案: $current_label" + echo "當前方案:$current_label" echo "" echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" @@ -14321,7 +14321,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14605,7 +14605,7 @@ print(json.dumps(data, indent=2)) echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" echo "Profile (預設): ${current_profile:-(unset)}" - echo "Exec 限制: ${current_sec:-(unset)}" + echo " Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" echo "提權開關: ${current_elevated:-(unset)}" @@ -14690,7 +14690,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切換為開發增強模式 (允許提權,但常規危險命令仍需審批)${gl_bai}" + echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" } openclaw_permission_apply_full() { @@ -14755,7 +14755,7 @@ except Exception: while true; do clear echo "=======================================" - echo " Exec 命令白名单管理" + echo "Exec 指令白名單管理" echo "=======================================" echo "目前白名單:" local allowlist_json @@ -14819,7 +14819,7 @@ except Exception as e: echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" + echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" @@ -15010,7 +15010,7 @@ PY return 0 fi fi - # 回退:從檔案系統讀取 + # 回退:从文件系统读取 python3 <<'PY' import json,os base=os.path.expanduser("~/.openclaw/agents") @@ -15109,7 +15109,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體建立失敗" + echo "❌ 智能體創建失敗" return 1 fi } @@ -15455,7 +15455,7 @@ openclaw_backup_restore_menu() { echo "先造訪URL觸發設備ID,然後回車下一步進行配對。" read echo -e "${gl_kjlan}正在載入設備列表…${gl_bai}" - # 自动添加域名到 allowedOrigins + # 自動新增網域到 allowedOrigins config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then new_origin="https://${yuming}" @@ -15605,7 +15605,7 @@ while true; do echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager視覺化面板" echo -e "${gl_kjlan}5. ${color5}OpenList多重儲存文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠端桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" @@ -15619,7 +15619,7 @@ while true; do echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" echo -e "${gl_kjlan}29. ${color29}searxng聚合搜尋站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相簿系統" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免费的在线图表软件 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" @@ -15895,7 +15895,7 @@ while true; do check_docker_image_update $docker_name clear echo -e "哪吒監控$check_docker $update_status" - echo "開源、輕量、易用的伺服器監控與維運工具" + echo "开源、轻量、易用的服务器监控与运维工具" echo "官網搭建文件: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -16635,7 +16635,7 @@ while true; do } - local docker_describe="dockge是一個可視化的docker-compose容器管理面板" + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" local docker_url="官網介紹:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" @@ -16786,7 +16786,7 @@ while true; do } - local docker_describe="Sun-Panel伺服器、NAS導覽面板、Homepage、瀏覽器首頁" + local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" local docker_url="官網介紹: https://doc.sun-panel.top/zh_cn/" local docker_use="echo \"帳號: admin@sun.cc 密碼: 12345678\"" local docker_passwd="" @@ -17139,7 +17139,7 @@ while true; do } - local docker_describe="這是一個普羅米修斯的主機資料擷取元件,請部署在被監控主機上。" + local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" @@ -17169,7 +17169,7 @@ while true; do } - local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" + local docker_describe="這是一個普羅米修斯的容器資料擷取元件,請部署在被監控主機上。" local docker_url="官網介紹:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -18162,7 +18162,7 @@ while true; do local docker_describe="輕量級的自架伺服器監控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" + local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -18330,7 +18330,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" - local docker_passwd="echo \"初始账号: admin 初始密码: abc123 登陆后请及时修改登录密码\"" + local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" local app_size="1" docker_app @@ -18753,7 +18753,7 @@ while true; do echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可快速連接網絡${gl_bai}" echo -e "${gl_lv}2. Windows下載客戶端,複製設定碼連接網路。${gl_bai}" - echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" + echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製設定碼連接網路。${gl_bai}" echo -e "${gl_lv}官方客戶端下載方式: https://www.wireguard.com/install/${gl_bai}" break_end @@ -18782,7 +18782,7 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 建立目錄(如果不存在) + # 创建目录(如果不存在) mkdir -p "$(dirname "$CONFIG_FILE")" echo "請貼上你的客戶端配置,連續按兩次回車保存:" @@ -18915,7 +18915,7 @@ while true; do syncthing/syncthing:latest } - local docker_describe="開源的點對點檔案同步工具,類似 Dropbox、Resilio Sync,但完全去中心化。" + local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" local docker_url="官網介紹:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" @@ -19277,7 +19277,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) local docker_port=8112 docker_rum() { @@ -19294,7 +19294,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="Lucky 是一个大内网穿透及端口转发管理工具,支持 DDNS、反向代理、WOL 等功能。" + local docker_describe="Lucky 是一個大內部網路穿透及連接埠轉送管理工具,支援 DDNS、反向代理、WOL 等功能。" local docker_url="項目地址:${gh_https_url}github.com/gdy666/lucky" local docker_use="echo \"預設帳號密碼: 666\"" local docker_passwd="" @@ -19381,11 +19381,11 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "全部應用還原" - echo "可用的應用程式備份" + echo "可用的应用备份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔名還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -19400,7 +19400,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -n "$filename" ]; then echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "應用資料已還原,目前請手動進入指定應用程式選單,更新應用,即可還原應用程式。" + echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" else echo "沒有找到壓縮包。" fi @@ -19442,11 +19442,11 @@ linux_work() { clear send_stats "後台工作區" echo -e "後台工作區" - echo -e "系統將為你提供可以後台常駐運作的工作區,你可以用來執行長時間的任務" + echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" - echo "当前已存在的工作区列表" + echo "目前已存在的工作區列表" echo -e "${gl_kjlan}------------------------" tmux list-sessions echo -e "${gl_kjlan}------------------------" @@ -19461,7 +19461,7 @@ linux_work() { echo -e "${gl_kjlan}9. ${gl_bai}9號工作區" echo -e "${gl_kjlan}10. ${gl_bai}10號工作區" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐模式${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}創建/進入工作區" echo -e "${gl_kjlan}23. ${gl_bai}注入指令到後台工作區" echo -e "${gl_kjlan}24. ${gl_bai}刪除指定工作區" @@ -19869,7 +19869,7 @@ log_menu() { ;; 3) send_stats "查看登入/安全日誌" - echo "====== 最近登入日誌 ======" + echo "====== 最近登录日志 ======" last -n 10 echo echo "====== 認證日誌 ======" @@ -19926,7 +19926,7 @@ env_menu() { BASHRC="$HOME/.bashrc" PROFILE="$HOME/.profile" - send_stats "系統變數管理工具" + send_stats "系统变量管理工具" show_env_vars() { clear @@ -19994,7 +19994,7 @@ env_menu() { } source_files() { - echo "正在重新加载环境变量..." + echo "正在重新載入環境變數..." send_stats "正在重新載入環境變數" source "$BASHRC" source "$PROFILE" @@ -20131,10 +20131,10 @@ linux_Settings() { echo -e "${gl_kjlan}7. ${gl_bai}優化DNS位址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}停用ROOT帳戶建立新帳戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看連接埠佔用狀態${gl_kjlan}12. ${gl_bai}修改虛擬記憶體大小" + echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虛擬記憶體大小" echo -e "${gl_kjlan}13. ${gl_bai}使用者管理${gl_kjlan}14. ${gl_bai}使用者/密碼產生器" echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設定BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主機名" + echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主机名" echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新來源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" @@ -20163,7 +20163,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -20202,7 +20202,7 @@ linux_Settings() { echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查詢更多版本: https://www.python.org/downloads/" + echo "查询更多版本: https://www.python.org/downloads/" echo "------------" read -e -p "輸入你要安裝的python版本號碼(輸入0退出):" py_new_v @@ -20280,7 +20280,7 @@ EOF send_stats "開放埠" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "連接埠已全部開放" + echo "端口已全部开放" ;; 6) @@ -20291,17 +20291,17 @@ EOF clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 讀取目前的 SSH 連接埠號 + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') - # 打印当前的 SSH 端口号 + # 列印目前的 SSH 連接埠號碼 echo -e "目前的 SSH 連接埠號碼是:${gl_huang}$current_port ${gl_bai}" echo "------------------------" echo "連接埠號碼範圍1到65535之間的數字。 (輸入0退出)" - # 提示使用者輸入新的 SSH 連接埠號碼 - read -e -p "請輸入新的 SSH 連接埠號碼:" new_port + # 提示用户输入新的 SSH 端口号 + read -e -p "请输入新的 SSH 端口号: " new_port # 判斷連接埠號碼是否在有效範圍內 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 @@ -20364,7 +20364,7 @@ EOF if grep -Eq '^\s*precedence\s+::ffff:0:0/96\s+100\s*$' /etc/gai.conf 2>/dev/null; then - echo -e "当前网络优先级设置: ${gl_huang}IPv4${gl_bai}優先" + echo -e "目前網路優先權設定:${gl_huang}IPv4${gl_bai}優先" else echo -e "目前網路優先權設定:${gl_huang}IPv6${gl_bai}優先" fi @@ -20375,7 +20375,7 @@ EOF echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "選擇優先的網路:" choice + read -e -p "选择优先的网络: " choice case $choice in 1) @@ -20489,7 +20489,7 @@ EOF case $sub_choice in 1) - # 提示使用者輸入新使用者名稱 + # 提示用户输入新用户名 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false @@ -20603,7 +20603,7 @@ EOF echo "------------------------" echo "亞洲" echo "1. 中國上海時間 2. 中國香港時間" - echo "3. 日本東京時間 4. 韓國首爾時間" + echo "3. 日本东京时间 4. 韩国首尔时间" echo "5. 新加坡時間 6. 印度加爾各答時間" echo "7. 阿聯酋杜拜時間 8. 澳洲雪梨時間" echo "9. 泰國曼谷時間" @@ -20701,7 +20701,7 @@ EOF send_stats "主機名稱已更改" sleep 1 else - echo "已退出,未更改主机名。" + echo "已退出,未更改主機名稱。" break fi done @@ -20936,7 +20936,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21108,7 +21108,7 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" echo "------------------------------------------------" linux_clean @@ -21287,7 +21287,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21347,7 +21347,7 @@ linux_file() { send_stats "修改檔案權限" ;; 14) # 重命名文件 - read -e -p "請輸入目前檔名:" current_name + read -e -p "请输入当前文件名: " current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" @@ -21744,7 +21744,7 @@ while true; do if [ -z "$sh_v_new" ]; then echo -e "${gl_hong}無法獲取最新版本信息,請檢查網絡連接${gl_bai}" elif [ "$sh_v" = "$sh_v_new" ]; then - echo -e "${gl_lv}你已经是最新版本!${gl_huang}v$sh_v${gl_bai}" + echo -e "${gl_lv}你已經是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "腳本已經最新了,無需更新" else echo "發現新版本!" @@ -21829,7 +21829,7 @@ while true; do if [ -n "$cron_sed_cmd" ]; then SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi - # 從舊腳本恢復 permission_granted 和 ENABLE_STATS 設置 + # 从旧脚本恢复 permission_granted 和 ENABLE_STATS 设置 SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # 部署到 /usr/local/bin/k 和 /usr/bin/k SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21939,7 +21939,7 @@ echo "核心調優面板 k nhyh | k 核心最佳化" echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" echo "系統回收站 k trash | k hsz | k 回收站" -echo "系统备份功能 k backup | k bf | k 备份" +echo "系統備份功能 k backup | k bf | k 備份" echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" @@ -22221,13 +22221,13 @@ else shift case "$1" in "" ) - # sshkey → 互動選單 + # sshkey → 交互菜单 send_stats "SSHKey 互動選單" sshkey_panel ;; github ) shift - send_stats "從 GitHub 導入 SSH 公鑰" + send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From f94ac69220c24c391753473545a1dbd1a73999ff Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 17 Jun 2026 21:54:12 +0800 Subject: [PATCH 1196/1285] Fix Jitsi Meet reverse proxy deployment --- cn/kejilion.sh | 45 +++++++++++++++++++++++++++++++-------------- en/kejilion.sh | 42 +++++++++++++++++++++++++++++------------- jp/kejilion.sh | 42 +++++++++++++++++++++++++++++------------- kejilion.sh | 45 +++++++++++++++++++++++++++++++-------------- kr/kejilion.sh | 42 +++++++++++++++++++++++++++++------------- tw/kejilion.sh | 42 +++++++++++++++++++++++++++++------------- 6 files changed, 178 insertions(+), 80 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5815f6b11..4c8fd949f 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}管理" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -3069,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "阻止IP访问 ${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -18057,6 +18060,7 @@ while true; do local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18064,32 +18068,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "应用已卸载" diff --git a/en/kejilion.sh b/en/kejilion.sh index 869c791d4..20db1d63a 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}manage" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}Domain name access settings" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -18063,6 +18065,7 @@ while true; do local app_text="An open source secure video conferencing solution that supports multi-person online conferencing, screen sharing and encrypted communication." local app_url="Official website: https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18070,32 +18073,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "App has been uninstalled" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 00e9ab2f3..068ee1ed3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}管理" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}ドメイン名アクセス設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -18063,6 +18065,7 @@ while true; do local app_text="複数人でのオンライン会議、画面共有、暗号化通信をサポートするオープンソースの安全なビデオ会議ソリューション。" local app_url="公式サイト:https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18070,32 +18073,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "アプリがアンインストールされました" diff --git a/kejilion.sh b/kejilion.sh index 661b0e82c..074b4f567 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}管理" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -3069,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "阻止IP访问 ${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -18063,6 +18066,7 @@ while true; do local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="官方网站: https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18070,32 +18074,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "应用已卸载" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index dbe709274..b0bbb78ab 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}관리하다" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}도메인 이름 액세스 설정" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -18063,6 +18065,7 @@ while true; do local app_text="다자간 온라인 회의, 화면 공유, 암호화된 통신을 지원하는 오픈 소스 보안 화상 회의 솔루션입니다." local app_url="공식 홈페이지: https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18070,32 +18073,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "앱이 제거되었습니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 7376ee895..bb750064c 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -2865,7 +2865,7 @@ send_stats "${docker_name}管理" while true; do clear check_docker_app - check_docker_image_update $docker_name + check_docker_image_update "${docker_app_service:-$docker_name}" echo -e "$docker_name $check_docker $update_status" echo "$docker_describe" echo "$docker_url" @@ -2991,9 +2991,10 @@ docker_app_plus() { echo -e "$app_name $check_docker $update_status" echo "$app_text" echo "$app_url" - if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then + local docker_check_name="${docker_app_service:-$docker_name}" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_check_name"; then if [ ! -f "/home/docker/${docker_name}_port.conf" ]; then - local docker_port=$(docker port "$docker_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') + local docker_port=$(docker port "$docker_check_name" | head -n1 | awk -F'[:]' '/->/ {print $NF; exit}') docker_port=${docker_port:-0000} echo "$docker_port" > "/home/docker/${docker_name}_port.conf" fi @@ -3056,7 +3057,8 @@ docker_app_plus() { send_stats "${docker_name}域名存取設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; 6) @@ -18063,6 +18065,7 @@ while true; do local app_text="一個開源的安全視訊會議解決方案,支援多人線上會議、螢幕分享與加密通訊。" local app_url="官方網站: https://jitsi.org/" local docker_name="jitsi" + local docker_app_service="jitsi-web-1" local docker_port="8081" local app_size="3" @@ -18070,32 +18073,45 @@ while true; do add_yuming mkdir -p /home/docker/jitsi && cd /home/docker/jitsi - wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4) - unzip "$(ls -t | head -n 1)" - cd "$(ls -dt */ | head -n 1)" + rm -rf docker-jitsi-meet-* jitsi.zip + local jitsi_zip_url=$(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep -m1 '"zipball_url"' | cut -d\" -f4) + if [ -z "$jitsi_zip_url" ]; then + echo "Failed to get Jitsi Meet latest download URL" + return 1 + fi + wget -O jitsi.zip "$jitsi_zip_url" + unzip -q jitsi.zip + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" cp env.example .env ./gen-passwords.sh - mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + mkdir -p /home/docker/jitsi/config/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri} + sed -i "s|^CONFIG=.*|CONFIG=/home/docker/jitsi/config|" .env + grep -q '^COMPOSE_PROJECT_NAME=' .env && sed -i "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=jitsi|" .env || echo "COMPOSE_PROJECT_NAME=jitsi" >> .env sed -i "s|^HTTP_PORT=.*|HTTP_PORT=${docker_port}|" .env - sed -i "s|^#PUBLIC_URL=https://meet.example.com:\${HTTPS_PORT}|PUBLIC_URL=https://$yuming:443|" .env + sed -i "s|^#\?PUBLIC_URL=.*|PUBLIC_URL=https://$yuming|" .env + grep -q '^PUBLIC_URL=' .env || echo "PUBLIC_URL=https://$yuming" >> .env + grep -q '^DISABLE_HTTPS=' .env && sed -i "s|^DISABLE_HTTPS=.*|DISABLE_HTTPS=1|" .env || echo "DISABLE_HTTPS=1" >> .env + grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env + sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - block_container_port "$docker_name" "$ipv4_address" + local jitsi_web_container=$(docker compose ps -q web) + [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } docker_app_update() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" - docker compose down --rmi all + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" + docker compose pull docker compose up -d } docker_app_uninstall() { cd /home/docker/jitsi - cd "$(ls -dt */ | head -n 1)" + cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi echo "應用程式已解除安裝" From ad4ec58bbf55d032080d24b07d819496a7d76736 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 17 Jun 2026 22:07:53 +0800 Subject: [PATCH 1197/1285] Fix Jitsi web container lookup after proxy setup --- cn/kejilion.sh | 2 +- en/kejilion.sh | 2 +- jp/kejilion.sh | 2 +- kejilion.sh | 2 +- kr/kejilion.sh | 2 +- tw/kejilion.sh | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4c8fd949f..edbca16bb 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -18089,9 +18089,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } diff --git a/en/kejilion.sh b/en/kejilion.sh index 20db1d63a..027a28131 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -18094,9 +18094,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 068ee1ed3..35ee28653 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -18094,9 +18094,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } diff --git a/kejilion.sh b/kejilion.sh index 074b4f567..cd2186c42 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -18095,9 +18095,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b0bbb78ab..b15c593ba 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -18094,9 +18094,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } diff --git a/tw/kejilion.sh b/tw/kejilion.sh index bb750064c..3e6052154 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -18094,9 +18094,9 @@ while true; do grep -q '^ENABLE_HTTP_REDIRECT=' .env && sed -i "s|^ENABLE_HTTP_REDIRECT=.*|ENABLE_HTTP_REDIRECT=0|" .env || echo "ENABLE_HTTP_REDIRECT=0" >> .env sed -i "/'\${HTTPS_PORT}:443'/d" docker-compose.yml docker compose up -d + local jitsi_web_container=$(docker compose ps -q web) ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} - local jitsi_web_container=$(docker compose ps -q web) [ -n "$jitsi_web_container" ] && block_container_port "$jitsi_web_container" "$ipv4_address" } From 51f8cb419f3c45e07946e3956f3ed6d1fbb0a715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Jun 2026 20:59:16 +0800 Subject: [PATCH 1198/1285] Update kejilion_sh_log.txt --- kejilion_sh_log.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 4933be98a..08bfc05f1 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1514,3 +1514,8 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 ------------------------ 2026-05-20 v4.5.1 应用市场 Hermes 管理增加新版本检测和API模型列表一致性同步功能。 +------------------------ +2026-06-18 v4.5.2 +系统工具中修复部分场景中SSH端口切换后无法连接的问题。 +应用市场中的多人会议项目部署报错问题。 + From 32f2bff6821359a62564ec38bd936398259c5645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Jun 2026 20:59:51 +0800 Subject: [PATCH 1199/1285] Update shell version from 4.5.1 to 4.5.2 --- kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index cd2186c42..8d1424f91 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' From dd9926786674e1ed72f7eac5ced0948d822f9f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=91=E6=8A=80lion?= <131984541+kejilion@users.noreply.github.com> Date: Thu, 18 Jun 2026 21:00:18 +0800 Subject: [PATCH 1200/1285] Update kejilion.sh --- cn/kejilion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index edbca16bb..de622feb0 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' From 74a80690d206a89abe9d11e8137671b6fa402688 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 21 Jun 2026 06:33:16 +0000 Subject: [PATCH 1201/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-06-21=2006:33:16?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 49 ++--- jp/kejilion.sh | 179 ++++++++--------- kr/kejilion.sh | 257 ++++++++++++------------ tw/kejilion.sh | 525 +++++++++++++++++++++++++------------------------ 4 files changed, 507 insertions(+), 503 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 027a28131..2f66feb73 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2331,12 +2331,12 @@ check_nginx_compression() { # Check if brotli is enabled and uncommented if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="brCompression is on" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # Check if gzip is enabled and uncommented if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip compression is on" else @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # Clear the rules that allow the specified IP + # Clear the rules that allow specified IPs if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -3071,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "Block IP access${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -3223,7 +3224,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -5096,7 +5097,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -6694,9 +6695,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6738,7 +6739,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7486,7 +7487,7 @@ run_task() { else echo "Sync failed! Please check the following:" echo "1. Is the network connection normal?" - echo "2. Is the remote host accessible?" + echo "2. Whether the remote host is accessible" echo "3. Is the authentication information correct?" echo "4. Do the local and remote directories have correct access permissions?" fi @@ -8177,7 +8178,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # mirror + # Mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8786,7 +8787,7 @@ linux_test() { echo "Chengdu Telecom: 61.139.2.69" echo "Chengdu China Unicom: 119.6.6.6" echo "Chengdu Mobile: 211.137.96.205" - echo "Hunan Telecom: 36.111.200.100" + echo "湖南电信: 36.111.200.100" echo "Hunan Unicom: 42.48.16.100" echo "Hunan Mobile: 39.134.254.6" echo "------------------------" @@ -10149,7 +10150,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API management" + echo "6. API Management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -12217,7 +12218,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12345,7 +12346,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -15605,7 +15606,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15976,7 +15977,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17715,7 +17716,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -20213,7 +20214,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21508,7 +21509,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}connect to$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}Connect to$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21542,7 +21543,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 35ee28653..52aee8681 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' @@ -260,7 +260,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -867,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -1541,7 +1541,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -1750,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2240,8 +2240,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CFパラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2561,7 +2561,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -3071,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "IPアクセスをブロックする${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -3223,7 +3224,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3754,7 +3755,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3965,7 +3966,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4312,7 +4313,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4609,7 +4610,7 @@ yt_menu_pro() { read -e -p "バッチダウンロードが完了しました。続行するには任意のキーを押してください..." ;; 7) send_stats "カスタムビデオのダウンロード" - read -e -p "完全な yt-dlp パラメータを入力してください (yt-dlp を除く):" custom + read -e -p "完全な yt-dlp パラメータを入力してください (yt-dlp を除く)。" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4840,7 +4841,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -4955,7 +4956,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "秘密鍵情報が生成されました。 Be sure to copy and save it.として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" + echo -e "秘密鍵情報が生成されました。必ずコピーして保存してください。として保存できます${gl_huang}${ipv4_address}_ssh.key${gl_bai}今後の SSH ログイン用のファイル" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5611,7 +5612,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) + # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5910,7 +5911,7 @@ elrepo() { [Yy]) check_swap elrepo_install - send_stats "升级红帽内核" + send_stats "Red Hat カーネルをアップグレードする" server_reboot ;; [Nn]) @@ -6015,7 +6016,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6042,7 +6043,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6325,7 +6326,7 @@ LIMITS sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi - echo -e "${gl_lv}${mode_name}最適化が完了しました!設定は永続化されています${CONF}${gl_bai}" + echo -e "${gl_lv}${mode_name}最適化が完了しました!構成は永続化されています${CONF}${gl_bai}" echo -e "${gl_lv}メモリ:${MEM_MB}MB |輻輳アルゴリズム:${CC}|列:${QDISC}${gl_bai}" } @@ -6379,7 +6380,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" + send_stats "Linux カーネルのチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6694,9 +6695,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6738,7 +6739,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7195,7 +7196,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7374,7 +7375,7 @@ add_task() { echo "同期モードを選択してください:" echo "1. 標準モード (-avz)" - echo "2. 対象ファイルを削除(-avz --delete)" + echo "2. 删除目标文件 (-avz --delete)" read -e -p "(1/2) を選択してください:" mode case $mode in 1) options="-avz" ;; @@ -7486,7 +7487,7 @@ run_task() { else echo "同期に失敗しました!以下の点をご確認ください。" echo "1. ネットワーク接続は正常ですか?" - echo "2. リモートホストはアクセス可能ですか?" + echo "2. リモートホストにアクセスできるかどうか" echo "3. 認証情報は正しいですか?" echo "4. ローカル ディレクトリとリモート ディレクトリには正しいアクセス許可がありますか?" fi @@ -7647,7 +7648,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7767,7 +7768,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -8329,7 +8330,7 @@ docker_ssh_migration() { read -e -p "移行するバックアップ ディレクトリを入力してください:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } - kj_ssh_read_host_user_port "ターゲットサーバーIP:" "ターゲットサーバーの SSH ユーザー名 [デフォルトのルート]:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "root" "22" + kj_ssh_read_host_user_port "ターゲットサーバーIP:" "ターゲットサーバーの SSH ユーザー名 [デフォルトのルート]:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" @@ -8412,7 +8413,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8453,10 +8454,10 @@ linux_docker() { echo -e "Docker コンテナ:${gl_lv}$container_count${gl_bai}" docker ps -a echo "" - echo -e "Docker卷: ${gl_lv}$volume_count${gl_bai}" + echo -e "Docker ボリューム:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Dockerネットワーク:${gl_lv}$network_count${gl_bai}" + echo -e "Docker ネットワーク:${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -9288,7 +9289,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9800,7 +9801,7 @@ linux_ldnmp() { read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -10349,7 +10350,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10448,7 +10449,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11238,7 +11239,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11556,7 +11557,7 @@ PY echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" - echo "1. APIを追加する" + echo "1. APIの追加" echo "2. APIプロバイダーモデルリストを同期する" echo "3. API タイプの切り替え (完了/応答)" echo "4. APIの削除" @@ -11851,7 +11852,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12205,7 +12206,7 @@ PYTHON_EOF echo "- [whatsapp] #WhatsApp オートメーション" echo "" echo "🧠 メモリと AI:" - echo "- [memory-core] # 基本メモリ (ファイル取得)" + echo "- [memory-core] # 基本メモリ (ファイル検索)" echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" @@ -12273,7 +12274,7 @@ PYTHON_EOF rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードに成功しました。アクティブ化しています..." + echo "✅ ダウンロードが成功しました。アクティブ化されています..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12291,7 +12292,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12315,7 +12316,7 @@ PYTHON_EOF install_skill() { - send_stats "スキル管理" + send_stats "技能管理" while true; do clear echo "========================================" @@ -12336,7 +12337,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12378,7 +12379,7 @@ PYTHON_EOF if [ "$skill_action" = "1" ]; then local skill_found=false if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then - echo "💡 スキル [$skill_name]がユーザーディレクトリにインストールされます。" + echo "💡 スキル [$skill_name] がユーザーディレクトリにインストールされます。" skill_found=true elif [ -d "/usr/lib/node_modules/openclaw/skills/${skill_name}" ]; then echo "💡 スキル [$skill_name]がシステムディレクトリにインストールされます。" @@ -12809,7 +12810,7 @@ EOF echo "バックアップ ファイルは次の方法でダウンロードできます。" echo "- ローカルパス:$file_path" echo "- scp の例: scp root@yourserver:$file_path ./" - echo "- またはSFTPクライアントを使用してダウンロードします" + echo "- またはSFTPクライアントを使用してダウンロード" } openclaw_prepare_import_archive() { @@ -13783,7 +13784,7 @@ PY echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" - echo "詳細オプション: config と入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" + echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in yes|YES) @@ -14197,7 +14198,7 @@ EOF echo "書類:$file" echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14291,7 +14292,7 @@ EOF echo "2. メモリファイルを表示する" echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" - echo "5. 検索テスト (インデックスが機能していることを確認する)" + echo "5. 検索テスト (インデックスが機能していることを確認します)" echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" @@ -14532,9 +14533,9 @@ try: elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": print("拡張モードの開発") elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": - print("フルオープンモード") + print("完全开放模式") else: - print("カスタムモード") + print("自定义模式") except Exception: print("カスタムモード") PY @@ -14674,7 +14675,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -15082,7 +15083,7 @@ else: } openclaw_multiagent_list_agents() { - send_stats "OpenClaw多智能体-列出Agent" + send_stats "OpenClaw マルチエージェント - エージェントのリスト" python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); if not agents: print("エージェントはまだ構成されていません。"); raise SystemExit(0) for idx,item in enumerate(agents,1): @@ -15099,10 +15100,10 @@ for idx,item in enumerate(agents,1): [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ 智能体创建成功: $agent_id" + echo "✅ エージェントが正常に作成されました:$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15155,7 +15156,7 @@ for idx,item in enumerate(bindings,1): read -e -p "ルート バインディング値 (telegram:ops / discord:guild-a など) を入力してください。" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントをバインドします [$agent_id] -> [$bind_value]" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に追加されました" @@ -15173,7 +15174,7 @@ for idx,item in enumerate(bindings,1): read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" - read -e -p "続行することを確認するには「yes」と入力します。" confirm + read -e -p "続行することを確認するには、「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に削除されました" @@ -15381,7 +15382,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 設定ファイルを編集する" + send_stats "OpenClaw 構成ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15541,7 +15542,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期構成ウィザード" + 11) send_stats "初期設定ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15605,7 +15606,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15637,13 +15638,13 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" + echo -e "${gl_kjlan}59. ${color59}NewAPI 大型モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -15896,7 +15897,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "ネザ監視$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15905,7 +15906,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -16367,7 +16368,7 @@ while true; do } - local docker_describe="Onlyoffice は、非常に強力なオープンソースのオンライン オフィス ツールです。" + local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -16515,7 +16516,7 @@ while true; do } - local docker_describe="Uptime Kuma 使いやすいセルフホスト型監視ツール" + local docker_describe="Uptime Kuma 易于使用的自托管监控工具" local docker_url="公式サイト紹介:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" @@ -16657,7 +16658,7 @@ while true; do } - local docker_describe="librespeed は、JavaScript で実装され、すぐに使用できる軽量の速度テスト ツールです。" + local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" local docker_url="公式サイト紹介:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" @@ -16714,7 +16715,7 @@ while true; do } - local docker_describe="Photoprism は非常に強力なプライベート フォト アルバム システムです" + local docker_describe="photoprism非常强大的私有相册系统" local docker_url="公式サイト紹介:https://www.photoprism.app/" local docker_use="echo \"アカウント: admin パスワード:$rootpasswd\"" local docker_passwd="" @@ -16841,7 +16842,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"アカウント: admin パスワード: a123456\"" + local docker_use="echo 「アカウント: admin パスワード: a123456」" local docker_passwd="" local app_size="1" docker_app @@ -17990,7 +17991,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -19278,7 +19279,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19371,7 +19372,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -19460,7 +19461,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19782,7 +19783,7 @@ net_menu() { echo echo "=========== ネットワークカード管理メニュー ===========" echo "1.ネットワークカードを有効にする" - echo "2. 禁用网卡" + echo "2.ネットワークカードを無効にする" echo "3. ネットワークカードの詳細を表示する" echo "4. ネットワークカード情報を更新する" echo "0. 前のメニューに戻る" @@ -20028,7 +20029,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数 (ソース) をリロードします。" + echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -21102,7 +21103,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21394,7 +21395,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21414,7 +21415,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21508,7 +21509,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}に接続する$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}に接続します$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21542,7 +21543,7 @@ while true; do echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21907,7 +21908,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" +echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -21947,7 +21948,7 @@ echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k アップデートを更新 | kアップデート" +echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21987,7 +21988,7 @@ echo "コマンド お気に入り k お気に入り | k コマンドのお気 echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" -echo "システム情報を表示 k info" +echo "システム情報の表示 k info" echo "ROOT キー管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " echo "SSH 公開キーのインポート (GitHub) k sshkey github " diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b15c593ba..ead575127 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -2673,7 +2673,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2692,7 +2692,7 @@ clear_container_rules() { iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP fi - # 지정된 IP를 허용하는 규칙을 지웁니다. + # 특정 IP를 허용하는 규칙 지우기 if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3017,7 +3017,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3071,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "IP 접근 차단${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -3223,7 +3224,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3425,7 +3426,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3511,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4108,7 +4109,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4170,7 +4171,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4985,7 +4986,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5060,7 +5061,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원래 Authorized_keys 파일이 백업되었습니다." + echo "원본 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5137,7 +5138,7 @@ sshkey_panel() { echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 로그인하는 보다 안전한 방법인 키 쌍이 생성됩니다." + echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." @@ -5724,7 +5725,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" server_reboot } @@ -5734,7 +5735,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot } @@ -5884,7 +5885,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5902,7 +5903,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -7486,7 +7487,7 @@ run_task() { else echo "동기화에 실패했습니다! 다음 사항을 확인하세요." echo "1. 네트워크 연결이 정상인가요?" - echo "2. 원격 호스트에 접근할 수 있나요?" + echo "2. 원격 호스트에 접근 가능한지 여부" echo "3. 인증정보가 정확합니까?" echo "4. 로컬 및 원격 디렉터리에 올바른 액세스 권한이 있습니까?" fi @@ -9287,7 +9288,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -10950,12 +10951,12 @@ except FileNotFoundError: print('MSG\tℹ️ openclaw.json을 찾을 수 없습니다. 먼저 설치/초기화를 완료하세요.') raise SystemExit(0) except Exception as e: - print(f'MSG\t❌ 读取配置失败: {type(e).__name__}: {e}') + print(f'MSG\t❌ 구성을 읽지 못했습니다: {type(e).__name__}: {e}') raise SystemExit(0) providers = ((obj.get('models') or {}).get('providers') or {}) if not isinstance(providers, dict) or not providers: - print('MSG\tℹ️ 当前未配置任何 API provider。') + print('MSG\tℹ️ 현재 구성된 API 제공업체가 없습니다.') raise SystemExit(0) print('MSG\t--- 구성된 API 목록 ---') @@ -11001,7 +11002,7 @@ PY } sync-openclaw-provider-interactive() { local config_file="${HOME}/.openclaw/openclaw.json" - send_stats "OpenClaw API按Provider同步" + send_stats "공급자별 OpenClaw API 동기화" if [ ! -f "$config_file" ]; then echo "❌ 구성 파일을 찾을 수 없습니다:$config_file" @@ -11009,12 +11010,12 @@ sync-openclaw-provider-interactive() { return 1 fi - read -erp "请输入要同步的 API 名称(provider),直接回车同步全部: " provider_name + read -erp "동기화할 API 이름(공급자)을 입력하고 Enter를 눌러 모두 동기화하세요." provider_name if [ -z "$provider_name" ]; then if sync_openclaw_api_models; then start_gateway else - echo "❌ API 模型同步失败,已中止重启网关。请检查 provider /models 返回后重试。" + echo "❌ API 모델 동기화에 실패하여 게이트웨이 다시 시작이 중단되었습니다. 공급자/모델을 확인하고 반환 후 다시 시도하십시오." return 1 fi break_end @@ -11041,7 +11042,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未检测到 API providers,无法同步') + print('❌ API 제공업체가 감지되지 않아 동기화할 수 없습니다.') raise SystemExit(2) provider = providers.get(target) @@ -11117,7 +11118,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} 当前 api={api},但脚本已不再探测/纠正协议;请手动设置为 openai-completions 或 openai-responses') + print(f'ℹ️ 공급자 {target}은 현재 api={api}이지만 스크립트는 더 이상 프로토콜을 감지/수정하지 않습니다. openai-completions 또는 openai-responses로 수동으로 설정하세요.') protocol_msg = None @@ -11136,7 +11137,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') + print(f'❌ {target}: 업스트림 /models가 비어 있고 동기화가 중단되었습니다.') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11145,7 +11146,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') + print(f'❌ {target}: 로컬 모델에 유효한 템플릿 모델이 없어 새 모델을 추가할 수 없습니다.') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -11161,7 +11162,7 @@ for mid in added_ids: new_models.append(nm) if not new_models: - print(f'❌ {target}: 同步后无可用模型,已中止写入') + print(f'❌ {target}: 동기화 후 사용할 수 있는 모델이 없어 쓰기가 중단되었습니다.') raise SystemExit(5) expected_refs = {model_ref(target, str(m['id'])) for m in new_models if isinstance(m, dict) and m.get('id')} @@ -11203,7 +11204,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: 新增 {len(added_ids)} 个,删除 {len(removed_ids)} 个,当前 {len(new_models)} 个') +print(f'✅ {target}: {len(add_ids)} 추가, 삭제 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: print(f'➕ 새 모델 추가({len(add_ids)}):') @@ -11215,30 +11216,30 @@ if removed_ids: print(f' - {mid}') if changed: - print('✅ 指定 provider 模型一致性同步完成并已写入配置') + print('✅ 지정된 공급자 모델 일관성 동기화가 완료되고 구성이 작성되었습니다.') else: - print('ℹ️ 无需同步:该 provider 配置已与上游 /models 保持一致') + print('ℹ️ 동기화가 필요하지 않습니다. 공급자 구성이 이미 업스트림/모델과 일치합니다.') PY2 local rc=$? case "$rc" in 0) - echo "✅ 同步执行完成" + echo "✅ 동기 실행 완료" start_gateway ;; 2) - echo "❌ 同步失败:provider 不存在或未配置" + echo "❌ 동기화 실패: 공급자가 존재하지 않거나 구성되지 않았습니다." ;; 3) echo "❌ 동기화 실패: 공급자 구성이 불완전하거나 유형이 지원되지 않습니다." ;; 4) - echo "❌ 同步失败:上游 /models 请求失败" + echo "❌ 동기화 실패: 업스트림 /models 요청 실패" ;; 5) echo "❌ 동기화 실패: 업스트림 모델이 비어 있거나 동기화 후 사용 가능한 모델이 없습니다." ;; *) - echo "❌ 同步失败:请检查配置文件结构或日志输出" + echo "❌ 동기화 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." ;; esac @@ -11246,9 +11247,9 @@ PY2 } openclaw_detect_api_protocol_by_provider() { - # 协议探测逻辑已移除:脚本不再自动探测/判定 API 类型。 + # 프로토콜 감지 논리가 제거되었습니다. 스크립트는 더 이상 API 유형을 자동으로 감지/결정하지 않습니다. # 이 기능은 메뉴 호출과의 호환성을 위해 유지되지만 재작성은 수행되지 않습니다. - echo "ℹ️ 프로토콜 감지가 꺼졌습니다. 수동으로 감지하세요.${HOME}/.openclaw/openclaw.json 中设置 provider.api 为 openai-completions 或 openai-responses" + echo "ℹ️ 프로토콜 감지가 꺼졌습니다. 수동으로 감지하세요.${HOME}/.openclaw/openclaw.json의 공급자.api를 openai-completions 또는 openai-responses로 설정합니다." return 0 } @@ -11450,7 +11451,7 @@ for fk in ('modelFallback', 'imageModelFallback'): print(f'❌ 삭제가 중단되었습니다. {fk}가 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + print(f'🔁 {fk} 스위치: {val} -> {교체}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11463,12 +11464,12 @@ with open(path, 'w', encoding='utf-8') as f: f.write('\n') print(f'🗑️ 삭제된 제공자: {name}') -print(f'🧹 已清理 defaults.models 中 {len(removed_refs)} 个关联模型引用') +print(f'🧹 defaults.models에서 {len(removed_refs)} 관련 모델 참조를 정리했습니다.') PY local rc=$? case "$rc" in 0) - send_stats "OpenClaw API删除确认" + send_stats "OpenClaw API 삭제 확인" echo "✅삭제 완료" start_gateway ;; @@ -11477,10 +11478,10 @@ PY ;; 3) send_stats "OpenClaw API 삭제 취소" - echo "❌ 删除失败:无可用替代模型,已保持原配置" + echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." ;; *) - echo "❌ 删除失败:请检查配置文件结构或日志输出" + echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." ;; esac @@ -11488,12 +11489,12 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장 사항" + send_stats "OpenClaw API 공급업체 권장사항" clear echo "" echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 벤더 추천 목록${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}일부 입구에는 AFF가 포함되어 있습니다.${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" echo "" @@ -11506,13 +11507,13 @@ PY echo -e " ${gl_lv}● Kimi${gl_bai}" echo -e " ${gl_kjlan}https://platform.moonshot.cn/docs/guide/start-using-kimi-api${gl_bai}" echo "" - echo -e " ${gl_lv}● 超算互联网${gl_bai}" + echo -e " ${gl_lv}● 슈퍼컴퓨팅 인터넷${gl_bai}" echo -e " ${gl_kjlan}https://www.scnet.cn/${gl_bai}" echo "" - echo -e " ${gl_huang}● 优云智算${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● Youyun 지능형 컴퓨팅${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://passport.compshare.cn/register?referral_code=4mscFZXfutfFi8swMVsPuf${gl_bai}" echo "" - echo -e " ${gl_huang}● 硅基流动${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 실리콘 기반 흐름${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://cloud.siliconflow.cn/i/irWVdPic${gl_bai}" echo "" echo -e " ${gl_huang}● GLM${gl_bai} ${gl_zi}[AFF]${gl_bai}" @@ -11521,10 +11522,10 @@ PY echo -e " ${gl_huang}● PackyAPI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://www.packyapi.com/register?aff=wHri${gl_bai}" echo "" - echo -e " ${gl_huang}● 云雾 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 클라우드 API${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://yunwu.ai/register?aff=ZuyK${gl_bai}" echo "" - echo -e " ${gl_huang}● 柏拉图AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" + echo -e " ${gl_huang}● 플라톤 AI${gl_bai} ${gl_zi}[AFF]${gl_bai}" echo -e " ${gl_kjlan}https://api.bltcy.ai/register?aff=TBzb114019${gl_bai}" echo "" echo -e " ${gl_lv}● MiniMax${gl_bai}" @@ -11540,9 +11541,9 @@ PY echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" - echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" + echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 추천 입장${gl_bai}" echo "" - echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" + echo -e "${gl_huang}팁: 링크를 복사하고 브라우저에서 열어서 액세스하세요.${gl_bai}" echo "" read -erp "돌아가려면 Enter를 누르세요..." dummy } @@ -11552,7 +11553,7 @@ PY while true; do clear echo "=======================================" - echo "OpenClaw API 管理" + echo "OpenClaw API 관리" echo "=======================================" openclaw_api_manage_list echo "---------------------------------------" @@ -11628,7 +11629,7 @@ REPO change_model() { - send_stats "换模型" + send_stats "모델 변경" local orange="#FF8C00" @@ -11796,7 +11797,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11814,7 +11815,7 @@ PYTHON_EOF second_reply="$reply_preview" reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -11826,7 +11827,7 @@ PYTHON_EOF reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) [ -z "$reply_trimmed" ] && reply_trimmed=$(printf '%s' "$second_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" + [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" OPENCLAW_PROBE_STATUS="FAIL" OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0} / exit ${first_exit:-1};${second_endpoint} -> HTTP ${second_http:-0} / exit ${second_exit:-1}" @@ -11840,22 +11841,22 @@ PYTHON_EOF while true; do local models_raw models_list default_model model_count selected_model confirm_switch - # 从配置文件读取模型键(不调用 openclaw models list) + # 구성 파일에서 모델 키 읽기(openclaw 모델 목록을 호출하지 않고) local oc_config oc_config=$(openclaw_get_config_file) models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" + echo "모델 목록을 가져오지 못했습니다. 구성 파일에서 Agent.defaults.models를 찾을 수 없습니다." break_end return 1 fi - # 为每个模型加编号,便于快速定位(例如:"(10) or-api/...:free") + # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') - # Read default model from configuration file (faster); 실패 시 openclaw 명령으로 대체 + # 구성 파일에서 기본 모델을 읽습니다(더 빠름). 실패 시 openclaw 명령으로 대체 default_model=$(jq -r '.agents.defaults.model.primary // empty' "$oc_config" 2>/dev/null) [ -z "$default_model" ] && default_model="(unknown)" @@ -11873,12 +11874,12 @@ PYTHON_EOF read -e -p "설정할 모델 이름을 입력하세요(예: openrouter/openai/gpt-4o)(종료하려면 0 입력)." selected_model if [ "$selected_model" = "0" ]; then - echo "操作已取消,正在退出..." + echo "작업이 취소되었습니다. 종료하는 중..." break fi if [ -z "$selected_model" ]; then - echo "Error: Model name cannot be empty. 다시 시도해 주세요." + echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." echo "" continue fi @@ -11904,10 +11905,10 @@ PYTHON_EOF gum style --foreground "$orange" "사용 가능한 모델(인증=예):${model_count}" gum style --foreground "$orange" "현재 기본값:${default_model}" echo "" - gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" + gum style --faint "↑↓ 테스트하려면 선택 / Enter / 종료하려면 Esc" echo "" - selected_model=$(echo "$models_list" | gum filter --placeholder "검색 모델(예: cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "검색 모델(예: cli-api/gpt-5.2)" --prompt "모델 선택 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "작업이 취소되었습니다. 종료하는 중..." @@ -11929,7 +11930,7 @@ PYTHON_EOF echo "요약:$OPENCLAW_PROBE_REPLY" echo "" - printf "Switch to this model? [y/N, Esc가 목록으로 돌아갑니다]:" + printf "이 모델로 전환하시겠습니까? [y/N, Esc가 목록으로 돌아갑니다]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12031,7 +12032,7 @@ PYTHON_EOF fi done - [ "$count" -gt 0 ] && echo "✅ 已同步 $count에이전트의 세션 모델은 다음과 같습니다.$model_ref" + [ "$count" -gt 0 ] && echo "✅ 동기화됨$count에이전트의 세션 모델은 다음과 같습니다.$model_ref" return 0 } @@ -12110,7 +12111,7 @@ PYTHON_EOF fi fi - echo "⚠️ 已安装插件,但同步 plugins.allow 失败,请手动检查: $config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -12191,7 +12192,7 @@ PYTHON_EOF echo "========================================" echo "플러그인 관리(설치/제거)" echo "========================================" - echo "当前插件列表:" + echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" @@ -12199,25 +12200,25 @@ PYTHON_EOF echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" echo "- [텔레그램] # 텔레그램 봇" - echo " - [slack] # Slack 企业通讯" + echo "- [slack] #Slack 기업 커뮤니케이션" echo " - [msteams] # Microsoft Teams" - echo " - [discord] # Discord 社区管理" + echo "- [디스코드] # 디스코드 커뮤니티 관리" echo "- [whatsapp] #WhatsApp 자동화" echo "" - echo "🧠 记忆与 AI:" - echo " - [memory-core] # 基础记忆 (文件检索)" + echo "🧠 메모리와 AI:" + echo "- [memory-core] # 기본 메모리(파일 검색)" echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" echo "- [copilot-proxy] # Copilot 인터페이스 전달" echo "" - echo "⚙️ 功能扩展:" + echo "⚙️ 기능 확장:" echo "- [랍스터] # 승인 흐름(수동 확인 포함)" echo "- [음성통화] # 음성통화 기능" - echo " - [nostr] # 加密隐私聊天" + echo "- [nostr] # 암호화된 비공개 채팅" echo "--------------------------------------------------------" - echo "1) 安装/启用插件" + echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 返回" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12258,7 +12259,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 发现系统内置目录存在该插件,尝试直接启用..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12282,14 +12283,14 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 安装失败:$plugin_full" + echo "❌ 설치 실패:$plugin_full" failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在删除/禁用插件: $plugin_id" + echo "🗑️ 플러그인 제거/비활성화:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then - echo "✅ 已卸载: $plugin_id" + echo "✅ 제거됨:$plugin_id" else echo "⚠️ 제거에 실패했습니다. 사전 설치된 플러그인일 수 있습니다. 다음만 비활성화하세요.$plugin_id" fi @@ -12327,8 +12328,8 @@ PYTHON_EOF # 추천 실기 목록 출력 echo "추천 실기 (이름을 직접 복사해서 입력하셔도 됩니다):" - echo "github # 管理 GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 页面、数据库和块" + echo "github # GitHub 문제/PR/CI 관리(gh CLI)" + echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" echo "1password # 1Password 키 읽기 및 삽입 자동화" @@ -12343,9 +12344,9 @@ PYTHON_EOF echo "코딩 에이전트 # Claude Code/Codex와 같은 프로그래밍 도우미를 자동으로 실행합니다." echo "----------------------------------------" - echo "1) 安装技能" + echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 返回" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12362,7 +12363,7 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. 계속하시겠습니까? (예/아니요):" confirm_del + read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. Are you sure to continue? (예/아니요):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then echo "삭제가 취소되었습니다." break_end @@ -12395,7 +12396,7 @@ PYTHON_EOF echo "기술 설치:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then - echo "✅ 技能 $skill_name설치가 성공했습니다." + echo "✅ 스킬$skill_name설치가 성공했습니다." success_list="$success_list $skill_name" changed=true else @@ -12481,7 +12482,7 @@ openclaw_json_get_bool() { # 두 가지 일반적인 디렉터리 이름과 호환됩니다. # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot - # 避免无脑 substring,优先精确匹配与 openclaw- 前缀匹配。 + # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. [ -d "${HOME}/.openclaw/extensions/${plugin}" ] \ || [ -d "${HOME}/.openclaw/extensions/openclaw-${plugin}" ] \ || [ -d "/usr/lib/node_modules/openclaw/extensions/${plugin}" ] \ @@ -12689,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12919,7 +12920,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end } @@ -13397,7 +13398,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." + echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -13670,7 +13671,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." return 0 } @@ -13782,7 +13783,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -14108,7 +14109,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14309,7 +14310,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14801,7 +14802,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15545,7 +15546,7 @@ openclaw_backup_restore_menu() { openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "상태 감지 및 수리" openclaw doctor --fix break_end ;; @@ -15605,7 +15606,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15617,7 +15618,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15876,7 +15877,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -15896,7 +15897,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15976,7 +15977,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16008,7 +16009,7 @@ while true; do 1) setup_docker_dir check_disk_space 2 /home/docker - read -e -p "이메일 도메인 이름을 설정하십시오(예: mail.yuming.com):" yuming + read -e -p "이메일 도메인 이름을 설정하세요(예: mail.yuming.com):" yuming mkdir -p /home/docker echo "$yuming" > /home/docker/mail.txt echo "------------------------" @@ -16576,7 +16577,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -17247,7 +17248,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -18944,7 +18945,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19917,7 +19918,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "3) 최대 로그 크기를 500M로 제한합니다." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -20142,7 +20143,7 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" @@ -20155,7 +20156,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20627,7 +20628,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20950,7 +20951,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21394,7 +21395,7 @@ linux_file() { continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하십시오." dest_path if [ -z "$dest_path" ]; then echo "오류: 대상 경로를 입력하십시오." send_stats "파일 또는 디렉터리 이동 실패: 대상 경로가 지정되지 않았습니다." @@ -21414,7 +21415,7 @@ linux_file() { continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하십시오." dest_path if [ -z "$dest_path" ]; then echo "오류: 대상 경로를 입력하십시오." send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." @@ -21500,7 +21501,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 탐색하고 명령을 실행합니다. + # 서버를 순회하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -21508,7 +21509,7 @@ run_commands_on_servers() { local username=${SERVER_ARRAY[i+3]} local password=${SERVER_ARRAY[i+4]} echo - echo -e "${gl_huang}연결하다$name ($hostname)...${gl_bai}" + echo -e "${gl_huang}연결 대상$name ($hostname)...${gl_bai}" # sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" sshpass -p "$password" ssh -t -o StrictHostKeyChecking=no "$username@$hostname" -p "$port" "$1" done @@ -21542,7 +21543,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21583,7 +21584,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21656,7 +21657,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21690,7 +21691,7 @@ games_server_tools() { echo -e "게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Eudemons Parlu 서버 오픈 스크립트" - echo -e "${gl_kjlan}2. ${gl_bai}Minecraft 서버 열기 스크립트" + echo -e "${gl_kjlan}2. ${gl_bai}Minecraft 서버 오프닝 스크립트" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21702,7 +21703,7 @@ games_server_tools() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; - 2) send_stats "Minecraft 서버 열기 스크립트" ; cd ~ + 2) send_stats "Minecraft 서버 오프닝 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh exit ;; @@ -21945,7 +21946,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -21974,12 +21975,12 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 3e6052154..a31b12362 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.1" +sh_v="4.5.2" gl_hui='\e[37m' @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 收集功能埋藏資訊的函數,記錄當前腳本版本號,使用時間,系統版本,CPU架構,機器所在國家和用戶使用的功能名稱,絕對不涉及任何敏感信息,請放心!請相信我! # 為什麼要設計這個功能,目的更好的了解使用者喜歡使用的功能,進一步優化功能推出更多符合使用者需求的功能。 -# 全文可搜搜 send_stats 函数调用位置,透明开源,如有顾虑可拒绝使用。 +# 全文可搜尋 send_stats 函數呼叫位置,透明開源,如有顧慮可拒絕使用。 @@ -131,7 +131,7 @@ UserLicenseAgreement() { if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then - send_stats "许可同意" + send_stats "許可同意" sed -i 's/^permission_granted="false"/permission_granted="true"/' ~/kejilion.sh sed -i 's/^permission_granted="false"/permission_granted="true"/' /usr/local/bin/k else @@ -304,7 +304,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1服務已重啟。" else - echo "錯誤:重啟$1服務失敗。" + echo "錯誤:重啟$1 服务失败。" fi } @@ -507,8 +507,8 @@ while true; do $dockername ;; 2) - send_stats "启动指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + send_stats "啟動指定容器" + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker start $dockername ;; 3) @@ -522,7 +522,7 @@ while true; do docker rm -f $dockername ;; 5) - send_stats "重啟指定容器" + send_stats "重启指定容器" read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker restart $dockername ;; @@ -599,7 +599,7 @@ while true; do ;; 16) - send_stats "阻止容器連接埠訪問" + send_stats "阻止容器端口访问" read -e -p "請輸入容器名稱:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" @@ -625,7 +625,7 @@ while true; do echo "" echo "鏡像操作" echo "------------------------" - echo "1. 取得指定鏡像 3. 刪除指定鏡像" + echo "1. 获取指定镜像 3. 删除指定镜像" echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}設定檔不存在${gl_bai}" + echo -e "${gl_hong}配置文件不存在${gl_bai}" return fi @@ -917,7 +917,7 @@ close_port() { allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "請提供至少一個IP位址或IP段" + echo "请提供至少一个IP地址或IP段" return 1 fi @@ -1095,10 +1095,10 @@ iptables_panel() { echo "" echo "防火牆管理" echo "------------------------" - echo "1. 开放指定端口 2. 关闭指定端口" + echo "1. 開放指定連接埠 2. 關閉指定連接埠" echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" - echo "5. IP白名單 6. IP黑名單" + echo "5. IP白名单 6. IP黑名单" echo "7. 清除指定IP" echo "------------------------" echo "11. 允許PING 12. 禁止PING" @@ -1200,7 +1200,7 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code + read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; @@ -1258,7 +1258,7 @@ add_swap() { rc-update add local fi - echo -e "虛擬記憶體大小已調整為${gl_huang}${new_swap}${gl_bai}M" + echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" } @@ -1481,7 +1481,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1540,11 +1540,11 @@ certs_status() { send_stats "網域證書申請成功" else send_stats "網域證書申請失敗" - echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + echo -e "${gl_hong}注意:${gl_bai}证书申请失败,请检查以下可能原因并重试:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" - echo -e "4. 防火墙限制 ➠ 检查80/443端口是否开放,确保验证可访问" + echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" echo -e "6. 國內備案限制 ➠ 中國大陸環境請確認網域是否備案" echo "------------------------" @@ -1617,7 +1617,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "網域重複使用" + send_stats "域名重复使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1626,7 +1626,7 @@ fi add_yuming() { ip_address - echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" + echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "請輸入你的IP或解析過的網域名稱:" yuming } @@ -1750,7 +1750,7 @@ cf_purge_cache() { # 提示使用者是否清理快取 read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" + echo "CF資訊保存在$CONFIG_FILE,可以后期修改CF信息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN read -e -p "請輸入你的CF用戶名:" EMAIL read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS @@ -1760,7 +1760,7 @@ cf_purge_cache() { fi fi - # 循環遍歷每個 zone_id 並執行清除快取命令 + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do echo "正在清除快取 for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ @@ -2115,7 +2115,7 @@ web_security() { check_waf_status check_cf_mode clear - echo -e "伺服器網站防禦程序${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" @@ -2126,10 +2126,10 @@ web_security() { echo "------------------------" echo "21. cloudflare模式 22. 高負載開啟5秒盾" echo "------------------------" - echo "31. 開啟WAF 32. 關閉WAF" + echo "31. 开启WAF 32. 关闭WAF" echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" echo "------------------------" - echo "9. 卸載防禦程序" + echo "9. 卸载防御程序" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -2215,10 +2215,10 @@ web_security() { 21) send_stats "cloudflare模式" - echo "到cf后台右上角我的个人资料,选择左侧API令牌,获取Global API Key" + echo "到cf後台右上角我的個人資料,選擇左側API令牌,取得Global API Key" echo "https://dash.cloudflare.com/login" read -e -p "輸入CF的帳號:" cfuser - read -e -p "输入CF的Global API Key: " cftoken + read -e -p "輸入CF的Global API Key:" cftoken wget -O /home/web/conf.d/default.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf docker exec nginx nginx -s reload @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" ;; 22) @@ -2242,7 +2242,7 @@ web_security() { echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}區域ID${gl_bai}" + echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "輸入CF的帳號:" cfuser @@ -2279,7 +2279,7 @@ web_security() { 32) nginx_waf off - echo "站點WAF已關閉" + echo "站点WAF已关闭" send_stats "站點WAF已關閉" ;; @@ -2306,7 +2306,7 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # 檢查 MySQL 設定檔中是否包含 4096M + # 检查 MySQL 配置文件中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="高性能模式" else @@ -2331,12 +2331,12 @@ check_nginx_compression() { # 檢查 brotli 是否開啟且未被註釋 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status="br壓縮已開啟" + br_status=" br压缩已开启" else br_status="" fi - # 檢查 gzip 是否開啟且未被註釋 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "優化LDNMP環境" echo -e "優化LDNMP環境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 標準模式 2. 高效能模式 (建議2H4G以上)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" echo "5. 開啟br壓縮 6. 關閉br壓縮" @@ -2708,7 +2708,7 @@ clear_container_rules() { fi - echo "已允许IP+端口访问该服务" + echo "已允許IP+連接埠存取該服務" save_iptables_rules } @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 清除封禁所有其他 IP 访问的规则 + # 清除封鎖所有其他 IP 存取的規則 if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2882,7 +2882,7 @@ while true; do echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 新增網域存取 6. 刪除網域存取" + echo "5. 添加域名访问 6. 删除域名访问" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" @@ -2893,12 +2893,12 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}端口: " app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" - send_stats "應用程式連接埠已被佔用" + send_stats "应用端口已被占用" else local docker_port=$app_port break @@ -3071,7 +3071,8 @@ docker_app_plus() { ;; 8) send_stats "阻止IP訪問${docker_name}" - block_container_port "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + block_container_port "$docker_check_name" "$ipv4_address" ;; *) break @@ -3160,7 +3161,7 @@ session_exists() { tmux has-session -t $1 2>/dev/null } -# 循环直到找到一个不存在的会话名称 +# 循環直到找到一個不存在的會話名稱 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done @@ -3243,7 +3244,7 @@ f2b_basic_config() { fi echo "即將配置 SSH jail:$jail_name" - read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry @@ -3276,7 +3277,7 @@ EOF fail2ban-client status $jail_name || true } -# 直接打开主配置/覆盖配置编辑(nano) +# 直接開啟主配置/覆蓋配置編輯(nano) # 優先編輯 /etc/fail2ban/jail.d/sshd.local(更安全),若不存在則創建 f2b_edit_config() { root_use @@ -3553,7 +3554,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-負載平衡" + webname="反向代理-负载均衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3706,7 +3707,7 @@ stream_panel() { install nano nano /home/web/stream.d/$stream_name.conf docker restart nginx - send_stats "修改四层代理" + send_stats "修改四層代理" ;; 6) send_stats "刪除轉送配置" @@ -3754,7 +3755,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無效選擇"; return 1 ;; esac - read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port + read -e -p "請輸入你的一個或多個後端IP+埠以空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3869,7 +3870,7 @@ ldnmp_web_status() { echo "------------------------" echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" - echo "5. 查看訪問日誌 6. 查看錯誤日誌" + echo "5. 查看访问日志 6. 查看错误日志" echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" @@ -3892,7 +3893,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3931,9 +3932,9 @@ ldnmp_web_status() { ;; 4) send_stats "建立關聯站點" - echo -e "為現有的站點再關聯一個新網域用於訪問" + echo -e "为现有的站点再关联一个新域名用于访问" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -4128,7 +4129,7 @@ EOF configure_frpc() { - send_stats "安装frp客户端" + send_stats "安裝frp客戶端" read -e -p "請輸入外網對接IP:" server_addr read -e -p "請輸入外網對接token:" token echo @@ -4151,7 +4152,7 @@ EOF add_forwarding_service() { send_stats "新增frp內網服務" - # 提示使用者輸入服務名稱和轉發訊息 + # 提示用户输入服务名称和转发信息 read -e -p "請輸入服務名稱:" service_name read -e -p "請輸入轉送類型 (tcp/udp) [回​​車預設tcp]:" service_type local service_type=${service_type:-tcp} @@ -4187,7 +4188,7 @@ delete_forwarding_service() { read -e -p "請輸入需要刪除的服務名稱:" service_name # 使用 sed 刪除該服務及其相關配置 sed -i "/\[$service_name\]/,/^$/d" /home/frp/frpc.toml - echo "服務$service_name 已成功从 frpc.toml 删除" + echo "服務$service_name已成功從 frpc.toml 刪除" docker restart frpc @@ -4198,7 +4199,7 @@ list_forwarding_services() { local config_file="$1" # 列印表頭 - printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" + printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外网地址" "協定" awk ' BEGIN { @@ -4260,7 +4261,7 @@ list_forwarding_services() { } END { - # 打印最后一个服务的信息 + # 列印最後一個服務的訊息 if (current_service != "" && current_service != "common" && local_ip != "" && local_port != "") { printf "%-16s %-21s %-26s %-10s\n", \ current_service, \ @@ -4303,7 +4304,7 @@ generate_access_urls() { fi done - # 處理 IPv6 位址(如果存在) + # 处理 IPv6 地址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4417,7 +4418,7 @@ frps_panel() { 8) send_stats "阻止IP訪問" - echo "如果你已经反代域名访问了,可用此功能阻止IP+端口访问,这样更安全。" + echo "如果你已經反代域名訪問了,可用此功能阻止IP+端口訪問,這樣更安全。" read -e -p "請輸入需要阻止的連接埠:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4458,7 +4459,7 @@ frpc_panel() { echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "4. 新增對外服務 5. 刪除對外服務 6. 手動設定服務" + echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4590,12 +4591,12 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下載完成,按任何鍵繼續..." ;; + read -e -p "下载完成,按任意键继续..." ;; 6) - send_stats "批量视频下载" + send_stats "大量影片下載" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 输入多个视频链接地址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 輸入多個視訊連結位址\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE echo "現在開始批量下載..." @@ -4609,7 +4610,7 @@ yt_menu_pro() { read -e -p "批次下載完成,按任何鍵繼續..." ;; 7) send_stats "自訂影片下載" - read -e -p "请输入完整 yt-dlp 参数(不含 yt-dlp): " custom + read -e -p "請輸入完整 yt-dlp 參數(不含 yt-dlp):" custom yt-dlp -P "$VIDEO_DIR" $custom \ --write-subs --sub-langs all \ --write-thumbnail --embed-thumbnail \ @@ -4787,7 +4788,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5014,19 +5015,19 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - read -e -p "請輸入您的遠端公鑰URL:" keys_url + read -e -p "请输入您的远端公钥URL: " keys_url fi - echo "此腳本將從遠端 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" + echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" echo "" - echo "遠端公鑰地址:" + echo "远程公钥地址:" echo " ${keys_url}" echo "" # 建立臨時文件 temp_file=$(mktemp) - # 下載公鑰 + # 下载公钥 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 @@ -5040,7 +5041,7 @@ fetch_remote_ssh_keys() { return 1 } else - echo "错误:系统中未找到 curl 或 wget,无法下载公钥" >&2 + echo "錯誤:系統中未找到 curl 或 wget,無法下載公鑰" >&2 rm -f "${temp_file}" return 1 fi @@ -5099,7 +5100,7 @@ fetch_github_ssh_keys() { echo "1. 登入${gh_https_url}github.com/settings/keys" echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" - echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" echo "5. 點選 Add SSH key 完成新增" echo "" echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" @@ -5108,7 +5109,7 @@ fetch_github_ssh_keys() { if [[ -z "${username}" ]]; then - read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username + read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username fi if [[ -z "${username}" ]]; then @@ -5211,7 +5212,7 @@ add_sshpasswd() { # 如果沒有透過參數傳入,則交互輸入 if [[ -z "$target_user" ]]; then - read -e -p "請輸入要修改密碼的使用者名稱(預設 root):" target_user + read -e -p "请输入要修改密码的用户名(默认 root): " target_user fi # 回車不輸入,預設 root @@ -5616,9 +5617,9 @@ bbrv3() { os_codename="releases" fi - # 官方已徹底移除對 jammy, focal, bullseye 等舊系統的 apt 支持 + # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then - echo -e "${gl_hong}XanMod 官方已停止对当前系统($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" + echo -e "${gl_hong}XanMod 官方已停止對目前系統($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" return 1 fi @@ -5630,7 +5631,7 @@ bbrv3() { install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then - echo "官方金鑰下載失敗,嘗試備用下載來源..." + echo "官方密钥下载失败,尝试备用下载源..." wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" @@ -5753,7 +5754,7 @@ bbrv3() { linux_Settings fi else - echo "無法確定作業系統類型" + echo "无法确定操作系统类型" break_end linux_Settings fi @@ -5768,7 +5769,7 @@ bbrv3() { echo "" echo "核心管理" echo "------------------------" - echo "1. 更新BBRv3内核 2. 卸载BBRv3内核" + echo "1. 更新BBRv3內核 2. 卸載BBRv3內核" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -5836,7 +5837,7 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安裝 ELRepo 倉庫設定 (版本 10)..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else echo "不支援的系統版本:$os_version" @@ -5847,7 +5848,7 @@ elrepo_install() { echo "啟用 ELRepo 核心倉庫並安裝最新的主線核心..." # yum -y --enablerepo=elrepo-kernel install kernel-ml yum --nogpgcheck -y --enablerepo=elrepo-kernel install kernel-ml - echo "已安装 ELRepo 仓库配置并更新到最新主线内核。" + echo "已安裝 ELRepo 倉庫配置並更新至最新主線核心。" server_reboot } @@ -5860,7 +5861,7 @@ elrepo() { while true; do clear kernel_version=$(uname -r) - echo "您已安装elrepo内核" + echo "您已安裝elrepo內核" echo "當前核心版本:$kernel_version" echo "" @@ -5959,7 +5960,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 執行 Docker 命令 + # 执行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -6015,7 +6016,7 @@ clamav() { ;; 3) send_stats "自訂目錄掃描" - read -e -p "请输入要扫描的目录,用空格分隔(例如:/etc /var /usr /home /root): " directories + read -e -p "請輸入要掃描的目錄,用空格分隔(例如:/etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6032,7 +6033,7 @@ clamav() { # ============================================================================ # Linux 核心調優模組(重構版) -# 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 +# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 # 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ @@ -6060,7 +6061,7 @@ _kernel_optimize_core() { case "$scene" in high|stream|game) - # 高性能/直播/游戏:激进参数 + # 高效能/直播/遊戲:激進參數 SWAPPINESS=10 DIRTY_RATIO=15 DIRTY_BG_RATIO=5 @@ -6106,7 +6107,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; balanced) - # 均衡模式:適度優化 + # 均衡模式:适度优化 SWAPPINESS=30 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6301,7 +6302,7 @@ SYSCTL done < "$CONF" echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" - # ── 透明大頁面 ── + # ── 透明大页面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi @@ -6321,12 +6322,12 @@ LIMITS # ── BBR 持久化 ── if [ "$CC" = "bbr" ]; then echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null - # 清理旧的 sysctl.conf 里的 bbr 配置(避免冲突) + # 清理舊的 sysctl.conf 裡的 bbr 設定(避免衝突) sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null fi echo -e "${gl_lv}${mode_name}優化完成!配置已持久化到${CONF}${gl_bai}" - echo -e "${gl_lv}記憶體:${MEM_MB}MB | 拥塞算法: ${CC}| 隊列:${QDISC}${gl_bai}" + echo -e "${gl_lv}記憶體:${MEM_MB}MB | 壅塞演算法:${CC}| 隊列:${QDISC}${gl_bai}" } # ── 各模式入口函數(保持原有呼叫介面不變) ── @@ -6349,7 +6350,7 @@ restore_defaults() { local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 刪除最佳化設定檔(含外鏈自動調優配置) + # 删除优化配置文件(含外链自动调优配置) rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf @@ -6359,7 +6360,7 @@ restore_defaults() { # 重新加载系统默认配置 sysctl --system 2>/dev/null | tail -1 - # 还原透明大页面 + # 還原透明大頁面 [ -f /sys/kernel/mm/transparent_hugepage/enabled ] && \ echo always > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null @@ -6371,7 +6372,7 @@ restore_defaults() { # 清理 BBR 持久化 rm -f /etc/modules-load.d/bbr.conf 2>/dev/null - echo -e "${gl_lv}系統已還原到預設設定${gl_bai}" + echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" } @@ -6382,7 +6383,7 @@ Kernel_optimize() { send_stats "Linux核心調優管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" - echo "Linux系统内核参数优化" + echo "Linux系統核心參數優化" if [ -n "$current_mode" ]; then echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" else @@ -6390,15 +6391,15 @@ Kernel_optimize() { fi echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" + echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo -e "--------------------" echo -e "1. 高效能最佳化模式: 最大化系統效能,激進的記憶體和網路參數。" echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" - echo -e "3. 網站最佳化模式: 針對網站伺服器最佳化,超高並發連線佇列。" + echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" - echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" + echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" @@ -6551,7 +6552,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" +echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" hash -r break_end @@ -6562,7 +6563,7 @@ break_end shell_bianse() { root_use - send_stats "命令行美化工具" + send_stats "命令列美化工具" while true; do clear echo "命令列美化工具" @@ -6655,7 +6656,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "回收站已启用,删除的文件将移至回收站。" + echo "回收站已啟用,刪除的檔案將移至回收站。" sleep 2 ;; 2) @@ -6714,7 +6715,7 @@ create_backup() { "/home" # 用户数据 ) else - # 將使用者輸入的目錄以空格分隔成數組 + # 将用户输入的目录按空格分隔成数组 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi @@ -6945,7 +6946,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "請貼上金鑰內容 (貼上完成後按兩次回車):" + echo "请粘贴密钥内容 (粘贴完成后按两次回车):" while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -7009,14 +7010,14 @@ list_connections() { add_connection() { send_stats "新增連接" echo "建立新連接範例:" - echo " - 连接名称: my_server" + echo "- 連線名稱: my_server" echo "- IP位址: 192.168.1.100" echo "- 使用者名稱: root" echo "- 連接埠: 22" echo "------------------------" read -e -p "請輸入連線名稱:" name - kj_ssh_read_host_user_port "請輸入IP位址:" "請輸入使用者名稱 (預設: root):" "請輸入連接埠號碼 (預設: 22):" "root" "22" + kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "請輸入連接埠號碼 (預設: 22):" "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi @@ -7064,12 +7065,12 @@ use_connection() { echo "正在連接到$name ($ip)..." if [[ -f "$password_or_key" ]]; then - # 使用密钥连接 + # 使用密鑰連接 ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" - echo "1. 密鑰檔案路徑是否正確:$password_or_key" - echo "2. 密鑰檔案權限是否正確(應為 600)。" + echo "1. 密钥文件路径是否正确:$password_or_key" + echo "2. 密钥文件权限是否正确(应为 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else @@ -7111,7 +7112,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以透過SSH連接到其他Linux系統上" + echo "可以通过SSH连接到其他Linux系统上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -7193,7 +7194,7 @@ mount_partition() { echo "分區已成功掛載到$MOUNT_POINT" - # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 + # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then echo "/etc/fstab 中已存在該分區記錄,跳過寫入" return 0 @@ -7248,7 +7249,7 @@ format_partition() { # 檢查分割區是否已經掛載 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分割區已經掛載,請先卸載!" + echo "分区已经挂载,请先卸载!" return fi @@ -7280,7 +7281,7 @@ format_partition() { mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分割區格式化成功!" + echo "分区格式化成功!" else echo "分割區格式化失敗!" fi @@ -7344,14 +7345,14 @@ list_tasks() { # 新增任務 add_task() { send_stats "新增同步任務" - echo "建立新同步任務範例:" + echo "创建新同步任务示例:" echo "- 任務名稱: backup_www" echo "- 本機目錄: /var/www" echo "- 遠端位址: user@192.168.1.100" echo "- 遠端目錄: /backup/www" echo "- 連接埠號碼 (預設 22)" echo "---------------------------------" - read -e -p "請輸入任務名稱:" name + read -e -p "请输入任务名称: " name read -e -p "請輸入本地目錄:" local_path read -e -p "請輸入遠端目錄:" remote_path @@ -7437,7 +7438,7 @@ run_task() { local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "錯誤: 未找到該任務!" + echo "错误: 未找到该任务!" return fi @@ -7485,7 +7486,7 @@ run_task() { echo "同步完成!" else echo "同步失敗! 請檢查以下內容:" - echo "1. 网络连接是否正常" + echo "1. 網路連線是否正常" echo "2. 遠端主機是否可存取" echo "3. 認證資訊是否正確" echo "4. 本機和遠端目錄是否有正確的存取權限" @@ -7562,14 +7563,14 @@ rsync_manager() { while true; do clear echo "Rsync 遠端同步工具" - echo "远程目录之间同步,支持增量同步,高效稳定。" + echo "遠端目錄之間同步,支援增量同步,高效穩定。" echo "---------------------------------" list_tasks echo view_tasks echo echo "1. 建立新任務 2. 刪除任務" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" @@ -7729,7 +7730,7 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未識別的套件管理器" + echo "❌ 未识别的包管理器" exit 1 fi @@ -7744,7 +7745,7 @@ linux_tools() { left=$(printf "❌ %-12s 未安裝" "${tools[i]}") fi - # 右列(防止数组越界) + # 右列(防止數組越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then right=$(printf "✅ %-12s 已安裝" "${tools[i+1]}") @@ -7758,11 +7759,11 @@ linux_tools() { done echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 视频编码直播推流工具" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}btop 現代化監控工具${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 檔案管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 磁碟佔用檢視工具${gl_kjlan}14. ${gl_bai}fzf 全域搜尋工具" @@ -7876,7 +7877,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安裝ranger" + send_stats "安装ranger" ;; 13) clear @@ -7999,7 +8000,7 @@ linux_tools() { clear read -e -p "請輸入已安裝的工具名稱(wget curl sudo htop):" installname install $installname - send_stats "安裝指定軟體" + send_stats "安装指定软件" ;; 42) clear @@ -8038,7 +8039,7 @@ linux_bbr() { echo "" echo "BBR管理" echo "------------------------" - echo "1. 開啟BBRv3 2. 關閉BBRv3(會重新啟動)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -8097,7 +8098,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "請輸入要備份的容器名稱(多個空格分隔,回車備份全部運行中容器):" containers + read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -8152,7 +8153,7 @@ docker_ssh_migration() { PACKED_COMPOSE_PATHS["$project_dir"]=1 echo -e "${gl_lv}Compose 項目 [$project_name] 已打包:${project_dir}${gl_bai}" else - echo -e "${gl_hong}未找到 docker-compose.yml,跳過此容器...${gl_bai}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" fi else # 普通容器備份卷 @@ -8191,11 +8192,11 @@ docker_ssh_migration() { if [ -d "/home/docker" ]; then echo -e "${gl_kjlan}備份 /home/docker 下的檔案...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的檔案已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" - echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}備份完成:${BACKUP_DIR}${gl_bai}" echo -e "${gl_lv}可用還原腳本:${RESTORE_SCRIPT}${gl_bai}" @@ -8304,7 +8305,7 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8369,7 +8370,7 @@ docker_ssh_migration() { echo -e "" echo "------------------------" echo -e "1. 備份docker項目" - echo -e "2. 迁移docker项目" + echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" echo -e "4. 刪除docker專案的備份文件" echo "------------------------" @@ -8516,7 +8517,7 @@ linux_docker() { 2) send_stats "加入網路" read -e -p "加入網路名稱:" dockernetwork - read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername @@ -8525,7 +8526,7 @@ linux_docker() { 3) send_stats "加入網路" read -e -p "退出網路名稱:" dockernetwork - read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames + read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8689,7 +8690,7 @@ linux_test() { while true; do clear # send_stats "測試腳本集合" - echo -e "測試腳本合集" + echo -e "测试脚本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP及解鎖狀態偵測" echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" @@ -8699,7 +8700,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}網路線路測速" - echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三网回程延迟路由测试" + echo -e "${gl_kjlan}11. ${gl_bai}besttrace 三網回程延遲路由測試" echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace 三網回程線路測試" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed 三網測速" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace 快速回程測試腳本" @@ -8710,7 +8711,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}硬體效能測試" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 效能測試" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU效能測試腳本" echo -e "${gl_kjlan}------------------------" @@ -8833,7 +8834,7 @@ linux_test() { curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪測評" + send_stats "spiritysdx融合怪测评" clear curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -8919,7 +8920,7 @@ linux_Oracle() { -e MEM_UTIL="$mem_util" \ -e SPEEDTEST_INTERVAL="$speedtest_interval" \ fogforest/lookbusy - send_stats "甲骨文云安装活跃脚本" + send_stats "甲骨文雲安裝活躍腳本" ;; [Nn]) @@ -9079,7 +9080,7 @@ linux_ldnmp() { echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" - echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" + echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自定义动态站点" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" @@ -9288,7 +9289,7 @@ linux_ldnmp() { echo "密碼: admin" echo "------------------------" echo "登入時右上角如果出現紅色error0請使用下列指令:" - echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9489,7 +9490,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}3/6${gl_bai}] 請選擇PHP版本" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 :" pho_v + read -e -p "1. php最新版 | 2. php7.4 : " pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -9535,7 +9536,7 @@ linux_ldnmp() { echo ;; 2) - echo "資料庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" + echo "資料庫備份必須是.gz結尾的壓縮包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ @@ -9788,7 +9789,7 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP環境備份" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_kjlan}正在備份$backup_filename ...${gl_bai}" @@ -9827,7 +9828,7 @@ linux_ldnmp() { 33) clear send_stats "定時遠端備份" - read -e -p "输入远程服务器IP: " useip + read -e -p "輸入遠端伺服器IP:" useip read -e -p "輸入遠端伺服器密碼:" usepasswd cd ~ @@ -9849,7 +9850,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "選擇每天備份的時間(小時,0-23):" hour + read -e -p "选择每天备份的时间(小时,0-23): " hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -10428,7 +10429,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API刪失敗Provider-確認') - summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') + summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') else: send_stat('OpenClaw API刪失敗Provider-拒絕') summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') @@ -10756,7 +10757,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 默认模型不能为空" + echo "❌ 預設模型不能為空" return 1 fi @@ -10777,7 +10778,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10864,7 +10865,7 @@ EOF else add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" add_result=$? - finish_msg="✅ 完成!已保留 provider,並僅載入預設模型:$default_model" + finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" fi if [[ $add_result -eq 0 ]]; then @@ -11235,7 +11236,7 @@ PY2 echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失敗:上游模型為空或同步後無可用模型" + echo "❌ 同步失败:上游模型为空或同步后无可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -11247,7 +11248,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 - # 保留函數以相容選單調用,但不做任何改寫。 + # 保留函数以兼容菜单调用,但不做任何改写。 echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -11340,7 +11341,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API刪除入口" + send_stats "OpenClaw API删除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11450,7 +11451,7 @@ for fk in ('modelFallback', 'imageModelFallback'): print(f'❌ 刪除中止:{fk} 指向該 provider,且無可用替代模型') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 切換: {val} -> {replacement}') + print(f'🔁 {fk} 切换: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11870,7 +11871,7 @@ PYTHON_EOF echo "目前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" selected_model + read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." @@ -11904,10 +11905,10 @@ PYTHON_EOF gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "目前預設:${default_model}" echo "" - gum style --faint "↑↓ 選擇 / Enter 測試 / Esc 退出" + gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" echo "" - selected_model=$(echo "$models_list" | gum filter --placeholder "搜尋模型(如 cli-api/gpt-5.2)" --prompt "選擇模型 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜尋模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -12189,7 +12190,7 @@ PYTHON_EOF while true; do clear echo "========================================" - echo "外掛程式管理 (安裝/刪除)" + echo " 插件管理 (安装/删除) " echo "========================================" echo "當前插件列表:" openclaw plugins list @@ -12306,7 +12307,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重啟 OpenClaw 服務以載入變更..." + echo "🔄 正在重启 OpenClaw 服务以加载变更..." start_gateway fi break_end @@ -12319,7 +12320,7 @@ PYTHON_EOF while true; do clear echo "========================================" - echo " 技能管理 (安装/删除) " + echo "技能管理 (安裝/刪除)" echo "========================================" echo "目前已安裝技能:" openclaw skills list @@ -12664,7 +12665,7 @@ openclaw_json_get_bool() { echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" - echo "1. Telegram 機器人對接" + echo "1. Telegram 机器人对接" echo "2. 飛書 (Lark) 機器人對接" echo "3. WhatsApp 機器人對接" echo "4. QQ 機器人對接" @@ -12689,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12806,7 +12807,7 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "可使用以下方式下載備份檔:" + echo "可使用以下方式下载备份文件:" echo "- 本地路徑:$file_path" echo "- scp 範例: scp root@你的伺服器:$file_path ./" echo "- 或使用 SFTP 用戶端下載" @@ -12935,7 +12936,7 @@ if os.path.isdir(agents_root): return 1 fi - echo "備份模式:" + echo "备份模式:" echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多狀態,敏感風險較高)" read -e -p "請選擇備份模式(預設 1):" export_mode @@ -13581,7 +13582,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可達(疑似國內/受限網路)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可达(疑似国内/受限网络)") fi if [ "$qmd_ok" = "true" ]; then @@ -13714,11 +13715,11 @@ PY echo "⚠️ qmd 指令存在但模組損壞,重新安裝..." fi fi - echo "⬇️ 透過 npm 安裝 qmd: @tobilu/qmd" + echo "⬇️ 通过 npm 安装 qmd: @tobilu/qmd" npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) if [ -z "$qmd_path" ]; then - echo "❌ qmd 安裝失敗" + echo "❌ qmd 安装失败" return 1 fi if ! qmd --version >/dev/null 2>&1; then @@ -13772,7 +13773,7 @@ PY echo "即將執行自動部署(詳細模式)" echo "目標方案:$scheme_label" echo "地區: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "鏡像來源探測: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "下載來源: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then echo "預計下載路徑:$OPENCLAW_MEMORY_EXPECT_PATH" @@ -13833,7 +13834,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正確" + echo "✅ memory.qmd.command 已正确" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -13897,7 +13898,7 @@ EOF OPENCLAW_MEMORY_MODEL_PATH="$model_dest" fi openclaw_memory_config_set "agents.defaults.memorySearch.local.modelPath" "$model_dest" - echo "✅ 已写入模型路径" + echo "✅ 已寫入模型路徑" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -14057,7 +14058,7 @@ EOF echo "=======================================" echo "索引修復診斷" echo "=======================================" - echo "目前 includeDefaultMemory: ${include_dm:-未設定}" + echo "当前 includeDefaultMemory: ${include_dm:-未设置}" echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ 偵測到 includeDefaultMemory=false" @@ -14072,7 +14073,7 @@ EOF break_end return 1 fi - echo "✅ 已恢復 includeDefaultMemory=true" + echo "✅ 已恢复 includeDefaultMemory=true" openclaw_memory_rebuild_index_all else echo "已取消。" @@ -14196,7 +14197,7 @@ EOF local start_line count echo "文件:$file" echo "總行數:$total_lines" - read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line + read -e -p "请输入起始行(回车默认末尾 $default_lines行):" start_line read -e -p "請輸入顯示行數(回車預設$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then @@ -14606,10 +14607,10 @@ print(json.dumps(data, indent=2)) echo -e "當前綜合安全等級:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" - echo "Profile (預設): ${current_profile:-(unset)}" - echo " Exec 限制: ${current_sec:-(unset)}" + echo " Profile (预设): ${current_profile:-(unset)}" + echo "Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" - echo "提權開關: ${current_elevated:-(unset)}" + echo " 提权开关: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" if openclaw_has_command openclaw; then @@ -14651,7 +14652,7 @@ try: print("提示策略 (Ask):" + str(d.get("ask", "(unset)"))) print("無UI兜底 (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print("(設定檔解析失敗)") + print(" (配置文件解析失败)") ' else echo "(未配置,強制使用系統內建安全兜底策略)" @@ -14674,7 +14675,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切換為標準安全模式 (所有危險命令將透過UI/TG請求你的批准)${gl_bai}" + echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14707,7 +14708,7 @@ except Exception: openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 echo "正在瓦解宿主機攔截防禦..." - # 這裡的 full 和 off 將徹底繞過底層宿主機的 exec 審批系統 + # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway @@ -14718,7 +14719,7 @@ except Exception: send_stats "OpenClaw權限-恢復官方默認" openclaw_permission_require_openclaw || return 1 - echo "清理應用層強制覆蓋..." + echo "清理应用层强制覆盖..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 @@ -14821,7 +14822,7 @@ except Exception as e: echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" - echo -e "${gl_kjlan}1.${gl_bai} 切换为标准安全模式(日常推荐,弹卡片审批)" + echo -e "${gl_kjlan}1.${gl_bai}切換為標準安全模式(日常推薦,彈卡核准)" echo -e "${gl_kjlan}2.${gl_bai}切換為開發增強模式(允許智能體申請提權)" echo -e "${gl_kjlan}3.${gl_bai}切換為完全開放模式(${gl_hong}高風險!徹底解除所有宿主機攔截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}恢復官方預設沙盒防禦策略" @@ -14844,7 +14845,7 @@ except Exception as e: break_end ;; 3) - echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" + echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" read -e -p "輸入 FULL 確認繼續:" confirm if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end @@ -15012,7 +15013,7 @@ PY return 0 fi fi - # 回退:从文件系统读取 + # 回退:從檔案系統讀取 python3 <<'PY' import json,os base=os.path.expanduser("~/.openclaw/agents") @@ -15126,7 +15127,7 @@ for idx,item in enumerate(agents,1): read -e -p "輸入 DELETE 確認刪除${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ 智能體刪除成功:$agent_id" + echo "✅ 智能体删除成功: $agent_id" else echo "❌ 智能體刪除失敗" return 1 @@ -15153,7 +15154,7 @@ for idx,item in enumerate(bindings,1): local agent_id bind_value confirm read -e -p "請輸入智能體 ID:" agent_id read -e -p "請輸入路由綁定值(如 telegram:ops / discord:guild-a):" bind_value - { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 echo "將綁定智能體 [$agent_id] -> [$bind_value]" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } @@ -15373,7 +15374,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15381,7 +15382,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "編輯 OpenClaw 設定檔" + send_stats "编辑 OpenClaw 配置文件" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15429,7 +15430,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15607,7 +15608,7 @@ while true; do echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager視覺化面板" echo -e "${gl_kjlan}5. ${color5}OpenList多重儲存文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠端桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" @@ -15627,7 +15628,7 @@ while true; do echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" @@ -15663,7 +15664,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -15897,7 +15898,7 @@ while true; do check_docker_image_update $docker_name clear echo -e "哪吒監控$check_docker $update_status" - echo "开源、轻量、易用的服务器监控与运维工具" + echo "開源、輕量、易用的伺服器監控與維運工具" echo "官網搭建文件: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -16165,7 +16166,7 @@ while true; do } local docker_describe="禪道是通用的專案管理軟體" - local docker_url="官網介紹: https://www.zentao.net/" + local docker_url="官网介绍: https://www.zentao.net/" local docker_use="echo \"初始使用者名稱: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" @@ -16307,7 +16308,7 @@ while true; do } - local docker_describe="Speedtest測速面板是VPS網路速度測試工具,多項測試功能,還可以即時監控VPS進出站流量" + local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" local docker_url="官網介紹:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -16386,7 +16387,7 @@ while true; do check_docker_app clear echo -e "雷池服務$check_docker" - echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" + echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16576,7 +16577,7 @@ while true; do } - local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" + local docker_describe="webtop基于Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16617,7 +16618,7 @@ while true; do } - local docker_describe="QD-Today是HTTP請求定時任務自動執行框架" + local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" local docker_url="官網介紹: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" @@ -16637,7 +16638,7 @@ while true; do } - local docker_describe="dockge是一个可视化的docker-compose容器管理面板" + local docker_describe="dockge是一個可視化的docker-compose容器管理面板" local docker_url="官網介紹:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" @@ -16682,7 +16683,7 @@ while true; do } - local docker_describe="searxng是一個私有且隱私的搜尋引擎站點" + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" @@ -16788,7 +16789,7 @@ while true; do } - local docker_describe="Sun-Panel服务器、NAS导航面板、Homepage、浏览器首页" + local docker_describe="Sun-Panel伺服器、NAS導覽面板、Homepage、瀏覽器首頁" local docker_url="官網介紹: https://doc.sun-panel.top/zh_cn/" local docker_use="echo \"帳號: admin@sun.cc 密碼: 12345678\"" local docker_passwd="" @@ -17100,7 +17101,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼皆為: admin" + echo "初始使用者名稱密碼均為: admin" } docker_app_update() { @@ -17141,7 +17142,7 @@ while true; do } - local docker_describe="这是一个普罗米修斯的主机数据采集组件,请部署在被监控主机上。" + local docker_describe="這是一個普羅米修斯的主機資料擷取元件,請部署在被監控主機上。" local docker_url="官網介紹:${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" @@ -17247,7 +17248,7 @@ while true; do } - local docker_describe="OpenWebUI一款大語言模型網頁框架,連結全新的llama3大語言模型" + local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17604,7 +17605,7 @@ while true; do } - local docker_describe="自動將你的公網 IP(IPv4/IPv6)即時更新到各大 DNS 服務商,實現動態網域解析。" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" local docker_url="官網介紹:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" @@ -17789,7 +17790,7 @@ while true; do local app_id="74" - local app_name="moontv私有影視" + local app_name="moontv私有影视" local app_text="免費線上影片搜尋與觀看平台" local app_url="影片介紹:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" @@ -18000,7 +18001,7 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下載官方 docker-compose 和 env 文件 + # 下载官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" @@ -18132,7 +18133,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -18178,7 +18179,7 @@ while true; do local docker_describe="輕量級的自架伺服器監控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" local docker_passwd="" local app_size="1" docker_app @@ -18220,7 +18221,7 @@ while true; do local app_id="85" local app_name="immich圖片影片管理器" - local app_text="高效能自架照片和影片管理解決方案。" + local app_text="高性能自托管照片和视频管理解决方案。" local app_url="官網介紹:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" @@ -18345,7 +18346,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" - local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" + local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" local app_size="1" docker_app @@ -18411,7 +18412,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "建立初始使用者或管理員。請設定以下內容使用者名稱和密碼以及是否為管理員。" + echo "建立初始使用者或管理員。请设置以下内容用户名和密码以及是否为管理员。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -18689,7 +18690,7 @@ while true; do read -e -p "請輸入組網的用戶端數量 (預設 5):" COUNT COUNT=${COUNT:-5} - read -e -p "請輸入 WireGuard 網段 (預設 10.13.13.0):" NETWORK + read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -18766,7 +18767,7 @@ while true; do echo -e "${gl_huang}所有客戶端配置代碼:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可快速連接網絡${gl_bai}" echo -e "${gl_lv}2. Windows下載客戶端,複製設定碼連接網路。${gl_bai}" echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製設定碼連接網路。${gl_bai}" @@ -18798,7 +18799,7 @@ while true; do local CONFIG_FILE="/home/docker/wireguard/config/wg0.conf" - # 创建目录(如果不存在) + # 建立目錄(如果不存在) mkdir -p "$(dirname "$CONFIG_FILE")" echo "請貼上你的客戶端配置,連續按兩次回車保存:" @@ -18931,7 +18932,7 @@ while true; do syncthing/syncthing:latest } - local docker_describe="开源的点对点文件同步工具,类似于 Dropbox、Resilio Sync,但完全去中心化。" + local docker_describe="開源的點對點檔案同步工具,類似 Dropbox、Resilio Sync,但完全去中心化。" local docker_url="官網介紹:${gh_https_url}github.com/syncthing/syncthing" local docker_use="" local docker_passwd="" @@ -18943,7 +18944,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19293,7 +19294,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) local docker_port=8112 docker_rum() { @@ -19379,7 +19380,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "檔案已傳送至遠端伺服器/根目錄。" + echo "文件已传送至远程服务器/根目录。" else echo "未找到要傳送的文件。" fi @@ -19397,7 +19398,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ r) root_use send_stats "全部應用還原" - echo "可用的应用备份" + echo "可用的應用程式備份" echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" @@ -19416,7 +19417,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -n "$filename" ]; then echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" cd / && tar -xzf "$filename" - echo "应用数据已还原,目前请手动进入指定应用菜单,更新应用,即可还原应用。" + echo "應用資料已還原,目前請手動進入指定應用程式選單,更新應用,即可還原應用程式。" else echo "沒有找到壓縮包。" fi @@ -19458,7 +19459,7 @@ linux_work() { clear send_stats "後台工作區" echo -e "後台工作區" - echo -e "系统将为你提供可以后台常驻运行的工作区,你可以用来执行长时间的任务" + echo -e "系統將為你提供可以後台常駐運作的工作區,你可以用來執行長時間的任務" echo -e "即使你斷開SSH,工作區的任務也不會中斷,後台常駐任務。" echo -e "${gl_huang}提示:${gl_bai}進入工作區後再使用Ctrl+b再單獨按d,退出工作區!" echo -e "${gl_kjlan}------------------------" @@ -19477,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}9. ${gl_bai}9號工作區" echo -e "${gl_kjlan}10. ${gl_bai}10號工作區" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}21. ${gl_bai}SSH常驻模式 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}21. ${gl_bai}SSH常駐模式${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}創建/進入工作區" echo -e "${gl_kjlan}23. ${gl_bai}注入指令到後台工作區" echo -e "${gl_kjlan}24. ${gl_bai}刪除指定工作區" @@ -19792,7 +19793,7 @@ net_menu() { case $choice in 1) send_stats "啟用網卡" - read -erp "請輸入要啟用的網路卡名稱:" nic + read -erp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else @@ -19879,13 +19880,13 @@ log_menu() { if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else - echo "✘ 服務不存在或無日誌" + echo "✘ 服务不存在或无日志" fi read -erp "按回車繼續..." ;; 3) send_stats "查看登入/安全日誌" - echo "====== 最近登录日志 ======" + echo "====== 最近登入日誌 ======" last -n 10 echo echo "====== 認證日誌 ======" @@ -19942,7 +19943,7 @@ env_menu() { BASHRC="$HOME/.bashrc" PROFILE="$HOME/.profile" - send_stats "系统变量管理工具" + send_stats "系統變數管理工具" show_env_vars() { clear @@ -20147,10 +20148,10 @@ linux_Settings() { echo -e "${gl_kjlan}7. ${gl_bai}優化DNS位址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}停用ROOT帳戶建立新帳戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}查看端口占用状态 ${gl_kjlan}12. ${gl_bai}修改虛擬記憶體大小" + echo -e "${gl_kjlan}11. ${gl_bai}查看連接埠佔用狀態${gl_kjlan}12. ${gl_bai}修改虛擬記憶體大小" echo -e "${gl_kjlan}13. ${gl_bai}使用者管理${gl_kjlan}14. ${gl_bai}使用者/密碼產生器" echo -e "${gl_kjlan}15. ${gl_bai}系統時區調整${gl_kjlan}16. ${gl_bai}設定BBR3加速" - echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主机名" + echo -e "${gl_kjlan}17. ${gl_bai}防火牆高階管理器${gl_kjlan}18. ${gl_bai}修改主機名" echo -e "${gl_kjlan}19. ${gl_bai}切換系統更新來源${gl_kjlan}20. ${gl_bai}定時任務管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}本機host解析${gl_kjlan}22. ${gl_bai}SSH防禦程序" @@ -20179,7 +20180,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -20189,7 +20190,7 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快速鍵已設定" + echo "快捷键已设置" send_stats "腳本快捷鍵已設定" break_end linux_Settings @@ -20213,7 +20214,7 @@ linux_Settings() { echo "python版本管理" echo "影片介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "此功能可無縫安裝python官方支援的任何版本!" + echo "该功能可无缝安装python官方支持的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20296,7 +20297,7 @@ EOF send_stats "開放埠" iptables_open remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 - echo "端口已全部开放" + echo "連接埠已全部開放" ;; 6) @@ -20307,7 +20308,7 @@ EOF clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 读取当前的 SSH 端口号 + # 讀取目前的 SSH 連接埠號 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') # 列印目前的 SSH 連接埠號碼 @@ -20316,8 +20317,8 @@ EOF echo "------------------------" echo "連接埠號碼範圍1到65535之間的數字。 (輸入0退出)" - # 提示用户输入新的 SSH 端口号 - read -e -p "请输入新的 SSH 端口号: " new_port + # 提示使用者輸入新的 SSH 連接埠號碼 + read -e -p "請輸入新的 SSH 連接埠號碼:" new_port # 判斷連接埠號碼是否在有效範圍內 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 @@ -20391,7 +20392,7 @@ EOF echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "选择优先的网络: " choice + read -e -p "選擇優先的網路:" choice case $choice in 1) @@ -20505,7 +20506,7 @@ EOF case $sub_choice in 1) - # 提示用户输入新用户名 + # 提示使用者輸入新使用者名稱 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false @@ -20619,7 +20620,7 @@ EOF echo "------------------------" echo "亞洲" echo "1. 中國上海時間 2. 中國香港時間" - echo "3. 日本东京时间 4. 韩国首尔时间" + echo "3. 日本東京時間 4. 韓國首爾時間" echo "5. 新加坡時間 6. 印度加爾各答時間" echo "7. 阿聯酋杜拜時間 8. 澳洲雪梨時間" echo "9. 泰國曼谷時間" @@ -20738,7 +20739,7 @@ EOF case $choice in 1) - send_stats "中國大陸預設來源" + send_stats "中国大陆默认源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -20773,7 +20774,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 新增定時任務 2. 刪除定時任務 3. 編輯定時任務" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20794,7 +20795,7 @@ EOF (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "選擇週幾執行任務? (0-6,0代表星期日):" weekday + read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) @@ -20853,7 +20854,7 @@ EOF ;; 2) - read -e -p "請輸入需要刪除的解析內容關鍵字:" delhost + read -e -p "请输入需要删除的解析内容关键字: " delhost sed -i "/$delhost/d" /etc/hosts send_stats "本機host解析刪除" ;; @@ -20888,7 +20889,7 @@ EOF local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) echo -e "${gl_lv}目前設定的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}目前設定的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}目前未啟用限流關機功能${gl_bai}" fi @@ -21102,7 +21103,7 @@ EOF echo "一條龍系統調優" echo "------------------------------------------------" echo "將對以下內容進行操作與優化" - echo "1. 最佳化系統更新來源,更新系統到最新" + echo "1. 优化系统更新源,更新系统到最新" echo "2. 清理系統垃圾文件" echo -e "3. 設定虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" @@ -21124,7 +21125,7 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean @@ -21315,7 +21316,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 - read -e -p "請輸入目錄名:" dirname + read -e -p "请输入目录名: " dirname cd "$dirname" 2>/dev/null || echo "無法進入目錄" send_stats "進入目錄" ;; @@ -21331,7 +21332,7 @@ linux_file() { send_stats "修改目錄權限" ;; 4) # 重命名目录 - read -e -p "请输入当前目录名: " current_name + read -e -p "請輸入目前目錄名稱:" current_name read -e -p "請輸入新目錄名稱:" new_name mv "$current_name" "$new_name" && echo "目錄已重新命名" || echo "重新命名失敗" send_stats "重新命名目錄" @@ -21343,7 +21344,7 @@ linux_file() { ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一層選單目錄" + send_stats "返回上一级选单目录" ;; 11) # 创建文件 read -e -p "請輸入要建立的檔案名稱:" filename @@ -21363,7 +21364,7 @@ linux_file() { send_stats "修改檔案權限" ;; 14) # 重命名文件 - read -e -p "请输入当前文件名: " current_name + read -e -p "請輸入目前檔名:" current_name read -e -p "請輸入新檔名:" new_name mv "$current_name" "$new_name" && echo "文件已重新命名" || echo "重新命名失敗" send_stats "重新命名文件" @@ -21380,7 +21381,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "请输入要解压的文件名 (.tar.gz): " filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21402,7 +21403,7 @@ linux_file() { fi mv "$src_path" "$dest_path" && echo "檔案或目錄已移動到$dest_path" || echo "移動檔案或目錄失敗" - send_stats "移動檔案或目錄" + send_stats "移动文件或目录" ;; @@ -21443,7 +21444,7 @@ linux_file() { kj_ssh_read_password "請輸入遠端伺服器密碼:" local remote_password="$KJ_SSH_PASSWORD" - # 清除已知主機的舊條目 + # 清除已知主机的旧条目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 @@ -21650,17 +21651,17 @@ echo "------------------------" echo -e "${gl_zi}Hostinger 52.7刀每年 美國 1核心 4G記憶體 50G硬碟 4T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}搬運工 49刀每季 美國CN2GIA 日本軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" +echo -e "${gl_huang}搬瓦工 49刀每季 美国CN2GIA 日本软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G記憶體 20G硬碟 800G流量每月${gl_bai}" echo -e "${gl_bai}網址: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" +echo -e "${gl_zi}V.PS 6.9刀每月 东京软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" -echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_bai}网址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "網域優惠" @@ -21779,7 +21780,7 @@ while true; do echo "------------------------" echo "1. 現在更新 2. 開啟自動更新 3. 關閉自動更新" echo "------------------------" - echo "0. 返回主選單" + echo "0. 返回主菜单" echo "------------------------" read -e -p "請輸入你的選擇:" choice case "$choice" in @@ -21816,7 +21817,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下载出错或文件校验不通过,已恢复原版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21845,7 +21846,7 @@ while true; do if [ -n "$cron_sed_cmd" ]; then SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi - # 从旧脚本恢复 permission_granted 和 ENABLE_STATS 设置 + # 從舊腳本恢復 permission_granted 和 ENABLE_STATS 設置 SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # 部署到 /usr/local/bin/k 和 /usr/bin/k SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21956,26 +21957,26 @@ echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" echo "系統回收站 k trash | k hsz | k 回收站" echo "系統備份功能 k backup | k bf | k 備份" -echo "ssh遠端連線工具 k ssh | k 遠端連線" +echo "ssh远程连接工具 k ssh | k 远程连接" echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "軟體重啟 k restart sshd | k 重啟 sshd" +echo "软件重启 k restart sshd | k 重启 sshd " echo "軟體狀態檢視 k status sshd | k 狀態 sshd" -echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" +echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " echo "網域憑證申請 k ssl" echo "網域名稱憑證到期查詢 k ssl ps" echo "docker管理平面 k docker" echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" -echo "docker映像管理 k docker img |k docker 映像" +echo "docker镜像管理 k docker img |k docker 镜像" echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" -echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" @@ -22087,7 +22088,7 @@ else time|时区) shift - send_stats "快速設定時區" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -22237,13 +22238,13 @@ else shift case "$1" in "" ) - # sshkey → 交互菜单 + # sshkey → 互動選單 send_stats "SSHKey 互動選單" sshkey_panel ;; github ) shift - send_stats "从 GitHub 导入 SSH 公钥" + send_stats "從 GitHub 導入 SSH 公鑰" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From 3c0074a8b42e120f8652c7a4fb38e32eae2f6fd6 Mon Sep 17 00:00:00 2001 From: kejilion Date: Fri, 26 Jun 2026 16:48:02 +0800 Subject: [PATCH 1202/1285] =?UTF-8?q?=E9=87=8D=E8=A3=85=E7=B3=BB=E7=BB=9F:?= =?UTF-8?q?=20Debian/Ubuntu=20=E5=85=A8=E9=83=A8=E6=94=B9=E7=94=A8=20bin45?= =?UTF-8?q?6789=20reinstall.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 Debian 10/11/12 和 Ubuntu 20.04/22.04/24.04 的重装方式 从 leitbogioro InstallNET.sh 改为 bin456789 reinstall.sh, 下载函数从 dd_xitong_1 改为 dd_xitong_3,与 Debian 13/Ubuntu 26.04 保持一致。 涉及文件: kejilion.sh, cn/kejilion.sh --- cn/kejilion.sh | 24 ++++++++++++------------ kejilion.sh | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index de622feb0..a45f14b13 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5355,22 +5355,22 @@ dd_xitong() { 2) send_stats "重装debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "重装debian 11" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "重装debian 10" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "重装ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "重装ubuntu 22.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "重装ubuntu 20.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; diff --git a/kejilion.sh b/kejilion.sh index 8d1424f91..48351a786 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5355,22 +5355,22 @@ dd_xitong() { 2) send_stats "重装debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "重装debian 11" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "重装debian 10" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "重装ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "重装ubuntu 22.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "重装ubuntu 20.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; From 0c57aaea33ae1de2161823cc8060bcca18c84d2c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 28 Jun 2026 06:21:24 +0000 Subject: [PATCH 1203/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-06-28=2006:21:24?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 90 +++++----- jp/kejilion.sh | 180 ++++++++++---------- kr/kejilion.sh | 124 +++++++------- tw/kejilion.sh | 444 ++++++++++++++++++++++++------------------------- 4 files changed, 419 insertions(+), 419 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 2f66feb73..41e3c9fff 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -4395,7 +4395,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4492,7 +4492,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -5355,22 +5355,22 @@ dd_xitong() { 2) send_stats "Reinstall debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "Reinstall debian 11" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "Reinstall debian 10" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "Reinstall ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "Reinstall ubuntu 22.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "Reinstall ubuntu 20.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -7344,10 +7344,10 @@ list_tasks() { # Add new task add_task() { - send_stats "Add new sync task" + send_stats "添加新同步任务" echo "Example of creating a new sync task:" echo "- Task name: backup_www" - echo "- Local directory: /var/www" + echo " - 本地目录: /var/www" echo "- Remote address: user@192.168.1.100" echo "- Remote directory: /backup/www" echo "- Port number (default 22)" @@ -8787,7 +8787,7 @@ linux_test() { echo "Chengdu Telecom: 61.139.2.69" echo "Chengdu China Unicom: 119.6.6.6" echo "Chengdu Mobile: 211.137.96.205" - echo "湖南电信: 36.111.200.100" + echo "Hunan Telecom: 36.111.200.100" echo "Hunan Unicom: 42.48.16.100" echo "Hunan Mobile: 39.134.254.6" echo "------------------------" @@ -15977,7 +15977,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16081,7 +16081,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -16135,7 +16135,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -16233,7 +16233,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17119,7 +17119,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17346,7 +17346,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17398,7 +17398,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17439,7 +17439,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17502,7 +17502,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17716,7 +17716,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -17830,7 +17830,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18051,7 +18051,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18115,7 +18115,7 @@ while true; do cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18251,7 +18251,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18478,7 +18478,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18616,7 +18616,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18670,7 +18670,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18903,7 +18903,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18974,7 +18974,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19043,7 +19043,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19184,7 +19184,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19254,7 +19254,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -20214,7 +20214,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21112,7 +21112,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" @@ -21160,7 +21160,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 52aee8681..6e5ed8137 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -260,7 +260,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -867,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -930,12 +930,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリース済みIP$ip" + echo "リリースされたIP$ip" fi done save_iptables_rules - send_stats "リリース済みIP" + send_stats "リリースされたIP" } block_ip() { @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1750,7 +1750,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされているすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2240,8 +2240,8 @@ web_security() { send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CF パラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2561,7 +2561,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -3755,7 +3755,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4841,7 +4841,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5164,7 +5164,7 @@ sshkey_panel() { break_end ;; 4) - send_stats "URL リモート公開キーをインポートする" + send_stats "导入URL远端公钥" read -e -p "リモート公開キーの URL を入力してください:" keys_url fetch_remote_ssh_keys "${keys_url}" break_end @@ -5354,23 +5354,23 @@ dd_xitong() { ;; 2) - send_stats "debian12を再インストールする" - dd_xitong_1 - bash InstallNET.sh -debian 12 + send_stats "重装debian 12" + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "debian11を再インストールする" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "debian10を再インストールする" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "ubuntu 24.04を再インストールします" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "ubuntu 22.04を再インストールします" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "ubuntu 20.04を再インストールします" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; @@ -5624,7 +5624,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません、XanMod ソースを構成できません" + echo "システムコードネームを取得できません。XanMod ソースを構成できません" return 1 fi @@ -6015,8 +6015,8 @@ clamav() { break_end ;; 3) - send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories + send_stats "自定义目录扫描" + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam clamav_scan $directories @@ -6395,7 +6395,7 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6827,7 +6827,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7196,7 +7196,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7327,7 +7327,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7364,7 +7364,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" + kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7375,7 +7375,7 @@ add_task() { echo "同期モードを選択してください:" echo "1. 標準モード (-avz)" - echo "2. 删除目标文件 (-avz --delete)" + echo "2. 対象ファイルを削除(-avz --delete)" read -e -p "(1/2) を選択してください:" mode case $mode in 1) options="-avz" ;; @@ -7586,7 +7586,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7648,7 +7648,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -8330,7 +8330,7 @@ docker_ssh_migration() { read -e -p "移行するバックアップ ディレクトリを入力してください:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}バックアップディレクトリが存在しません${gl_bai}"; return; } - kj_ssh_read_host_user_port "ターゲットサーバーIP:" "ターゲットサーバーの SSH ユーザー名 [デフォルトのルート]:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "root" "22" + kj_ssh_read_host_user_port "ターゲットサーバーIP:" "ターゲットサーバーの SSH ユーザー名 [デフォルトのルート]:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "root" "22" local TARGET_IP="$KJ_SSH_HOST" local TARGET_USER="$KJ_SSH_USER" local TARGET_PORT="$KJ_SSH_PORT" @@ -9801,7 +9801,7 @@ linux_ldnmp() { read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "22" + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -10429,7 +10429,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10449,7 +10449,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11239,7 +11239,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11549,7 +11549,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入口" + send_stats "OpenClaw APIの入り口" while true; do clear echo "=======================================" @@ -12274,7 +12274,7 @@ PYTHON_EOF rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードが成功しました。アクティブ化されています..." + echo "✅ ダウンロードに成功しました。アクティブ化しています..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12292,7 +12292,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12316,7 +12316,7 @@ PYTHON_EOF install_skill() { - send_stats "技能管理" + send_stats "スキル管理" while true; do clear echo "========================================" @@ -12690,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13733,7 +13733,7 @@ PY openclaw_memory_render_auto_summary() { echo "---------------------------------------" - echo "✅ 環境準備完了" + echo "✅ 环境就绪" echo "スキーム: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then echo "モード: 設定の書き込みのみ (インストールされない/ダウンロードされない)" @@ -13973,7 +13973,7 @@ EOF while true; do clear echo "=======================================" - echo "メモリソリューションの自動展開" + echo "メモリソリューションの自動導入" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14034,7 +14034,7 @@ EOF } openclaw_memory_offer_restart() { - echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14196,7 +14196,7 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "合計行数:$total_lines" + echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines @@ -14293,7 +14293,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステートの検出 (組み込みモデルのチェック)" + echo "6. ディープステート検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14533,9 +14533,9 @@ try: elif p == "coding" and s == "allowlist" and a == "on-miss" and e == "true" and b == "true" and ap == "true" and w == "true": print("拡張モードの開発") elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": - print("完全开放模式") + print("フルオープンモード") else: - print("自定义模式") + print("カスタムモード") except Exception: print("カスタムモード") PY @@ -14655,7 +14655,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -15100,7 +15100,7 @@ for idx,item in enumerate(agents,1): [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then echo "✅ エージェントが正常に作成されました:$agent_id" @@ -15156,7 +15156,7 @@ for idx,item in enumerate(bindings,1): read -e -p "ルート バインディング値 (telegram:ops / discord:guild-a など) を入力してください。" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 echo "エージェントをバインドします [$agent_id] -> [$bind_value]" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents bind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に追加されました" @@ -15173,8 +15173,8 @@ for idx,item in enumerate(bindings,1): read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" - read -e -p "続行することを確認するには、「yes」と入力します。" confirm + echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" + read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ ルートバインディングが正常に削除されました" @@ -15382,7 +15382,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 構成ファイルを編集する" + send_stats "OpenClaw 設定ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15638,13 +15638,13 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI 大型モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" + echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -15897,7 +15897,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザ監視$check_docker $update_status" + echo -e "ネザモニタリング$check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15906,7 +15906,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -16516,7 +16516,7 @@ while true; do } - local docker_describe="Uptime Kuma 易于使用的自托管监控工具" + local docker_describe="Uptime Kuma 使いやすいセルフホスト型監視ツール" local docker_url="公式サイト紹介:${gh_proxy}github.com/louislam/uptime-kuma" local docker_use="" local docker_passwd="" @@ -16658,7 +16658,7 @@ while true; do } - local docker_describe="librespeed是用Javascript实现的轻量级速度测试工具,即开即用" + local docker_describe="librespeed は、JavaScript で実装され、すぐに使用できる軽量の速度テスト ツールです。" local docker_url="公式サイト紹介:${gh_proxy}github.com/librespeed/speedtest" local docker_use="" local docker_passwd="" @@ -16715,7 +16715,7 @@ while true; do } - local docker_describe="photoprism非常强大的私有相册系统" + local docker_describe="Photoprism は非常に強力なプライベート フォト アルバム システムです" local docker_url="公式サイト紹介:https://www.photoprism.app/" local docker_use="echo \"アカウント: admin パスワード:$rootpasswd\"" local docker_passwd="" @@ -17991,7 +17991,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートするオープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18344,7 +18344,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -19279,7 +19279,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19372,7 +19372,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ read -e -p "バックアップ データをリモート サーバーに転送しますか? (はい/いいえ):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲットサーバーの SSH ポート [デフォルト 22]:" "22" + kj_ssh_read_host_port "リモートサーバーのIPを入力してください:" "ターゲット サーバーの SSH ポート [デフォルト 22]:" "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /app*.tar.gz | head -1) @@ -19799,7 +19799,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19809,7 +19809,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19821,7 +19821,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19872,7 +19872,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19882,7 +19882,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19897,7 +19897,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19985,7 +19985,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -20000,7 +20000,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -20016,7 +20016,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -20219,7 +20219,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -21339,7 +21339,7 @@ linux_file() { ;; 5) # 删除目录 read -e -p "削除するディレクトリ名を入力してください:" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除に失敗しました" + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "删除失败" send_stats "ディレクトリを削除する" ;; 6) # 返回上一级选单目录 @@ -21538,7 +21538,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21576,7 +21576,7 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -21957,7 +21957,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21980,7 +21980,7 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -21988,7 +21988,7 @@ echo "コマンド お気に入り k お気に入り | k コマンドのお気 echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" -echo "システム情報の表示 k info" +echo "システム情報を表示 k info" echo "ROOT キー管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " echo "SSH 公開キーのインポート (GitHub) k sshkey github " diff --git a/kr/kejilion.sh b/kr/kejilion.sh index ead575127..3d630d1a6 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2789,7 +2789,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3017,7 +3017,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3224,7 +3224,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 재정의하며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3426,7 +3426,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3512,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4986,7 +4986,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5355,22 +5355,22 @@ dd_xitong() { 2) send_stats "데비안 12 다시 설치" - dd_xitong_1 - bash InstallNET.sh -debian 12 + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "데비안 11 다시 설치" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "데비안 10 다시 설치" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "우분투 24.04 다시 설치" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "우분투 22.04 다시 설치" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "우분투 20.04 다시 설치" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; @@ -5725,7 +5725,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5735,7 +5735,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5885,7 +5885,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5903,7 +5903,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5939,7 +5939,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6639,7 +6639,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -8237,7 +8237,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8372,7 +8372,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8526,7 +8526,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -12363,7 +12363,7 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. Are you sure to continue? (예/아니요):" confirm_del + read -e -p "보조 확인: 삭제는 사용자 디렉터리 ~/.openclaw/workspace/skills에만 영향을 미칩니다. 계속하시겠습니까? (예/아니요):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then echo "삭제가 취소되었습니다." break_end @@ -12920,7 +12920,7 @@ if os.path.isdir(agents_root): if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) print(f"✅ 에이전트 메모리 복원됨: {aid}")' "$workspaces_json" "$pkg_dir/payload" - rm -rf "$tmp_unpack"; echo "✅ 전체 메모리 복원 완료"; break_end + rm -rf "$tmp_unpack"; echo "✅ 메모리 전체 복구 완료"; break_end } @@ -13689,7 +13689,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13783,7 +13783,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -14663,7 +14663,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14682,7 +14682,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14700,7 +14700,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14802,7 +14802,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15646,7 +15646,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15666,7 +15666,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15675,7 +15675,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15888,7 +15888,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -15897,7 +15897,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15977,7 +15977,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16716,7 +16716,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -17410,7 +17410,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -18945,7 +18945,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19294,7 +19294,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -19918,7 +19918,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한합니다." + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -20608,7 +20608,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간을 가져옵니다 + # 현재 시스템 시간 가져오기 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -20628,7 +20628,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 위트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20951,7 +20951,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21395,7 +21395,7 @@ linux_file() { continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하십시오." dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then echo "오류: 대상 경로를 입력하십시오." send_stats "파일 또는 디렉터리 이동 실패: 대상 경로가 지정되지 않았습니다." @@ -21415,7 +21415,7 @@ linux_file() { continue fi - read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하십시오." dest_path + read -e -p "대상 경로(새 파일 또는 디렉터리 이름 포함)를 입력하세요." dest_path if [ -z "$dest_path" ]; then echo "오류: 대상 경로를 입력하십시오." send_stats "파일 또는 디렉터리 복사 실패: 대상 경로가 지정되지 않았습니다." @@ -21657,7 +21657,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21691,7 +21691,7 @@ games_server_tools() { echo -e "게임 서버 오프닝 스크립트 모음" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Eudemons Parlu 서버 오픈 스크립트" - echo -e "${gl_kjlan}2. ${gl_bai}Minecraft 서버 오프닝 스크립트" + echo -e "${gl_kjlan}2. ${gl_bai}Minecraft 서버 열기 스크립트" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21703,7 +21703,7 @@ games_server_tools() { curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/palworld.sh ; chmod +x palworld.sh ; ./palworld.sh exit ;; - 2) send_stats "Minecraft 서버 오프닝 스크립트" ; cd ~ + 2) send_stats "Minecraft 서버 열기 스크립트" ; cd ~ curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/mc.sh ; chmod +x mc.sh ; ./mc.sh exit ;; @@ -21975,7 +21975,7 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" @@ -21985,7 +21985,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index a31b12362..e7a256a38 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -36,7 +36,7 @@ quanju_canshu -# 定義一個函數來執行命令 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -304,7 +304,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1服務已重啟。" else - echo "錯誤:重啟$1 服务失败。" + echo "錯誤:重啟$1服務失敗。" fi } @@ -522,7 +522,7 @@ while true; do docker rm -f $dockername ;; 5) - send_stats "重启指定容器" + send_stats "重啟指定容器" read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker restart $dockername ;; @@ -599,7 +599,7 @@ while true; do ;; 16) - send_stats "阻止容器端口访问" + send_stats "阻止容器連接埠訪問" read -e -p "請輸入容器名稱:" docker_name ip_address block_container_port "$docker_name" "$ipv4_address" @@ -625,7 +625,7 @@ while true; do echo "" echo "鏡像操作" echo "------------------------" - echo "1. 获取指定镜像 3. 删除指定镜像" + echo "1. 取得指定鏡像 3. 刪除指定鏡像" echo "2. 更新指定鏡像 4. 刪除所有鏡像" echo "------------------------" echo "0. 返回上一級選單" @@ -791,7 +791,7 @@ docker_ipv6_off() { # 檢查設定檔是否存在 if [ ! -f "$CONFIG_FILE" ]; then - echo -e "${gl_hong}配置文件不存在${gl_bai}" + echo -e "${gl_hong}設定檔不存在${gl_bai}" return fi @@ -917,7 +917,7 @@ close_port() { allow_ip() { local ips=($@) # 将传入的参数转换为数组 if [ ${#ips[@]} -eq 0 ]; then - echo "请提供至少一个IP地址或IP段" + echo "請提供至少一個IP位址或IP段" return 1 fi @@ -1098,7 +1098,7 @@ iptables_panel() { echo "1. 開放指定連接埠 2. 關閉指定連接埠" echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" - echo "5. IP白名单 6. IP黑名单" + echo "5. IP白名單 6. IP黑名單" echo "7. 清除指定IP" echo "------------------------" echo "11. 允許PING 12. 禁止PING" @@ -1157,7 +1157,7 @@ iptables_panel() { 5) # IP 白名單 - read -e -p "请输入放行的IP或IP段: " o_ip + read -e -p "請輸入放行的IP或IP段:" o_ip allow_ip $o_ip ;; 6) @@ -1200,7 +1200,7 @@ iptables_panel() { send_stats "允許國家$country_code的IP" ;; 16) - read -e -p "请输入允许的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code + read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules allow $country_code send_stats "阻止國家$country_code的IP" ;; @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1258,7 +1258,7 @@ add_swap() { rc-update add local fi - echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" + echo -e "虛擬記憶體大小已調整為${gl_huang}${new_swap}${gl_bai}M" } @@ -1481,7 +1481,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1540,8 +1540,8 @@ certs_status() { send_stats "網域證書申請成功" else send_stats "網域證書申請失敗" - echo -e "${gl_hong}注意:${gl_bai}证书申请失败,请检查以下可能原因并重试:" - echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" + echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" @@ -1617,7 +1617,7 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then - send_stats "域名重复使用" + send_stats "網域重複使用" web_del "${yuming}" > /dev/null 2>&1 fi @@ -1750,7 +1750,7 @@ cf_purge_cache() { # 提示使用者是否清理快取 read -e -p "需要清理 Cloudflare 的快取嗎? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF資訊保存在$CONFIG_FILE,可以后期修改CF信息" + echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN read -e -p "請輸入你的CF用戶名:" EMAIL read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS @@ -1760,7 +1760,7 @@ cf_purge_cache() { fi fi - # 循环遍历每个 zone_id 并执行清除缓存命令 + # 循環遍歷每個 zone_id 並執行清除快取命令 for ZONE_ID in "${ZONE_IDS[@]}"; do echo "正在清除快取 for zone_id:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ @@ -2115,7 +2115,7 @@ web_security() { check_waf_status check_cf_mode clear - echo -e "服务器网站防御程序 ${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" + echo -e "伺服器網站防禦程序${check_f2b_status}${gl_lv}${CFmessage}${waf_status}${gl_bai}" echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" @@ -2126,10 +2126,10 @@ web_security() { echo "------------------------" echo "21. cloudflare模式 22. 高負載開啟5秒盾" echo "------------------------" - echo "31. 开启WAF 32. 关闭WAF" + echo "31. 開啟WAF 32. 關閉WAF" echo "33. 開啟DDOS防禦 34. 關閉DDOS防禦" echo "------------------------" - echo "9. 卸载防御程序" + echo "9. 卸載防禦程序" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) @@ -2279,7 +2279,7 @@ web_security() { 32) nginx_waf off - echo "站点WAF已关闭" + echo "站點WAF已關閉" send_stats "站點WAF已關閉" ;; @@ -2306,7 +2306,7 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # 检查 MySQL 配置文件中是否包含 4096M + # 檢查 MySQL 設定檔中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="高性能模式" else @@ -2331,12 +2331,12 @@ check_nginx_compression() { # 檢查 brotli 是否開啟且未被註釋 if grep -qE '^\s*brotli\s+on;' "$CONFIG_FILE"; then - br_status=" br压缩已开启" + br_status="br壓縮已開啟" else br_status="" fi - # 检查 gzip 是否开启且未被注释 + # 檢查 gzip 是否開啟且未被註釋 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "優化LDNMP環境" echo -e "優化LDNMP環境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" + echo "1. 標準模式 2. 高效能模式 (建議2H4G以上)" echo "------------------------" echo "3. 開啟gzip壓縮 4. 關閉gzip壓縮" echo "5. 開啟br壓縮 6. 關閉br壓縮" @@ -2882,7 +2882,7 @@ while true; do echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "5. 添加域名访问 6. 删除域名访问" + echo "5. 新增網域存取 6. 刪除網域存取" echo "7. 允許IP+連接埠存取 8. 阻止IP+連接埠訪問" echo "------------------------" echo "0. 返回上一級選單" @@ -2893,12 +2893,12 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}端口: " app_port + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" - send_stats "应用端口已被占用" + send_stats "應用程式連接埠已被佔用" else local docker_port=$app_port break @@ -3244,7 +3244,7 @@ f2b_basic_config() { fi echo "即將配置 SSH jail:$jail_name" - read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime + read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry @@ -3284,7 +3284,7 @@ f2b_edit_config() { install nano if [ ! -d /etc/fail2ban ]; then - echo -e "${gl_hui}/etc/fail2ban 不存在,請先安裝 fail2ban。${gl_bai}" + echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" return fi @@ -3554,7 +3554,7 @@ ldnmp_Proxy() { ldnmp_Proxy_backend() { clear - webname="反向代理-负载均衡" + webname="反向代理-負載平衡" send_stats "安裝$webname" echo "開始部署$webname" @@ -3615,7 +3615,7 @@ list_stream_services() { # 服務名取檔名 service_name=$(basename "$conf" .conf) - # 获取 upstream 块中的 server 后端 IP:端口 + # 取得 upstream 區塊中的 server 後端 IP:端口 backend=$(grep -Po '(?<=server )[^;]+' "$conf" | head -n1) # 取得 listen 端口 @@ -3870,7 +3870,7 @@ ldnmp_web_status() { echo "------------------------" echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" - echo "5. 查看访问日志 6. 查看错误日志" + echo "5. 查看訪問日誌 6. 查看錯誤日誌" echo "7. 編輯全域配置 8. 編輯站點配置" echo "9. 管理站點資料庫 10. 查看站點分析報告" echo "------------------------" @@ -3932,7 +3932,7 @@ ldnmp_web_status() { ;; 4) send_stats "建立關聯站點" - echo -e "为现有的站点再关联一个新域名用于访问" + echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming read -e -p "請輸入新網域名稱:" yuming install_certbot @@ -4017,7 +4017,7 @@ while true; do echo "" echo "------------------------" - echo "1. 安裝 2. 管理 3. 卸載" + echo "1. 安装 2. 管理 3. 卸载" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4152,7 +4152,7 @@ EOF add_forwarding_service() { send_stats "新增frp內網服務" - # 提示用户输入服务名称和转发信息 + # 提示使用者輸入服務名稱和轉發訊息 read -e -p "請輸入服務名稱:" service_name read -e -p "請輸入轉送類型 (tcp/udp) [回​​車預設tcp]:" service_type local service_type=${service_type:-tcp} @@ -4172,7 +4172,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入 frpc.toml" + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4199,7 +4199,7 @@ list_forwarding_services() { local config_file="$1" # 列印表頭 - printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外网地址" "協定" + printf "%-20s %-25s %-30s %-10s\n" "服務名稱" "內部網路位址" "外網位址" "協定" awk ' BEGIN { @@ -4304,7 +4304,7 @@ generate_access_urls() { fi done - # 处理 IPv6 地址(如果存在) + # 處理 IPv6 位址(如果存在) if [ -n "$ipv6_address" ]; then for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then @@ -4459,7 +4459,7 @@ frpc_panel() { echo "------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "------------------------" - echo "4. 添加对外服务 5. 删除对外服务 6. 手动配置服务" + echo "4. 新增對外服務 5. 刪除對外服務 6. 手動設定服務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4591,7 +4591,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "下载完成,按任意键继续..." ;; + read -e -p "下載完成,按任何鍵繼續..." ;; 6) send_stats "大量影片下載" install nano @@ -4788,7 +4788,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版本 sysctl.conf 殘留 +# 清理可能導致衝突的舊版 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5015,19 +5015,19 @@ fetch_remote_ssh_keys() { local temp_file if [[ -z "${keys_url}" ]]; then - read -e -p "请输入您的远端公钥URL: " keys_url + read -e -p "請輸入您的遠端公鑰URL:" keys_url fi - echo "此脚本将从远程 URL 拉取 SSH 公钥,并添加到 ${authorized_keys}" + echo "此腳本將從遠端 URL 拉取 SSH 公鑰,並添加到${authorized_keys}" echo "" - echo "远程公钥地址:" + echo "遠端公鑰地址:" echo " ${keys_url}" echo "" # 建立臨時文件 temp_file=$(mktemp) - # 下载公钥 + # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 @@ -5100,7 +5100,7 @@ fetch_github_ssh_keys() { echo "1. 登入${gh_https_url}github.com/settings/keys" echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" - echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" + echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" echo "5. 點選 Add SSH key 完成新增" echo "" echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" @@ -5109,7 +5109,7 @@ fetch_github_ssh_keys() { if [[ -z "${username}" ]]; then - read -e -p "请输入您的 GitHub 用户名(username,不含 @): " username + read -e -p "請輸入您的 GitHub 使用者名稱(username,不含 @):" username fi if [[ -z "${username}" ]]; then @@ -5141,7 +5141,7 @@ sshkey_panel() { echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" - echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" + echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5212,7 +5212,7 @@ add_sshpasswd() { # 如果沒有透過參數傳入,則交互輸入 if [[ -z "$target_user" ]]; then - read -e -p "请输入要修改密码的用户名(默认 root): " target_user + read -e -p "請輸入要修改密碼的使用者名稱(預設 root):" target_user fi # 回車不輸入,預設 root @@ -5355,22 +5355,22 @@ dd_xitong() { 2) send_stats "重裝debian 12" - dd_xitong_1 - bash InstallNET.sh -debian 12 + dd_xitong_3 + bash reinstall.sh debian 12 reboot exit ;; 3) send_stats "重裝debian 11" - dd_xitong_1 - bash InstallNET.sh -debian 11 + dd_xitong_3 + bash reinstall.sh debian 11 reboot exit ;; 4) send_stats "重裝debian 10" - dd_xitong_1 - bash InstallNET.sh -debian 10 + dd_xitong_3 + bash reinstall.sh debian 10 reboot exit ;; @@ -5383,22 +5383,22 @@ dd_xitong() { ;; 12) send_stats "重裝ubuntu 24.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 24.04 + dd_xitong_3 + bash reinstall.sh ubuntu 24.04 reboot exit ;; 13) send_stats "重裝ubuntu 22.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 22.04 + dd_xitong_3 + bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) send_stats "重裝ubuntu 20.04" - dd_xitong_1 - bash InstallNET.sh -ubuntu 20.04 + dd_xitong_3 + bash reinstall.sh ubuntu 20.04 reboot exit ;; @@ -5617,7 +5617,7 @@ bbrv3() { os_codename="releases" fi - # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 + # 官方已徹底移除對 jammy, focal, bullseye 等舊系統的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod 官方已停止對目前系統($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" return 1 @@ -5631,7 +5631,7 @@ bbrv3() { install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then - echo "官方密钥下载失败,尝试备用下载源..." + echo "官方金鑰下載失敗,嘗試備用下載來源..." wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" @@ -5754,7 +5754,7 @@ bbrv3() { linux_Settings fi else - echo "无法确定操作系统类型" + echo "無法確定作業系統類型" break_end linux_Settings fi @@ -5837,7 +5837,7 @@ elrepo_install() { echo "安裝 ELRepo 倉庫設定 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "安装 ELRepo 仓库配置 (版本 10)..." + echo "安裝 ELRepo 倉庫設定 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else echo "不支援的系統版本:$os_version" @@ -5856,7 +5856,7 @@ elrepo_install() { elrepo() { root_use - send_stats "紅帽內核管理" + send_stats "红帽内核管理" if uname -r | grep -q 'elrepo'; then while true; do clear @@ -5960,7 +5960,7 @@ clamav_scan() { mkdir -p /home/docker/clamav/log/ > /dev/null 2>&1 > /home/docker/clamav/log/scan.log > /dev/null 2>&1 - # 执行 Docker 命令 + # 執行 Docker 命令 docker run --rm \ --name clamav \ --mount source=clam_db,target=/var/lib/clamav \ @@ -6033,7 +6033,7 @@ clamav() { # ============================================================================ # Linux 核心調優模組(重構版) -# 统一核心函数 + 场景差异化参数 + 持久化到配置文件 + 硬件自适应 +# 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 # 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ @@ -6107,7 +6107,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; balanced) - # 均衡模式:适度优化 + # 均衡模式:適度優化 SWAPPINESS=30 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6302,7 +6302,7 @@ SYSCTL done < "$CONF" echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" - # ── 透明大页面 ── + # ── 透明大頁面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi @@ -6350,14 +6350,14 @@ restore_defaults() { local CONF="/etc/sysctl.d/99-kejilion-optimize.conf" - # 删除优化配置文件(含外链自动调优配置) + # 刪除最佳化設定檔(含外鏈自動調優配置) rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf # 清理 sysctl.conf 裡可能殘留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null - # 重新加载系统默认配置 + # 重新載入系統預設配置 sysctl --system 2>/dev/null | tail -1 # 還原透明大頁面 @@ -6372,7 +6372,7 @@ restore_defaults() { # 清理 BBR 持久化 rm -f /etc/modules-load.d/bbr.conf 2>/dev/null - echo -e "${gl_lv}系统已还原到默认设置${gl_bai}" + echo -e "${gl_lv}系統已還原到預設設定${gl_bai}" } @@ -6391,15 +6391,15 @@ Kernel_optimize() { fi echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" - echo "提供多种系统参数调优模式,用户可以根据自身使用场景进行选择切换。" + echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo -e "--------------------" echo -e "1. 高效能最佳化模式: 最大化系統效能,激進的記憶體和網路參數。" echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" - echo -e "3. 网站优化模式: 针对网站服务器优化,超高并发连接队列。" + echo -e "3. 網站最佳化模式: 針對網站伺服器最佳化,超高並發連線佇列。" echo -e "4. 直播最佳化模式: 針對直播推流優化,UDP 緩衝區加大,減少延遲。" echo -e "5. 遊戲服最佳化模式: 針對遊戲伺服器最佳化,低延遲優先。" - echo -e "6. 还原默认设置: 将系统设置还原为默认配置。" + echo -e "6. 還原預設設定: 將系統設定還原為預設配置。" echo -e "7. 自動調優: 依測試資料自動調優核心參數。${gl_huang}★${gl_bai}" echo "--------------------" echo "0. 返回上一級選單" @@ -6552,7 +6552,7 @@ else echo "${bianse}" >> ~/.profile # source ~/.profile fi -echo -e "${gl_lv}变更完成。重新连接SSH后可查看变化!${gl_bai}" +echo -e "${gl_lv}變更完成。重新連接SSH後可查看變化!${gl_bai}" hash -r break_end @@ -6715,7 +6715,7 @@ create_backup() { "/home" # 用户数据 ) else - # 将用户输入的目录按空格分隔成数组 + # 將使用者輸入的目錄以空格分隔成數組 IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi @@ -6946,7 +6946,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "请粘贴密钥内容 (粘贴完成后按两次回车):" + echo "請貼上金鑰內容 (貼上完成後按兩次回車):" while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -7017,7 +7017,7 @@ add_connection() { echo "------------------------" read -e -p "請輸入連線名稱:" name - kj_ssh_read_host_user_port "请输入IP地址: " "请输入用户名 (默认: root): " "請輸入連接埠號碼 (預設: 22):" "root" "22" + kj_ssh_read_host_user_port "請輸入IP位址:" "請輸入使用者名稱 (預設: root):" "請輸入連接埠號碼 (預設: 22):" "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi @@ -7069,8 +7069,8 @@ use_connection() { ssh -o StrictHostKeyChecking=no -i "$password_or_key" -p "$port" "$user@$ip" if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" - echo "1. 密钥文件路径是否正确:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" + echo "1. 密鑰檔案路徑是否正確:$password_or_key" + echo "2. 密鑰檔案權限是否正確(應為 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else @@ -7112,7 +7112,7 @@ ssh_manager() { while true; do clear echo "SSH 遠端連線工具" - echo "可以通过SSH连接到其他Linux系统上" + echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections echo "1. 建立新連接 2. 使用連接 3. 刪除連接" @@ -7194,7 +7194,7 @@ mount_partition() { echo "分區已成功掛載到$MOUNT_POINT" - # 检查 /etc/fstab 是否已经存在 UUID 或挂载点 + # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then echo "/etc/fstab 中已存在該分區記錄,跳過寫入" return 0 @@ -7249,7 +7249,7 @@ format_partition() { # 檢查分割區是否已經掛載 if lsblk -o MOUNTPOINT | grep -w "$PARTITION" > /dev/null; then - echo "分区已经挂载,请先卸载!" + echo "分割區已經掛載,請先卸載!" return fi @@ -7281,7 +7281,7 @@ format_partition() { mkfs.$FS_TYPE "/dev/$PARTITION" if [ $? -eq 0 ]; then - echo "分区格式化成功!" + echo "分割區格式化成功!" else echo "分割區格式化失敗!" fi @@ -7345,14 +7345,14 @@ list_tasks() { # 新增任務 add_task() { send_stats "新增同步任務" - echo "创建新同步任务示例:" + echo "建立新同步任務範例:" echo "- 任務名稱: backup_www" echo "- 本機目錄: /var/www" echo "- 遠端位址: user@192.168.1.100" echo "- 遠端目錄: /backup/www" echo "- 連接埠號碼 (預設 22)" echo "---------------------------------" - read -e -p "请输入任务名称: " name + read -e -p "請輸入任務名稱:" name read -e -p "請輸入本地目錄:" local_path read -e -p "請輸入遠端目錄:" remote_path @@ -7438,7 +7438,7 @@ run_task() { local task=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$task" ]]; then - echo "错误: 未找到该任务!" + echo "錯誤: 未找到該任務!" return fi @@ -7730,7 +7730,7 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 未识别的包管理器" + echo "❌ 未識別的套件管理器" exit 1 fi @@ -7759,8 +7759,8 @@ linux_tools() { done echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}1. ${gl_bai}curl 下载工具 ${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" @@ -7877,7 +7877,7 @@ linux_tools() { clear ranger cd ~ - send_stats "安装ranger" + send_stats "安裝ranger" ;; 13) clear @@ -8000,7 +8000,7 @@ linux_tools() { clear read -e -p "請輸入已安裝的工具名稱(wget curl sudo htop):" installname install $installname - send_stats "安装指定软件" + send_stats "安裝指定軟體" ;; 42) clear @@ -8039,7 +8039,7 @@ linux_bbr() { echo "" echo "BBR管理" echo "------------------------" - echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" + echo "1. 開啟BBRv3 2. 關閉BBRv3(會重新啟動)" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -8098,7 +8098,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -e -p "請輸入要備份的容器名稱(多個空格分隔,回車備份全部運行中容器):" containers install tar jq gzip install_docker @@ -8153,7 +8153,7 @@ docker_ssh_migration() { PACKED_COMPOSE_PATHS["$project_dir"]=1 echo -e "${gl_lv}Compose 項目 [$project_name] 已打包:${project_dir}${gl_bai}" else - echo -e "${gl_hong}未找到 docker-compose.yml,跳过此容器...${gl_bai}" + echo -e "${gl_hong}未找到 docker-compose.yml,跳過此容器...${gl_bai}" fi else # 普通容器備份卷 @@ -8305,7 +8305,7 @@ docker_ssh_migration() { eval "docker run -d --name \"$container\" $PORT_ARGS $VOL_ARGS $ENV_ARGS \"$IMAGE\"" done - [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的备份信息${gl_bai}" + [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" # 還原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then @@ -8517,7 +8517,7 @@ linux_docker() { 2) send_stats "加入網路" read -e -p "加入網路名稱:" dockernetwork - read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames + read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername @@ -8526,7 +8526,7 @@ linux_docker() { 3) send_stats "加入網路" read -e -p "退出網路名稱:" dockernetwork - read -e -p "那些容器退出该网络(多个容器名请用空格分隔): " dockernames + read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8690,7 +8690,7 @@ linux_test() { while true; do clear # send_stats "測試腳本集合" - echo -e "测试脚本合集" + echo -e "測試腳本合集" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP及解鎖狀態偵測" echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解鎖狀態偵測" @@ -8711,7 +8711,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}硬體效能測試" - echo -e "${gl_kjlan}21. ${gl_bai}yabs 性能测试" + echo -e "${gl_kjlan}21. ${gl_bai}yabs 效能測試" echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU效能測試腳本" echo -e "${gl_kjlan}------------------------" @@ -8834,7 +8834,7 @@ linux_test() { curl -Lso- bench.sh | bash ;; 32) - send_stats "spiritysdx融合怪测评" + send_stats "spiritysdx融合怪測評" clear curl -L ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; @@ -8887,7 +8887,7 @@ linux_Oracle() { 1) clear echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" - read -e -p "確定安裝嗎? (Y/N):" choice + read -e -p "确定安装吗? (Y/N):" choice case "$choice" in [Yy]) @@ -8899,17 +8899,17 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 提示用户输入CPU核心数和占用百分比,如果回车则使用默认值 - read -e -p "請輸入CPU核心數 [預設:$DEFAULT_CPU_CORE]: " cpu_core + # 提示使用者輸入CPU核心數和占用百分比,如果回車則使用預設值 + read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [預設:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "請輸入記憶體佔用百分比 [預設:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "請輸入Speedtest間隔時間(秒) [預設:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 運行Docker容器 @@ -8935,7 +8935,7 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文雲端卸載活躍腳本" + send_stats "甲骨文云卸载活跃脚本" ;; 3) @@ -8948,7 +8948,7 @@ linux_Oracle() { case "$choice" in [Yy]) while true; do - read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice + read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice case "$sys_choice" in 1) @@ -9080,13 +9080,13 @@ linux_ldnmp() { echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" - echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自定义动态站点" + echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo部落格網站" echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" - echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" + echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自訂靜態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" @@ -9289,7 +9289,7 @@ linux_ldnmp() { echo "密碼: admin" echo "------------------------" echo "登入時右上角如果出現紅色error0請使用下列指令:" - echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" + echo "我也很氣憤獨角數卡為啥這麼麻煩,會有這樣的問題!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9490,7 +9490,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}3/6${gl_bai}] 請選擇PHP版本" echo "-------------" - read -e -p "1. php最新版 | 2. php7.4 : " pho_v + read -e -p "1. php最新版 | 2. php7.4 :" pho_v case "$pho_v" in 1) sed -i "s#php:9000#php:9000#g" /home/web/conf.d/$yuming.conf @@ -9536,7 +9536,7 @@ linux_ldnmp() { echo ;; 2) - echo "資料庫備份必須是.gz結尾的壓縮包。请放到/home/目录下,支持宝塔/1panel备份数据导入。" + echo "数据库备份必须是.gz结尾的压缩包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ @@ -9789,7 +9789,7 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP环境备份" + send_stats "LDNMP環境備份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_kjlan}正在備份$backup_filename ...${gl_bai}" @@ -9850,7 +9850,7 @@ linux_ldnmp() { ;; 2) check_crontab_installed - read -e -p "选择每天备份的时间(小时,0-23): " hour + read -e -p "選擇每天備份的時間(小時,0-23):" hour (crontab -l ; echo "0 $hour * * * ./${useip}_beifen.sh") | crontab - > /dev/null 2>&1 ;; *) @@ -9869,7 +9869,7 @@ linux_ldnmp() { echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份檔名還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -10429,9 +10429,9 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API刪失敗Provider-確認') - summary.append(f'✅ {name}: 用户已确认删除该 provider 及全部相关模型引用') + summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') else: - send_stat('OpenClaw API刪失敗Provider-拒絕') + send_stat('OpenClaw API删失败Provider-拒绝') summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') continue @@ -10778,7 +10778,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 交互式添加 OpenClaw Provider (全量模型) ===" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10865,7 +10865,7 @@ EOF else add-default-model-only-to-provider "$provider_name" "$base_url" "$api_key" "$default_model" add_result=$? - finish_msg="✅ 完成!已保留 provider,并仅加载默认模型:$default_model" + finish_msg="✅ 完成!已保留 provider,並僅載入預設模型:$default_model" fi if [[ $add_result -eq 0 ]]; then @@ -11015,7 +11015,7 @@ sync-openclaw-provider-interactive() { if sync_openclaw_api_models; then start_gateway else - echo "❌ API 模型同步失敗,已中止重新啟動網關。請檢查 provider /models 返回後重試。" + echo "❌ API 模型同步失败,已中止重启网关。請檢查 provider /models 返回後重試。" return 1 fi break_end @@ -11114,7 +11114,7 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,無法執行同步') + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') raise SystemExit(3) if api not in SUPPORTED_APIS: @@ -11137,7 +11137,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 為空,已中止同步') + print(f'❌ {target}: 上游 /models 为空,已中止同步') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11236,7 +11236,7 @@ PY2 echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失败:上游模型为空或同步后无可用模型" + echo "❌ 同步失敗:上游模型為空或同步後無可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -11248,7 +11248,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 - # 保留函数以兼容菜单调用,但不做任何改写。 + # 保留函數以相容選單調用,但不做任何改寫。 echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -11341,7 +11341,7 @@ PY delete-openclaw-provider-interactive() { local config_file config_file=$(openclaw_get_config_file) - send_stats "OpenClaw API删除入口" + send_stats "OpenClaw API刪除入口" if [ ! -f "$config_file" ]; then echo "❌ 未找到設定檔:$config_file" @@ -11439,7 +11439,7 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 刪除中止:預設主模型指向該 provider,且無可用替代模型') + print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') raise SystemExit(3) set_primary_ref(defaults, replacement) print(f'🔁 預設主模型切換: {primary_ref} -> {replacement}') @@ -11451,7 +11451,7 @@ for fk in ('modelFallback', 'imageModelFallback'): print(f'❌ 刪除中止:{fk} 指向該 provider,且無可用替代模型') raise SystemExit(3) defaults[fk] = replacement - print(f'🔁 {fk} 切换: {val} -> {replacement}') + print(f'🔁 {fk} 切換: {val} -> {replacement}') removed_refs = [r for r in list(defaults_models.keys()) if r.startswith(name + '/')] for r in removed_refs: @@ -11481,7 +11481,7 @@ PY echo "❌ 刪除失敗:無可用替代模型,已保持原始配置" ;; *) - echo "❌ 刪除失敗:請檢查設定檔結構或日誌輸出" + echo "❌ 删除失败:请检查配置文件结构或日志输出" ;; esac @@ -11871,7 +11871,7 @@ PYTHON_EOF echo "目前可用模型:" jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d' echo "----------------" - read -e -p "请输入要设置的模型名称 (例如 openrouter/openai/gpt-4o)(输入 0 退出): " selected_model + read -e -p "請輸入要設定的模型名稱 (例如 openrouter/openai/gpt-4o)(輸入 0 退出):" selected_model if [ "$selected_model" = "0" ]; then echo "操作已取消,正在退出..." @@ -11905,10 +11905,10 @@ PYTHON_EOF gum style --foreground "$orange" "可用模型(Auth=yes):${model_count}" gum style --foreground "$orange" "目前預設:${default_model}" echo "" - gum style --faint "↑↓ 选择 / Enter 测试 / Esc 退出" + gum style --faint "↑↓ 選擇 / Enter 測試 / Esc 退出" echo "" - selected_model=$(echo "$models_list" | gum filter --placeholder "搜尋模型(如 cli-api/gpt-5.2)" --prompt "选择模型 > " --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) + selected_model=$(echo "$models_list" | gum filter --placeholder "搜尋模型(如 cli-api/gpt-5.2)" --prompt "選擇模型 >" --indicator "➜ " --prompt.foreground "$orange" --indicator.foreground "$orange" --cursor-text.foreground "$orange" --match.foreground "$orange" --header "" --height 35) if [ -z "$selected_model" ] || echo "$selected_model" | head -n 1 | grep -iqE '^(error|usage|gum:)'; then echo "操作已取消,正在退出..." @@ -12190,7 +12190,7 @@ PYTHON_EOF while true; do clear echo "========================================" - echo " 插件管理 (安装/删除) " + echo "外掛程式管理 (安裝/刪除)" echo "========================================" echo "當前插件列表:" openclaw plugins list @@ -12307,7 +12307,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 正在重启 OpenClaw 服务以加载变更..." + echo "🔄 正在重啟 OpenClaw 服務以載入變更..." start_gateway fi break_end @@ -12665,7 +12665,7 @@ openclaw_json_get_bool() { echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" - echo "1. Telegram 机器人对接" + echo "1. Telegram 機器人對接" echo "2. 飛書 (Lark) 機器人對接" echo "3. WhatsApp 機器人對接" echo "4. QQ 機器人對接" @@ -12690,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12807,7 +12807,7 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "可使用以下方式下载备份文件:" + echo "可使用以下方式下載備份檔:" echo "- 本地路徑:$file_path" echo "- scp 範例: scp root@你的伺服器:$file_path ./" echo "- 或使用 SFTP 用戶端下載" @@ -12936,7 +12936,7 @@ if os.path.isdir(agents_root): return 1 fi - echo "备份模式:" + echo "備份模式:" echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多狀態,敏感風險較高)" read -e -p "請選擇備份模式(預設 1):" export_mode @@ -13582,7 +13582,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可訪問") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可达(疑似国内/受限网络)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com 可能不可達(疑似國內/受限網路)") fi if [ "$qmd_ok" = "true" ]; then @@ -13715,11 +13715,11 @@ PY echo "⚠️ qmd 指令存在但模組損壞,重新安裝..." fi fi - echo "⬇️ 通过 npm 安装 qmd: @tobilu/qmd" + echo "⬇️ 透過 npm 安裝 qmd: @tobilu/qmd" npm install -g @tobilu/qmd qmd_path=$(command -v qmd 2>/dev/null || true) if [ -z "$qmd_path" ]; then - echo "❌ qmd 安装失败" + echo "❌ qmd 安裝失敗" return 1 fi if ! qmd --version >/dev/null 2>&1; then @@ -13834,7 +13834,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ 已寫入 memory.qmd.command:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command 已正确" + echo "✅ memory.qmd.command 已正確" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 預熱索引(可能下載模型)" @@ -13891,7 +13891,7 @@ EOF if [ -f "$model_dest" ]; then echo "✅ 已發現預設模型檔:$model_dest" else - echo "⬇️ 下載模型:$model_url" + echo "⬇️ 下载模型: $model_url" openclaw_memory_download_file "$model_url" "$model_dest" || return 1 echo "✅ 模型已下載:$model_dest" fi @@ -14058,7 +14058,7 @@ EOF echo "=======================================" echo "索引修復診斷" echo "=======================================" - echo "当前 includeDefaultMemory: ${include_dm:-未设置}" + echo "目前 includeDefaultMemory: ${include_dm:-未設定}" echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ 偵測到 includeDefaultMemory=false" @@ -14073,7 +14073,7 @@ EOF break_end return 1 fi - echo "✅ 已恢复 includeDefaultMemory=true" + echo "✅ 已恢復 includeDefaultMemory=true" openclaw_memory_rebuild_index_all else echo "已取消。" @@ -14197,7 +14197,7 @@ EOF local start_line count echo "文件:$file" echo "總行數:$total_lines" - read -e -p "请输入起始行(回车默认末尾 $default_lines行):" start_line + read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line read -e -p "請輸入顯示行數(回車預設$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then @@ -14607,10 +14607,10 @@ print(json.dumps(data, indent=2)) echo -e "當前綜合安全等級:${current_mode}" echo "---------------------------------------" echo -e "${gl_huang}[應用層 Tool Policy 狀態]${gl_bai}" - echo " Profile (预设): ${current_profile:-(unset)}" + echo "Profile (預設): ${current_profile:-(unset)}" echo "Exec 限制: ${current_sec:-(unset)}" echo "審核提示: ${current_ask:-(unset)}" - echo " 提权开关: ${current_elevated:-(unset)}" + echo "提權開關: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[底層 Exec Approvals 狀態]${gl_bai}" if openclaw_has_command openclaw; then @@ -14652,7 +14652,7 @@ try: print("提示策略 (Ask):" + str(d.get("ask", "(unset)"))) print("無UI兜底 (AskFallback):" + str(d.get("askFallback", "(unset)"))) except Exception: - print(" (配置文件解析失败)") + print("(設定檔解析失敗)") ' else echo "(未配置,強制使用系統內建安全兜底策略)" @@ -14675,7 +14675,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切换为标准安全模式 (所有危险命令将通过UI/TG请求你的审批)${gl_bai}" + echo -e "${gl_lv}✅ 已切換為標準安全模式 (所有危險命令將透過UI/TG請求你的批准)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14693,7 +14693,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切换为开发增强模式 (允许提权,但常规危险命令依然需要审批)${gl_bai}" + echo -e "${gl_lv}✅ 已切換為開發增強模式 (允許提權,但常規危險命令仍需審批)${gl_bai}" } openclaw_permission_apply_full() { @@ -14708,7 +14708,7 @@ except Exception: openclaw config set tools.exec.strictInlineEval false >/dev/null 2>&1 echo "正在瓦解宿主機攔截防禦..." - # 这里的 full 和 off 将彻底绕过底层宿主机的 exec 审批系统 + # 這裡的 full 和 off 將徹底繞過底層宿主機的 exec 審批系統 openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway @@ -14719,7 +14719,7 @@ except Exception: send_stats "OpenClaw權限-恢復官方默認" openclaw_permission_require_openclaw || return 1 - echo "清理应用层强制覆盖..." + echo "清理應用層強制覆蓋..." openclaw config unset tools.profile >/dev/null 2>&1 openclaw config unset tools.exec.security >/dev/null 2>&1 openclaw config unset tools.exec.ask >/dev/null 2>&1 @@ -14735,12 +14735,12 @@ except Exception: fi openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已恢復到 OpenClaw 官方安全沙盒防禦機制${gl_bai}" + echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" } openclaw_permission_run_audit() { echo "=======================================" - echo "運行 OpenClaw 官方安全審計與體檢..." + echo "运行 OpenClaw 官方安全审计与体检..." echo "=======================================" openclaw security audit echo "---------------------------------------" @@ -14845,7 +14845,7 @@ except Exception as e: break_end ;; 3) - echo -e "${gl_hong}⚠️ 完全开放模式会彻底瓦解 exec 审批并自动放行高危代码。${gl_bai}" + echo -e "${gl_hong}⚠️ 完全開放模式會徹底瓦解 exec 審核並自動放行高風險程式碼。${gl_bai}" read -e -p "輸入 FULL 確認繼續:" confirm if [ "$confirm" = "FULL" ]; then openclaw_permission_apply_full; else echo "已取消"; fi break_end @@ -14946,7 +14946,7 @@ except Exception: return 0 fi fi - # 回退:從設定檔讀取 + # 回退:从配置文件读取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -15127,7 +15127,7 @@ for idx,item in enumerate(agents,1): read -e -p "輸入 DELETE 確認刪除${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "已取消"; return 1; } if openclaw agents delete "$agent_id"; then - echo "✅ 智能体删除成功: $agent_id" + echo "✅ 智能體刪除成功:$agent_id" else echo "❌ 智能體刪除失敗" return 1 @@ -15154,7 +15154,7 @@ for idx,item in enumerate(bindings,1): local agent_id bind_value confirm read -e -p "請輸入智能體 ID:" agent_id read -e -p "請輸入路由綁定值(如 telegram:ops / discord:guild-a):" bind_value - { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:参数不能为空。" && return 1 + { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "已取消:參數不能為空​​。" && return 1 echo "將綁定智能體 [$agent_id] -> [$bind_value]" read -e -p "輸入 yes 確認繼續:" confirm [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } @@ -15374,7 +15374,7 @@ openclaw_backup_restore_menu() { npm uninstall -g openclaw crontab -l 2>/dev/null | grep -v "s gateway" | crontab - rm -rf "$HOME/.openclaw" - [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 检测到 root 目录下仍存在 /root/.openclaw,如需清理请手动处理" + [ "$HOME" != "/root" ] && [ -d /root/.openclaw ] && echo "⚠️ 偵測到 root 目錄下仍存在 /root/.openclaw,如需清理請手動處理" hash -r sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "卸載完成" @@ -15382,7 +15382,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "编辑 OpenClaw 配置文件" + send_stats "編輯 OpenClaw 設定檔" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15430,7 +15430,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15628,7 +15628,7 @@ while true; do echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm遠端連線工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" @@ -15664,7 +15664,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -15675,7 +15675,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" - echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看开发者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -16166,7 +16166,7 @@ while true; do } local docker_describe="禪道是通用的專案管理軟體" - local docker_url="官网介绍: https://www.zentao.net/" + local docker_url="官網介紹: https://www.zentao.net/" local docker_use="echo \"初始使用者名稱: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" @@ -16308,7 +16308,7 @@ while true; do } - local docker_describe="Speedtest测速面板是一个VPS网速测试工具,多项测试功能,还可以实时监控VPS进出站流量" + local docker_describe="Speedtest測速面板是VPS網路速度測試工具,多項測試功能,還可以即時監控VPS進出站流量" local docker_url="官網介紹:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -16387,7 +16387,7 @@ while true; do check_docker_app clear echo -e "雷池服務$check_docker" - echo "雷池是长亭科技开发的WAF站点防火墙程序面板,可以反代站点进行自动化防御" + echo "雷池是長亭科技開發的WAF站點防火牆程式面板,可反代站點進行自動化防禦" echo "影片介紹: https://www.bilibili.com/video/BV1mZ421T74c?t=0.1" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then check_docker_app_ip @@ -16577,7 +16577,7 @@ while true; do } - local docker_describe="webtop基于Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" + local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16599,7 +16599,7 @@ while true; do } local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" - local docker_url="官網介紹: https://nextcloud.com/" + local docker_url="官网介绍: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" @@ -16618,7 +16618,7 @@ while true; do } - local docker_describe="QD-Today是一个HTTP请求定时任务自动执行框架" + local docker_describe="QD-Today是HTTP請求定時任務自動執行框架" local docker_url="官網介紹: https://qd-today.github.io/qd/zh_CN/" local docker_use="" local docker_passwd="" @@ -16683,7 +16683,7 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_describe="searxng是一個私有且隱私的搜尋引擎站點" local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" @@ -16919,7 +16919,7 @@ while true; do } - local docker_describe="Bililive-go是一個支援多種直播平台的直播錄製工具" + local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" local docker_url="官網介紹:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" @@ -17248,7 +17248,7 @@ while true; do } - local docker_describe="OpenWebUI一款大语言模型网页框架,接入全新的llama3大语言模型" + local docker_describe="OpenWebUI一款大語言模型網頁框架,連結全新的llama3大語言模型" local docker_url="官網介紹:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17605,7 +17605,7 @@ while true; do } - local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" + local docker_describe="自動將你的公網 IP(IPv4/IPv6)即時更新到各大 DNS 服務商,實現動態網域解析。" local docker_url="官網介紹:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" @@ -17790,7 +17790,7 @@ while true; do local app_id="74" - local app_name="moontv私有影视" + local app_name="moontv私有影視" local app_text="免費線上影片搜尋與觀看平台" local app_url="影片介紹:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" @@ -18001,7 +18001,7 @@ while true; do install git openssl mkdir -p /home/docker/linkwarden && cd /home/docker/linkwarden - # 下载官方 docker-compose 和 env 文件 + # 下載官方 docker-compose 和 env 文件 curl -O ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml curl -L ${gh_proxy}raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env" @@ -18133,7 +18133,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -18221,7 +18221,7 @@ while true; do local app_id="85" local app_name="immich圖片影片管理器" - local app_text="高性能自托管照片和视频管理解决方案。" + local app_text="高效能自架照片和影片管理解決方案。" local app_url="官網介紹:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" @@ -18346,7 +18346,7 @@ while true; do local docker_describe="開源、免費的自建直播平台" local docker_url="官網介紹: https://owncast.online" - local docker_use="echo \"访问地址后面带 /admin 访问管理员页面\"" + local docker_use="echo \"訪問地址後面帶 /admin 訪問管理員頁面\"" local docker_passwd="echo \"初始帳號: admin 初始密碼: abc123 登陸後請及時修改登入密碼\"" local app_size="1" docker_app @@ -18412,7 +18412,7 @@ while true; do --restart=always \ matrixdotorg/synapse:latest - echo "建立初始使用者或管理員。请设置以下内容用户名和密码以及是否为管理员。" + echo "建立初始使用者或管理員。請設定以下內容使用者名稱和密碼以及是否為管理員。" docker exec -it matrix register_new_matrix_user \ http://localhost:8008 \ -c /data/homeserver.yaml @@ -18445,7 +18445,7 @@ while true; do local app_id="91" local app_name="gitea私有程式碼倉庫" - local app_text="免費新一代的程式碼託管平台,提供接近 GitHub 的使用體驗。" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" local app_url="影片介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" @@ -18690,7 +18690,7 @@ while true; do read -e -p "請輸入組網的用戶端數量 (預設 5):" COUNT COUNT=${COUNT:-5} - read -e -p "请输入 WireGuard 网段 (默认 10.13.13.0): " NETWORK + read -e -p "請輸入 WireGuard 網段 (預設 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -18767,7 +18767,7 @@ while true; do echo -e "${gl_huang}所有客戶端配置代碼:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" + echo -e "${gl_lv}${COUNT}個客戶端配置全部輸出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 手機下載wg的APP,掃描上方二維碼,可快速連接網絡${gl_bai}" echo -e "${gl_lv}2. Windows下載客戶端,複製設定碼連接網路。${gl_bai}" echo -e "${gl_lv}3. Linux用腳本部署WG客戶端,複製設定碼連接網路。${gl_bai}" @@ -18944,7 +18944,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19294,7 +19294,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) local docker_port=8112 docker_rum() { @@ -19380,7 +19380,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 添加等待时间 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no "$latest_tar" "root@$remote_ip:/" - echo "文件已传送至远程服务器/根目录。" + echo "檔案已傳送至遠端伺服器/根目錄。" else echo "未找到要傳送的文件。" fi @@ -19402,7 +19402,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ echo "-------------------------" ls -lt /app*.gz | awk '{print $NF}' echo "" - read -e -p "回車鍵還原最新的備份,輸入備份檔名還原指定的備份,輸入0退出:" filename + read -e -p "回車鍵還原最新的備份,輸入備份檔案名稱還原指定的備份,輸入0退出:" filename if [ "$filename" == "0" ]; then break_end @@ -19793,7 +19793,7 @@ net_menu() { case $choice in 1) send_stats "啟用網卡" - read -erp "请输入要启用的网卡名: " nic + read -erp "請輸入要啟用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" else @@ -19880,7 +19880,7 @@ log_menu() { if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else - echo "✘ 服务不存在或无日志" + echo "✘ 服務不存在或無日誌" fi read -erp "按回車繼續..." ;; @@ -20180,7 +20180,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -20190,7 +20190,7 @@ linux_Settings() { ln -sf /usr/local/bin/k /usr/local/bin/$kuaijiejian fi ln -sf /usr/local/bin/k /usr/bin/$kuaijiejian > /dev/null 2>&1 - echo "快捷键已设置" + echo "快速鍵已設定" send_stats "腳本快捷鍵已設定" break_end linux_Settings @@ -20214,12 +20214,12 @@ linux_Settings() { echo "python版本管理" echo "影片介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "该功能可无缝安装python官方支持的任何版本!" + echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "目前python版本號:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推薦版本: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "查询更多版本: https://www.python.org/downloads/" + echo "查詢更多版本: https://www.python.org/downloads/" echo "------------" read -e -p "輸入你要安裝的python版本號碼(輸入0退出):" py_new_v @@ -20739,7 +20739,7 @@ EOF case $choice in 1) - send_stats "中国大陆默认源" + send_stats "中國大陸預設來源" bash <(curl -sSL https://linuxmirrors.cn/main.sh) ;; 2) @@ -20774,7 +20774,7 @@ EOF echo "" echo "操作" echo "------------------------" - echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" + echo "1. 新增定時任務 2. 刪除定時任務 3. 編輯定時任務" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20795,7 +20795,7 @@ EOF (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) - read -e -p "选择周几执行任务? (0-6,0代表星期日): " weekday + read -e -p "選擇週幾執行任務? (0-6,0代表星期日):" weekday (crontab -l ; echo "0 0 * * $weekday $newquest") | crontab - > /dev/null 2>&1 ;; 3) @@ -20854,7 +20854,7 @@ EOF ;; 2) - read -e -p "请输入需要删除的解析内容关键字: " delhost + read -e -p "請輸入需要刪除的解析內容關鍵字:" delhost sed -i "/$delhost/d" /etc/hosts send_stats "本機host解析刪除" ;; @@ -20889,7 +20889,7 @@ EOF local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) echo -e "${gl_lv}目前設定的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" - echo -e "${gl_lv}当前设置的出站限流阈值为: ${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" + echo -e "${gl_lv}目前設定的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}目前未啟用限流關機功能${gl_bai}" fi @@ -21103,7 +21103,7 @@ EOF echo "一條龍系統調優" echo "------------------------------------------------" echo "將對以下內容進行操作與優化" - echo "1. 优化系统更新源,更新系统到最新" + echo "1. 最佳化系統更新來源,更新系統到最新" echo "2. 清理系統垃圾文件" echo -e "3. 設定虛擬內存${gl_huang}1G${gl_bai}" echo -e "4. 設定SSH埠號為${gl_huang}5522${gl_bai}" @@ -21125,7 +21125,7 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系統到最新" echo "------------------------------------------------" linux_clean @@ -21316,7 +21316,7 @@ linux_file() { case "$Limiting" in 1) # 进入目录 - read -e -p "请输入目录名: " dirname + read -e -p "請輸入目錄名:" dirname cd "$dirname" 2>/dev/null || echo "無法進入目錄" send_stats "進入目錄" ;; @@ -21344,7 +21344,7 @@ linux_file() { ;; 6) # 返回上一级选单目录 cd .. - send_stats "返回上一级选单目录" + send_stats "返回上一層選單目錄" ;; 11) # 创建文件 read -e -p "請輸入要建立的檔案名稱:" filename @@ -21381,7 +21381,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "请输入要解压的文件名 (.tar.gz): " filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21403,7 +21403,7 @@ linux_file() { fi mv "$src_path" "$dest_path" && echo "檔案或目錄已移動到$dest_path" || echo "移動檔案或目錄失敗" - send_stats "移动文件或目录" + send_stats "移動檔案或目錄" ;; @@ -21444,7 +21444,7 @@ linux_file() { kj_ssh_read_password "請輸入遠端伺服器密碼:" local remote_password="$KJ_SSH_PASSWORD" - # 清除已知主机的旧条目 + # 清除已知主機的舊條目 ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 @@ -21651,17 +21651,17 @@ echo "------------------------" echo -e "${gl_zi}Hostinger 52.7刀每年 美國 1核心 4G記憶體 50G硬碟 4T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" echo "------------------------" -echo -e "${gl_huang}搬瓦工 49刀每季 美国CN2GIA 日本软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" +echo -e "${gl_huang}搬運工 49刀每季 美國CN2GIA 日本軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://bandwagonhost.com/aff.php?aff=69004&pid=87${gl_bai}" echo "------------------------" echo -e "${gl_lan}DMIT 28刀每季 美國CN2GIA 1核心 2G記憶體 20G硬碟 800G流量每月${gl_bai}" echo -e "${gl_bai}網址: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 6.9刀每月 东京软银 2核心 1G内存 20G硬盘 1T流量每月${gl_bai}" +echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" -echo -e "${gl_bai}网址: https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "網域優惠" @@ -21780,7 +21780,7 @@ while true; do echo "------------------------" echo "1. 現在更新 2. 開啟自動更新 3. 關閉自動更新" echo "------------------------" - echo "0. 返回主菜单" + echo "0. 返回主選單" echo "------------------------" read -e -p "請輸入你的選擇:" choice case "$choice" in @@ -21817,7 +21817,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下载出错或文件校验不通过,已恢复原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21957,26 +21957,26 @@ echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" echo "系統回收站 k trash | k hsz | k 回收站" echo "系統備份功能 k backup | k bf | k 備份" -echo "ssh远程连接工具 k ssh | k 远程连接" +echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" echo "軟體停止 k stop sshd | k 停止 sshd" -echo "软件重启 k restart sshd | k 重启 sshd " +echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" -echo "软件开机启动 k enable docker | k autostart docke | k 开机启动 docker " +echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" echo "網域名稱憑證到期查詢 k ssl ps" echo "docker管理平面 k docker" echo "docker環境安裝 k docker install |k docker 安裝" echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" +echo "docker映像管理 k docker img |k docker 映像" echo "LDNMP站台管理 k web" echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" -echo "安装反向代理 k fd |k rp |k 反代 |k fd xxx.com" +echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" @@ -22088,7 +22088,7 @@ else time|时区) shift - send_stats "快速设置时区" + send_stats "快速設定時區" set_timedate "$@" ;; From 1c412559b9d8c09a63bfb1eee764bf7ce1d58df0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 5 Jul 2026 05:50:58 +0000 Subject: [PATCH 1204/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-07-05=2005:50:58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 62 ++++++++--------- jp/kejilion.sh | 122 ++++++++++++++++---------------- kr/kejilion.sh | 90 ++++++++++++------------ tw/kejilion.sh | 184 ++++++++++++++++++++++++------------------------- 4 files changed, 229 insertions(+), 229 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 41e3c9fff..aee9be2ec 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add shutdown rule + # Add a shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3691,7 +3691,7 @@ stream_panel() { send_stats "Update Stream four-layer proxy" echo "nginx container has been deleted." else - echo "The operation has been cancelled." + echo "操作已取消。" fi ;; @@ -4395,7 +4395,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4492,7 +4492,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -5097,7 +5097,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -7344,10 +7344,10 @@ list_tasks() { # Add new task add_task() { - send_stats "添加新同步任务" + send_stats "Add new sync task" echo "Example of creating a new sync task:" echo "- Task name: backup_www" - echo " - 本地目录: /var/www" + echo "- Local directory: /var/www" echo "- Remote address: user@192.168.1.100" echo "- Remote directory: /backup/www" echo "- Port number (default 22)" @@ -16081,7 +16081,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -16135,7 +16135,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16233,7 +16233,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17119,7 +17119,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17346,7 +17346,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17398,7 +17398,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17439,7 +17439,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17502,7 +17502,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17830,7 +17830,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18051,7 +18051,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18115,7 +18115,7 @@ while true; do cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18251,7 +18251,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18478,7 +18478,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18616,7 +18616,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18670,7 +18670,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18903,7 +18903,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18974,7 +18974,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19043,7 +19043,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19184,7 +19184,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19254,7 +19254,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -20214,7 +20214,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -21112,7 +21112,7 @@ EOF echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" echo -e "8. Set time zone to${gl_huang}Shanghai${gl_bai}" echo -e "9. Automatically optimize DNS addresses${gl_huang}Overseas: 1.1.1.1 8.8.8.8 Domestic: 223.5.5.5${gl_bai}" - echo -e "10. Set the network to${gl_huang}ipv4 priority${gl_bai}" + echo -e "10. Set the network to${gl_huang}IPv4 priority${gl_bai}" echo -e "11. Install basic tools${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux system kernel parameter optimization${gl_huang}Automatically tune according to network environment${gl_bai}" echo "------------------------------------------------" @@ -21160,7 +21160,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. Automatically optimize DNS address${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}ipv4 priority${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. Set the network to${gl_huang}IPv4 priority${gl_bai}}" echo "------------------------------------------------" install_docker diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 6e5ed8137..3c156c1c3 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -867,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "ポートがオープンしました$port" fi done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -3278,7 +3278,7 @@ EOF } # メイン構成/オーバーレイ構成エディター (nano) を直接開きます。 -# /etc/fail2ban/jail.d/sshd.local を最初に編集し (より安全です)、存在しない場合は作成します +# 最初に /etc/fail2ban/jail.d/sshd.local を編集し (より安全です)、存在しない場合は作成します f2b_edit_config() { root_use install nano @@ -3512,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すとデフォルトでローカル IP 127.0.0.1 になります):" reverseproxy + read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すと、デフォルトのローカル IP 127.0.0.1 になります)。" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -5164,7 +5164,7 @@ sshkey_panel() { break_end ;; 4) - send_stats "导入URL远端公钥" + send_stats "URL リモート公開キーをインポートする" read -e -p "リモート公開キーの URL を入力してください:" keys_url fetch_remote_ssh_keys "${keys_url}" break_end @@ -5354,7 +5354,7 @@ dd_xitong() { ;; 2) - send_stats "重装debian 12" + send_stats "debian12を再インストールする" dd_xitong_3 bash reinstall.sh debian 12 reboot @@ -5951,7 +5951,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6015,7 +6015,7 @@ clamav() { break_end ;; 3) - send_stats "自定义目录扫描" + send_stats "カスタムディレクトリスキャン" read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories install_docker clamav_freshclam @@ -6043,7 +6043,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6827,7 +6827,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7196,7 +7196,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードドライブのパーティション管理" + echo "ハードディスクのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7327,7 +7327,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7364,7 +7364,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" + kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7496,7 +7496,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7586,7 +7586,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -8119,7 +8119,7 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自動生成された復元スクリプト" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" # パッケージ化の繰り返しを避けるために、パッケージ化された Compose プロジェクトのパスを記録します。 declare -A PACKED_COMPOSE_PATHS=() @@ -8556,7 +8556,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -8787,7 +8787,7 @@ linux_test() { echo "成都電信: 61.139.2.69" echo "成都チャイナユニコム: 119.6.6.6" echo "成都携帯電話: 211.137.96.205" - echo "湖南電信: 36.111.200.100" + echo "湖南电信: 36.111.200.100" echo "湖南ユニコム: 42.48.16.100" echo "湖南省モバイル: 39.134.254.6" echo "------------------------" @@ -8899,7 +8899,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -11852,7 +11852,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12938,7 +12938,7 @@ if os.path.isdir(agents_root): echo "バックアップモード:" echo "1. セーフ モード (デフォルト、推奨): ワークスペース + openclaw.json + 拡張機能/スキル/プロンプト/ツール (存在する場合)" - echo "2. 完全モード (より多くの状態が含まれ、機密性のリスクが高くなります)" + echo "2. 完全モード (より多くの状態が含まれ、機密リスクが高くなります)" read -e -p "バックアップ モードを選択してください (デフォルト 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -12995,7 +12995,7 @@ if os.path.isdir(agents_root): mkdir -p "$openclaw_root" echo "⚠️ リスクの高い操作: プロジェクトを復元すると、OpenClaw 構成とワークスペースのコンテンツが上書きされます。" - echo "⚠️マニフェスト/sha256の検証、ホワイトリストの復元、ゲートウェイのシャットダウン、ヘルスチェックが復元前に実行されます。" + echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" read -e -p "続行するには、確認の単語 [リスクが高いことを承知しており、復元を続行します] を入力してください:" confirm_text if [ "$confirm_text" != "高いリスクを認識しており、復旧を続けています" ]; then echo "❌ 確認ワードが一致しなかったため、リストアはキャンセルされました。" @@ -13208,7 +13208,7 @@ if os.path.isdir(agents_root): break_end return 0 fi - read -e -p "2 番目の確認: 「DELETE」と入力して削除します。" confirm_step2 + read -e -p "二次確認: 削除するには「DELETE」と入力します。" confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then echo "削除がキャンセルされました。" break_end @@ -13733,7 +13733,7 @@ PY openclaw_memory_render_auto_summary() { echo "---------------------------------------" - echo "✅ 环境就绪" + echo "✅ 環境準備完了" echo "スキーム: ${OPENCLAW_MEMORY_AUTO_SCHEME:-unknown}" if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then echo "モード: 設定の書き込みのみ (インストールされない/ダウンロードされない)" @@ -13783,7 +13783,7 @@ PY else echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi - echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in @@ -14034,7 +14034,7 @@ EOF } openclaw_memory_offer_restart() { - echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14196,9 +14196,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "総行数:$total_lines" + echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14293,7 +14293,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステート検出 (組み込みモデルのチェック)" + echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14311,7 +14311,7 @@ EOF if [ "$confirm_step2" = "force" ]; then echo "⚠️ 完全な再構築はより徹底的ですが、時間がかかります。" echo "推奨事項: 安全に再構築するには、再構築を入力してください (最初にインデックス データベースをバックアップします)。" - read -e -p "3 番目の確認: 安全な再構築を実行するには、「再構築」と入力します。 Enter キーを押して通常の力で続行します。" confirm_step3 + read -e -p "3 番目の確認: 「再構築」と入力して、安全な再構築を実行します。 Enter キーを押して通常の力で続行します。" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all else @@ -14606,7 +14606,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14712,7 +14712,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -15085,7 +15085,7 @@ else: openclaw_multiagent_list_agents() { send_stats "OpenClaw マルチエージェント - エージェントのリスト" python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); -if not agents: print("エージェントはまだ構成されていません。"); raise SystemExit(0) +if not agents: print("エージェントはまだ設定されていません。"); raise SystemExit(0) for idx,item in enumerate(agents,1): print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" } @@ -15095,8 +15095,8 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm read -e -p "新しいエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 - read -e -p "ワークスペースのパスを入力してください (デフォルトは ~/.openclaw/workspace-${agent_id}): " workspace + [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 + read -e -p "ワークスペースのパス (デフォルトは ~/.openclaw/workspace-) を入力してください。${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" @@ -15122,7 +15122,7 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id confirm read -e -p "削除するエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 echo "⚠️ エージェントを削除すると、その作業ディレクトリ、ルート バインディング、およびセッション ルーティングに影響する可能性があります。" read -e -p "「DELETE」と入力して削除を確認します${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "キャンセル"; return 1; } @@ -15173,7 +15173,7 @@ for idx,item in enumerate(bindings,1): read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" + echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15638,7 +15638,7 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" + echo -e "${gl_kjlan}59. ${color59}NewAPI 大型モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" @@ -15906,7 +15906,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -17172,7 +17172,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -18344,7 +18344,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -18690,7 +18690,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -19279,7 +19279,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19461,7 +19461,7 @@ linux_work() { echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19799,7 +19799,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19809,7 +19809,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19821,7 +19821,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19872,7 +19872,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19882,7 +19882,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19897,7 +19897,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19985,7 +19985,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -20000,7 +20000,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -20016,7 +20016,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -20029,7 +20029,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数(ソース)をリロードします。" + echo "6. 環境変数 (ソース) をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -21102,7 +21102,7 @@ EOF send_stats "ワンストップチューニング" echo "ワンストップのシステムチューニング" echo "------------------------------------------------" - echo "以下のコンテンツを運用・最適化していきます" + echo "将对以下内容进行操作与优化" echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" @@ -21339,7 +21339,7 @@ linux_file() { ;; 5) # 删除目录 read -e -p "削除するディレクトリ名を入力してください:" dirname - rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "删除失败" + rm -rf "$dirname" && echo "ディレクトリが削除されました" || echo "削除に失敗しました" send_stats "ディレクトリを削除する" ;; 6) # 返回上一级选单目录 @@ -21538,7 +21538,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21576,7 +21576,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -21657,7 +21657,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" @@ -21947,7 +21947,7 @@ echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" echo "システム k 更新を更新します。 kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 3d630d1a6..b3b502f78 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다." + waf_status="WAF가 켜져 있습니다" else waf_status="" fi @@ -4782,7 +4782,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5725,7 +5725,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" server_reboot } @@ -5735,7 +5735,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" server_reboot } @@ -5885,7 +5885,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -5939,7 +5939,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 드라이브 파티션 관리" + echo "하드 디스크 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8237,7 +8237,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8372,7 +8372,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8572,7 +8572,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9626,7 +9626,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -12690,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13028,7 +13028,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13148,7 +13148,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 백업 파일 삭제" + send_stats "OpenClaw 삭제 백업 파일" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13783,7 +13783,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -13834,7 +13834,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다." + echo "✅ memory.qmd.command가 정확합니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -14080,7 +14080,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14109,7 +14109,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14324,7 +14324,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -15546,7 +15546,7 @@ openclaw_backup_restore_menu() { openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 수리" + 12) send_stats "상태 감지 및 복구" openclaw doctor --fix break_end ;; @@ -15618,7 +15618,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15646,7 +15646,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15675,7 +15675,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15877,7 +15877,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16577,7 +16577,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16743,7 +16743,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -17248,7 +17248,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17410,7 +17410,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -18373,7 +18373,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -19294,7 +19294,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # Lucky는 호스트 네트워크 모드를 사용하므로 여기의 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). + # Lucky는 호스트 네트워크 모드를 사용하므로 여기서 포트는 기록/설명 참조용으로만 사용되며 실제로는 애플리케이션 자체에 의해 제어됩니다(기본값 16601). local docker_port=8112 docker_rum() { @@ -20024,7 +20024,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20143,10 +20143,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20156,7 +20156,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20696,7 +20696,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20791,7 +20791,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 달의 날짜는 무엇입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -21501,7 +21501,7 @@ run_commands_on_servers() { # 추출된 정보를 배열로 변환 IFS=$'\n' read -r -d '' -a SERVER_ARRAY <<< "$SERVERS" - # 서버를 순회하고 명령을 실행합니다. + # 서버를 탐색하고 명령을 실행합니다. for ((i=0; i<${#SERVER_ARRAY[@]}; i+=5)); do local name=${SERVER_ARRAY[i]} local hostname=${SERVER_ARRAY[i+1]} @@ -21584,7 +21584,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21657,7 +21657,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21975,17 +21975,17 @@ echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" echo "LDNMP 사이트 관리 k web" echo "LDNMP 캐시 정리 k 웹 캐시" -echo "WordPress k wp 설치 | k 워드프레스 | kwp xxx.com" +echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index e7a256a38..c3e430e7b 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -36,7 +36,7 @@ quanju_canshu -# 定义一个函数来执行命令 +# 定義一個函數來執行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -179,7 +179,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供軟體包參數!" + echo "未提供软件包参数!" return 1 fi @@ -620,7 +620,7 @@ docker_image() { while true; do clear send_stats "Docker映像管理" - echo "Docker映像列表" + echo "Docker镜像列表" docker image ls echo "" echo "鏡像操作" @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "網站資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1541,8 +1541,8 @@ certs_status() { else send_stats "網域證書申請失敗" echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" - echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" - echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" + echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" @@ -1753,7 +1753,7 @@ cf_purge_cache() { echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN read -e -p "請輸入你的CF用戶名:" EMAIL - read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS + read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" @@ -2242,7 +2242,7 @@ web_security() { echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" - echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "輸入CF的帳號:" cfuser @@ -2336,7 +2336,7 @@ check_nginx_compression() { br_status="" fi - # 檢查 gzip 是否開啟且未被註釋 + # 检查 gzip 是否开启且未被注释 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2965,7 +2965,7 @@ while true; do ;; 8) - send_stats "阻止IP訪問${docker_name}" + send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -3237,7 +3237,7 @@ f2b_basic_config() { local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # Alpine 預設 jail 通常為 sshd;僅當偵測到自訂 alpine-sshd 規則時才切換 + # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi @@ -3284,7 +3284,7 @@ f2b_edit_config() { install nano if [ ! -d /etc/fail2ban ]; then - echo -e "${gl_hui}/etc/fail2ban 不存在,请先安装 fail2ban。${gl_bai}" + echo -e "${gl_hui}/etc/fail2ban 不存在,請先安裝 fail2ban。${gl_bai}" return fi @@ -3893,7 +3893,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -3932,9 +3932,9 @@ ldnmp_web_status() { ;; 4) send_stats "建立關聯站點" - echo -e "為現有的站點再關聯一個新網域用於訪問" + echo -e "为现有的站点再关联一个新域名用于访问" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域名稱:" yuming + read -e -p "請輸入新網域:" yuming install_certbot install_ssltls certs_status @@ -4017,7 +4017,7 @@ while true; do echo "" echo "------------------------" - echo "1. 安装 2. 管理 3. 卸载" + echo "1. 安裝 2. 管理 3. 卸載" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -4172,7 +4172,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4471,7 +4471,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP客戶端已經安裝完成" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4544,7 +4544,7 @@ yt_menu_pro() { echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "已下載影片清單:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" echo "-------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" @@ -5030,7 +5030,7 @@ fetch_remote_ssh_keys() { # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } @@ -5141,7 +5141,7 @@ sshkey_panel() { echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" - echo "3. 从GitHub导入已有公钥 4. 从URL导入已有公钥" + echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" @@ -5154,7 +5154,7 @@ sshkey_panel() { break_end ;; 2) - send_stats "導入已有公鑰" + send_stats "导入已有公钥" import_sshkey break_end ;; @@ -5631,7 +5631,7 @@ bbrv3() { install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then - echo "官方金鑰下載失敗,嘗試備用下載來源..." + echo "官方密钥下载失败,尝试备用下载源..." wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" @@ -5856,7 +5856,7 @@ elrepo_install() { elrepo() { root_use - send_stats "红帽内核管理" + send_stats "紅帽內核管理" if uname -r | grep -q 'elrepo'; then while true; do clear @@ -5943,7 +5943,7 @@ clamav_scan() { return fi - echo -e "${gl_kjlan}正在掃描目錄$@...${gl_bai}" + echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" # 建構 mount 參數 local MOUNT_PARAMS="" @@ -6168,7 +6168,7 @@ net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 遊戲服場景額外:低延遲優先 ── + # ── 游戏服场景额外:低延迟优先 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" @@ -6203,7 +6203,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 核心調優配置 +# kejilion 内核调优配置 # 模式: $mode_name | 場景: $scene # 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') @@ -6300,9 +6300,9 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" + echo -e "${gl_lv}已应用 ${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" - # ── 透明大頁面 ── + # ── 透明大页面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi @@ -6734,7 +6734,7 @@ create_backup() { local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" # 列印使用者選擇的目錄 - echo "您選擇的備份目錄為:" + echo "您选择的备份目录为:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done @@ -6771,7 +6771,7 @@ restore_backup() { if [ $? -eq 0 ]; then echo "備份恢復成功!" else - echo "備份恢復失敗!" + echo "备份恢复失败!" exit 1 fi } @@ -6911,7 +6911,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "錯誤: SSH 使用者名稱格式不正確。" + echo "错误: SSH 用户名格式不正确。" return 1 fi @@ -7041,7 +7041,7 @@ delete_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果連接使用的是密鑰文件,則刪除該密鑰文件 + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -7314,7 +7314,7 @@ disk_manager() { list_partitions echo "------------------------" echo "1. 掛載分割區 2. 卸載分割區 3. 檢視已掛載分割區" - echo "4. 格式化分割區 5. 檢查分割區狀態" + echo "4. 格式化分区 5. 检查分区状态" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7446,7 +7446,7 @@ run_task() { # 根據同步方向調整來源和目標路徑 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" + echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -7570,7 +7570,7 @@ rsync_manager() { view_tasks echo echo "1. 建立新任務 2. 刪除任務" - echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" @@ -8887,7 +8887,7 @@ linux_Oracle() { 1) clear echo "活躍腳本: CPU佔用10-20% 記憶體佔用20%" - read -e -p "确定安装吗? (Y/N):" choice + read -e -p "確定安裝嗎? (Y/N):" choice case "$choice" in [Yy]) @@ -8900,16 +8900,16 @@ linux_Oracle() { local DEFAULT_SPEEDTEST_INTERVAL=120 # 提示使用者輸入CPU核心數和占用百分比,如果回車則使用預設值 - read -e -p "请输入CPU核心数 [默认: $DEFAULT_CPU_CORE]: " cpu_core + read -e -p "請輸入CPU核心數 [預設:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "請輸入CPU佔用百分比範圍(例如10-20) [預設:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util + read -e -p "請輸入記憶體佔用百分比 [預設:$DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} - read -e -p "请输入Speedtest间隔时间(秒) [默认: $DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval + read -e -p "請輸入Speedtest間隔時間(秒) [預設:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} # 運行Docker容器 @@ -8935,7 +8935,7 @@ linux_Oracle() { clear docker rm -f lookbusy docker rmi fogforest/lookbusy - send_stats "甲骨文云卸载活跃脚本" + send_stats "甲骨文雲端卸載活躍腳本" ;; 3) @@ -8948,7 +8948,7 @@ linux_Oracle() { case "$choice" in [Yy]) while true; do - read -e -p "请选择要重装的系统: 1. Debian12 | 2. Ubuntu20.04 : " sys_choice + read -e -p "請選擇要重裝的系統: 1. Debian12 | 2. Ubuntu20.04 :" sys_choice case "$sys_choice" in 1) @@ -9086,7 +9086,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo部落格網站" echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" - echo -e "${gl_huang}29. ${gl_bai}Stream四层代理转发 ${gl_huang}30. ${gl_bai}自訂靜態站點" + echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" @@ -9390,7 +9390,7 @@ linux_ldnmp() { clear ldnmp_web_on - echo "資料庫前綴: typecho_" + echo "数据库前缀: typecho_" echo "資料庫位址: mysql" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" @@ -9536,7 +9536,7 @@ linux_ldnmp() { echo ;; 2) - echo "数据库备份必须是.gz结尾的压缩包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" + echo "資料庫備份必須是.gz結尾的壓縮包。請放到/home/目錄下,支援寶塔/1panel備份資料導入。" read -e -p "也可以輸入下載鏈接,遠端下載備份數據,直接回車將跳過遠端下載:" url_download_db cd /home/ @@ -10247,7 +10247,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未偵測到 API providers,跳過模型同步') + print('ℹ️ 未检测到 API providers,跳过模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10350,11 +10350,11 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} 指向該 provider,但無可用替代模型,已中止刪除') + summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') return False defaults[fk] = repl changed = True - summary.append(f'🔁 刪除前已切換 {fk}: {val} -> {repl}') + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') return True @@ -10416,14 +10416,14 @@ for name, provider in list(providers.items()): continue if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 發現非法協定 {api or "(unset)"},將重新探測') + summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') provider['api'] = '' api = '' changed = True data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: - summary.append(f'⚠️ {name}: /models 偵測失敗,已重試 {attempts} 次 ({type(err).__name__}: {err})') + summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') send_stat('OpenClaw API確認介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) @@ -10431,7 +10431,7 @@ for name, provider in list(providers.items()): send_stat('OpenClaw API刪失敗Provider-確認') summary.append(f'✅ {name}: 使用者已確認刪除該 provider 及全部相關模型引用') else: - send_stat('OpenClaw API删失败Provider-拒绝') + send_stat('OpenClaw API刪失敗Provider-拒絕') summary.append(f'ℹ️ {name}: 使用者未確認刪除,保留現有 provider 配置') continue @@ -10539,7 +10539,7 @@ if changed: f.write('\n') for line in summary: print(line) - print('✅ OpenClaw API 模型一致性同步完成並已寫入配置') + print('✅ OpenClaw API 模型一致性同步完成并已写入配置') else: for line in summary: print(line) @@ -10602,7 +10602,7 @@ PY # OpenClaw API 協定偵測邏輯已移除:不再自動偵測/判定 API 類型。 - # 說明:API 類型由使用者明確配置(models.providers..api),腳本不再嘗試呼叫 /responses 做推論。 + # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 # 建構模型配置 JSON build-openclaw-provider-models-json() { @@ -10757,7 +10757,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 預設模型不能為空" + echo "❌ 默认模型不能为空" return 1 fi @@ -10778,7 +10778,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11015,7 +11015,7 @@ sync-openclaw-provider-interactive() { if sync_openclaw_api_models; then start_gateway else - echo "❌ API 模型同步失败,已中止重启网关。請檢查 provider /models 返回後重試。" + echo "❌ API 模型同步失敗,已中止重新啟動網關。請檢查 provider /models 返回後重試。" return 1 fi break_end @@ -11114,7 +11114,7 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,無法執行同步') raise SystemExit(3) if api not in SUPPORTED_APIS: @@ -11223,20 +11223,20 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同步執行完成" + echo "✅ 同步执行完成" start_gateway ;; 2) echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失敗:provider 配置不完整或類型不支持" + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失敗:上游模型為空或同步後無可用模型" + echo "❌ 同步失败:上游模型为空或同步后无可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -11249,7 +11249,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 # 保留函數以相容選單調用,但不做任何改寫。 - echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" + echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -11270,7 +11270,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "請選擇要設定的 API 類型:" + echo "请选择要设置的 API 类型:" echo "1. openai-completions" echo "2. openai-responses" read -erp "請輸入你的選擇 (1/2):" proto_choice @@ -11280,7 +11280,7 @@ fix-openclaw-provider-protocol-interactive() { 1) new_api="openai-completions" ;; 2) new_api="openai-responses" ;; *) - echo "❌ 無效選擇" + echo "❌ 无效选择" break_end return 1 ;; @@ -11325,7 +11325,7 @@ PY start_gateway ;; 2) - echo "❌ 切換失敗:provider 不存在或未配置" + echo "❌ 切换失败:provider 不存在或未配置" ;; 3) echo "❌ 切換失敗:協定值非法" @@ -11439,7 +11439,7 @@ replacement = replacement_candidates[0] if replacement_candidates else None primary_ref = get_primary_ref(defaults) if ref_provider(primary_ref) == name: if not replacement: - print('❌ 删除中止:默认主模型指向该 provider,且无可用替代模型') + print('❌ 刪除中止:預設主模型指向該 provider,且無可用替代模型') raise SystemExit(3) set_primary_ref(defaults, replacement) print(f'🔁 預設主模型切換: {primary_ref} -> {replacement}') @@ -11481,7 +11481,7 @@ PY echo "❌ 刪除失敗:無可用替代模型,已保持原始配置" ;; *) - echo "❌ 删除失败:请检查配置文件结构或日志输出" + echo "❌ 刪除失敗:請檢查設定檔結構或日誌輸出" ;; esac @@ -12287,7 +12287,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在刪除/停用插件:$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ 已卸載:$plugin_id" @@ -12690,7 +12690,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13574,7 +13574,7 @@ PY fi case "$model_status" in ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案存在") ;; - hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型來自 HF 下載來源(國內可能慢/失敗)") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then @@ -13973,7 +13973,7 @@ EOF while true; do clear echo "=======================================" - echo "記憶方案自動部署" + echo "记忆方案自动部署" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14292,7 +14292,7 @@ EOF echo "2. 檢視記憶文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" - echo "5. 搜尋測試(驗證索引是否運作)" + echo "5. 搜索测试(验证索引是否工作)" echo "6. 深度狀態探測(檢查嵌入模型)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14324,7 +14324,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -14735,12 +14735,12 @@ except Exception: fi openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已恢复到 OpenClaw 官方安全沙盒防御机制${gl_bai}" + echo -e "${gl_lv}✅ 已恢復到 OpenClaw 官方安全沙盒防禦機制${gl_bai}" } openclaw_permission_run_audit() { echo "=======================================" - echo "运行 OpenClaw 官方安全审计与体检..." + echo "運行 OpenClaw 官方安全審計與體檢..." echo "=======================================" openclaw security audit echo "---------------------------------------" @@ -14839,7 +14839,7 @@ except Exception as e: break_end ;; 2) - echo "準備應用:開發增強模式" + echo "准备应用:开发增强模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end @@ -14946,7 +14946,7 @@ except Exception: return 0 fi fi - # 回退:从配置文件读取 + # 回退:從設定檔讀取 local config_file config_file=$(openclaw_permission_config_file) if [ -s "$config_file" ]; then @@ -15112,7 +15112,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體創建失敗" + echo "❌ 智能體建立失敗" return 1 fi } @@ -15675,7 +15675,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" - echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看开发者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}想要讓你的應用程式出現在這裡?查看開發者指南:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -16599,7 +16599,7 @@ while true; do } local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" - local docker_url="官网介绍: https://nextcloud.com/" + local docker_url="官網介紹: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" @@ -16919,7 +16919,7 @@ while true; do } - local docker_describe="Bililive-go是一个支持多种直播平台的直播录制工具" + local docker_describe="Bililive-go是一個支援多種直播平台的直播錄製工具" local docker_url="官網介紹:${gh_proxy}github.com/hr3lxphr6j/bililive-go" local docker_use="" local docker_passwd="" @@ -17101,7 +17101,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼均為: admin" + echo "初始使用者名稱密碼皆為: admin" } docker_app_update() { @@ -18445,7 +18445,7 @@ while true; do local app_id="91" local app_name="gitea私有程式碼倉庫" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_text="免費新一代的程式碼託管平台,提供接近 GitHub 的使用體驗。" local app_url="影片介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" @@ -20180,7 +20180,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian + read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -20953,7 +20953,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21112,7 +21112,7 @@ EOF echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" + echo -e "10. 设置网络为${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" @@ -21304,7 +21304,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" + echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21335,7 +21335,7 @@ linux_file() { read -e -p "請輸入目前目錄名稱:" current_name read -e -p "請輸入新目錄名稱:" new_name mv "$current_name" "$new_name" && echo "目錄已重新命名" || echo "重新命名失敗" - send_stats "重新命名目錄" + send_stats "重命名目录" ;; 5) # 删除目录 read -e -p "請輸入要刪除的目錄名稱:" dirname @@ -21381,7 +21381,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21643,7 +21643,7 @@ echo "" echo -e "伺服器優惠" echo "------------------------" echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活動${gl_bai}" -echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" +echo -e "${gl_bai}网址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd 10.99刀每年 美國 1核心 1G記憶體 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" @@ -21817,7 +21817,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21982,7 +21982,7 @@ echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" From 42bd35965e2702389a0e36ea29cc2e056490fc6a Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 6 Jul 2026 15:43:33 +0800 Subject: [PATCH 1205/1285] Add TcpQuality test script --- cn/kejilion.sh | 7 +++++++ kejilion.sh | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a45f14b13..a055869d9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8702,6 +8702,7 @@ linux_test() { echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP重传探测脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}硬件性能测试" @@ -8809,6 +8810,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP重传探测脚本" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "yabs性能测试" diff --git a/kejilion.sh b/kejilion.sh index 48351a786..cf5f3af28 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -8708,6 +8708,7 @@ linux_test() { echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三网线路测试" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能测速脚本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP重传探测脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}硬件性能测试" @@ -8815,6 +8816,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP重传探测脚本" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "yabs性能测试" From 02de3ecca7c1bd44e09eaf811efb2d7cd737f4ce Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 12 Jul 2026 06:17:58 +0000 Subject: [PATCH 1206/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-07-12=2006:17:58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 147 +++++++++++++------------- jp/kejilion.sh | 275 +++++++++++++++++++++++++------------------------ kr/kejilion.sh | 257 +++++++++++++++++++++++---------------------- tw/kejilion.sh | 161 +++++++++++++++-------------- 4 files changed, 434 insertions(+), 406 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index aee9be2ec..8e9129591 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -890,7 +890,7 @@ close_port() { iptables -D INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null iptables -D INPUT -p udp --dport $port -j ACCEPT 2>/dev/null - # Add a shutdown rule + # Add shutdown rule if ! iptables -C INPUT -p tcp --dport $port -j DROP 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j DROP fi @@ -1748,7 +1748,7 @@ cf_purge_cache() { ZONE_IDS=($ZONE_IDS) else # Prompt user whether to clear cache - read -e -p "Need to clear Cloudflare's cache? (y/n):" answer + read -e -p "需要清理 Cloudflare 的缓存吗? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF information is stored in$CONFIG_FILE, you can modify the CF information later" read -e -p "Please enter your API_TOKEN:" API_TOKEN @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" send_stats "uninstall$docker_name" ;; @@ -3605,7 +3605,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -3691,7 +3691,7 @@ stream_panel() { send_stats "Update Stream four-layer proxy" echo "nginx container has been deleted." else - echo "操作已取消。" + echo "The operation has been cancelled." fi ;; @@ -4395,7 +4395,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4492,7 +4492,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; 4) @@ -5097,7 +5097,7 @@ fetch_github_ssh_keys() { local base_dir="${2:-$HOME}" echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" - echo "1. Login${gh_https_url}github.com/settings/keys" + echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5532,7 +5532,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall Windows 11" + send_stats "Reinstall windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "Partition successfully mounted to$MOUNT_POINT" + echo "The partition was successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard drive partition management" + echo "Hard disk partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7704,7 +7704,7 @@ linux_tools() { while true; do clear - # send_stats "Basic tools" + # send_stats "Basic Tools" echo -e "basic tools" tools=( @@ -8178,7 +8178,7 @@ docker_ssh_migration() { local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done - # Mirror + # mirror local IMAGE IMAGE=$(jq -r '.[0].Config.Image' "$inspect_file") @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8706,8 +8706,9 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP retransmission detection script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}Hardware performance testing" @@ -8815,6 +8816,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP retransmission detection script" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "yabs performance test" @@ -10092,7 +10099,7 @@ moltbot_menu() { return 1 fi - # Add --no-update-notifier and make sure error redirection is in the correct location + # Add --no-update-notifier and make sure error redirects are in the correct location local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10150,7 +10157,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API Management" + echo "6. API management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -11204,7 +11211,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: Added {len(added_ids)}, deleted {len(removed_ids)}, current {len(new_models)}') +print(f'✅ {target}: Add {len(added_ids)}, delete {len(removed_ids)}, current {len(new_models)}') if added_ids: print(f'➕ Add new model ({len(added_ids)}):') @@ -12218,7 +12225,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12346,7 +12353,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -13877,7 +13884,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ The model file already exists:$model_path" + echo "✅ Model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14080,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory configuration is normal." - echo "Will be executed: Clean old indexes → Fully rebuild all agent indexes" + echo "Will be executed: clean old indexes → fully rebuild all agent indexes" echo "" read -e -p "Confirm execution? (Y/n):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14198,7 +14205,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count + read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14215,7 +14222,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ Number of rows must be greater than 0." + echo "❌ The number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14575,7 +14582,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: Write the file directly + # Fallback: write file directly echo "$json_payload" > "$approvals_file" } @@ -14675,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ Switched to standard safety mode (all dangerous commands will ask for your approval through UI/TG)${gl_bai}" + echo -e "${gl_lv}✅ Switched to standard safe mode (all dangerous commands will request your approval through UI/TG)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14744,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "Attempt to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice + read -e -p "Do you want to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ Automatic repair completed.${gl_bai}" @@ -15103,7 +15110,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ The agent was created successfully:$agent_id" + echo "✅The agent is created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -15167,7 +15174,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw multi-agent - remove route binding" + send_stats "OpenClaw multi-agent - remove routing binding" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "Please enter the agent ID:" agent_id @@ -15295,7 +15302,7 @@ print("✅Multi-agent health check completed") echo "6. View session overview" echo "7. Run multi-agent health checks" echo "8. Modify the agent’s identity (name/Emoji)" - echo "9. Clean up expired sessions" + echo "9. 清理过期会话" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" multi_choice @@ -15327,10 +15334,10 @@ openclaw_backup_restore_menu() { openclaw_backup_render_file_list echo "---------------------------------------" echo "1. Back up the entire memory" - echo "2. Restore the full memory" + echo "2. 还原记忆全量" echo "3. Back up the OpenClaw project (default safe mode)" echo "4. Restore OpenClaw Project (Advanced/High Risk)" - echo "5. Delete backup files" + echo "5. 删除备份文件" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" backup_choice @@ -15352,7 +15359,7 @@ openclaw_backup_restore_menu() { update_moltbot() { - echo "Update OpenClaw..." + echo "更新 OpenClaw..." send_stats "Update OpenClaw..." install_node_and_tools git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ @@ -15606,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -16081,7 +16088,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App has been uninstalled" + echo "App uninstalled" ;; *) @@ -16135,7 +16142,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -16233,7 +16240,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -16308,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -17119,7 +17126,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17346,7 +17353,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17398,7 +17405,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17439,7 +17446,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17502,7 +17509,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -17743,7 +17750,7 @@ while true; do } - local docker_describe="A password manager that puts you in control of your data" + local docker_describe="A password manager where you can control your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -17830,7 +17837,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18051,7 +18058,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18115,7 +18122,7 @@ while true; do cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18251,7 +18258,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18314,7 +18321,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18478,7 +18485,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18616,7 +18623,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18670,7 +18677,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18903,7 +18910,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -18974,7 +18981,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19043,7 +19050,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19184,7 +19191,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19254,7 +19261,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "App uninstalled" } docker_app_plus @@ -19460,7 +19467,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -19471,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" + echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19857,7 +19864,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. View the latest system log (journal)" + echo "1. Check the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -19869,7 +19876,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "View the most recent log lines? [Default 100]:" lines + read -erp "How many recent log lines have you viewed? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -19947,7 +19954,7 @@ env_menu() { show_env_vars() { clear - send_stats "Currently in effect environment variables" + send_stats "Environment variables currently in effect" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -20214,7 +20221,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20400,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -20633,7 +20640,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil time 26. Argentina time" + echo "25. Brazil Time 26. Argentina Time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -21411,7 +21418,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Copying file or directory failed: File or directory does not exist" + send_stats "Failed to copy file or directory: File or directory does not exist" continue fi @@ -21543,7 +21550,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21941,7 +21948,7 @@ done k_info() { -send_stats "k command reference examples" +send_stats "k command reference use case" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 3c156c1c3..7313e6c39 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1541,7 +1541,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2241,7 +2241,7 @@ web_security() { echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3017,7 +3017,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3278,7 +3278,7 @@ EOF } # メイン構成/オーバーレイ構成エディター (nano) を直接開きます。 -# 最初に /etc/fail2ban/jail.d/sshd.local を編集し (より安全です)、存在しない場合は作成します +# /etc/fail2ban/jail.d/sshd.local を最初に編集し (より安全です)、存在しない場合は作成します f2b_edit_config() { root_use install nano @@ -3293,7 +3293,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3512,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すと、デフォルトのローカル IP 127.0.0.1 になります)。" reverseproxy + read -e -p "アンチジェネレーション IP を入力してください (Enter キーを押すとデフォルトでローカル IP 127.0.0.1 になります):" reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4313,7 +4313,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4782,7 +4782,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4841,7 +4841,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 設定を手動で編集する" + echo "3. DNS 構成を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5476,7 +5476,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5612,7 +5612,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) + # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5903,7 +5903,7 @@ elrepo() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat シリーズのディストリビューション CentOS/RedHat/Alma/Rocky/oracle のみをサポートします" - echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試してみて、慎重に実稼働環境をアップグレードすることをお勧めします。" + echo "Linux カーネルをアップグレードすると、システムのパフォーマンスとセキュリティが向上します。可能であれば試して、慎重に実稼働環境をアップグレードすることをお勧めします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6016,7 +6016,7 @@ clamav() { ;; 3) send_stats "カスタムディレクトリスキャン" - read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root)。" directories + read -e -p "スキャンするディレクトリをスペースで区切って入力してください (例: /etc /var /usr /home /root):" directories install_docker clamav_freshclam clamav_scan $directories @@ -6043,7 +6043,7 @@ _get_mem_mb() { } # 統合されたカーネルチューニングのコア機能 -# パラメータ: $1 = モード名、$2 = シーン (高/バランス/Web/ストリーム/ゲーム) +# パラメータ: $1 = モード名、$2 = シーン (高/バランス/ウェブ/ストリーム/ゲーム) _kernel_optimize_core() { local mode_name="$1" local scene="${2:-high}" @@ -6380,7 +6380,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6395,9 +6395,9 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6522,7 +6522,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6827,7 +6827,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7150,7 +7150,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションをマウントする" + send_stats "パーティションのマウント" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "パーティションが正常にマウントされました$MOUNT_POINT" + echo "パーティションは正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7327,7 +7327,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7364,7 +7364,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" + kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7380,7 +7380,7 @@ add_task() { case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "選択が無効です。デフォルトの -avz を使用してください"; options="-avz" ;; + *) echo "无效选择,使用默认 -avz"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" @@ -7586,7 +7586,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7648,7 +7648,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7704,7 +7704,7 @@ linux_tools() { while true; do clear - # send_stats "基本ツール" + # send_stats 「基本ツール」 echo -e "基本的なツール" tools=( @@ -7768,7 +7768,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7828,7 +7828,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -8119,7 +8119,7 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" + echo "# 自動生成された復元スクリプト" >> "$RESTORE_SCRIPT" # パッケージ化の繰り返しを避けるために、パッケージ化された Compose プロジェクトのパスを記録します。 declare -A PACKED_COMPOSE_PATHS=() @@ -8130,7 +8130,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8140,7 +8140,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8160,7 +8160,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包体積:$path" + echo "梱包量:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8225,7 +8225,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8307,7 +8307,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8708,6 +8708,7 @@ linux_test() { echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 3つのネットワーク回線テスト" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多機能速度テスト スクリプト" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality ネットワーク品質チェック スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP 再送検出スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}ハードウェアパフォーマンステスト" @@ -8787,7 +8788,7 @@ linux_test() { echo "成都電信: 61.139.2.69" echo "成都チャイナユニコム: 119.6.6.6" echo "成都携帯電話: 211.137.96.205" - echo "湖南电信: 36.111.200.100" + echo "湖南電信: 36.111.200.100" echo "湖南ユニコム: 42.48.16.100" echo "湖南省モバイル: 39.134.254.6" echo "------------------------" @@ -8815,6 +8816,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP 再送検出スクリプト" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "yabsパフォーマンステスト" @@ -8899,7 +8906,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9289,7 +9296,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -10350,7 +10357,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10429,7 +10436,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10449,7 +10456,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10667,7 +10674,7 @@ EOF local config_file config_file=$(openclaw_get_config_file) - # API プロトコルを自動的に検出/修正しなくなりました。ユーザー設定を維持します + # API プロトコルを自動的に検出/修正しなくなりました。ユーザー構成を維持します DETECTED_API="openai-completions" [[ -f "$config_file" ]] && cp "$config_file" "${config_file}.bak.$(date +%s)" @@ -10833,7 +10840,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11223,7 +11230,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行完了" + echo "✅ 同期実行が完了しました" start_gateway ;; 2) @@ -11239,7 +11246,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11270,7 +11277,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "設定したい API タイプを選択してください:" + echo "セットアップする API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -11549,7 +11556,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入り口" + send_stats "OpenClaw APIの入口" while true; do clear echo "=======================================" @@ -11852,7 +11859,7 @@ PYTHON_EOF return 1 fi - # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free")。 + # 簡単に見つけられるように各モデルに番号を付けます (例: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -12292,7 +12299,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12316,7 +12323,7 @@ PYTHON_EOF install_skill() { - send_stats "スキル管理" + send_stats "スキルマネジメント" while true; do clear echo "========================================" @@ -12669,7 +12676,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5. WeChatロボットのドッキング" + echo "5.WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12938,7 +12945,7 @@ if os.path.isdir(agents_root): echo "バックアップモード:" echo "1. セーフ モード (デフォルト、推奨): ワークスペース + openclaw.json + 拡張機能/スキル/プロンプト/ツール (存在する場合)" - echo "2. 完全モード (より多くの状態が含まれ、機密リスクが高くなります)" + echo "2. 完全モード (より多くの状態が含まれ、機密性のリスクが高くなります)" read -e -p "バックアップ モードを選択してください (デフォルト 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -12995,7 +13002,7 @@ if os.path.isdir(agents_root): mkdir -p "$openclaw_root" echo "⚠️ リスクの高い操作: プロジェクトを復元すると、OpenClaw 構成とワークスペースのコンテンツが上書きされます。" - echo "⚠️ 还原前将执行 manifest/sha256 校验、白名单恢复、gateway 停启与健康检查。" + echo "⚠️マニフェスト/sha256の検証、ホワイトリストの復元、ゲートウェイのシャットダウン、ヘルスチェックが復元前に実行されます。" read -e -p "続行するには、確認の単語 [リスクが高いことを承知しており、復元を続行します] を入力してください:" confirm_text if [ "$confirm_text" != "高いリスクを認識しており、復旧を続けています" ]; then echo "❌ 確認ワードが一致しなかったため、リストアはキャンセルされました。" @@ -13208,7 +13215,7 @@ if os.path.isdir(agents_root): break_end return 0 fi - read -e -p "二次確認: 削除するには「DELETE」と入力します。" confirm_step2 + read -e -p "2 番目の確認: 「DELETE」と入力して削除します。" confirm_step2 if [ "$confirm_step2" != "DELETE" ]; then echo "削除がキャンセルされました。" break_end @@ -13465,7 +13472,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("基本的なソリューション: %s" % backend) + print("基礎となるソリューション: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) @@ -13783,7 +13790,7 @@ PY else echo "考えられるトラフィック/ディスク使用量: 実際の状況によって異なります" fi - echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "確認後、自動的にインストール/ダウンロード、構成の書き込み、インデックスの構築、ゲートウェイの再起動が行われます。" echo "詳細オプション: config を入力して構成のみを書き込みます (インストールなし、ダウンロードなし、インデックス作成なし、再起動なし)。" read -e -p "続行することを確認するには「yes」と入力します (デフォルトは N):" confirm_step case "$confirm_step" in @@ -13973,7 +13980,7 @@ EOF while true; do clear echo "=======================================" - echo "メモリソリューションの自動導入" + echo "メモリソリューションの自動展開" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14034,7 +14041,7 @@ EOF } openclaw_memory_offer_restart() { - echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14080,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 構成は正常です。" - echo "実行内容: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" + echo "実行予定: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" echo "" read -e -p "実行を確認しますか? (はい/いいえ):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14196,9 +14203,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "合計行数:$total_lines" + echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count + read -e -p "表示される行数を入力してください (Enter を押してデフォルトに設定します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14293,7 +14300,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステートの検出 (組み込みモデルのチェック)" + echo "6. ディープステート検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14311,7 +14318,7 @@ EOF if [ "$confirm_step2" = "force" ]; then echo "⚠️ 完全な再構築はより徹底的ですが、時間がかかります。" echo "推奨事項: 安全に再構築するには、再構築を入力してください (最初にインデックス データベースをバックアップします)。" - read -e -p "3 番目の確認: 「再構築」と入力して、安全な再構築を実行します。 Enter キーを押して通常の力で続行します。" confirm_step3 + read -e -p "3 番目の確認: 安全な再構築を実行するには、「再構築」と入力します。 Enter キーを押して通常の力で続行します。" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all else @@ -14606,7 +14613,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14631,12 +14638,12 @@ try: print("傍受戦略 (セキュリティ):" + str(sec)) print("即時戦略 (質問):" + str(ask)) print("UI カバーなし (AskFallback):" + str(fb)) - print("自動許可スキル:" + ("on" if auto else "off")) + print(" 自动放行技能 (autoAllowSkills): " + ("on" if auto else "off")) exists = d.get("exists", True) if not exists: - print("(承認文書は存在しません。システムに組み込まれたセーフティネットを使用してください)") + print(" (审批文件不存在,使用系统内置安全兜底)") except Exception as e: - print("(解析に失敗しました:" + str(e) + ")") + print(" (解析失败: " + str(e) + ")") ' "$approvals_json" else echo "(openclaw の承認では --json が出力されません)" @@ -14655,7 +14662,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14675,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフ モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を要求します)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14712,7 +14719,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 完全オープン モードに切り替えられました (警告: すべてのホスト コマンド インターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" + echo -e "${gl_lv}✅ 完全オープン モードに切り替えられています (警告: すべてのホスト コマンドのインターセプトの有効期限が切れており、エージェントには最高の権限が与えられています)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14744,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "発見されたセキュリティ脆弱性を自動的に修復してみますか? (y/n):" fix_choice + read -e -p "発見されたセキュリティ脆弱性を自動的に修復しますか? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復が完了しました。${gl_bai}" @@ -15085,7 +15092,7 @@ else: openclaw_multiagent_list_agents() { send_stats "OpenClaw マルチエージェント - エージェントのリスト" python3 -c 'import json,sys; agents=json.loads(sys.argv[1] or "[]"); -if not agents: print("エージェントはまだ設定されていません。"); raise SystemExit(0) +if not agents: print("エージェントはまだ構成されていません。"); raise SystemExit(0) for idx,item in enumerate(agents,1): print("%s. %s" % (idx, item.get("id","?"))); print(" workspace : %s" % item.get("workspace","-")); ident=(item.get("identityName") or "-") + ((" " + item.get("identityEmoji")) if item.get("identityEmoji") else ""); print(" identity : %s" % ident.strip()); print(" model : %s" % (item.get("model") or "-")); print(" bindings : %s" % item.get("bindings",0)); print(" default : %s" % ("yes" if item.get("isDefault") else "no"))' "$(openclaw_multiagent_agents_json)" } @@ -15095,15 +15102,15 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id workspace confirm read -e -p "新しいエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 - read -e -p "ワークスペースのパス (デフォルトは ~/.openclaw/workspace-) を入力してください。${agent_id}): " workspace + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 + read -e -p "ワークスペースのパスを入力してください (デフォルトは ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "エージェントが作成されます。$agent_id" echo "作業ディレクトリ:$workspace" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました:$agent_id" + echo "✅ エージェントが正常に作成されました。$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15122,7 +15129,7 @@ for idx,item in enumerate(agents,1): openclaw_multiagent_require_openclaw || return 1 local agent_id confirm read -e -p "削除するエージェント ID を入力してください:" agent_id - [ -z "$agent_id" ] && echo "キャンセル済み: エージェント ID を空にすることはできません。" && return 1 + [ -z "$agent_id" ] && echo "キャンセル: エージェント ID を空にすることはできません。" && return 1 echo "⚠️ エージェントを削除すると、その作業ディレクトリ、ルート バインディング、およびセッション ルーティングに影響する可能性があります。" read -e -p "「DELETE」と入力して削除を確認します${agent_id}: " confirm [ "$confirm" = "DELETE" ] || { echo "キャンセル"; return 1; } @@ -15167,13 +15174,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw マルチエージェント - ルート バインディングの削除" + send_stats "OpenClaw マルチエージェント - ルーティング バインディングの削除" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" + echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15382,7 +15389,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 設定ファイルを編集する" + send_stats "OpenClaw 構成ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15542,7 +15549,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期設定ウィザード" + 11) send_stats "初期構成ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15606,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15638,7 +15645,7 @@ while true; do echo -e "${gl_kjlan}53. ${color53}llama3チャットAI大型モデル${gl_kjlan}54. ${color54}AMH ホスト Web サイト構築管理パネル" echo -e "${gl_kjlan}55. ${color55}FRPイントラネット普及(サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}56. ${color56}FRPイントラネット普及(クライアント)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}57. ${color57}ディープシークチャットAI大型モデル${gl_kjlan}58. ${color58}Dify 大規模モデルのナレッジ ベース${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}59. ${color59}NewAPI 大型モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" + echo -e "${gl_kjlan}59. ${color59}NewAPI 大規模モデル資産管理${gl_kjlan}60. ${color60}JumpServer オープンソース要塞マシン" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" @@ -15654,7 +15661,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -15906,7 +15913,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用する" + echo "1. 使用方法" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -16308,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -17172,7 +17179,7 @@ while true; do } - local docker_describe="これは Prometheus コンテナのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" + local docker_describe="これは Prometheus コンテナーのデータ収集コンポーネントです。監視対象ホストにデプロイしてください。" local docker_url="公式サイト紹介:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -17474,7 +17481,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17743,7 +17750,7 @@ while true; do } - local docker_describe="データを管理できるパスワード マネージャー" + local docker_describe="データを管理できるパスワードマネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18220,7 +18227,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18314,7 +18321,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -18690,7 +18697,7 @@ while true; do read -e -p "ネットワーク内のクライアントの数を入力してください (デフォルトは 5):" COUNT COUNT=${COUNT:-5} - read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0):" NETWORK + read -e -p "WireGuard ネットワーク セグメントを入力してください (デフォルトは 10.13.13.0)。" NETWORK NETWORK=${NETWORK:-10.13.13.0} PEERS=$(seq -f "wg%02g" 1 "$COUNT" | paste -sd,) @@ -18802,7 +18809,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント構成を貼り付け、Enter キーを 2 回押して保存してください。" + echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" # 変数を初期化する input="" @@ -19279,7 +19286,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19460,8 +19467,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d を単独で押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19471,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" + echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19799,7 +19806,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19809,7 +19816,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19821,7 +19828,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19857,7 +19864,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を表示する" + echo "1. 最新のシステムログ(ジャーナル)を確認する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -19869,10 +19876,10 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines + read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19882,7 +19889,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19897,7 +19904,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19985,7 +19992,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -20000,7 +20007,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -20016,7 +20023,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -20029,7 +20036,7 @@ env_menu() { echo "3. ~/.profile を表示する" echo "4. ~/.bashrc を編集します" echo "5. ~/.profile を編集する" - echo "6. 環境変数 (ソース) をリロードします。" + echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" echo "0. 前のメニューに戻る" echo "--------------------------------------" @@ -20144,7 +20151,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20219,7 +20226,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -20400,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -20608,7 +20615,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -21102,8 +21109,8 @@ EOF send_stats "ワンストップチューニング" echo "ワンストップのシステムチューニング" echo "------------------------------------------------" - echo "将对以下内容进行操作与优化" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "以下のコンテンツを運用・最適化していきます" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21541,9 +21548,9 @@ while true; do echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}システムをアップデートする${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" + echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21908,7 +21915,7 @@ echo -e "${gl_kjlan}16. ${gl_bai}ゲームサーバー起動スクリプト集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}スクリプトの更新" echo -e "${gl_kjlan}------------------------${gl_bai}" -echo -e "${gl_kjlan}0. ${gl_bai}スクリプトを終了します" +echo -e "${gl_kjlan}0. ${gl_bai}終了スクリプト" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "選択肢を入力してください:" choice @@ -21941,14 +21948,14 @@ done k_info() { -send_stats "k コマンドのリファレンス例" +send_stats "k コマンドリファレンスの使用例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" echo "スクリプトkを開始します" echo "パッケージをインストールします k install nano wget | k ナノ wget を追加 | nano wgetをインストールします" -echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | k nano wget をアンインストールする | nano wgetをアンインストールします" -echo "システム k 更新を更新します。 kアップデート" +echo "パッケージをアンインストールします。 k 削除 nano wget | kデルナノwget | nano wget をアンインストールする | nano wgetをアンインストールします" +echo "システム k アップデートを更新 | kアップデート" echo "クリーン系ジャンククリーン |きれいだ" echo "システムパネルを再度取り付けます。 k再インストール" echo "BBR3 コントロール パネル K BBR3 | k bbrv3" @@ -21957,7 +21964,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21976,11 +21983,11 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -22181,7 +22188,7 @@ else shift case $1 in install|安装) - send_stats "Dockerを素早くインストールする" + send_stats "Docker をすばやくインストールする" install_docker ;; ps|容器) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index b3b502f78..0371bf1f9 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -65,7 +65,7 @@ CheckFirstRun_true() { # 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP 지우기" + echo "7. 지정된 IP를 삭제합니다." echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1852,7 +1852,7 @@ check_waf_status() { if grep -q "^\s*#\s*modsecurity on;" /home/web/nginx.conf; then waf_status="" elif grep -q "modsecurity on;" /home/web/nginx.conf; then - waf_status="WAF가 켜져 있습니다" + waf_status="WAF가 켜져 있습니다." else waf_status="" fi @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2805,7 +2805,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -3426,7 +3426,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -4109,7 +4109,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4156,7 +4156,7 @@ add_forwarding_service() { read -e -p "서비스 이름을 입력하세요:" service_name read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip + read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "인트라넷 포트를 입력하십시오:" local_port read -e -p "외부 네트워크 포트를 입력하세요:" remote_port @@ -4171,7 +4171,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4418,7 +4418,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4447,7 +4447,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." + echo "서버에 연결합니다. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -4782,7 +4782,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4986,7 +4986,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5903,7 +5903,7 @@ elrepo() { echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5939,7 +5939,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -6946,7 +6946,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -7017,13 +7017,13 @@ add_connection() { echo "------------------------" read -e -p "연결 이름을 입력하세요:" name - kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "포트 번호를 입력하십시오(기본값: 22):" "root" "22" + kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "请输入端口号 (默认: 22): " "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "연결이 저장되었습니다!" + echo "连接已保存!" } @@ -7156,7 +7156,7 @@ mount_partition() { DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" - # 파티션이 존재하는지 확인 + # 检查分区是否存在 if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "파티션이 존재하지 않습니다!" return 1 @@ -7164,7 +7164,7 @@ mount_partition() { # 마운트되어 있는지 확인해보세요 if mount | grep -qw "$DEVICE"; then - echo "파티션이 마운트되었습니다!" + echo "分区已经挂载!" return 1 fi @@ -8098,7 +8098,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers install tar jq gzip install_docker @@ -8237,7 +8237,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8372,7 +8372,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. Docker 프로젝트의 백업 파일을 삭제합니다." + echo -e "4. docker 프로젝트 백업 파일 삭제" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -8708,6 +8708,7 @@ linux_test() { echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 세 개의 네트워크 라인 테스트" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 다기능 속도 테스트 스크립트" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 네트워크 품질 확인 스크립트${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP 재전송 감지 스크립트${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}하드웨어 성능 테스트" @@ -8815,6 +8816,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP 재전송 감지 스크립트" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "Yabs 성능 테스트" @@ -9288,7 +9295,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9626,7 +9633,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming nginx_install_status install_ssltls @@ -10550,8 +10557,8 @@ PY install_moltbot() { - echo "OpenClaw 설치를 시작합니다..." - send_stats "OpenClaw 설치를 시작합니다..." + echo "OpenClaw 설치를 시작하세요..." + send_stats "OpenClaw 설치를 시작하세요..." install git jq install_node_and_tools @@ -11204,7 +11211,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: {len(add_ids)} 추가, 삭제 {len(removed_ids)}, 현재 {len(new_models)}') +print(f'✅ {target}: {len(add_ids)} 추가, {len(removed_ids)} 삭제, 현재 {len(new_models)}') if added_ids: print(f'➕ 새 모델 추가({len(add_ids)}):') @@ -11489,7 +11496,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장사항" + send_stats "OpenClaw API 공급업체 권장 사항" clear echo "" @@ -12218,7 +12225,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12242,7 +12249,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인 중:$plugin_id" + echo "🔍 플러그인 상태 확인:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12259,7 +12266,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." + echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12346,7 +12353,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -12690,7 +12697,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp에서 받은 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "WhatsApp에서 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13028,7 +13035,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13148,7 +13155,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw 백업 파일 삭제" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13398,7 +13405,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." + echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -13565,7 +13572,7 @@ PY if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로:$model_path") @@ -13573,14 +13580,14 @@ PY OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로가 구성되지 않았습니다.") fi case "$model_status" in - ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재합니다.") ;; + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("모델은 HF 다운로드 소스에서 제공됩니다(중국에서는 느리거나 실패할 수 있음).") ;; *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재하지 않거나 사용할 수 없습니다.") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co에 액세스할 수 있습니다.") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") elif [ "$mirror_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可访问") else OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") fi @@ -13659,7 +13666,7 @@ PY wget -O "$dest" "$url" return $? fi - echo "❌ Curl이나 wget이 감지되지 않아 다운로드할 수 없습니다." + echo "❌ 未检测到 curl 或 wget,无法下载。" return 1 } @@ -13671,7 +13678,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." return 0 } @@ -13683,20 +13690,20 @@ PY echo "✅ 롤빵이 이미 존재합니다" return 0 fi - echo "⬇️ 번 설치..." + echo "⬇️ 安装 bun..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 未检测到 curl 或 wget,无法安装 bun。" return 1 fi if [ -d "$HOME/.bun/bin" ]; then export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ 번 설치 완료" + echo "✅ bun 安装完成" return 0 fi echo "❌ 번 설치 실패" @@ -13783,7 +13790,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -14080,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전히 재구축" + echo "실행됩니다: 이전 인덱스 정리 → 모든 에이전트 인덱스를 완전히 재구축합니다." echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14198,7 +14205,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14208,7 +14215,7 @@ EOF fi fi if ! [[ "$start_line" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then - echo "❌ 유효한 번호를 입력하세요." + echo "❌ 유효한 숫자를 입력하세요." return 1 fi if [ "$start_line" -lt 1 ]; then @@ -14575,7 +14582,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일을 직접 작성 + # 대체: 파일 직접 쓰기 echo "$json_payload" > "$approvals_file" } @@ -14675,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 명령은 모두 UI/TG를 통해 승인을 요청합니다)${gl_bai}" + echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 모든 명령은 UI/TG를 통해 승인을 요청합니다)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14693,7 +14700,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { @@ -14744,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "발견된 보안 취약점을 자동으로 해결하려고 합니까? (예/아니요):" fix_choice + read -e -p "발견된 보안 취약점을 자동으로 해결하시겠습니까? (예/아니요):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 자동 복구가 완료되었습니다.${gl_bai}" @@ -14794,7 +14801,7 @@ except Exception as e: read -e -p "선택하세요:" al_choice case "$al_choice" in 1) - read -e -p "해제할 명령 경로를 입력하십시오(/usr/bin/git와 같은 glob 지원)." pattern + read -e -p "해제할 명령 경로를 입력하세요(/usr/bin/git와 같은 glob 지원)." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } read -e -p "에이전트 ID 지정(비워 두기 = 모든 에이전트 *):" agent_id agent_id="${agent_id:-*}" @@ -14802,7 +14809,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15103,7 +15110,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15167,7 +15174,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw 다중 에이전트 - 경로 바인딩 제거" + send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "상담원 ID를 입력하세요:" agent_id @@ -15542,11 +15549,11 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "초기 구성 마법사" + 11) send_stats "初始化配置向导" openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "상태 감지 및 수리" openclaw doctor --fix break_end ;; @@ -15606,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15646,7 +15653,7 @@ while true; do echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" @@ -15671,8 +15678,8 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" - echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -16308,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -16716,7 +16723,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -16743,7 +16750,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -16948,7 +16955,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 오리지널 마우스 패널" + local panelname="AcePanel 原耗子面板" local panelurl="공식 주소:${gh_proxy}github.com/acepanel/panel" panel_app_install() { @@ -17248,7 +17255,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17410,7 +17417,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17743,7 +17750,7 @@ while true; do } - local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" + local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -17991,7 +17998,7 @@ while true; do local app_id="80" local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18314,9 +18321,9 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" - local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 적시에 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -18945,7 +18952,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19460,7 +19467,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -19471,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" + echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19573,7 +19580,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜기 2. 끄기" + echo "1. 켜짐 2. 꺼짐" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -19665,7 +19672,7 @@ switch_mirror() { --install-epel false \ --pure-mode else - echo "해외 미러 소스를 활용하세요.." + echo "使用海外镜像源..." if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ @@ -19734,7 +19741,7 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH 방어 기본 매개변수 구성" + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; @@ -19763,10 +19770,10 @@ fail2ban_panel() { net_menu() { - send_stats "네트워크 카드 관리 도구" + send_stats "网卡管理工具" show_nics() { echo "================ 현재 네트워크 카드 정보 =================" - printf "%-18s %-12s %-20s %-26s\n" "네트워크 카드 이름" "상태" "IP 주소" "MAC 주소" + printf "%-18s %-12s %-20s %-26s\n" "网卡名" "상태" "IP 주소" "MAC 주소" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -19783,7 +19790,7 @@ net_menu() { echo echo "=========== 네트워크 카드 관리 메뉴 ===========" echo "1. 네트워크 카드 활성화" - echo "2. 네트워크 카드 비활성화" + echo "2. 禁用网卡" echo "3. 네트워크 카드 세부정보 보기" echo "4. 네트워크 카드 정보 새로 고침" echo "0. 이전 메뉴로 돌아가기" @@ -19793,17 +19800,17 @@ net_menu() { case $choice in 1) send_stats "네트워크 카드 활성화" - read -erp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic + read -erp "请输入要启用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" else - echo "✘ 네트워크 카드가 존재하지 않습니다." + echo "✘ 网卡不存在" fi read -erp "계속하려면 Enter를 누르세요..." ;; 2) - send_stats "네트워크 카드 비활성화" - read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic + send_stats "禁用网卡" + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" else @@ -19842,7 +19849,7 @@ log_menu() { show_log_overview() { echo "============= 시스템 로그 개요 =============" echo "호스트 이름: $(호스트 이름)" - echo "시스템 시간: $(날짜)" + echo "系统时间: $(date)" echo echo "[/var/log 디렉토리 직업]" du -sh /var/log 2>/dev/null @@ -19857,19 +19864,19 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지) 보기" + echo "1. 최신 시스템 로그(일지)를 확인하세요." echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" - echo "4. 실시간 추적 로그" - echo "5. 오래된 저널 로그 정리" + echo "4. 实时跟踪日志" + echo "5. 清理旧 journal 日志" echo "0. 이전 메뉴로 돌아가기" echo "=======================================" read -erp "작업을 선택하십시오:" choice case $choice in 1) - send_stats "최근 로그 보기" - read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines + send_stats "查看最近日志" + read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -19885,7 +19892,7 @@ log_menu() { read -erp "계속하려면 Enter를 누르세요..." ;; 3) - send_stats "로그인/보안 로그 보기" + send_stats "查看登录/安全日志" echo "====== 최근 로그인 로그 ======" last -n 10 echo @@ -19902,7 +19909,7 @@ log_menu() { 4) send_stats "실시간 추적 로그" echo "1) 시스템 로그" - echo "2) 서비스 로그 지정" + echo "2) 指定服务日志" read -erp "추적 유형 선택:" t if [ "$t" = "1" ]; then journalctl -f @@ -19915,10 +19922,10 @@ log_menu() { ;; 5) send_stats "오래된 저널 로그 정리" - echo "⚠️ 일지를 청소하세요(안전한 방법)" - echo "1) 최근 7일을 보관" - echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "⚠️ 清理 journal 日志(安全方式)" + echo "1) 保留最近 7 天" + echo "2) 保留最近 3 天" + echo "3) 限制日志最大 500M" read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19926,7 +19933,7 @@ log_menu() { 3) journalctl --vacuum-size=500M ;; *) echo "잘못된 옵션" ;; esac - echo "✔ 저널 로그 정리 완료" + echo "✔ journal 日志清理完成" sleep 2 ;; *) @@ -19960,14 +19967,14 @@ env_menu() { echo "$PATH" | tr ':' '\n' | nl -ba echo - echo "========== 구성 파일에 정의된 변수(파싱) ==========" + echo "========== 配置文件中定义的变量(解析) ==========" parse_file_vars() { local file="$1" [ -f "$file" ] || return echo - echo ">>> 소스 파일:$file" + echo ">>> 来源文件:$file" echo "-----------------------------------------------" # 내보내기 VAR=xxx 또는 VAR=xxx 추출 @@ -20024,9 +20031,9 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 查看当前常用环境变量" echo "2. ~/.bashrc 보기" - echo "3. ~/.profile 보기" + echo "3. 查看 ~/.profile" echo "4. ~/.bashrc 편집" echo "5. ~/.profile 편집" echo "6. 환경 변수 다시 로드(출처)" @@ -20090,7 +20097,7 @@ create_user_with_sshkey() { fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "공개 키를 직접 가져오기" + send_stats "公钥直接导入" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) @@ -20105,7 +20112,7 @@ create_user_with_sshkey() { install sudo - # sudo 비밀번호가 필요하지 않음 + # sudo 免密 if [[ "$is_sudo" == "true" ]]; then cat >"/etc/sudoers.d/$new_username" < /dev/null 2>&1 ;; 2) @@ -20907,7 +20914,7 @@ EOF case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -20951,7 +20958,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21411,7 +21418,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -21543,7 +21550,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21657,7 +21664,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 Tokyo Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" @@ -21941,7 +21948,7 @@ done k_info() { -send_stats "k 명령 참조 예" +send_stats "k 명령 참조 사용 사례" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." diff --git a/tw/kejilion.sh b/tw/kejilion.sh index c3e430e7b..2a348ec5a 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -179,7 +179,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供软件包参数!" + echo "未提供軟體包參數!" return 1 fi @@ -620,7 +620,7 @@ docker_image() { while true; do clear send_stats "Docker映像管理" - echo "Docker镜像列表" + echo "Docker映像列表" docker image ls echo "" echo "鏡像操作" @@ -649,7 +649,7 @@ while true; do done ;; 3) - send_stats "刪除鏡像" + send_stats "删除镜像" read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do docker rmi -f $name @@ -1498,7 +1498,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "網站資訊 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1542,7 +1542,7 @@ certs_status() { send_stats "網域證書申請失敗" echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" - echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" + echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" echo -e "4. 防火牆限制 ➠ 檢查80/443連接埠是否開放,確保驗證可存取" echo -e "5. 申請次數超限 ➠ Let's Encrypt有每週限額(5次/網域/週)" @@ -1753,7 +1753,7 @@ cf_purge_cache() { echo "CF資訊保存在$CONFIG_FILE,可以後期修改CF訊息" read -e -p "請輸入你的 API_TOKEN:" API_TOKEN read -e -p "請輸入你的CF用戶名:" EMAIL - read -e -p "请输入 zone_id(多个用空格分隔): " -a ZONE_IDS + read -e -p "請輸入 zone_id(多個以空格分隔):" -a ZONE_IDS mkdir -p /home/web/config/ echo "$API_TOKEN $EMAIL ${ZONE_IDS[*]}" > "$CONFIG_FILE" @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" ;; 22) @@ -2242,7 +2242,7 @@ web_security() { echo "--------------" echo "取得CF參數:" echo -e "到cf後台右上角我的個人資料,選擇左側API令牌,取得${gl_huang}Global API Key${gl_bai}" - echo -e "到cf后台域名概要页面右下方获取${gl_huang}區域ID${gl_bai}" + echo -e "到cf後台域名概要頁面右下方獲取${gl_huang}區域ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "輸入CF的帳號:" cfuser @@ -2336,7 +2336,7 @@ check_nginx_compression() { br_status="" fi - # 检查 gzip 是否开启且未被注释 + # 檢查 gzip 是否開啟且未被註釋 if grep -qE '^\s*gzip\s+on;' "$CONFIG_FILE"; then gzip_status="gzip壓縮已開啟" else @@ -2965,7 +2965,7 @@ while true; do ;; 8) - send_stats "阻止IP访问 ${docker_name}" + send_stats "阻止IP訪問${docker_name}" block_container_port "$docker_name" "$ipv4_address" ;; @@ -3237,7 +3237,7 @@ f2b_basic_config() { local jail_name="sshd" if grep -qi 'Alpine' /etc/issue 2>/dev/null; then - # Alpine 默认 jail 通常为 sshd;仅当检测到自定义 alpine-sshd 规则时才切换 + # Alpine 預設 jail 通常為 sshd;僅當偵測到自訂 alpine-sshd 規則時才切換 if [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; then jail_name="alpine-sshd" fi @@ -3740,7 +3740,7 @@ ldnmp_Proxy_backend_stream() { fi # 取得監聽埠 - read -erp "請輸入本機監聽埠 (如 3306):" listen_port + read -erp "请输入本机监听端口 (如 3306): " listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "連接埠必須是數字"; return 1 fi @@ -3893,7 +3893,7 @@ ldnmp_web_status() { 2) send_stats "克隆站點域名" read -e -p "請輸入舊網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -3932,9 +3932,9 @@ ldnmp_web_status() { ;; 4) send_stats "建立關聯站點" - echo -e "为现有的站点再关联一个新域名用于访问" + echo -e "為現有的站點再關聯一個新網域用於訪問" read -e -p "請輸入現有的網域名稱:" oddyuming - read -e -p "請輸入新網域:" yuming + read -e -p "請輸入新網域名稱:" yuming install_certbot install_ssltls certs_status @@ -4471,7 +4471,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP客户端已经安装完成" + echo "FRP客戶端已經安裝完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4544,7 +4544,7 @@ yt_menu_pro() { echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "已下載影片清單:" - ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暂无)" + ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" echo "1. 安裝 2. 更新 3. 卸載" echo "-------------------------" @@ -4788,7 +4788,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5030,7 +5030,7 @@ fetch_remote_ssh_keys() { # 下載公鑰 if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 + echo "錯誤:無法從 URL 下載公鑰(網路問題或位址無效)" >&2 rm -f "${temp_file}" return 1 } @@ -5154,7 +5154,7 @@ sshkey_panel() { break_end ;; 2) - send_stats "导入已有公钥" + send_stats "導入已有公鑰" import_sshkey break_end ;; @@ -5631,7 +5631,7 @@ bbrv3() { install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then - echo "官方密钥下载失败,尝试备用下载源..." + echo "官方金鑰下載失敗,嘗試備用下載來源..." wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" @@ -5943,7 +5943,7 @@ clamav_scan() { return fi - echo -e "${gl_kjlan}正在扫描目录$@... ${gl_bai}" + echo -e "${gl_kjlan}正在掃描目錄$@...${gl_bai}" # 建構 mount 參數 local MOUNT_PARAMS="" @@ -6168,7 +6168,7 @@ net.ipv4.udp_wmem_min = 16384 net.ipv4.tcp_notsent_lowat = 16384" fi - # ── 游戏服场景额外:低延迟优先 ── + # ── 遊戲服場景額外:低延遲優先 ── local GAME_EXTRA="" if [ "$scene" = "game" ]; then GAME_EXTRA=" @@ -6203,7 +6203,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 内核调优配置 +# kejilion 核心調優配置 # 模式: $mode_name | 場景: $scene # 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') @@ -6300,9 +6300,9 @@ SYSCTL skipped=$((skipped + 1)) fi done < "$CONF" - echo -e "${gl_lv}已应用 ${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" + echo -e "${gl_lv}已應用${applied}項參數${skipped:+,跳過${skipped}項不支援的參數}${gl_bai}" - # ── 透明大页面 ── + # ── 透明大頁面 ── if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo "$THP" > /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null fi @@ -6719,7 +6719,7 @@ create_backup() { IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 產生備份檔案前綴 + # 生成备份文件前缀 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do # 提取目錄名稱並去除斜杠 @@ -6734,7 +6734,7 @@ create_backup() { local BACKUP_NAME="${PREFIX}_$TIMESTAMP.tar.gz" # 列印使用者選擇的目錄 - echo "您选择的备份目录为:" + echo "您選擇的備份目錄為:" for path in "${BACKUP_PATHS[@]}"; do echo "- $path" done @@ -6771,7 +6771,7 @@ restore_backup() { if [ $? -eq 0 ]; then echo "備份恢復成功!" else - echo "备份恢复失败!" + echo "備份恢復失敗!" exit 1 fi } @@ -6911,7 +6911,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "错误: SSH 用户名格式不正确。" + echo "錯誤: SSH 使用者名稱格式不正確。" return 1 fi @@ -7041,7 +7041,7 @@ delete_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果连接使用的是密钥文件,则删除该密钥文件 + # 如果連接使用的是密鑰文件,則刪除該密鑰文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -7076,7 +7076,7 @@ use_connection() { else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "错误:未安装 sshpass,请先安装 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7314,7 +7314,7 @@ disk_manager() { list_partitions echo "------------------------" echo "1. 掛載分割區 2. 卸載分割區 3. 檢視已掛載分割區" - echo "4. 格式化分区 5. 检查分区状态" + echo "4. 格式化分割區 5. 檢查分割區狀態" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -7446,7 +7446,7 @@ run_task() { # 根據同步方向調整來源和目標路徑 if [[ "$direction" == "pull" ]]; then - echo "正在拉取同步到本地: $remote:$local_path -> $remote_path" + echo "正在拉取同步到本地:$remote:$local_path -> $remote_path" source="$remote:$local_path" destination="$remote_path" else @@ -7570,7 +7570,7 @@ rsync_manager() { view_tasks echo echo "1. 建立新任務 2. 刪除任務" - echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" echo "5. 建立定時任務 6. 刪除定時任務" echo "---------------------------------" echo "0. 返回上一級選單" @@ -8708,6 +8708,7 @@ linux_test() { echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 三線線路測試" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多功能測速腳本" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 網路品質體檢腳本${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP重傳偵測腳本${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}硬體效能測試" @@ -8815,6 +8816,12 @@ linux_test() { bash <(curl -sL Net.Check.Place) ;; + 19) + clear + send_stats "TcpQuality TCP重傳偵測腳本" + bash <(curl -sL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh) + ;; + 21) clear send_stats "yabs效能測試" @@ -9390,7 +9397,7 @@ linux_ldnmp() { clear ldnmp_web_on - echo "数据库前缀: typecho_" + echo "資料庫前綴: typecho_" echo "資料庫位址: mysql" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" @@ -10247,7 +10254,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') + print('ℹ️ 未偵測到 API providers,跳過模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10350,11 +10357,11 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} 指向该 provider,但无可用替代模型,已中止删除') + summary.append(f'❌ {name}: {fk} 指向該 provider,但無可用替代模型,已中止刪除') return False defaults[fk] = repl changed = True - summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') + summary.append(f'🔁 刪除前已切換 {fk}: {val} -> {repl}') return True @@ -10416,14 +10423,14 @@ for name, provider in list(providers.items()): continue if api not in SUPPORTED_APIS: - summary.append(f'🔁 {name}: 发现非法协议 {api or "(unset)"},将重新探测') + summary.append(f'🔁 {name}: 發現非法協定 {api or "(unset)"},將重新探測') provider['api'] = '' api = '' changed = True data, err, attempts = fetch_remote_models_with_retry(name, base_url, api_key, retries=3) if err is not None: - summary.append(f'⚠️ {name}: /models 探测失败,已重试 {attempts} 次 ({type(err).__name__}: {err})') + summary.append(f'⚠️ {name}: /models 偵測失敗,已重試 {attempts} 次 ({type(err).__name__}: {err})') send_stat('OpenClaw API確認介入') if prompt_delete_provider(name): deleted = delete_provider_and_refs(name) @@ -10539,7 +10546,7 @@ if changed: f.write('\n') for line in summary: print(line) - print('✅ OpenClaw API 模型一致性同步完成并已写入配置') + print('✅ OpenClaw API 模型一致性同步完成並已寫入配置') else: for line in summary: print(line) @@ -10602,7 +10609,7 @@ PY # OpenClaw API 協定偵測邏輯已移除:不再自動偵測/判定 API 類型。 - # 说明:API 类型由用户显式配置(models.providers..api),脚本不再尝试调用 /responses 做推断。 + # 說明:API 類型由使用者明確配置(models.providers..api),腳本不再嘗試呼叫 /responses 做推論。 # 建構模型配置 JSON build-openclaw-provider-models-json() { @@ -10757,7 +10764,7 @@ EOF local default_model="$4" if [[ -z "$default_model" ]]; then - echo "❌ 默认模型不能为空" + echo "❌ 預設模型不能為空" return 1 fi @@ -11223,20 +11230,20 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同步执行完成" + echo "✅ 同步執行完成" start_gateway ;; 2) echo "❌ 同步失敗:provider 不存在或未配置" ;; 3) - echo "❌ 同步失败:provider 配置不完整或类型不支持" + echo "❌ 同步失敗:provider 配置不完整或類型不支持" ;; 4) echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失败:上游模型为空或同步后无可用模型" + echo "❌ 同步失敗:上游模型為空或同步後無可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -11249,7 +11256,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 # 保留函數以相容選單調用,但不做任何改寫。 - echo "ℹ️ 已关闭协议探测:请手动在 ${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" + echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -11270,7 +11277,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "请选择要设置的 API 类型:" + echo "請選擇要設定的 API 類型:" echo "1. openai-completions" echo "2. openai-responses" read -erp "請輸入你的選擇 (1/2):" proto_choice @@ -11280,7 +11287,7 @@ fix-openclaw-provider-protocol-interactive() { 1) new_api="openai-completions" ;; 2) new_api="openai-responses" ;; *) - echo "❌ 无效选择" + echo "❌ 無效選擇" break_end return 1 ;; @@ -11325,7 +11332,7 @@ PY start_gateway ;; 2) - echo "❌ 切换失败:provider 不存在或未配置" + echo "❌ 切換失敗:provider 不存在或未配置" ;; 3) echo "❌ 切換失敗:協定值非法" @@ -12287,7 +12294,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在删除/禁用插件: $plugin_id" + echo "🗑️ 正在刪除/停用插件:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ 已卸載:$plugin_id" @@ -12690,7 +12697,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連接碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13574,7 +13581,7 @@ PY fi case "$model_status" in ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案存在") ;; - hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型來自 HF 下載來源(國內可能慢/失敗)") ;; *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型檔案不存在或不可用") ;; esac if [ "$hf_ok" = "ok" ]; then @@ -13891,7 +13898,7 @@ EOF if [ -f "$model_dest" ]; then echo "✅ 已發現預設模型檔:$model_dest" else - echo "⬇️ 下载模型: $model_url" + echo "⬇️ 下載模型:$model_url" openclaw_memory_download_file "$model_url" "$model_dest" || return 1 echo "✅ 模型已下載:$model_dest" fi @@ -13973,7 +13980,7 @@ EOF while true; do clear echo "=======================================" - echo "记忆方案自动部署" + echo "記憶方案自動部署" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14292,7 +14299,7 @@ EOF echo "2. 檢視記憶文件" echo "3. 索引修復(Indexed 異常)" echo "4. 記憶方案(QMD/Local/Auto)" - echo "5. 搜索测试(验证索引是否工作)" + echo "5. 搜尋測試(驗證索引是否運作)" echo "6. 深度狀態探測(檢查嵌入模型)" echo "0. 返回上一級" echo "---------------------------------------" @@ -14839,7 +14846,7 @@ except Exception as e: break_end ;; 2) - echo "准备应用:开发增强模式" + echo "準備應用:開發增強模式" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_apply_developer; else echo "已取消"; fi break_end @@ -17101,7 +17108,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼皆為: admin" + echo "初始使用者名稱密碼均為: admin" } docker_app_update() { @@ -20953,7 +20960,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21112,7 +21119,7 @@ EOF echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" - echo -e "10. 设置网络为${gl_huang}ipv4優先${gl_bai}" + echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" echo "------------------------------------------------" @@ -21304,7 +21311,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21335,7 +21342,7 @@ linux_file() { read -e -p "請輸入目前目錄名稱:" current_name read -e -p "請輸入新目錄名稱:" new_name mv "$current_name" "$new_name" && echo "目錄已重新命名" || echo "重新命名失敗" - send_stats "重命名目录" + send_stats "重新命名目錄" ;; 5) # 删除目录 read -e -p "請輸入要刪除的目錄名稱:" dirname @@ -21643,7 +21650,7 @@ echo "" echo -e "伺服器優惠" echo "------------------------" echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活動${gl_bai}" -echo -e "${gl_bai}网址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" +echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd 10.99刀每年 美國 1核心 1G記憶體 20G硬碟 1T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" @@ -21955,34 +21962,34 @@ echo "bbr3控制面板 k bbr3 | k bbrv3" echo "核心調優面板 k nhyh | k 核心最佳化" echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" -echo "系統回收站 k trash | k hsz | k 回收站" +echo "系统回收站 k trash | k hsz | k 回收站" echo "系統備份功能 k backup | k bf | k 備份" echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" -echo "硬碟管理工具 k disk | k 硬碟管理" +echo "硬盘管理工具 k disk | k 硬盘管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" -echo "軟體停止 k stop sshd | k 停止 sshd" +echo "软件停止 k stop sshd | k 停止 sshd " echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" -echo "網域名稱憑證到期查詢 k ssl ps" +echo "域名证书到期查询 k ssl ps" echo "docker管理平面 k docker" echo "docker環境安裝 k docker install |k docker 安裝" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker映像管理 k docker img |k docker 映像" -echo "LDNMP站台管理 k web" -echo "LDNMP快取清理 k web cache" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker镜像管理 k docker img |k docker 镜像" +echo "LDNMP站点管理 k web" +echo "LDNMP缓存清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" -echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" +echo "开放端口 k dkdk 8080 |k 打开端口 8080" echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" -echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" +echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" @@ -22157,18 +22164,18 @@ else enable|autostart|开机启动) shift - send_stats "軟體開機自啟" + send_stats "软件开机自启" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看證書狀態" + send_stats "查看证书状态" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申請證書" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" send_stats "快速申請證書" From de3296862e7929a9d0626612f19001fed7f8e08c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 19 Jul 2026 05:56:14 +0000 Subject: [PATCH 1207/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-07-19=2005:56:14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 136 ++++++++++++------------- jp/kejilion.sh | 208 ++++++++++++++++++------------------- kr/kejilion.sh | 270 ++++++++++++++++++++++++------------------------- tw/kejilion.sh | 104 +++++++++---------- 4 files changed, 359 insertions(+), 359 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 8e9129591..5c886a5d0 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1748,7 +1748,7 @@ cf_purge_cache() { ZONE_IDS=($ZONE_IDS) else # Prompt user whether to clear cache - read -e -p "需要清理 Cloudflare 的缓存吗? (y/n):" answer + read -e -p "Need to clear Cloudflare's cache? (y/n):" answer if [[ "$answer" == "y" ]]; then echo "CF information is stored in$CONFIG_FILE, you can modify the CF information later" read -e -p "Please enter your API_TOKEN:" API_TOKEN @@ -2942,7 +2942,7 @@ while true; do rm -f /home/docker/${docker_name}_port.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" send_stats "uninstall$docker_name" ;; @@ -3605,7 +3605,7 @@ ldnmp_Proxy_backend() { list_stream_services() { STREAM_DIR="/home/web/stream.d" - printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "local address" "Backend address" + printf "%-25s %-18s %-25s %-20s\n" "Service name" "Communication type" "Local address" "Backend address" if [ -z "$(ls -A "$STREAM_DIR")" ]; then return @@ -4395,7 +4395,7 @@ frps_panel() { close_port 8055 8056 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 5) echo "Reverse intranet penetration service into domain name access" @@ -4492,7 +4492,7 @@ frpc_panel() { close_port 8055 sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; 4) @@ -5532,7 +5532,7 @@ dd_xitong() { ;; 41) - send_stats "Reinstall windows 11" + send_stats "Reinstall Windows 11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "The partition was successfully mounted to$MOUNT_POINT" + echo "Partition successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "Hard disk management function" while true; do clear - echo "Hard disk partition management" + echo "Hard drive partition management" echo -e "${gl_huang}This feature is under internal testing and should not be used in a production environment.${gl_bai}" echo "------------------------" list_partitions @@ -7704,7 +7704,7 @@ linux_tools() { while true; do clear - # send_stats "Basic Tools" + # send_stats "Basic tools" echo -e "basic tools" tools=( @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8706,7 +8706,7 @@ linux_test() { echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" - echo -e "${gl_kjlan}17. ${gl_bai}i-abc multifunctional speed test script" + echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP retransmission detection script${gl_huang}★${gl_bai}" @@ -10099,7 +10099,7 @@ moltbot_menu() { return 1 fi - # Add --no-update-notifier and make sure error redirects are in the correct location + # Add --no-update-notifier and make sure error redirection is in the correct location local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -10157,7 +10157,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API management" + echo "6. API Management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -11211,7 +11211,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: Add {len(added_ids)}, delete {len(removed_ids)}, current {len(new_models)}') +print(f'✅ {target}: Added {len(added_ids)}, deleted {len(removed_ids)}, current {len(new_models)}') if added_ids: print(f'➕ Add new model ({len(added_ids)}):') @@ -12225,7 +12225,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12353,7 +12353,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -13884,7 +13884,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ Model file already exists:$model_path" + echo "✅ The model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory configuration is normal." - echo "Will be executed: clean old indexes → fully rebuild all agent indexes" + echo "Will be executed: Clean old indexes → Fully rebuild all agent indexes" echo "" read -e -p "Confirm execution? (Y/n):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14205,7 +14205,7 @@ EOF echo "document:$file" echo "Total number of rows:$total_lines" read -e -p "Please enter the starting line (Press Enter to default to the end of$default_linesOK):" start_line - read -e -p "Please enter the number of displayed lines (press Enter to default$default_lines): " count + read -e -p "Please enter the number of rows to display (default is to press Enter$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14222,7 +14222,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ The number of rows must be greater than 0." + echo "❌ Number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -14582,7 +14582,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # Fallback: write file directly + # Fallback: Write the file directly echo "$json_payload" > "$approvals_file" } @@ -14682,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ Switched to standard safe mode (all dangerous commands will request your approval through UI/TG)${gl_bai}" + echo -e "${gl_lv}✅ Switched to standard safety mode (all dangerous commands will ask for your approval through UI/TG)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14751,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "Do you want to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice + read -e -p "Attempt to automatically remediate discovered security vulnerabilities? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ Automatic repair completed.${gl_bai}" @@ -15110,7 +15110,7 @@ for idx,item in enumerate(agents,1): read -e -p "Enter yes to confirm to continue:" confirm [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅The agent is created successfully:$agent_id" + echo "✅ The agent was created successfully:$agent_id" local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" @@ -15174,7 +15174,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw multi-agent - remove routing binding" + send_stats "OpenClaw multi-agent - remove route binding" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "Please enter the agent ID:" agent_id @@ -15302,7 +15302,7 @@ print("✅Multi-agent health check completed") echo "6. View session overview" echo "7. Run multi-agent health checks" echo "8. Modify the agent’s identity (name/Emoji)" - echo "9. 清理过期会话" + echo "9. Clean up expired sessions" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" multi_choice @@ -15334,10 +15334,10 @@ openclaw_backup_restore_menu() { openclaw_backup_render_file_list echo "---------------------------------------" echo "1. Back up the entire memory" - echo "2. 还原记忆全量" + echo "2. Restore the full memory" echo "3. Back up the OpenClaw project (default safe mode)" echo "4. Restore OpenClaw Project (Advanced/High Risk)" - echo "5. 删除备份文件" + echo "5. Delete backup files" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" backup_choice @@ -15359,7 +15359,7 @@ openclaw_backup_restore_menu() { update_moltbot() { - echo "更新 OpenClaw..." + echo "Update OpenClaw..." send_stats "Update OpenClaw..." install_node_and_tools git config --global url."${gh_proxy}github.com/".insteadOf ssh://git@github.com/ @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15984,7 +15984,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal services$check_docker $update_status" + echo -e "postal service$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16088,7 +16088,7 @@ while true; do rm -rf /home/docker/mail sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "App uninstalled" + echo "App has been uninstalled" ;; *) @@ -16142,7 +16142,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16240,7 +16240,7 @@ while true; do docker_app_uninstall() { cd /home/docker/cloud/ && docker compose down --rmi all rm -rf /home/docker/cloud - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -16315,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest speed test panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." + local docker_describe="Speedtest speed measurement panel is a VPS network speed test tool with multiple test functions and can also monitor VPS inbound and outbound traffic in real time." local docker_url="Official website introduction:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -17126,7 +17126,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17353,7 +17353,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dify/docker/ && docker compose down --rmi all rm -rf /home/docker/dify - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17405,7 +17405,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17446,7 +17446,7 @@ while true; do cd /opt rm -rf jumpserver-installer*/ rm -rf jumpserver - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17509,7 +17509,7 @@ while true; do docker_app_uninstall() { cd /home/docker/ragflow/docker/ && docker compose down --rmi all rm -rf /home/docker/ragflow - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -17723,7 +17723,7 @@ while true; do } - local docker_describe="It is a lightweight, high-performance music streaming server" + local docker_describe="Is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -17750,7 +17750,7 @@ while true; do } - local docker_describe="A password manager where you can control your data" + local docker_describe="A password manager that puts you in control of your data" local docker_url="Official website introduction: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -17837,7 +17837,7 @@ while true; do docker_app_uninstall() { cd /home/docker/moontv/ && docker compose down --rmi all rm -rf /home/docker/moontv - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18058,7 +18058,7 @@ while true; do docker_app_uninstall() { cd /home/docker/linkwarden && docker compose down --rmi all rm -rf /home/docker/linkwarden - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18122,7 +18122,7 @@ while true; do cd "$(find . -maxdepth 1 -type d -name '*docker-jitsi-meet*' | head -n 1)" docker compose down --rmi all rm -rf /home/docker/jitsi - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18258,7 +18258,7 @@ while true; do docker_app_uninstall() { cd /home/docker/${docker_name} && docker compose down --rmi all rm -rf /home/docker/${docker_name} - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18321,7 +18321,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18485,7 +18485,7 @@ while true; do docker_app_uninstall() { cd /home/docker/gitea/ && docker compose down --rmi all rm -rf /home/docker/gitea - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18623,7 +18623,7 @@ while true; do docker_app_uninstall() { cd /home/docker/paperless/ && docker compose down --rmi all rm -rf /home/docker/paperless - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18677,7 +18677,7 @@ while true; do docker_app_uninstall() { cd /home/docker/2fauth/ && docker compose down --rmi all rm -rf /home/docker/2fauth - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18910,7 +18910,7 @@ while true; do docker_app_uninstall() { cd /home/docker/dsm/ && docker compose down --rmi all rm -rf /home/docker/dsm - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -18981,7 +18981,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19050,7 +19050,7 @@ while true; do docker_app_uninstall() { cd /home/docker/umami/ && docker compose down --rmi all rm -rf /home/docker/umami - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19191,7 +19191,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/LangBot/docker/ && docker compose down --rmi all rm -rf /home/docker/LangBot - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19261,7 +19261,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App uninstalled" + echo "App has been uninstalled" } docker_app_plus @@ -19467,7 +19467,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -19478,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" - echo -e "${gl_kjlan}5. ${gl_bai}Work Area 5" + echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" @@ -19864,7 +19864,7 @@ log_menu() { show_log_overview echo echo "=========== System log management menu ===========" - echo "1. Check the latest system log (journal)" + echo "1. View the latest system log (journal)" echo "2. View the specified service log" echo "3. View login/security logs" echo "4. Real-time tracking logs" @@ -19954,7 +19954,7 @@ env_menu() { show_env_vars() { clear - send_stats "Environment variables currently in effect" + send_stats "Currently in effect environment variables" echo "========== Currently in effect environment variables (excerpt) ==========" printf "%-20s %s\n" "variable name" "value" echo "-----------------------------------------------" @@ -20221,7 +20221,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20407,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 first" - send_stats "Switched to IPv6 first" + echo "Switched to IPv6 priority" + send_stats "Switched to IPv6 priority" ;; 3) @@ -20640,7 +20640,7 @@ EOF echo "America" echo "21. US Western Time 22. US Eastern Time" echo "23. Canada time 24. Mexico time" - echo "25. Brazil Time 26. Argentina Time" + echo "25. Brazil time 26. Argentina time" echo "------------------------" echo "31. UTC global standard time" echo "------------------------" @@ -21418,7 +21418,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Failed to copy file or directory: File or directory does not exist" + send_stats "Copying file or directory failed: File or directory does not exist" continue fi @@ -21550,7 +21550,7 @@ while true; do echo -e "${gl_kjlan}Execute tasks in batches${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}Install technology lion script${gl_kjlan}12. ${gl_bai}Update system${gl_kjlan}13. ${gl_bai}Clean the system" echo -e "${gl_kjlan}14. ${gl_bai}Install docker${gl_kjlan}15. ${gl_bai}Install BBR3${gl_kjlan}16. ${gl_bai}Set 1G virtual memory" - echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}custom directive" + echo -e "${gl_kjlan}17. ${gl_bai}Set time zone to Shanghai${gl_kjlan}18. ${gl_bai}Open all ports${gl_kjlan}51. ${gl_bai}Custom instructions" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}Return to main menu" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21667,7 +21667,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" +echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21948,7 +21948,7 @@ done k_info() { -send_stats "k command reference use case" +send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 7313e6c39..fbcfbfff0 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -1541,7 +1541,7 @@ certs_status() { else send_stats "ドメイン名証明書の申請に失敗しました" echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2241,7 +2241,7 @@ web_security() { echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2561,7 +2561,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2620,7 +2620,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2637,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8を確認して許可します。 + # ローカルネットワーク127.0.0.0/8をチェックして許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3017,7 +3017,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3293,7 +3293,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3755,7 +3755,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3966,7 +3966,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4313,7 +4313,7 @@ generate_access_urls() { done fi - # HTTPS 構成を処理する + # HTTPS 構成の処理 for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -4782,7 +4782,7 @@ linux_clean() { bbr_on() { -# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 +# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4841,7 +4841,7 @@ while true; do echo "2.国内DNSの最適化:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 構成を手動で編集する" + echo "3. DNS 設定を手動で編集する" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -5476,7 +5476,7 @@ dd_xitong() { ;; 30) - send_stats "centos9を再インストールする" + send_stats "CentOS9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5612,7 +5612,7 @@ bbrv3() { os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) + # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi @@ -5624,7 +5624,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません。XanMod ソースを構成できません" + echo "システムコードネームを取得できません、XanMod ソースを構成できません" return 1 fi @@ -5951,7 +5951,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドパラメータを構築する + # clamscan コマンドのパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6380,7 +6380,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linuxカーネルチューニング管理" + send_stats "Linux カーネルのチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6395,9 +6395,9 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -6522,7 +6522,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6827,7 +6827,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7150,7 +7150,7 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションのマウント" + send_stats "パーティションをマウントする" read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" @@ -7192,11 +7192,11 @@ mount_partition() { return 1 fi - echo "パーティションは正常にマウントされました$MOUNT_POINT" + echo "パーティションが正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "ハードディスク管理機能" while true; do clear - echo "ハードディスクのパーティション管理" + echo "ハードドライブのパーティション管理" echo -e "${gl_huang}この機能は内部テスト中であるため、運用環境では使用しないでください。${gl_bai}" echo "------------------------" list_partitions @@ -7327,7 +7327,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7364,7 +7364,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" + kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7380,7 +7380,7 @@ add_task() { case $mode in 1) options="-avz" ;; 2) options="-avz --delete" ;; - *) echo "无效选择,使用默认 -avz"; options="-avz" ;; + *) echo "選択が無効です。デフォルトの -avz を使用してください"; options="-avz" ;; esac echo "$name|$local_path|$remote|$remote_path|$port|$options|$auth_method|$password_or_key" >> "$CONFIG_FILE" @@ -7586,7 +7586,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -7648,7 +7648,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7704,7 +7704,7 @@ linux_tools() { while true; do clear - # send_stats 「基本ツール」 + # send_stats "基本ツール" echo -e "基本的なツール" tools=( @@ -7828,7 +7828,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftopをインストールする" + send_stats "iftop をインストールする" ;; 7) clear @@ -7860,7 +7860,7 @@ linux_tools() { clear echo "ツールはインストールされており、次のように使用されます。" ffmpeg --help - send_stats "ffmpegをインストールする" + send_stats "安装ffmpeg" ;; 11) @@ -7924,7 +7924,7 @@ linux_tools() { clear git --help cd ~ - send_stats "gitをインストールする" + send_stats "安装git" ;; 18) @@ -8225,7 +8225,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8556,7 +8556,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成する" + echo "1. 新しいボリュームを作成します" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -10357,7 +10357,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10436,7 +10436,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10456,7 +10456,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10840,7 +10840,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -11277,7 +11277,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "セットアップする API タイプを選択してください:" + echo "設定したい API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -11556,7 +11556,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入口" + send_stats "OpenClaw APIの入り口" while true; do clear echo "=======================================" @@ -12299,7 +12299,7 @@ PYTHON_EOF if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12344,7 +12344,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12676,7 +12676,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5.WeChatロボットのドッキング" + echo "5. WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -12697,7 +12697,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -14041,7 +14041,7 @@ EOF } openclaw_memory_offer_restart() { - echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 構成は正常です。" - echo "実行予定: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" + echo "実行内容: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" echo "" read -e -p "実行を確認しますか? (はい/いいえ):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14205,7 +14205,7 @@ EOF echo "書類:$file" echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示される行数を入力してください (Enter を押してデフォルトに設定します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14300,7 +14300,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステート検出 (組み込みモデルのチェック)" + echo "6. ディープステートの検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14638,12 +14638,12 @@ try: print("傍受戦略 (セキュリティ):" + str(sec)) print("即時戦略 (質問):" + str(ask)) print("UI カバーなし (AskFallback):" + str(fb)) - print(" 自动放行技能 (autoAllowSkills): " + ("on" if auto else "off")) + print("自動許可スキル:" + ("on" if auto else "off")) exists = d.get("exists", True) if not exists: - print(" (审批文件不存在,使用系统内置安全兜底)") + print("(承認文書は存在しません。システムに組み込まれたセーフティネットを使用してください)") except Exception as e: - print(" (解析失败: " + str(e) + ")") + print("(解析に失敗しました:" + str(e) + ")") ' "$approvals_json" else echo "(openclaw の承認では --json が出力されません)" @@ -14662,7 +14662,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14682,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフ モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を要求します)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14751,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "発見されたセキュリティ脆弱性を自動的に修復しますか? (y/n):" fix_choice + read -e -p "発見されたセキュリティ脆弱性を自動的に修復してみますか? (y/n):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復が完了しました。${gl_bai}" @@ -15110,7 +15110,7 @@ for idx,item in enumerate(agents,1): read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ エージェントが正常に作成されました。$agent_id" + echo "✅ エージェントが正常に作成されました:$agent_id" local name theme read -e -p "エージェント ID 名を入力してください (例: コード エキスパート):" name [ -z "$name" ] && name="$agent_id" @@ -15174,13 +15174,13 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw マルチエージェント - ルーティング バインディングの削除" + send_stats "OpenClaw マルチエージェント - ルート バインディングの削除" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" + echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15389,7 +15389,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 構成ファイルを編集する" + send_stats "OpenClaw 設定ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15549,7 +15549,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初期構成ウィザード" + 11) send_stats "初期設定ウィザード" openclaw onboard --install-daemon break_end ;; @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15651,7 +15651,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -15661,7 +15661,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -16315,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest スピード テスト パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" + local docker_describe="Speedtest 速度測定パネルは、複数のテスト機能を備えた VPS ネットワーク速度テスト ツールで、VPS のインバウンドおよびアウトバウンドのトラフィックをリアルタイムで監視することもできます。" local docker_url="公式サイト紹介:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -17481,7 +17481,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17750,7 +17750,7 @@ while true; do } - local docker_describe="データを管理できるパスワードマネージャー" + local docker_describe="データを管理できるパスワード マネージャー" local docker_url="公式サイト紹介:https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18227,7 +18227,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチピクチャービデオマネージャー" + local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18321,7 +18321,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -18351,7 +18351,7 @@ while true; do } - local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -19467,8 +19467,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19478,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}作業エリア 2" echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" - echo -e "${gl_kjlan}5. ${gl_bai}作業エリア5" + echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" @@ -19806,7 +19806,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19816,7 +19816,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19828,7 +19828,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19864,7 +19864,7 @@ log_menu() { show_log_overview echo echo "=========== システムログ管理メニュー ===========" - echo "1. 最新のシステムログ(ジャーナル)を確認する" + echo "1. 最新のシステムログ(ジャーナル)を表示する" echo "2. 指定したサービスログを表示します。" echo "3. ログイン/セキュリティログの表示" echo "4. リアルタイム追跡ログ" @@ -19879,7 +19879,7 @@ log_menu() { read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19889,7 +19889,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19904,7 +19904,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19992,7 +19992,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -20007,7 +20007,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -20023,7 +20023,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } while true; do @@ -20151,7 +20151,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20226,7 +20226,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認してください: https://www.python.org/downloads/" + echo "他のバージョンを確認する: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -20407,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "最初にIPv6に切り替えました" - send_stats "最初にIPv6に切り替えました" + echo "IPv6優先に切り替えました" + send_stats "IPv6優先に切り替えました" ;; 3) @@ -21110,7 +21110,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21402,7 +21402,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21422,7 +21422,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21545,12 +21545,12 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" echo -e "${gl_kjlan}14. ${gl_bai}ドッカーをインストールする${gl_kjlan}15. ${gl_bai}BBR3をインストールする${gl_kjlan}16. ${gl_bai}1Gの仮想メモリを設定する" - echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタムディレクティブ" + echo -e "${gl_kjlan}17. ${gl_bai}タイムゾーンを上海に設定${gl_kjlan}18. ${gl_bai}すべてのポートを開く${gl_kjlan}51. ${gl_bai}カスタム命令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21583,14 +21583,14 @@ while true; do 4) clear - send_stats "バックアップクラスター" + send_stats "バックアップクラスタ" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -21664,10 +21664,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21948,7 +21948,7 @@ done k_info() { -send_stats "k コマンドリファレンスの使用例" +send_stats "k コマンドのリファレンス例" echo "-------------------" echo "ビデオ紹介: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下は、k コマンドの参考使用例です。" @@ -21964,7 +21964,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | k リモート接続" +echo "ssh リモート接続ツール k ssh | kリモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 0371bf1f9..d022dd6ec 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1099,7 +1099,7 @@ iptables_panel() { echo "3. 모든 포트를 엽니다. 4. 모든 포트를 닫습니다." echo "------------------------" echo "5. IP 화이트리스트 6. IP 블랙리스트" - echo "7. 지정된 IP를 삭제합니다." + echo "7. 지정된 IP 지우기" echo "------------------------" echo "11. PING 허용 12. PING 비활성화" echo "------------------------" @@ -1268,7 +1268,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1546,7 +1546,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -2238,7 +2238,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -3224,7 +3224,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 재정의하며 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3426,7 +3426,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3512,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -3728,7 +3728,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4109,7 +4109,7 @@ EOF donlond_frp frps - # 생성된 정보를 출력 + # 생성된 정보 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4171,7 +4171,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보를 출력 + # 생성된 정보 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -4418,7 +4418,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4986,7 +4986,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" return 1 fi @@ -5058,7 +5058,7 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 원본 인증_키 백업 + # 원래 인증된_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" echo "원본 Authorized_keys 파일이 백업되었습니다." @@ -5138,7 +5138,7 @@ sshkey_panel() { echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." + echo "SSH를 통해 로그인하는 보다 안전한 방법인 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." @@ -5725,7 +5725,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 재시작 후 적용" + echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5735,7 +5735,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" + echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" server_reboot } @@ -5795,7 +5795,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5885,7 +5885,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" + echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -6423,7 +6423,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -6946,7 +6946,7 @@ kj_ssh_read_auth() { KJ_SSH_AUTH_SECRET="$password_or_key" ;; 2) - echo "주요 내용을 붙여넣으세요(붙여넣은 후 Enter를 두 번 누르세요)." + echo "주요 내용을 붙여넣으세요(붙인 후 Enter를 두 번 누르세요)." while IFS= read -r line; do if [[ -z "$line" && "$password_or_key" == *"-----BEGIN"* ]]; then break @@ -7017,13 +7017,13 @@ add_connection() { echo "------------------------" read -e -p "연결 이름을 입력하세요:" name - kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "请输入端口号 (默认: 22): " "root" "22" + kj_ssh_read_host_user_port "IP 주소를 입력하세요:" "사용자 이름을 입력하십시오(기본값: 루트):" "포트 번호를 입력하십시오(기본값: 22):" "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi echo "$name|$KJ_SSH_HOST|$KJ_SSH_USER|$KJ_SSH_PORT|$KJ_SSH_AUTH_SECRET" >> "$CONFIG_FILE" - echo "连接已保存!" + echo "연결이 저장되었습니다!" } @@ -7156,7 +7156,7 @@ mount_partition() { DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" - # 检查分区是否存在 + # 파티션이 존재하는지 확인 if ! lsblk -no NAME | grep -qw "$PARTITION"; then echo "파티션이 존재하지 않습니다!" return 1 @@ -7164,7 +7164,7 @@ mount_partition() { # 마운트되어 있는지 확인해보세요 if mount | grep -qw "$DEVICE"; then - echo "分区已经挂载!" + echo "파티션이 마운트되었습니다!" return 1 fi @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "파티션이 성공적으로 마운트되었습니다.$MOUNT_POINT" + echo "파티션이 다음에 성공적으로 마운트되었습니다.$MOUNT_POINT" # /etc/fstab을 확인하여 UUID 또는 마운트 지점이 이미 존재하는지 확인하세요. if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7308,7 +7308,7 @@ disk_manager() { send_stats "하드디스크 관리 기능" while true; do clear - echo "하드 디스크 파티션 관리" + echo "하드 드라이브 파티션 관리" echo -e "${gl_huang}이 기능은 내부 테스트 중이므로 프로덕션 환경에서는 사용하면 안 됩니다.${gl_bai}" echo "------------------------" list_partitions @@ -8253,7 +8253,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}처리용기:$container${gl_bai}" + echo -e "${gl_lv}처리 용기:$container${gl_bai}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8526,7 +8526,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8572,7 +8572,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8894,7 +8894,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -9285,7 +9285,7 @@ linux_ldnmp() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "" - echo "레디스 주소 : 레디스" + echo "레디스 주소: 레디스" echo "redis 비밀번호: 기본적으로 입력되지 않음" echo "레디스 포트: 6379" echo "" @@ -9295,7 +9295,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9537,7 +9537,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db case $use_db in 1) echo @@ -10148,7 +10148,7 @@ moltbot_menu() { echo "=======================================" echo -e "🦞 KEJILION의 OPENCLAW 관리 도구 🦞" - echo -e "💡 터미널 실행 \033[1;33mk 클로\033[0m 빠르게 메뉴 진입" + echo -e "💡 터미널 실행 \033[1;33mk 클로\033[0m 빠른 메뉴 진입" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 설치" @@ -10557,8 +10557,8 @@ PY install_moltbot() { - echo "OpenClaw 설치를 시작하세요..." - send_stats "OpenClaw 설치를 시작하세요..." + echo "OpenClaw 설치를 시작합니다..." + send_stats "OpenClaw 설치를 시작합니다..." install git jq install_node_and_tools @@ -11211,7 +11211,7 @@ if changed: json.dump(work, f, ensure_ascii=False, indent=2) f.write('\n') -print(f'✅ {target}: {len(add_ids)} 추가, {len(removed_ids)} 삭제, 현재 {len(new_models)}') +print(f'✅ {target}: {len(add_ids)} 추가, 삭제 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: print(f'➕ 새 모델 추가({len(add_ids)}):') @@ -11485,7 +11485,7 @@ PY ;; 3) send_stats "OpenClaw API 삭제 취소" - echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." + echo "❌ 삭제 실패: 대체 모델이 없으며 원래 구성이 유지되었습니다." ;; *) echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." @@ -11893,7 +11893,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11961,7 +11961,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12118,7 +12118,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -12225,7 +12225,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12249,7 +12249,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인:$plugin_id" + echo "🔍 플러그인 상태 확인 중:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12353,7 +12353,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -13035,7 +13035,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -13572,7 +13572,7 @@ PY if [ "$qmd_ok" = "true" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD 사용 가능") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("未检测到 QMD") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD가 감지되지 않음") fi if [ -n "$model_path" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로:$model_path") @@ -13580,14 +13580,14 @@ PY OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 경로가 구성되지 않았습니다.") fi case "$model_status" in - ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型文件存在") ;; + ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재합니다.") ;; hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("모델은 HF 다운로드 소스에서 제공됩니다(중국에서는 느리거나 실패할 수 있음).") ;; *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("로컬 모델 파일이 존재하지 않거나 사용할 수 없습니다.") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co에 액세스할 수 있습니다.") elif [ "$mirror_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com 可访问") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") else OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") fi @@ -13666,7 +13666,7 @@ PY wget -O "$dest" "$url" return $? fi - echo "❌ 未检测到 curl 或 wget,无法下载。" + echo "❌ Curl이나 wget이 감지되지 않아 다운로드할 수 없습니다." return 1 } @@ -13690,20 +13690,20 @@ PY echo "✅ 롤빵이 이미 존재합니다" return 0 fi - echo "⬇️ 安装 bun..." + echo "⬇️ 번 설치..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 未检测到 curl 或 wget,无法安装 bun。" + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 安装完成" + echo "✅ 번 설치 완료" return 0 fi echo "❌ 번 설치 실패" @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행됩니다: 이전 인덱스 정리 → 모든 에이전트 인덱스를 완전히 재구축합니다." + echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14116,7 +14116,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14205,7 +14205,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시된 줄 수를 입력하십시오(기본값으로 돌아가려면 Enter를 누르십시오).$default_lines): " count + read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14317,7 +14317,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14582,7 +14582,7 @@ print(json.dumps(data, indent=2)) if openclaw_has_command openclaw && echo "$json_payload" | openclaw approvals set --stdin >/dev/null 2>&1; then return 0 fi - # 대체: 파일 직접 쓰기 + # 대체: 파일을 직접 작성 echo "$json_payload" > "$approvals_file" } @@ -14670,7 +14670,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14682,14 +14682,14 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 모든 명령은 UI/TG를 통해 승인을 요청합니다)${gl_bai}" + echo -e "${gl_lv}✅ 표준 안전 모드로 전환(위험한 명령은 모두 UI/TG를 통해 승인을 요청합니다)${gl_bai}" } openclaw_permission_apply_developer() { send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14707,7 +14707,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14751,7 +14751,7 @@ except Exception: echo "=======================================" openclaw security audit echo "---------------------------------------" - read -e -p "발견된 보안 취약점을 자동으로 해결하시겠습니까? (예/아니요):" fix_choice + read -e -p "발견된 보안 취약점을 자동으로 해결하려고 합니까? (예/아니요):" fix_choice if [[ "$fix_choice" == "y" || "$fix_choice" == "Y" || "$fix_choice" == "yes" ]]; then openclaw security audit --fix echo -e "${gl_lv}✅ 자동 복구가 완료되었습니다.${gl_bai}" @@ -14801,7 +14801,7 @@ except Exception as e: read -e -p "선택하세요:" al_choice case "$al_choice" in 1) - read -e -p "해제할 명령 경로를 입력하세요(/usr/bin/git와 같은 glob 지원)." pattern + read -e -p "해제할 명령 경로를 입력하십시오(/usr/bin/git와 같은 glob 지원)." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } read -e -p "에이전트 ID 지정(비워 두기 = 모든 에이전트 *):" agent_id agent_id="${agent_id:-*}" @@ -14809,7 +14809,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15110,7 +15110,7 @@ for idx,item in enumerate(agents,1): read -e -p "계속하려면 yes를 입력하여 확인하세요." confirm [ "$confirm" = "yes" ] || { echo "취소"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅에이전트가 성공적으로 생성되었습니다:$agent_id" + echo "✅ 에이전트가 성공적으로 생성되었습니다:$agent_id" local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" @@ -15174,7 +15174,7 @@ for idx,item in enumerate(bindings,1): } openclaw_multiagent_remove_binding() { - send_stats "OpenClaw 다중 에이전트 - 라우팅 바인딩 제거" + send_stats "OpenClaw 다중 에이전트 - 경로 바인딩 제거" openclaw_multiagent_require_openclaw || return 1 local agent_id bind_value confirm read -e -p "상담원 ID를 입력하세요:" agent_id @@ -15549,11 +15549,11 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初始化配置向导" + 11) send_stats "초기 구성 마법사" openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 수리" + 12) send_stats "상태 감지 및 복구" openclaw doctor --fix break_end ;; @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15673,13 +15673,13 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" - echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -15884,7 +15884,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -15895,7 +15895,7 @@ while true; do ;; 7|nezha) clear - send_stats "나타 빌드" + send_stats "네자 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -15904,7 +15904,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "나타 모니터링$check_docker $update_status" + echo -e "네자 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -15984,7 +15984,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우편 서비스$check_docker $update_status" + echo -e "우정$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -16315,7 +16315,7 @@ while true; do } - local docker_describe="Speedtest 속도 테스트 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." + local docker_describe="Speedtest 속도 측정 패널은 다양한 테스트 기능을 갖춘 VPS 네트워크 속도 테스트 도구이며 VPS 인바운드 및 아웃바운드 트래픽을 실시간으로 모니터링할 수도 있습니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/wikihost-opensource/als" local docker_use="" local docker_passwd="" @@ -16584,7 +16584,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16723,7 +16723,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개: https://www.photoprism.app/" + local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -16750,7 +16750,7 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 Docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" @@ -16955,7 +16955,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" - local panelname="AcePanel 原耗子面板" + local panelname="AcePanel 오리지널 마우스 패널" local panelurl="공식 주소:${gh_proxy}github.com/acepanel/panel" panel_app_install() { @@ -17417,7 +17417,7 @@ while true; do local app_id="60" local app_name="JumpServer 오픈 소스 요새 머신" - local app_text="오픈소스 권한 있는 액세스 관리(PAM) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." + local app_text="오픈소스 PAM(Privileged Access Management) 도구입니다. 이 프로그램은 포트 80을 사용하며 액세스를 위한 도메인 이름 추가를 지원하지 않습니다." local app_url="공식 소개:${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" @@ -17750,7 +17750,7 @@ while true; do } - local docker_describe="데이터를 제어할 수 있는 비밀번호 관리자" + local docker_describe="귀하의 데이터를 통제할 수 있는 비밀번호 관리자" local docker_url="공식 홈페이지 소개: https://bitwarden.com/" local docker_use="" local docker_passwd="" @@ -18321,9 +18321,9 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" - local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 적시에 로그인 비밀번호를 변경하세요\"" + local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" local app_size="1" docker_app @@ -18353,7 +18353,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -18952,7 +18952,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19467,7 +19467,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -19478,7 +19478,7 @@ linux_work() { echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" - echo -e "${gl_kjlan}5. ${gl_bai}작업 영역 5" + echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" @@ -19580,7 +19580,7 @@ linux_work() { echo -e "SSH 상주 모드${tmux_sshd_status}" echo "SSH 연결을 연 후 바로 상주 모드로 들어가고 이전 작업 상태로 바로 돌아갑니다." echo "------------------------" - echo "1. 켜짐 2. 꺼짐" + echo "1. 켜기 2. 끄기" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -19672,7 +19672,7 @@ switch_mirror() { --install-epel false \ --pure-mode else - echo "使用海外镜像源..." + echo "해외 미러 소스를 활용하세요.." if [ -f /etc/os-release ] && grep -qi "oracle" /etc/os-release; then bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.xtom.com \ @@ -19741,7 +19741,7 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH防御基础参数配置" + send_stats "SSH 방어 기본 매개변수 구성" f2b_basic_config break_end ;; @@ -19770,10 +19770,10 @@ fail2ban_panel() { net_menu() { - send_stats "网卡管理工具" + send_stats "네트워크 카드 관리 도구" show_nics() { echo "================ 현재 네트워크 카드 정보 =================" - printf "%-18s %-12s %-20s %-26s\n" "网卡名" "상태" "IP 주소" "MAC 주소" + printf "%-18s %-12s %-20s %-26s\n" "네트워크 카드 이름" "상태" "IP 주소" "MAC 주소" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -19790,7 +19790,7 @@ net_menu() { echo echo "=========== 네트워크 카드 관리 메뉴 ===========" echo "1. 네트워크 카드 활성화" - echo "2. 禁用网卡" + echo "2. 네트워크 카드 비활성화" echo "3. 네트워크 카드 세부정보 보기" echo "4. 네트워크 카드 정보 새로 고침" echo "0. 이전 메뉴로 돌아가기" @@ -19800,17 +19800,17 @@ net_menu() { case $choice in 1) send_stats "네트워크 카드 활성화" - read -erp "请输入要启用的网卡名: " nic + read -erp "활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" up && echo "✔ 네트워크 카드$nic활성화됨" else - echo "✘ 网卡不存在" + echo "✘ 네트워크 카드가 존재하지 않습니다." fi read -erp "계속하려면 Enter를 누르세요..." ;; 2) - send_stats "禁用网卡" - read -erp "请输入要禁用的网卡名: " nic + send_stats "네트워크 카드 비활성화" + read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" else @@ -19849,7 +19849,7 @@ log_menu() { show_log_overview() { echo "============= 시스템 로그 개요 =============" echo "호스트 이름: $(호스트 이름)" - echo "系统时间: $(date)" + echo "시스템 시간: $(날짜)" echo echo "[/var/log 디렉토리 직업]" du -sh /var/log 2>/dev/null @@ -19864,18 +19864,18 @@ log_menu() { show_log_overview echo echo "=========== 시스템 로그 관리 메뉴 ===========" - echo "1. 최신 시스템 로그(일지)를 확인하세요." + echo "1. 최신 시스템 로그(일지) 보기" echo "2. 지정된 서비스 로그 보기" echo "3. 로그인/보안 로그 보기" - echo "4. 实时跟踪日志" - echo "5. 清理旧 journal 日志" + echo "4. 실시간 추적 로그" + echo "5. 오래된 저널 로그 정리" echo "0. 이전 메뉴로 돌아가기" echo "=======================================" read -erp "작업을 선택하십시오:" choice case $choice in 1) - send_stats "查看最近日志" + send_stats "최근 로그 보기" read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager @@ -19892,7 +19892,7 @@ log_menu() { read -erp "계속하려면 Enter를 누르세요..." ;; 3) - send_stats "查看登录/安全日志" + send_stats "로그인/보안 로그 보기" echo "====== 최근 로그인 로그 ======" last -n 10 echo @@ -19909,7 +19909,7 @@ log_menu() { 4) send_stats "실시간 추적 로그" echo "1) 시스템 로그" - echo "2) 指定服务日志" + echo "2) 서비스 로그 지정" read -erp "추적 유형 선택:" t if [ "$t" = "1" ]; then journalctl -f @@ -19922,10 +19922,10 @@ log_menu() { ;; 5) send_stats "오래된 저널 로그 정리" - echo "⚠️ 清理 journal 日志(安全方式)" - echo "1) 保留最近 7 天" - echo "2) 保留最近 3 天" - echo "3) 限制日志最大 500M" + echo "⚠️ 일지를 청소하세요(안전한 방법)" + echo "1) 최근 7일을 보관" + echo "2) 최근 3일을 보관한다" + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -19933,7 +19933,7 @@ log_menu() { 3) journalctl --vacuum-size=500M ;; *) echo "잘못된 옵션" ;; esac - echo "✔ journal 日志清理完成" + echo "✔ 저널 로그 정리 완료" sleep 2 ;; *) @@ -19967,14 +19967,14 @@ env_menu() { echo "$PATH" | tr ':' '\n' | nl -ba echo - echo "========== 配置文件中定义的变量(解析) ==========" + echo "========== 구성 파일에 정의된 변수(파싱) ==========" parse_file_vars() { local file="$1" [ -f "$file" ] || return echo - echo ">>> 来源文件:$file" + echo ">>> 소스 파일:$file" echo "-----------------------------------------------" # 내보내기 VAR=xxx 또는 VAR=xxx 추출 @@ -20031,9 +20031,9 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 查看当前常用环境变量" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" - echo "3. 查看 ~/.profile" + echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" echo "5. ~/.profile 편집" echo "6. 환경 변수 다시 로드(출처)" @@ -20097,7 +20097,7 @@ create_user_with_sshkey() { fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "公钥直接导入" + send_stats "공개 키를 직접 가져오기" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) @@ -20112,7 +20112,7 @@ create_user_with_sshkey() { install sudo - # sudo 免密 + # sudo 비밀번호가 필요하지 않음 if [[ "$is_sudo" == "true" ]]; then cat >"/etc/sudoers.d/$new_username" < /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20958,7 +20958,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21418,7 +21418,7 @@ linux_file() { read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -21550,7 +21550,7 @@ while true; do echo -e "${gl_kjlan}일괄적으로 작업 실행${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}기술 사자 스크립트 설치${gl_kjlan}12. ${gl_bai}시스템 업데이트${gl_kjlan}13. ${gl_bai}시스템 청소" echo -e "${gl_kjlan}14. ${gl_bai}도커 설치${gl_kjlan}15. ${gl_bai}BBR3 설치${gl_kjlan}16. ${gl_bai}1G 가상 메모리 설정" - echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}사용자 정의 지시어" + echo -e "${gl_kjlan}17. ${gl_bai}시간대를 상하이로 설정${gl_kjlan}18. ${gl_bai}모든 포트 열기${gl_kjlan}51. ${gl_bai}맞춤 지침" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -21591,7 +21591,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21667,7 +21667,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 Tokyo Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21824,7 +21824,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}업데이트에 실패했습니다! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" + echo -e "${gl_hong}업데이트 실패! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" send_stats "스크립트 업데이트 실패" fi break_end @@ -21948,7 +21948,7 @@ done k_info() { -send_stats "k 명령 참조 사용 사례" +send_stats "k 명령 참조 예" echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." @@ -21992,7 +21992,7 @@ echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "애플리케이션 시장관리 kapp" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" echo "Fail2ban 관리 k Fail2ban | 케이 F2B" echo "시스템 정보 표시 k 정보" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 2a348ec5a..4db925412 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -649,7 +649,7 @@ while true; do done ;; 3) - send_stats "删除镜像" + send_stats "刪除鏡像" read -e -p "請輸入鏡像名稱(多個鏡像名稱請以空格分隔):" imagenames for name in $imagenames; do docker rmi -f $name @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分區 + # 取得目前系統中所有的 swap 分割區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -2233,7 +2233,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) @@ -3351,7 +3351,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "無法再次安裝LDNMP環境" + send_stats "无法再次安装LDNMP环境" echo -e "${gl_huang}提示:${gl_bai}建站環境已安裝。無需再次安裝!" break_end linux_ldnmp @@ -3740,7 +3740,7 @@ ldnmp_Proxy_backend_stream() { fi # 取得監聽埠 - read -erp "请输入本机监听端口 (如 3306): " listen_port + read -erp "請輸入本機監聽埠 (如 3306):" listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "連接埠必須是數字"; return 1 fi @@ -4109,7 +4109,7 @@ EOF donlond_frp frps - # 輸出產生的信息 + # 输出生成的信息 ip_address echo "------------------------" echo "客戶端部署時所需使用的參數" @@ -4172,7 +4172,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入 frpc.toml" + echo "服務$service_name已成功加入到 frpc.toml" docker restart frpc @@ -4627,7 +4627,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音訊下載完成,按任意鍵繼續..." ;; + read -e -p "音频下载完成,按任意键继续..." ;; 9) send_stats "刪除影片" @@ -4788,7 +4788,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版本 sysctl.conf 殘留 +# 清理可能導致衝突的舊版 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5280,7 +5280,7 @@ dd_xitong() { dd_xitong_1() { echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" - echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" + echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -5725,7 +5725,7 @@ bbrv3() { echo "BBR3參數寫入失敗,請檢查系統配置" return 1 } - echo "XanMod BBRv3內核處理完成。重啟後生效" + echo "XanMod BBRv3內核處理完成。重启后生效" server_reboot } @@ -5794,7 +5794,7 @@ bbrv3() { echo "設定BBR3加速" echo "影片介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "僅支援Debian/Ubuntu" + echo "仅支持Debian/Ubuntu" echo "請備份數據,將為你升級Linux核心開啟BBR3" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -6702,7 +6702,7 @@ create_backup() { # 提示使用者輸入備份目錄 echo "建立備份範例:" - echo "- 備份單一目錄: /var/www" + echo " - 备份单个目录: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input @@ -6719,7 +6719,7 @@ create_backup() { IFS=' ' read -r -a BACKUP_PATHS <<< "$input" fi - # 生成备份文件前缀 + # 產生備份檔案前綴 local PREFIX="" for path in "${BACKUP_PATHS[@]}"; do # 提取目錄名稱並去除斜杠 @@ -7076,7 +7076,7 @@ use_connection() { else # 使用密碼連接 if ! command -v sshpass &> /dev/null; then - echo "错误:未安装 sshpass,请先安装 sshpass。" + echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "分區已成功掛載到$MOUNT_POINT" + echo "分割區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8369,7 +8369,7 @@ docker_ssh_migration() { list_backups echo -e "" echo "------------------------" - echo -e "1. 備份docker項目" + echo -e "1. 备份docker项目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" echo -e "4. 刪除docker專案的備份文件" @@ -9528,7 +9528,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}5/6${gl_bai}] 編輯網站配置" echo "-------------" - echo "按任一鍵繼續,可詳細設定網站配置,如偽靜態等內容" + echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf @@ -10443,7 +10443,7 @@ for name, provider in list(providers.items()): continue if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重試後成功') + summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): summary.append(f'⚠️ 跳過 {name}: /models 回傳結構不可識別') @@ -10456,7 +10456,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 為空,無法為該 provider 提供兜底模型') + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10714,7 +10714,7 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" } - # 核心函數:取得並加入所有模型 + # 核心函数:获取并添加所有模型 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" @@ -10785,7 +10785,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -11144,7 +11144,7 @@ for item in data['data']: remote_ids.append(str(item['id'])) remote_set = set(remote_ids) if not remote_set: - print(f'❌ {target}: 上游 /models 为空,已中止同步') + print(f'❌ {target}: 上游 /models 為空,已中止同步') raise SystemExit(5) local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -14331,7 +14331,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -15119,7 +15119,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體建立失敗" + echo "❌ 智能體創建失敗" return 1 fi } @@ -15437,7 +15437,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15671,7 +15671,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -18151,7 +18151,7 @@ while true; do } - local docker_describe="高效能AI介面透明代理服務" + local docker_describe="高性能AI接口透明代理服务" local docker_url="官網介紹: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" @@ -18951,7 +18951,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19220,7 +19220,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一個適用於個人或小型團隊的線上網盤程式。" + local docker_describe="是一个适用于个人或小团队的在线网盘程序。" local docker_url="官網介紹:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" @@ -19770,7 +19770,7 @@ fail2ban_panel() { net_menu() { - send_stats "網路卡管理工具" + send_stats "网卡管理工具" show_nics() { echo "================ 目前網卡資訊 ==================" printf "%-18s %-12s %-20s %-26s\n" "網路卡名" "狀態" "IP位址" "MAC位址" @@ -20088,16 +20088,16 @@ create_user_with_sshkey() { echo "導入公鑰範例:" echo " - URL: ${gh_https_url}github.com/torvalds.keys" - echo "- 直接貼上: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." - read -e -p "請導入${new_username}的公鑰:" sshkey_vl + echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "請導入${new_username} 的公钥: " sshkey_vl case "$sshkey_vl" in http://*|https://*) - send_stats "從 URL 匯入 SSH 公鑰" + send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "公鑰直接導入" + send_stats "公钥直接导入" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) @@ -20958,7 +20958,7 @@ EOF root_use send_stats "電報預警" echo "TG-bot監控預警功能" - echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" + echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" @@ -21547,9 +21547,9 @@ while true; do echo -e "${gl_kjlan}1. ${gl_bai}新增伺服器${gl_kjlan}2. ${gl_bai}刪除伺服器${gl_kjlan}3. ${gl_bai}編輯伺服器" echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}批次執行任務${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" - echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" + echo -e "${gl_kjlan}批量执行任务${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系统 ${gl_kjlan}13. ${gl_bai}清理系统" + echo -e "${gl_kjlan}14. ${gl_bai}安装docker ${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -21824,7 +21824,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -21962,32 +21962,32 @@ echo "bbr3控制面板 k bbr3 | k bbrv3" echo "核心調優面板 k nhyh | k 核心最佳化" echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" -echo "系统回收站 k trash | k hsz | k 回收站" +echo "系統回收站 k trash | k hsz | k 回收站" echo "系統備份功能 k backup | k bf | k 備份" echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" -echo "硬盘管理工具 k disk | k 硬盘管理" +echo "硬碟管理工具 k disk | k 硬碟管理" echo "內網穿透(服務端) k frps" echo "內網穿透(客戶端) k frpc" echo "軟體啟動 k start sshd | k 啟動 sshd" -echo "软件停止 k stop sshd | k 停止 sshd " +echo "軟體停止 k stop sshd | k 停止 sshd" echo "軟體重啟 k restart sshd | k 重啟 sshd" echo "軟體狀態檢視 k status sshd | k 狀態 sshd" echo "軟體開機啟動 k enable docker | k autostart docke | k 開機啟動 docker" echo "網域憑證申請 k ssl" -echo "域名证书到期查询 k ssl ps" +echo "網域名稱憑證到期查詢 k ssl ps" echo "docker管理平面 k docker" echo "docker環境安裝 k docker install |k docker 安裝" -echo "docker容器管理 k docker ps |k docker 容器" -echo "docker镜像管理 k docker img |k docker 镜像" -echo "LDNMP站点管理 k web" -echo "LDNMP缓存清理 k web cache" +echo "docker容器管理 k docker ps |k docker 容器" +echo "docker映像管理 k docker img |k docker 映像" +echo "LDNMP站台管理 k web" +echo "LDNMP快取清理 k web cache" echo "安裝WordPress k wp |k wordpress |k wp xxx.com" echo "安裝反向代理 k fd |k rp |k 反代 |k fd xxx.com" echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" -echo "开放端口 k dkdk 8080 |k 打开端口 8080" +echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" @@ -22164,18 +22164,18 @@ else enable|autostart|开机启动) shift - send_stats "软件开机自启" + send_stats "軟體開機自啟" enable "$@" ;; ssl) shift if [ "$1" = "ps" ]; then - send_stats "查看证书状态" + send_stats "查看證書狀態" ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "快速申请证书" + send_stats "快速申請證書" elif [ -n "$1" ]; then add_ssl "$1" send_stats "快速申請證書" From fdf771abad442db1306723bd32e172d7a260596f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 26 Jul 2026 06:07:22 +0000 Subject: [PATCH 1208/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-07-26=2006:07:22?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 68 ++++++++++---------- jp/kejilion.sh | 164 ++++++++++++++++++++++++------------------------- kr/kejilion.sh | 162 ++++++++++++++++++++++++------------------------ tw/kejilion.sh | 76 +++++++++++------------ 4 files changed, 235 insertions(+), 235 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 5c886a5d0..5cb2c634e 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -63,7 +63,7 @@ CheckFirstRun_true() { -# This function collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! +# A function that collects function buried information and records the current script version number, usage time, system version, CPU architecture, machine country and function name used by the user. It does not involve any sensitive information, so don’t worry! Please believe me! # Why is this function designed? The purpose is to better understand the functions that users like to use, and to further optimize the functions and launch more functions that meet user needs. # The full text can be searched for the send_stats function call location. It is transparent and open source. If you have any concerns, you can refuse to use it. @@ -754,7 +754,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # Check if the configuration file exists, if not create the file and write the default settings + # Check if the configuration file exists, if not create the file and write default settings if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -2241,7 +2241,7 @@ web_security() { echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and obtain${gl_huang}Global API Key${gl_bai}" echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -3224,7 +3224,7 @@ f2b_sshd() { # Basic parameter configuration: ban duration (bantime), time window (findtime), number of retries (maxretry) # illustrate: -# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overrides the default jail configuration and is not easy to lose when upgrading) +# - Prioritize writing to /etc/fail2ban/jail.d/sshd.local (overwrites the default jail configuration and is not easy to lose when upgrading) # - If it is Alpine and the jail names are different, still write sshd.local; Fail2Ban will match according to the jail name. f2b_basic_config() { root_use @@ -5096,7 +5096,7 @@ fetch_github_ssh_keys() { local username="$1" local base_dir="${2:-$HOME}" - echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" + echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" echo "1. Log in${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" @@ -5138,7 +5138,7 @@ sshkey_panel() { echo -e "User key login mode${IS_KEY_ENABLED}" echo "Advanced gameplay: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "A key pair will be generated, a more secure way to log in via SSH" + echo "A key pair will be generated for a more secure way to log in via SSH" echo "------------------------" echo "1. Generate a new key pair 2. Manually enter an existing public key" echo "3. Import the existing public key from GitHub 4. Import the existing public key from the URL" @@ -5749,7 +5749,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "The current environment does not support it. Only Debian and Ubuntu systems are supported." + echo "The current environment does not support it, only Debian and Ubuntu systems are supported." break_end linux_Settings fi @@ -6158,7 +6158,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── Additional live broadcast scenarios: UDP buffer enlarged ── + # ── Extras for live broadcast scenarios: UDP buffer enlarged ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -6695,9 +6695,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create backup +# Create a backup create_backup() { - send_stats "Create backup" + send_stats "Create a backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6739,7 +6739,7 @@ create_backup() { echo "- $path" done - # Create backup + # Create a backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in using key + # Log in with key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -9162,7 +9162,7 @@ linux_ldnmp() { 4) clear - # Kedao cloud desktop + # 可道云桌面 webname="Kedao cloud desktop" send_stats "Install$webname" echo "Start deployment$webname" @@ -10157,7 +10157,7 @@ moltbot_menu() { echo "--------------------" echo "4. View status log" echo "5. Change model" - echo "6. API Management" + echo "6. API management" echo "7. Robot connection and docking" echo "8. Plug-in management (installation/removal)" echo "9. Skill management (installation/removal)" @@ -10609,7 +10609,7 @@ PY # OpenClaw API protocol detection logic has been removed: API types are no longer automatically detected/determined. - # Note: The API type is explicitly configured by the user (models.providers..api), and the script no longer attempts to call /responses for inference. + # Note: The API type is configured explicitly by the user (models.providers..api), and the script no longer attempts to call /responses for inference. # Construct model configuration JSON build-openclaw-provider-models-json() { @@ -10811,7 +10811,7 @@ EOF echo done - # 4. No longer detecting/determining API types; protocols are selected and maintained by users themselves + # 4. No longer detecting/judging API types; protocols are selected and maintained by users themselves # 5. Get model list echo "🔍 Getting list of available models..." @@ -13884,7 +13884,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ The model file already exists:$model_path" + echo "✅ Model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14065,7 +14065,7 @@ EOF echo "=======================================" echo "Index repair diagnostics" echo "=======================================" - echo "Current includeDefaultMemory: ${include_dm:-not set}" + echo "Currently includeDefaultMemory: ${include_dm:-not set}" echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ includeDefaultMemory=false detected" @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory configuration is normal." - echo "Will be executed: Clean old indexes → Fully rebuild all agent indexes" + echo "Will be executed: clean old indexes → fully rebuild all agent indexes" echo "" read -e -p "Confirm execution? (Y/n):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14278,7 +14278,7 @@ EOF echo "Keywords cannot be empty." return 1 fi - echo "Searching memory..." + echo "正在搜索记忆..." openclaw memory search "$query" --max-results 5 } @@ -14420,7 +14420,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ openclaw is not detected and OpenClaw Gateway cannot be restarted." + echo "❌ OpenClaw is not detected and OpenClaw Gateway cannot be restarted." return 1 fi echo "Restarting OpenClaw Gateway..." @@ -15114,7 +15114,7 @@ for idx,item in enumerate(agents,1): local name theme read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name [ -z "$name" ] && name="$agent_id" - read -e -p "Please enter the agent personality theme (eg: rigorous, efficient):" theme + read -e -p "Please enter the agent personality theme (for example: rigorous, efficient):" theme [ -z "$theme" ] && theme="assistant" echo "Configuring agent identity..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15995,13 +15995,13 @@ while true; do if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then echo -e "${gl_lv}port$portCurrently available${gl_bai}" else - echo -e "${gl_hong}port$portCurrently unavailable${gl_bai}" + echo -e "${gl_hong}端口 $portCurrently unavailable${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "Visit address:" + echo "访问地址: " echo "https://$yuming" fi @@ -17529,7 +17529,7 @@ while true; do } - local docker_describe="OpenWebUI is a large language model web page framework, the official simplified version supports API access to all major models." + local docker_describe="OpenWebUI is a large language model web page framework, the official streamlined version supports API access to all major models." local docker_url="Official website introduction:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" @@ -17694,7 +17694,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -19467,7 +19467,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -19876,7 +19876,7 @@ log_menu() { case $choice in 1) send_stats "View recent logs" - read -erp "How many recent log lines have you viewed? [Default 100]:" lines + read -erp "View the most recent log lines? [Default 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Press Enter to continue..." @@ -20221,7 +20221,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by python!" + echo "This function can seamlessly install any version officially supported by Python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20407,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "Switched to IPv6 priority" - send_stats "Switched to IPv6 priority" + echo "Switched to IPv6 first" + send_stats "Switched to IPv6 first" ;; 3) @@ -21667,7 +21667,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 6.9 dollars per month Tokyo Softbank 2 cores 1G memory 20G hard drive 1T traffic per month${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}More popular VPS deals${gl_bai}" +echo -e "${gl_kjlan}More popular VPS offers${gl_bai}" echo -e "${gl_bai}Website: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21973,7 +21973,7 @@ echo "Software startup k start sshd | k start sshd" echo "Software stop k stop sshd | k stop sshd" echo "Software restart k restart sshd | k restart sshd" echo "Check software status k status sshd | k status sshd" -echo "k enable docker | k autostart docker | k enable docker when booting the software" +echo "k enable docker | k autostart docker | k start docker on startup" echo "Domain name certificate application k ssl" echo "Domain name certificate expiry query k ssl ps" echo "docker management plane k docker" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index fbcfbfff0..5fac0879d 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -63,9 +63,9 @@ CheckFirstRun_true() { -# この機能は、機能の埋め込み情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、およびユーザーが使用した機能名を記録します。機密情報は含まれませんので、ご安心ください。信じてください! +# 関数の埋もれた情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、ユーザーが使用した関数名を記録する機能。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -125,7 +125,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -754,7 +754,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成し、デフォルト設定を書き込みます + # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成してデフォルト設定を書き込みます if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -867,12 +867,12 @@ open_port() { if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンしました$port" + echo "ポートがオープンされました$port" fi done save_iptables_rules - send_stats "ポートがオープンしました" + send_stats "ポートがオープンされました" } @@ -1195,7 +1195,7 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; @@ -2122,7 +2122,7 @@ web_security() { echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" - echo "11. インターセプトパラメータを設定します。 12. ブロックされた IP をすべてクリアします。" + echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" echo "------------------------" echo "21. クラウドフレア モード 22. 高負荷時に 5 秒間のシールドを有効にする" echo "------------------------" @@ -2241,7 +2241,7 @@ web_security() { echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側にある API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側の API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2355,7 +2355,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2561,7 +2561,7 @@ check_docker_image_update() { # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -3224,7 +3224,7 @@ f2b_sshd() { # 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) # 例証します: -# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定をオーバーライドし、アップグレード時に失われにくくなります) +# - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 f2b_basic_config() { root_use @@ -3456,7 +3456,7 @@ ldnmp_wp() { webname="WordPress" yuming="${1:-}" send_stats "インストール$webname" - echo "導入を開始する$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -3755,7 +3755,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無効な選択"; return 1 ;; esac - read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "1 つ以上のバックエンド IP + ポートをスペースで区切って入力してください (例: 10.13.0.2:3306 10.13.0.3:3306)。" reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -3966,7 +3966,7 @@ ldnmp_web_status() { 8) send_stats "サイト構成を編集する" - read -e -p "サイト設定を編集するには、編集するドメイン名を入力してください:" yuming + read -e -p "サイト構成を編集するには、編集するドメイン名を入力してください:" yuming install nano nano /home/web/conf.d/$yuming.conf docker exec nginx nginx -s reload @@ -4596,7 +4596,7 @@ yt_menu_pro() { send_stats "ビデオのバッチダウンロード" install nano if [ ! -f "$URL_FILE" ]; then - echo -e "# 複数のビデオ リンク アドレスを入力します\n# https://www.bilibili.com/bangumi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" + echo -e "# 複数のビデオ リンク アドレスを入力します\n# https://www.bilibili.com/banguchi/play/ep733316?spm_id_from=333.337.0.0&from_spmid=666.25.episode.0" > "$URL_FILE" fi nano $URL_FILE echo "今すぐバッチダウンロードを開始してください..." @@ -4782,7 +4782,7 @@ linux_clean() { bbr_on() { -# カーネルチューニングモジュールとの競合を防ぐためのsysctl.dへの書き込みを統合 +# カーネル チューニング モジュールとの競合を防ぐための sysctl.d への書き込みを統合しました。 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5138,7 +5138,7 @@ sshkey_panel() { echo -e "ユーザーキーログインモード${IS_KEY_ENABLED}" echo "高度なゲームプレイ: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" + echo "SSH 経由でログインするためのより安全な方法のためにキー ペアが生成されます。" echo "------------------------" echo "1. 新しいキーペアを生成します。 2. 既存の公開キーを手動で入力します。" echo "3. GitHub から既存の公開キーをインポートします。 4. URL から既存の公開キーをインポートします。" @@ -5749,7 +5749,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "現在の環境では対応しておりません。 Debian および Ubuntu システムのみがサポートされています。" + echo "現在の環境ではサポートされていません。Debian と Ubuntu システムのみがサポートされています。" break_end linux_Settings fi @@ -5951,7 +5951,7 @@ clamav_scan() { MOUNT_PARAMS+="--mount type=bind,source=${dir},target=/mnt/host${dir} " done - # clamscan コマンドのパラメータを構築する + # clamscan コマンドパラメータを構築する local SCAN_PARAMS="" for dir in "$@"; do SCAN_PARAMS+="/mnt/host${dir} " @@ -6158,7 +6158,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── ライブブロードキャストシナリオの追加:UDPバッファの拡大 ── + # ── 生放送シナリオ追加:UDPバッファ拡大 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -6695,9 +6695,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップの作成 +# バックアップを作成する create_backup() { - send_stats "バックアップの作成" + send_stats "バックアップを作成する" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6739,7 +6739,7 @@ create_backup() { echo "- $path" done - # バックアップの作成 + # バックアップを作成する echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7196,7 +7196,7 @@ mount_partition() { # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then - echo "パーティション レコードは既に /etc/fstab に存在するため、書き込みをスキップします" + echo "パーティション レコードはすでに /etc/fstab に存在するため、書き込みをスキップします" return 0 fi @@ -7496,7 +7496,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期スケジュールされたタスクを追加する" + send_stats "同期のスケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7768,7 +7768,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7860,7 +7860,7 @@ linux_tools() { clear echo "ツールはインストールされており、次のように使用されます。" ffmpeg --help - send_stats "安装ffmpeg" + send_stats "ffmpegをインストールする" ;; 11) @@ -7924,7 +7924,7 @@ linux_tools() { clear git --help cd ~ - send_stats "安装git" + send_stats "gitをインストールする" ;; 18) @@ -8130,7 +8130,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8140,7 +8140,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8160,7 +8160,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包量:$path" + echo "梱包体積:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8225,7 +8225,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -8307,7 +8307,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元します + # /home/docker 下のファイルを復元する if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーを使用してログインする + # キーでログイン scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8556,7 +8556,7 @@ linux_docker() { echo "" echo "ボリューム操作" echo "------------------------" - echo "1. 新しいボリュームを作成します" + echo "1. 新しいボリュームを作成する" echo "2. 指定したボリュームを削除します" echo "3. すべてのボリュームを削除します" echo "------------------------" @@ -10164,7 +10164,7 @@ moltbot_menu() { echo "10. メイン設定ファイルを編集します" echo "11. 設定ウィザード" echo "12. 健全性の検出と修復" - echo "13. WebUI へのアクセスと設定" + echo "13. WebUI访问与设置" echo "14. TUIコマンドラインダイアログウィンドウ" echo "15. 記憶・記憶" echo "16. 権限管理" @@ -10811,7 +10811,7 @@ EOF echo done - # 4. API タイプを検出/決定しなくなりました。プロトコルはユーザー自身によって選択および維持されます + # 4. API タイプの検出/判断が行われなくなりました。プロトコルはユーザー自身によって選択および維持されます # 5. モデルリストの取得 echo "🔍 利用可能なモデルのリストを取得中..." @@ -11246,7 +11246,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" ;; esac @@ -11277,7 +11277,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "設定したい API タイプを選択してください:" + echo "セットアップする API タイプを選択してください:" echo "1. openai-completions" echo "2. openai-responses" read -erp "選択肢を入力してください (1/2):" proto_choice @@ -12294,12 +12294,12 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ プラグインの削除/無効化:$plugin_id" + echo "🗑️ 正在删除/禁用插件: $plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" else - echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。次の機能のみを無効にしてください。$plugin_id" + echo "⚠️ アンインストールに失敗しました。プリインストールされたプラグインである可能性があります。以下を無効にするだけです。$plugin_id" fi sync_openclaw_plugin_denylist "$plugin_id" >/dev/null 2>&1 success_list="$success_list $plugin_id" @@ -12344,7 +12344,7 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" echo "openhue # Philips Hue スマート照明シーンの制御" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" @@ -12676,7 +12676,7 @@ openclaw_json_get_bool() { echo "2.フェイシュ(ヒバリ)ロボットドッキング" echo "3. WhatsApp ボットのドッキング" echo "4. QQロボットドッキング" - echo "5. WeChatロボットのドッキング" + echo "5.WeChatロボットのドッキング" echo "----------------------------------------" echo "0. 前のメニューに戻る" echo "----------------------------------------" @@ -13061,7 +13061,7 @@ if os.path.isdir(agents_root): rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw プロジェクトの復元が完了しました" + echo "✅ OpenClaw 项目还原完成" break_end } @@ -13472,7 +13472,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("基礎となるソリューション: %s" % backend) + print("基本的なソリューション: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) @@ -13980,7 +13980,7 @@ EOF while true; do clear echo "=======================================" - echo "メモリソリューションの自動展開" + echo "メモリソリューションの自動導入" echo "=======================================" echo "1. QMD" echo "2. Local" @@ -14065,7 +14065,7 @@ EOF echo "=======================================" echo "インデックス修復診断" echo "=======================================" - echo "現在の includeDefaultMemory: ${include_dm:-not set}" + echo "現在 includeDefaultMemory: ${include_dm:-not set}" echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ includeDefaultMemory=false が検出されました" @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 構成は正常です。" - echo "実行内容: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" + echo "実行予定: 古いインデックスを削除 → すべてのエージェント インデックスを完全に再構築" echo "" read -e -p "実行を確認しますか? (はい/いいえ):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14203,9 +14203,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "総行数:$total_lines" + echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14300,7 +14300,7 @@ EOF echo "3. インデックス修復(インデックス例外)" echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" - echo "6. ディープステートの検出 (組み込みモデルのチェック)" + echo "6. ディープステート検出 (組み込みモデルのチェック)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" memory_choice @@ -14406,7 +14406,7 @@ EOF config_file=$(openclaw_permission_config_file) backup_file=$(openclaw_permission_backup_file) if [ ! -s "$backup_file" ]; then - echo "❌ 復元可能な権限のバックアップ ファイルが見つかりません。" + echo "❌ 未找到可恢复的权限备份文件。" return 1 fi cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { @@ -14420,10 +14420,10 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ openclaw が検出されず、OpenClaw Gateway を再起動できません。" + echo "❌ OpenClaw が検出されず、OpenClaw Gateway を再起動できません。" return 1 fi - echo "OpenClaw ゲートウェイを再起動しています..." + echo "正在重启 OpenClaw Gateway..." openclaw gateway restart >/dev/null 2>&1 || { openclaw gateway stop >/dev/null 2>&1 openclaw gateway start >/dev/null 2>&1 @@ -14613,7 +14613,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14662,7 +14662,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成、システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" fi } @@ -14682,7 +14682,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -15180,7 +15180,7 @@ for idx,item in enumerate(bindings,1): read -e -p "エージェント ID を入力してください:" agent_id read -e -p "削除するルート バインディング値を入力してください:" bind_value { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "キャンセル: パラメータを空にすることはできません。" && return 1 - echo "エージェントを削除します [$agent_id] ルート バインディング [$bind_value]" + echo "エージェントを削除します [$agent_id]ルートバインディング[$bind_value]" read -e -p "続行することを確認するには「yes」と入力します。" confirm [ "$confirm" = "yes" ] || { echo "キャンセル"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15651,7 +15651,7 @@ while true; do echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" @@ -17529,7 +17529,7 @@ while true; do } - local docker_describe="OpenWebUI は大規模な言語モデルの Web ページ フレームワークであり、公式の簡易バージョンではすべての主要モデルへの API アクセスがサポートされています。" + local docker_describe="OpenWebUI は大規模な言語モデルの Web ページ フレームワークであり、公式の合理化されたバージョンでは、すべての主要なモデルへの API アクセスがサポートされています。" local docker_url="公式サイト紹介:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" @@ -17694,7 +17694,7 @@ while true; do } - local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" + local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -17998,7 +17998,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チームコラボレーションをサポートする、オープンソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18351,7 +18351,7 @@ while true; do } - local docker_describe="オープンソースの無料の自作ライブ ブロードキャスト プラットフォーム" + local docker_describe="オープンソース、無料の自社構築ライブ ブロードキャスト プラットフォーム" local docker_url="公式サイト紹介:https://owncast.online" local docker_use="echo \"管理者ページにアクセスするには、アクセス アドレスの後に /admin を続けます\"" local docker_passwd="echo \"初期アカウント: admin 初期パスワード: abc123 ログイン後、時間内にログイン パスワードを変更してください\"" @@ -19286,7 +19286,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -19467,8 +19467,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -19876,7 +19876,7 @@ log_menu() { case $choice in 1) send_stats "最近のログを表示する" - read -erp "最近のログ行を何行表示しましたか? [デフォルト 100]:" lines + read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "Enter を押して続行します..." @@ -20407,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6優先に切り替えました" - send_stats "IPv6優先に切り替えました" + echo "最初にIPv6に切り替えました" + send_stats "最初にIPv6に切り替えました" ;; 3) @@ -20615,7 +20615,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得します + # 現在のシステム時刻を取得する local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -21402,7 +21402,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -21422,7 +21422,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -21545,7 +21545,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスターを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21590,7 +21590,7 @@ while true; do 5) clear - send_stats "クラスターを復元する" + send_stats "クラスタを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -21664,10 +21664,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21853,7 +21853,7 @@ while true; do if [ -n "$cron_sed_cmd" ]; then SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi - # 古いスクリプトからpermission_grantedおよびENABLE_STATS設定を復元します + # 古いスクリプトからpermission_grantedおよびENABLE_STATS設定を復元します。 SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # /usr/local/bin/k および /usr/bin/k にデプロイします SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21964,7 +21964,7 @@ echo "仮想メモリ k スワップを設定 2048" echo "仮想タイムゾーンを設定します k 時間 アジア/上海 | k タイムゾーン アジア/上海" echo "システムごみ箱のゴミ箱 | k hz | k ごみ箱" echo "システムバックアップ機能 kバックアップ | k bf | k バックアップ" -echo "ssh リモート接続ツール k ssh | kリモート接続" +echo "ssh リモート接続ツール k ssh | k リモート接続" echo "rsync リモート同期ツール k rsync | k リモート同期" echo "ハードディスク管理ツール k ディスク | k ハードディスクの管理" echo "イントラネット普及率 (サーバー) k frps" @@ -21973,7 +21973,7 @@ echo "ソフトウェア起動 k start sshd | sshdを起動します" echo "ソフトウェア停止 k 停止 sshd | k ストップ sshd" echo "ソフトウェア再起動 k 再起動 sshd | k sshdを再起動します" echo "ソフトウェアのステータスを確認します。 k ステータス sshd | kステータスsshd" -echo "k ドッカーを有効にする | k 自動開始ドッカー | k ソフトウェアの起動時に Docker を有効にする" +echo "k ドッカーを有効にする | k 自動開始ドッカー | k 起動時に docker を起動します" echo "ドメイン名証明書アプリケーション k ssl" echo "ドメイン名証明書の有効期限のクエリ k ssl ps" echo "docker 管理プレーン k docker" @@ -21983,7 +21983,7 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" +echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" diff --git a/kr/kejilion.sh b/kr/kejilion.sh index d022dd6ec..da9d36c41 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -63,9 +63,9 @@ CheckFirstRun_true() { -# 이 기능은 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록합니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! +# 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록하는 기능입니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. -# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 불편하신 점이 있으시면 이용을 거부하실 수 있습니다. +# send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -1206,7 +1206,7 @@ iptables_panel() { ;; 17) - read -e -p "지워진 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code + read -e -p "삭제된 국가 코드를 입력하십시오(여러 국가 코드는 CN US JP와 같이 공백으로 구분될 수 있음)." country_code manage_country_rules unblock $country_code send_stats "명확한 국가$country_codeIP" ;; @@ -1322,7 +1322,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 교체 + # docker-compose.yml 파일에서 바꾸기 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1361,7 +1361,7 @@ auto_optimize_dns() { # 국가 코드(예: CN, US 등)를 가져옵니다. local country=$(curl -s ipinfo.io/country) - # 국가에 따라 DNS 설정 + # 국가별 DNS 설정 if [ "$country" = "CN" ]; then local dns1_ipv4="223.5.5.5" local dns2_ipv4="183.60.83.19" @@ -1546,7 +1546,7 @@ certs_status() { echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." - echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하세요." + echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" echo "------------------------" @@ -2893,7 +2893,7 @@ while true; do setup_docker_dir check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3017,7 +3017,7 @@ docker_app_plus() { check_disk_space $app_size /home/docker while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port local app_port=${app_port:-${docker_port}} if ss -tuln | grep -q ":$app_port "; then @@ -3224,7 +3224,7 @@ f2b_sshd() { # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) # 설명하다: -# - /etc/fail2ban/jail.d/sshd.local에 대한 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 무시하고 업그레이드 시 손실되기 쉽지 않습니다). +# - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { root_use @@ -3426,7 +3426,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치정보는 다음과 같습니다." + echo "$webname설치 정보는 다음과 같습니다." } @@ -3512,7 +3512,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4156,7 +4156,7 @@ add_forwarding_service() { read -e -p "서비스 이름을 입력하세요:" service_name read -e -p "전달 유형(tcp/udp)을 입력하십시오. [기본값을 tcp로 입력]:" service_type local service_type=${service_type:-tcp} - read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1]:" local_ip + read -e -p "인트라넷 IP를 입력하십시오. [Enter를 누르면 기본값은 127.0.0.1입니다]:" local_ip local local_ip=${local_ip:-127.0.0.1} read -e -p "인트라넷 포트를 입력하십시오:" local_port read -e -p "외부 네트워크 포트를 입력하세요:" remote_port @@ -4447,7 +4447,7 @@ frpc_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP 클라이언트$check_frp $update_status" - echo "서버에 연결합니다. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." + echo "서버에 연결하세요. 연결 후에는 인트라넷 침투 서비스를 만들어 인터넷에 액세스할 수 있습니다." echo "공식 웹사이트 소개:${gh_https_url}github.com/fatedier/frp/" echo "비디오 튜토리얼: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" @@ -5058,7 +5058,7 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 원래 인증된_키 백업 + # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" echo "원본 Authorized_keys 파일이 백업되었습니다." @@ -5138,7 +5138,7 @@ sshkey_panel() { echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 로그인하는 보다 안전한 방법인 키 쌍이 생성됩니다." + echo "SSH를 통해 보다 안전하게 로그인할 수 있도록 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." @@ -5749,7 +5749,7 @@ bbrv3() { if [ -r /etc/os-release ]; then . /etc/os-release if [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then - echo "현재 환경에서는 지원하지 않습니다. Debian 및 Ubuntu 시스템만 지원됩니다." + echo "현재 환경에서는 지원하지 않으며 Debian 및 Ubuntu 시스템만 지원됩니다." break_end linux_Settings fi @@ -5795,7 +5795,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화해 드리겠습니다." + echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -5939,7 +5939,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -6158,7 +6158,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── 추가 라이브 방송 시나리오: UDP 버퍼 확대 ── + # ── 생방송 시나리오를 위한 추가 사항: UDP 버퍼 확대 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "파티션이 다음에 성공적으로 마운트되었습니다.$MOUNT_POINT" + echo "파티션이 성공적으로 마운트되었습니다.$MOUNT_POINT" # /etc/fstab을 확인하여 UUID 또는 마운트 지점이 이미 존재하는지 확인하세요. if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8098,7 +8098,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}Docker 컨테이너 백업 중...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "백업할 컨테이너의 이름을 입력하십시오(여러 개의 공백을 구분하고 Enter를 눌러 실행 중인 모든 컨테이너를 백업하십시오)." containers + read -e -p "백업할 컨테이너의 이름을 입력하십시오(실행 중인 모든 컨테이너를 백업하려면 여러 개의 공백을 구분하고 Enter 키를 누르십시오)." containers install tar jq gzip install_docker @@ -8237,7 +8237,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8253,7 +8253,7 @@ docker_ssh_migration() { [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}처리 용기:$container${gl_bai}" + echo -e "${gl_lv}처리용기:$container${gl_bai}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then @@ -8339,7 +8339,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 키로 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8526,7 +8526,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8894,7 +8894,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "설치하시겠습니까? (예/아니요):" choice + read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8906,7 +8906,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter 키를 누르면 기본값이 사용됩니다. + # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter를 누르면 기본값이 사용됩니다. read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9285,7 +9285,7 @@ linux_ldnmp() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "" - echo "레디스 주소: 레디스" + echo "레디스 주소 : 레디스" echo "redis 비밀번호: 기본적으로 입력되지 않음" echo "레디스 포트: 6379" echo "" @@ -9295,7 +9295,7 @@ linux_ldnmp() { echo "사용자 이름: 관리자" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용해주세요." + echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -9537,7 +9537,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업이 있습니다." use_db + read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db case $use_db in 1) echo @@ -10148,7 +10148,7 @@ moltbot_menu() { echo "=======================================" echo -e "🦞 KEJILION의 OPENCLAW 관리 도구 🦞" - echo -e "💡 터미널 실행 \033[1;33mk 클로\033[0m 빠른 메뉴 진입" + echo -e "💡 터미널 실행 \033[1;33mk 클로\033[0m 빠르게 메뉴 진입" echo -e "$install_status $running_status $update_message" echo "=======================================" echo "1. 설치" @@ -10520,7 +10520,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10557,8 +10557,8 @@ PY install_moltbot() { - echo "OpenClaw 설치를 시작합니다..." - send_stats "OpenClaw 설치를 시작합니다..." + echo "OpenClaw 설치를 시작하세요..." + send_stats "OpenClaw 설치를 시작하세요..." install git jq install_node_and_tools @@ -10811,7 +10811,7 @@ EOF echo done - # 4. 더 이상 API 유형을 감지/결정하지 않습니다. 프로토콜은 사용자가 직접 선택하고 유지 관리합니다. + # 4. 더 이상 API 유형을 감지/판단하지 않습니다. 프로토콜은 사용자가 직접 선택하고 유지 관리합니다. # 5. 모델 목록 가져오기 echo "🔍 사용 가능한 모델 목록을 가져오는 중..." @@ -11893,7 +11893,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -11961,7 +11961,7 @@ PYTHON_EOF echo "전환되는 모델은 다음과 같습니다.$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "스위치 실패: openclaw 모델 세트에서 오류가 반환되었습니다." + echo "전환 실패: openclaw 모델 세트에서 오류가 반환되었습니다." break_end return 1 fi @@ -12118,7 +12118,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -12225,7 +12225,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반환" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12249,7 +12249,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인 중:$plugin_id" + echo "🔍 플러그인 상태 확인:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -12353,7 +12353,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반환" + echo "0) 복귀" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -13155,7 +13155,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 백업 파일 삭제" + send_stats "OpenClaw 삭제 백업 파일" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13405,7 +13405,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." + echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -13678,7 +13678,7 @@ PY local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." return 0 } @@ -14087,7 +14087,7 @@ EOF fi else echo "includeDefaultMemory 구성이 정상입니다." - echo "실행 예정: 기존 인덱스 정리 → 모든 에이전트 인덱스 완전 재구축" + echo "실행됩니다: 이전 인덱스 정리 → 모든 에이전트 인덱스를 완전히 재구축합니다." echo "" read -e -p "실행을 확인하시겠습니까? (예/아니요):" confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then @@ -14116,7 +14116,7 @@ EOF echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" - echo "자동: 자동 추천(가용성 + 네트워크 감지 기반)" + echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" @@ -14317,7 +14317,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14331,7 +14331,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -14420,7 +14420,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ openclaw가 감지되지 않아 OpenClaw Gateway를 다시 시작할 수 없습니다." + echo "❌ OpenClaw가 감지되지 않아 OpenClaw Gateway를 다시 시작할 수 없습니다." return 1 fi echo "OpenClaw 게이트웨이 다시 시작 중..." @@ -14670,7 +14670,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14689,7 +14689,7 @@ except Exception: send_stats "OpenClaw 권한 - 개발 강화 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -14707,7 +14707,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 계층 정책 구성 중..." + echo "애플리케이션 레이어 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -14809,7 +14809,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "제거할 명령 경로를 입력하세요." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15114,7 +15114,7 @@ for idx,item in enumerate(agents,1): local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" - read -e -p "상담원 성격 주제(예: 엄격함, 효율적)를 입력하세요." theme + read -e -p "상담원 성격 테마(예: 엄격함, 효율적)를 입력하세요." theme [ -z "$theme" ] && theme="어시스턴트" echo "에이전트 ID 구성 중..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" @@ -15613,7 +15613,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15673,7 +15673,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15682,7 +15682,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15904,7 +15904,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "네자 모니터링$check_docker $update_status" + echo -e "나타 모니터링$check_docker $update_status" echo "오픈 소스, 가볍고 사용하기 쉬운 서버 모니터링 및 운영 및 유지 관리 도구" echo "공식 웹사이트 구축 문서: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -17529,7 +17529,7 @@ while true; do } - local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 단순화 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." + local docker_describe="OpenWebUI는 대규모 언어 모델 웹 페이지 프레임워크로, 공식 간소화된 버전은 모든 주요 모델에 대한 API 액세스를 지원합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="" local docker_passwd="" @@ -17694,7 +17694,7 @@ while true; do } - local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -17985,7 +17985,7 @@ while true; do } local docker_describe="Beszel은 가볍고 사용하기 쉬운 서버 모니터링입니다." - local docker_url="공식 홈페이지 소개: https://beszel.dev/zh/" + local docker_url="공식 홈페이지 소개 : https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18353,7 +18353,7 @@ while true; do local docker_describe="오픈 소스, 자체 구축한 무료 라이브 방송 플랫폼" local docker_url="공식 홈페이지 소개 : https://owncast.online" - local docker_use="echo \"액세스 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" + local docker_use="echo \"접속 주소 뒤에는 /admin이 붙어서 관리자 페이지에 접근합니다\"" local docker_passwd="echo \"초기 계정: admin 초기 비밀번호: abc123 로그인 후 시간 내에 로그인 비밀번호를 변경해주세요\"" local app_size="1" docker_app @@ -18380,7 +18380,7 @@ while true; do } - local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고, 빠른 배송과 같은 파일 픽업" + local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" @@ -18637,7 +18637,7 @@ while true; do local app_id="96" local app_name="2FAuth 자체 호스팅 2단계 인증자" - local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." + local app_text="자체 호스팅 2단계 인증(2FA) 계정 관리 및 확인 코드 생성 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" @@ -19467,7 +19467,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -19876,7 +19876,7 @@ log_menu() { case $choice in 1) send_stats "최근 로그 보기" - read -erp "최근 로그 줄을 몇 개나 보셨나요? [기본값 100]:" lines + read -erp "가장 최근 로그 줄을 보시겠습니까? [기본값 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager read -erp "계속하려면 Enter를 누르세요..." @@ -20019,7 +20019,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드 중" + send_stats "환경 변수 다시 로드" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -20031,7 +20031,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20153,7 +20153,7 @@ linux_Settings() { echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20163,7 +20163,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20221,7 +20221,7 @@ linux_Settings() { echo "파이썬 버전 관리" echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" + echo "이 기능은 Python에서 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20407,8 +20407,8 @@ EOF ;; 2) rm -f /etc/gai.conf - echo "IPv6 우선순위로 전환됨" - send_stats "IPv6 우선순위로 전환됨" + echo "먼저 IPv6로 전환됨" + send_stats "먼저 IPv6로 전환됨" ;; 3) @@ -20615,7 +20615,7 @@ EOF # 현재 시스템 시간대 가져오기 local timezone=$(current_timezone) - # 현재 시스템 시간 가져오기 + # 현재 시스템 시간을 가져옵니다 local current_time=$(date +"%Y-%m-%d %H:%M:%S") # 시간대 및 시간 표시 @@ -21233,7 +21233,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." + send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" ;; *) break @@ -21591,7 +21591,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21664,10 +21664,10 @@ echo "------------------------" echo -e "${gl_lan}DMIT 분기당 $28 US CN2GIA 1 코어 2G 메모리 20G 하드 드라이브 월별 800G 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 월 6.9달러 Tokyo Softbank 2코어 1G 메모리 20G 하드 드라이브 월 1T 트래픽${gl_bai}" +echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -21824,7 +21824,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}업데이트 실패! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" + echo -e "${gl_hong}업데이트에 실패했습니다! 다운로드 중 오류가 발생했거나 파일 확인에 실패했습니다. 원본 버전이 복원되었습니다.${gl_bai}" send_stats "스크립트 업데이트 실패" fi break_end @@ -21973,7 +21973,7 @@ echo "소프트웨어 시작 k start sshd | k sshd를 시작하세요" echo "소프트웨어 중지 k 중지 sshd | k sshd 중지" echo "소프트웨어 재시작 k 재시작 sshd | k sshd를 다시 시작하세요" echo "소프트웨어 상태 확인 k status sshd | k 상태 sshd" -echo "k 도커 활성화 | k 자동 시작 도커 | k 소프트웨어를 부팅할 때 도커를 활성화합니다." +echo "k 도커 활성화 | k 자동 시작 도커 | k 시작 시 도커 시작" echo "도메인 이름 인증서 신청 k SSL" echo "도메인 이름 인증서 만료 쿼리 k SSL ps" echo "도커 관리 플레인 k 도커" @@ -21987,7 +21987,7 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" +echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 4db925412..b1035cf6a 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1227,7 +1227,7 @@ iptables_panel() { add_swap() { local new_swap=$1 # 获取传入的参数 - # 取得目前系統中所有的 swap 分割區 + # 取得目前系統中所有的 swap 分區 local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') # 遍歷並刪除所有的 swap 分割區 @@ -3351,7 +3351,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear - send_stats "无法再次安装LDNMP环境" + send_stats "無法再次安裝LDNMP環境" echo -e "${gl_huang}提示:${gl_bai}建站環境已安裝。無需再次安裝!" break_end linux_ldnmp @@ -4109,7 +4109,7 @@ EOF donlond_frp frps - # 输出生成的信息 + # 輸出產生的信息 ip_address echo "------------------------" echo "客戶端部署時所需使用的參數" @@ -4627,7 +4627,7 @@ yt_menu_pro() { --write-info-json \ -o "$VIDEO_DIR/%(title)s/%(title)s.%(ext)s" \ --no-overwrites --no-post-overwrites "$url" - read -e -p "音频下载完成,按任意键继续..." ;; + read -e -p "音訊下載完成,按任意鍵繼續..." ;; 9) send_stats "刪除影片" @@ -4788,7 +4788,7 @@ mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" echo "net.ipv4.tcp_congestion_control=bbr" >> "$CONF" -# 清理可能導致衝突的舊版 sysctl.conf 殘留 +# 清理可能導致衝突的舊版本 sysctl.conf 殘留 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 2>/dev/null @@ -5280,7 +5280,7 @@ dd_xitong() { dd_xitong_1() { echo -e "重裝後初始使用者名稱:${gl_huang}root${gl_bai}初始密碼:${gl_huang}LeitboGi0ro${gl_bai}初始連接埠:${gl_huang}22${gl_bai}" - echo -e "${gl_huang}重装后请及时修改初始密码,防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" + echo -e "${gl_huang}重裝後請及時修改初始密碼,以防止暴力入侵。命令列輸入passwd修改密碼${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -5725,7 +5725,7 @@ bbrv3() { echo "BBR3參數寫入失敗,請檢查系統配置" return 1 } - echo "XanMod BBRv3內核處理完成。重启后生效" + echo "XanMod BBRv3內核處理完成。重啟後生效" server_reboot } @@ -5794,7 +5794,7 @@ bbrv3() { echo "設定BBR3加速" echo "影片介紹: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" - echo "仅支持Debian/Ubuntu" + echo "僅支援Debian/Ubuntu" echo "請備份數據,將為你升級Linux核心開啟BBR3" echo "------------------------------------------------" read -e -p "確定繼續嗎? (Y/N):" choice @@ -6702,7 +6702,7 @@ create_backup() { # 提示使用者輸入備份目錄 echo "建立備份範例:" - echo " - 备份单个目录: /var/www" + echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input @@ -7192,7 +7192,7 @@ mount_partition() { return 1 fi - echo "分割區已成功掛載到$MOUNT_POINT" + echo "分區已成功掛載到$MOUNT_POINT" # 檢查 /etc/fstab 是否已經存在 UUID 或掛載點 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8369,7 +8369,7 @@ docker_ssh_migration() { list_backups echo -e "" echo "------------------------" - echo -e "1. 备份docker项目" + echo -e "1. 備份docker項目" echo -e "2. 遷移docker項目" echo -e "3. 還原docker項目" echo -e "4. 刪除docker專案的備份文件" @@ -9528,7 +9528,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}5/6${gl_bai}] 編輯網站配置" echo "-------------" - echo "按任意键继续,可以详细设置站点配置,如伪静态等内容" + echo "按任一鍵繼續,可詳細設定網站配置,如偽靜態等內容" read -n 1 -s -r -p "" install nano nano /home/web/conf.d/$yuming.conf @@ -10443,7 +10443,7 @@ for name, provider in list(providers.items()): continue if attempts > 1: - summary.append(f'🔁 {name}: /models 第 {attempts} 次重试后成功') + summary.append(f'🔁 {name}: /models 第 {attempts} 次重試後成功') if not (isinstance(data, dict) and isinstance(data.get('data'), list)): summary.append(f'⚠️ 跳過 {name}: /models 回傳結構不可識別') @@ -10456,7 +10456,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') + fatal_errors.append(f'❌ {name} 上游 /models 為空,無法為該 provider 提供兜底模型') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10714,7 +10714,7 @@ EOF ' "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" } - # 核心函数:获取并添加所有模型 + # 核心函數:取得並加入所有模型 add-all-models-from-provider() { local provider_name="$1" local base_url="$2" @@ -10785,7 +10785,7 @@ EOF add-openclaw-provider-interactive() { send_stats "OpenClaw API新增" - echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" + echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -14331,7 +14331,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧體執行 force 重建並自動重新啟動網關" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -15119,7 +15119,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體創建失敗" + echo "❌ 智能體建立失敗" return 1 fi } @@ -15437,7 +15437,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域地址:" + echo "網域名稱地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -15671,7 +15671,7 @@ while true; do echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" @@ -18151,7 +18151,7 @@ while true; do } - local docker_describe="高性能AI接口透明代理服务" + local docker_describe="高效能AI介面透明代理服務" local docker_url="官網介紹: https://www.gpt-load.com/" local docker_use="" local docker_passwd="" @@ -18951,7 +18951,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片產生工具" + local app_name="AI影片生成工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -19220,7 +19220,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="是一个适用于个人或小团队的在线网盘程序。" + local docker_describe="是一個適用於個人或小型團隊的線上網盤程式。" local docker_url="官網介紹:${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" @@ -19770,7 +19770,7 @@ fail2ban_panel() { net_menu() { - send_stats "网卡管理工具" + send_stats "網路卡管理工具" show_nics() { echo "================ 目前網卡資訊 ==================" printf "%-18s %-12s %-20s %-26s\n" "網路卡名" "狀態" "IP位址" "MAC位址" @@ -20088,16 +20088,16 @@ create_user_with_sshkey() { echo "導入公鑰範例:" echo " - URL: ${gh_https_url}github.com/torvalds.keys" - echo " - 直接粘贴: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." - read -e -p "請導入${new_username} 的公钥: " sshkey_vl + echo "- 直接貼上: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + read -e -p "請導入${new_username}的公鑰:" sshkey_vl case "$sshkey_vl" in http://*|https://*) - send_stats "从 URL 导入 SSH 公钥" + send_stats "從 URL 匯入 SSH 公鑰" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) - send_stats "公钥直接导入" + send_stats "公鑰直接導入" import_sshkey "$sshkey_vl" "/home/$new_username" ;; *) @@ -20333,7 +20333,7 @@ EOF send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH埠修改" + send_stats "退出SSH連接埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20958,9 +20958,9 @@ EOF root_use send_stats "電報預警" echo "TG-bot監控預警功能" - echo "视频介绍: https://youtu.be/vLL-eb3Z_TY" + echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21311,7 +21311,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" + echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21388,7 +21388,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21547,9 +21547,9 @@ while true; do echo -e "${gl_kjlan}1. ${gl_bai}新增伺服器${gl_kjlan}2. ${gl_bai}刪除伺服器${gl_kjlan}3. ${gl_bai}編輯伺服器" echo -e "${gl_kjlan}4. ${gl_bai}備份叢集${gl_kjlan}5. ${gl_bai}還原叢集" echo -e "${gl_kjlan}------------------------${gl_bai}" - echo -e "${gl_kjlan}批量执行任务${gl_bai}" - echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系统 ${gl_kjlan}13. ${gl_bai}清理系统" - echo -e "${gl_kjlan}14. ${gl_bai}安装docker ${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" + echo -e "${gl_kjlan}批次執行任務${gl_bai}" + echo -e "${gl_kjlan}11. ${gl_bai}安裝科技lion腳本${gl_kjlan}12. ${gl_bai}更新系統${gl_kjlan}13. ${gl_bai}清理系統" + echo -e "${gl_kjlan}14. ${gl_bai}安裝docker${gl_kjlan}15. ${gl_bai}安裝BBR3${gl_kjlan}16. ${gl_bai}設定1G虛擬內存" echo -e "${gl_kjlan}17. ${gl_bai}設定時區到上海${gl_kjlan}18. ${gl_bai}開放所有連接埠${gl_kjlan}51. ${gl_bai}自訂指令" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -21816,7 +21816,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" @@ -21824,7 +21824,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" send_stats "腳本更新失敗" fi break_end From db7dc2aea9201467ec260271ce39a970c8e43cd8 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 26 Jul 2026 21:03:07 +0800 Subject: [PATCH 1209/1285] fix: guard app lifecycle registration --- kejilion.sh | 33 +++++++++++-------- ..._docker_app_plus_lifecycle_status_smoke.sh | 29 ++++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100755 tests/test_docker_app_plus_lifecycle_status_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index cf5f3af28..cb05521dc 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3031,25 +3031,32 @@ docker_app_plus() { install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_name 安装" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + send_stats "$app_name 安装" + else + echo -e "${gl_hong}安装失败: ${gl_bai}未登记应用状态,请根据上方错误修复后重试。" + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_name 更新" + if docker_app_update; then + add_app_id + send_stats "$app_name 更新" + else + echo -e "${gl_hong}更新失败: ${gl_bai}已保留原应用登记状态。" + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name 卸载" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_name 卸载" + else + echo -e "${gl_hong}卸载失败: ${gl_bai}已保留应用登记状态。" + fi ;; 5) diff --git a/tests/test_docker_app_plus_lifecycle_status_smoke.sh b/tests/test_docker_app_plus_lifecycle_status_smoke.sh new file mode 100755 index 000000000..cad4715be --- /dev/null +++ b/tests/test_docker_app_plus_lifecycle_status_smoke.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" +function_body="$( + awk ' + /^docker_app_plus\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" + +printf '%s\n' "${function_body}" | grep -F 'if docker_app_install; then' >/dev/null +printf '%s\n' "${function_body}" | grep -F 'if docker_app_update; then' >/dev/null +printf '%s\n' "${function_body}" | grep -F 'if docker_app_uninstall; then' >/dev/null + +install_branch="$(printf '%s\n' "${function_body}" | sed -n '/if docker_app_install; then/,/^[[:space:]]*fi$/p')" +update_branch="$(printf '%s\n' "${function_body}" | sed -n '/if docker_app_update; then/,/^[[:space:]]*fi$/p')" +uninstall_branch="$(printf '%s\n' "${function_body}" | sed -n '/if docker_app_uninstall; then/,/^[[:space:]]*fi$/p')" + +printf '%s\n' "${install_branch}" | + grep -F 'echo "$docker_port" > "/home/docker/${docker_name}_port.conf"' >/dev/null +printf '%s\n' "${install_branch}" | grep -F 'add_app_id' >/dev/null +printf '%s\n' "${update_branch}" | grep -F 'add_app_id' >/dev/null +printf '%s\n' "${uninstall_branch}" | grep -F 'rm -f /home/docker/${docker_name}_port.conf' >/dev/null +printf '%s\n' "${uninstall_branch}" | grep -F 'appno.txt' >/dev/null + +printf '%s\n' "docker_app_plus_lifecycle_status=pass" From 14c84fe2cff8c3453682bf91a43ab71453c0b77c Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 26 Jul 2026 22:12:09 +0800 Subject: [PATCH 1210/1285] feat: add noninteractive KPanel app installs --- kejilion.sh | 80 ++++++++++++++ tests/test_kpanel_app_noninteractive_smoke.sh | 104 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100755 tests/test_kpanel_app_noninteractive_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index cb05521dc..ab3239e69 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2857,11 +2857,84 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "错误: KPanel 未提供有效的应用端口" + return 1 + ;; + esac + if [ "$requested_port" -lt 1024 ] || [ "$requested_port" -gt 65535 ]; then + echo "错误: KPanel 应用端口必须在 1024-65535 之间" + return 1 + fi + if ss -tuln 2>/dev/null | grep -q ":${requested_port} "; then + echo "错误: 端口 ${requested_port} 已被占用" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "错误: KPanel 当前仅允许非交互安装" + return 1 + fi + + kpanel_app_progress 5 "正在校验端口与宿主机环境" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "正在准备 Docker 运行环境" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "正在执行 kejilion.sh 应用安装函数" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "安装失败: 未登记应用状态" + return 1 + fi + else + if ! docker_rum; then + echo "安装失败: 未登记应用状态" + return 1 + fi + fi + + kpanel_app_progress 90 "正在写入 kejilion.sh 兼容状态" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "应用安装完成" + echo "$docker_name 已经安装完成" + return 0 +} + docker_app() { send_stats "${docker_name}管理" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_install standard + return $? +fi + while true; do clear check_docker_app @@ -2984,6 +3057,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_install plus + return $? + fi while true; do clear check_docker_app @@ -19459,6 +19536,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh new file mode 100755 index 000000000..185a039ee --- /dev/null +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -0,0 +1,104 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" + +helper_body="$( + awk ' + /^kpanel_run_docker_app_install\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +progress_body="$( + awk ' + /^kpanel_app_progress\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +port_body="$( + awk ' + /^kpanel_app_install_port\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +docker_app_body="$( + awk ' + /^docker_app\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +docker_app_plus_body="$( + awk ' + /^docker_app_plus\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" + +printf '%s\n' "${helper_body}" | grep -F '[ "${KJ_APP_ACTION:-}" != "install" ]' >/dev/null +printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_install_port || return 1' >/dev/null +printf '%s\n' "${helper_body}" | grep -F 'if ! docker_app_install; then' >/dev/null +printf '%s\n' "${helper_body}" | grep -F 'if ! docker_rum; then' >/dev/null +printf '%s\n' "${helper_body}" | grep -F 'echo "$docker_port" > "/home/docker/${docker_name}_port.conf"' >/dev/null +printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_progress 100 "应用安装完成"' >/dev/null +printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_install standard' >/dev/null +printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_install plus' >/dev/null +grep -F 'if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null + +test_app_root="$(mktemp -d)" +trap 'rm -rf "${test_app_root}"' EXIT +mkdir -p "${test_app_root}" +runtime_helpers="$( + printf '%s\n%s\n%s\n' "${progress_body}" "${port_body}" "${helper_body}" | + sed "s|/home/docker|${test_app_root}|g" +)" +eval "${runtime_helpers}" + +setup_docker_dir() { return 0; } +check_disk_space() { return 0; } +install() { return 0; } +install_docker() { return 0; } +ss() { return 0; } +add_app_id() { printf '%s\n' "${app_id}" >>"${test_app_root}/appno.txt"; } +docker_app_install() { return 0; } +docker_rum() { return 0; } +show_user() { printf '%s\n' "user=admin"; } +show_pass() { printf '%s\n' "password=protected"; } + +export KJ_APP_NONINTERACTIVE=1 KJ_APP_ACTION=install KJ_APP_PORT=18081 +docker_name="test-standard" +docker_port=8080 +app_id=999 +app_size=1 +docker_use=show_user +docker_passwd=show_pass +runtime_output="$(kpanel_run_docker_app_install standard)" +test "$(cat "${test_app_root}/test-standard_port.conf")" = "18081" +grep -qxF "999" "${test_app_root}/appno.txt" +printf '%s\n' "${runtime_output}" | grep -F "KPANEL_PROGRESS 5" >/dev/null +printf '%s\n' "${runtime_output}" | grep -F "KPANEL_PROGRESS 100" >/dev/null +printf '%s\n' "${runtime_output}" | grep -F "user=admin" >/dev/null +printf '%s\n' "${runtime_output}" | grep -F "password=protected" >/dev/null + +docker_rum() { return 1; } +docker_name="test-failed" +app_id=998 +if kpanel_run_docker_app_install standard >/dev/null 2>&1; then + printf '%s\n' "failed installer was reported as successful" >&2 + exit 1 +fi +test ! -e "${test_app_root}/test-failed_port.conf" +! grep -qxF "998" "${test_app_root}/appno.txt" + +KJ_APP_PORT=80 +if kpanel_app_install_port >/dev/null 2>&1; then + printf '%s\n' "privileged port was accepted" >&2 + exit 1 +fi + +printf '%s\n' "kpanel_app_noninteractive=pass" From bee182914087edd7a042ad0b85e482d5641b6bf3 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 26 Jul 2026 22:15:37 +0800 Subject: [PATCH 1211/1285] fix: preserve low app default ports --- kejilion.sh | 4 ++-- tests/test_kpanel_app_noninteractive_smoke.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index ab3239e69..74cd73f88 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2871,8 +2871,8 @@ kpanel_app_install_port() { return 1 ;; esac - if [ "$requested_port" -lt 1024 ] || [ "$requested_port" -gt 65535 ]; then - echo "错误: KPanel 应用端口必须在 1024-65535 之间" + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "错误: KPanel 应用端口必须在 1-65535 之间" return 1 fi if ss -tuln 2>/dev/null | grep -q ":${requested_port} "; then diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index 185a039ee..e00e8fa5f 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -95,9 +95,9 @@ fi test ! -e "${test_app_root}/test-failed_port.conf" ! grep -qxF "998" "${test_app_root}/appno.txt" -KJ_APP_PORT=80 +KJ_APP_PORT=0 if kpanel_app_install_port >/dev/null 2>&1; then - printf '%s\n' "privileged port was accepted" >&2 + printf '%s\n' "zero port was accepted" >&2 exit 1 fi From cfe5c2e8b0c53e1f2f28170eb7f55f3efc74915a Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 00:41:07 +0800 Subject: [PATCH 1212/1285] feat: expose native app management to KPanel --- kejilion.sh | 240 +++++++++++++++++- tests/test_kpanel_app_noninteractive_smoke.sh | 124 ++++++++- 2 files changed, 359 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 74cd73f88..a384acc67 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2862,6 +2862,138 @@ kpanel_app_progress() { printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" } +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "错误: 应用主容器名称无效" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "错误: 未发现应用主容器 ${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "错误: 无法确认应用主容器 ${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "错误: 应用主容器已变化,请刷新面板后重试" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "错误: 应用状态文件名称无效" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "错误: 不支持的应用访问模式" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "错误: 不支持的应用访问模式" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + kpanel_app_install_port() { local requested_port="${KJ_APP_PORT:-${docker_port:-}}" @@ -2916,6 +3048,11 @@ kpanel_run_docker_app_install() { kpanel_app_progress 90 "正在写入 kejilion.sh 兼容状态" echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi if [ "$adapter" = "standard" ]; then [ -n "${docker_use:-}" ] && $docker_use [ -n "${docker_passwd:-}" ] && $docker_passwd @@ -2925,13 +3062,97 @@ kpanel_run_docker_app_install() { return 0 } +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "错误: KPanel 不支持此应用操作" + return 1 + ;; + esac + + kpanel_app_progress 5 "正在核对 kejilion.sh 安装标记与主容器" + service_name="$(kpanel_app_verified_service true)" || return 1 + grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null || { + echo "错误: 未发现 kejilion.sh 应用安装标记" + return 1 + } + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在执行 kejilion.sh 原生更新函数" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "正在恢复应用访问策略" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "应用更新完成" + echo "$service_name 已经更新完成" + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在执行 kejilion.sh 原生卸载函数" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "错误: 卸载函数完成后主容器仍然存在" + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "应用卸载完成" + echo "$service_name 已经卸载完成" + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "错误: KPanel 未提供有效的应用访问模式" + return 1 + ;; + esac + kpanel_app_progress 40 "正在执行 kejilion.sh IP+端口访问策略" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "应用访问策略更新完成" + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}管理" if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then - kpanel_run_docker_app_install standard + kpanel_run_docker_app_action standard return $? fi @@ -2984,6 +3205,7 @@ while true; do echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_name 已经安装完成" @@ -2999,6 +3221,7 @@ while true; do docker_rum add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_name 已经安装完成" @@ -3013,6 +3236,7 @@ while true; do docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" @@ -3025,6 +3249,7 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only ;; 6) @@ -3035,11 +3260,13 @@ while true; do 7) send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct ;; 8) send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only ;; *) @@ -3058,7 +3285,7 @@ done docker_app_plus() { send_stats "$app_name" if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then - kpanel_run_docker_app_install plus + kpanel_run_docker_app_action plus return $? fi while true; do @@ -3111,6 +3338,7 @@ docker_app_plus() { if docker_app_install; then echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct send_stats "$app_name 安装" else echo -e "${gl_hong}安装失败: ${gl_bai}未登记应用状态,请根据上方错误修复后重试。" @@ -3120,6 +3348,7 @@ docker_app_plus() { 2) if docker_app_update; then add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" send_stats "$app_name 更新" else echo -e "${gl_hong}更新失败: ${gl_bai}已保留原应用登记状态。" @@ -3129,6 +3358,7 @@ docker_app_plus() { 3) if docker_app_uninstall; then rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "$app_name 卸载" else @@ -3143,6 +3373,7 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only ;; 6) @@ -3151,12 +3382,15 @@ docker_app_plus() { ;; 7) send_stats "允许IP访问 ${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct ;; 8) send_stats "阻止IP访问 ${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only ;; *) break diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index e00e8fa5f..77454bb98 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -39,6 +39,13 @@ docker_app_plus_body="$( capture && /^}$/ { exit } ' "${script_path}" )" +action_body="$( + awk ' + /^kpanel_run_docker_app_action\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" printf '%s\n' "${helper_body}" | grep -F '[ "${KJ_APP_ACTION:-}" != "install" ]' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_install_port || return 1' >/dev/null @@ -46,8 +53,10 @@ printf '%s\n' "${helper_body}" | grep -F 'if ! docker_app_install; then' >/dev/n printf '%s\n' "${helper_body}" | grep -F 'if ! docker_rum; then' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'echo "$docker_port" > "/home/docker/${docker_name}_port.conf"' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_progress 100 "应用安装完成"' >/dev/null -printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_install standard' >/dev/null -printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_install plus' >/dev/null +printf '%s\n' "${action_body}" | grep -F 'kpanel_app_verified_service true' >/dev/null +printf '%s\n' "${action_body}" | grep -F 'KJ_APP_ACCESS_MODE' >/dev/null +printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_action standard' >/dev/null +printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_action plus' >/dev/null grep -F 'if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null test_app_root="$(mktemp -d)" @@ -65,6 +74,8 @@ install() { return 0; } install_docker() { return 0; } ss() { return 0; } add_app_id() { printf '%s\n' "${app_id}" >>"${test_app_root}/appno.txt"; } +kpanel_app_write_access_mode() { printf '%s\n' "$1" >"${test_app_root}/${docker_name}_access.conf"; } +kpanel_app_apply_access_mode() { kpanel_app_write_access_mode "$1"; } docker_app_install() { return 0; } docker_rum() { return 0; } show_user() { printf '%s\n' "user=admin"; } @@ -101,4 +112,113 @@ if kpanel_app_install_port >/dev/null 2>&1; then exit 1 fi +management_helpers="$( + for helper in \ + kpanel_app_service_name \ + kpanel_app_verified_service \ + kpanel_app_access_path \ + kpanel_app_read_access_mode \ + kpanel_app_write_access_mode \ + kpanel_app_apply_access_mode \ + kpanel_app_restore_access_mode \ + kpanel_app_remove_compatibility_state \ + kpanel_run_docker_app_action + do + awk -v helper="${helper}" ' + $0 ~ "^" helper "\\(\\) \\{" { capture=1 } + capture { print } + capture && /^}$/ { print ""; capture=0; exit } + ' "${script_path}" + done | sed "s|/home/docker|${test_app_root}|g" +)" +eval "${management_helpers}" + +current_exists=true +current_id="$(printf 'a%.0s' {1..64})" +updated_id="$(printf 'b%.0s' {1..64})" +docker_calls=() +docker_call_log="${test_app_root}/docker-calls.log" +docker() { + docker_calls+=("$*") + printf '%s\n' "$*" >>"${docker_call_log}" + case "$1" in + inspect) + "${current_exists}" || return 1 + printf '%s\n' "${current_id}" + ;; + ps) + "${current_exists}" && printf '%s\n' "${docker_app_service:-$docker_name}" + ;; + rm) + current_exists=false + ;; + rmi) + return 0 + ;; + esac +} +docker_rum() { + current_exists=true + current_id="${updated_id}" +} +docker_app_update() { + current_exists=true + current_id="${updated_id}" +} +docker_app_uninstall() { current_exists=false; } +ip_address() { ipv4_address="192.0.2.10"; } +clear_container_rules() { return 0; } +block_container_port() { return 0; } +iptables() { return 0; } + +docker_name="managed-standard" +docker_app_service="" +docker_img="example/managed:latest" +app_id=997 +printf '%s\n' "${app_id}" >>"${test_app_root}/appno.txt" +test "$(kpanel_app_read_access_mode)" = "domain_only" +printf '%s\n' "domain_only" >"${test_app_root}/${docker_name}_access.conf" +export KJ_APP_ACTION=update +export KJ_APP_EXPECTED_CONTAINER_ID="${current_id}" +kpanel_run_docker_app_action standard >/dev/null +test "${current_exists}" = "true" +test "${current_id}" = "${updated_id}" +test "$(cat "${test_app_root}/${docker_name}_access.conf")" = "domain_only" + +docker_name="managed-plus" +docker_app_service="managed-plus-web" +app_id=996 +current_exists=true +current_id="$(printf 'c%.0s' {1..64})" +printf '%s\n' "${app_id}" >>"${test_app_root}/appno.txt" +printf '%s\n' "direct" >"${test_app_root}/${docker_name}_access.conf" +export KJ_APP_ACTION=update +export KJ_APP_EXPECTED_CONTAINER_ID="${current_id}" +kpanel_run_docker_app_action plus >/dev/null +test "${current_id}" = "${updated_id}" + +current_id="$(printf 'd%.0s' {1..64})" +current_exists=true +export KJ_APP_ACTION=direct_access +export KJ_APP_ACCESS_MODE=domain_only +export KJ_APP_EXPECTED_CONTAINER_ID="${current_id}" +kpanel_run_docker_app_action plus >/dev/null +test "$(cat "${test_app_root}/${docker_name}_access.conf")" = "domain_only" + +export KJ_APP_EXPECTED_CONTAINER_ID="$(printf 'e%.0s' {1..64})" +before_calls="$(wc -l <"${docker_call_log}")" +if kpanel_run_docker_app_action plus >/dev/null 2>&1; then + printf '%s\n' "container identity mismatch was accepted" >&2 + exit 1 +fi +test "$(wc -l <"${docker_call_log}")" -eq "$((before_calls + 1))" + +export KJ_APP_ACTION=uninstall +export KJ_APP_EXPECTED_CONTAINER_ID="${current_id}" +kpanel_run_docker_app_action plus >/dev/null +test "${current_exists}" = "false" +test ! -e "${test_app_root}/${docker_name}_port.conf" +test ! -e "${test_app_root}/${docker_name}_access.conf" +! grep -qxF "${app_id}" "${test_app_root}/appno.txt" + printf '%s\n' "kpanel_app_noninteractive=pass" From a056fecc948b9d5f79cd8967fdd9d8fed00cd155 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 04:10:54 +0800 Subject: [PATCH 1213/1285] feat: add KPanel website recipe protocol --- kejilion.sh | 54 ++++++++++++++++++- tests/test_kpanel_web_noninteractive_smoke.sh | 29 ++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/test_kpanel_web_noninteractive_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index a384acc67..c95accf61 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1540,6 +1540,10 @@ certs_status() { send_stats "域名证书申请成功" else send_stats "域名证书申请失败" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 域名证书申请失败,请检查 DNS、80/443 端口和签发限额" + return 1 + fi echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" @@ -1618,6 +1622,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "域名重复使用" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖 kejilion.sh 或 KPanel 的现有产物" + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1633,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + return 0 + fi ip_address echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "请输入你的IP或者解析过的域名: " yuming @@ -9421,7 +9438,29 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 3|4|5|6|7|8|9|27) ;; + *) + echo "KPANEL_PROGRESS 100 不支持的 KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖现有产物" + return 1 + fi + echo "KPANEL_PROGRESS 5 正在启动 kejilion.sh 原生一键建站流程" + else + read -e -p "请输入你的选择: " sub_choice + fi case $sub_choice in @@ -10396,6 +10435,19 @@ linux_ldnmp() { *) echo "无效的输入!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx 配置校验失败" + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh 原生建站产物已完成" + return 0 + fi break_end done diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh new file mode 100644 index 000000000..93f218669 --- /dev/null +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" + +bash -n "${script_path}" +grep -F 'if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then' "${script_path}" >/dev/null +grep -F 'sub_choice="${KJ_WEB_RECIPE:-}"' "${script_path}" >/dev/null +grep -F 'yuming="${KJ_WEB_DOMAIN:-}"' "${script_path}" >/dev/null +grep -F '域名已存在,拒绝覆盖现有产物' "${script_path}" >/dev/null +grep -F 'docker exec nginx nginx -t' "${script_path}" >/dev/null +grep -F 'KPANEL_PROGRESS 100 kejilion.sh 原生建站产物已完成' "${script_path}" >/dev/null + +# KPanel only exposes the fixed, audited one-click menu selectors. +recipe_case="$( + awk ' + /sub_choice="\$\{KJ_WEB_RECIPE:-\}"/ { capture=1 } + capture { print } + capture && /不支持的 KJ_WEB_RECIPE/ { exit } + ' "${script_path}" +)" +for selector in 3 4 5 6 7 8 9 27; do + printf '%s\n' "${recipe_case}" | grep -E "(^|[[:space:]|])${selector}([|)])" >/dev/null +done +if printf '%s\n' "${recipe_case}" | grep -E '(^|[[:space:]|])(20|22|23|24|29|30|34|38)([|)])' >/dev/null; then + printf '%s\n' "unsafe or interactive recipe selector was exposed to KPanel" >&2 + exit 1 +fi From af8fe7cd87ed26ce02cf932653c40b3e4fab3f08 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 12:47:31 +0800 Subject: [PATCH 1214/1285] fix: reject stale application catalog --- kejilion.sh | 42 +++++++------ tests/test_app_catalog_refresh_smoke.sh | 79 +++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 tests/test_app_catalog_refresh_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index c95accf61..f94fa9782 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -15947,21 +15947,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}错误: ${gl_bai}${apps_dir} 已存在但不是应用市场 Git 仓库,拒绝覆盖。" + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}应用列表下载失败,拒绝使用不完整配置。${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}应用列表更新失败,拒绝继续使用可能过期的配置。${gl_bai}" + echo "请检查网络或 ${apps_dir} 中的本地修改后重试。" + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -19805,15 +19821,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" diff --git a/tests/test_app_catalog_refresh_smoke.sh b/tests/test_app_catalog_refresh_smoke.sh new file mode 100644 index 000000000..8546f4709 --- /dev/null +++ b/tests/test_app_catalog_refresh_smoke.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -euo pipefail + +script_path=${1:-"$(cd "$(dirname "$0")/.." && pwd)/kejilion.sh"} +helper_body=$( + awk ' + /^refresh_apps_catalog\(\) \{/ { capture=1 } + capture { print } + capture && /^}/ { exit } + ' "$script_path" +) +[ -n "$helper_body" ] +eval "$helper_body" + +test_root=$(mktemp -d) +cleanup() { + case "$test_root" in + /tmp/*) rm -rf -- "$test_root" ;; + esac +} +trap cleanup EXIT HUP INT TERM + +export HOME="$test_root/home" +mkdir -p "$HOME" +git_log="$test_root/git.log" +: >"$git_log" +gh_proxy= +gl_hong= +gl_bai= + +install() { + [ "$1" = git ] +} + +timeout() { + [ "$1" = 30s ] + shift + "$@" +} + +git() { + printf '%s\n' "$*" >>"$git_log" + case "$1" in + clone) + destination=${4:?missing clone destination} + mkdir -p "$destination/.git" + ;; + -C) + [ "${GIT_PULL_FAIL:-0}" != 1 ] + ;; + *) + return 1 + ;; + esac +} + +refresh_apps_catalog +test -d "$HOME/apps/.git" +grep -Fx 'clone --depth=1 github.com/kejilion/apps.git '"$HOME"'/apps' "$git_log" >/dev/null + +: >"$git_log" +refresh_apps_catalog +grep -Fx -- '-C '"$HOME"'/apps pull --ff-only github.com/kejilion/apps.git main' "$git_log" >/dev/null + +if GIT_PULL_FAIL=1 refresh_apps_catalog >"$test_root/pull-failure.out" 2>&1; then + echo "catalog refresh accepted a failed fast-forward pull" >&2 + exit 1 +fi +grep -F '拒绝继续使用可能过期的配置' "$test_root/pull-failure.out" >/dev/null + +rm -rf -- "$HOME/apps" +mkdir -p "$HOME/apps" +if refresh_apps_catalog >"$test_root/non-git.out" 2>&1; then + echo "catalog refresh accepted an existing non-Git directory" >&2 + exit 1 +fi +grep -F '已存在但不是应用市场 Git 仓库' "$test_root/non-git.out" >/dev/null + +echo "app_catalog_refresh_smoke=pass" From 5cf46fc927bc41360817d459005cfca9f88794bf Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 16:04:21 +0800 Subject: [PATCH 1215/1285] feat: expose WordPress and proxy to KPanel --- kejilion.sh | 42 ++++++++++++++++--- tests/test_kpanel_web_noninteractive_smoke.sh | 10 ++++- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index f94fa9782..051636a45 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2879,6 +2879,11 @@ kpanel_app_progress() { printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" } +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + kpanel_app_service_name() { local service_name="${docker_app_service:-${docker_name:-}}" @@ -3790,25 +3795,31 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "正在校验 WordPress 域名与现有站点" send_stats "安装$webname" echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "正在准备 kejilion.sh LDNMP 环境" ldnmp_install_status + kpanel_web_progress 35 "正在签发并配置站点证书" install_ssltls certs_status + kpanel_web_progress 50 "正在创建 WordPress 数据库与账号" add_db + kpanel_web_progress 60 "正在获取 kejilion.sh WordPress Nginx 配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "正在获取并配置 kejilion.sh WordPress 源码" cd /home/web/html mkdir $yuming cd $yuming @@ -3824,6 +3835,7 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "正在重启 LDNMP 并核验 WordPress 站点" restart_ldnmp nginx_web_on @@ -3838,6 +3850,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "正在校验反向代理域名与上游地址" send_stats "安装$webname" echo "开始部署 $webname" if [ -z "$yuming" ]; then @@ -3854,12 +3867,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "请输入你的反代端口: " port fi + kpanel_web_progress 25 "正在准备 kejilion.sh Nginx 环境" nginx_install_status + kpanel_web_progress 40 "正在签发并配置反向代理证书" install_ssltls certs_status + kpanel_web_progress 60 "正在获取 kejilion.sh 反向代理配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3880,6 +3896,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "正在校验并重载反向代理配置" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -9441,7 +9458,7 @@ linux_ldnmp() { if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then sub_choice="${KJ_WEB_RECIPE:-}" case "$sub_choice" in - 3|4|5|6|7|8|9|27) ;; + 2|3|4|5|6|7|8|9|23|27) ;; *) echo "KPANEL_PROGRESS 100 不支持的 KJ_WEB_RECIPE" return 1 @@ -9457,6 +9474,18 @@ linux_ldnmp() { echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖现有产物" return 1 fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名" + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT 不是有效端口" + return 1 + fi + fi echo "KPANEL_PROGRESS 5 正在启动 kejilion.sh 原生一键建站流程" else read -e -p "请输入你的选择: " sub_choice @@ -9469,7 +9498,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9970,7 +9999,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -10436,8 +10465,11 @@ linux_ldnmp() { echo "无效的输入!" esac if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then - if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || - [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" + return 1 + fi + if [ "$sub_choice" != "23" ] && [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" return 1 fi diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh index 93f218669..791c7783e 100644 --- a/tests/test_kpanel_web_noninteractive_smoke.sh +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -20,10 +20,16 @@ recipe_case="$( capture && /不支持的 KJ_WEB_RECIPE/ { exit } ' "${script_path}" )" -for selector in 3 4 5 6 7 8 9 27; do +for selector in 2 3 4 5 6 7 8 9 23 27; do printf '%s\n' "${recipe_case}" | grep -E "(^|[[:space:]|])${selector}([|)])" >/dev/null done -if printf '%s\n' "${recipe_case}" | grep -E '(^|[[:space:]|])(20|22|23|24|29|30|34|38)([|)])' >/dev/null; then +if printf '%s\n' "${recipe_case}" | grep -E '(^|[[:space:]|])(20|22|24|29|30|34|38)([|)])' >/dev/null; then printf '%s\n' "unsafe or interactive recipe selector was exposed to KPanel" >&2 exit 1 fi + +grep -F 'ldnmp_wp "${KJ_WEB_DOMAIN:-}"' "${script_path}" >/dev/null +grep -F 'ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}"' "${script_path}" >/dev/null +grep -F 'KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名' "${script_path}" >/dev/null +grep -F 'KJ_WEB_PROXY_PORT 不是有效端口' "${script_path}" >/dev/null +grep -F 'if [ "$sub_choice" != "23" ] && [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then' "${script_path}" >/dev/null From 2296c8cf8a3e440d375f87aa4319640adb7f8c18 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 17:03:22 +0800 Subject: [PATCH 1216/1285] feat: add KPanel interactive app protocol --- kejilion.sh | 101 +++++++++++++++--- tests/test_kpanel_app_noninteractive_smoke.sh | 38 +++++++ 2 files changed, 126 insertions(+), 13 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 051636a45..f65c06e4a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2879,6 +2879,44 @@ kpanel_app_progress() { printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" } +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "错误: KPanel 未提供有效的应用访问模式" + return 1 + ;; + esac + ;; + *) + echo "错误: KPanel 交互终端不支持此应用操作" + return 1 + ;; + esac +} + kpanel_web_progress() { [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" @@ -3203,7 +3241,12 @@ while true; do echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" - read -e -p "请输入你的选择: " choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "请输入你的选择: " choice + fi + local action_status=0 case $choice in 1) setup_docker_dir @@ -3223,7 +3266,12 @@ while true; do install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}安装失败: ${gl_bai}应用容器未能启动。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id @@ -3240,7 +3288,12 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}更新失败: ${gl_bai}应用容器未能重新启动。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" @@ -3254,7 +3307,12 @@ while true; do send_stats "更新$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}卸载失败: ${gl_bai}应用容器未能删除。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf @@ -3271,30 +3329,33 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" - kpanel_app_write_access_mode domain_only + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "域名格式 example.com 不带https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" - kpanel_app_write_access_mode direct + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" - kpanel_app_write_access_mode domain_only + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -3336,7 +3397,12 @@ docker_app_plus() { echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" - read -e -p "输入你的选择: " choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "输入你的选择: " choice + fi + local action_status=0 case $choice in 1) setup_docker_dir @@ -3364,6 +3430,7 @@ docker_app_plus() { send_stats "$app_name 安装" else echo -e "${gl_hong}安装失败: ${gl_bai}未登记应用状态,请根据上方错误修复后重试。" + action_status=1 fi ;; @@ -3374,6 +3441,7 @@ docker_app_plus() { send_stats "$app_name 更新" else echo -e "${gl_hong}更新失败: ${gl_bai}已保留原应用登记状态。" + action_status=1 fi ;; @@ -3385,6 +3453,7 @@ docker_app_plus() { send_stats "$app_name 卸载" else echo -e "${gl_hong}卸载失败: ${gl_bai}已保留应用登记状态。" + action_status=1 fi ;; @@ -3395,29 +3464,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" - kpanel_app_write_access_mode domain_only + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "域名格式 example.com 不带https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允许IP访问 ${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" clear_container_rules "$docker_check_name" "$ipv4_address" - kpanel_app_write_access_mode direct + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP访问 ${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" - kpanel_app_write_access_mode domain_only + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -19865,6 +19937,9 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then return fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index 77454bb98..25d9059f5 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -18,6 +18,13 @@ progress_body="$( capture && /^}$/ { exit } ' "${script_path}" )" +interactive_body="$( + awk ' + /^kpanel_app_interactive_choice\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" port_body="$( awk ' /^kpanel_app_install_port\(\) \{/ { capture=1 } @@ -58,6 +65,37 @@ printf '%s\n' "${action_body}" | grep -F 'KJ_APP_ACCESS_MODE' >/dev/null printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_action standard' >/dev/null printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_action plus' >/dev/null grep -F 'if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null +grep -F 'if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null + +eval "${interactive_body}" +unset KJ_APP_INTERACTIVE KJ_APP_ACTION +choice="" +if kpanel_app_interactive_choice choice >/dev/null 2>&1; then + printf '%s\n' "interactive helper accepted a normal SSH session" >&2 + exit 1 +fi +export KJ_APP_INTERACTIVE=1 KJ_APP_ACTION=install +kpanel_app_interactive_choice choice +test "${choice}" = "1" +kpanel_app_verified_service() { return 0; } +export KJ_APP_ACTION=update +kpanel_app_interactive_choice choice +test "${choice}" = "2" +export KJ_APP_ACTION=uninstall +kpanel_app_interactive_choice choice +test "${choice}" = "3" +export KJ_APP_ACTION=direct_access KJ_APP_ACCESS_MODE=direct +kpanel_app_interactive_choice choice +test "${choice}" = "7" +export KJ_APP_ACCESS_MODE=domain_only +kpanel_app_interactive_choice choice +test "${choice}" = "8" +export KJ_APP_ACTION=unsupported +if kpanel_app_interactive_choice choice >/dev/null 2>&1; then + printf '%s\n' "interactive helper accepted an unsupported action" >&2 + exit 1 +fi +unset KJ_APP_INTERACTIVE KJ_APP_ACTION KJ_APP_ACCESS_MODE test_app_root="$(mktemp -d)" trap 'rm -rf "${test_app_root}"' EXIT From 486625bec0117f41ec9a43a72a99f318a35cb6af Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 18:12:18 +0800 Subject: [PATCH 1217/1285] feat: expose DNS settings to KPanel --- kejilion.sh | 245 ++++++++++++++++++ tests/test_kpanel_dns_noninteractive_smoke.sh | 40 +++ 2 files changed, 285 insertions(+) create mode 100644 tests/test_kpanel_dns_noninteractive_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index f65c06e4a..d714c359c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5247,6 +5247,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "错误: /etc/resolv.conf 是失效的符号链接" + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "错误: DNS 配置目录不存在" + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "错误: systemctl 不可用" + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 回滚失败,需要人工检查" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 已恢复文件,但服务重载失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "错误: KPanel DNS 协议必须以 root 运行" + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "错误: DNS 地址数量必须为 1-4 个" + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "错误: DNS 地址为空或过长" + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "错误: IPv4 DNS 地址最多 2 个" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "错误: IPv6 DNS 地址最多 2 个" + return 1 + } + else + echo "错误: 无效的 DNS 地址" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "错误: DNS 地址不能重复" + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -22587,6 +22827,11 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + iptables_open) iptables_open diff --git a/tests/test_kpanel_dns_noninteractive_smoke.sh b/tests/test_kpanel_dns_noninteractive_smoke.sh new file mode 100644 index 000000000..b0c861b1e --- /dev/null +++ b/tests/test_kpanel_dns_noninteractive_smoke.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" + +bash -n "${script_path}" +grep -F 'kpanel_set_dns_noninteractive() {' "${script_path}" >/dev/null +grep -F '[ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null +grep -F 'KPANEL_DNS_MANAGER systemd-resolved' "${script_path}" >/dev/null +grep -F 'KPANEL_DNS_MANAGER resolv.conf' "${script_path}" >/dev/null +grep -F 'KPANEL_DNS_RESULT applied' "${script_path}" >/dev/null +grep -F 'KPANEL_DNS_RESULT unchanged' "${script_path}" >/dev/null +grep -F 'kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable"' "${script_path}" >/dev/null +grep -F 'systemctl reload-or-restart systemd-resolved.service' "${script_path}" >/dev/null +grep -F 'kpanel_set_dns_noninteractive "$@"' "${script_path}" >/dev/null + +validator_body="$( + awk ' + /^kpanel_dns_is_ipv4\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { completed++ } + capture && completed == 2 { exit } + ' "${script_path}" +)" +eval "${validator_body}" + +kpanel_dns_is_ipv4 "1.1.1.1" +kpanel_dns_is_ipv4 "255.255.255.255" +if kpanel_dns_is_ipv4 "256.1.1.1" || kpanel_dns_is_ipv4 "1.1.1"; then + echo "DNS IPv4 validator accepted an invalid address" >&2 + exit 1 +fi +kpanel_dns_is_ipv6 "2606:4700:4700::1111" +if kpanel_dns_is_ipv6 "not-an-ip"; then + echo "DNS IPv6 validator accepted an invalid address" >&2 + exit 1 +fi + +printf '%s\n' "kpanel_dns_noninteractive_smoke=pass" From 6f6a1a78cdc989e9196978b5cb0e1ace5e747559 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 19:22:42 +0800 Subject: [PATCH 1218/1285] feat: expose diagnostic tests to KPanel --- kejilion.sh | 162 ++++++++++++++++++ .../test_kpanel_test_noninteractive_smoke.sh | 63 +++++++ 2 files changed, 225 insertions(+) create mode 100644 tests/test_kpanel_test_noninteractive_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index d714c359c..0efa72507 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9349,6 +9349,159 @@ linux_docker() { +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://bash.icu/gb5 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPT解锁状态检测" + curl -fsSL https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh | bash + ;; + region) + send_stats "Region流媒体解锁测试" + curl -fsSL https://check.unlock.media | bash + ;; + media) + send_stats "yeahwu流媒体解锁检测" + install wget + wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash + ;; + ip-quality) + send_stats "xykt_IP质量体检脚本" + curl -fsSL https://IP.Check.Place | bash + ;; + besttrace) + send_stats "besttrace三网回程延迟路由测试" + install wget + wget -qO- https://git.io/besttrace | bash + ;; + mtr) + send_stats "mtr_trace三网回程线路测试" + curl -fsSL ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash + ;; + superspeed) + send_stats "Superspeed三网测速" + curl -fsSL https://git.io/superspeed_uxh | bash + ;; + nxtrace-fast) + send_stats "nxtrace快速回程测试脚本" + curl -fsSL https://nxtrace.org/nt | bash + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020三网线路测试" + curl -fsSL ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh | sh + ;; + speedtest) + send_stats "i-abc多功能测速脚本" + curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh | bash + ;; + net-quality) + send_stats "网络质量测试脚本" + curl -fsSL https://Net.Check.Place | bash + ;; + tcp-quality) + send_stats "TcpQuality TCP重传探测脚本" + curl -fsSL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh | bash + ;; + yabs) + send_stats "yabs性能测试" + check_swap + curl -fsSL https://yabs.sh | bash -s -- -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU性能测试脚本" + check_swap + curl -fsSL https://bash.icu/gb5 | bash + ;; + bench) + send_stats "bench性能测试" + curl -fsSL https://bench.sh | bash + ;; + ecs) + send_stats "spiritysdx融合怪测评" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "nodequality融合怪测评" + curl -fsSL https://run.NodeQuality.com | bash + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac +} + + linux_test() { while true; do @@ -22832,6 +22985,15 @@ else kpanel_set_dns_noninteractive "$@" ;; + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open diff --git a/tests/test_kpanel_test_noninteractive_smoke.sh b/tests/test_kpanel_test_noninteractive_smoke.sh new file mode 100644 index 000000000..1d84a82bf --- /dev/null +++ b/tests/test_kpanel_test_noninteractive_smoke.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +source_script="${project_root}/kejilion.sh" +script_path="$(mktemp)" +fake_bin="$(mktemp -d)" +cleanup() { + rm -f "$script_path" "$fake_bin/curl" + rmdir "$fake_bin" 2>/dev/null || true +} +trap cleanup EXIT +sed 's/\r$//' "$source_script" >"$script_path" + +bash -n "${script_path}" +grep -F 'kpanel_run_test_noninteractive() {' "${script_path}" >/dev/null +grep -F '[ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null +grep -F 'KPANEL_TEST_ITEM yabs hardware' "${script_path}" >/dev/null +grep -F 'KPANEL_TEST_ITEM nodequality comprehensive' "${script_path}" >/dev/null +grep -F 'kpanel_run_test_noninteractive "$@"' "${script_path}" >/dev/null + +protocol_body="$( + awk ' + /^kpanel_test_catalog\(\) \{/ { capture=1 } + capture { print } + /^kpanel_run_test_noninteractive\(\) \{/ { in_dispatch=1 } + capture && in_dispatch && /^}$/ { exit } + ' "${script_path}" +)" +eval "${protocol_body}" + +catalog="$(KJ_TEST_NONINTERACTIVE=1 kpanel_run_test_noninteractive list)" +item_count="$(printf '%s\n' "$catalog" | grep -c '^KPANEL_TEST_ITEM')" +category_count="$(printf '%s\n' "$catalog" | grep -c '^KPANEL_TEST_CATEGORY')" +[ "$item_count" -eq 17 ] +[ "$category_count" -eq 4 ] +printf '%s\n' "$catalog" | grep -F $'KPANEL_TEST_ITEM\tyabs\thardware\tYABS 性能测试' >/dev/null + +if KJ_TEST_NONINTERACTIVE=1 kpanel_run_test_noninteractive run unknown >/dev/null 2>&1; then + echo "unknown test selector was accepted" >&2 + exit 1 +fi +if KJ_TEST_NONINTERACTIVE=0 kpanel_run_test_noninteractive list >/dev/null 2>&1; then + echo "machine protocol ran without opt-in marker" >&2 + exit 1 +fi + +printf '%s\n' '#!/bin/bash' "printf '%s\n' \"printf 'mock-score=123\\\\n'\"" >"$fake_bin/curl" +chmod +x "$fake_bin/curl" +send_stats() { :; } +result="$(PATH="$fake_bin:$PATH" KJ_TEST_NONINTERACTIVE=1 kpanel_run_test_noninteractive run chatgpt)" +printf '%s\n' "$result" | grep -F 'mock-score=123' >/dev/null +printf '%s\n' "$result" | grep -F 'KPANEL_TEST_RESULT succeeded chatgpt' >/dev/null + +printf '%s\n' '#!/bin/bash' 'exit 22' >"$fake_bin/curl" +set +e +failure_output="$(PATH="$fake_bin:$PATH" KJ_TEST_NONINTERACTIVE=1 kpanel_run_test_noninteractive run chatgpt 2>&1)" +failure_status=$? +set -e +[ "$failure_status" -eq 22 ] +printf '%s\n' "$failure_output" | grep -F 'KPANEL_TEST_RESULT failed chatgpt' >/dev/null + +printf '%s\n' "kpanel_test_noninteractive_smoke=pass" From 4732d87b31b41ef11b4a16cd2d1465e38a5ac7a4 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 20:12:29 +0800 Subject: [PATCH 1219/1285] fix: replace retired GB5 endpoint --- cn/kejilion.sh | 2 +- en/kejilion.sh | 2 +- ir/kejilion.sh | 2 +- jp/kejilion.sh | 2 +- kejilion.sh | 6 +++--- kr/kejilion.sh | 2 +- ru/kejilion.sh | 2 +- tests/test_kpanel_test_noninteractive_smoke.sh | 5 +++++ tw/kejilion.sh | 2 +- 9 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a055869d9..1028981e2 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -8826,7 +8826,7 @@ linux_test() { clear send_stats "icu/gb5 CPU性能测试脚本" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/en/kejilion.sh b/en/kejilion.sh index 5cb2c634e..33975646e 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -8832,7 +8832,7 @@ linux_test() { clear send_stats "icu/gb5 CPU performance test script" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/ir/kejilion.sh b/ir/kejilion.sh index 93c1fff20..524235265 100644 --- a/ir/kejilion.sh +++ b/ir/kejilion.sh @@ -6584,7 +6584,7 @@ linux_test() { clear send_stats "اسکریپت تست عملکرد CPU IICU/GB5" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 5fac0879d..148567a96 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -8832,7 +8832,7 @@ linux_test() { clear send_stats "icu/gb5 CPU パフォーマンステストスクリプト" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/kejilion.sh b/kejilion.sh index 0efa72507..32c8cff6f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9368,7 +9368,7 @@ KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络 KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive -KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://bash.icu/gb5 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive @@ -9456,7 +9456,7 @@ kpanel_run_test_noninteractive() { cpu) send_stats "icu/gb5 CPU性能测试脚本" check_swap - curl -fsSL https://bash.icu/gb5 | bash + curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh | bash ;; bench) send_stats "bench性能测试" @@ -9649,7 +9649,7 @@ linux_test() { clear send_stats "icu/gb5 CPU性能测试脚本" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/kr/kejilion.sh b/kr/kejilion.sh index da9d36c41..f8c5766da 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -8832,7 +8832,7 @@ linux_test() { clear send_stats "icu/gb5 CPU 성능 테스트 스크립트" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/ru/kejilion.sh b/ru/kejilion.sh index aa8505e4f..c0c0fc2a1 100644 --- a/ru/kejilion.sh +++ b/ru/kejilion.sh @@ -6612,7 +6612,7 @@ linux_test() { clear send_stats "Сценарий тестирования производительности процессора IICU/GB5" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) diff --git a/tests/test_kpanel_test_noninteractive_smoke.sh b/tests/test_kpanel_test_noninteractive_smoke.sh index 1d84a82bf..cf836768d 100644 --- a/tests/test_kpanel_test_noninteractive_smoke.sh +++ b/tests/test_kpanel_test_noninteractive_smoke.sh @@ -17,6 +17,11 @@ grep -F 'kpanel_run_test_noninteractive() {' "${script_path}" >/dev/null grep -F '[ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null grep -F 'KPANEL_TEST_ITEM yabs hardware' "${script_path}" >/dev/null grep -F 'KPANEL_TEST_ITEM nodequality comprehensive' "${script_path}" >/dev/null +grep -F 'https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh' "${script_path}" >/dev/null +if grep -F 'bash.icu/gb5' "${script_path}" >/dev/null; then + echo "retired GB5 short URL is still exposed" >&2 + exit 1 +fi grep -F 'kpanel_run_test_noninteractive "$@"' "${script_path}" >/dev/null protocol_body="$( diff --git a/tw/kejilion.sh b/tw/kejilion.sh index b1035cf6a..f514e3ea5 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -8832,7 +8832,7 @@ linux_test() { clear send_stats "icu/gb5 CPU效能測試腳本" check_swap - bash <(curl -sL bash.icu/gb5) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh) ;; 31) From 5361f8f9ba7133e8ce64f32adfa27b22d6247484 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 22:11:28 +0800 Subject: [PATCH 1220/1285] feat: allow interactive KPanel website recovery --- kejilion.sh | 8 +++++++- tests/test_kpanel_web_noninteractive_smoke.sh | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kejilion.sh b/kejilion.sh index 32c8cff6f..9e9bee1fe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1540,7 +1540,8 @@ certs_status() { send_stats "域名证书申请成功" else send_stats "域名证书申请失败" - if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then echo "KPANEL_PROGRESS 100 域名证书申请失败,请检查 DNS、80/443 端口和签发限额" return 1 fi @@ -2922,6 +2923,11 @@ kpanel_web_progress() { printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" } +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + kpanel_app_service_name() { local service_name="${docker_app_service:-${docker_name:-}}" diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh index 791c7783e..15edbb99c 100644 --- a/tests/test_kpanel_web_noninteractive_smoke.sh +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -6,6 +6,8 @@ script_path="${project_root}/kejilion.sh" bash -n "${script_path}" grep -F 'if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then' "${script_path}" >/dev/null +grep -F 'kpanel_web_interactive()' "${script_path}" >/dev/null +grep -F '! kpanel_web_interactive; then' "${script_path}" >/dev/null grep -F 'sub_choice="${KJ_WEB_RECIPE:-}"' "${script_path}" >/dev/null grep -F 'yuming="${KJ_WEB_DOMAIN:-}"' "${script_path}" >/dev/null grep -F '域名已存在,拒绝覆盖现有产物' "${script_path}" >/dev/null From 727d6816629631e19cca5d31a4e0c6521cb97b11 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 27 Jul 2026 23:28:55 +0800 Subject: [PATCH 1221/1285] feat: expose safe website delete command --- kejilion.sh | 71 +++++++++++++++---- tests/test_kpanel_web_noninteractive_smoke.sh | 4 ++ 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 9e9bee1fe..c805b6a61 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1804,32 +1804,72 @@ web_cache() { web_del() { send_stats "删除站点数据" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "无效域名,拒绝删除: $yuming" + action_status=1 + continue + fi + echo "正在删除域名: $yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "正在删除数据库: $dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "站点产物删除不完整: $yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx 配置验证或重载失败" + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -23110,6 +23150,9 @@ else shift if [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "删除" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh index 15edbb99c..073b564ef 100644 --- a/tests/test_kpanel_web_noninteractive_smoke.sh +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -35,3 +35,7 @@ grep -F 'ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PRO grep -F 'KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名' "${script_path}" >/dev/null grep -F 'KJ_WEB_PROXY_PORT 不是有效端口' "${script_path}" >/dev/null grep -F 'if [ "$sub_choice" != "23" ] && [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then' "${script_path}" >/dev/null +grep -F 'web_del "$@"' "${script_path}" >/dev/null +grep -F 'KPANEL_DELETE_SITE deleted $yuming' "${script_path}" >/dev/null +grep -F 'KPANEL_DELETE_DATABASE dropped $yuming' "${script_path}" >/dev/null +grep -F 'rm -rf -- "/home/web/html/$yuming"' "${script_path}" >/dev/null From 7555b4c5d0b39a8c37c8d5a0bdefb3c0b8612c5e Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 00:07:07 +0800 Subject: [PATCH 1222/1285] fix: preserve interactive panel script input --- kejilion.sh | 105 +++++++++++++++--- .../test_kpanel_test_noninteractive_smoke.sh | 13 ++- tests/test_kpanel_web_noninteractive_smoke.sh | 5 + 3 files changed, 104 insertions(+), 19 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index c805b6a61..a25278880 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9421,6 +9421,29 @@ KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQ KPANEL_TEST_CATALOG } +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} + kpanel_run_test_noninteractive() { [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 @@ -9445,68 +9468,66 @@ kpanel_run_test_noninteractive() { case "$selector" in chatgpt) send_stats "ChatGPT解锁状态检测" - curl -fsSL https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh | bash + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh ;; region) send_stats "Region流媒体解锁测试" - curl -fsSL https://check.unlock.media | bash + kpanel_run_remote_bash https://check.unlock.media ;; media) send_stats "yeahwu流媒体解锁检测" - install wget - wget -qO- ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh | bash + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh ;; ip-quality) send_stats "xykt_IP质量体检脚本" - curl -fsSL https://IP.Check.Place | bash + kpanel_run_remote_bash https://IP.Check.Place ;; besttrace) send_stats "besttrace三网回程延迟路由测试" - install wget - wget -qO- https://git.io/besttrace | bash + kpanel_run_remote_bash https://git.io/besttrace ;; mtr) send_stats "mtr_trace三网回程线路测试" - curl -fsSL ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh ;; superspeed) send_stats "Superspeed三网测速" - curl -fsSL https://git.io/superspeed_uxh | bash + kpanel_run_remote_bash https://git.io/superspeed_uxh ;; nxtrace-fast) send_stats "nxtrace快速回程测试脚本" - curl -fsSL https://nxtrace.org/nt | bash + kpanel_run_remote_bash https://nxtrace.org/nt nexttrace --fast-trace --tcp ;; backtrace) send_stats "ludashi2020三网线路测试" - curl -fsSL ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh | sh + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh ;; speedtest) send_stats "i-abc多功能测速脚本" - curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh | bash + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh ;; net-quality) send_stats "网络质量测试脚本" - curl -fsSL https://Net.Check.Place | bash + kpanel_run_remote_bash https://Net.Check.Place ;; tcp-quality) send_stats "TcpQuality TCP重传探测脚本" - curl -fsSL https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh | bash + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh ;; yabs) send_stats "yabs性能测试" check_swap - curl -fsSL https://yabs.sh | bash -s -- -i -5 + kpanel_run_remote_bash https://yabs.sh -i -5 ;; cpu) send_stats "icu/gb5 CPU性能测试脚本" check_swap - curl -fsSL ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh | bash + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh ;; bench) send_stats "bench性能测试" - curl -fsSL https://bench.sh | bash + kpanel_run_remote_bash https://bench.sh ;; ecs) send_stats "spiritysdx融合怪测评" @@ -9525,7 +9546,7 @@ kpanel_run_test_noninteractive() { ;; nodequality) send_stats "nodequality融合怪测评" - curl -fsSL https://run.NodeQuality.com | bash + kpanel_run_remote_bash https://run.NodeQuality.com ;; *) echo "KPANEL_TEST_ERROR unsupported test selector" >&2 @@ -9938,9 +9959,24 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "用法: k <建站命令> <域名>" + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + linux_ldnmp +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP建站" echo -e "${gl_huang}LDNMP建站" @@ -9966,6 +10002,7 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" + fi if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then sub_choice="${KJ_WEB_RECIPE:-}" case "$sub_choice" in @@ -22990,6 +23027,38 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" ;; fd|rp|反代) shift diff --git a/tests/test_kpanel_test_noninteractive_smoke.sh b/tests/test_kpanel_test_noninteractive_smoke.sh index cf836768d..14cb6e34e 100644 --- a/tests/test_kpanel_test_noninteractive_smoke.sh +++ b/tests/test_kpanel_test_noninteractive_smoke.sh @@ -23,6 +23,11 @@ if grep -F 'bash.icu/gb5' "${script_path}" >/dev/null; then exit 1 fi grep -F 'kpanel_run_test_noninteractive "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_remote_bash() {' "${script_path}" >/dev/null +if sed -n '/^kpanel_run_test_noninteractive()/,/^linux_test()/p' "${script_path}" | grep -Eq '\|[[:space:]]*(ba)?sh'; then + echo "KPanel diagnostics must download scripts before execution so PTY stdin stays interactive" >&2 + exit 1 +fi protocol_body="$( awk ' @@ -50,7 +55,13 @@ if KJ_TEST_NONINTERACTIVE=0 kpanel_run_test_noninteractive list >/dev/null 2>&1; exit 1 fi -printf '%s\n' '#!/bin/bash' "printf '%s\n' \"printf 'mock-score=123\\\\n'\"" >"$fake_bin/curl" +printf '%s\n' \ + '#!/bin/bash' \ + 'while [ "$#" -gt 0 ]; do' \ + ' if [ "$1" = "-o" ]; then output="$2"; shift 2; else shift; fi' \ + 'done' \ + 'printf '"'"'%s\n'"'"' "printf '"'"'mock-score=123\\n'"'"'" >"$output"' \ + >"$fake_bin/curl" chmod +x "$fake_bin/curl" send_stats() { :; } result="$(PATH="$fake_bin:$PATH" KJ_TEST_NONINTERACTIVE=1 kpanel_run_test_noninteractive run chatgpt)" diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh index 073b564ef..4ed7faab5 100644 --- a/tests/test_kpanel_web_noninteractive_smoke.sh +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -39,3 +39,8 @@ grep -F 'web_del "$@"' "${script_path}" >/dev/null grep -F 'KPANEL_DELETE_SITE deleted $yuming' "${script_path}" >/dev/null grep -F 'KPANEL_DELETE_DATABASE dropped $yuming' "${script_path}" >/dev/null grep -F 'rm -rf -- "/home/web/html/$yuming"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli()' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 3 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 27 "$@"' "${script_path}" >/dev/null +grep -F 'ldnmp_wp "$@"' "${script_path}" >/dev/null +grep -F 'ldnmp_Proxy "$@"' "${script_path}" >/dev/null From a06bbc0662a426841c28bef9d692c12f13cc1d9d Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 08:16:34 +0800 Subject: [PATCH 1223/1285] fix: isolate KPanel script protocols --- kejilion.sh | 33 ++++++++++++------- tests/test_kpanel_dns_noninteractive_smoke.sh | 18 ++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a25278880..77133835f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -16,6 +16,14 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +kpanel_protocol_active() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -100,17 +108,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 - +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -141,7 +150,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi diff --git a/tests/test_kpanel_dns_noninteractive_smoke.sh b/tests/test_kpanel_dns_noninteractive_smoke.sh index b0c861b1e..5b8f3ec3d 100644 --- a/tests/test_kpanel_dns_noninteractive_smoke.sh +++ b/tests/test_kpanel_dns_noninteractive_smoke.sh @@ -6,6 +6,8 @@ script_path="${project_root}/kejilion.sh" bash -n "${script_path}" grep -F 'kpanel_set_dns_noninteractive() {' "${script_path}" >/dev/null +grep -F 'kpanel_protocol_active() {' "${script_path}" >/dev/null +grep -F 'if ! kpanel_protocol_active; then' "${script_path}" >/dev/null grep -F '[ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null grep -F 'KPANEL_DNS_MANAGER systemd-resolved' "${script_path}" >/dev/null grep -F 'KPANEL_DNS_MANAGER resolv.conf' "${script_path}" >/dev/null @@ -37,4 +39,20 @@ if kpanel_dns_is_ipv6 "not-an-ip"; then exit 1 fi +protocol_guard_body="$( + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +eval "${protocol_guard_body}" +KJ_DNS_NONINTERACTIVE=1 +kpanel_protocol_active +unset KJ_DNS_NONINTERACTIVE +if kpanel_protocol_active; then + echo "KPanel protocol guard activated without a protocol environment variable" >&2 + exit 1 +fi + printf '%s\n' "kpanel_dns_noninteractive_smoke=pass" From ded5af10d04ba4f9b39ca324ae662c126c364481 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 11:36:12 +0800 Subject: [PATCH 1224/1285] feat: add KPanel LDNMP environment protocol --- kejilion.sh | 688 +++++++++++++++++-- tests/test_kpanel_ldnmp_environment_smoke.sh | 65 ++ 2 files changed, 677 insertions(+), 76 deletions(-) create mode 100644 tests/test_kpanel_ldnmp_environment_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index 77133835f..82160fd2f 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -21,6 +21,7 @@ kpanel_protocol_active() { [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] } @@ -2413,8 +2414,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "不支持的 LDNMP 优化模式" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "LDNMP环境已设置成 高性能模式" + else + optimize_balanced + echo "LDNMP环境已设置成 标准模式" + fi +} web_optimization() { while true; do @@ -2436,83 +2495,11 @@ web_optimization() { case $sub_choice in 1) send_stats "站点标准模式" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # php调优 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php调优 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql调优 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "LDNMP环境已设置成 标准模式" - + ldnmp_optimization_mode standard ;; 2) send_stats "站点高性能模式" - - # nginx调优 - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # php调优 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php调优 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql调优 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "LDNMP环境已设置成 高性能模式" - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -9980,7 +9967,553 @@ kpanel_run_web_recipe_cli() { KJ_WEB_NONINTERACTIVE=1 KJ_WEB_RECIPE="$selector" KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "已有网站或 LDNMP 环境任务正在执行" >&2 + exec {lock_fd}>&- + return 75 + fi linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","required":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","repoDigest":"%s","updateStatus":"unknown","updateReason":"Registry 状态仅在更新任务中实时确认"}' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"完整 LDNMP"},{"id":"nginx","label":"仅 Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudflare-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"]},{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "正在检查安装条件" + case "$profile" in + full) kpanel_ldnmp_event install 15 "正在安装完整 LDNMP"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "正在安装 Nginx"; nginx_install_all ;; + *) echo "不支持的安装形态" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "正在验证环境" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare 凭据通道无效" >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "不支持的防护动作" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "防护配置验证失败,正在恢复原配置" + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "当前协议不支持该优化动作" >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "优化验证失败,正在恢复原配置" + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "正在创建更新前冷备" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "不支持的更新组件" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "正在短暂停止 LDNMP" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "正在归档 /home/web" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "正在恢复 LDNMP" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "正在扫描备份归档" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "正在解压到安全暂存目录" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "正在原子切换 /home/web" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "已有网站或 LDNMP 环境任务正在执行" + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP 环境任务已启动" + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP 环境任务已完成" + kpanel_ldnmp_result succeeded "$action" "任务执行成功" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP 环境任务执行失败" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "任务失败且无法确认安全回滚,需要人工处理" + else + kpanel_ldnmp_result failed "$action" "任务执行失败" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP 环境管理" + echo "------------------------" + echo "1. 查看环境状态" + echo "2. 安装完整 LDNMP" + echo "3. 仅安装 Nginx" + echo "4. 防护管理" + echo "5. 优化管理" + echo "6. 更新环境" + echo "7. 创建冷备" + echo "8. 还原备份" + echo "9. 卸载环境" + echo "0. 返回" + echo "------------------------" + read -e -p "请输入你的选择: " choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "更新组件 (nginx/mysql/php/redis/all): " component + read -e -p "目标版本(默认 latest): " version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "输入要还原的备份文件名: " backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "输入 DELETE 确认卸载 LDNMP 环境: " confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "无效的输入" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "不支持的 LDNMP 环境命令" >&2; return 2 ;; + esac } @@ -23228,7 +23761,10 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "环境" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "删除" ]; then shift diff --git a/tests/test_kpanel_ldnmp_environment_smoke.sh b/tests/test_kpanel_ldnmp_environment_smoke.sh new file mode 100644 index 000000000..5bc255577 --- /dev/null +++ b/tests/test_kpanel_ldnmp_environment_smoke.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" + +bash -n "${script_path}" + +for function_name in \ + ldnmp_environment_status \ + ldnmp_environment_catalog \ + ldnmp_environment_install \ + ldnmp_protection_action \ + ldnmp_optimization_mode \ + ldnmp_optimization_action \ + ldnmp_update_action \ + ldnmp_backup_action \ + ldnmp_backup_delete_action \ + ldnmp_restore_action \ + ldnmp_uninstall_action \ + ldnmp_environment_menu \ + kpanel_ldnmp_dispatch; do + grep -F "${function_name}() {" "${script_path}" >/dev/null +done + +grep -F '[ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/null +grep -F 'KPANEL_LDNMP_PROTOCOL 1' "${script_path}" >/dev/null +grep -F 'KPANEL_LDNMP_EVENT {' "${script_path}" >/dev/null +grep -F 'KPANEL_LDNMP_RESULT %s' "${script_path}" >/dev/null +grep -F '/var/lib/kejilion-panel/environment-jobs/*.receipt)' "${script_path}" >/dev/null +grep -F "grep -Eq '^web_[0-9]{14}\\.tar\\.gz$'" "${script_path}" >/dev/null +grep -F 'docker compose -f "$stage/web/docker-compose.yml" config -q' "${script_path}" >/dev/null +grep -F 'kpanel_ldnmp_dispatch "$@"' "${script_path}" >/dev/null +grep -F '/run/lock/kejilion-web-environment.lock' "${script_path}" >/dev/null +grep -F 'kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@"' "${script_path}" >/dev/null +grep -F 'ldnmp_optimization_mode standard' "${script_path}" >/dev/null +grep -F 'ldnmp_optimization_mode high' "${script_path}" >/dev/null +grep -F 'ldnmp_backup_action || return 1' "${script_path}" >/dev/null +grep -F 'ldnmp_environment_menu' "${script_path}" >/dev/null +grep -F '/var/lib/kejilion-panel/environment-jobs/*.secret)' "${script_path}" >/dev/null +grep -F 'cloudflare-fail2ban|cloudflare-shield)' "${script_path}" >/dev/null +grep -F 'rm -f -- "$KJ_LDNMP_SECRET_FILE"' "${script_path}" >/dev/null + +# The original k web menu remains present and keeps its established selectors. +for menu_line in \ + '1. ${gl_bai}安装LDNMP环境' \ + '32. ${gl_bai}备份全站数据' \ + '34. ${gl_bai}还原全站数据' \ + '37. ${gl_bai}更新LDNMP环境' \ + '38. ${gl_bai}卸载LDNMP环境'; do + grep -F "${menu_line}" "${script_path}" >/dev/null +done + +protocol_guard_body="$( + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +eval "${protocol_guard_body}" +KJ_LDNMP_NONINTERACTIVE=1 +kpanel_protocol_active + +printf '%s\n' "kpanel_ldnmp_environment_smoke=pass" From 8ad705bc48f56eda2ce5b39e2562b3630d2dcef5 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 12:44:32 +0800 Subject: [PATCH 1225/1285] feat: expose SSH defense protocol for KPanel --- kejilion.sh | 111 +++++++++++++++++- tests/test_kpanel_f2b_noninteractive_smoke.sh | 66 +++++++++++ 2 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 tests/test_kpanel_f2b_noninteractive_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index 82160fd2f..c4b80be70 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -18,6 +18,7 @@ ENABLE_STATS="true" kpanel_protocol_active() { [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || @@ -3668,6 +3669,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH jail 未能正常启动" >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban 服务仍在运行" >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "用法: k f2b [status|enable|disable]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -23502,7 +23604,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" +echo "fail2ban管理 k fail2ban | k f2b [status|enable|disable]" echo "显示系统信息 k info" echo "ROOT密钥管理 k sshkey" echo "SSH公钥导入(URL) k sshkey " @@ -23796,7 +23898,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; diff --git a/tests/test_kpanel_f2b_noninteractive_smoke.sh b/tests/test_kpanel_f2b_noninteractive_smoke.sh new file mode 100644 index 000000000..2309492c6 --- /dev/null +++ b/tests/test_kpanel_f2b_noninteractive_smoke.sh @@ -0,0 +1,66 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" + +bash -n "${script_path}" + +for function_name in \ + kpanel_f2b_jail_name \ + kpanel_f2b_enabled \ + kpanel_f2b_autostart \ + kpanel_f2b_status \ + kpanel_f2b_dispatch; do + grep -F "${function_name}() {" "${script_path}" >/dev/null +done + +grep -F '[ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/null +grep -F 'KPANEL_F2B_PROTOCOL 1' "${script_path}" >/dev/null +grep -F 'KPANEL_F2B_STATUS {' "${script_path}" >/dev/null +grep -F 'KPANEL_F2B_RESULT %s' "${script_path}" >/dev/null +grep -F 'kpanel_f2b_dispatch "$@"' "${script_path}" >/dev/null +grep -F '/bin/systemctl disable --now fail2ban.service' "${script_path}" >/dev/null + +# The original bare `k f2b` path must remain an interactive menu. +grep -F 'fail2ban_panel' "${script_path}" >/dev/null +grep -F '1. 安装防御程序' "${script_path}" >/dev/null +grep -F '9. 卸载防御程序' "${script_path}" >/dev/null + +protocol_guard_body="$( + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +eval "${protocol_guard_body}" +KJ_F2B_NONINTERACTIVE=1 +kpanel_protocol_active + +status_functions="$( + awk ' + /^kpanel_f2b_jail_name\(\) \{/ { capture=1 } + /^f2b_sshd\(\) \{/ { exit } + capture { print } + ' "${script_path}" +)" +eval "${status_functions}" +fail2ban-client() { + case "${1:-}" in + ping) return 0 ;; + status) + printf '%s\n' \ + "Status for the jail: sshd" \ + "| Currently banned: 2" + ;; + esac +} +status_output="$(kpanel_f2b_status)" +grep -F '"installed":true' <<<"${status_output}" >/dev/null +grep -F '"running":true' <<<"${status_output}" >/dev/null +grep -F '"enabled":true' <<<"${status_output}" >/dev/null +grep -F '"jail":"sshd"' <<<"${status_output}" >/dev/null +grep -F '"banned":2' <<<"${status_output}" >/dev/null + +printf '%s\n' "kpanel_f2b_noninteractive_smoke=pass" From cd4a97823e95f4029f6cb3a82249f2adf5d53763 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 15:21:05 +0800 Subject: [PATCH 1226/1285] feat: expose interactive app management for KPanel --- kejilion.sh | 16 ++++++++++++++++ tests/test_kpanel_app_noninteractive_smoke.sh | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/kejilion.sh b/kejilion.sh index c4b80be70..a42c81424 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2919,6 +2919,19 @@ kpanel_app_progress() { printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" } +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + kpanel_app_verified_service true || return 1 + read -r -e -p "请输入你的选择: " selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "错误: KPanel 应用管理终端只接受菜单编号" + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + kpanel_app_interactive_choice() { local target_variable="$1" @@ -2935,6 +2948,9 @@ kpanel_app_interactive_choice() { kpanel_app_verified_service true || return 1 printf -v "$target_variable" '%s' "3" ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; direct_access) kpanel_app_verified_service true || return 1 case "${KJ_APP_ACCESS_MODE:-}" in diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index 25d9059f5..60893cb06 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -25,6 +25,13 @@ interactive_body="$( capture && /^}$/ { exit } ' "${script_path}" )" +interactive_manage_body="$( + awk ' + /^kpanel_app_interactive_manage_choice\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" port_body="$( awk ' /^kpanel_app_install_port\(\) \{/ { capture=1 } @@ -66,7 +73,9 @@ printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_action stand printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_action plus' >/dev/null grep -F 'if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null grep -F 'if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null +printf '%s\n' "${interactive_manage_body}" | grep -F 'KPanel 应用管理终端只接受菜单编号' >/dev/null +eval "${interactive_manage_body}" eval "${interactive_body}" unset KJ_APP_INTERACTIVE KJ_APP_ACTION choice="" @@ -84,6 +93,14 @@ test "${choice}" = "2" export KJ_APP_ACTION=uninstall kpanel_app_interactive_choice choice test "${choice}" = "3" +export KJ_APP_ACTION=manage +choice="" +kpanel_app_interactive_choice choice <<<'6' +test "${choice}" = "6" +if kpanel_app_interactive_choice choice <<<'invalid' >/dev/null 2>&1; then + printf '%s\n' "interactive management accepted a non-menu input" >&2 + exit 1 +fi export KJ_APP_ACTION=direct_access KJ_APP_ACCESS_MODE=direct kpanel_app_interactive_choice choice test "${choice}" = "7" From 9c19fc3f10e77dd352e5f6f7a0c53d8a1ba64761 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 21:14:12 +0800 Subject: [PATCH 1227/1285] feat: support KPanel marker recovery terminal --- kejilion.sh | 17 +++++++---- tests/test_kpanel_app_noninteractive_smoke.sh | 28 ++++++++++++++++++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index a42c81424..59a1897bf 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -20,6 +20,7 @@ kpanel_protocol_active() { [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || @@ -2923,7 +2924,9 @@ kpanel_app_interactive_manage_choice() { local target_variable="$1" local selected_choice="" - kpanel_app_verified_service true || return 1 + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi read -r -e -p "请输入你的选择: " selected_choice || return 1 if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then echo "错误: KPanel 应用管理终端只接受菜单编号" @@ -3204,10 +3207,14 @@ kpanel_run_docker_app_action() { kpanel_app_progress 5 "正在核对 kejilion.sh 安装标记与主容器" service_name="$(kpanel_app_verified_service true)" || return 1 - grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null || { - echo "错误: 未发现 kejilion.sh 应用安装标记" - return 1 - } + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "错误: 未发现 kejilion.sh 应用安装标记" + return 1 + fi + kpanel_app_progress 10 "正在修复 kejilion.sh 应用安装标记" + add_app_id || return 1 + fi case "$action" in update) diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index 60893cb06..798c5e5c5 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -4,6 +4,13 @@ set -euo pipefail project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" script_path="${project_root}/kejilion.sh" +protocol_body="$( + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" helper_body="$( awk ' /^kpanel_run_docker_app_install\(\) \{/ { capture=1 } @@ -69,11 +76,15 @@ printf '%s\n' "${helper_body}" | grep -F 'echo "$docker_port" > "/home/docker/${ printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_progress 100 "应用安装完成"' >/dev/null printf '%s\n' "${action_body}" | grep -F 'kpanel_app_verified_service true' >/dev/null printf '%s\n' "${action_body}" | grep -F 'KJ_APP_ACCESS_MODE' >/dev/null +printf '%s\n' "${action_body}" | grep -F 'KJ_APP_RECONCILE_MARKER' >/dev/null +printf '%s\n' "${action_body}" | grep -F 'add_app_id || return 1' >/dev/null printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_run_docker_app_action standard' >/dev/null printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_run_docker_app_action plus' >/dev/null +printf '%s\n' "${protocol_body}" | grep -F '[ "${KJ_APP_INTERACTIVE:-}" = "1" ]' >/dev/null grep -F 'if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null grep -F 'if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then' "${script_path}" >/dev/null printf '%s\n' "${interactive_manage_body}" | grep -F 'KPanel 应用管理终端只接受菜单编号' >/dev/null +printf '%s\n' "${interactive_manage_body}" | grep -F 'KJ_APP_MARKER_RECOVERY' >/dev/null eval "${interactive_manage_body}" eval "${interactive_body}" @@ -97,6 +108,21 @@ export KJ_APP_ACTION=manage choice="" kpanel_app_interactive_choice choice <<<'6' test "${choice}" = "6" +recovery_verifications=0 +kpanel_app_verified_service() { + recovery_verifications=$((recovery_verifications + 1)) + return 1 +} +export KJ_APP_MARKER_RECOVERY=1 +kpanel_app_interactive_choice choice <<<'1' +test "${choice}" = "1" +test "${recovery_verifications}" = "0" +unset KJ_APP_MARKER_RECOVERY +if kpanel_app_interactive_choice choice <<<'1' >/dev/null 2>&1; then + printf '%s\n' "interactive management bypassed container verification without recovery mode" >&2 + exit 1 +fi +kpanel_app_verified_service() { return 0; } if kpanel_app_interactive_choice choice <<<'invalid' >/dev/null 2>&1; then printf '%s\n' "interactive management accepted a non-menu input" >&2 exit 1 @@ -112,7 +138,7 @@ if kpanel_app_interactive_choice choice >/dev/null 2>&1; then printf '%s\n' "interactive helper accepted an unsupported action" >&2 exit 1 fi -unset KJ_APP_INTERACTIVE KJ_APP_ACTION KJ_APP_ACCESS_MODE +unset KJ_APP_INTERACTIVE KJ_APP_ACTION KJ_APP_ACCESS_MODE KJ_APP_MARKER_RECOVERY test_app_root="$(mktemp -d)" trap 'rm -rf "${test_app_root}"' EXIT From 4ee3f96591d4f6bd9a062fb574beee03107572fc Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 28 Jul 2026 22:37:11 +0800 Subject: [PATCH 1228/1285] fix: detect Docker Hub latest image updates --- kejilion.sh | 57 ++++++++++++++------ tests/test_docker_image_update_smoke.sh | 70 +++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 tests/test_docker_image_update_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index 59a1897bf..d9e970698 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2602,19 +2602,18 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 区域检查 - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. 获取本地镜像信息 - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. 获取容器及本地镜像信息。更新检测不再按地区跳过。 + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 智能路由判断 + # 2. 智能路由判断 if [[ "$full_image_name" == ghcr.io* ]]; then # --- 场景 A: 镜像在 GitHub (ghcr.io) --- # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg @@ -2630,19 +2629,45 @@ check_docker_image_update() { else # --- 场景 C: 标准 Docker Hub --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}发现新版本!${gl_bai}" + fi + return + fi fi - # 4. 时间戳对比 + # 3. Registry 未提供可比较摘要时,兼容使用发布时间判断。 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" fi fi diff --git a/tests/test_docker_image_update_smoke.sh b/tests/test_docker_image_update_smoke.sh new file mode 100644 index 000000000..3fa6d2889 --- /dev/null +++ b/tests/test_docker_image_update_smoke.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${repo_root}/kejilion.sh" +tmp_dir="$(mktemp -d)" +trap 'rm -rf "$tmp_dir"' EXIT + +awk ' + /^check_docker_image_update\(\) \{/ { capture=1 } + capture { print } + capture && /^}/ { exit } +' "$script_path" | sed 's/\r$//' >"$tmp_dir/function.sh" + +mkdir -p "$tmp_dir/bin" +cat >"$tmp_dir/bin/docker" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +if [[ "$1" == "inspect" ]]; then + printf '%s\n' '2026-07-27T00:00:00Z,docker.io/kjlion/kejilion-panel:latest,sha256:local-image' + exit 0 +fi +if [[ "$1" == "image" && "$2" == "inspect" ]]; then + printf 'docker.io/kjlion/kejilion-panel@%s\n' "${LOCAL_DIGEST:?}" + exit 0 +fi +exit 1 +EOF +cat >"$tmp_dir/bin/curl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +url="${@: -1}" +printf '%s\n' "$url" >>"${CURL_LOG:?}" +printf '%s\n' '{"digest":"placeholder","last_updated":"2026-07-28T00:00:00Z"}' +EOF +cat >"$tmp_dir/bin/jq" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +cat >/dev/null +case "$*" in + *'.digest // empty'*) printf '%s\n' "${REMOTE_DIGEST:?}" ;; + *'.last_updated // empty'*) printf '%s\n' '2026-07-28T00:00:00Z' ;; + *) exit 1 ;; +esac +EOF +chmod +x "$tmp_dir/bin/docker" "$tmp_dir/bin/curl" "$tmp_dir/bin/jq" + +# shellcheck disable=SC1090 +source "$tmp_dir/function.sh" +gl_huang="" +gl_bai="" +export CURL_LOG="$tmp_dir/curl.log" +export LOCAL_DIGEST="sha256:$(printf 'a%.0s' {1..64})" +export REMOTE_DIGEST="sha256:$(printf 'b%.0s' {1..64})" +PATH="$tmp_dir/bin:$PATH" + +check_docker_image_update kpanel +test "$update_status" = "发现新版本!" +grep -Fx 'https://hub.docker.com/v2/repositories/kjlion/kejilion-panel/tags/latest' "$CURL_LOG" >/dev/null +if grep -q 'ipinfo.io' "$CURL_LOG"; then + printf '%s\n' "update detection still depends on IP geolocation" >&2 + exit 1 +fi + +: >"$CURL_LOG" +export REMOTE_DIGEST="$LOCAL_DIGEST" +check_docker_image_update kpanel +test -z "$update_status" + +printf '%s\n' "docker_image_update_smoke=pass" From 229355b1b6e1ce405cc97019b3755e36f2b814c1 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 00:24:44 +0800 Subject: [PATCH 1229/1285] feat: accept KPanel application install ports --- kejilion.sh | 65 ++++++++++++------- tests/test_kpanel_app_noninteractive_smoke.sh | 30 ++++++++- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d9e970698..9bbb6dbd7 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3156,7 +3156,7 @@ kpanel_app_install_port() { echo "错误: KPanel 应用端口必须在 1-65535 之间" return 1 fi - if ss -tuln 2>/dev/null | grep -q ":${requested_port} "; then + if kpanel_app_port_in_use "$requested_port"; then echo "错误: 端口 ${requested_port} 已被占用" return 1 fi @@ -3164,6 +3164,43 @@ kpanel_app_install_port() { return 0 } +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + docker_port="$app_port" + return 0 + fi + done +} + kpanel_run_docker_app_install() { local adapter="$1" @@ -3344,18 +3381,7 @@ while true; do 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker @@ -3501,18 +3527,7 @@ docker_app_plus() { setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index 798c5e5c5..b7b5f158e 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -46,6 +46,20 @@ port_body="$( capture && /^}$/ { exit } ' "${script_path}" )" +port_in_use_body="$( + awk ' + /^kpanel_app_port_in_use\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" +choose_port_body="$( + awk ' + /^kpanel_app_choose_install_port\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" +)" docker_app_body="$( awk ' /^docker_app\(\) \{/ { capture=1 } @@ -70,6 +84,10 @@ action_body="$( printf '%s\n' "${helper_body}" | grep -F '[ "${KJ_APP_ACTION:-}" != "install" ]' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'kpanel_app_install_port || return 1' >/dev/null +printf '%s\n' "${docker_app_body}" | grep -F 'kpanel_app_choose_install_port || return 1' >/dev/null +printf '%s\n' "${docker_app_plus_body}" | grep -F 'kpanel_app_choose_install_port || return 1' >/dev/null +printf '%s\n' "${choose_port_body}" | grep -F '[ "${KJ_APP_INTERACTIVE:-}" = "1" ]' >/dev/null +printf '%s\n' "${choose_port_body}" | grep -F 'kpanel_app_install_port' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'if ! docker_app_install; then' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'if ! docker_rum; then' >/dev/null printf '%s\n' "${helper_body}" | grep -F 'echo "$docker_port" > "/home/docker/${docker_name}_port.conf"' >/dev/null @@ -144,7 +162,9 @@ test_app_root="$(mktemp -d)" trap 'rm -rf "${test_app_root}"' EXIT mkdir -p "${test_app_root}" runtime_helpers="$( - printf '%s\n%s\n%s\n' "${progress_body}" "${port_body}" "${helper_body}" | + printf '%s\n%s\n%s\n%s\n%s\n' \ + "${progress_body}" "${port_in_use_body}" "${port_body}" \ + "${choose_port_body}" "${helper_body}" | sed "s|/home/docker|${test_app_root}|g" )" eval "${runtime_helpers}" @@ -177,6 +197,14 @@ printf '%s\n' "${runtime_output}" | grep -F "KPANEL_PROGRESS 100" >/dev/null printf '%s\n' "${runtime_output}" | grep -F "user=admin" >/dev/null printf '%s\n' "${runtime_output}" | grep -F "password=protected" >/dev/null +unset KJ_APP_NONINTERACTIVE +export KJ_APP_INTERACTIVE=1 KJ_APP_PORT=18082 +docker_port=8080 +kpanel_app_choose_install_port +test "${docker_port}" = "18082" +unset KJ_APP_INTERACTIVE +export KJ_APP_NONINTERACTIVE=1 + docker_rum() { return 1; } docker_name="test-failed" app_id=998 From fe199dff5323a64a6394fb0725f359b8127fbd43 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 08:23:21 +0800 Subject: [PATCH 1230/1285] chore: release kejilion.sh 4.5.3 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kejilion_sh_log.txt | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1028981e2..a6008334e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.3" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 9bbb6dbd7..281457290 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.3" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 08bfc05f1..774a28606 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1518,4 +1518,12 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 2026-06-18 v4.5.2 系统工具中修复部分场景中SSH端口切换后无法连接的问题。 应用市场中的多人会议项目部署报错问题。 +------------------------ +2026-07-29 v4.5.3 +新增KPanel兼容协议,支持应用、网站、DNS、SSH防御、体检及LDNMP环境管理等业务由面板调用。 +应用市场支持KPanel后台交互终端和任务完成标记,提升安装、更新、卸载及脚本管理状态同步的准确性。 +应用安装支持由KPanel预先传入端口,并在脚本端再次检测端口占用;原SSH与 k app 交互方式保持不变。 +优化KPanel协议隔离、交互输入和任务恢复,降低任务中断、状态漂移及结果误判。 +修复Docker Hub latest镜像更新检测,提高应用新版本识别准确性。 +新增KPanel的WordPress、IP端口反代、网站删除及LDNMP环境管理入口,原 k web 菜单保持兼容。 From 68328934697ac31d804613d466b2eb08c89fe5b0 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 11:05:14 +0800 Subject: [PATCH 1231/1285] docs: refresh project README --- README.md | 229 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 120 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 9be65afee..7d5da2eee 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,163 @@ -


-
- logo -
- -
-

KEJILION.SH - 科技lion一键脚本工具

-
+

+ 科技lion一键脚本工具 +

+

科技lion一键脚本工具

- - 简体中文 - - - 繁體中文 - - - English - - - 한국어 - - - 日本語 - - - Русский - - - فارسی - + 面向 Linux 服务器的综合运维脚本,集成系统管理、Docker、LDNMP 建站、 + 应用市场、网络测试、备份迁移与安全防护。

+

+ GitHub Stars + GitHub Forks + Apache-2.0 License + Last Commit +

+

+ 简体中文 · + 繁體中文 · + 한국어 · + 日本語 · + Русский · + فارسی +

-


- - -## 📜 介绍 (Introduction) -科技Lion 的 Shell 脚本工具是一款全能脚本工具箱,专为 Linux 监控、测试和管理而设计。无论您是初学者还是经验丰富的用户,该工具都能为您提供便捷的解决方案。集成了独创的 Docker 管理功能,让您轻松管理容器化应用;LNMP建站解决方案能帮助您快速搭建网站,站点优化、防御、备份还原迁移一应俱全;并且整合了各类系统工具面板的安装及使用,使系统维护变得更加简单。我们的目标是成为全网最优秀的 Linux 一键脚本工具,为用户提供高效、便捷的科技支持。 - -KejiLion's Shell script tool is an all-in-one script toolbox designed for Linux monitoring, testing, and management. Whether you are a beginner or an experienced user, this tool offers convenient solutions. It integrates unique Docker management features, enabling easy containerized application management. The LNMP site-building solution helps you quickly set up websites, covering optimization, defense, backup, restoration, and migration. It also includes the installation and use of various system tool panels, making system maintenance simpler. Our goal is to become the best Linux one-click script tool on the internet, providing users with efficient and convenient tech support. - -

- - -## 🌐 支持系统 (Supported Systems) - -

- - Ubuntu - - - Debian - - - CentOS - - - alpinelinux - - - Kali - - - Arch - - - RedHat - - - Fedora - - - almalinux - - - Rocky - +

+ 快速开始 · + 核心能力 · + 常用命令 · + KPanel · + 支持系统 · + 项目文档

+## 项目介绍 + +科技lion一键脚本是一套面向 Linux 服务器的交互式运维工具箱。它将常用系统操作、 +Docker 管理、网站搭建、应用部署、网络测试和数据维护集中到统一菜单,并提供 `k` +快捷命令,适合新手快速使用,也方便熟悉 SSH 的用户提高日常运维效率。 + +脚本直接读取和管理宿主机真实资源。通过脚本、SSH、Docker Compose 或 +[KPanel](https://github.com/kejilion/KPanel) 创建的资源,可以继续由其他入口发现和管理。 +## 快速开始 -

+使用 `root` 用户执行。 + +### 中文版 -## 🚀 一键安装 (One-Click Installation) CN ```bash bash <(curl -sL kejilion.sh) ``` -## 🚀 一键安装 (One-Click Installation) EN +### English + ```bash bash <(curl -sL kejilion.sh) en ``` -

+首次运行后可按提示设置快捷命令。后续输入 `k` 即可打开主菜单。 -## 🖼️ 效果图预览 (Preview) -

- 中文版 - English Version -

+> [!IMPORTANT] +> 脚本包含软件安装、网络配置、防火墙、磁盘和网站环境等系统级操作。 +> 请确认服务器数据已备份,并在执行前阅读终端中的影响范围和确认提示。 + +## 核心能力 +- **系统信息与维护**:查看 CPU、内存、磁盘、负载、网络和流量,管理更新、清理、 + 时区、Swap、DNS、软件源、SSH、用户及常用系统服务。 +- **Docker 管理**:安装 Docker,管理容器、镜像、网络和存储卷,查看日志与资源状态, + 并提供备份、还原和迁移能力。 +- **LDNMP 与网站管理**:部署 Nginx、MySQL、PHP、Redis,创建 WordPress、静态站、 + PHP 站、反向代理、负载均衡和常见建站程序。 +- **网站防护与优化**:提供 Fail2Ban、WAF、防火墙、CC 防护、性能优化、缓存清理、 + 证书管理和环境更新。 +- **应用市场**:集中安装和管理常用面板、网盘、监控、AI、开发、媒体和网络工具。 +- **网络与性能测试**:提供测速、回程路由、流媒体解锁、IP 质量、硬件性能和综合测评。 +- **备份与迁移**:支持网站、数据库、Docker 数据和服务器间的数据备份与恢复。 +- **快捷命令**:常用业务可以直接通过 `k` 子命令进入,无需逐级查找菜单。 +## 常用命令 +| 操作 | 命令 | +| --- | --- | +| 打开脚本主菜单 | `k` | +| 查看系统信息 | `k info` | +| Docker 管理 | `k docker` | +| LDNMP 与站点管理 | `k web` | +| 安装 WordPress | `k wp example.com` | +| 创建反向代理 | `k fd example.com` | +| 应用市场 | `k app` | +| 管理指定应用 | `k app 1panel` | +| Fail2Ban 管理 | `k f2b` | +| SSH 密钥管理 | `k sshkey` | +运行脚本内的“命令行帮助”可以查看当前版本支持的完整命令列表。 -

-## 📦 核心功能 (Core Features) +## KPanel Web 管理面板 -- **系统信息概览**:快速展示 CPU、内存、磁盘、带宽等运行状态 - *System status overview: CPU, memory, disk, bandwidth and more*
+如果希望在浏览器中管理服务器,可以通过应用入口一键部署 KPanel: -- **网络测试工具**:集成测速、回程、延迟、丢包检测等 - *Network tools: speed test, route trace, latency, packet loss test*
+```bash +bash <(curl -sL kejilion.sh) app kpanel +``` -- **Docker 容器管理**:独家容器可视化 + 容器控制增强命令 - *Advanced Docker management with enhanced commands and visualization*
+KPanel 是 `kejilion.sh` 的现代 Web 管理形态。脚本、SSH、Compose 和 KPanel +管理的是同一批宿主机真实资源,可在不同入口之间继续发现和管理。 -- **LNMP 一键部署**:轻松搭建 Nginx + MySQL + PHP 站点 - *One-click LNMP stack deployment (Nginx, MySQL, PHP)*
+- [KPanel GitHub 项目](https://github.com/kejilion/KPanel) +- [KPanel 一键部署与功能介绍](https://blog.kejilion.pro/kpanel-kejilion-web-server-panel/) -- **网站防御与优化**:防CC、防爬虫,自动配置防火墙与性能优化 - *Site defense and optimization: anti-CC, anti-crawler, firewall and tuning*
+## 支持系统 -- **备份与迁移**:站点与数据库一键备份/恢复/远程迁移 - *Backup & migration: one-click site/database backup and remote restore*
+脚本持续适配以下 Linux 发行版: -- **BBR 加速优化**:内核加速、网络拥塞控制智能切换 - *Network acceleration: BBR/tcp congestion control optimization*
+- Debian、Ubuntu、Kali Linux +- CentOS、Rocky Linux、AlmaLinux、Red Hat Enterprise Linux、Fedora +- Arch Linux +- Alpine Linux -- **应用市场集成**:内置主流工具与面板,支持一键安装常用服务 - *App Store integration: built-in panels and tools for one-click deployment*
+不同发行版的软件包、网络栈和服务管理方式存在差异,部分功能会根据当前系统能力动态开放。 -- **自动更新机制**:定时检测脚本版本,保持最新最稳定 - *Auto-update engine: ensure you're always running the latest version*
+## 效果图预览 + +

+ 科技lion一键脚本中文版界面 + KejiLion Shell Script English interface +

+## 项目文档 -

+- [脚本更新日志](kejilion_sh_log.txt) +- [应用市场说明](apps/README.md) +- [问题反馈](https://github.com/kejilion/sh/issues) +- [KPanel Web 管理面板](https://github.com/kejilion/KPanel) +- [科技lion官方网站](https://kejilion.sh/) -## 💖 支持我们 (Support Us) -觉得脚本还可以 USTD TRC20 打赏 +## 安全建议 + +- 仅从官方域名和本仓库获取脚本,执行前可先审阅源码。 +- 重要网站、数据库、Docker 数据和系统配置应定期备份。 +- 生产服务器建议先确认命令影响范围,再执行升级、卸载、磁盘或网络相关操作。 +- 提交问题时请隐藏密码、Token、私钥、公网 IP 等敏感信息。 + +## 支持项目 + +如果这个项目对你有帮助,欢迎 Star、提交 Issue 或参与改进。 + +USDT TRC20: + +```text +TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 +``` -Feel free to support us with USTD TRC20 donations. +## 开源许可 -TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 +本项目采用 [Apache License 2.0](LICENSE) 开源。 -

+## Star History -## ⭐ Star History [![Star History Chart](https://api.star-history.com/svg?repos=kejilion/sh&type=Date)](https://star-history.com/#kejilion/sh&Date) From 4864058e12162590e43117d32fe5b6d1394861d4 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 11:09:53 +0800 Subject: [PATCH 1232/1285] Revert "docs: refresh project README" This reverts commit 68328934697ac31d804613d466b2eb08c89fe5b0. --- README.md | 229 ++++++++++++++++++++++++++---------------------------- 1 file changed, 109 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 7d5da2eee..9be65afee 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,152 @@ -

- 科技lion一键脚本工具 -

+


+
+ logo +
-

科技lion一键脚本工具

+
+

KEJILION.SH - 科技lion一键脚本工具

+
-

- 面向 Linux 服务器的综合运维脚本,集成系统管理、Docker、LDNMP 建站、 - 应用市场、网络测试、备份迁移与安全防护。 -

- GitHub Stars - GitHub Forks - Apache-2.0 License - Last Commit + + 简体中文 + + + 繁體中文 + + + English + + + 한국어 + + + 日本語 + + + Русский + + + فارسی +

-

- 简体中文 · - 繁體中文 · - 한국어 · - 日本語 · - Русский · - فارسی -

-

- 快速开始 · - 核心能力 · - 常用命令 · - KPanel · - 支持系统 · - 项目文档 -

- -## 项目介绍 - -科技lion一键脚本是一套面向 Linux 服务器的交互式运维工具箱。它将常用系统操作、 -Docker 管理、网站搭建、应用部署、网络测试和数据维护集中到统一菜单,并提供 `k` -快捷命令,适合新手快速使用,也方便熟悉 SSH 的用户提高日常运维效率。 -脚本直接读取和管理宿主机真实资源。通过脚本、SSH、Docker Compose 或 -[KPanel](https://github.com/kejilion/KPanel) 创建的资源,可以继续由其他入口发现和管理。 +


+ + +## 📜 介绍 (Introduction) +科技Lion 的 Shell 脚本工具是一款全能脚本工具箱,专为 Linux 监控、测试和管理而设计。无论您是初学者还是经验丰富的用户,该工具都能为您提供便捷的解决方案。集成了独创的 Docker 管理功能,让您轻松管理容器化应用;LNMP建站解决方案能帮助您快速搭建网站,站点优化、防御、备份还原迁移一应俱全;并且整合了各类系统工具面板的安装及使用,使系统维护变得更加简单。我们的目标是成为全网最优秀的 Linux 一键脚本工具,为用户提供高效、便捷的科技支持。 + +KejiLion's Shell script tool is an all-in-one script toolbox designed for Linux monitoring, testing, and management. Whether you are a beginner or an experienced user, this tool offers convenient solutions. It integrates unique Docker management features, enabling easy containerized application management. The LNMP site-building solution helps you quickly set up websites, covering optimization, defense, backup, restoration, and migration. It also includes the installation and use of various system tool panels, making system maintenance simpler. Our goal is to become the best Linux one-click script tool on the internet, providing users with efficient and convenient tech support. + +

+ + +## 🌐 支持系统 (Supported Systems) + +

+ + Ubuntu + + + Debian + + + CentOS + + + alpinelinux + + + Kali + + + Arch + + + RedHat + + + Fedora + + + almalinux + + + Rocky + +

-## 快速开始 -使用 `root` 用户执行。 -### 中文版 +

+## 🚀 一键安装 (One-Click Installation) CN ```bash bash <(curl -sL kejilion.sh) ``` -### English - +## 🚀 一键安装 (One-Click Installation) EN ```bash bash <(curl -sL kejilion.sh) en ``` -首次运行后可按提示设置快捷命令。后续输入 `k` 即可打开主菜单。 - -> [!IMPORTANT] -> 脚本包含软件安装、网络配置、防火墙、磁盘和网站环境等系统级操作。 -> 请确认服务器数据已备份,并在执行前阅读终端中的影响范围和确认提示。 +

-## 核心能力 - -- **系统信息与维护**:查看 CPU、内存、磁盘、负载、网络和流量,管理更新、清理、 - 时区、Swap、DNS、软件源、SSH、用户及常用系统服务。 -- **Docker 管理**:安装 Docker,管理容器、镜像、网络和存储卷,查看日志与资源状态, - 并提供备份、还原和迁移能力。 -- **LDNMP 与网站管理**:部署 Nginx、MySQL、PHP、Redis,创建 WordPress、静态站、 - PHP 站、反向代理、负载均衡和常见建站程序。 -- **网站防护与优化**:提供 Fail2Ban、WAF、防火墙、CC 防护、性能优化、缓存清理、 - 证书管理和环境更新。 -- **应用市场**:集中安装和管理常用面板、网盘、监控、AI、开发、媒体和网络工具。 -- **网络与性能测试**:提供测速、回程路由、流媒体解锁、IP 质量、硬件性能和综合测评。 -- **备份与迁移**:支持网站、数据库、Docker 数据和服务器间的数据备份与恢复。 -- **快捷命令**:常用业务可以直接通过 `k` 子命令进入,无需逐级查找菜单。 - -## 常用命令 - -| 操作 | 命令 | -| --- | --- | -| 打开脚本主菜单 | `k` | -| 查看系统信息 | `k info` | -| Docker 管理 | `k docker` | -| LDNMP 与站点管理 | `k web` | -| 安装 WordPress | `k wp example.com` | -| 创建反向代理 | `k fd example.com` | -| 应用市场 | `k app` | -| 管理指定应用 | `k app 1panel` | -| Fail2Ban 管理 | `k f2b` | -| SSH 密钥管理 | `k sshkey` | - -运行脚本内的“命令行帮助”可以查看当前版本支持的完整命令列表。 - -## KPanel Web 管理面板 - -如果希望在浏览器中管理服务器,可以通过应用入口一键部署 KPanel: +## 🖼️ 效果图预览 (Preview) +

+ 中文版 + English Version +

-```bash -bash <(curl -sL kejilion.sh) app kpanel -``` -KPanel 是 `kejilion.sh` 的现代 Web 管理形态。脚本、SSH、Compose 和 KPanel -管理的是同一批宿主机真实资源,可在不同入口之间继续发现和管理。 -- [KPanel GitHub 项目](https://github.com/kejilion/KPanel) -- [KPanel 一键部署与功能介绍](https://blog.kejilion.pro/kpanel-kejilion-web-server-panel/) -## 支持系统 -脚本持续适配以下 Linux 发行版: +

+## 📦 核心功能 (Core Features) -- Debian、Ubuntu、Kali Linux -- CentOS、Rocky Linux、AlmaLinux、Red Hat Enterprise Linux、Fedora -- Arch Linux -- Alpine Linux +- **系统信息概览**:快速展示 CPU、内存、磁盘、带宽等运行状态 + *System status overview: CPU, memory, disk, bandwidth and more*
-不同发行版的软件包、网络栈和服务管理方式存在差异,部分功能会根据当前系统能力动态开放。 +- **网络测试工具**:集成测速、回程、延迟、丢包检测等 + *Network tools: speed test, route trace, latency, packet loss test*
-## 效果图预览 +- **Docker 容器管理**:独家容器可视化 + 容器控制增强命令 + *Advanced Docker management with enhanced commands and visualization*
-

- 科技lion一键脚本中文版界面 - KejiLion Shell Script English interface -

+- **LNMP 一键部署**:轻松搭建 Nginx + MySQL + PHP 站点 + *One-click LNMP stack deployment (Nginx, MySQL, PHP)*
-## 项目文档 +- **网站防御与优化**:防CC、防爬虫,自动配置防火墙与性能优化 + *Site defense and optimization: anti-CC, anti-crawler, firewall and tuning*
-- [脚本更新日志](kejilion_sh_log.txt) -- [应用市场说明](apps/README.md) -- [问题反馈](https://github.com/kejilion/sh/issues) -- [KPanel Web 管理面板](https://github.com/kejilion/KPanel) -- [科技lion官方网站](https://kejilion.sh/) +- **备份与迁移**:站点与数据库一键备份/恢复/远程迁移 + *Backup & migration: one-click site/database backup and remote restore*
-## 安全建议 +- **BBR 加速优化**:内核加速、网络拥塞控制智能切换 + *Network acceleration: BBR/tcp congestion control optimization*
-- 仅从官方域名和本仓库获取脚本,执行前可先审阅源码。 -- 重要网站、数据库、Docker 数据和系统配置应定期备份。 -- 生产服务器建议先确认命令影响范围,再执行升级、卸载、磁盘或网络相关操作。 -- 提交问题时请隐藏密码、Token、私钥、公网 IP 等敏感信息。 +- **应用市场集成**:内置主流工具与面板,支持一键安装常用服务 + *App Store integration: built-in panels and tools for one-click deployment*
-## 支持项目 +- **自动更新机制**:定时检测脚本版本,保持最新最稳定 + *Auto-update engine: ensure you're always running the latest version*
-如果这个项目对你有帮助,欢迎 Star、提交 Issue 或参与改进。 -USDT TRC20: +

-```text -TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 -``` +## 💖 支持我们 (Support Us) +觉得脚本还可以 USTD TRC20 打赏 -## 开源许可 +Feel free to support us with USTD TRC20 donations. -本项目采用 [Apache License 2.0](LICENSE) 开源。 +TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 -## Star History +

+## ⭐ Star History [![Star History Chart](https://api.star-history.com/svg?repos=kejilion/sh&type=Date)](https://star-history.com/#kejilion/sh&Date) From 689d622caa6f8938d36afe72823fc5e0b815fbb4 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 11:19:18 +0800 Subject: [PATCH 1233/1285] docs: align README with KPanel layout --- README.md | 227 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 118 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 9be65afee..9e8d66dfc 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,161 @@ -


-
- logo -
- -
-

KEJILION.SH - 科技lion一键脚本工具

-
+

+ KEJILION.SH 科技lion一键脚本工具 +

+

KEJILION.SH · 科技lion一键脚本工具

- - 简体中文 - - - 繁體中文 - - - English - - - 한국어 - - - 日本語 - - - Русский - - - فارسی - + 面向 Linux 服务器的综合脚本工具箱,集成系统管理、网络测试、Docker、LDNMP 建站、 + 应用市场、备份迁移与安全防护。

+

+ GitHub Stars + GitHub Forks + Last Commit + Apache-2.0 License +

+

+ 简体中文 + 繁體中文 + English + 한국어 + 日本語 + Русский + فارسی +

-


- - -## 📜 介绍 (Introduction) -科技Lion 的 Shell 脚本工具是一款全能脚本工具箱,专为 Linux 监控、测试和管理而设计。无论您是初学者还是经验丰富的用户,该工具都能为您提供便捷的解决方案。集成了独创的 Docker 管理功能,让您轻松管理容器化应用;LNMP建站解决方案能帮助您快速搭建网站,站点优化、防御、备份还原迁移一应俱全;并且整合了各类系统工具面板的安装及使用,使系统维护变得更加简单。我们的目标是成为全网最优秀的 Linux 一键脚本工具,为用户提供高效、便捷的科技支持。 - -KejiLion's Shell script tool is an all-in-one script toolbox designed for Linux monitoring, testing, and management. Whether you are a beginner or an experienced user, this tool offers convenient solutions. It integrates unique Docker management features, enabling easy containerized application management. The LNMP site-building solution helps you quickly set up websites, covering optimization, defense, backup, restoration, and migration. It also includes the installation and use of various system tool panels, making system maintenance simpler. Our goal is to become the best Linux one-click script tool on the internet, providing users with efficient and convenient tech support. - -

- - -## 🌐 支持系统 (Supported Systems) - -

- - Ubuntu - - - Debian - - - CentOS - - - alpinelinux - - - Kali - - - Arch - - - RedHat - - - Fedora - - - almalinux - - - Rocky - +

+ 介绍 · + 一键安装 · + 支持系统 · + 效果图预览 · + 核心功能 · + KPanel · + 开源许可

+## 介绍 + +科技Lion 的 Shell 脚本工具是一款全能脚本工具箱,专为 Linux 监控、测试和管理而设计。 +无论您是初学者还是经验丰富的用户,该工具都能提供便捷的解决方案。脚本集成 Docker +管理、LDNMP 建站、网站优化与防御、备份还原迁移,以及各类系统工具和应用的安装管理, +让服务器维护更加简单。 + +KejiLion's Shell script is an all-in-one toolbox designed for Linux monitoring, testing, and +server management. It brings together Docker management, LDNMP website deployment, optimization, +protection, backup, restoration, migration, and common server applications in one interactive tool. + +## 一键安装 +使用 `root` 用户执行以下命令。 -

+### 中文版 -## 🚀 一键安装 (One-Click Installation) CN ```bash bash <(curl -sL kejilion.sh) ``` -## 🚀 一键安装 (One-Click Installation) EN +### English Version + ```bash bash <(curl -sL kejilion.sh) en ``` -

+首次运行后可按脚本提示设置 `k` 快捷命令,后续直接输入 `k` 即可打开主菜单。 -## 🖼️ 效果图预览 (Preview) -

- 中文版 - English Version -

+> [!IMPORTANT] +> 脚本包含软件安装、网络、防火墙、磁盘和网站环境等系统级操作。 +> 请在执行前阅读终端提示,并提前备份重要网站、数据库、容器和配置。 +## 支持系统 +

+ Ubuntu + Debian + CentOS + Alpine Linux + Kali Linux + Arch Linux + Red Hat + Fedora + AlmaLinux + Rocky Linux +

+不同发行版的软件包、网络栈和服务管理方式存在差异,脚本会根据当前系统能力开放对应功能。 +## 效果图预览 -

-## 📦 核心功能 (Core Features) +

+ 科技lion一键脚本中文版 + KejiLion Shell Script English Version +

-- **系统信息概览**:快速展示 CPU、内存、磁盘、带宽等运行状态 - *System status overview: CPU, memory, disk, bandwidth and more*
+## 核心功能 + +- **系统信息概览**:快速展示 CPU、内存、磁盘、带宽等运行状态。
+ *System status overview: CPU, memory, disk, bandwidth, and more.* +- **网络测试工具**:集成测速、回程、延迟、丢包检测等工具。
+ *Network tools: speed tests, route tracing, latency, and packet loss tests.* +- **Docker 容器管理**:提供容器、镜像、网络、存储卷和日志管理。
+ *Docker management for containers, images, networks, volumes, and logs.* +- **LDNMP 一键部署**:快速搭建 Nginx、MySQL、PHP、Redis 网站环境。
+ *One-click LDNMP stack deployment for Nginx, MySQL, PHP, and Redis.* +- **网站防御与优化**:提供 CC 防护、防爬虫、防火墙和性能优化。
+ *Website protection and optimization with anti-CC, anti-crawler, firewall, and tuning tools.* +- **备份与迁移**:支持站点和数据库备份、恢复与远程迁移。
+ *Backup and migration for websites, databases, restoration, and remote transfer.* +- **BBR 加速优化**:管理内核加速与网络拥塞控制算法。
+ *Network acceleration and TCP congestion control optimization.* +- **应用市场集成**:一键安装和管理常用面板、服务与应用。
+ *App market integration for one-click deployment and management.* +- **自动更新机制**:检测脚本版本并提供更新入口。
+ *Update detection keeps the script features current.* + +## KPanel Web 管理面板 + +偏好浏览器操作时,可以通过 `kejilion.sh` 应用入口一键部署 KPanel: -- **网络测试工具**:集成测速、回程、延迟、丢包检测等 - *Network tools: speed test, route trace, latency, packet loss test*
+```bash +bash <(curl -sL kejilion.sh) app kpanel +``` -- **Docker 容器管理**:独家容器可视化 + 容器控制增强命令 - *Advanced Docker management with enhanced commands and visualization*
+KPanel 是 `kejilion.sh` 的现代 Web 管理形态。脚本、SSH、Docker Compose 和 KPanel +创建的真实资源可以互相发现并继续管理。 -- **LNMP 一键部署**:轻松搭建 Nginx + MySQL + PHP 站点 - *One-click LNMP stack deployment (Nginx, MySQL, PHP)*
+- [KPanel GitHub 项目](https://github.com/kejilion/KPanel) +- [KPanel 一键部署与功能介绍](https://blog.kejilion.pro/kpanel-kejilion-web-server-panel/) -- **网站防御与优化**:防CC、防爬虫,自动配置防火墙与性能优化 - *Site defense and optimization: anti-CC, anti-crawler, firewall and tuning*
+## 项目文档 -- **备份与迁移**:站点与数据库一键备份/恢复/远程迁移 - *Backup & migration: one-click site/database backup and remote restore*
+- [脚本更新日志](kejilion_sh_log.txt) +- [应用市场说明](apps/README.md) +- [问题反馈](https://github.com/kejilion/sh/issues) +- [科技lion官方网站](https://kejilion.sh/) -- **BBR 加速优化**:内核加速、网络拥塞控制智能切换 - *Network acceleration: BBR/tcp congestion control optimization*
+## 使用与安全 -- **应用市场集成**:内置主流工具与面板,支持一键安装常用服务 - *App Store integration: built-in panels and tools for one-click deployment*
+- 仅从官方域名和本仓库获取脚本,执行前可先审阅源码。 +- 重要网站、数据库、Docker 数据和系统配置应定期备份。 +- 生产服务器执行升级、卸载、磁盘或网络操作前,应确认终端显示的影响范围。 +- 提交问题时,请隐藏密码、Token、私钥和公网 IP 等敏感信息。 -- **自动更新机制**:定时检测脚本版本,保持最新最稳定 - *Auto-update engine: ensure you're always running the latest version*
+## 支持我们 +觉得脚本还可以,欢迎 Star、反馈问题或参与改进。 -

+Feel free to support the project with USDT TRC20: -## 💖 支持我们 (Support Us) -觉得脚本还可以 USTD TRC20 打赏 +```text +TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 +``` -Feel free to support us with USTD TRC20 donations. +## 开源许可 -TCP3PLGUTG9Z4z4tnHHSLbw5bgp8NXhTT3 +本项目采用 [Apache License 2.0](LICENSE) 开源。 -

+## Star History -## ⭐ Star History [![Star History Chart](https://api.star-history.com/svg?repos=kejilion/sh&type=Date)](https://star-history.com/#kejilion/sh&Date) From f031d1206224de3743845d2fc81c4801ecda32f4 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 29 Jul 2026 12:37:37 +0800 Subject: [PATCH 1234/1285] feat(kpanel): expose interactive site recipes --- kejilion.sh | 40 ++++++++++++++++++- tests/test_kpanel_web_noninteractive_smoke.sh | 14 +++++-- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 281457290..746300684 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -10147,6 +10147,13 @@ kpanel_run_web_recipe_cli() { return "$rc" } +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + kpanel_ldnmp_escape() { local value="${1:-}" value=${value//\\/\\\\}; value=${value//\"/\\\"} @@ -10715,7 +10722,7 @@ linux_ldnmp() { if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then sub_choice="${KJ_WEB_RECIPE:-}" case "$sub_choice" in - 2|3|4|5|6|7|8|9|23|27) ;; + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; *) echo "KPANEL_PROGRESS 100 不支持的 KJ_WEB_RECIPE" return 1 @@ -11726,7 +11733,8 @@ linux_ldnmp() { echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" return 1 fi - if [ "$sub_choice" != "23" ] && [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" return 1 fi @@ -23769,6 +23777,34 @@ else shift kpanel_run_web_recipe_cli 27 "$@" ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" + ;; fd|rp|反代) shift ldnmp_Proxy "$@" diff --git a/tests/test_kpanel_web_noninteractive_smoke.sh b/tests/test_kpanel_web_noninteractive_smoke.sh index 4ed7faab5..ea80c6ffb 100644 --- a/tests/test_kpanel_web_noninteractive_smoke.sh +++ b/tests/test_kpanel_web_noninteractive_smoke.sh @@ -22,10 +22,10 @@ recipe_case="$( capture && /不支持的 KJ_WEB_RECIPE/ { exit } ' "${script_path}" )" -for selector in 2 3 4 5 6 7 8 9 23 27; do +for selector in 2 3 4 5 6 7 8 9 20 22 23 24 25 26 27 28 30; do printf '%s\n' "${recipe_case}" | grep -E "(^|[[:space:]|])${selector}([|)])" >/dev/null done -if printf '%s\n' "${recipe_case}" | grep -E '(^|[[:space:]|])(20|22|24|29|30|34|38)([|)])' >/dev/null; then +if printf '%s\n' "${recipe_case}" | grep -E '(^|[[:space:]|])(21|29|31|32|33|34|35|36|37|38)([|)])' >/dev/null; then printf '%s\n' "unsafe or interactive recipe selector was exposed to KPanel" >&2 exit 1 fi @@ -34,7 +34,8 @@ grep -F 'ldnmp_wp "${KJ_WEB_DOMAIN:-}"' "${script_path}" >/dev/null grep -F 'ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}"' "${script_path}" >/dev/null grep -F 'KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名' "${script_path}" >/dev/null grep -F 'KJ_WEB_PROXY_PORT 不是有效端口' "${script_path}" >/dev/null -grep -F 'if [ "$sub_choice" != "23" ] && [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then' "${script_path}" >/dev/null +grep -F 'kpanel_web_recipe_requires_document_root()' "${script_path}" >/dev/null +grep -F 'if kpanel_web_recipe_requires_document_root "$sub_choice" &&' "${script_path}" >/dev/null grep -F 'web_del "$@"' "${script_path}" >/dev/null grep -F 'KPANEL_DELETE_SITE deleted $yuming' "${script_path}" >/dev/null grep -F 'KPANEL_DELETE_DATABASE dropped $yuming' "${script_path}" >/dev/null @@ -42,5 +43,12 @@ grep -F 'rm -rf -- "/home/web/html/$yuming"' "${script_path}" >/dev/null grep -F 'kpanel_run_web_recipe_cli()' "${script_path}" >/dev/null grep -F 'kpanel_run_web_recipe_cli 3 "$@"' "${script_path}" >/dev/null grep -F 'kpanel_run_web_recipe_cli 27 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 20 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 22 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 24 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 25 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 26 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 28 "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_run_web_recipe_cli 30 "$@"' "${script_path}" >/dev/null grep -F 'ldnmp_wp "$@"' "${script_path}" >/dev/null grep -F 'ldnmp_Proxy "$@"' "${script_path}" >/dev/null From 5fb03154a3728c4528d6fc93337bde8083cc6af2 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 03:59:39 +0800 Subject: [PATCH 1235/1285] fix(ldnmp): normalize new site permissions --- cn/kejilion.sh | 69 +++++++++++++---- kejilion.sh | 69 +++++++++++++---- tests/test_ldnmp_site_permissions_smoke.sh | 87 ++++++++++++++++++++++ 3 files changed, 199 insertions(+), 26 deletions(-) create mode 100644 tests/test_ldnmp_site_permissions_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a6008334e..f9e052b26 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1676,6 +1676,39 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "无效的站点目录名称: $site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + install -d -m 0755 -- "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "站点目录不存在: $site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -3475,7 +3508,7 @@ ldnmp_wp() { cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +3522,8 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -9132,7 +9167,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9141,6 +9176,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9175,13 +9211,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9216,7 +9253,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9225,6 +9262,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9265,10 +9303,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9321,7 +9360,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9343,6 +9382,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9380,12 +9420,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9423,12 +9464,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9461,7 +9503,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9560,6 +9602,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9700,14 +9743,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9742,7 +9785,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9770,7 +9813,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on diff --git a/kejilion.sh b/kejilion.sh index 746300684..886151e36 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1708,6 +1708,39 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "无效的站点目录名称: $site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + install -d -m 0755 -- "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "站点目录不存在: $site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -4102,7 +4135,7 @@ ldnmp_wp() { kpanel_web_progress 75 "正在获取并配置 kejilion.sh WordPress 源码" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -4117,6 +4150,8 @@ ldnmp_wp() { kpanel_web_progress 90 "正在重启 LDNMP 并核验 WordPress 站点" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -10788,7 +10823,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -10797,6 +10832,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10831,13 +10867,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -10872,7 +10909,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -10881,6 +10918,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10921,10 +10959,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10977,7 +11016,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -10999,6 +11038,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11036,12 +11076,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11079,12 +11120,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11117,7 +11159,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -11216,6 +11258,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -11356,14 +11399,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -11398,7 +11441,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -11426,7 +11469,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on diff --git a/tests/test_ldnmp_site_permissions_smoke.sh b/tests/test_ldnmp_site_permissions_smoke.sh new file mode 100644 index 000000000..800a03c8d --- /dev/null +++ b/tests/test_ldnmp_site_permissions_smoke.sh @@ -0,0 +1,87 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +scripts=( + "${project_root}/kejilion.sh" + "${project_root}/cn/kejilion.sh" +) + +extract_function() { + local function_name="$1" + local script_path="$2" + awk -v signature="${function_name}() {" ' + $0 == signature { capture=1 } + capture { + print + line=$0 + opens=gsub(/{/, "{", line) + closes=gsub(/}/, "}", line) + depth += opens - closes + if (depth == 0) { + exit + } + } + ' "${script_path}" +} + +for script_path in "${scripts[@]}"; do + bash -n "${script_path}" + + prepare_count="$(grep -Fc 'prepare_ldnmp_site_root "$yuming" || return 1' "${script_path}")" + normalize_count="$(grep -Fc 'normalize_ldnmp_site_permissions "$yuming" || return 1' "${script_path}")" + [ "${prepare_count}" -eq 11 ] + [ "${normalize_count}" -eq 11 ] + + if grep -F 'mkdir $yuming' "${script_path}" >/dev/null; then + printf '%s\n' "unsafe umask-dependent site directory creation remains in ${script_path}" >&2 + exit 1 + fi + if grep -F 'chmod -R nginx:nginx' "${script_path}" >/dev/null; then + printf '%s\n' "invalid chmod owner syntax remains in ${script_path}" >&2 + exit 1 + fi + + test_root="$(mktemp -d)" + ( + eval "$(extract_function ldnmp_site_domain_is_safe "${script_path}")" + eval "$(extract_function prepare_ldnmp_site_root "${script_path}")" + eval "$(extract_function normalize_ldnmp_site_permissions "${script_path}")" + + ldnmp_web_root_base="${test_root}/html" + umask 0077 + prepare_ldnmp_site_root "wp.example.test" + mkdir -p "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes" + printf '%s\n' "body {}" > "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css" + printf '%s\n' "#!/bin/sh" > "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test")" = "755" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "700" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "600" ] + + normalize_ldnmp_site_permissions "wp.example.test" + + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "755" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "644" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh")" = "755" ] + + if prepare_ldnmp_site_root "../escape"; then + printf '%s\n' "path traversal domain was accepted by ${script_path}" >&2 + exit 1 + fi + [ ! -e "${test_root}/escape" ] + ) + rm -rf -- "${test_root}" +done + +for function_name in ldnmp_site_domain_is_safe prepare_ldnmp_site_root normalize_ldnmp_site_permissions; do + cmp \ + <(extract_function "${function_name}" "${scripts[0]}") \ + <(extract_function "${function_name}" "${scripts[1]}") +done + +grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[0]}" >/dev/null +grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[1]}" >/dev/null + +printf '%s\n' "LDNMP site permission smoke tests passed" From 4174a8350c823ba2c86dacb60852f1a0f9a23695 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 12:31:01 +0800 Subject: [PATCH 1236/1285] fix(ldnmp): avoid shadowed install helper --- cn/kejilion.sh | 3 ++- kejilion.sh | 3 ++- tests/test_ldnmp_site_permissions_smoke.sh | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index f9e052b26..6a4ab1554 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1691,7 +1691,8 @@ ldnmp_site_domain_is_safe() { prepare_ldnmp_site_root() { local site_domain="${1:-}" ldnmp_site_domain_is_safe "$site_domain" || return 1 - install -d -m 0755 -- "${ldnmp_web_root_base}/${site_domain}" + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "${ldnmp_web_root_base}/${site_domain}" } normalize_ldnmp_site_permissions() { diff --git a/kejilion.sh b/kejilion.sh index 886151e36..f31390fae 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1723,7 +1723,8 @@ ldnmp_site_domain_is_safe() { prepare_ldnmp_site_root() { local site_domain="${1:-}" ldnmp_site_domain_is_safe "$site_domain" || return 1 - install -d -m 0755 -- "${ldnmp_web_root_base}/${site_domain}" + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "${ldnmp_web_root_base}/${site_domain}" } normalize_ldnmp_site_permissions() { diff --git a/tests/test_ldnmp_site_permissions_smoke.sh b/tests/test_ldnmp_site_permissions_smoke.sh index 800a03c8d..2ddfcd903 100644 --- a/tests/test_ldnmp_site_permissions_smoke.sh +++ b/tests/test_ldnmp_site_permissions_smoke.sh @@ -49,12 +49,24 @@ for script_path in "${scripts[@]}"; do eval "$(extract_function normalize_ldnmp_site_permissions "${script_path}")" ldnmp_web_root_base="${test_root}/html" + install() { + printf '%s\n' "shadowed install() must not be called" >&2 + return 97 + } + mkdir() { + printf '%s\n' "shadowed mkdir() must not be called" >&2 + return 98 + } + chmod() { + printf '%s\n' "shadowed chmod() must not be called" >&2 + return 99 + } umask 0077 prepare_ldnmp_site_root "wp.example.test" - mkdir -p "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes" + command mkdir -p "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes" printf '%s\n' "body {}" > "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css" printf '%s\n' "#!/bin/sh" > "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" - chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + command chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test")" = "755" ] [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "700" ] From 84e2e9c86de039c50291baf2ed348bcc93a642c5 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 12:39:09 +0800 Subject: [PATCH 1237/1285] fix(ldnmp): expose web mount root --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- tests/test_ldnmp_site_permissions_smoke.sh | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6a4ab1554..9a5931e6e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1692,7 +1692,7 @@ prepare_ldnmp_site_root() { local site_domain="${1:-}" ldnmp_site_domain_is_safe "$site_domain" || return 1 command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && - command chmod 0755 -- "${ldnmp_web_root_base}/${site_domain}" + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" } normalize_ldnmp_site_permissions() { diff --git a/kejilion.sh b/kejilion.sh index f31390fae..68d3ff775 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1724,7 +1724,7 @@ prepare_ldnmp_site_root() { local site_domain="${1:-}" ldnmp_site_domain_is_safe "$site_domain" || return 1 command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && - command chmod 0755 -- "${ldnmp_web_root_base}/${site_domain}" + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" } normalize_ldnmp_site_permissions() { diff --git a/tests/test_ldnmp_site_permissions_smoke.sh b/tests/test_ldnmp_site_permissions_smoke.sh index 2ddfcd903..6ebe77ec5 100644 --- a/tests/test_ldnmp_site_permissions_smoke.sh +++ b/tests/test_ldnmp_site_permissions_smoke.sh @@ -68,6 +68,7 @@ for script_path in "${scripts[@]}"; do printf '%s\n' "#!/bin/sh" > "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" command chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + [ "$(stat -c '%a' "${ldnmp_web_root_base}")" = "755" ] [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test")" = "755" ] [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "700" ] [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "600" ] From e46c61602d470b835d84af78e0aaad22e7609415 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 12:40:51 +0800 Subject: [PATCH 1238/1285] revert: restore repository to f031d12 --- cn/kejilion.sh | 70 +++------------ kejilion.sh | 70 +++------------ tests/test_ldnmp_site_permissions_smoke.sh | 100 --------------------- 3 files changed, 26 insertions(+), 214 deletions(-) delete mode 100644 tests/test_ldnmp_site_permissions_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9a5931e6e..a6008334e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1676,40 +1676,6 @@ add_db() { } -ldnmp_web_root_base="/home/web/html" - -ldnmp_site_domain_is_safe() { - local site_domain="${1:-}" - case "$site_domain" in - ""|"."|".."|*/*) - echo "无效的站点目录名称: $site_domain" >&2 - return 1 - ;; - esac -} - -prepare_ldnmp_site_root() { - local site_domain="${1:-}" - ldnmp_site_domain_is_safe "$site_domain" || return 1 - command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && - command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" -} - -normalize_ldnmp_site_permissions() { - local site_domain="${1:-}" - local site_root - ldnmp_site_domain_is_safe "$site_domain" || return 1 - site_root="${ldnmp_web_root_base}/${site_domain}" - [ -d "$site_root" ] || { - echo "站点目录不存在: $site_root" >&2 - return 1 - } - - find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && - find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -3509,7 +3475,7 @@ ldnmp_wp() { cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3523,8 +3489,6 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php - normalize_ldnmp_site_permissions "$yuming" || return 1 - chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -9168,7 +9132,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9177,7 +9141,6 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9212,14 +9175,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9254,7 +9216,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9263,7 +9225,6 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9304,11 +9265,10 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9361,7 +9321,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9383,7 +9343,6 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9421,13 +9380,12 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9465,13 +9423,12 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9504,7 +9461,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming clear @@ -9603,7 +9560,6 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9744,14 +9700,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - normalize_ldnmp_site_permissions "$yuming" || return 1 + docker exec nginx chmod -R nginx:nginx /var/www/html docker exec nginx nginx -s reload nginx_web_on @@ -9786,7 +9742,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming @@ -9814,7 +9770,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - normalize_ldnmp_site_permissions "$yuming" || return 1 + docker exec nginx chmod -R nginx:nginx /var/www/html docker exec nginx nginx -s reload nginx_web_on diff --git a/kejilion.sh b/kejilion.sh index 68d3ff775..746300684 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1708,40 +1708,6 @@ add_db() { } -ldnmp_web_root_base="/home/web/html" - -ldnmp_site_domain_is_safe() { - local site_domain="${1:-}" - case "$site_domain" in - ""|"."|".."|*/*) - echo "无效的站点目录名称: $site_domain" >&2 - return 1 - ;; - esac -} - -prepare_ldnmp_site_root() { - local site_domain="${1:-}" - ldnmp_site_domain_is_safe "$site_domain" || return 1 - command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && - command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" -} - -normalize_ldnmp_site_permissions() { - local site_domain="${1:-}" - local site_root - ldnmp_site_domain_is_safe "$site_domain" || return 1 - site_root="${ldnmp_web_root_base}/${site_domain}" - [ -d "$site_root" ] || { - echo "站点目录不存在: $site_root" >&2 - return 1 - } - - find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && - find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + -} - - restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -4136,7 +4102,7 @@ ldnmp_wp() { kpanel_web_progress 75 "正在获取并配置 kejilion.sh WordPress 源码" cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -4151,8 +4117,6 @@ ldnmp_wp() { kpanel_web_progress 90 "正在重启 LDNMP 并核验 WordPress 站点" - normalize_ldnmp_site_permissions "$yuming" || return 1 - chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -10824,7 +10788,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -10833,7 +10797,6 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10868,14 +10831,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -10910,7 +10872,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -10919,7 +10881,6 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10960,11 +10921,10 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11017,7 +10977,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -11039,7 +10999,6 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11077,13 +11036,12 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11121,13 +11079,12 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11160,7 +11117,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming clear @@ -11259,7 +11216,6 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini - normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -11400,14 +11356,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - normalize_ldnmp_site_permissions "$yuming" || return 1 + docker exec nginx chmod -R nginx:nginx /var/www/html docker exec nginx nginx -s reload nginx_web_on @@ -11442,7 +11398,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - prepare_ldnmp_site_root "$yuming" || return 1 + mkdir $yuming cd $yuming @@ -11470,7 +11426,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - normalize_ldnmp_site_permissions "$yuming" || return 1 + docker exec nginx chmod -R nginx:nginx /var/www/html docker exec nginx nginx -s reload nginx_web_on diff --git a/tests/test_ldnmp_site_permissions_smoke.sh b/tests/test_ldnmp_site_permissions_smoke.sh deleted file mode 100644 index 6ebe77ec5..000000000 --- a/tests/test_ldnmp_site_permissions_smoke.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash -set -euo pipefail - -project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -scripts=( - "${project_root}/kejilion.sh" - "${project_root}/cn/kejilion.sh" -) - -extract_function() { - local function_name="$1" - local script_path="$2" - awk -v signature="${function_name}() {" ' - $0 == signature { capture=1 } - capture { - print - line=$0 - opens=gsub(/{/, "{", line) - closes=gsub(/}/, "}", line) - depth += opens - closes - if (depth == 0) { - exit - } - } - ' "${script_path}" -} - -for script_path in "${scripts[@]}"; do - bash -n "${script_path}" - - prepare_count="$(grep -Fc 'prepare_ldnmp_site_root "$yuming" || return 1' "${script_path}")" - normalize_count="$(grep -Fc 'normalize_ldnmp_site_permissions "$yuming" || return 1' "${script_path}")" - [ "${prepare_count}" -eq 11 ] - [ "${normalize_count}" -eq 11 ] - - if grep -F 'mkdir $yuming' "${script_path}" >/dev/null; then - printf '%s\n' "unsafe umask-dependent site directory creation remains in ${script_path}" >&2 - exit 1 - fi - if grep -F 'chmod -R nginx:nginx' "${script_path}" >/dev/null; then - printf '%s\n' "invalid chmod owner syntax remains in ${script_path}" >&2 - exit 1 - fi - - test_root="$(mktemp -d)" - ( - eval "$(extract_function ldnmp_site_domain_is_safe "${script_path}")" - eval "$(extract_function prepare_ldnmp_site_root "${script_path}")" - eval "$(extract_function normalize_ldnmp_site_permissions "${script_path}")" - - ldnmp_web_root_base="${test_root}/html" - install() { - printf '%s\n' "shadowed install() must not be called" >&2 - return 97 - } - mkdir() { - printf '%s\n' "shadowed mkdir() must not be called" >&2 - return 98 - } - chmod() { - printf '%s\n' "shadowed chmod() must not be called" >&2 - return 99 - } - umask 0077 - prepare_ldnmp_site_root "wp.example.test" - command mkdir -p "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes" - printf '%s\n' "body {}" > "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css" - printf '%s\n' "#!/bin/sh" > "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" - command chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" - - [ "$(stat -c '%a' "${ldnmp_web_root_base}")" = "755" ] - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test")" = "755" ] - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "700" ] - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "600" ] - - normalize_ldnmp_site_permissions "wp.example.test" - - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "755" ] - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "644" ] - [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh")" = "755" ] - - if prepare_ldnmp_site_root "../escape"; then - printf '%s\n' "path traversal domain was accepted by ${script_path}" >&2 - exit 1 - fi - [ ! -e "${test_root}/escape" ] - ) - rm -rf -- "${test_root}" -done - -for function_name in ldnmp_site_domain_is_safe prepare_ldnmp_site_root normalize_ldnmp_site_permissions; do - cmp \ - <(extract_function "${function_name}" "${scripts[0]}") \ - <(extract_function "${function_name}" "${scripts[1]}") -done - -grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[0]}" >/dev/null -grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[1]}" >/dev/null - -printf '%s\n' "LDNMP site permission smoke tests passed" From b1c17c23bb5e87ed1602832b3dc8ed358d42460b Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 12:54:19 +0800 Subject: [PATCH 1239/1285] fix(ldnmp): normalize new site permissions --- cn/kejilion.sh | 70 ++++++++++++--- kejilion.sh | 70 ++++++++++++--- tests/test_ldnmp_site_permissions_smoke.sh | 100 +++++++++++++++++++++ 3 files changed, 214 insertions(+), 26 deletions(-) create mode 100644 tests/test_ldnmp_site_permissions_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a6008334e..9a5931e6e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1676,6 +1676,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "无效的站点目录名称: $site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "站点目录不存在: $site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -3475,7 +3509,7 @@ ldnmp_wp() { cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +3523,8 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -9132,7 +9168,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9141,6 +9177,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9175,13 +9212,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9216,7 +9254,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9225,6 +9263,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9265,10 +9304,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9321,7 +9361,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9343,6 +9383,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9380,12 +9421,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9423,12 +9465,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9461,7 +9504,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9560,6 +9603,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9700,14 +9744,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9742,7 +9786,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9770,7 +9814,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on diff --git a/kejilion.sh b/kejilion.sh index 746300684..68d3ff775 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1708,6 +1708,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "无效的站点目录名称: $site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "站点目录不存在: $site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -4102,7 +4136,7 @@ ldnmp_wp() { kpanel_web_progress 75 "正在获取并配置 kejilion.sh WordPress 源码" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -4117,6 +4151,8 @@ ldnmp_wp() { kpanel_web_progress 90 "正在重启 LDNMP 并核验 WordPress 站点" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -10788,7 +10824,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -10797,6 +10833,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10831,13 +10868,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -10872,7 +10910,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -10881,6 +10919,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10921,10 +10960,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -10977,7 +11017,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -10999,6 +11039,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11036,12 +11077,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11079,12 +11121,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -11117,7 +11160,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -11216,6 +11259,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -11356,14 +11400,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -11398,7 +11442,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -11426,7 +11470,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on diff --git a/tests/test_ldnmp_site_permissions_smoke.sh b/tests/test_ldnmp_site_permissions_smoke.sh new file mode 100644 index 000000000..6ebe77ec5 --- /dev/null +++ b/tests/test_ldnmp_site_permissions_smoke.sh @@ -0,0 +1,100 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +scripts=( + "${project_root}/kejilion.sh" + "${project_root}/cn/kejilion.sh" +) + +extract_function() { + local function_name="$1" + local script_path="$2" + awk -v signature="${function_name}() {" ' + $0 == signature { capture=1 } + capture { + print + line=$0 + opens=gsub(/{/, "{", line) + closes=gsub(/}/, "}", line) + depth += opens - closes + if (depth == 0) { + exit + } + } + ' "${script_path}" +} + +for script_path in "${scripts[@]}"; do + bash -n "${script_path}" + + prepare_count="$(grep -Fc 'prepare_ldnmp_site_root "$yuming" || return 1' "${script_path}")" + normalize_count="$(grep -Fc 'normalize_ldnmp_site_permissions "$yuming" || return 1' "${script_path}")" + [ "${prepare_count}" -eq 11 ] + [ "${normalize_count}" -eq 11 ] + + if grep -F 'mkdir $yuming' "${script_path}" >/dev/null; then + printf '%s\n' "unsafe umask-dependent site directory creation remains in ${script_path}" >&2 + exit 1 + fi + if grep -F 'chmod -R nginx:nginx' "${script_path}" >/dev/null; then + printf '%s\n' "invalid chmod owner syntax remains in ${script_path}" >&2 + exit 1 + fi + + test_root="$(mktemp -d)" + ( + eval "$(extract_function ldnmp_site_domain_is_safe "${script_path}")" + eval "$(extract_function prepare_ldnmp_site_root "${script_path}")" + eval "$(extract_function normalize_ldnmp_site_permissions "${script_path}")" + + ldnmp_web_root_base="${test_root}/html" + install() { + printf '%s\n' "shadowed install() must not be called" >&2 + return 97 + } + mkdir() { + printf '%s\n' "shadowed mkdir() must not be called" >&2 + return 98 + } + chmod() { + printf '%s\n' "shadowed chmod() must not be called" >&2 + return 99 + } + umask 0077 + prepare_ldnmp_site_root "wp.example.test" + command mkdir -p "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes" + printf '%s\n' "body {}" > "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css" + printf '%s\n' "#!/bin/sh" > "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + command chmod 0755 "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh" + + [ "$(stat -c '%a' "${ldnmp_web_root_base}")" = "755" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test")" = "755" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "700" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "600" ] + + normalize_ldnmp_site_permissions "wp.example.test" + + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress")" = "755" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/wp-includes/style.css")" = "644" ] + [ "$(stat -c '%a' "${ldnmp_web_root_base}/wp.example.test/wordpress/task.sh")" = "755" ] + + if prepare_ldnmp_site_root "../escape"; then + printf '%s\n' "path traversal domain was accepted by ${script_path}" >&2 + exit 1 + fi + [ ! -e "${test_root}/escape" ] + ) + rm -rf -- "${test_root}" +done + +for function_name in ldnmp_site_domain_is_safe prepare_ldnmp_site_root normalize_ldnmp_site_permissions; do + cmp \ + <(extract_function "${function_name}" "${scripts[0]}") \ + <(extract_function "${function_name}" "${scripts[1]}") +done + +grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[0]}" >/dev/null +grep -F 'chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1' "${scripts[1]}" >/dev/null + +printf '%s\n' "LDNMP site permission smoke tests passed" From b792ba9451abee7787a8fe992a72f7df3d555480 Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 14:35:38 +0800 Subject: [PATCH 1240/1285] feat(kpanel): add managed BBRv3 protocol --- cn/kejilion.sh | 2 +- kejilion.sh | 128 +++++++++++++++++- kejilion_sh_log.txt | 5 + .../test_kpanel_bbrv3_noninteractive_smoke.sh | 46 +++++++ 4 files changed, 174 insertions(+), 7 deletions(-) create mode 100755 tests/test_kpanel_bbrv3_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 9a5931e6e..04443cf08 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.3" +sh_v="4.5.4" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 68d3ff775..0c74c3022 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.3" +sh_v="4.5.4" gl_hui='\e[37m' @@ -19,6 +19,7 @@ ENABLE_STATS="true" kpanel_protocol_active() { [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || @@ -6504,9 +6505,114 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && ! printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + local status_line + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "当前主机不支持 KPanel BBRv3 受控执行" >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s\n' 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":false}' + kpanel_bbrv3_status + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "尚未安装 XanMod BBRv3 内核,不能执行更新" >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s\n' 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":false}' + kpanel_bbrv3_status + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":true}\n' \ + "$command" "$changed" + kpanel_bbrv3_status + ;; + *) + echo "用法: k bbrv3 [status|install|update|uninstall]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3管理" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3管理" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -6635,7 +6741,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3内核处理完成。重启后生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -6645,9 +6751,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "XanMod内核已卸载。重启后生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -23755,7 +23866,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 774a28606..73e5255fc 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1526,4 +1526,9 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 优化KPanel协议隔离、交互输入和任务恢复,降低任务中断、状态漂移及结果误判。 修复Docker Hub latest镜像更新检测,提高应用新版本识别准确性。 新增KPanel的WordPress、IP端口反代、网站删除及LDNMP环境管理入口,原 k web 菜单保持兼容。 +------------------------ +2026-07-30 v4.5.4 +系统工具BBRv3新增KPanel固定协议,支持面板读取真实状态并提交安装、更新和卸载任务。 +KPanel调用BBRv3流程时不会自动重启服务器,任务完成后由用户确认重启并复核内核状态。 +原 k bbrv3 交互菜单、XanMod安装方式和ARM64脚本入口保持不变。 diff --git a/tests/test_kpanel_bbrv3_noninteractive_smoke.sh b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh new file mode 100755 index 000000000..ccd8015ed --- /dev/null +++ b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" + +bash -n "${script_path}" + +for function_name in \ + kpanel_bbrv3_status \ + kpanel_bbrv3_dispatch \ + bbrv3; do + grep -F "${function_name}() {" "${script_path}" >/dev/null +done + +grep -F '[ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/null +grep -F 'KPANEL_BBRV3_PROTOCOL 1' "${script_path}" >/dev/null +grep -F 'KPANEL_BBRV3_STATUS {' "${script_path}" >/dev/null +grep -F 'KPANEL_BBRV3_RESULT {' "${script_path}" >/dev/null +grep -F 'kpanel_bbrv3_dispatch "$@"' "${script_path}" >/dev/null +grep -F '[ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot' "${script_path}" >/dev/null + +# The legacy command without the protocol environment must remain interactive. +grep -F 'send_stats "bbrv3管理"' "${script_path}" >/dev/null +grep -F '1. 更新BBRv3内核' "${script_path}" >/dev/null +grep -F '确定继续吗?(Y/N)' "${script_path}" >/dev/null +grep -F 'bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh)' "${script_path}" >/dev/null + +status_output="$( + KJ_BBRV3_NONINTERACTIVE=1 \ + LC_ALL=C.UTF-8 \ + LANG=C.UTF-8 \ + bash "${script_path}" bbrv3 status +)" +grep -Fx 'KPANEL_BBRV3_PROTOCOL 1' <<<"${status_output}" >/dev/null +grep -F 'KPANEL_BBRV3_STATUS {"supported":' <<<"${status_output}" >/dev/null +grep -F '"installed":' <<<"${status_output}" >/dev/null +grep -F '"runningKernel":"' <<<"${status_output}" >/dev/null +grep -F '"rebootRequired":' <<<"${status_output}" >/dev/null + +if KJ_BBRV3_NONINTERACTIVE=1 bash "${script_path}" bbrv3 arbitrary >/dev/null 2>&1; then + echo "unknown BBRv3 action was accepted" >&2 + exit 1 +fi + +printf '%s\n' "kpanel_bbrv3_noninteractive_smoke=pass" From f14c276ffc9b2a8319a71e6653069ddb99d685ea Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 14:40:01 +0800 Subject: [PATCH 1241/1285] fix(kpanel): detect pending BBRv3 kernel switch --- kejilion.sh | 17 +++++++++++++---- tests/test_kpanel_bbrv3_noninteractive_smoke.sh | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 0c74c3022..091e9a585 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6506,7 +6506,7 @@ dd_xitong() { kpanel_bbrv3_status() { - local architecture os_id codename running_kernel installed=false active=false supported=false + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false local congestion qdisc reboot_required=false reason="" architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') @@ -6516,6 +6516,14 @@ kpanel_bbrv3_status() { os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') xanmod_installed && installed=true @@ -6541,14 +6549,15 @@ kpanel_bbrv3_status() { else reason="missing_dependencies" fi - if { [ "$installed" = "true" ] && ! printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || [ -f /var/run/reboot-required ]; then reboot_required=true fi - printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ - "$running_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" } kpanel_bbrv3_dispatch() { diff --git a/tests/test_kpanel_bbrv3_noninteractive_smoke.sh b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh index ccd8015ed..a6115a05d 100755 --- a/tests/test_kpanel_bbrv3_noninteractive_smoke.sh +++ b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh @@ -36,6 +36,7 @@ grep -Fx 'KPANEL_BBRV3_PROTOCOL 1' <<<"${status_output}" >/dev/null grep -F 'KPANEL_BBRV3_STATUS {"supported":' <<<"${status_output}" >/dev/null grep -F '"installed":' <<<"${status_output}" >/dev/null grep -F '"runningKernel":"' <<<"${status_output}" >/dev/null +grep -F '"installedKernel":"' <<<"${status_output}" >/dev/null grep -F '"rebootRequired":' <<<"${status_output}" >/dev/null if KJ_BBRV3_NONINTERACTIVE=1 bash "${script_path}" bbrv3 arbitrary >/dev/null 2>&1; then From 4a6e5b5b6054fd4da47d0362bc759c43cf83c06a Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 30 Jul 2026 14:55:54 +0800 Subject: [PATCH 1242/1285] fix(kpanel): synchronize BBRv3 reboot state --- kejilion.sh | 26 ++++++++++++------- .../test_kpanel_bbrv3_noninteractive_smoke.sh | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 091e9a585..5d096a185 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6561,7 +6561,7 @@ kpanel_bbrv3_status() { } kpanel_bbrv3_dispatch() { - local command="${1:-status}" changed=false + local command="${1:-status}" changed=false status_line reboot_required=false printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" case "$command" in status) @@ -6569,7 +6569,6 @@ kpanel_bbrv3_dispatch() { ;; install|update|uninstall) root_use - local status_line status_line=$(kpanel_bbrv3_status) if ! printf '%s' "$status_line" | grep -q '"supported":true' && { [ "$command" != "uninstall" ] || @@ -6581,8 +6580,11 @@ kpanel_bbrv3_dispatch() { case "$command" in install) if xanmod_installed; then - printf '%s\n' 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":false}' - kpanel_bbrv3_status + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" return 0 fi xanmod_install_or_update install || return 1 @@ -6598,17 +6600,23 @@ kpanel_bbrv3_dispatch() { ;; uninstall) if ! xanmod_installed; then - printf '%s\n' 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":false}' - kpanel_bbrv3_status + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" return 0 fi xanmod_uninstall || return 1 changed=true ;; esac - printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":true}\n' \ - "$command" "$changed" - kpanel_bbrv3_status + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" ;; *) echo "用法: k bbrv3 [status|install|update|uninstall]" >&2 diff --git a/tests/test_kpanel_bbrv3_noninteractive_smoke.sh b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh index a6115a05d..06fa4eaed 100755 --- a/tests/test_kpanel_bbrv3_noninteractive_smoke.sh +++ b/tests/test_kpanel_bbrv3_noninteractive_smoke.sh @@ -17,6 +17,7 @@ grep -F '[ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/nul grep -F 'KPANEL_BBRV3_PROTOCOL 1' "${script_path}" >/dev/null grep -F 'KPANEL_BBRV3_STATUS {' "${script_path}" >/dev/null grep -F 'KPANEL_BBRV3_RESULT {' "${script_path}" >/dev/null +grep -F 'printf '\''%s'\'' "$status_line" | grep -q '\''"rebootRequired":true'\''' "${script_path}" >/dev/null grep -F 'kpanel_bbrv3_dispatch "$@"' "${script_path}" >/dev/null grep -F '[ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot' "${script_path}" >/dev/null From 4b3df934c5c04d810bc653bd5ab6b6e8a0787354 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 09:51:02 +0800 Subject: [PATCH 1243/1285] fix: follow Komari setup wizard --- cn/kejilion.sh | 4 +--- en/kejilion.sh | 4 +--- jp/kejilion.sh | 4 +--- kejilion.sh | 4 +--- kr/kejilion.sh | 4 +--- tw/kejilion.sh | 4 +--- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 04443cf08..139344735 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -18214,8 +18214,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -18224,7 +18222,7 @@ while true; do local docker_describe="轻量级的自托管服务器监控工具" local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app diff --git a/en/kejilion.sh b/en/kejilion.sh index 33975646e..aa955cf53 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -18176,8 +18176,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -18186,7 +18184,7 @@ while true; do local docker_describe="Lightweight self-hosted server monitoring tool" local docker_url="Official website introduction:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"Default account: admin Default password: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 148567a96..d1c69315f 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -18176,8 +18176,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -18186,7 +18184,7 @@ while true; do local docker_describe="軽量のセルフホスト型サーバー監視ツール" local docker_url="公式サイト紹介:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"デフォルトのアカウント: admin デフォルトのパスワード: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app diff --git a/kejilion.sh b/kejilion.sh index 5d096a185..59e38bb26 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -20031,8 +20031,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -20041,7 +20039,7 @@ while true; do local docker_describe="轻量级的自托管服务器监控工具" local docker_url="官网介绍: ${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"默认账号: admin 默认密码: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app diff --git a/kr/kejilion.sh b/kr/kejilion.sh index f8c5766da..91622aa62 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -18176,8 +18176,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -18186,7 +18184,7 @@ while true; do local docker_describe="경량 자체 호스팅 서버 모니터링 도구" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"기본 계정: admin 기본 비밀번호: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app diff --git a/tw/kejilion.sh b/tw/kejilion.sh index f514e3ea5..64a98b5da 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -18176,8 +18176,6 @@ while true; do --name komari \ -p ${docker_port}:25774 \ -v /home/docker/komari:/app/data \ - -e ADMIN_USERNAME=admin \ - -e ADMIN_PASSWORD=1212156 \ -e TZ=Asia/Shanghai \ --restart=always \ ghcr.io/komari-monitor/komari:latest @@ -18186,7 +18184,7 @@ while true; do local docker_describe="輕量級的自架伺服器監控工具" local docker_url="官網介紹:${gh_https_url}github.com/komari-monitor/komari/tree/main" - local docker_use="echo \"預設帳號: admin 預設密碼: 1212156\"" + local docker_use="" local docker_passwd="" local app_size="1" docker_app From b4641e34c45231addb7a9c6b1b3ae224d77e2fe0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 2 Aug 2026 06:09:01 +0000 Subject: [PATCH 1244/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-08-02=2006:09:01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 2419 +++++++++++++++++++++++++++++++++++++++----- jp/kejilion.sh | 2559 +++++++++++++++++++++++++++++++++++++++++------ kr/kejilion.sh | 2507 ++++++++++++++++++++++++++++++++++++++++------ tw/kejilion.sh | 2613 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 8935 insertions(+), 1163 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index aa955cf53..7e55ab625 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.4" gl_hui='\e[37m' @@ -16,6 +16,18 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +kpanel_protocol_active() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -100,17 +112,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 - -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -141,7 +154,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi @@ -754,7 +769,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # Check if the configuration file exists, if not create the file and write default settings + # Check if the configuration file exists, if not create the file and write the default settings if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -1540,6 +1555,11 @@ certs_status() { send_stats "Domain name certificate application successful" else send_stats "Domain name certificate application failed" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then + echo "KPANEL_PROGRESS 100 Domain name certificate application failed, please check DNS, 80/443 port and issuance quota" + return 1 + fi echo -e "${gl_hong}Notice:${gl_bai}Certificate application failed, please check the following possible reasons and try again:" echo -e "1. Domain name is spelled incorrectly ➠ Please check whether the domain name is entered correctly" echo -e "2. DNS resolution problem ➠ Confirm that the domain name has been correctly resolved to the server IP" @@ -1618,6 +1638,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "Domain name reuse" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 The domain name already exists, refusing to overwrite existing products of kejilion.sh or KPanel" + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1649,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN is not a valid domain name" + return 1 + fi + return 0 + fi ip_address echo -e "First resolve the domain name to the local IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "Please enter your IP or resolved domain name:" yuming @@ -1676,6 +1709,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "Invalid site directory name:$site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "Site directory does not exist:$site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -1786,32 +1853,72 @@ web_cache() { web_del() { send_stats "Delete site data" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "To delete site data, please enter your domain name (separate multiple domain names with spaces):" yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "To delete site data, please enter your domain name (separate multiple domain names with spaces):" yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "Invalid domain name, refused to delete:$yuming" + action_status=1 + continue + fi + echo "Domain name is being deleted:$yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # Convert domain name to database name dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "Deleting database:$dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # Check whether the database exists before deleting it to avoid errors. - echo "Deleting database:$dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "Site product deletion is incomplete:$yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx configuration verification or reload failed" + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -2241,7 +2348,7 @@ web_security() { echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and obtain${gl_huang}Global API Key${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2344,8 +2451,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "Unsupported LDNMP optimization mode" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "The LDNMP environment has been set to high performance mode" + else + optimize_balanced + echo "The LDNMP environment has been set to standard mode" + fi +} web_optimization() { while true; do @@ -2367,83 +2532,11 @@ web_optimization() { case $sub_choice in 1) send_stats "site standards mode" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # php tuning - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php tuning - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql tuning - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "The LDNMP environment has been set to standard mode" - + ldnmp_optimization_mode standard ;; 2) send_stats "Site high performance mode" - - # nginx tuning - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # php tuning - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php tuning - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql tuning - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "The LDNMP environment has been set to high performance mode" - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -2544,19 +2637,18 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. Regional inspection - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. Get local mirror information - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. Obtain container and local image information. Update detection is no longer skipped by region. + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. Intelligent routing judgment + # 2. Intelligent routing judgment if [[ "$full_image_name" == ghcr.io* ]]; then # --- Scenario A: Mirror on GitHub (ghcr.io) --- # Extract the warehouse path, for example ghcr.io/onexru/oneimg -> onexru/oneimg @@ -2572,19 +2664,45 @@ check_docker_image_update() { else # --- Scenario C: Standard Docker Hub --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}New version found!${gl_bai}" + fi + return + fi fi - # 4. Timestamp comparison + # 3. When the Registry does not provide a comparable summary, it is compatible with the release time judgment. if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}New version found!${gl_bai}" fi fi @@ -2857,11 +2975,412 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi + read -r -e -p "Please enter your choice:" selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "Error: KPanel application management terminal only accepts menu numbers" + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "Error: KPanel does not provide a valid application access mode" + return 1 + ;; + esac + ;; + *) + echo "Error: KPanel interactive terminal does not support this application operation" + return 1 + ;; + esac +} + +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "Error: Invalid application main container name" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "Error: Application main container not found${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "Error: Unable to identify application master container${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "Error: The main application container has changed, please refresh the panel and try again" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "Error: Invalid application state file name" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "Error: Unsupported application access mode" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "Error: Unsupported application access mode" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "Error: KPanel did not provide a valid application port" + return 1 + ;; + esac + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "Error: KPanel application port must be between 1-65535" + return 1 + fi + if kpanel_app_port_in_use "$requested_port"; then + echo "Error: port${requested_port}Already occupied" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}mistake:${gl_bai}port$app_portAlready occupied, please change a port" + send_stats "Application port is occupied" + else + docker_port="$app_port" + return 0 + fi + done +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "Error: KPanel currently only allows non-interactive installation" + return 1 + fi + + kpanel_app_progress 5 "Verifying port and host environment" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "Preparing Docker runtime environment" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "Executing kejilion.sh application installation function" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "Installation failed: Application status not registered" + return 1 + fi + else + if ! docker_rum; then + echo "Installation failed: Application status not registered" + return 1 + fi + fi + + kpanel_app_progress 90 "Writing kejilion.sh compatibility status" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "Application installation completed" + echo "$docker_nameInstallation completed" + return 0 +} + +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "Error: KPanel does not support this application operation" + return 1 + ;; + esac + + kpanel_app_progress 5 "Checking kejilion.sh installation flag against main container" + service_name="$(kpanel_app_verified_service true)" || return 1 + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "Error: kejilion.sh application installation tag not found" + return 1 + fi + kpanel_app_progress 10 "Fixing kejilion.sh app install flag" + add_app_id || return 1 + fi + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "Executing kejilion.sh native update function" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "Restoring app access policy" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "Application update completed" + echo "$service_nameAlready updated" + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "Executing kejilion.sh native uninstall function" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "Error: Main container still exists after uninstall function completes" + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "Application uninstall completed" + echo "$service_nameUninstallation completed" + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "Error: KPanel does not provide a valid application access mode" + return 1 + ;; + esac + kpanel_app_progress 40 "Executing kejilion.sh IP+port access policy" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "Application access policy update completed" + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}manage" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action standard + return $? +fi + while true; do clear check_docker_app @@ -2887,30 +3406,30 @@ while true; do echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your choice:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "Please enter your choice:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}mistake:${gl_bai}port$app_portAlready occupied, please change a port" - send_stats "Application port is occupied" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}Installation failed:${gl_bai}The application container failed to start." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_nameInstallation completed" @@ -2923,9 +3442,15 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}Update failed:${gl_bai}The application container failed to restart." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_nameInstallation completed" @@ -2936,10 +3461,16 @@ while true; do send_stats "renew$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}Uninstall failed:${gl_bai}The application container could not be deleted." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "App has been uninstalled" @@ -2952,27 +3483,33 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "Domain name format example.com without https://" - web_del + web_del || action_status=1 ;; 7) send_stats "Allow IP access${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "Block IP access${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -2984,6 +3521,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action plus + return $? + fi while true; do clear check_docker_app @@ -3010,46 +3551,53 @@ docker_app_plus() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your selection:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "Enter your selection:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "Enter the application external service port and press Enter to use it by default.${docker_port}port:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}mistake:${gl_bai}port$app_portAlready occupied, please change a port" - send_stats "Application port is occupied" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_nameInstall" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + kpanel_app_write_access_mode direct + send_stats "$app_nameInstall" + else + echo -e "${gl_hong}Installation failed:${gl_bai}The application status has not been registered. Please fix the error above and try again." + action_status=1 + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_namerenew" + if docker_app_update; then + add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" + send_stats "$app_namerenew" + else + echo -e "${gl_hong}Update failed:${gl_bai}The original application registration status has been retained." + action_status=1 + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_nameuninstall" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_nameuninstall" + else + echo -e "${gl_hong}Uninstall failed:${gl_bai}Application registration status has been retained." + action_status=1 + fi ;; 5) @@ -3059,25 +3607,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "Domain name format example.com without https://" - web_del + web_del || action_status=1 ;; 7) send_stats "Allow IP access${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "Block IP access${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -3212,6 +3767,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH jail failed to start properly" >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban service is still running" >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "Usage: k f2b [status|enable|disable]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -3455,27 +4111,33 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "Verifying WordPress domain name with existing site" send_stats "Install$webname" echo "Start deployment$webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "Preparing kejilion.sh LDNMP environment" ldnmp_install_status + kpanel_web_progress 35 "Issuing and configuring site certificate" install_ssltls certs_status + kpanel_web_progress 50 "Creating WordPress database and account" add_db + kpanel_web_progress 60 "Getting kejilion.sh WordPress Nginx configuration" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "Obtaining and configuring kejilion.sh WordPress source code" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +4151,9 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "Restarting LDNMP and verifying WordPress site" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -3503,6 +4168,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "Verifying reverse proxy domain name and upstream address" send_stats "Install$webname" echo "Start deployment$webname" if [ -z "$yuming" ]; then @@ -3519,12 +4185,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "Please enter your anti-generation port:" port fi + kpanel_web_progress 25 "Preparing kejilion.sh Nginx environment" nginx_install_status + kpanel_web_progress 40 "Issuing and configuring reverse proxy certificate" install_ssltls certs_status + kpanel_web_progress 60 "Getting kejilion.sh reverse proxy configuration" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3545,6 +4214,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "Verifying and reloading reverse proxy configuration" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -4823,6 +5493,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "Error: /etc/resolv.conf is a broken symbolic link" + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "Error: DNS configuration directory does not exist" + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "Error: chattr is not available, unable to maintain kejilion.sh DNS lifecycle semantics" + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "Error: Unable to lock DNS configuration" + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "Error: Unable to unlock existing DNS configuration" + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "Error: DNS write failed and rollback failed, manual check required" + return 1 + } + rm -f "$desired" "$backup" + echo "Error: DNS write or readback verification failed, original configuration has been restored" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "Error: systemctl is not available" + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "Error: systemd-resolved DNS rollback failed, manual inspection required" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "Error: systemd-resolved DNS has restored files, but service reload failed, manual inspection required" + return 1 + } + rm -f "$desired" "$backup" + echo "Error: systemd-resolved DNS write or readback verification failed, original configuration has been restored" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "Error: KPanel DNS protocol must be run as root" + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "Error: Number of DNS addresses must be 1-4" + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "Error: DNS address is empty or too long" + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "Error: Maximum of 2 IPv4 DNS addresses" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "Error: Maximum of 2 IPv6 DNS addresses" + return 1 + } + else + echo "Error: Invalid DNS address" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "Error: DNS address cannot be repeated" + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -4938,7 +5848,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}The user key login mode has been turned on and the password login mode has been turned off. Reconnection will take effect.${gl_bai}" + echo -e "${gl_lv}The user key login mode is turned on and the password login mode is turned off. Reconnection will take effect.${gl_bai}" } @@ -5030,7 +5940,7 @@ fetch_remote_ssh_keys() { # Download public key if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "Error: Unable to download public key from URL (network issue or invalid address)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } @@ -5096,8 +6006,8 @@ fetch_github_ssh_keys() { local username="$1" local base_dir="${2:-$HOME}" - echo "操作前,请确保您已在 GitHub 账户中添加了 SSH 公钥:" - echo "1. Log in${gh_https_url}github.com/settings/keys" + echo "Before proceeding, make sure you have added your SSH public key to your GitHub account:" + echo "1. Login${gh_https_url}github.com/settings/keys" echo "2. Click New SSH key or Add SSH key" echo "3. Title can be filled in as desired (for example: Home Laptop 2026)" echo "4. Paste the contents of the local public key (usually the entire contents of ~/.ssh/id_ed25519.pub or id_rsa.pub) into the Key field" @@ -5138,7 +6048,7 @@ sshkey_panel() { echo -e "User key login mode${IS_KEY_ENABLED}" echo "Advanced gameplay: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "A key pair will be generated for a more secure way to log in via SSH" + echo "A key pair will be generated, a more secure way to log in via SSH" echo "------------------------" echo "1. Generate a new key pair 2. Manually enter an existing public key" echo "3. Import the existing public key from GitHub 4. Import the existing public key from the URL" @@ -5595,9 +6505,131 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false status_line reboot_required=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "The current host does not support KPanel BBRv3 controlled execution" >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "The XanMod BBRv3 kernel has not been installed and the update cannot be performed" >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" + ;; + *) + echo "Usage: k bbrv3 [status|install|update|uninstall]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3 management" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3 management" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -5704,7 +6736,7 @@ bbrv3() { } package=$(xanmod_detect_package) || { - echo "The current CPU cannot be recognized or a matching kernel package cannot be found. The installation has been cancelled." + echo "The current CPU cannot be recognized or the matching kernel package cannot be found. The installation has been cancelled." return 1 } @@ -5726,7 +6758,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3 kernel processing completed. Take effect after restart" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -5736,9 +6768,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "The XanMod kernel has been uninstalled. Take effect after restart" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -6158,7 +7195,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── Extras for live broadcast scenarios: UDP buffer enlarged ── + # ── Additional live broadcast scenarios: UDP buffer enlarged ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -6423,7 +7460,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization mode" + send_stats "Website optimization model" ;; 4) cd ~ @@ -6695,9 +7732,9 @@ send_stats "Command Favorites" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# Create a backup +# Create backup create_backup() { - send_stats "Create a backup" + send_stats "Create backup" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # Prompt user for backup directory @@ -6739,7 +7776,7 @@ create_backup() { echo "- $path" done - # Create a backup + # Create backup echo "Creating backup$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -7151,7 +8188,7 @@ list_partitions() { # Persistently mounted partition mount_partition() { send_stats "Mount partition" - read -e -p "Please enter the name of the partition to be mounted (e.g. sda1):" PARTITION + read -e -p "Please enter the partition name to be mounted (e.g. sda1):" PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" @@ -7192,7 +8229,7 @@ mount_partition() { return 1 fi - echo "Partition successfully mounted to$MOUNT_POINT" + echo "The partition was successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8339,7 +9376,7 @@ docker_ssh_migration() { echo -e "${gl_huang}Transferring backup...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # Log in with key + # Log in using key scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8685,6 +9722,180 @@ linux_docker() { +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} + +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPT unlock status detection" + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh + ;; + region) + send_stats "Region streaming media unlock test" + kpanel_run_remote_bash https://check.unlock.media + ;; + media) + send_stats "yeahwu streaming media unlock detection" + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh + ;; + ip-quality) + send_stats "xykt_IP quality check script" + kpanel_run_remote_bash https://IP.Check.Place + ;; + besttrace) + send_stats "besttrace triple network backhaul delay routing test" + kpanel_run_remote_bash https://git.io/besttrace + ;; + mtr) + send_stats "mtr_trace triple network backhaul line test" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh + ;; + superspeed) + send_stats "Superspeed triple network speed test" + kpanel_run_remote_bash https://git.io/superspeed_uxh + ;; + nxtrace-fast) + send_stats "nxtrace fast backhaul test script" + kpanel_run_remote_bash https://nxtrace.org/nt + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020 three network line test" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh + ;; + speedtest) + send_stats "i-abc multifunctional speed test script" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh + ;; + net-quality) + send_stats "Network quality test script" + kpanel_run_remote_bash https://Net.Check.Place + ;; + tcp-quality) + send_stats "TcpQuality TCP retransmission detection script" + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh + ;; + yabs) + send_stats "yabs performance test" + check_swap + kpanel_run_remote_bash https://yabs.sh -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU performance test script" + check_swap + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh + ;; + bench) + send_stats "bench performance test" + kpanel_run_remote_bash https://bench.sh + ;; + ecs) + send_stats "spiritysdx fusion monster review" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "nodequality fusion monster evaluation" + kpanel_run_remote_bash https://run.NodeQuality.com + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac +} + + linux_test() { while true; do @@ -9075,9 +10286,577 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "Usage: k " + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "An existing website or LDNMP environment task is being executed" >&2 + exec {lock_fd}>&- + return 75 + fi + linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","required":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","repoDigest":"%s","updateStatus":"unknown","updateReason":"Registry status is only confirmed in real time during update tasks"}' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"Full LDNMP"},{"id":"nginx","label":"Only Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudfl are-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on ","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"] },{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "Checking installation conditions" + case "$profile" in + full) kpanel_ldnmp_event install 15 "Installing full LDNMP"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "Installing nginx"; nginx_install_all ;; + *) echo "Unsupported installation form" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "Verifying environment" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare credential channel is invalid" >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "Unsupported protective action" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "The protection configuration verification failed and the original configuration is being restored." + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "The current protocol does not support this optimization action" >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "Optimization verification failed and original configuration is being restored." + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "Creating pre-update cold standby" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "Unsupported update component" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "Briefly stopping LDNMP" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "Archiving /home/web" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "Restoring LDNMP" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "Scanning backup archives" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "Extracting to safe staging directory" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "Switching atomically to /home/web" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "An existing website or LDNMP environment task is being executed" + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP environment task started" + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP environment task completed" + kpanel_ldnmp_result succeeded "$action" "Task execution successful" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP environment task execution failed" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "The task failed and safe rollback could not be confirmed, requiring manual processing." + else + kpanel_ldnmp_result failed "$action" "Task execution failed" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP environment management" + echo "------------------------" + echo "1. Check the environment status" + echo "2. Install full LDNMP" + echo "3. Install only Nginx" + echo "4. Protection management" + echo "5. Optimize management" + echo "6. Update environment" + echo "7. Create a cold standby" + echo "8. Restore backup" + echo "9. Uninstall the environment" + echo "0. Return" + echo "------------------------" + read -e -p "Please enter your choice:" choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "Update components (nginx/mysql/php/redis/all):" component + read -e -p "Target version (default latest):" version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "Enter the backup file name to be restored:" backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "Enter DELETE to confirm the uninstallation of the LDNMP environment:" confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "Invalid input" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "Unsupported LDNMP environment commands" >&2; return 2 ;; + esac +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP website building" echo -e "${gl_huang}LDNMP website building" @@ -9103,7 +10882,42 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}Return to main menu" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "Please enter your choice:" sub_choice + fi + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; + *) + echo "KPANEL_PROGRESS 100 Unsupported KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN is not a valid domain name" + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 The domain name already exists, refusing to overwrite existing products" + return 1 + fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST is not a valid IP or hostname" + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT is not a valid port" + return 1 + fi + fi + echo "KPANEL_PROGRESS 5 is starting the kejilion.sh native one-click website building process" + else + read -e -p "Please enter your choice:" sub_choice + fi case $sub_choice in @@ -9112,7 +10926,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9138,7 +10952,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9147,6 +10961,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9162,7 +10977,7 @@ linux_ldnmp() { 4) clear - # 可道云桌面 + # Kedao cloud desktop webname="Kedao cloud desktop" send_stats "Install$webname" echo "Start deployment$webname" @@ -9181,13 +10996,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9222,7 +11038,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9231,6 +11047,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9271,10 +11088,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9327,7 +11145,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9349,6 +11167,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9386,12 +11205,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9429,12 +11249,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9467,7 +11288,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9566,6 +11387,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9613,7 +11435,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -9706,14 +11528,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9748,7 +11570,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9776,7 +11598,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -10078,6 +11900,23 @@ linux_ldnmp() { *) echo "Invalid input!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh website building product is incomplete" + return 1 + fi + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh website building product is incomplete" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx configuration verification failed" + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh native website building product has been completed" + return 0 + fi break_end done @@ -10099,7 +11938,7 @@ moltbot_menu() { return 1 fi - # Add --no-update-notifier and make sure error redirection is in the correct location + # Add --no-update-notifier and make sure error redirects are in the correct location local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -11125,7 +12964,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ provider {target} currently api={api}, but the script no longer detects/corrects the protocol; please manually set it to openai-completions or openai-responses') + print(f'ℹ️ provider {target} current api={api}, but the script no longer detects/corrects the protocol; please manually set it to openai-completions or openai-responses') protocol_msg = None @@ -12225,7 +14064,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12336,8 +14175,8 @@ PYTHON_EOF # Output a list of recommended practical skills echo "Recommended practical skills (you can directly copy the name and enter it):" echo "github # Manage GitHub Issues/PR/CI (gh CLI)" - echo "notion # Manipulate Notion pages, databases and blocks" - echo "apple-notes # macOS native note management (create/edit/search)" + echo "notion # 操作 Notion 页面、数据库和块" + echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" echo "apple-reminders # macOS reminder management (to-do list)" echo "1password # Automate reading and injecting 1Password keys" echo "gog # Google Workspace (Gmail/cloud disk/documents) all-round assistant" @@ -12353,7 +14192,7 @@ PYTHON_EOF echo "1) Installation skills" echo "2) Delete skills" - echo "0) return" + echo "0) Return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -13589,7 +15428,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com can be accessed") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com may be unreachable (suspected domestic/restricted network)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com may not be reachable (suspected domestic/restricted network)") fi if [ "$qmd_ok" = "true" ]; then @@ -13884,7 +15723,7 @@ EOF model_path=$(openclaw_memory_expand_path "$model_path") model_status=$(openclaw_memory_local_model_status "$model_path") if [ "$model_status" = "ok" ]; then - echo "✅ Model file already exists:$model_path" + echo "✅ The model file already exists:$model_path" OPENCLAW_MEMORY_MODEL_PATH="$model_path" else local model_name="embeddinggemma-300M-Q8_0.gguf" @@ -14278,7 +16117,7 @@ EOF echo "Keywords cannot be empty." return 1 fi - echo "正在搜索记忆..." + echo "Searching memory..." openclaw memory search "$query" --max-results 5 } @@ -15269,7 +17108,7 @@ print("✅Multi-agent health check completed") local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" - echo "Identity information can also be read automatically from IDENTITY.md." + echo "Identity information can also be automatically read from IDENTITY.md." read -e -p "Read from IDENTITY.md? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" @@ -15577,21 +17416,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}mistake:${gl_bai}${apps_dir}It already exists but is not the App Market Git repository and overwriting is refused." + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}Application list download failed and incomplete configuration was rejected.${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}Application list update failed, refusing to continue using potentially expired configurations.${gl_bai}" + echo "Please check the network or${apps_dir}Try again after local modification." + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}The application list is being updated. Please wait...${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -15613,7 +17468,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}Pagoda panel official version${gl_kjlan}2. ${color2}aaPanel Pagoda International Version" echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" - echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Version" + echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" @@ -15995,13 +17850,13 @@ while true; do if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then echo -e "${gl_lv}port$portCurrently available${gl_bai}" else - echo -e "${gl_hong}端口 $portCurrently unavailable${gl_bai}" + echo -e "${gl_hong}port$portCurrently unavailable${gl_bai}" fi echo "" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then yuming=$(cat /home/docker/mail.txt) - echo "访问地址: " + echo "Visit address:" echo "https://$yuming" fi @@ -17694,7 +19549,7 @@ while true; do } - local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to AI large models" + local docker_describe="Open source AI chatbot framework, supporting WeChat, QQ, and TG access to large AI models" local docker_url="Official website introduction: https://astrbot.app/" local docker_use="echo \"Username: astrbot Password: astrbot\"" local docker_passwd="" @@ -17723,7 +19578,7 @@ while true; do } - local docker_describe="Is a lightweight, high-performance music streaming server" + local docker_describe="It is a lightweight, high-performance music streaming server" local docker_url="Official website introduction: https://www.navidrome.org/" local docker_use="" local docker_passwd="" @@ -18319,7 +20174,7 @@ while true; do } - local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -18950,7 +20805,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos" + local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19433,15 +21288,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" @@ -19450,6 +21297,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" @@ -20633,7 +22486,7 @@ EOF echo "Europe" echo "11. London, UK time 12. Paris, France time" echo "13. Berlin, Germany time 14. Moscow, Russia time" - echo "15. Utracht Time, Netherlands 16. Madrid Time, Spain" + echo "15. Utrecht Time, Netherlands 16. Madrid Time, Spain" echo "------------------------" echo "America" echo "21. US Western Time 22. US Eastern Time" @@ -21992,7 +23845,7 @@ echo "Block IP k zzip 177.5.25.36 |k Block IP 177.5.25.36" echo "command favorites k fav | k command favorites" echo "Application market management k app" echo "Quick management of application numbers k app 26 | k app 1panel | k app npm" -echo "fail2ban management k fail2ban | k f2b" +echo "fail2ban management k fail2ban | k f2b [status|enable|disable]" echo "Display system information k info" echo "ROOT key management k sshkey" echo "SSH public key import (URL) k sshkey " @@ -22028,7 +23881,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize @@ -22061,6 +23919,66 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" + ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" ;; fd|rp|反代) shift @@ -22097,6 +24015,20 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open @@ -22205,8 +24137,14 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "environment" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "delete" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then @@ -22234,7 +24172,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; diff --git a/jp/kejilion.sh b/jp/kejilion.sh index d1c69315f..0b8658c35 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.4" gl_hui='\e[37m' @@ -16,6 +16,18 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +kpanel_protocol_active() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -65,7 +77,7 @@ CheckFirstRun_true() { # 関数の埋もれた情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、ユーザーが使用した関数名を記録する機能。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 @@ -100,17 +112,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 - -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -125,7 +138,7 @@ UserLicenseAgreement() { clear echo -e "${gl_kjlan}テクノロジー ライオン スクリプト ツールボックスへようこそ${gl_bai}" echo "初めてスクリプトを使用する場合は、ユーザー使用許諾契約を読み、同意してください。" - echo "ユーザー使用許諾契約: https://blog.kejilion.pro/user-license-agreement/" + echo "ユーザー使用許諾契約書: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" read -e -p "上記の条件に同意しますか? (y/n):" user_input @@ -141,7 +154,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi @@ -754,7 +769,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成してデフォルト設定を書き込みます + # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成し、デフォルト設定を書き込みます if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -872,7 +887,7 @@ open_port() { done save_iptables_rules - send_stats "ポートがオープンされました" + send_stats "ポートがオープンしました" } @@ -930,12 +945,12 @@ allow_ip() { # 許可ルールを追加する if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT - echo "リリースされたIP$ip" + echo "リリース済みIP$ip" fi done save_iptables_rules - send_stats "リリースされたIP" + send_stats "リリース済みIP" } block_ip() { @@ -1540,8 +1555,13 @@ certs_status() { send_stats "ドメイン名証明書の申請が成功しました" else send_stats "ドメイン名証明書の申請に失敗しました" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then + echo "KPANEL_PROGRESS 100 ドメイン名証明書の申請に失敗しました。DNS、80/443 ポート、および発行クォータを確認してください。" + return 1 + fi echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" - echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているか確認してください" + echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" @@ -1618,6 +1638,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "ドメイン名の再利用" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 ドメイン名はすでに存在しており、kejilion.sh または KPanel の既存の製品を上書きすることを拒否しています" + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1649,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN は有効なドメイン名ではありません" + return 1 + fi + return 0 + fi ip_address echo -e "まず、ドメイン名をローカル IP に解決します。${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "IP または解決されたドメイン名を入力してください:" yuming @@ -1676,6 +1709,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "無効なサイト ディレクトリ名:$site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "サイト ディレクトリが存在しません:$site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -1786,32 +1853,72 @@ web_cache() { web_del() { send_stats "サイトデータを削除する" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "サイト データを削除するには、ドメイン名を入力してください (複数のドメイン名はスペースで区切ります)。" yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "サイト データを削除するには、ドメイン名を入力してください (複数のドメイン名はスペースで区切ります)。" yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "無効なドメイン名のため、削除が拒否されました:$yuming" + action_status=1 + continue + fi + echo "ドメイン名が削除されています:$yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # ドメイン名をデータベース名に変換する dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "データベースを削除しています:$dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # エラーを避けるために、データベースを削除する前にデータベースが存在するかどうかを確認してください。 - echo "データベースを削除しています:$dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "サイト製品の削除が不完全です:$yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx 構成の検証またはリロードに失敗しました" + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -1991,7 +2098,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # ブロトリを閉じる: コメントを追加 + # Brotliを閉じる: コメントを追加 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2237,11 +2344,11 @@ web_security() { ;; 22) - send_stats "高負荷により5秒シールドが可能" + send_stats "高負荷で5秒シールド可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" - echo "CF パラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側の API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo "CFパラメータを取得します。" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" @@ -2344,8 +2451,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "サポートされていない LDNMP 最適化モード" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "LDNMP 環境が高パフォーマンス モードに設定されている" + else + optimize_balanced + echo "LDNMP環境は標準モードに設定されています" + fi +} web_optimization() { while true; do @@ -2367,83 +2532,11 @@ web_optimization() { case $sub_choice in 1) send_stats "サイト標準モード" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # PHPのチューニング - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # PHPのチューニング - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysqlのチューニング - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "LDNMP環境は標準モードに設定されています" - + ldnmp_optimization_mode standard ;; 2) send_stats "サイトハイパフォーマンスモード" - - # nginxのチューニング - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # PHPのチューニング - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # PHPのチューニング - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysqlのチューニング - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "LDNMP 環境が高パフォーマンス モードに設定されている" - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -2544,24 +2637,23 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 地域検査 - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. ローカルミラー情報の取得 - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. コンテナーとローカル イメージの情報を取得します。更新検出がリージョンごとにスキップされなくなりました。 + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. インテリジェントな配線判断 + # 2. インテリジェントな配線判断 if [[ "$full_image_name" == ghcr.io* ]]; then # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです + # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2572,19 +2664,45 @@ check_docker_image_update() { else # --- シナリオ C: 標準 Docker ハブ --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}新しいバージョンが見つかりました!${gl_bai}" + fi + return + fi fi - # 4. タイムスタンプの比較 + # 3. レジストリが比較可能な概要を提供していない場合は、リリース時期の判断に準拠します。 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}新しいバージョンが見つかりました!${gl_bai}" fi fi @@ -2620,7 +2738,7 @@ block_container_port() { iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2637,7 +2755,7 @@ block_container_port() { iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT fi - # ローカルネットワーク127.0.0.0/8をチェックして許可します。 + # ローカルネットワーク127.0.0.0/8を確認して許可します。 if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT fi @@ -2857,11 +2975,412 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi + read -r -e -p "選択肢を入力してください:" selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "エラー: KPanel アプリケーション管理ターミナルはメニュー番号のみを受け入れます" + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "エラー: KPanel は有効なアプリケーション アクセス モードを提供しません" + return 1 + ;; + esac + ;; + *) + echo "エラー: KPanel インタラクティブ ターミナルは、このアプリケーション操作をサポートしていません" + return 1 + ;; + esac +} + +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "エラー: アプリケーションのメインコンテナ名が無効です" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "エラー: アプリケーションのメインコンテナが見つかりません${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "エラー: アプリケーション マスター コンテナを識別できません${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "エラー: メイン アプリケーション コンテナが変更されました。パネルを更新して再試行してください。" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "エラー: アプリケーション状態ファイル名が無効です" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "エラー: サポートされていないアプリケーション アクセス モード" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "エラー: サポートされていないアプリケーション アクセス モード" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "エラー: KPanel は有効なアプリケーション ポートを提供しませんでした" + return 1 + ;; + esac + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "エラー: KPanel アプリケーション ポートは 1 ~ 65535 でなければなりません" + return 1 + fi + if kpanel_app_port_in_use "$requested_port"; then + echo "エラー: ポート${requested_port}すでに占有されています" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}間違い:${gl_bai}ポート$app_portすでに占有されています。ポートを変更してください" + send_stats "アプリケーションポートが占有されています" + else + docker_port="$app_port" + return 0 + fi + done +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "エラー: KPanel では現在、非対話型インストールのみが許可されています" + return 1 + fi + + kpanel_app_progress 5 "ポートとホスト環境の確認" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "Docker実行環境の準備" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "kejilion.shアプリケーションインストール関数の実行" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "インストール失敗: アプリケーションステータスが登録されていません" + return 1 + fi + else + if ! docker_rum; then + echo "インストール失敗: アプリケーションステータスが登録されていません" + return 1 + fi + fi + + kpanel_app_progress 90 "kejilion.sh 互換性ステータスの書き込み" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "アプリケーションのインストールが完了しました" + echo "$docker_nameインストール完了" + return 0 +} + +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "エラー: KPanel はこのアプリケーション操作をサポートしていません" + return 1 + ;; + esac + + kpanel_app_progress 5 "kejilion.sh インストール フラグをメイン コンテナに対してチェックする" + service_name="$(kpanel_app_verified_service true)" || return 1 + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "エラー: kejilion.sh アプリケーション インストール タグが見つかりません" + return 1 + fi + kpanel_app_progress 10 "kejilion.sh アプリのインストールフラグを修正" + add_app_id || return 1 + fi + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "kejilion.sh ネイティブ更新関数の実行" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "アプリのアクセスポリシーを復元する" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "アプリケーションのアップデートが完了しました" + echo "$service_nameすでに更新されています" + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "kejilion.sh ネイティブ アンインストール機能の実行" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "エラー: アンインストール機能が完了した後もメイン コンテナがまだ存在します" + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "アプリケーションのアンインストールが完了しました" + echo "$service_nameアンインストールが完了しました" + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "エラー: KPanel は有効なアプリケーション アクセス モードを提供しません" + return 1 + ;; + esac + kpanel_app_progress 40 "kejilion.sh IP+ポートアクセスポリシーの実行" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "アプリケーション アクセス ポリシーの更新が完了しました" + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}管理" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action standard + return $? +fi + while true; do clear check_docker_app @@ -2887,30 +3406,30 @@ while true; do echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択肢を入力してください:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "選択肢を入力してください:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}間違い:${gl_bai}ポート$app_portすでに占有されています。ポートを変更してください" - send_stats "アプリケーションポートが占有されています" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}インストールに失敗しました:${gl_bai}アプリケーションコンテナの起動に失敗しました。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_nameインストール完了" @@ -2923,9 +3442,15 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}更新に失敗しました:${gl_bai}アプリケーションコンテナの再起動に失敗しました。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_nameインストール完了" @@ -2936,10 +3461,16 @@ while true; do send_stats "更新する$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}アンインストールに失敗しました:${gl_bai}アプリケーションコンテナを削除できませんでした。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "アプリがアンインストールされました" @@ -2952,27 +3483,33 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "ドメイン名の形式 example.com (https:// なし)" - web_del + web_del || action_status=1 ;; 7) send_stats "IPアクセスを許可する${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "IPアクセスをブロックする${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -2984,6 +3521,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action plus + return $? + fi while true; do clear check_docker_app @@ -3010,46 +3551,53 @@ docker_app_plus() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択内容を入力してください:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "選択内容を入力してください:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}間違い:${gl_bai}ポート$app_portすでに占有されています。ポートを変更してください" - send_stats "アプリケーションポートが占有されています" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_nameインストール" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + kpanel_app_write_access_mode direct + send_stats "$app_nameインストール" + else + echo -e "${gl_hong}インストールに失敗しました:${gl_bai}申請状況が登録されていません。上記のエラーを修正して再試行してください。" + action_status=1 + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_name更新する" + if docker_app_update; then + add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" + send_stats "$app_name更新する" + else + echo -e "${gl_hong}更新に失敗しました:${gl_bai}元のアプリケーションの登録ステータスは保持されます。" + action_status=1 + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_nameアンインストールする" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_nameアンインストールする" + else + echo -e "${gl_hong}アンインストールに失敗しました:${gl_bai}アプリケーションの登録状態は保持されています。" + action_status=1 + fi ;; 5) @@ -3059,25 +3607,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "ドメイン名の形式 example.com (https:// なし)" - web_del + web_del || action_status=1 ;; 7) send_stats "IPアクセスを許可する${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "IPアクセスをブロックする${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -3212,6 +3767,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH ジェイルが正しく起動できませんでした" >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban サービスはまだ実行中です" >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "使用法: k f2b [ステータス|有効|無効]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -3293,7 +3949,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロードしています..." + echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -3455,27 +4111,33 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "WordPress ドメイン名を既存のサイトで検証する" send_stats "インストール$webname" - echo "开始部署 $webname" + echo "導入を開始する$webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "kejilion.sh LDNMP環境の準備" ldnmp_install_status + kpanel_web_progress 35 "サイト証明書の発行と設定" install_ssltls certs_status + kpanel_web_progress 50 "WordPress データベースとアカウントの作成" add_db + kpanel_web_progress 60 "kejilion.sh WordPress Nginx 構成の取得" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "kejilion.sh WordPress ソース コードの取得と構成" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +4151,9 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "LDNMP の再起動と WordPress サイトの検証" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -3503,6 +4168,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "リバース プロキシ ドメイン名とアップストリーム アドレスの確認" send_stats "インストール$webname" echo "導入を開始する$webname" if [ -z "$yuming" ]; then @@ -3519,12 +4185,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "アンチジェネレーションポートを入力してください:" port fi + kpanel_web_progress 25 "kejilion.sh Nginx環境の準備" nginx_install_status + kpanel_web_progress 40 "リバースプロキシ証明書の発行と設定" install_ssltls certs_status + kpanel_web_progress 60 "kejilion.sh リバースプロキシ構成の取得" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3545,6 +4214,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "リバースプロキシ構成の確認と再ロード" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -4418,7 +5088,7 @@ frps_panel() { 8) send_stats "IPアクセスをブロックする" - echo "ドメイン名アクセスを反転している場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全です。" + echo "ドメイン名アクセスを逆にしている場合は、この機能を使用して IP+ポート アクセスをブロックすることができ、より安全になります。" read -e -p "ブロックするポートを入力してください:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -4823,6 +5493,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "エラー: /etc/resolv.conf は壊れたシンボリック リンクです" + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "エラー: DNS 構成ディレクトリが存在しません" + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "エラー: chattr が利用できないため、kejilion.sh DNS ライフサイクル セマンティクスを維持できません" + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "エラー: DNS 構成をロックできません" + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "エラー: 既存の DNS 構成のロックを解除できません" + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "エラー: DNS 書き込みに失敗し、ロールバックに失敗しました。手動チェックが必要です" + return 1 + } + rm -f "$desired" "$backup" + echo "エラー: DNS 書き込みまたはリードバック検証が失敗しました。元の構成が復元されました" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "エラー: systemctl は使用できません" + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "エラー: systemd で解決された DNS ロールバックが失敗しました。手動検査が必要です" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "エラー: systemd で解決された DNS はファイルを復元しましたが、サービスのリロードに失敗しました。手動検査が必要です" + return 1 + } + rm -f "$desired" "$backup" + echo "エラー: systemd で解決された DNS 書き込みまたはリードバック検証が失敗しました。元の構成が復元されました" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "エラー: KPanel DNS プロトコルは root として実行する必要があります" + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "エラー: DNS アドレスの数は 1 ~ 4 である必要があります" + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "エラー: DNS アドレスが空か長すぎます" + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "エラー: 最大 2 つの IPv4 DNS アドレス" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "エラー: IPv6 DNS アドレスは最大 2 つです" + return 1 + } + else + echo "エラー: DNS アドレスが無効です" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "エラー: DNS アドレスを繰り返すことはできません" + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -4938,7 +5848,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}ユーザーキーログインモードがオンになり、パスワードログインモードがオフになりました。再接続が有効になります。${gl_bai}" + echo -e "${gl_lv}ユーザーキーログインモードがオンになり、パスワードログインモードがオフになります。再接続が有効になります。${gl_bai}" } @@ -5138,7 +6048,7 @@ sshkey_panel() { echo -e "ユーザーキーログインモード${IS_KEY_ENABLED}" echo "高度なゲームプレイ: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH 経由でログインするためのより安全な方法のためにキー ペアが生成されます。" + echo "キーペアが生成され、SSH 経由でログインするためのより安全な方法になります。" echo "------------------------" echo "1. 新しいキーペアを生成します。 2. 既存の公開キーを手動で入力します。" echo "3. GitHub から既存の公開キーをインポートします。 4. URL から既存の公開キーをインポートします。" @@ -5215,7 +6125,7 @@ add_sshpasswd() { read -e -p "パスワードを変更するユーザー名を入力してください (デフォルトは root):" target_user fi - # Enter キーを押して入力しないでください。デフォルトは root です + # Enter キーを押します。入力しないでください。デフォルトは root です。 target_user=${target_user:-root} # ユーザーが存在することを確認する @@ -5476,7 +6386,7 @@ dd_xitong() { ;; 30) - send_stats "CentOS9を再インストールする" + send_stats "centos9を再インストールする" dd_xitong_3 bash reinstall.sh centos 9 reboot @@ -5595,9 +6505,131 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false status_line reboot_required=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "現在のホストは、KPanel BBRv3 制御の実行をサポートしていません" >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "XanMod BBRv3 カーネルがインストールされていないため、アップデートを実行できません" >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" + ;; + *) + echo "使用法: k bbrv3 [ステータス|インストール|更新|アンインストール]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3管理" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3管理" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -5624,7 +6656,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません、XanMod ソースを構成できません" + echo "システムコードネームを取得できません。XanMod ソースを構成できません" return 1 fi @@ -5726,7 +6758,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3 カーネル処理が完了しました。再起動後に有効になります" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -5736,9 +6768,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "XanMod カーネルがアンインストールされました。再起動後に有効になります" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -6158,7 +7195,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── 生放送シナリオ追加:UDPバッファ拡大 ── + # ── ライブブロードキャストシナリオの追加:UDPバッファの拡大 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -6380,7 +7417,7 @@ Kernel_optimize() { root_use while true; do clear - send_stats "Linux カーネルのチューニング管理" + send_stats "Linuxカーネルチューニング管理" local current_mode=$(grep "^# モード:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# モード: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="オートチューニングモード" echo "Linuxシステムのカーネルパラメータの最適化" @@ -6395,9 +7432,9 @@ Kernel_optimize() { echo -e "${gl_huang}ヒント:${gl_bai}本番環境では注意して使用してください。" echo -e "--------------------" echo -e "1. ハイパフォーマンス最適化モード: システムパフォーマンス、積極的なメモリ、およびネットワークパラメータを最大化します。" - echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常的な使用に適しています。" + echo -e "2. バランスのとれた最適化モード: パフォーマンスとリソース消費のバランスをとり、日常の使用に適しています。" echo -e "3. Web サイト最適化モード: Web サイトサーバー、超高同時接続キュー用に最適化されています。" - echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングを最適化するために、UDP バッファーを拡大して遅延を削減します。" + echo -e "4. ライブ ブロードキャスト最適化モード: ライブ ストリーミングの最適化では、遅延を減らすために UDP バッファーが拡大されます。" echo -e "5. ゲームサーバー最適化モード:低遅延を優先してゲームサーバーに最適化します。" echo -e "6. デフォルト設定の復元: システム設定をデフォルト構成に復元します。" echo -e "7. 自動チューニング: テストデータに基づいてカーネルパラメータを自動的にチューニングします。${gl_huang}★${gl_bai}" @@ -6423,7 +7460,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モード" + send_stats "ウェブサイト最適化モデル" ;; 4) cd ~ @@ -6522,7 +7559,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えてください" + send_stats "英語に切り替えて" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -6695,9 +7732,9 @@ send_stats "コマンドのお気に入り" bash <(curl -l -s ${gh_proxy}raw.githubusercontent.com/byJoey/cmdbox/refs/heads/main/install.sh) } -# バックアップを作成する +# バックアップの作成 create_backup() { - send_stats "バックアップを作成する" + send_stats "バックアップの作成" local TIMESTAMP=$(date +"%Y%m%d%H%M%S") # ユーザーにバックアップ ディレクトリの入力を求めるプロンプトを表示する @@ -6739,7 +7776,7 @@ create_backup() { echo "- $path" done - # バックアップを作成する + # バックアップの作成 echo "バックアップの作成$BACKUP_NAME..." install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" @@ -6827,7 +7864,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7150,8 +8187,8 @@ list_partitions() { # 永続的にマウントされたパーティション mount_partition() { - send_stats "パーティションをマウントする" - read -e -p "マウントするパーティションの名前を入力してください (例: sda1):" PARTITION + send_stats "パーティションのマウント" + read -e -p "マウントするパーティション名を入力してください (例: sda1):" PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" @@ -7192,7 +8229,7 @@ mount_partition() { return 1 fi - echo "パーティションが正常にマウントされました$MOUNT_POINT" + echo "パーティションは正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -7327,7 +8364,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7364,7 +8401,7 @@ add_task() { fi done - kj_ssh_read_port "SSH ポートを入力してください (デフォルトは 22):" "22" + kj_ssh_read_port "SSH ポート (デフォルトは 22) を入力してください:" "22" port="$KJ_SSH_PORT" if ! kj_ssh_read_auth "$KEY_DIR/${name}_sync.key"; then @@ -7496,7 +8533,7 @@ run_task() { # スケジュールされたタスクを作成する schedule_task() { - send_stats "同期のスケジュールされたタスクを追加する" + send_stats "同期スケジュールされたタスクを追加する" read -e -p "定期的に同期するタスク番号を入力してください:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -7586,7 +8623,7 @@ rsync_manager() { 0) break ;; *) echo "選択が無効です。もう一度お試しください。" ;; esac - read -e -p "Enter を押して続行します..." + read -e -p "続行するには Enter キーを押してください..." done } @@ -7648,7 +8685,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (実行時間 > 0) printf("%d 時間 ", 実行時間); printf("%d 分\n", run_ minutes)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d 時間 ", run_hours); printf("%d 分\n", run_ minutes)}') local timezone=$(current_timezone) @@ -7768,7 +8805,7 @@ linux_tools() { echo -e "${gl_kjlan}11. ${gl_bai}btop 最新の監視ツール${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}レンジャーファイル管理ツール" echo -e "${gl_kjlan}13. ${gl_bai}ncdu ディスク使用量表示ツール${gl_kjlan}14. ${gl_bai}fzf グローバル検索ツール" echo -e "${gl_kjlan}15. ${gl_bai}vim テキストエディタ${gl_kjlan}16. ${gl_bai}ナノテキストエディタ${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AIプログラミングアシスタント${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" @@ -7828,7 +8865,7 @@ linux_tools() { install iftop clear iftop - send_stats "iftop をインストールする" + send_stats "iftopをインストールする" ;; 7) clear @@ -8130,7 +9167,7 @@ docker_ssh_migration() { docker inspect "$c" > "$inspect_file" if is_compose_container "$c"; then - echo -e "${gl_kjlan}検出されました$cdocker-composeコンテナです${gl_bai}" + echo -e "${gl_kjlan}検出されました$cdocker-compose コンテナーです${gl_bai}" local project_dir=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project.working_dir"] // empty') local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') @@ -8140,7 +9177,7 @@ docker_ssh_migration() { # Compose プロジェクトがすでにパッケージ化されている場合は、スキップしてください if [[ -n "${PACKED_COMPOSE_PATHS[$project_dir]}" ]]; then - echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているので、繰り返しのパッケージ化をスキップします...${gl_bai}" + echo -e "${gl_huang}プロジェクトの作成 [$project_name] すでにバックアップされているため、繰り返しのパッケージ化をスキップします...${gl_bai}" continue fi @@ -8160,7 +9197,7 @@ docker_ssh_migration() { local VOL_PATHS VOL_PATHS=$(docker inspect "$c" --format '{{range .Mounts}}{{.Source}} {{end}}') for path in $VOL_PATHS; do - echo "梱包体積:$path" + echo "梱包量:$path" tar -czpf "${BACKUP_DIR}/${c}_$(basename $path).tar.gz" -C / "$(echo $path | sed 's/^\///')" done @@ -8307,7 +9344,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}共通コンテナのバックアップ情報が見つかりません${gl_bai}" - # /home/docker 下のファイルを復元する + # /home/docker 下のファイルを復元します if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}/home/docker の下にファイルを復元しています...${gl_bai}" mkdir -p /home/docker @@ -8339,7 +9376,7 @@ docker_ssh_migration() { echo -e "${gl_huang}バックアップを転送中...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # キーでログイン + # キーを使用してログインする scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8413,7 +9450,7 @@ linux_docker() { echo -e "${gl_kjlan}5. ${gl_bai}Dockerネットワーク管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker ボリューム管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします" + echo -e "${gl_kjlan}7. ${gl_bai}不要な Docker コンテナをクリーンアップし、ネットワーク データ ボリュームをミラーリングします。" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Dockerソースを変更する" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json ファイルを編集する" @@ -8685,6 +9722,180 @@ linux_docker() { +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} + +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPTロック解除状態検出" + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh + ;; + region) + send_stats "リージョンストリーミングメディアロック解除テスト" + kpanel_run_remote_bash https://check.unlock.media + ;; + media) + send_stats "Yeawu ストリーミング メディアのロック解除の検出" + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh + ;; + ip-quality) + send_stats "xykt_IP 品質チェック スクリプト" + kpanel_run_remote_bash https://IP.Check.Place + ;; + besttrace) + send_stats "besttrace トリプル ネットワーク バックホール遅延ルーティング テスト" + kpanel_run_remote_bash https://git.io/besttrace + ;; + mtr) + send_stats "mtr_trace トリプルネットワークバックホール回線テスト" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh + ;; + superspeed) + send_stats "超高速トリプルネットワーク速度テスト" + kpanel_run_remote_bash https://git.io/superspeed_uxh + ;; + nxtrace-fast) + send_stats "nxtrace 高速バックホール テスト スクリプト" + kpanel_run_remote_bash https://nxtrace.org/nt + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020 3つのネットワーク回線テスト" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh + ;; + speedtest) + send_stats "i-abc 多機能速度テスト スクリプト" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh + ;; + net-quality) + send_stats "ネットワーク品質テストスクリプト" + kpanel_run_remote_bash https://Net.Check.Place + ;; + tcp-quality) + send_stats "TcpQuality TCP 再送検出スクリプト" + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh + ;; + yabs) + send_stats "yabsパフォーマンステスト" + check_swap + kpanel_run_remote_bash https://yabs.sh -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU パフォーマンステストスクリプト" + check_swap + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh + ;; + bench) + send_stats "ベンチパフォーマンステスト" + kpanel_run_remote_bash https://bench.sh + ;; + ecs) + send_stats "Spiritysdx フュージョンモンスター レビュー" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "ノードクオリティ融合モンスターの評価" + kpanel_run_remote_bash https://run.NodeQuality.com + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac +} + + linux_test() { while true; do @@ -8906,7 +10117,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9075,9 +10286,577 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "使用法: k <ドメイン名>" + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "既存の Web サイトまたは LDNMP 環境タスクが実行されている" >&2 + exec {lock_fd}>&- + return 75 + fi + linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","re​​quired":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","re​​poDigest":"%s","updateStatus":"unknown","updateReason":"レジストリ ステータスは更新タスク中にリアルタイムでのみ確認されます"}' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"Full LDNMP"},{"id":"nginx","label":"Only Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudfl are-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on ","zstd-off"],"updateComponents":[{"id":"nginx","versions":["最新"]},{"id":"mysql","versions":["最新","8.0","8.3","8.4","9.0"] },{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["最新"]},{"id":"すべて","バージョン":["最新"]}]}' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "設置条件の確認" + case "$profile" in + full) kpanel_ldnmp_event install 15 "完全な LDNMP のインストール"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "nginxのインストール"; nginx_install_all ;; + *) echo "サポートされていないインストール形式" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "環境の検証" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare認証情報チャネルが無効です" >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "サポートされていない保護アクション" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "保護構成の検証に失敗したため、元の構成が復元されています。" + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "現在のプロトコルはこの最適化アクションをサポートしていません" >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "最適化の検証が失敗したため、元の構成が復元されています。" + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "アップデート前のコールドスタンバイの作成" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "サポートされていないアップデートコンポーネント" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "LDNMP を一時的に停止する" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "アーカイブ /ホーム/ウェブ" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "LDNMP の復元" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "バックアップ アーカイブのスキャン" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "安全なステージング ディレクトリに抽出しています" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "/home/web にアトミックに切り替える" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "既存の Web サイトまたは LDNMP 環境タスクが実行されている" + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP環境タスクが開始されました" + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP環境タスクが完了しました" + kpanel_ldnmp_result succeeded "$action" "タスクの実行が成功しました" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP環境タスクの実行に失敗しました" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "タスクが失敗し、安全なロールバックが確認できなかったため、手動処理が必要でした。" + else + kpanel_ldnmp_result failed "$action" "タスクの実行に失敗しました" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP環境管理" + echo "------------------------" + echo "1. 環境の状態を確認する" + echo "2. 完全な LDNMP をインストールする" + echo "3. Nginxのみをインストールする" + echo "4. 保護管理" + echo "5. 管理の最適化" + echo "6. 環境のアップデート" + echo "7. コールドスタンバイの作成" + echo "8. バックアップを復元する" + echo "9. 環境をアンインストールする" + echo "0.戻る" + echo "------------------------" + read -e -p "選択肢を入力してください:" choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "コンポーネントを更新します (nginx/mysql/php/redis/all):" component + read -e -p "ターゲット バージョン (デフォルトは最新):" version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "復元するバックアップ ファイル名を入力します:" backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "DELETE と入力して、LDNMP 環境のアンインストールを確認します。" confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "無効な入力" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "サポートされていないLDNMP環境コマンド" >&2; return 2 ;; + esac +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP Web サイトの構築" echo -e "${gl_huang}LDNMP Web サイトの構築" @@ -9103,7 +10882,42 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "選択肢を入力してください:" sub_choice + fi + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; + *) + echo "KPANEL_PROGRESS 100 サポートされていません KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN は有効なドメイン名ではありません" + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 ドメイン名はすでに存在しており、既存の製品の上書きを拒否しています" + return 1 + fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST は有効な IP またはホスト名ではありません" + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT は有効なポートではありません" + return 1 + fi + fi + echo "KPANEL_PROGRESS 5 は、kejilion.sh ネイティブのワンクリック Web サイト構築プロセスを開始しています" + else + read -e -p "選択肢を入力してください:" sub_choice + fi case $sub_choice in @@ -9112,7 +10926,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9138,7 +10952,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9147,6 +10961,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9181,13 +10996,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9222,7 +11038,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9231,6 +11047,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9271,10 +11088,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9296,7 +11114,7 @@ linux_ldnmp() { echo "パスワード: 管理者" echo "------------------------" echo "ログイン時に右上隅に赤色の error0 が表示される場合は、次のコマンドを使用してください。" - echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、問題が多いのか、とても腹が立っています。" + echo "私も、なぜユニコーンナンバーカードがこんなに面倒で、こんな問題を抱えているのか、とても腹が立っています。" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -9327,7 +11145,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9349,6 +11167,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9386,12 +11205,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9429,12 +11249,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9467,7 +11288,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9566,6 +11387,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9613,7 +11435,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -9706,14 +11528,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9748,7 +11570,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9776,7 +11598,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -10078,6 +11900,23 @@ linux_ldnmp() { *) echo "無効な入力です!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh Web サイト構築製品は不完全です" + return 1 + fi + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh Web サイト構築製品は不完全です" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx 構成の検証に失敗しました" + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh ネイティブ Web サイト構築製品が完了しました" + return 0 + fi break_end done @@ -10164,7 +12003,7 @@ moltbot_menu() { echo "10. メイン設定ファイルを編集します" echo "11. 設定ウィザード" echo "12. 健全性の検出と修復" - echo "13. WebUI访问与设置" + echo "13. WebUI へのアクセスと設定" echo "14. TUIコマンドラインダイアログウィンドウ" echo "15. 記憶・記憶" echo "16. 権限管理" @@ -10357,7 +12196,7 @@ def rebind_defaults_before_delete(name): if ref_provider(val) == name: repl = get_replacement() if not repl: - summary.append(f'❌ {name}: {fk} はプロバイダーを指しますが、使用可能な代替モデルがないため、削除は中止されました') + summary.append(f'❌ {name}: {fk} はプロバイダーを指していますが、利用可能な代替モデルがないため、削除は中止されました') return False defaults[fk] = repl changed = True @@ -10436,7 +12275,7 @@ for name, provider in list(providers.items()): deleted = delete_provider_and_refs(name) if deleted: send_stat('OpenClaw API の削除に失敗しましたプロバイダー確認') - summary.append(f'✅ {name}: ユーザーはプロバイダーと関連するすべてのモデル参照を削除することを確認しました') + summary.append(f'✅ {name}: ユーザーはプロバイダーとすべての関連モデル参照を削除することを確認しました') else: send_stat('OpenClaw API の削除に失敗しましたプロバイダーによって拒否されました') summary.append(f'ℹ️ {name}: ユーザーは削除を確認しておらず、既存のプロバイダー構成を保持しています。') @@ -10456,7 +12295,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} の上流の /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') + fatal_errors.append(f'❌ {name} の上流 /models は空であるため、このプロバイダーにボトムアップ モデルを提供できません。') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -11125,7 +12964,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ プロバイダー {target} は現在 api={api} ですが、スクリプトはプロトコルを検出/修正しなくなりました。手動で openai-completions または openai-responses に設定してください。') + print(f'ℹ️ プロバイダー {target} の現在の api={api} ですが、スクリプトはプロトコルを検出/修正しなくなりました。手動で openai-completions または openai-responses に設定してください。') protocol_msg = None @@ -11230,7 +13069,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行が完了しました" + echo "✅ 同期実行完了" start_gateway ;; 2) @@ -11246,7 +13085,7 @@ PY2 echo "❌ 同期に失敗しました: 上流モデルが空であるか、同期後に使用可能なモデルがありません" ;; *) - echo "❌ 同期に失敗しました: 設定ファイルの構造またはログ出力を確認してください。" + echo "❌ 同期に失敗しました: 構成ファイルの構造またはログ出力を確認してください。" ;; esac @@ -12281,7 +14120,7 @@ PYTHON_EOF rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードに成功しました。アクティブ化しています..." + echo "✅ ダウンロードが成功しました。アクティブ化されています..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12294,7 +14133,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "🗑️ 正在删除/禁用插件: $plugin_id" + echo "🗑️ プラグインの削除/無効化:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then echo "✅ アンインストール済み:$plugin_id" @@ -12314,7 +14153,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." start_gateway fi break_end @@ -12344,8 +14183,8 @@ PYTHON_EOF echo "things-mac # Things 3 タスク管理の緊密な統合" echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" - echo "要約 # Web ページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンの制御" + echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" + echo "openhue # Philips Hue スマート照明シーンを制御する" echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" @@ -12432,7 +14271,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." + echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." start_gateway fi break_end @@ -12697,7 +14536,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -13061,7 +14900,7 @@ if os.path.isdir(agents_root): rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "✅ OpenClaw 项目还原完成" + echo "✅ OpenClaw プロジェクトの復元が完了しました" break_end } @@ -13472,7 +15311,7 @@ for entry in data: first = False print("Agent: %s" % agent_id) backend = s.get("backend") or s.get("provider") or "-" - print("基本的なソリューション: %s" % backend) + print("基礎となるソリューション: %s" % backend) files = s.get("files", 0) chunks = s.get("chunks", 0) print("含まれるもの: %s ファイル / %s ブロック" % (files, chunks)) @@ -13589,7 +15428,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com にアクセスできます") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com にアクセスできない可能性があります (国内/制限付きネットワークの疑い)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com にアクセスできない可能性があります (国内/制限されたネットワークの疑い)") fi if [ "$qmd_ok" = "true" ]; then @@ -14041,7 +15880,7 @@ EOF } openclaw_memory_offer_restart() { - echo "設定は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" + echo "構成は書き込まれており、OpenClaw ゲートウェイの再起動後に有効にするには、再起動する必要があります。" read -e -p "今すぐ OpenClaw ゲートウェイを再起動しますか? (はい/いいえ):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "再起動はスキップされました。後で実行できます: openclaw ゲートウェイの再起動" @@ -14203,9 +16042,9 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "合計行数:$total_lines" + echo "総行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line - read -e -p "表示する行数を入力してください (デフォルトでは Enter を押します)$default_lines): " count + read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -14406,7 +16245,7 @@ EOF config_file=$(openclaw_permission_config_file) backup_file=$(openclaw_permission_backup_file) if [ ! -s "$backup_file" ]; then - echo "❌ 未找到可恢复的权限备份文件。" + echo "❌ 復元可能な権限のバックアップ ファイルが見つかりません。" return 1 fi cp -f "$backup_file" "$config_file" >/dev/null 2>&1 || { @@ -14423,7 +16262,7 @@ EOF echo "❌ OpenClaw が検出されず、OpenClaw Gateway を再起動できません。" return 1 fi - echo "正在重启 OpenClaw Gateway..." + echo "OpenClaw ゲートウェイを再起動しています..." openclaw gateway restart >/dev/null 2>&1 || { openclaw gateway stop >/dev/null 2>&1 openclaw gateway start >/dev/null 2>&1 @@ -14613,7 +16452,7 @@ print(json.dumps(data, indent=2)) fi echo -e "現在の包括的なセキュリティ レベル:${current_mode}" echo "---------------------------------------" - echo -e "${gl_huang}[アプリケーション層ツールのポリシーステータス]${gl_bai}" + echo -e "${gl_huang}[アプリケーション層ツールのポリシーのステータス]${gl_bai}" echo "プロファイル (デフォルト): ${current_profile:-(未設定)}" echo "実行制限: ${current_sec:-(未設定)}" echo "承認プロンプト: ${current_ask:-(unset)}" @@ -14682,7 +16521,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 標準の安全モードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" + echo -e "${gl_lv}✅ 標準セーフティモードに切り替えられました (すべての危険なコマンドは UI/TG を通じて承認を求めます)${gl_bai}" } openclaw_permission_apply_developer() { @@ -14700,7 +16539,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには引き続き承認が必要です)${gl_bai}" + echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには依然として承認が必要です)${gl_bai}" } openclaw_permission_apply_full() { @@ -15389,7 +17228,7 @@ openclaw_backup_restore_menu() { } nano_openclaw_json() { - send_stats "OpenClaw 設定ファイルを編集する" + send_stats "OpenClaw 構成ファイルを編集する" install nano nano "$(openclaw_get_config_file)" start_gateway @@ -15577,21 +17416,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}間違い:${gl_bai}${apps_dir}すでに存在しますが、App Market Git リポジトリではないため、上書きは拒否されます。" + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}アプリケーション リストのダウンロードが失敗し、不完全な構成が拒否されました。${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}アプリケーション リストの更新が失敗し、期限切れの可能性がある構成の使用を継続できませんでした。${gl_bai}" + echo "ネットワークを確認するか、${apps_dir}ローカルで変更した後、再試行してください。" + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}アプリケーションリストは更新中です。お待ちください...${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -15613,7 +17468,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}パゴダパネル正式版${gl_kjlan}2. ${color2}aaPanel パゴダ国際版" echo -e "${gl_kjlan}3. ${color3}1Panel 新世代管理パネル${gl_kjlan}4. ${color4}NginxProxyManager 視覚化パネル" - echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web バージョン" + echo -e "${gl_kjlan}5. ${color5}OpenList マルチストア ファイル リスト プログラム${gl_kjlan}6. ${color6}Ubuntu リモート デスクトップ Web エディション" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" @@ -15661,7 +17516,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" - echo -e "${gl_kjlan}85. ${color85}イミッチ・ピクチャー・ビデオ・マネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" + echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" @@ -15691,7 +17546,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") # インストールステータスを確認します (appno.txt の ID と一致します)。 - # ここでは、appno.txtに記録されているのはbase_name(つまりファイル名)であると仮定します。 + # ここで、appno.txtに記録されているのはbase_name(つまりファイル名)であると仮定します。 if echo "$app_numbers" | grep -q "^$base_name$"; then # インストールされている場合: showbase_name - description [インストール済み] (緑色) echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[インストール済み]${gl_bai}" @@ -16849,7 +18704,7 @@ while true; do local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo 「アカウント: admin パスワード: a123456」" + local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -17481,7 +19336,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -17694,7 +19549,7 @@ while true; do } - local docker_describe="オープンソースの AI チャットボット フレームワーク。WeChat、QQ、TG による AI の大規模モデルへのアクセスをサポート" + local docker_describe="オープンソース AI チャットボット フレームワーク。WeChat、QQ、TG による大規模 AI モデルへのアクセスをサポート" local docker_url="公式サイト紹介:https://astrbot.app/" local docker_use="echo \"ユーザー名: astrbot パスワード: astrbot\"" local docker_passwd="" @@ -17998,7 +19853,7 @@ while true; do local app_id="80" local app_name="リンクワーデンのブックマーク管理" - local app_text="タグ付け、検索、チームコラボレーションをサポートする、オープンソースの自己ホスト型ブックマーク管理プラットフォーム。" + local app_text="タグ付け、検索、チーム コラボレーションをサポートする、オープン ソースの自己ホスト型ブックマーク管理プラットフォーム。" local app_url="公式サイト:https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -18225,7 +20080,7 @@ while true; do 85|immich) local app_id="85" - local app_name="イミッチ・ピクチャー・ビデオ・マネージャー" + local app_name="イミッチピクチャービデオマネージャー" local app_text="高性能の自己ホスト型写真およびビデオ管理ソリューション。" local app_url="公式サイト紹介:${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" @@ -18319,7 +20174,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -18587,7 +20442,7 @@ while true; do local app_id="95" local app_name="ペーパーレス文書管理プラットフォーム" - local app_text="オープンソースの電子文書管理システムであり、その主な目的は紙文書をデジタル化して管理することです。" + local app_text="オープンソースの電子文書管理システムであり、その主な目的は紙の文書をデジタル化して管理することです。" local app_url="ビデオ紹介: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" @@ -18950,7 +20805,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -19433,15 +21288,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" @@ -19450,6 +21297,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" @@ -19804,7 +21657,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -19814,7 +21667,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -19826,7 +21679,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -19877,7 +21730,7 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 2) send_stats "指定したサービスログを表示する" @@ -19887,7 +21740,7 @@ log_menu() { else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -19902,7 +21755,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -19990,7 +21843,7 @@ env_menu() { echo echo "===============================================" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } @@ -20005,7 +21858,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } edit_file() { @@ -20021,7 +21874,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "Enter を押して続行します..." + read -erp "続行するには Enter キーを押してください..." } while true; do @@ -20149,7 +22002,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -20613,7 +22466,7 @@ EOF # 現在のシステムのタイムゾーンを取得する local timezone=$(current_timezone) - # 現在のシステム時刻を取得する + # 現在のシステム時刻を取得します local current_time=$(date +"%Y-%m-%d %H:%M:%S") # タイムゾーンと時間を表示する @@ -20633,7 +22486,7 @@ EOF echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" echo "13. ベルリン、ドイツ時間 14. モスクワ、ロシア時間" - echo "15. ユトラハト時間、オランダ 16. マドリッド時間、スペイン" + echo "15. ユトレヒト時間、オランダ 16. マドリッド時間、スペイン" echo "------------------------" echo "アメリカ" echo "21. 米国西部時間 22. 米国東部時間" @@ -21108,7 +22961,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -21543,7 +23396,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスタ${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -21581,7 +23434,7 @@ while true; do 4) clear - send_stats "バックアップクラスタ" + send_stats "バックアップクラスター" echo -e "変更してください${gl_huang}/root/cluster/servers.py${gl_bai}ファイルをダウンロードしてバックアップを完了してください。" break_end ;; @@ -21662,7 +23515,7 @@ echo "------------------------" echo -e "${gl_lan}DMIT 四半期あたり 28 ドル 米国 CN2GIA 1 コア 2G メモリ 20G ハード ドライブ 1 か月あたり 800G トラフィック${gl_bai}" echo -e "${gl_bai}URL: https://www.dmit.io/aff.php?aff=4966&pid=100${gl_bai}" echo "------------------------" -echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額トラフィック 1T${gl_bai}" +echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" @@ -21851,7 +23704,7 @@ while true; do if [ -n "$cron_sed_cmd" ]; then SH_Update_task="$SH_Update_task && $cron_sed_cmd" fi - # 古いスクリプトからpermission_grantedおよびENABLE_STATS設定を復元します。 + # 古いスクリプトからpermission_grantedおよびENABLE_STATS設定を復元します SH_Update_task="$SH_Update_task && grep -q 'permission_granted=\"true\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" # /usr/local/bin/k および /usr/bin/k にデプロイします SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" @@ -21985,14 +23838,14 @@ echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xx echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" +echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" echo "コマンド お気に入り k お気に入り | k コマンドのお気に入り" echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" -echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b" +echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b [ステータス|有効|無効]" echo "システム情報を表示 k info" echo "ROOT キー管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " @@ -22028,7 +23881,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize @@ -22061,6 +23919,66 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" + ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" ;; fd|rp|反代) shift @@ -22097,6 +24015,20 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open @@ -22205,8 +24137,14 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "環境" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "消去" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then @@ -22234,7 +24172,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 91622aa62..10026e4ad 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.4" gl_hui='\e[37m' @@ -16,6 +16,18 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +kpanel_protocol_active() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -63,7 +75,7 @@ CheckFirstRun_true() { -# 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 시스템 국가 및 기능 이름을 기록하는 기능입니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! +# 함수에 묻혀있는 정보를 수집하고 사용자가 사용하는 현재 스크립트 버전 번호, 사용 시간, 시스템 버전, CPU 아키텍처, 기기 국가 및 기능 이름을 기록하는 기능입니다. 민감한 정보는 포함되어 있지 않으니 걱정하지 마세요! 저를 믿어주세요! # 이 기능은 왜 설계되었나요? 그 목적은 사용자가 사용하고 싶어하는 기능을 더 잘 이해하고, 기능을 더욱 최적화하고 사용자 요구에 맞는 더 많은 기능을 출시하는 것입니다. # send_stats 함수 호출 위치에 대한 전문을 검색할 수 있습니다. 투명하고 오픈 소스입니다. 우려되는 사항이 있는 경우 이용을 거부하실 수 있습니다. @@ -100,17 +112,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 - -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -141,7 +154,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi @@ -508,22 +523,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername docker restart $dockername ;; 6) @@ -1268,7 +1283,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 생성해야 하는지 결정 +# 가상 메모리를 만들어야 하는지 확인 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1322,7 +1337,7 @@ install_ldnmp_conf() { wget -O /home/web/docker-compose.yml ${gh_proxy}raw.githubusercontent.com/kejilion/docker/main/LNMP-docker-compose-10.yml dbrootpasswd=$(openssl rand -base64 16) ; dbuse=$(openssl rand -hex 4) ; dbusepasswd=$(openssl rand -base64 8) - # docker-compose.yml 파일에서 바꾸기 + # docker-compose.yml 파일에서 교체 sed -i "s#webroot#$dbrootpasswd#g" /home/web/docker-compose.yml sed -i "s#kejilionYYDS#$dbusepasswd#g" /home/web/docker-compose.yml sed -i "s#kejilion#$dbuse#g" /home/web/docker-compose.yml @@ -1361,7 +1376,7 @@ auto_optimize_dns() { # 국가 코드(예: CN, US 등)를 가져옵니다. local country=$(curl -s ipinfo.io/country) - # 국가별 DNS 설정 + # 국가에 따라 DNS 설정 if [ "$country" = "CN" ]; then local dns1_ipv4="223.5.5.5" local dns2_ipv4="183.60.83.19" @@ -1540,11 +1555,16 @@ certs_status() { send_stats "도메인 이름 인증서 신청이 성공했습니다." else send_stats "도메인 이름 인증서 신청 실패" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then + echo "KPANEL_PROGRESS 100 도메인 이름 인증서 신청에 실패했습니다. DNS, 80/443 포트 및 발급 할당량을 확인하십시오." + return 1 + fi echo -e "${gl_hong}알아채다:${gl_bai}인증서 신청이 실패했습니다. 다음 가능한 이유를 확인하고 다시 시도하십시오." echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." - echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." + echo -e "4. 방화벽 제한 사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" @@ -1618,6 +1638,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "도메인 이름 재사용" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 도메인 이름이 이미 존재하므로 kejilion.sh 또는 KPanel의 기존 제품 덮어쓰기를 거부합니다." + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1649,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN은 유효한 도메인 이름이 아닙니다." + return 1 + fi + return 0 + fi ip_address echo -e "먼저 도메인 이름을 로컬 IP로 확인합니다.${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "귀하의 IP 또는 확인된 도메인 이름을 입력하십시오:" yuming @@ -1676,6 +1709,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "잘못된 사이트 디렉터리 이름:$site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "사이트 디렉토리가 존재하지 않습니다:$site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -1786,32 +1853,72 @@ web_cache() { web_del() { send_stats "사이트 데이터 삭제" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "잘못된 도메인 이름, 삭제가 거부됨:$yuming" + action_status=1 + continue + fi + echo "도메인 이름을 삭제하는 중입니다:$yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # 도메인 이름을 데이터베이스 이름으로 변환 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "데이터베이스 삭제 중:$dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # 오류를 방지하려면 데이터베이스를 삭제하기 전에 데이터베이스가 존재하는지 확인하세요. - echo "데이터베이스 삭제 중:$dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "사이트 제품 삭제가 완료되지 않았습니다.$yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx 구성 확인 또는 다시 로드에 실패했습니다." + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -2238,7 +2345,7 @@ web_security() { 22) send_stats "고부하로 5초 쉴드 가능" - echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 고부하를 감지하면 자동으로 실드를 열고, 저부하를 감지하면 자동으로 5초 동안 실드를 닫습니다.${gl_bai}" + echo -e "${gl_huang}웹사이트는 5분마다 자동으로 감지합니다. 높은 부하를 감지하면 자동으로 쉴드가 열리고, 낮은 부하가 감지되면 자동으로 5초 동안 쉴드가 닫힙니다.${gl_bai}" echo "--------------" echo "CF 매개변수 가져오기:" echo -e "cf 백엔드 오른쪽 상단에 있는 내 프로필로 이동하여 왼쪽에 있는 API 토큰을 선택하고${gl_huang}Global API Key${gl_bai}" @@ -2344,8 +2451,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "지원되지 않는 LDNMP 최적화 모드" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "LDNMP 환경이 고성능 모드로 설정되었습니다." + else + optimize_balanced + echo "LDNMP 환경이 표준 모드로 설정되었습니다." + fi +} web_optimization() { while true; do @@ -2367,83 +2532,11 @@ web_optimization() { case $sub_choice in 1) send_stats "사이트 표준 모드" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # PHP 튜닝 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # PHP 튜닝 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # MySQL 튜닝 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "LDNMP 환경이 표준 모드로 설정되었습니다." - + ldnmp_optimization_mode standard ;; 2) send_stats "사이트 고성능 모드" - - # nginx 튜닝 - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # PHP 튜닝 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # PHP 튜닝 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # MySQL 튜닝 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "LDNMP 환경이 고성능 모드로 설정되었습니다." - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -2544,19 +2637,18 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 지역점검 - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. 로컬 미러 정보 얻기 - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. 컨테이너 및 로컬 이미지 정보를 획득합니다. 업데이트 감지는 더 이상 지역별로 건너뛰지 않습니다. + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 지능형 라우팅 판단 + # 2. 지능형 라우팅 판단 if [[ "$full_image_name" == ghcr.io* ]]; then # --- 시나리오 A: GitHub(ghcr.io)의 미러링 --- # 웨어하우스 경로를 추출합니다(예: ghcr.io/onexru/oneimg -> onexru/oneimg). @@ -2572,19 +2664,45 @@ check_docker_image_update() { else # --- 시나리오 C: 표준 Docker 허브 --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" + fi + return + fi fi - # 4. 타임스탬프 비교 + # 3. 레지스트리가 비교 가능한 요약을 제공하지 않는 경우 이는 릴리스 시간 판단과 일치합니다. if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" fi fi @@ -2789,7 +2907,7 @@ clear_host_port_rules() { install iptables - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p tcp --dport "$port" -j DROP fi @@ -2805,7 +2923,7 @@ clear_host_port_rules() { fi - # 다른 모든 IP의 접근을 차단하는 규칙을 삭제하세요. + # 다른 모든 IP의 접근을 차단하는 규칙을 해제하세요. if iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -D INPUT -p udp --dport "$port" -j DROP fi @@ -2857,11 +2975,412 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi + read -r -e -p "선택사항을 입력하세요:" selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "오류: KPanel 애플리케이션 관리 터미널은 메뉴 번호만 허용합니다." + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "오류: KPanel이 유효한 애플리케이션 액세스 모드를 제공하지 않습니다." + return 1 + ;; + esac + ;; + *) + echo "오류: KPanel 대화형 터미널은 이 애플리케이션 작업을 지원하지 않습니다." + return 1 + ;; + esac +} + +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "오류: 잘못된 애플리케이션 기본 컨테이너 이름" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "오류: 애플리케이션 기본 컨테이너를 찾을 수 없습니다.${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "오류: 애플리케이션 마스터 컨테이너를 식별할 수 없습니다.${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "오류: 기본 애플리케이션 컨테이너가 변경되었습니다. 패널을 새로 고치고 다시 시도하십시오." >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "오류: 잘못된 애플리케이션 상태 파일 이름" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "오류: 지원되지 않는 애플리케이션 액세스 모드" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "오류: 지원되지 않는 애플리케이션 액세스 모드" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "오류: KPanel이 유효한 애플리케이션 포트를 제공하지 않았습니다." + return 1 + ;; + esac + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "오류: KPanel 애플리케이션 포트는 1-65535 사이여야 합니다." + return 1 + fi + if kpanel_app_port_in_use "$requested_port"; then + echo "오류: 포트${requested_port}이미 점유되어 있습니다" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter 키를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." + send_stats "애플리케이션 포트가 점유되어 있습니다." + else + docker_port="$app_port" + return 0 + fi + done +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "오류: KPanel은 현재 비대화형 설치만 허용합니다." + return 1 + fi + + kpanel_app_progress 5 "포트 및 호스트 환경 확인" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "Docker 런타임 환경 준비" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "kejilion.sh 애플리케이션 설치 기능 실행" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "설치 실패: 애플리케이션 상태가 등록되지 않았습니다." + return 1 + fi + else + if ! docker_rum; then + echo "설치 실패: 애플리케이션 상태가 등록되지 않았습니다." + return 1 + fi + fi + + kpanel_app_progress 90 "kejilion.sh 호환성 상태 작성 중" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "애플리케이션 설치 완료" + echo "$docker_name설치 완료" + return 0 +} + +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "오류: KPanel은 이 애플리케이션 작업을 지원하지 않습니다." + return 1 + ;; + esac + + kpanel_app_progress 5 "메인 컨테이너에 대해 kejilion.sh 설치 플래그 확인" + service_name="$(kpanel_app_verified_service true)" || return 1 + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "오류: kejilion.sh 애플리케이션 설치 태그를 찾을 수 없습니다." + return 1 + fi + kpanel_app_progress 10 "kejilion.sh 앱 설치 플래그 수정" + add_app_id || return 1 + fi + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "kejilion.sh 네이티브 업데이트 기능 실행" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "앱 액세스 정책 복원 중" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "애플리케이션 업데이트 완료" + echo "$service_name이미 업데이트되었습니다." + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "kejilion.sh 기본 제거 기능 실행" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "오류: 제거 기능이 완료된 후에도 기본 컨테이너가 여전히 존재합니다." + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "애플리케이션 제거가 완료되었습니다." + echo "$service_name제거가 완료되었습니다." + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "오류: KPanel이 유효한 애플리케이션 액세스 모드를 제공하지 않습니다." + return 1 + ;; + esac + kpanel_app_progress 40 "kejilion.sh IP+포트 접근 정책 실행" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "애플리케이션 액세스 정책 업데이트가 완료되었습니다." + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}관리하다" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action standard + return $? +fi + while true; do clear check_docker_app @@ -2887,30 +3406,30 @@ while true; do echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "선택사항을 입력하세요:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." - send_stats "애플리케이션 포트가 점유되어 있습니다." - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}설치 실패:${gl_bai}애플리케이션 컨테이너를 시작하지 못했습니다." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_name설치 완료" @@ -2923,9 +3442,15 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}업데이트 실패:${gl_bai}애플리케이션 컨테이너를 다시 시작하지 못했습니다." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_name설치 완료" @@ -2936,10 +3461,16 @@ while true; do send_stats "고쳐 쓰다$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}제거 실패:${gl_bai}애플리케이션 컨테이너를 삭제할 수 없습니다." + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "앱이 제거되었습니다." @@ -2952,27 +3483,33 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "https://가 없는 도메인 이름 형식 example.com" - web_del + web_del || action_status=1 ;; 7) send_stats "IP 액세스 허용${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "IP 접근 차단${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -2984,6 +3521,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action plus + return $? + fi while true; do clear check_docker_app @@ -3010,46 +3551,53 @@ docker_app_plus() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택 항목을 입력하세요." choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "선택 항목을 입력하세요." choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "애플리케이션 외부 서비스 포트를 입력하고 Enter를 누르면 기본적으로 사용됩니다.${docker_port}포트:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}실수:${gl_bai}포트$app_port이미 사용 중입니다. 포트를 변경하세요." - send_stats "애플리케이션 포트가 점유되어 있습니다." - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_name설치하다" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + kpanel_app_write_access_mode direct + send_stats "$app_name설치하다" + else + echo -e "${gl_hong}설치 실패:${gl_bai}신청상황이 등록되지 않았습니다. 위의 오류를 수정한 후 다시 시도해 주세요." + action_status=1 + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_name고쳐 쓰다" + if docker_app_update; then + add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" + send_stats "$app_name고쳐 쓰다" + else + echo -e "${gl_hong}업데이트 실패:${gl_bai}원래 애플리케이션 등록 상태가 유지되었습니다." + action_status=1 + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name제거" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_name제거" + else + echo -e "${gl_hong}제거 실패:${gl_bai}애플리케이션 등록 상태가 유지되었습니다." + action_status=1 + fi ;; 5) @@ -3059,25 +3607,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "https://가 없는 도메인 이름 형식 example.com" - web_del + web_del || action_status=1 ;; 7) send_stats "IP 액세스 허용${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "IP 접근 차단${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -3212,6 +3767,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH 감옥이 제대로 시작되지 않았습니다." >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban 서비스가 아직 실행 중입니다." >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "사용법: k f2b [상태|활성화|비활성화]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -3231,7 +3887,7 @@ f2b_basic_config() { install nano if ! command -v fail2ban-client >/dev/null 2>&1; then - echo -e "${gl_hui}FAIL2BAN-클라이언트가 감지되지 않습니다. 먼저 Fail2ban을 설치하십시오.${gl_bai}" + echo -e "${gl_hui}failure2ban-client가 감지되지 않습니다. 먼저 fall2ban을 설치하십시오.${gl_bai}" return fi @@ -3426,7 +4082,7 @@ ldnmp_web_on() { echo "당신의$webname건설되었습니다!" echo "https://$yuming" echo "------------------------" - echo "$webname설치 정보는 다음과 같습니다." + echo "$webname설치정보는 다음과 같습니다." } @@ -3455,27 +4111,33 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "기존 사이트로 WordPress 도메인 이름 확인" send_stats "설치하다$webname" echo "배포 시작$webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "kejilion.sh LDNMP 환경 준비" ldnmp_install_status + kpanel_web_progress 35 "사이트 인증서 발급 및 구성" install_ssltls certs_status + kpanel_web_progress 50 "WordPress 데이터베이스 및 계정 생성" add_db + kpanel_web_progress 60 "kejilion.sh WordPress Nginx 구성 가져오기" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "kejilion.sh WordPress 소스 코드 얻기 및 구성" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +4151,9 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "LDNMP 다시 시작 및 WordPress 사이트 확인" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -3503,6 +4168,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "역방향 프록시 도메인 이름 및 업스트림 주소 확인" send_stats "설치하다$webname" echo "배포 시작$webname" if [ -z "$yuming" ]; then @@ -3519,12 +4185,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "안티 세대 포트를 입력하십시오:" port fi + kpanel_web_progress 25 "kejilion.sh Nginx 환경 준비" nginx_install_status + kpanel_web_progress 40 "역방향 프록시 인증서 발급 및 구성" install_ssltls certs_status + kpanel_web_progress 60 "kejilion.sh 역방향 프록시 구성 가져오기" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3545,6 +4214,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "역방향 프록시 구성 확인 및 다시 로드" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3565,7 +4235,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "여러 개의 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port + read -e -p "여러 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port fi nginx_install_status @@ -3728,7 +4398,7 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트리밍 4계층 프록시-로드 밸런싱" + webname="스트림 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" @@ -4782,7 +5452,7 @@ linux_clean() { bbr_on() { -# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -4823,6 +5493,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "오류: /etc/resolv.conf는 손상된 심볼릭 링크입니다." + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "오류: DNS 구성 디렉터리가 존재하지 않습니다." + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "오류: chattr을 사용할 수 없습니다. kejilion.sh DNS 수명 주기 의미를 유지할 수 없습니다." + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "오류: DNS 구성을 잠글 수 없습니다." + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "오류: 기존 DNS 구성을 잠금 해제할 수 없습니다." + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "오류: DNS 쓰기 실패 및 롤백 실패, 수동 확인 필요" + return 1 + } + rm -f "$desired" "$backup" + echo "오류: DNS 쓰기 또는 다시 읽기 확인에 실패했습니다. 원래 구성이 복원되었습니다." + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "오류: systemctl을 사용할 수 없습니다." + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "오류: systemd-resolved DNS 롤백 실패, 수동 검사 필요" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "오류: systemd-resolved DNS가 파일을 복원했지만 서비스 다시 로드에 실패했습니다. 수동 검사가 필요합니다." + return 1 + } + rm -f "$desired" "$backup" + echo "오류: systemd-resolved DNS 쓰기 또는 다시 읽기 확인에 실패했습니다. 원래 구성이 복원되었습니다." + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "오류: KPanel DNS 프로토콜은 루트로 실행되어야 합니다." + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "오류: DNS 주소 수는 1~4개여야 합니다." + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "오류: DNS 주소가 비어 있거나 너무 깁니다." + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "오류: 최대 2개의 IPv4 DNS 주소" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "오류: 최대 2개의 IPv6 DNS 주소" + return 1 + } + else + echo "오류: 잘못된 DNS 주소" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "오류: DNS 주소는 반복될 수 없습니다." + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -4938,7 +5848,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}사용자 키 로그인 모드가 켜져 있고 비밀번호 로그인 모드가 꺼졌습니다. 다시 연결이 적용됩니다.${gl_bai}" + echo -e "${gl_lv}사용자 키 로그인 모드는 켜지고 비밀번호 로그인 모드는 꺼집니다. 다시 연결이 적용됩니다.${gl_bai}" } @@ -5061,7 +5971,7 @@ fetch_remote_ssh_keys() { # 원본 인증_키 백업 if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "원본 Authorized_keys 파일이 백업되었습니다." + echo "원래 Authorized_keys 파일이 백업되었습니다." fi # 공개 키 추가(중복 방지) @@ -5138,7 +6048,7 @@ sshkey_panel() { echo -e "사용자 키 로그인 모드${IS_KEY_ENABLED}" echo "고급 게임플레이: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "SSH를 통해 보다 안전하게 로그인할 수 있도록 키 쌍이 생성됩니다." + echo "SSH를 통해 더욱 안전하게 로그인할 수 있는 키 쌍이 생성됩니다." echo "------------------------" echo "1. 새 키 쌍 생성 2. 기존 공개 키를 수동으로 입력" echo "3. GitHub에서 기존 공개 키를 가져옵니다. 4. URL에서 기존 공개 키를 가져옵니다." @@ -5595,9 +6505,131 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false status_line reboot_required=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "현재 호스트는 KPanel BBRv3 제어 실행을 지원하지 않습니다." >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "XanMod BBRv3 커널이 설치되지 않았으며 업데이트를 수행할 수 없습니다." >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" + ;; + *) + echo "사용법: k bbrv3 [상태|설치|업데이트|제거]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3 관리" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3 관리" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -5726,7 +6758,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -5736,9 +6768,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5939,7 +6976,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하세요." + echo "스캔할 디렉터리를 지정하십시오." return fi @@ -6158,7 +7195,7 @@ _kernel_optimize_core() { BACKLOG=1000 fi - # ── 생방송 시나리오를 위한 추가 사항: UDP 버퍼 확대 ── + # ── 추가 라이브 방송 시나리오: UDP 버퍼 확대 ── local STREAM_EXTRA="" if [ "$scene" = "stream" ]; then STREAM_EXTRA=" @@ -6423,7 +7460,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모드" + send_stats "웹사이트 최적화 모델" ;; 4) cd ~ @@ -7151,7 +8188,7 @@ list_partitions() { # 지속적으로 마운트된 파티션 mount_partition() { send_stats "마운트 파티션" - read -e -p "마운트할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION + read -e -p "마운트할 파티션 이름을 입력하십시오(예: sda1):" PARTITION DEVICE="/dev/$PARTITION" MOUNT_POINT="/mnt/$PARTITION" @@ -8237,7 +9274,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]는 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -8339,7 +9376,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키로 로그인 + # 키를 사용하여 로그인 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -8526,7 +9563,7 @@ linux_docker() { 3) send_stats "네트워크에 가입하세요" read -e -p "종료 네트워크 이름:" dockernetwork - read -e -p "이러한 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames + read -e -p "해당 컨테이너는 네트워크를 종료합니다(여러 컨테이너 이름을 공백으로 구분하세요)." dockernames for dockername in $dockernames; do docker network disconnect $dockernetwork $dockername @@ -8572,7 +9609,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -8685,6 +9722,180 @@ linux_docker() { +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} + +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPT 잠금 해제 상태 감지" + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh + ;; + region) + send_stats "지역 스트리밍 미디어 잠금 해제 테스트" + kpanel_run_remote_bash https://check.unlock.media + ;; + media) + send_stats "예우 스트리밍 미디어 잠금 해제 감지" + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh + ;; + ip-quality) + send_stats "xykt_IP 품질 확인 스크립트" + kpanel_run_remote_bash https://IP.Check.Place + ;; + besttrace) + send_stats "besttrace 삼중 네트워크 백홀 지연 라우팅 테스트" + kpanel_run_remote_bash https://git.io/besttrace + ;; + mtr) + send_stats "mtr_trace 삼중 네트워크 백홀 회선 테스트" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh + ;; + superspeed) + send_stats "초고속 트리플 네트워크 속도 테스트" + kpanel_run_remote_bash https://git.io/superspeed_uxh + ;; + nxtrace-fast) + send_stats "nxtrace 빠른 백홀 테스트 스크립트" + kpanel_run_remote_bash https://nxtrace.org/nt + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020 세 개의 네트워크 라인 테스트" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh + ;; + speedtest) + send_stats "i-abc 다기능 속도 테스트 스크립트" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh + ;; + net-quality) + send_stats "네트워크 품질 테스트 스크립트" + kpanel_run_remote_bash https://Net.Check.Place + ;; + tcp-quality) + send_stats "TcpQuality TCP 재전송 감지 스크립트" + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh + ;; + yabs) + send_stats "Yabs 성능 테스트" + check_swap + kpanel_run_remote_bash https://yabs.sh -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU 성능 테스트 스크립트" + check_swap + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh + ;; + bench) + send_stats "벤치 성능 테스트" + kpanel_run_remote_bash https://bench.sh + ;; + ecs) + send_stats "spiritysdx 퓨전 몬스터 리뷰" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "Nodequality 융합 몬스터 평가" + kpanel_run_remote_bash https://run.NodeQuality.com + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac +} + + linux_test() { while true; do @@ -8894,7 +10105,7 @@ linux_Oracle() { 1) clear echo "활성 스크립트: CPU 사용량 10-20% 메모리 사용량 20%" - read -e -p "정말로 설치하시겠습니까? (예/아니요):" choice + read -e -p "설치하시겠습니까? (예/아니요):" choice case "$choice" in [Yy]) @@ -8906,7 +10117,7 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter를 누르면 기본값이 사용됩니다. + # 사용자에게 CPU 코어 수와 점유율을 입력하라는 메시지를 표시합니다. 사용자가 Enter 키를 누르면 기본값이 사용됩니다. read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} @@ -9075,9 +10286,577 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "사용법: k <웹사이트 구축 명령> <도메인 이름>" + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "기존 웹 사이트 또는 LDNMP 환경 작업이 실행 중입니다." >&2 + exec {lock_fd}>&- + return 75 + fi + linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","required":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","repoDigest":"%s","updateStatus":"unknown","updateReason":"레지스트리 상태는 업데이트 작업 중에 실시간으로만 확인됩니다."}' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"Full LDNMP"},{"id":"nginx","label":"전용 Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudfl are-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on ","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"] },{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "설치 조건 확인" + case "$profile" in + full) kpanel_ldnmp_event install 15 "전체 LDNMP 설치"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "nginx 설치"; nginx_install_all ;; + *) echo "지원되지 않는 설치 형식" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "환경 확인 중" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare 자격 증명 채널이 잘못되었습니다." >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "지원되지 않는 보호 조치" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "보호 구성 확인에 실패했으며 원래 구성을 복원하는 중입니다." + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "현재 프로토콜은 이 최적화 작업을 지원하지 않습니다." >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "최적화 확인에 실패했으며 원래 구성을 복원하는 중입니다." + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "업데이트 전 콜드 대기 생성" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "지원되지 않는 업데이트 구성 요소" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "LDNMP를 잠시 중지" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "/home/web 보관" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "LDNMP 복원 중" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "백업 아카이브 검사" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "안전한 준비 디렉터리로 추출 중" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "/home/web으로 원자적으로 전환" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "기존 웹 사이트 또는 LDNMP 환경 작업이 실행 중입니다." + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP 환경 작업이 시작되었습니다." + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP 환경 작업 완료" + kpanel_ldnmp_result succeeded "$action" "작업 실행 성공" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP 환경 작업 실행 실패" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "작업이 실패했으며 안전한 롤백을 확인할 수 없어 수동 처리가 필요합니다." + else + kpanel_ldnmp_result failed "$action" "작업 실행 실패" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP 환경 관리" + echo "------------------------" + echo "1. 환경상태를 확인한다" + echo "2. 전체 LDNMP 설치" + echo "3. Nginx만 설치" + echo "4. 보호관리" + echo "5. 관리 최적화" + echo "6. 환경 업데이트" + echo "7. 콜드 대기 만들기" + echo "8. 백업 복원" + echo "9. 환경 제거" + echo "0. 반품" + echo "------------------------" + read -e -p "선택사항을 입력하세요:" choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "구성 요소 업데이트(nginx/mysql/php/redis/all):" component + read -e -p "대상 버전(기본 최신 버전):" version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "복원할 백업 파일 이름을 입력하세요:" backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "DELETE를 입력하여 LDNMP 환경 제거를 확인합니다." confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "잘못된 입력" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "지원되지 않는 LDNMP 환경 명령" >&2; return 2 ;; + esac +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP 웹사이트 구축" echo -e "${gl_huang}LDNMP 웹사이트 구축" @@ -9103,7 +10882,42 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "선택사항을 입력하세요:" sub_choice + fi + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; + *) + echo "KPANEL_PROGRESS 100 지원되지 않음 KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN은 유효한 도메인 이름이 아닙니다." + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 도메인 이름이 이미 존재하므로 기존 제품 덮어쓰기를 거부합니다." + return 1 + fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST는 유효한 IP 또는 호스트 이름이 아닙니다." + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT는 유효한 포트가 아닙니다." + return 1 + fi + fi + echo "KPANEL_PROGRESS 5는 kejilion.sh 기본 원클릭 웹사이트 구축 프로세스를 시작합니다." + else + read -e -p "선택사항을 입력하세요:" sub_choice + fi case $sub_choice in @@ -9112,7 +10926,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9138,7 +10952,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9147,6 +10961,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9181,13 +10996,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9222,7 +11038,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9231,6 +11047,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9271,10 +11088,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9327,7 +11145,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9349,6 +11167,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9386,12 +11205,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9429,12 +11249,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9467,7 +11288,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9566,6 +11387,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9613,7 +11435,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -9706,14 +11528,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9748,7 +11570,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9776,7 +11598,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -10078,6 +11900,23 @@ linux_ldnmp() { *) echo "입력이 잘못되었습니다!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 웹사이트 구축 제품이 불완전합니다" + return 1 + fi + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 웹사이트 구축 제품이 불완전합니다" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx 구성 확인에 실패했습니다." + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh 네이티브 웹사이트 구축 제품이 완성되었습니다." + return 0 + fi break_end done @@ -10520,7 +12359,7 @@ for name, provider in list(providers.items()): provider['models'] = new_models changed = True - summary.append(f'✅ {name}: {len(add_ids)} 추가, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') + summary.append(f'✅ {name}: {len(add_ids)} 추가됨, 삭제됨 {len(removed_ids)}, 현재 {len(new_models)}') if added_ids: summary.append(f'➕ 새 모델 추가({len(add_ids)}):') @@ -10557,8 +12396,8 @@ PY install_moltbot() { - echo "OpenClaw 설치를 시작하세요..." - send_stats "OpenClaw 설치를 시작하세요..." + echo "OpenClaw 설치를 시작합니다..." + send_stats "OpenClaw 설치를 시작합니다..." install git jq install_node_and_tools @@ -11125,7 +12964,7 @@ if not base_url or not api_key or not isinstance(model_list, list) or not model_ raise SystemExit(3) if api not in SUPPORTED_APIS: - print(f'ℹ️ 공급자 {target}은 현재 api={api}이지만 스크립트는 더 이상 프로토콜을 감지/수정하지 않습니다. openai-completions 또는 openai-responses로 수동으로 설정하세요.') + print(f'ℹ️ 공급자 {target} 현재 api={api}이지만 스크립트는 더 이상 프로토콜을 감지/수정하지 않습니다. openai-completions 또는 openai-responses로 수동으로 설정하세요.') protocol_msg = None @@ -11485,7 +13324,7 @@ PY ;; 3) send_stats "OpenClaw API 삭제 취소" - echo "❌ 삭제 실패: 대체 모델이 없으며 원래 구성이 유지되었습니다." + echo "❌ 삭제 실패: 사용 가능한 대체 모델이 없으며 원래 구성이 유지되었습니다." ;; *) echo "❌ 삭제 실패: 구성 파일 구조 또는 로그 출력을 확인하세요." @@ -11937,7 +13776,7 @@ PYTHON_EOF echo "요약:$OPENCLAW_PROBE_REPLY" echo "" - printf "이 모델로 전환하시겠습니까? [y/N, Esc가 목록으로 돌아갑니다]:" + printf "이 모델로 전환하시겠습니까? [y/N, Esc를 누르면 목록으로 돌아갑니다.]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12118,7 +13957,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" return 1 } @@ -12225,7 +14064,7 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" plugin_action [ "$plugin_action" = "0" ] && break @@ -12266,7 +14105,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 시스템 내장 디렉토리에 플러그인이 존재하는 것을 발견했습니다. 직접 활성화해 보세요..." + echo "💡 플러그인이 시스템 내장 디렉토리에 존재하는 것을 발견했습니다. 직접 활성화해 보십시오..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -12353,7 +14192,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 복귀" + echo "0) 반품" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -13155,7 +14994,7 @@ if os.path.isdir(agents_root): } openclaw_backup_delete_file() { - send_stats "OpenClaw 삭제 백업 파일" + send_stats "OpenClaw 백업 파일 삭제" local backup_root backup_root_real user_input target_file target_path target_type backup_root=$(openclaw_backup_root) @@ -13183,7 +15022,7 @@ if os.path.isdir(agents_root): case "$target_path" in "$backup_root_real"/*) ;; *) - echo "❌ 경로 초과: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." + echo "❌ 경로 밖: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." break_end return 1 ;; @@ -13589,7 +15428,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 접속할 수 없습니다(국내/제한된 네트워크로 의심됨).") fi if [ "$qmd_ok" = "true" ]; then @@ -13696,7 +15535,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -13790,7 +15629,7 @@ PY else echo "가능한 트래픽/디스크 사용량: 실제 상황에 따라 다름" fi - echo "확인 후 자동으로 설치/다운로드하고, 구성을 작성하고, 인덱스를 작성하고, 게이트웨이를 다시 시작합니다." + echo "확인 후 자동으로 설치/다운로드, 구성 작성, 색인 작성 및 게이트웨이를 다시 시작합니다." echo "고급 옵션: 구성만 작성하려면 구성을 입력하세요(설치 없음, 다운로드 없음, 인덱싱 없음, 다시 시작 없음)." read -e -p "계속하려면 yes를 입력하세요(기본값 N)." confirm_step case "$confirm_step" in @@ -13841,7 +15680,7 @@ PY openclaw_memory_config_set "memory.qmd.command" "$OPENCLAW_MEMORY_QMD_PATH" echo "✅ memory.qmd.command에 작성:$OPENCLAW_MEMORY_QMD_PATH" else - echo "✅ memory.qmd.command가 정확합니다" + echo "✅ memory.qmd.command가 정확합니다." fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then echo "🔥 따뜻한 지수(모델 다운로드 가능)" @@ -14317,7 +16156,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." + echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -14331,7 +16170,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 모든 에이전트에 대해 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." + echo "✅ 모든 에이전트에서 강제 재구성이 수행되었으며 게이트웨이가 자동으로 다시 시작되었습니다." fi else openclaw memory index @@ -14700,7 +16539,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만 일반적인 위험한 명령에는 여전히 승인이 필요함)${gl_bai}" + echo -e "${gl_lv}✅ 개발 강화 모드로 전환(권한 상승은 허용되지만, 일반적으로 위험한 명령은 여전히 ​​승인이 필요함)${gl_bai}" } openclaw_permission_apply_full() { @@ -14809,7 +16648,7 @@ except Exception as e: break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하세요." pattern + read -e -p "제거할 명령 경로를 입력하십시오:" pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -15577,21 +17416,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}실수:${gl_bai}${apps_dir}이미 존재하지만 App Market Git 저장소가 아니므로 덮어쓰기가 거부됩니다." + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}애플리케이션 목록 다운로드에 실패했으며 불완전한 구성이 거부되었습니다.${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}애플리케이션 목록 업데이트에 실패했습니다. 잠재적으로 만료된 구성을 계속 사용하는 것을 거부했습니다.${gl_bai}" + echo "네트워크를 확인하시거나${apps_dir}로컬 수정 후 다시 시도해 보세요." + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}신청 목록이 업데이트 중입니다. 기다리세요...${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -15613,7 +17468,7 @@ while true; do echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" - echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 버전" + echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" echo -e "${gl_kjlan}9. ${color9}Poste.io 메일 서버 프로그램${gl_kjlan}10. ${color10}RocketChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15625,7 +17480,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode 웹 버전${gl_kjlan}22. ${color22}UptimeKuma 모니터링 도구" echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-오늘 예약된 작업 관리 프레임워크" + echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" echo -e "${gl_kjlan}-------------------------" @@ -15673,7 +17528,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" @@ -15682,7 +17537,7 @@ while true; do echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -15884,7 +17739,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -16584,7 +18439,7 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접근할 수 없는 경우, 접근할 도메인 이름을 추가해주세요." + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -17255,7 +19110,7 @@ while true; do } - local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결되는 대규모 언어 모델 웹 페이지 프레임워크입니다." + local docker_describe="OpenWebUI는 새로운 llama3 대규모 언어 모델에 연결된 대규모 언어 모델 웹 페이지 프레임워크입니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/open-webui/open-webui" local docker_use="docker exec ollama ollama run llama3.2:1b" local docker_passwd="" @@ -17694,7 +19549,7 @@ while true; do } - local docker_describe="AI 대형 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" + local docker_describe="대규모 AI 모델에 대한 WeChat, QQ 및 TG 액세스를 지원하는 오픈 소스 AI 챗봇 프레임워크" local docker_url="공식 홈페이지 소개: https://astrbot.app/" local docker_use="echo \"사용자 이름: astrbot 비밀번호: astrbot\"" local docker_passwd="" @@ -17985,7 +19840,7 @@ while true; do } local docker_describe="Beszel은 가볍고 사용하기 쉬운 서버 모니터링입니다." - local docker_url="공식 홈페이지 소개 : https://beszel.dev/zh/" + local docker_url="공식 홈페이지 소개: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18319,7 +20174,7 @@ while true; do } - local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -18571,7 +20426,7 @@ while true; do } - local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" + local docker_describe="다중 프로토콜을 지원하는 분산 고속 다운로드 도구" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -18635,7 +20490,7 @@ while true; do local app_id="96" local app_name="2FAuth 자체 호스팅 2단계 인증자" - local app_text="자체 호스팅 2단계 인증(2FA) 계정 관리 및 확인 코드 생성 도구입니다." + local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" local docker_port="8096" @@ -19433,15 +21288,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" @@ -19450,6 +21297,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" @@ -19923,7 +21776,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한하십시오." + echo "3) 최대 로그 크기를 500M로 제한합니다." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -20017,7 +21870,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드" + send_stats "환경 변수 다시 로드 중" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -20029,7 +21882,7 @@ env_menu() { echo "=========== 시스템 환경 변수 관리 ==========" echo "현재 사용자:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인한다" + echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." echo "2. ~/.bashrc 보기" echo "3. ~/.profile 보기" echo "4. ~/.bashrc 편집" @@ -20148,10 +22001,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -20161,7 +22014,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}기본 호스트 확인${gl_kjlan}22. ${gl_bai}SSH 방어 프로그램" echo -e "${gl_kjlan}23. ${gl_bai}전류 제한 자동 종료${gl_kjlan}24. ${gl_bai}사용자 키 로그인 모드" - echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" + echo -e "${gl_kjlan}25. ${gl_bai}TG-bot 시스템 모니터링 및 조기 경보${gl_kjlan}26. ${gl_bai}OpenSSH 고위험 취약점 수정" echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux 커널 업그레이드${gl_kjlan}28. ${gl_bai}Linux 시스템 커널 매개변수 최적화${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" @@ -20219,7 +22072,7 @@ linux_Settings() { echo "파이썬 버전 관리" echo "영상 소개: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "이 기능은 Python에서 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" + echo "이 기능은 Python이 공식적으로 지원하는 모든 버전을 원활하게 설치할 수 있습니다!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -20633,7 +22486,7 @@ EOF echo "유럽" echo "11. 영국 런던 시간 12. 프랑스 파리 시간" echo "13. 독일 베를린 시간 14. 러시아 모스크바 시간" - echo "15. 네덜란드 유트라흐트 시간 16. 스페인 마드리드 시간" + echo "15. 네덜란드 위트레흐트 시간 16. 스페인 마드리드 시간" echo "------------------------" echo "미국" echo "21. 미국 서부 시간 22. 미국 동부 시간" @@ -20701,7 +22554,7 @@ EOF echo "$new_hostname" > /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 + # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -20734,7 +22587,7 @@ EOF send_stats "시스템 업데이트 소스 변경" clear echo "업데이트 소스 지역 선택" - echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" + echo "LinuxMirror에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" echo "------------------------" @@ -20796,7 +22649,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날짜는 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -20956,7 +22809,7 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." @@ -21231,7 +23084,7 @@ EOF sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="true"/ENABLE_STATS="false"/' ~/kejilion.sh echo "컬렉션이 닫혔습니다." - send_stats "개인 정보 보호 및 보안 수집이 꺼졌습니다" + send_stats "개인정보 보호 및 보안 수집이 사용 중지되었습니다." ;; *) break @@ -21589,7 +23442,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" + echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -21951,7 +23804,7 @@ echo "-------------------" echo "영상 소개: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "다음은 k 명령의 참조 사용 사례입니다." echo "시작 스크립트 k" -echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 나노 wget을 설치합니다." +echo "패키지 설치 k install nano wget | k 나노 wget 추가 | k는 nano wget을 설치합니다." echo "패키지 제거 k 제거 nano wget | k 델 나노 wget | k 나노 wget 제거 | k 나노 wget 제거" echo "시스템 k 업데이트 업데이트 | k 업데이트" echo "클린 시스템 정크 k 클린 | 케이 깨끗하다" @@ -21985,14 +23838,14 @@ echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com echo "로드 밸런싱 설치 k loadbalance |k 로드 밸런싱" echo "L4 로드 밸런싱 설치 k 스트림 |k L4 로드 밸런싱" echo "방화벽 패널 k fhq |k 방화벽" -echo "포트 k 열기 ddk 8080 |k 포트 8080 열기" +echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장관리 kapp" +echo "애플리케이션 시장 관리 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" -echo "Fail2ban 관리 k Fail2ban | 케이 F2B" +echo "Fail2ban 관리 k Fail2ban | k f2b [상태|활성화|비활성화]" echo "시스템 정보 표시 k 정보" echo "ROOT 키 관리 k sshkey" echo "SSH 공개 키 가져오기(URL) k sshkey " @@ -22028,7 +23881,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize @@ -22061,6 +23919,66 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" + ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" ;; fd|rp|反代) shift @@ -22097,6 +24015,20 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open @@ -22205,8 +24137,14 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "환경" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "삭제" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then @@ -22234,7 +24172,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 64a98b5da..7ecde80d9 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.2" +sh_v="4.5.4" gl_hui='\e[37m' @@ -16,6 +16,18 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +kpanel_protocol_active() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -100,17 +112,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 - -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -127,7 +140,7 @@ UserLicenseAgreement() { echo "首次使用腳本,請先閱讀並同意使用者授權協議。" echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -e -p "是否同意以上條款? (y/n):" user_input + read -e -p "是否同意以上条款? (y/n):" user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -141,7 +154,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi @@ -233,7 +248,7 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}提示:${gl_bai}磁碟空間不足!" echo "目前可用空間: $((available_space_mb/1024))G" - echo "最小需求空間:${required_gb}G" + echo "最小需求空间: ${required_gb}G" echo "無法繼續安裝,請清理磁碟空間後重試。" send_stats "磁碟空間不足" break_end @@ -508,12 +523,12 @@ while true; do ;; 2) send_stats "啟動指定容器" - read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) send_stats "停止指定容器" - read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker stop $dockername ;; 4) @@ -772,7 +787,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 比較原始配置與新配置 + # 对比原始配置与新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}目前已開啟ipv6訪問${gl_bai}" else @@ -1019,7 +1034,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域檔案失敗" + echo "错误:下载 $country_code的 IP 區域檔案失敗" continue fi @@ -1103,7 +1118,7 @@ iptables_panel() { echo "------------------------" echo "11. 允許PING 12. 禁止PING" echo "------------------------" - echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" + echo "13. 启动DDOS防御 14. 关闭DDOS防御" echo "------------------------" echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" echo "17. 解除指定國家IP限制" @@ -1197,7 +1212,7 @@ iptables_panel() { 15) read -e -p "請輸入阻止的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules block $country_code - send_stats "允許國家$country_code的IP" + send_stats "允許國家$country_code 的IP" ;; 16) read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code @@ -1481,7 +1496,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1498,7 +1513,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "站點資訊 證書到期時間" + echo "網站資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1540,7 +1555,12 @@ certs_status() { send_stats "網域證書申請成功" else send_stats "網域證書申請失敗" - echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then + echo "KPANEL_PROGRESS 100 網域名稱憑證申請失敗,請檢查 DNS、80/443 連接埠和簽發限額" + return 1 + fi + echo -e "${gl_hong}注意:${gl_bai}证书申请失败,请检查以下可能原因并重试:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" @@ -1586,7 +1606,7 @@ certs_status() { done # 3. 智能校驗 - # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可透過 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1618,6 +1638,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "網域重複使用" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 網域名稱已存在,拒絕覆蓋 kejilion.sh 或 KPanel 的現有產物" + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1649,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + return 0 + fi ip_address echo -e "先將網域名稱解析到本機IP:${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "請輸入你的IP或解析過的網域名稱:" yuming @@ -1676,6 +1709,40 @@ add_db() { } +ldnmp_web_root_base="/home/web/html" + +ldnmp_site_domain_is_safe() { + local site_domain="${1:-}" + case "$site_domain" in + ""|"."|".."|*/*) + echo "無效的網站目錄名稱:$site_domain" >&2 + return 1 + ;; + esac +} + +prepare_ldnmp_site_root() { + local site_domain="${1:-}" + ldnmp_site_domain_is_safe "$site_domain" || return 1 + command mkdir -p -- "${ldnmp_web_root_base}/${site_domain}" && + command chmod 0755 -- "$ldnmp_web_root_base" "${ldnmp_web_root_base}/${site_domain}" +} + +normalize_ldnmp_site_permissions() { + local site_domain="${1:-}" + local site_root + ldnmp_site_domain_is_safe "$site_domain" || return 1 + site_root="${ldnmp_web_root_base}/${site_domain}" + [ -d "$site_root" ] || { + echo "站點目錄不存在:$site_root" >&2 + return 1 + } + + find "$site_root" -type d -exec chmod u+rwx,go+rx,go-w {} + && + find "$site_root" -type f -exec chmod u+rw,go+r,go-w {} + +} + + restart_ldnmp() { docker exec nginx chown -R nginx:nginx /var/www/html > /dev/null 2>&1 docker exec nginx mkdir -p /var/cache/nginx/proxy > /dev/null 2>&1 @@ -1786,32 +1853,72 @@ web_cache() { web_del() { send_stats "刪除站點數據" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "無效域名,拒絕刪除:$yuming" + action_status=1 + continue + fi + echo "正在刪除網域名稱:$yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # 將網域名稱轉換為資料庫名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "正在刪除資料庫:$dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # 刪除資料庫前檢查是否存在,避免報錯 - echo "正在刪除資料庫:$dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "站點產物刪除不完整:$yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx 設定驗證或重載失敗" + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -1829,7 +1936,7 @@ nginx_waf() { sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 關閉 WAF:加上註釋 + # 关闭 WAF:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2233,7 +2340,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" + echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" ;; 22) @@ -2344,8 +2451,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "不支援的 LDNMP 優化模式" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "LDNMP環境已設定成 高效能模式" + else + optimize_balanced + echo "LDNMP環境已設定成 標準模式" + fi +} web_optimization() { while true; do @@ -2367,83 +2532,11 @@ web_optimization() { case $sub_choice in 1) send_stats "站點標準模式" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # php調優 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php調優 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql調優 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "LDNMP環境已設定成 標準模式" - + ldnmp_optimization_mode standard ;; 2) send_stats "站點高效能模式" - - # nginx調優 - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # php調優 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php調優 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql調優 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "LDNMP環境已設定成 高效能模式" - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -2544,19 +2637,18 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 區域檢查 - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. 取得本地鏡像訊息 - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. 取得容器及本地鏡像資訊。更新檢測不再按地區跳過。 + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 智慧路由判斷 + # 2. 智慧路由判斷 if [[ "$full_image_name" == ghcr.io* ]]; then # --- 場景 A: 鏡像在 GitHub (ghcr.io) --- # 提取倉庫路徑,例如 ghcr.io/onexru/oneimg -> onexru/oneimg @@ -2572,19 +2664,45 @@ check_docker_image_update() { else # --- 場景 C: 標準 Docker Hub --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}發現新版本!${gl_bai}" + fi + return + fi fi - # 4. 時間戳對比 + # 3. Registry 未提供可比較摘要時,相容使用發佈時間判斷。 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}發現新版本!${gl_bai}" fi fi @@ -2782,7 +2900,7 @@ clear_host_port_rules() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "錯誤:請提供連接埠號碼和允許存取的 IP。" - echo "用法: clear_host_port_rules <連接埠號碼> <允許的IP>" + echo "用法: clear_host_port_rules <端口号> <允许的IP>" return 1 fi @@ -2857,11 +2975,412 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi + read -r -e -p "請輸入你的選擇:" selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "錯誤: KPanel 應用程式管理終端機只接受選單編號" + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "錯誤: KPanel 未提供有效的應用存取模式" + return 1 + ;; + esac + ;; + *) + echo "錯誤: KPanel 交互終端不支援此應用操作" + return 1 + ;; + esac +} + +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "錯誤: 應用主容器名稱無效" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "錯誤: 未發現應用主容器${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "錯誤: 無法確認應用主容器${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "錯誤: 應用主容器已變化,請刷新面板後重試" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "錯誤: 應用狀態檔案名稱無效" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "錯誤: 不支援的應用程式存取模式" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "錯誤: 不支援的應用程式存取模式" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "錯誤: KPanel 未提供有效的應用端口" + return 1 + ;; + esac + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "錯誤: KPanel 應用埠必須在 1-65535 之間" + return 1 + fi + if kpanel_app_port_in_use "$requested_port"; then + echo "錯誤: 連接埠${requested_port}已被佔用" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" + send_stats "應用程式連接埠已被佔用" + else + docker_port="$app_port" + return 0 + fi + done +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "錯誤: KPanel 目前僅允許非互動安裝" + return 1 + fi + + kpanel_app_progress 5 "正在校驗連接埠與宿主機環境" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "正在準備 Docker 運行環境" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "正在執行 kejilion.sh 應用程式安裝函數" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "安裝失敗: 未登記應用程式狀態" + return 1 + fi + else + if ! docker_rum; then + echo "安裝失敗: 未登記應用程式狀態" + return 1 + fi + fi + + kpanel_app_progress 90 "正在寫入 kejilion.sh 相容狀態" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "应用安装完成" + echo "$docker_name已經安裝完成" + return 0 +} + +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "錯誤: KPanel 不支援此應用程式操作" + return 1 + ;; + esac + + kpanel_app_progress 5 "正在核對 kejilion.sh 安裝標記與主容器" + service_name="$(kpanel_app_verified_service true)" || return 1 + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "錯誤: 未發現 kejilion.sh 應用安裝標記" + return 1 + fi + kpanel_app_progress 10 "正在修復 kejilion.sh 應用程式安裝標記" + add_app_id || return 1 + fi + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在執行 kejilion.sh 原生更新函數" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "正在恢復應用程式存取策略" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "應用程式更新完成" + echo "$service_name已經更新完成" + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在執行 kejilion.sh 原生卸載函數" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "錯誤: 卸載函數完成後主容器仍然存在" + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "應用程式卸載完成" + echo "$service_name已經卸載完成" + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "錯誤: KPanel 未提供有效的應用存取模式" + return 1 + ;; + esac + kpanel_app_progress 40 "正在執行 kejilion.sh IP+連接埠存取策略" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "應用程式存取策略更新完成" + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}管理" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action standard + return $? +fi + while true; do clear check_docker_app @@ -2887,30 +3406,30 @@ while true; do echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "請輸入你的選擇:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "請輸入你的選擇:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" - send_stats "應用程式連接埠已被佔用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}安裝失敗:${gl_bai}應用容器未能啟動。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_name已經安裝完成" @@ -2923,9 +3442,15 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}更新失敗:${gl_bai}應用容器未能重新啟動。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_name已經安裝完成" @@ -2936,10 +3461,16 @@ while true; do send_stats "更新$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}卸載失敗:${gl_bai}應用容器未能刪除。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "應用程式已解除安裝" @@ -2947,32 +3478,38 @@ while true; do ;; 5) - echo "${docker_name}域名存取設定" + echo "${docker_name}域名访问设置" send_stats "${docker_name}域名存取設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "網域格式 example.com 不含https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允許IP存取${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP訪問${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -2984,6 +3521,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action plus + return $? + fi while true; do clear check_docker_app @@ -3010,46 +3551,53 @@ docker_app_plus() { echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "輸入你的選擇:" choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "輸入你的選擇:" choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "輸入應用程式對外服務端口,回車預設使用${docker_port}連接埠:" app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}錯誤:${gl_bai}連接埠$app_port已被佔用,請更換一個端口" - send_stats "應用程式連接埠已被佔用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_name安裝" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + kpanel_app_write_access_mode direct + send_stats "$app_name安裝" + else + echo -e "${gl_hong}安裝失敗:${gl_bai}未登記套用狀態,請依上方錯誤修復後重試。" + action_status=1 + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_name更新" + if docker_app_update; then + add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" + send_stats "$app_name更新" + else + echo -e "${gl_hong}更新失敗:${gl_bai}已保留原應用程式登記狀態。" + action_status=1 + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name解除安裝" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_name解除安裝" + else + echo -e "${gl_hong}卸載失敗:${gl_bai}已保留應用程式登記狀態。" + action_status=1 + fi ;; 5) @@ -3059,25 +3607,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "網域格式 example.com 不含https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允許IP存取${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP訪問${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -3212,6 +3767,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH jail 未能正常啟動" >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban 服務仍在運行" >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "用法: k f2b [status|enable|disable]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -3455,27 +4111,33 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "正在校驗 WordPress 網域與現有站點" send_stats "安裝$webname" echo "開始部署$webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "正在準備 kejilion.sh LDNMP 環境" ldnmp_install_status + kpanel_web_progress 35 "正在簽發並配置網站證書" install_ssltls certs_status + kpanel_web_progress 50 "正在建立 WordPress 資料庫與帳號" add_db + kpanel_web_progress 60 "正在取得 kejilion.sh WordPress Nginx 配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "正在取得並配置 kejilion.sh WordPress 原始碼" cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/wp-latest.zip unzip latest.zip @@ -3489,6 +4151,9 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "正在重新啟動 LDNMP 並核驗 WordPress 站點" + normalize_ldnmp_site_permissions "$yuming" || return 1 + chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp nginx_web_on @@ -3503,6 +4168,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "正在校驗反向代理域名與上游地址" send_stats "安裝$webname" echo "開始部署$webname" if [ -z "$yuming" ]; then @@ -3519,12 +4185,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "請輸入你的反代端口:" port fi + kpanel_web_progress 25 "正在準備 kejilion.sh Nginx 環境" nginx_install_status + kpanel_web_progress 40 "正在簽發並配置反向代理證書" install_ssltls certs_status + kpanel_web_progress 60 "正在取得 kejilion.sh 反向代理配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3545,6 +4214,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "正在校驗並重載反向代理配置" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -3625,7 +4295,7 @@ list_stream_services() { ip_address local_ip="$ipv4_address" - # 取得通訊類型,優先從檔案名稱後綴或內容判斷 + # 获取通信类型,优先从文件名后缀或内容判断 if grep -qi 'udp;' "$conf"; then proto="udp" else @@ -3868,7 +4538,7 @@ ldnmp_web_status() { echo "" echo "操作" echo "------------------------" - echo "1. 申請/更新網域憑證 2. 克隆站點域名" + echo "1. 申请/更新域名证书 2. 克隆站点域名" echo "3. 清理站點快取 4. 建立關聯站點" echo "5. 查看訪問日誌 6. 查看錯誤日誌" echo "7. 編輯全域配置 8. 編輯站點配置" @@ -4172,7 +4842,7 @@ remote_port = ${remote_port} EOF # 輸出產生的信息 - echo "服務$service_name已成功加入到 frpc.toml" + echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4471,7 +5141,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP客戶端已經安裝完成" + echo "FRP客户端已经安装完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -4823,6 +5493,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "錯誤: /etc/resolv.conf 是失效的符號鏈接" + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "錯誤: DNS 配置目錄不存在" + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "錯誤: chattr 不可用,無法保持 kejilion.sh DNS 生命週期語意" + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "錯誤: 無法鎖定 DNS 配置" + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "錯誤: 無法解除現有 DNS 設定鎖定" + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "錯誤: DNS 寫入失敗且回滾失敗,需要手動檢查" + return 1 + } + rm -f "$desired" "$backup" + echo "錯誤: DNS 寫入或回讀驗證失敗,已恢復原始配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "錯誤: systemctl 不可用" + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "錯誤: systemd-resolved DNS 回滾失敗,需要手動檢查" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "錯誤: systemd-resolved DNS 已恢復文件,但服務重載失敗,需要手動檢查" + return 1 + } + rm -f "$desired" "$backup" + echo "錯誤: systemd-resolved DNS 寫入或回讀驗證失敗,已恢復原始配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "錯誤: KPanel DNS 協定必須以 root 執行" + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "錯誤: DNS 位址數量必須為 1-4 個" + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "錯誤: DNS 位址為空或過長" + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "錯誤: IPv4 DNS 位址最多 2 個" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "錯誤: IPv6 DNS 位址最多 2 個" + return 1 + } + else + echo "錯誤: 無效的 DNS 位址" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "錯誤: DNS 位址不能重複" + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -4831,7 +5741,7 @@ while true; do clear echo "優化DNS位址" echo "------------------------" - echo "目前DNS地址" + echo "当前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" @@ -4938,7 +5848,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}使用者金鑰登入模式已開啟,已關閉密碼登入模式,重連將會生效${gl_bai}" + echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" } @@ -4956,7 +5866,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5058,7 +5968,7 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 備份原有 authorized_keys + # 备份原有 authorized_keys if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" echo "已備份原有 authorized_keys 文件" @@ -5140,7 +6050,7 @@ sshkey_panel() { echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" + echo "1. 生成新密钥对 2. 手动输入已有公钥" echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" @@ -5595,9 +6505,131 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false status_line reboot_required=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "目前主機不支援 KPanel BBRv3 受控執行" >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "尚未安裝 XanMod BBRv3 內核,不能執行更新" >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" + ;; + *) + echo "用法: k bbrv3 [status|install|update|uninstall]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3管理" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3管理" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -5699,12 +6731,12 @@ bbrv3() { check_disk_space 3 check_swap xanmod_add_repo || { - echo "XanMod官方倉庫配置失敗,請稍後重試" + echo "XanMod官方仓库配置失败,请稍后重试" return 1 } package=$(xanmod_detect_package) || { - echo "無法辨識目前CPU或找不到匹配核心包,已取消安裝" + echo "无法识别当前CPU或找不到匹配内核包,已取消安装" return 1 } @@ -5726,7 +6758,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3內核處理完成。重啟後生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -5736,9 +6768,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "XanMod核心已卸載。重啟後生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -5939,7 +6976,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "請指定要掃描的目錄。" + echo "请指定要扫描的目录。" return fi @@ -5982,7 +7019,7 @@ clamav_scan() { clamav() { root_use - send_stats "病毒掃描管理" + send_stats "病毒扫描管理" while true; do clear echo "clamav病毒掃描工具" @@ -6034,7 +7071,7 @@ clamav() { # ============================================================================ # Linux 核心調優模組(重構版) # 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 -# 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ # 取得記憶體大小(MB) @@ -6084,7 +7121,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; web) - # 網站伺服器:高並發優先 + # 网站服务器:高并发优先 SWAPPINESS=10 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -6205,7 +7242,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" cat > "$CONF" << SYSCTL # kejilion 核心調優配置 # 模式: $mode_name | 場景: $scene -# 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') +# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') # ── TCP 擁塞控制 ── net.core.default_qdisc = $QDISC @@ -6392,7 +7429,7 @@ Kernel_optimize() { echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" - echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" + echo -e "${gl_huang}提示:${gl_bai}生产环境请谨慎使用!" echo -e "--------------------" echo -e "1. 高效能最佳化模式: 最大化系統效能,激進的記憶體和網路參數。" echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" @@ -6513,7 +7550,7 @@ while true; do clear echo "當前系統語言:$LANG" echo "------------------------" - echo "1. 英文 2. 簡體中文 3. 繁體中文" + echo "1. 英文 2. 简体中文 3. 繁体中文" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -6704,7 +7741,7 @@ create_backup() { echo "建立備份範例:" echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" - echo "- 直接回車將使用預設目錄 (/etc /usr /home)" + echo " - 直接回车将使用默认目录 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input # 如果使用者沒有輸入目錄,則使用預設目錄 @@ -6839,7 +7876,7 @@ linux_backup() { -# SSH 輸入標準化函數 +# SSH 输入标准化函数 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -7041,7 +8078,7 @@ delete_connection() { IFS='|' read -r name ip user port password_or_key <<< "$connection" - # 如果連接使用的是密鑰文件,則刪除該密鑰文件 + # 如果连接使用的是密钥文件,则删除该密钥文件 if [[ "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -7070,7 +8107,7 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" echo "1. 密鑰檔案路徑是否正確:$password_or_key" - echo "2. 密鑰檔案權限是否正確(應為 600)。" + echo "2. 密钥文件权限是否正确(应为 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else @@ -7141,7 +8178,7 @@ ssh_manager() { -# 列出可用的硬碟分割區 +# 列出可用的硬盘分区 list_partitions() { echo "可用的硬碟分割區:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" @@ -7353,7 +8390,7 @@ add_task() { echo "- 連接埠號碼 (預設 22)" echo "---------------------------------" read -e -p "請輸入任務名稱:" name - read -e -p "請輸入本地目錄:" local_path + read -e -p "请输入本地目录: " local_path read -e -p "請輸入遠端目錄:" remote_path while true; do @@ -7404,7 +8441,7 @@ delete_task() { IFS='|' read -r name local_path remote remote_path port options auth_method password_or_key <<< "$task" - # 如果任務使用的是金鑰文件,則刪除該金鑰文件 + # 如果任务使用的是密钥文件,则删除该密钥文件 if [[ "$auth_method" == "key" && "$password_or_key" == "$KEY_DIR"* ]]; then rm -f "$password_or_key" fi @@ -7431,7 +8468,7 @@ run_task() { num="$1" fi - # 如果沒有傳入任務編號,提示使用者輸入 + # 如果没有传入任务编号,提示用户输入 if [[ -z "$num" ]]; then read -e -p "請輸入要執行的任務編號:" num fi @@ -7663,7 +8700,7 @@ linux_info() { echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" @@ -8098,7 +9135,7 @@ docker_ssh_migration() { echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "請輸入要備份的容器名稱(多個空格分隔,回車備份全部運行中容器):" containers + read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers install tar jq gzip install_docker @@ -8121,7 +9158,7 @@ docker_ssh_migration() { echo "set -e" >> "$RESTORE_SCRIPT" echo "# 自動產生的還原腳本" >> "$RESTORE_SCRIPT" - # 記錄已打包過的 Compose 專案路徑,避免重複打包 + # 记录已打包过的 Compose 项目路径,避免重复打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -8135,7 +9172,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未偵測到 compose 目錄,請手動輸入路徑:" project_dir + read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -8188,11 +9225,11 @@ docker_ssh_migration() { done - # 備份 /home/docker 下的所有檔案(不含子目錄) + # 备份 /home/docker 下的所有文件(不含子目录) if [ -d "/home/docker" ]; then echo -e "${gl_kjlan}備份 /home/docker 下的檔案...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的檔案已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" @@ -8216,7 +9253,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # --------- 優先還原 Compose 專案 --------- + # --------- 优先还原 Compose 项目 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -8262,7 +9299,7 @@ docker_ssh_migration() { fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到鏡像訊息,跳過:$container${gl_bai}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } # 連接埠映射 PORT_ARGS="" @@ -8376,7 +9413,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 返回上一級選單" echo "------------------------" - read -e -p "請選擇:" choice + read -e -p "请选择: " choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; @@ -8685,6 +9722,180 @@ linux_docker() { +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} + +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPT解鎖狀態偵測" + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh + ;; + region) + send_stats "Region串流解鎖測試" + kpanel_run_remote_bash https://check.unlock.media + ;; + media) + send_stats "yeahwu串流解鎖偵測" + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh + ;; + ip-quality) + send_stats "xykt_IP品質體檢腳本" + kpanel_run_remote_bash https://IP.Check.Place + ;; + besttrace) + send_stats "besttrace三網回程延遲路由測試" + kpanel_run_remote_bash https://git.io/besttrace + ;; + mtr) + send_stats "mtr_trace三網回程線路測試" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh + ;; + superspeed) + send_stats "Superspeed三網測速" + kpanel_run_remote_bash https://git.io/superspeed_uxh + ;; + nxtrace-fast) + send_stats "nxtrace快速回程測試腳本" + kpanel_run_remote_bash https://nxtrace.org/nt + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020三線線路測試" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh + ;; + speedtest) + send_stats "i-abc多功能測速腳本" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh + ;; + net-quality) + send_stats "網路品質測試腳本" + kpanel_run_remote_bash https://Net.Check.Place + ;; + tcp-quality) + send_stats "TcpQuality TCP重傳偵測腳本" + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh + ;; + yabs) + send_stats "yabs效能測試" + check_swap + kpanel_run_remote_bash https://yabs.sh -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU效能測試腳本" + check_swap + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh + ;; + bench) + send_stats "bench效能測試" + kpanel_run_remote_bash https://bench.sh + ;; + ecs) + send_stats "spiritysdx融合怪測評" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "nodequality融合怪測評" + kpanel_run_remote_bash https://run.NodeQuality.com + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac +} + + linux_test() { while true; do @@ -8776,7 +9987,7 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京電信: 219.141.136.12" + echo "北京电信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" @@ -8787,7 +9998,7 @@ linux_test() { echo "廣州移動: 120.196.165.24" echo "成都電信: 61.139.2.69" echo "成都聯通: 119.6.6.6" - echo "成都移動: 211.137.96.205" + echo "成都移动: 211.137.96.205" echo "湖南電信: 36.111.200.100" echo "湖南聯通: 42.48.16.100" echo "湖南移動: 39.134.254.6" @@ -8882,7 +10093,7 @@ linux_Oracle() { echo -e "${gl_kjlan}2. ${gl_bai}卸載閒置機器活躍腳本" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD重裝系統腳本" - echo -e "${gl_kjlan}4. ${gl_bai}R探長開機腳本" + echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登入模式" echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢復工具" echo -e "${gl_kjlan}------------------------" @@ -9075,9 +10286,577 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "用法: k <建站指令> <網域名稱>" + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "已有網站或 LDNMP 環境任務正在執行" >&2 + exec {lock_fd}>&- + return 75 + fi + linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","re​​quired":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","re​​poDigest":"%s","updateStatus":"%s","re​​poDigest":"%s","updateStatus":"dnown」' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"完整 LDNMP"},{"id":"nginx","label":"僅Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudfl are-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on ","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"] },{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":}"' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "正在檢查安裝條件" + case "$profile" in + full) kpanel_ldnmp_event install 15 "正在安裝完整 LDNMP"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "正在安裝 Nginx"; nginx_install_all ;; + *) echo "不支援的安裝形態" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "正在驗證環境" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare 憑證通道無效" >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "不支持的防護動作" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "防護配置驗證失敗,正在恢復原配置" + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "當前協議不支援該優化動作" >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "優化驗證失敗,正在恢復原始配置" + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "正在創建更新前冷備" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "不支援的更新元件" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "正在短暫停止 LDNMP" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "正在歸檔 /home/web" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "正在恢復 LDNMP" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "正在掃描備份歸檔" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "正在解壓縮到安全暫存目錄" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "正在原子切換 /home/web" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "已有網站或 LDNMP 環境任務正在執行" + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP 環境任務已啟動" + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP 環境任務已完成" + kpanel_ldnmp_result succeeded "$action" "任務執行成功" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP 環境任務執行失敗" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "任务失败且无法确认安全回滚,需要人工处理" + else + kpanel_ldnmp_result failed "$action" "任務執行失敗" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP 環境管理" + echo "------------------------" + echo "1. 查看環境狀態" + echo "2. 安裝完整 LDNMP" + echo "3. 僅安裝 Nginx" + echo "4. 防護管理" + echo "5. 優化管理" + echo "6. 更新環境" + echo "7. 創建冷備" + echo "8. 還原備份" + echo "9. 卸載環境" + echo "0. 返回" + echo "------------------------" + read -e -p "請輸入你的選擇:" choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "更新元件 (nginx/mysql/php/redis/all):" component + read -e -p "目標版本(預設 latest):" version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "輸入要還原的備份檔名:" backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "输入 DELETE 确认卸载 LDNMP 环境: " confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "無效的輸入" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "不支援的 LDNMP 環境指令" >&2; return 2 ;; + esac +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP建置站" echo -e "${gl_huang}LDNMP建站" @@ -9085,7 +10864,7 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" - echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" + echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安裝獨角數發卡網" echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" @@ -9103,7 +10882,42 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主選單" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "請輸入你的選擇:" sub_choice + fi + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; + *) + echo "KPANEL_PROGRESS 100 不支援的 KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 網域名稱已存在,拒絕覆蓋現有產物" + return 1 + fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST 不是有效的 IP 或主機名" + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT 不是有效埠" + return 1 + fi + fi + echo "KPANEL_PROGRESS 5 正在啟動 kejilion.sh 原生一鍵建站流程" + else + read -e -p "請輸入你的選擇:" sub_choice + fi case $sub_choice in @@ -9112,7 +10926,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9138,7 +10952,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_URL=$(curl -s https://api.gitee.com/api/v5/repos/Discuz/DiscuzX/releases/latest | grep -o 'https://[^"]*Discuz_X[^"]*SC_UTF8[^"]*\.zip' | head -n 1) wget -O latest.zip ${LATEST_URL} @@ -9147,6 +10961,7 @@ linux_ldnmp() { rm -rf upload readme readme.html utility.html LICENSE qqqun.png rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9181,13 +10996,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming LATEST_VERSION=$(curl -s https://api.github.com/repos/kalcaddle/kodbox/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') wget -O latest.zip ${gh_proxy}github.com/kalcaddle/kodbox/archive/refs/tags/${LATEST_VERSION}.zip unzip -o latest.zip rm latest.zip mv /home/web/html/$yuming/kodbox* /home/web/html/$yuming/kodbox + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on @@ -9222,7 +11038,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming # wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && rm maccms10.zip wget ${gh_proxy}github.com/magicblack/maccms_down/raw/master/maccms10.zip && unzip maccms10.zip && mv maccms10-*/* . && rm -r maccms10-* && rm maccms10.zip @@ -9231,6 +11047,7 @@ linux_ldnmp() { cp /home/web/html/$yuming/template/DYXS2/asset/admin/dycms.html /home/web/html/$yuming/application/admin/view/system mv /home/web/html/$yuming/admin.php /home/web/html/$yuming/vip.php && wget -O /home/web/html/$yuming/application/extra/maccms.php ${gh_proxy}raw.githubusercontent.com/kejilion/Website_source_code/main/maccms.php + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9271,10 +11088,11 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/assimon/dujiaoka/releases/download/2.0.6/2.0.6-antibody.tar.gz && tar -zxvf 2.0.6-antibody.tar.gz && rm 2.0.6-antibody.tar.gz + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9327,7 +11145,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming docker exec php sh -c "php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"" @@ -9349,6 +11167,7 @@ linux_ldnmp() { docker exec php sh -c "cd /var/www/html/$yuming && composer require clarkwinkelmann/flarum-ext-emojionearea" + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9386,12 +11205,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/typecho/typecho/releases/latest/download/typecho.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9429,12 +11249,13 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget -O latest.zip ${gh_proxy}github.com/linkstackorg/linkstack/releases/latest/download/linkstack.zip unzip latest.zip rm latest.zip + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp @@ -9467,7 +11288,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming clear @@ -9566,6 +11387,7 @@ linux_ldnmp() { docker exec php rm -f /usr/local/etc/php/conf.d/optimized_php.ini + normalize_ldnmp_site_permissions "$yuming" || return 1 restart_ldnmp ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" @@ -9613,7 +11435,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -9706,14 +11528,14 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming wget ${gh_proxy}github.com/kejilion/Website_source_code/raw/refs/heads/main/ai_prompt_generator.zip unzip $(ls -t *.zip | head -n 1) rm -f $(ls -t *.zip | head -n 1) - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9748,7 +11570,7 @@ linux_ldnmp() { nginx_http_on cd /home/web/html - mkdir $yuming + prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -9776,7 +11598,7 @@ linux_ldnmp() { sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf - docker exec nginx chmod -R nginx:nginx /var/www/html + normalize_ldnmp_site_permissions "$yuming" || return 1 docker exec nginx nginx -s reload nginx_web_on @@ -9893,7 +11715,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -9943,7 +11765,7 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" echo "5. 更新完整環境" echo "------------------------" @@ -10078,6 +11900,23 @@ linux_ldnmp() { *) echo "無效的輸入!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站產物不完整" + return 1 + fi + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站產物不完整" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx 設定校驗失敗" + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh 原生建站產物已完成" + return 0 + fi break_end done @@ -10158,7 +11997,7 @@ moltbot_menu() { echo "4. 狀態日誌查看" echo "5. 換模型" echo "6. API管理" - echo "7. 機器人連線對接" + echo "7. 机器人连接对接" echo "8. 插件管理(安裝/刪除)" echo "9. 技能管理(安裝/刪除)" echo "10. 編輯主設定文件" @@ -10254,7 +12093,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未偵測到 API providers,跳過模型同步') + print('ℹ️ 未检测到 API providers,跳过模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -10456,7 +12295,7 @@ for name, provider in list(providers.items()): remote_set = set(remote_ids) if not remote_set: - fatal_errors.append(f'❌ {name} 上游 /models 為空,無法為該 provider 提供兜底模型') + fatal_errors.append(f'❌ {name} 上游 /models 为空,无法为该 provider 提供兜底模型') continue local_models = [m for m in model_list if isinstance(m, dict) and m.get('id')] @@ -10784,8 +12623,8 @@ EOF } add-openclaw-provider-interactive() { - send_stats "OpenClaw API新增" - echo "=== 互動式加入 OpenClaw Provider (全量模型) ===" + send_stats "OpenClaw API添加" + echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" # 1. Provider 名稱 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name @@ -10844,7 +12683,7 @@ EOF if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) - echo "🎯 使用第一個模型:$default_model" + echo "🎯 使用第一个模型: $default_model" elif [[ "$input_model" =~ ^[0-9]+$ ]] && [ "${#model_list[@]}" -gt 0 ] && [ "$input_model" -ge 1 ] && [ "$input_model" -le "${#model_list[@]}" ]; then default_model="${model_list[$((input_model-1))]}" echo "🎯 已選擇模型:$default_model" @@ -10862,7 +12701,7 @@ EOF echo "模型總數 :$model_count" echo "======================" - read -erp "是否同時新增其他所有可用模型? (y/N):" confirm + read -erp "是否同时添加其他所有可用模型? (y/N):" confirm install jq if [[ "$confirm" =~ ^[Yy]$ ]]; then @@ -11049,7 +12888,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('❌ 未偵測到 API providers,無法同步') + print('❌ 未检测到 API providers,无法同步') raise SystemExit(2) provider = providers.get(target) @@ -11121,7 +12960,7 @@ api_key = provider.get('apiKey') model_list = provider.get('models', []) if not base_url or not api_key or not isinstance(model_list, list) or not model_list: - print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,無法執行同步') + print(f'❌ provider {target} 缺少 baseUrl/apiKey/models,无法执行同步') raise SystemExit(3) if api not in SUPPORTED_APIS: @@ -11243,7 +13082,7 @@ PY2 echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失敗:上游模型為空或同步後無可用模型" + echo "❌ 同步失败:上游模型为空或同步后无可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -11255,7 +13094,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 - # 保留函數以相容選單調用,但不做任何改寫。 + # 保留函数以兼容菜单调用,但不做任何改写。 echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -11477,7 +13316,7 @@ PY case "$rc" in 0) send_stats "OpenClaw API刪除確認" - echo "✅ 刪除完成" + echo "✅ 删除完成" start_gateway ;; 2) @@ -11826,7 +13665,7 @@ PYTHON_EOF if [ "$second_exit" = "0" ] && [ "$second_http" -ge 200 ] && [ "$second_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" - OPENCLAW_PROBE_MESSAGE="${first_endpoint}-> HTTP ${first_http:-0},切換${second_endpoint} -> HTTP ${second_http}" + OPENCLAW_PROBE_MESSAGE="${first_endpoint} -> HTTP ${first_http:-0},切换 ${second_endpoint} -> HTTP ${second_http}" OPENCLAW_PROBE_LATENCY="${second_latency}ms" OPENCLAW_PROBE_REPLY="$reply_trimmed" return 0 @@ -11937,7 +13776,7 @@ PYTHON_EOF echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" - printf "是否切換到該模型? [y/N,Esc 返回列表]:" + printf "是否切换到该模型?[y/N,Esc 返回列表]: " IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -12214,7 +14053,7 @@ PYTHON_EOF echo "" echo "🧠 記憶與 AI:" echo "- [memory-core] # 基礎記憶 (文件檢索)" - echo "- [memory-lancedb] # 增強記憶 (向量資料庫)" + echo " - [memory-lancedb] # 增强记忆 (向量数据库)" echo "- [copilot-proxy] # Copilot 介面轉發" echo "" echo "⚙️ 功能擴充:" @@ -12277,7 +14116,7 @@ PYTHON_EOF continue fi - echo "📥 本機未發現,嘗試下載安裝:$plugin_full" + echo "📥 本地未发现,尝试下载安装: $plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -12370,7 +14209,7 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "二次確認:刪除僅影響使用者目錄 ~/.openclaw/workspace/skills,確認繼續? (y/N):" confirm_del + read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续? (y/N):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then echo "已取消刪除。" break_end @@ -12673,7 +14512,7 @@ openclaw_json_get_bool() { openclaw_show_bot_local_status_block echo "----------------------------------------" echo "1. Telegram 機器人對接" - echo "2. 飛書 (Lark) 機器人對接" + echo "2. 飞书 (Lark) 机器人对接" echo "3. WhatsApp 機器人對接" echo "4. QQ 機器人對接" echo "5. 微信機器人對接" @@ -12697,7 +14536,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "請輸入WhatsApp收到的連線碼 (例如 NYA99R2F)(輸入 0 退出):" code + read -e -p "请输入WhatsApp收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "錯誤:連接碼不能為空。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -12841,7 +14680,7 @@ EOF local real_type real_type=$(grep '^TYPE=' "$pkg_dir/backup.meta" | head -n1 | cut -d'=' -f2-) if [ "$real_type" != "$expected_type" ]; then - echo "❌ 備份類型不匹配,期望:$expected_type,實際: ${real_type:-未知}" + echo "❌ 備份類型不匹配,期望:$expected_type,实际: ${real_type:-未知}" return 1 fi @@ -12926,7 +14765,7 @@ if os.path.isdir(agents_root): src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) - print(f"✅ 已還原智能體記憶: {aid}")' "$workspaces_json" "$pkg_dir/payload" + print(f"✅ 已还原智能体记忆: {aid}")' "$workspaces_json" "$pkg_dir/payload" rm -rf "$tmp_unpack"; echo "✅ 記憶全量還原完成"; break_end } @@ -12986,7 +14825,7 @@ if os.path.isdir(agents_root): echo "✅ OpenClaw 專案備份完成 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 專案備份失敗" + echo "❌ OpenClaw 项目备份失败" fi rm -rf "$tmp_payload" @@ -13011,7 +14850,7 @@ if os.path.isdir(agents_root): fi local archive_path - archive_path=$(openclaw_read_import_path "請輸入 OpenClaw 專案備份包路徑") + archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") [ -z "$archive_path" ] && { echo "❌ 未輸入備份路徑"; break_end; return 1; } local tmp_unpack @@ -13055,7 +14894,7 @@ if os.path.isdir(agents_root): echo "▶️ 還原後啟動 OpenClaw gateway..." openclaw gateway start >/dev/null 2>&1 sleep 2 - echo "🩺 gateway 健康檢查:" + echo "🩺 gateway 健康检查:" openclaw gateway status || true fi @@ -13790,9 +15629,9 @@ PY else echo "可能流量/磁碟佔用: 視實際情況而定" fi - echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" + echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" - read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step + read -e -p "输入 yes 确认继续(默认 N): " confirm_step case "$confirm_step" in yes|YES) OPENCLAW_MEMORY_PREHEAT="true" @@ -13833,7 +15672,7 @@ PY echo "✅ memory.backend 已是 qmd" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ 已設定 memory.backend=qmd" + echo "✅ 已设置 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") @@ -14036,7 +15875,7 @@ EOF echo "❌ 未知方案:$scheme" return 1 esac - echo "✅ 已更新記憶方案配置" + echo "✅ 已更新记忆方案配置" return 0 } @@ -14114,7 +15953,7 @@ EOF esac echo "當前方案:$current_label" echo "" - echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" + echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" @@ -14331,7 +16170,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" + echo "✅ 已对所有智能体执行 force 重建并自动重启网关" fi else openclaw memory index @@ -14397,7 +16236,7 @@ EOF echo "⚠️ 權限備份失敗:$backup_file" return 1 } - echo "✅ 已備份目前權限配置:$backup_file" + echo "✅ 已备份当前权限配置: $backup_file" return 0 } @@ -14641,7 +16480,7 @@ try: print("自動放行技能 (autoAllowSkills):" + ("on" if auto else "off")) exists = d.get("exists", True) if not exists: - print("(審核文件不存在,使用系統內建安全兜底)") + print(" (审批文件不存在,使用系统内置安全兜底)") except Exception as e: print("(解析失敗:" + str(e) + ")") ' "$approvals_json" @@ -14719,7 +16558,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切換為完全開放模式 (警告:所有宿主機指令攔截已失效,智能體具有最高權限)${gl_bai}" + echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -14782,7 +16621,7 @@ try: al = agent_data.get("allowlist", []) if al: found = True - print("智能體 [%s]:" % agent_id) + print(" 智能体 [%s]:" % agent_id) for item in al: print(" - %s" % item) if not found: @@ -14858,7 +16697,7 @@ except Exception as e: break_end ;; 4) - echo "將清除所有自訂覆蓋,恢復 OpenClaw 剛安裝時的嚴格沙盒狀態。" + echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "已取消"; fi break_end @@ -15119,7 +16958,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體建立失敗" + echo "❌ 智能體創建失敗" return 1 fi } @@ -15279,7 +17118,7 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "即將清理過期/冗餘會話資料..." + echo "即将清理过期/冗余会话数据..." read -e -p "輸入 yes 確認:" confirm [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } openclaw sessions cleanup @@ -15577,21 +17416,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}錯誤:${gl_bai}${apps_dir}已存在但不是應用市場 Git 倉庫,拒絕覆蓋。" + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}應用程式清單下載失敗,拒絕使用不完整配置。${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}應用程式清單更新失敗,拒絕繼續使用可能過期的配置。${gl_bai}" + echo "請檢查網路或${apps_dir}中的本地修改後重試。" + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}正在更新應用程式清單請稍等…${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -15615,7 +17470,7 @@ while true; do echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager視覺化面板" echo -e "${gl_kjlan}5. ${color5}OpenList多重儲存文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠端桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" @@ -15635,7 +17490,7 @@ while true; do echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" @@ -15650,7 +17505,7 @@ while true; do echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自架AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp影片下載工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo檔案傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" @@ -15678,7 +17533,7 @@ while true; do echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw機器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" @@ -16050,7 +17905,7 @@ while true; do add_app_id clear - echo "poste.io已經安裝完成" + echo "poste.io已经安装完成" echo "------------------------" echo "您可以使用以下地址存取poste.io:" echo "https://$yuming" @@ -16472,7 +18327,7 @@ while true; do } - local docker_describe="portainer是一個輕量級的docker容器管理面板" + local docker_describe="portainer是一个轻量级的docker容器管理面板" local docker_url="官網介紹: https://www.portainer.io/" local docker_use="" local docker_passwd="" @@ -16605,8 +18460,8 @@ while true; do } - local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" - local docker_url="官網介紹: https://nextcloud.com/" + local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" + local docker_url="官网介绍: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" @@ -16645,7 +18500,7 @@ while true; do } - local docker_describe="dockge是一個可視化的docker-compose容器管理面板" + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" local docker_url="官網介紹:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" @@ -16690,7 +18545,7 @@ while true; do } - local docker_describe="searxng是一個私有且隱私的搜尋引擎站點" + local docker_describe="searxng是一个私有且隐私的搜索引擎站点" local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" @@ -17723,8 +19578,8 @@ while true; do } - local docker_describe="是一個輕量、高效能的音樂串流伺服器" - local docker_url="官網介紹: https://www.navidrome.org/" + local docker_describe="是一个轻量、高性能的音乐流媒体服务器" + local docker_url="官网介绍: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -18140,7 +19995,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd + read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -18450,7 +20305,7 @@ while true; do local app_id="91" local app_name="gitea私有程式碼倉庫" - local app_text="免費新一代的程式碼託管平台,提供接近 GitHub 的使用體驗。" + local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" local app_url="影片介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" @@ -18513,7 +20368,7 @@ while true; do } - local docker_describe="是一個基於Web的文件管理器" + local docker_describe="是一个基于Web的文件管理器" local docker_url="官網介紹: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" @@ -19299,7 +21154,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) + # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) local docker_port=8112 docker_rum() { @@ -19433,15 +21288,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" @@ -19450,6 +21297,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" @@ -19578,7 +21431,7 @@ linux_work() { echo -e "SSH常駐模式${tmux_sshd_status}" echo "開啟後SSH連線後會直接進入常駐模式,直接回到先前的工作狀態。" echo "------------------------" - echo "1. 開啟 2. 關閉" + echo "1. 开启 2. 关闭" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -20217,7 +22070,7 @@ linux_Settings() { root_use send_stats "py版本管理" echo "python版本管理" - echo "影片介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') @@ -20325,13 +22178,13 @@ EOF # 提示使用者輸入新的 SSH 連接埠號碼 read -e -p "請輸入新的 SSH 連接埠號碼:" new_port - # 判斷連接埠號碼是否在有效範圍內 + # 判断端口号是否在有效范围内 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH連接埠已修改" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "退出SSH連接埠修改" + send_stats "退出SSH埠修改" break else echo "連接埠號碼無效,請輸入1到65535之間的數字。" @@ -20511,7 +22364,7 @@ EOF case $sub_choice in 1) - # 提示使用者輸入新使用者名稱 + # 提示用户输入新用户名 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false @@ -20638,7 +22491,7 @@ EOF echo "美洲" echo "21. 美國西部時間 22. 美國東部時間" echo "23. 加拿大時間 24. 墨西哥時間" - echo "25. 巴西時間 26. 阿根廷時間" + echo "25. 巴西时间 26. 阿根廷时间" echo "------------------------" echo "31. UTC全球標準時間" echo "------------------------" @@ -20723,7 +22576,7 @@ EOF send_stats "主機名稱已更改" sleep 1 else - echo "已退出,未更改主機名稱。" + echo "已退出,未更改主机名。" break fi done @@ -20790,7 +22643,7 @@ EOF read -e -p "請輸入新任務的執行指令:" newquest echo "------------------------" echo "1. 每月任務 2. 每週任務" - echo "3. 每天任務 4. 每小時任務" + echo "3. 每天任务 4. 每小时任务" echo "------------------------" read -e -p "請輸入你的選擇:" dingshi @@ -20808,7 +22661,7 @@ EOF (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "輸入每小時的第幾分鐘執行任務? (分鐘,0-60):" minute + read -e -p "輸入每小時的第幾分鐘執行任務? (分钟,0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) @@ -20881,7 +22734,7 @@ EOF while true; do clear echo "限流關機功能" - echo "影片介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" echo "目前流量使用情況,重啟伺服器流量計算會清除!" output_status @@ -20958,7 +22811,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -21116,7 +22969,7 @@ EOF echo -e "6. 開放所有端口" echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" - echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" + echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" @@ -21170,7 +23023,7 @@ EOF echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash @@ -21250,7 +23103,7 @@ EOF send_stats "解除安裝科技lion腳本" echo "解除安裝科技lion腳本" echo "------------------------------------------------" - echo "將徹底卸載kejilion腳本,不影響你其他功能" + echo "将彻底卸载kejilion脚本,不影响你其他功能" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in @@ -21309,7 +23162,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 建立檔案 12. 編輯檔案 13. 修改檔案權限 14. 重新命名文件" + echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -21376,7 +23229,7 @@ linux_file() { ;; 15) # 删除文件 read -e -p "請輸入要刪除的檔名:" filename - rm -f "$filename" && echo "文件已刪除" || echo "刪除失敗" + rm -f "$filename" && echo "文件已删除" || echo "刪除失敗" send_stats "刪除文件" ;; 21) # 压缩文件/目录 @@ -21386,7 +23239,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -21436,7 +23289,7 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "錯誤: 文件不存在。" + echo "错误: 文件不存在。" send_stats "傳送文件失敗: 文件不存在" continue fi @@ -21561,7 +23414,7 @@ while true; do read -e -p "伺服器IP:" server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} - read -e -p "伺服器使用者名稱(root):" server_username + read -e -p "服务器用户名(root): " server_username local server_username=${server_username:-root} read -e -p "伺服器用戶密碼:" server_password @@ -21986,14 +23839,14 @@ echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" -echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" +echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" -echo "顯示系統資訊 k info" +echo "fail2ban管理 k fail2ban | k f2b [status|enable|disable]" +echo "显示系统信息 k info" echo "ROOT金鑰管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " echo "SSH公鑰導入(GitHub) k sshkey github " @@ -22028,7 +23881,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize @@ -22061,6 +23919,66 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" + ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" ;; fd|rp|反代) shift @@ -22097,6 +24015,20 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open @@ -22205,8 +24137,14 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "環境" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "刪除" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then @@ -22234,7 +24172,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; @@ -22249,7 +24192,7 @@ else ;; github ) shift - send_stats "從 GitHub 導入 SSH 公鑰" + send_stats "从 GitHub 导入 SSH 公钥" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From 60b7982f5622c5be958a0c8197d3077783505494 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 14:00:07 +0800 Subject: [PATCH 1245/1285] feat: install KPanel lightweight nodes --- kejilion.sh | 320 ++++++++++++++++++++++++++ tests/test_kpanel_light_node_smoke.sh | 90 ++++++++ 2 files changed, 410 insertions(+) create mode 100755 tests/test_kpanel_light_node_smoke.sh diff --git a/kejilion.sh b/kejilion.sh index 59e38bb26..d8fc30b6e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -16,7 +16,12 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -9722,6 +9727,310 @@ linux_docker() { +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel 轻量节点安装需要 root 权限。" >&2 + return 1 + } + for command_name in curl sha256sum systemctl install mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "缺少必要命令: ${command_name}" >&2 + return 1 + } + done + command -v useradd >/dev/null 2>&1 || { + echo "缺少必要命令: useradd" >&2 + return 1 + } + [ -d /run/systemd/system ] || { + echo "当前系统未运行 systemd,无法安装 KPanel 轻量节点。" >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "当前 CPU 架构暂不支持 KPanel 轻量节点。" >&2 + return 1 + ;; + esac +} + +kpanel_node_write_updater() { + install -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + systemctl daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_join() { + local token="${1:-}" node_name + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "轻量节点接入授权无效。" >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "轻量节点接入授权无效。" >&2 + return 2 + } + [ ! -e "$KPANEL_NODE_CONFIG" ] || { + echo "本机已接入一个 KPanel 中心;请先执行 k kpanel node uninstall。" >&2 + return 1 + } + if ! id kejilion-node >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell /usr/sbin/nologin kejilion-node || return 1 + fi + install -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + kpanel_node_cleanup_failed_join + return 1 + fi + node_name="$(hostname 2>/dev/null | tr -cd '[:alnum:]._- ' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + kpanel_node_cleanup_failed_join + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + kpanel_node_cleanup_failed_join + return 1 + fi + systemctl daemon-reload + if ! systemctl enable --now kejilion-node.service kejilion-node-update.timer || + ! systemctl is-active --quiet kejilion-node.service; then + kpanel_node_cleanup_failed_join + echo "KPanel 轻量节点启动失败。" >&2 + return 1 + fi + echo "KPanel 轻量节点已接入,后续将自动更新。" +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel 轻量节点未安装。" >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + systemctl --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel 轻量节点未安装。" >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "卸载 KPanel 轻量节点需要 root 权限。" >&2 + return 1 + } + systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + systemctl daemon-reload >/dev/null 2>&1 || true + echo "KPanel 轻量节点已从本机卸载;中心端的离线记录需在集群页面删除。" +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + return 2 + ;; + esac +} + kpanel_test_catalog() { cat <<'KPANEL_TEST_CATALOG' KPANEL_TEST_CATEGORY access IP 与解锁 @@ -24156,6 +24465,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift diff --git a/tests/test_kpanel_light_node_smoke.sh b/tests/test_kpanel_light_node_smoke.sh new file mode 100755 index 000000000..31b4a0e41 --- /dev/null +++ b/tests/test_kpanel_light_node_smoke.sh @@ -0,0 +1,90 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" +temporary_dir="$(mktemp -d)" +trap 'rm -rf -- "${temporary_dir}"' EXIT + +normalized_script="${temporary_dir}/kejilion.sh" +sed 's/\r$//' "${script_path}" >"${normalized_script}" +bash -n "${normalized_script}" + +extract_heredoc() { + local marker="$1" terminator="$2" output="$3" + awk -v marker="$marker" -v terminator="$terminator" ' + $0 == marker { capture=1; next } + capture && $0 == terminator { exit } + capture { print } + ' "${normalized_script}" >"${output}" +} + +updater="${temporary_dir}/update.sh" +extract_heredoc "\tcat >\"\$KPANEL_NODE_UPDATER\" <<'KPANEL_NODE_UPDATE'" "KPANEL_NODE_UPDATE" "${updater}" +test -s "${updater}" +bash -n "${updater}" + +protocol_body="$( + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${normalized_script}" +)" +dispatch_body="$( + awk ' + /^kpanel_node_dispatch\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${normalized_script}" +)" +join_body="$( + awk ' + /^kpanel_node_join\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${normalized_script}" +)" +service_body="$(sed -n "/^\[Unit\]$/,/^KPANEL_NODE_SERVICE$/p" "${normalized_script}" | head -n -1)" +timer_body="$(sed -n "/^\[Timer\]$/,/^KPANEL_NODE_UPDATE_TIMER$/p" "${normalized_script}" | head -n -1)" + +printf '%s\n' "${protocol_body}" | grep -F '[ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ]' >/dev/null +grep -F 'KJ_LIGHT_NODE_PROTOCOL=1' "${normalized_script}" >/dev/null +grep -F 'kpanel_node_dispatch "$@"' "${normalized_script}" >/dev/null +printf '%s\n' "${dispatch_body}" | grep -F 'join) kpanel_node_join "$@"' >/dev/null +printf '%s\n' "${dispatch_body}" | grep -F 'status) kpanel_node_status' >/dev/null +printf '%s\n' "${dispatch_body}" | grep -F 'update) kpanel_node_update' >/dev/null +printf '%s\n' "${dispatch_body}" | grep -F 'uninstall|remove) kpanel_node_uninstall' >/dev/null + +printf '%s\n' "${join_body}" | grep -F 'kpl1.*)' >/dev/null +printf '%s\n' "${join_body}" | grep -F 'useradd --system --no-create-home' >/dev/null +printf '%s\n' "${join_body}" | grep -F 'chown root:kejilion-node "$KPANEL_NODE_CONFIG"' >/dev/null +printf '%s\n' "${join_body}" | grep -F 'chmod 0640 "$KPANEL_NODE_CONFIG"' >/dev/null +grep -F '[ -d /run/systemd/system ]' "${normalized_script}" >/dev/null +if printf '%s\n' "${join_body}" | grep -Eq 'docker|podman'; then + echo "lightweight node installer unexpectedly depends on a container runtime" >&2 + exit 1 +fi + +grep -F 'base_url="https://github.com/kejilion/KPanel/releases/latest/download"' "${updater}" >/dev/null +grep -F -- "--proto '=https' --tlsv1.2" "${updater}" >/dev/null +grep -F 'SHA256SUMS' "${updater}" >/dev/null +grep -F 'sha256sum' "${updater}" >/dev/null +grep -F "grep -Eq '^[^[:space:]]+ light-v1$'" "${updater}" >/dev/null +grep -F 'was rolled back' "${updater}" >/dev/null +if grep -Eq 'curl .*(-k|--insecure)' "${updater}"; then + echo "lightweight node updater disables TLS verification" >&2 + exit 1 +fi + +printf '%s\n' "${service_body}" | grep -Fx 'User=kejilion-node' >/dev/null +printf '%s\n' "${service_body}" | grep -Fx 'NoNewPrivileges=true' >/dev/null +printf '%s\n' "${service_body}" | grep -Fx 'ProtectSystem=strict' >/dev/null +printf '%s\n' "${service_body}" | grep -Fx 'ProtectHome=true' >/dev/null +printf '%s\n' "${service_body}" | grep -Fx 'CapabilityBoundingSet=' >/dev/null +printf '%s\n' "${service_body}" | grep -Fx 'RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6' >/dev/null +printf '%s\n' "${timer_body}" | grep -Fx 'OnUnitActiveSec=24h' >/dev/null +printf '%s\n' "${timer_body}" | grep -Fx 'RandomizedDelaySec=6h' >/dev/null +printf '%s\n' "${timer_body}" | grep -Fx 'Persistent=true' >/dev/null + +echo "KPanel lightweight-node installer smoke checks passed." From 4f23412bfa401ee421b581e5b28900b754d5eee8 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 17:53:47 +0800 Subject: [PATCH 1246/1285] fix(kpanel): support minimal systemd node hosts --- kejilion.sh | 60 +++++++++++++++++++---- tests/test_kpanel_light_node_smoke.sh | 68 ++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 10 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index d8fc30b6e..5c127514c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9740,16 +9740,23 @@ kpanel_node_preflight() { echo "KPanel 轻量节点安装需要 root 权限。" >&2 return 1 } - for command_name in curl sha256sum systemctl install mktemp; do + for command_name in curl sha256sum systemctl mktemp; do command -v "$command_name" >/dev/null 2>&1 || { echo "缺少必要命令: ${command_name}" >&2 return 1 } done - command -v useradd >/dev/null 2>&1 || { - echo "缺少必要命令: useradd" >&2 + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "缺少必要命令: install (coreutils)" >&2 return 1 } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "缺少系统账户创建工具: useradd、systemd-sysusers 或 adduser" >&2 + return 1 + fi [ -d /run/systemd/system ] || { echo "当前系统未运行 systemd,无法安装 KPanel 轻量节点。" >&2 return 1 @@ -9764,8 +9771,47 @@ kpanel_node_preflight() { esac } +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "现有 kejilion-node 账户的主组不安全,拒绝继续。" >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "缺少系统组创建工具: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel 轻量节点低权限账户创建失败。" >&2 + return 1 + } +} + kpanel_node_write_updater() { - install -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' #!/bin/bash set -euo pipefail @@ -9949,10 +9995,8 @@ kpanel_node_join() { echo "本机已接入一个 KPanel 中心;请先执行 k kpanel node uninstall。" >&2 return 1 } - if ! id kejilion-node >/dev/null 2>&1; then - useradd --system --no-create-home --home-dir /nonexistent --shell /usr/sbin/nologin kejilion-node || return 1 - fi - install -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then kpanel_node_cleanup_failed_join return 1 diff --git a/tests/test_kpanel_light_node_smoke.sh b/tests/test_kpanel_light_node_smoke.sh index 31b4a0e41..29c0f2156 100755 --- a/tests/test_kpanel_light_node_smoke.sh +++ b/tests/test_kpanel_light_node_smoke.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" script_path="${project_root}/kejilion.sh" temporary_dir="$(mktemp -d)" trap 'rm -rf -- "${temporary_dir}"' EXIT @@ -45,6 +45,13 @@ join_body="$( capture && /^}$/ { exit } ' "${normalized_script}" )" +account_body="$( + awk ' + /^kpanel_node_ensure_account\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${normalized_script}" +)" service_body="$(sed -n "/^\[Unit\]$/,/^KPANEL_NODE_SERVICE$/p" "${normalized_script}" | head -n -1)" timer_body="$(sed -n "/^\[Timer\]$/,/^KPANEL_NODE_UPDATE_TIMER$/p" "${normalized_script}" | head -n -1)" @@ -57,10 +64,22 @@ printf '%s\n' "${dispatch_body}" | grep -F 'update) kpanel_node_update' >/dev/nu printf '%s\n' "${dispatch_body}" | grep -F 'uninstall|remove) kpanel_node_uninstall' >/dev/null printf '%s\n' "${join_body}" | grep -F 'kpl1.*)' >/dev/null -printf '%s\n' "${join_body}" | grep -F 'useradd --system --no-create-home' >/dev/null +printf '%s\n' "${join_body}" | grep -F 'kpanel_node_ensure_account || return 1' >/dev/null +printf '%s\n' "${join_body}" | grep -F '"$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node' >/dev/null +printf '%s\n' "${account_body}" | grep -F 'useradd --system --no-create-home' >/dev/null +printf '%s\n' "${account_body}" | grep -F 'systemd-sysusers "$sysusers_config"' >/dev/null +printf '%s\n' "${account_body}" | grep -F 'adduser --system --group --no-create-home' >/dev/null +printf '%s\n' "${account_body}" | grep -F 'adduser -S -D -H' >/dev/null +printf '%s\n' "${account_body}" | grep -F 'id -gn kejilion-node' >/dev/null printf '%s\n' "${join_body}" | grep -F 'chown root:kejilion-node "$KPANEL_NODE_CONFIG"' >/dev/null printf '%s\n' "${join_body}" | grep -F 'chmod 0640 "$KPANEL_NODE_CONFIG"' >/dev/null grep -F '[ -d /run/systemd/system ]' "${normalized_script}" >/dev/null +grep -F 'KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)"' "${normalized_script}" >/dev/null +grep -F '"$KPANEL_NODE_INSTALL_BIN" -d -o root -g root' "${normalized_script}" >/dev/null +if grep -F $'\tinstall -d -o root' "${normalized_script}" >/dev/null; then + echo "lightweight node installer is shadowed by the package install helper" >&2 + exit 1 +fi if printf '%s\n' "${join_body}" | grep -Eq 'docker|podman'; then echo "lightweight node installer unexpectedly depends on a container runtime" >&2 exit 1 @@ -87,4 +106,49 @@ printf '%s\n' "${timer_body}" | grep -Fx 'OnUnitActiveSec=24h' >/dev/null printf '%s\n' "${timer_body}" | grep -Fx 'RandomizedDelaySec=6h' >/dev/null printf '%s\n' "${timer_body}" | grep -Fx 'Persistent=true' >/dev/null +# Exercise the systemd-sysusers fallback used by minimal systemd hosts that do +# not ship useradd. The fake PATH intentionally contains no useradd/adduser. +fallback_bin="${temporary_dir}/fallback-bin" +fallback_marker="${temporary_dir}/account-created" +mkdir -p "${fallback_bin}" +cat >"${fallback_bin}/id" <<'MOCK_ID' +#!/bin/bash +if [ -f "${KPANEL_TEST_ACCOUNT_MARKER}" ]; then + if [ "${1:-}" = "-gn" ]; then + printf '%s\n' kejilion-node + fi + exit 0 +fi +exit 1 +MOCK_ID +cat >"${fallback_bin}/systemd-sysusers" <<'MOCK_SYSUSERS' +#!/bin/bash +grep -F 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent ' "$1" >/dev/null +touch "${KPANEL_TEST_ACCOUNT_MARKER}" +MOCK_SYSUSERS +cat >"${fallback_bin}/mktemp" <<'MOCK_MKTEMP' +#!/bin/bash +/usr/bin/mktemp "$@" +MOCK_MKTEMP +cat >"${fallback_bin}/rm" <<'MOCK_RM' +#!/bin/bash +/usr/bin/rm "$@" +MOCK_RM +cat >"${fallback_bin}/grep" <<'MOCK_GREP' +#!/bin/bash +/usr/bin/grep "$@" +MOCK_GREP +cat >"${fallback_bin}/touch" <<'MOCK_TOUCH' +#!/bin/bash +/usr/bin/touch "$@" +MOCK_TOUCH +chmod +x "${fallback_bin}"/* +( + export PATH="${fallback_bin}" + export KPANEL_TEST_ACCOUNT_MARKER="${fallback_marker}" + eval "${account_body}" + kpanel_node_ensure_account +) +test -f "${fallback_marker}" + echo "KPanel lightweight-node installer smoke checks passed." From e9f1670d0a89b06bf3e690509deb184e4804d6dd Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 18:09:21 +0800 Subject: [PATCH 1247/1285] fix(kpanel): synchronize regional node bootstrap --- cn/kejilion.sh | 2655 +++++++++++++++++++++++-- kejilion.sh | 4 +- tests/test_kpanel_light_node_smoke.sh | 2 +- 3 files changed, 2465 insertions(+), 196 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 139344735..e72cb41a3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -16,6 +16,23 @@ canshu="CN" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + +kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_WEB_INTERACTIVE:-}" = "1" ] || + [ "${KJ_LDNMP_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] +} + quanju_canshu() { if [ "$canshu" = "CN" ]; then @@ -100,17 +117,18 @@ fi -canshu_v6 -CheckFirstRun_true -yinsiyuanquan2 - +if ! kpanel_protocol_active; then + canshu_v6 + CheckFirstRun_true + yinsiyuanquan2 -sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 -sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 -cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 -cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 -ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bashrc > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.profile > /dev/null 2>&1 + sed -i '/^alias k=/d' ~/.bash_profile > /dev/null 2>&1 + cp -f ./kejilion.sh ~/kejilion.sh > /dev/null 2>&1 + cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 + ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 +fi @@ -141,7 +159,9 @@ UserLicenseAgreement() { fi } -CheckFirstRun_false +if ! kpanel_protocol_active; then + CheckFirstRun_false +fi @@ -1540,6 +1560,11 @@ certs_status() { send_stats "域名证书申请成功" else send_stats "域名证书申请失败" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + ! kpanel_web_interactive; then + echo "KPANEL_PROGRESS 100 域名证书申请失败,请检查 DNS、80/443 端口和签发限额" + return 1 + fi echo -e "${gl_hong}注意: ${gl_bai}证书申请失败,请检查以下可能原因并重试:" echo -e "1. 域名拼写错误 ➠ 请检查域名输入是否正确" echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" @@ -1618,6 +1643,10 @@ certs_status() { repeat_add_yuming() { if [ -e /home/web/conf.d/$yuming.conf ]; then send_stats "域名重复使用" + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖 kejilion.sh 或 KPanel 的现有产物" + return 1 + fi web_del "${yuming}" > /dev/null 2>&1 fi @@ -1625,6 +1654,15 @@ fi add_yuming() { + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + yuming="${KJ_WEB_DOMAIN:-}" + if [ -z "$yuming" ] || [ ${#yuming} -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + return 0 + fi ip_address echo -e "先将域名解析到本机IP: ${gl_huang}$ipv4_address $ipv6_address${gl_bai}" read -e -p "请输入你的IP或者解析过的域名: " yuming @@ -1820,32 +1858,72 @@ web_cache() { web_del() { send_stats "删除站点数据" - yuming_list="${1:-}" - if [ -z "$yuming_list" ]; then - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_list - if [[ -z "$yuming_list" ]]; then + local -a yuming_list=() + if [ "$#" -gt 0 ]; then + yuming_list=("$@") + else + local yuming_input="" + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_input + if [[ -z "$yuming_input" ]]; then return fi + read -r -a yuming_list <<< "$yuming_input" fi - for yuming in $yuming_list; do + local action_status=0 + for yuming in "${yuming_list[@]}"; do + if [ -z "$yuming" ] || [ "${#yuming}" -gt 253 ] || + ! printf '%s' "$yuming" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "无效域名,拒绝删除: $yuming" + action_status=1 + continue + fi + echo "正在删除域名: $yuming" - rm -r /home/web/html/$yuming > /dev/null 2>&1 - rm /home/web/conf.d/$yuming.conf > /dev/null 2>&1 - rm /home/web/certs/${yuming}_key.pem > /dev/null 2>&1 - rm /home/web/certs/${yuming}_cert.pem > /dev/null 2>&1 + rm -rf -- "/home/web/html/$yuming" > /dev/null 2>&1 + rm -f -- "/home/web/conf.d/$yuming.conf" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 + rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') - dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + if [ -f /home/web/docker-compose.yml ] && + docker inspect mysql > /dev/null 2>&1; then + dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') + echo "正在删除数据库: $dbname" + if docker exec mysql mysql -u root -p"$dbrootpasswd" \ + -e "DROP DATABASE IF EXISTS \`${dbname}\`;" > /dev/null 2>&1; then + echo "KPANEL_DELETE_DATABASE dropped $yuming" + else + echo "KPANEL_DELETE_DATABASE failed $yuming" + action_status=1 + fi + else + echo "KPANEL_DELETE_DATABASE skipped $yuming" + fi - # 删除数据库前检查是否存在,避免报错 - echo "正在删除数据库: $dbname" - docker exec mysql mysql -u root -p"$dbrootpasswd" -e "DROP DATABASE ${dbname};" > /dev/null 2>&1 + if [ -e "/home/web/html/$yuming" ] || + [ -e "/home/web/conf.d/$yuming.conf" ] || + [ -e "/home/web/certs/${yuming}_key.pem" ] || + [ -e "/home/web/certs/${yuming}_cert.pem" ]; then + echo "站点产物删除不完整: $yuming" + action_status=1 + else + echo "KPANEL_DELETE_SITE deleted $yuming" + fi done - docker exec nginx nginx -s reload + if docker inspect nginx > /dev/null 2>&1; then + if ! docker exec nginx nginx -t > /dev/null 2>&1 || + ! docker exec nginx nginx -s reload; then + echo "Nginx 配置验证或重载失败" + action_status=1 + fi + else + echo "KPANEL_DELETE_WARNING nginx_unavailable" + fi + return "$action_status" } @@ -2378,8 +2456,66 @@ check_nginx_compression() { fi } +ldnmp_optimization_mode() { + local mode="${1:-}" + local cpu_cores connections connections_per_core php_fpm_source mysql_source + case "$mode" in + standard) + connections_per_core=1024 + php_fpm_source="www-1.conf" + mysql_source="custom_mysql_config-1.cnf" + ;; + high) + connections_per_core=2048 + php_fpm_source="www.conf" + mysql_source="custom_mysql_config.cnf" + ;; + *) + echo "不支持的 LDNMP 优化模式" >&2 + return 2 + ;; + esac - + cpu_cores=$(nproc) + connections=$((connections_per_core * cpu_cores)) + sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf + sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf + + wget -O /home/optimized_php.ini "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini" && + docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini + rm -f /home/optimized_php.ini + + wget -O /home/www.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${php_fpm_source}" && + docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf + docker inspect php74 >/dev/null 2>&1 && + docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf + rm -f /home/www.conf + + if [ "$mode" = high ]; then + patch_wp_memory_limit 512M 512M + else + patch_wp_memory_limit + fi + patch_wp_debug + fix_phpfpm_conf php + docker inspect php74 >/dev/null 2>&1 && fix_phpfpm_conf php74 + + wget -O /home/custom_mysql_config.cnf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/${mysql_source}" && + docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ + rm -f /home/custom_mysql_config.cnf + + cd /home/web && docker compose restart || return 1 + if [ "$mode" = high ]; then + optimize_web_server + echo "LDNMP环境已设置成 高性能模式" + else + optimize_balanced + echo "LDNMP环境已设置成 标准模式" + fi +} web_optimization() { while true; do @@ -2401,83 +2537,11 @@ web_optimization() { case $sub_choice in 1) send_stats "站点标准模式" - - local cpu_cores=$(nproc) - local connections=$((1024 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - - # php调优 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php调优 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www-1.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql调优 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config-1.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - - cd /home/web && docker compose restart - - optimize_balanced - - - echo "LDNMP环境已设置成 标准模式" - + ldnmp_optimization_mode standard ;; 2) send_stats "站点高性能模式" - - # nginx调优 - local cpu_cores=$(nproc) - local connections=$((2048 * ${cpu_cores})) - sed -i "s/worker_processes.*/worker_processes ${cpu_cores};/" /home/web/nginx.conf - sed -i "s/worker_connections.*/worker_connections ${connections};/" /home/web/nginx.conf - - # php调优 - wget -O /home/optimized_php.ini ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/optimized_php.ini - docker cp /home/optimized_php.ini php:/usr/local/etc/php/conf.d/optimized_php.ini - docker cp /home/optimized_php.ini php74:/usr/local/etc/php/conf.d/optimized_php.ini - rm -rf /home/optimized_php.ini - - # php调优 - wget -O /home/www.conf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/www.conf - docker cp /home/www.conf php:/usr/local/etc/php-fpm.d/www.conf - docker cp /home/www.conf php74:/usr/local/etc/php-fpm.d/www.conf - rm -rf /home/www.conf - - patch_wp_memory_limit 512M 512M - patch_wp_debug - - fix_phpfpm_conf php - fix_phpfpm_conf php74 - - # mysql调优 - wget -O /home/custom_mysql_config.cnf ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/custom_mysql_config.cnf - docker cp /home/custom_mysql_config.cnf mysql:/etc/mysql/conf.d/ - rm -rf /home/custom_mysql_config.cnf - - cd /home/web && docker compose restart - - optimize_web_server - - echo "LDNMP环境已设置成 高性能模式" - + ldnmp_optimization_mode high ;; 3) send_stats "nginx_gzip on" @@ -2578,19 +2642,18 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 区域检查 - local country=$(curl -s --max-time 2 ipinfo.io/country) - [[ "$country" == "CN" ]] && return - - # 2. 获取本地镜像信息 - local container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}}' "$container_name" 2>/dev/null) + # 1. 获取容器及本地镜像信息。更新检测不再按地区跳过。 + local container_info + container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return - local container_created=$(echo "$container_info" | cut -d',' -f1) - local full_image_name=$(echo "$container_info" | cut -d',' -f2) - local container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) + local container_created full_image_name container_image_id container_created_ts + container_created=$(echo "$container_info" | cut -d',' -f1) + full_image_name=$(echo "$container_info" | cut -d',' -f2) + container_image_id=$(echo "$container_info" | cut -d',' -f3) + container_created_ts=$(date -d "$container_created" +%s 2>/dev/null) - # 3. 智能路由判断 + # 2. 智能路由判断 if [[ "$full_image_name" == ghcr.io* ]]; then # --- 场景 A: 镜像在 GitHub (ghcr.io) --- # 提取仓库路径,例如 ghcr.io/onexru/oneimg -> onexru/oneimg @@ -2606,19 +2669,45 @@ check_docker_image_update() { else # --- 场景 C: 标准 Docker Hub --- - local image_repo=${full_image_name%%:*} - local image_tag=${full_image_name##*:} - [[ "$image_repo" == "$image_tag" ]] && image_tag="latest" + local docker_ref image_repo image_tag api_payload remote_digest local_digest + docker_ref=${full_image_name#docker.io/} + docker_ref=${docker_ref#index.docker.io/} + docker_ref=${docker_ref#registry-1.docker.io/} + if [[ "$docker_ref" == *@* ]]; then + image_repo=${docker_ref%@*} + image_tag="latest" + elif [[ "${docker_ref##*/}" == *:* ]]; then + image_repo=${docker_ref%:*} + image_tag=${docker_ref##*:} + else + image_repo=$docker_ref + image_tag="latest" + fi [[ "$image_repo" != */* ]] && image_repo="library/$image_repo" local api_url="https://hub.docker.com/v2/repositories/$image_repo/tags/$image_tag" - local remote_date=$(curl -s "$api_url" | jq -r '.last_updated' 2>/dev/null) + api_payload=$(curl -fsSL --max-time 8 "$api_url" 2>/dev/null) + remote_digest=$(printf '%s' "$api_payload" | jq -r '.digest // empty' 2>/dev/null) + local remote_date + remote_date=$(printf '%s' "$api_payload" | jq -r '.last_updated // empty' 2>/dev/null) + local_digest=$( + docker image inspect --format='{{range .RepoDigests}}{{println .}}{{end}}' "$container_image_id" 2>/dev/null | + sed -n 's/^.*@\(sha256:[a-f0-9]\{64\}\)$/\1/p' | + head -n 1 + ) + if [[ "$remote_digest" =~ ^sha256:[a-f0-9]{64}$ && "$local_digest" =~ ^sha256:[a-f0-9]{64}$ ]]; then + if [[ "$remote_digest" != "$local_digest" ]]; then + update_status="${gl_huang}发现新版本!${gl_bai}" + fi + return + fi fi - # 4. 时间戳对比 + # 3. Registry 未提供可比较摘要时,兼容使用发布时间判断。 if [[ -n "$remote_date" && "$remote_date" != "null" ]]; then local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) - if [[ $container_created_ts -lt $remote_ts ]]; then + if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && + [[ $container_created_ts -lt $remote_ts ]]; then update_status="${gl_huang}发现新版本!${gl_bai}" fi fi @@ -2891,11 +2980,412 @@ grep -qxF "${app_id}" /home/docker/appno.txt || echo "${app_id}" >> /home/docker } +kpanel_app_progress() { + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_app_interactive_manage_choice() { + local target_variable="$1" + local selected_choice="" + + if [ "${KJ_APP_MARKER_RECOVERY:-0}" != "1" ]; then + kpanel_app_verified_service true || return 1 + fi + read -r -e -p "请输入你的选择: " selected_choice || return 1 + if [[ ! "$selected_choice" =~ ^[0-9]+$ ]]; then + echo "错误: KPanel 应用管理终端只接受菜单编号" + return 1 + fi + printf -v "$target_variable" '%s' "$selected_choice" +} + +kpanel_app_interactive_choice() { + local target_variable="$1" + + [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || return 2 + case "${KJ_APP_ACTION:-}" in + install) + printf -v "$target_variable" '%s' "1" + ;; + update) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "2" + ;; + uninstall) + kpanel_app_verified_service true || return 1 + printf -v "$target_variable" '%s' "3" + ;; + manage) + kpanel_app_interactive_manage_choice "$target_variable" + ;; + direct_access) + kpanel_app_verified_service true || return 1 + case "${KJ_APP_ACCESS_MODE:-}" in + direct) + printf -v "$target_variable" '%s' "7" + ;; + domain_only) + printf -v "$target_variable" '%s' "8" + ;; + *) + echo "错误: KPanel 未提供有效的应用访问模式" + return 1 + ;; + esac + ;; + *) + echo "错误: KPanel 交互终端不支持此应用操作" + return 1 + ;; + esac +} + +kpanel_web_progress() { + [ "${KJ_WEB_NONINTERACTIVE:-}" = "1" ] || return 0 + printf 'KPANEL_PROGRESS %s %s\n' "$1" "$2" +} + +kpanel_web_interactive() { + [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && + [ "${KJ_WEB_INTERACTIVE:-0}" = "1" ] +} + +kpanel_app_service_name() { + local service_name="${docker_app_service:-${docker_name:-}}" + + if [[ ! "$service_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "错误: 应用主容器名称无效" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_verified_service() { + local verify_expected="${1:-true}" + local service_name="" + local container_id="" + local expected_id="${KJ_APP_EXPECTED_CONTAINER_ID:-}" + + service_name="$(kpanel_app_service_name)" || return 1 + container_id="$(docker inspect --format '{{.Id}}' "$service_name" 2>/dev/null)" || { + echo "错误: 未发现应用主容器 ${service_name}" >&2 + return 1 + } + [ -n "$container_id" ] || { + echo "错误: 无法确认应用主容器 ${service_name}" >&2 + return 1 + } + if [ "$verify_expected" = "true" ] && [ -n "$expected_id" ] && + [ "$container_id" != "$expected_id" ]; then + echo "错误: 应用主容器已变化,请刷新面板后重试" >&2 + return 1 + fi + printf '%s\n' "$service_name" +} + +kpanel_app_access_path() { + if [[ ! "${docker_name:-}" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$ ]]; then + echo "错误: 应用状态文件名称无效" >&2 + return 1 + fi + printf '/home/docker/%s_access.conf\n' "$docker_name" +} + +kpanel_app_read_access_mode() { + local access_path="" + local access_mode="" + local service_name="" + local container_ip="" + + access_path="$(kpanel_app_access_path)" || return 1 + if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then + access_mode="$(tr -d '\r\n' < "$access_path" 2>/dev/null)" + fi + case "$access_mode" in + direct|domain_only) + printf '%s\n' "$access_mode" + return 0 + ;; + esac + service_name="$(kpanel_app_service_name)" || return 1 + container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" + if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && + iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + printf '%s\n' "domain_only" + else + printf '%s\n' "direct" + fi +} + +kpanel_app_write_access_mode() { + local access_mode="$1" + local access_path="" + local temporary="" + + case "$access_mode" in + direct|domain_only) ;; + *) + echo "错误: 不支持的应用访问模式" >&2 + return 1 + ;; + esac + setup_docker_dir || return 1 + access_path="$(kpanel_app_access_path)" || return 1 + temporary="$(mktemp "/home/docker/.${docker_name}_access.XXXXXX")" || return 1 + if ! printf '%s\n' "$access_mode" > "$temporary" || + ! chmod 0644 "$temporary" || + ! mv -f "$temporary" "$access_path"; then + rm -f "$temporary" + return 1 + fi +} + +kpanel_app_apply_access_mode() { + local access_mode="$1" + local verify_expected="${2:-true}" + local service_name="" + + service_name="$(kpanel_app_verified_service "$verify_expected")" || return 1 + ip_address + case "$access_mode" in + direct) + clear_container_rules "$service_name" "$ipv4_address" || return 1 + ;; + domain_only) + block_container_port "$service_name" "$ipv4_address" || return 1 + ;; + *) + echo "错误: 不支持的应用访问模式" >&2 + return 1 + ;; + esac + kpanel_app_write_access_mode "$access_mode" +} + +kpanel_app_restore_access_mode() { + local access_mode="$1" + + if [ "$access_mode" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false + else + kpanel_app_write_access_mode direct + fi +} + +kpanel_app_remove_compatibility_state() { + local access_path="" + + access_path="$(kpanel_app_access_path)" || return 1 + rm -f "/home/docker/${docker_name}_port.conf" "$access_path" || return 1 + if [ -f /home/docker/appno.txt ]; then + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt || return 1 + fi +} + +kpanel_app_install_port() { + local requested_port="${KJ_APP_PORT:-${docker_port:-}}" + + case "$requested_port" in + ''|*[!0-9]*) + echo "错误: KPanel 未提供有效的应用端口" + return 1 + ;; + esac + if [ "$requested_port" -lt 1 ] || [ "$requested_port" -gt 65535 ]; then + echo "错误: KPanel 应用端口必须在 1-65535 之间" + return 1 + fi + if kpanel_app_port_in_use "$requested_port"; then + echo "错误: 端口 ${requested_port} 已被占用" + return 1 + fi + docker_port="$requested_port" + return 0 +} + +kpanel_app_port_in_use() { + local requested_port="$1" + + ss -H -lntu 2>/dev/null | + awk -v requested_port="$requested_port" ' + { + local_address = $5 + sub(/^.*:/, "", local_address) + if (local_address == requested_port) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' +} + +kpanel_app_choose_install_port() { + local app_port="" + + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ] && [ -n "${KJ_APP_PORT:-}" ]; then + kpanel_app_install_port + return $? + fi + while true; do + read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port + app_port=${app_port:-${docker_port}} + + if kpanel_app_port_in_use "$app_port"; then + echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" + send_stats "应用端口已被占用" + else + docker_port="$app_port" + return 0 + fi + done +} + +kpanel_run_docker_app_install() { + local adapter="$1" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + if [ "${KJ_APP_ACTION:-}" != "install" ]; then + echo "错误: KPanel 当前仅允许非交互安装" + return 1 + fi + + kpanel_app_progress 5 "正在校验端口与宿主机环境" + kpanel_app_install_port || return 1 + setup_docker_dir || return 1 + check_disk_space "${app_size:-1}" /home/docker || return 1 + kpanel_app_progress 15 "正在准备 Docker 运行环境" + install jq || return 1 + install_docker || return 1 + kpanel_app_progress 30 "正在执行 kejilion.sh 应用安装函数" + + if [ "$adapter" = "plus" ]; then + if ! docker_app_install; then + echo "安装失败: 未登记应用状态" + return 1 + fi + else + if ! docker_rum; then + echo "安装失败: 未登记应用状态" + return 1 + fi + fi + + kpanel_app_progress 90 "正在写入 kejilion.sh 兼容状态" + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + if [ "${KJ_APP_ACCESS_MODE:-direct}" = "domain_only" ]; then + kpanel_app_apply_access_mode domain_only false || return 1 + else + kpanel_app_write_access_mode direct || return 1 + fi + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "应用安装完成" + echo "$docker_name 已经安装完成" + return 0 +} + +kpanel_run_docker_app_action() { + local adapter="$1" + local action="${KJ_APP_ACTION:-}" + local service_name="" + local access_mode="" + + [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || return 2 + case "$action" in + install) + kpanel_run_docker_app_install "$adapter" + return $? + ;; + update|uninstall|direct_access) ;; + *) + echo "错误: KPanel 不支持此应用操作" + return 1 + ;; + esac + + kpanel_app_progress 5 "正在核对 kejilion.sh 安装标记与主容器" + service_name="$(kpanel_app_verified_service true)" || return 1 + if ! grep -qxF "${app_id}" /home/docker/appno.txt 2>/dev/null; then + if [ "${KJ_APP_RECONCILE_MARKER:-0}" != "1" ]; then + echo "错误: 未发现 kejilion.sh 应用安装标记" + return 1 + fi + kpanel_app_progress 10 "正在修复 kejilion.sh 应用安装标记" + add_app_id || return 1 + fi + + case "$action" in + update) + access_mode="$(kpanel_app_read_access_mode)" || return 1 + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在执行 kejilion.sh 原生更新函数" + if [ "$adapter" = "plus" ]; then + docker_app_update || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + docker_rum || return 1 + fi + kpanel_app_verified_service false >/dev/null || return 1 + add_app_id + kpanel_app_progress 80 "正在恢复应用访问策略" + kpanel_app_restore_access_mode "$access_mode" || return 1 + if [ "$adapter" = "standard" ]; then + [ -n "${docker_use:-}" ] && $docker_use + [ -n "${docker_passwd:-}" ] && $docker_passwd + fi + kpanel_app_progress 100 "应用更新完成" + echo "$service_name 已经更新完成" + ;; + uninstall) + kpanel_app_verified_service true >/dev/null || return 1 + kpanel_app_progress 25 "正在执行 kejilion.sh 原生卸载函数" + if [ "$adapter" = "plus" ]; then + docker_app_uninstall || return 1 + else + docker rm -f "$docker_name" || return 1 + docker rmi -f "$docker_img" >/dev/null 2>&1 || true + rm -rf "/home/docker/$docker_name" || return 1 + fi + if docker inspect "$service_name" >/dev/null 2>&1; then + echo "错误: 卸载函数完成后主容器仍然存在" + return 1 + fi + kpanel_app_remove_compatibility_state || return 1 + kpanel_app_progress 100 "应用卸载完成" + echo "$service_name 已经卸载完成" + ;; + direct_access) + access_mode="${KJ_APP_ACCESS_MODE:-}" + case "$access_mode" in + direct|domain_only) ;; + *) + echo "错误: KPanel 未提供有效的应用访问模式" + return 1 + ;; + esac + kpanel_app_progress 40 "正在执行 kejilion.sh IP+端口访问策略" + kpanel_app_apply_access_mode "$access_mode" true || return 1 + kpanel_app_progress 100 "应用访问策略更新完成" + ;; + esac + return 0 +} + docker_app() { send_stats "${docker_name}管理" +if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action standard + return $? +fi + while true; do clear check_docker_app @@ -2921,30 +3411,30 @@ while true; do echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" - read -e -p "请输入你的选择: " choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "请输入你的选择: " choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}安装失败: ${gl_bai}应用容器未能启动。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id + kpanel_app_write_access_mode direct clear echo "$docker_name 已经安装完成" @@ -2957,9 +3447,15 @@ while true; do 2) docker rm -f "$docker_name" docker rmi -f "$docker_img" - docker_rum + if ! docker_rum; then + echo -e "${gl_hong}更新失败: ${gl_bai}应用容器未能重新启动。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" clear echo "$docker_name 已经安装完成" @@ -2970,10 +3466,16 @@ while true; do send_stats "更新$docker_name" ;; 3) - docker rm -f "$docker_name" + if ! docker rm -f "$docker_name"; then + echo -e "${gl_hong}卸载失败: ${gl_bai}应用容器未能删除。" + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return 1 + fi + fi docker rmi -f "$docker_img" rm -rf "/home/docker/$docker_name" rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt echo "应用已卸载" @@ -2986,27 +3488,33 @@ while true; do add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "域名格式 example.com 不带https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允许IP访问 ${docker_name}" clear_container_rules "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP访问 ${docker_name}" block_container_port "$docker_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done @@ -3018,6 +3526,10 @@ done docker_app_plus() { send_stats "$app_name" + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_docker_app_action plus + return $? + fi while true; do clear check_docker_app @@ -3044,46 +3556,53 @@ docker_app_plus() { echo "------------------------" echo "0. 返回上一级选单" echo "------------------------" - read -e -p "输入你的选择: " choice + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + kpanel_app_interactive_choice choice || return 1 + else + read -e -p "输入你的选择: " choice + fi + local action_status=0 case $choice in 1) setup_docker_dir check_disk_space $app_size /home/docker - while true; do - read -e -p "输入应用对外服务端口,回车默认使用${docker_port}端口: " app_port - local app_port=${app_port:-${docker_port}} - - if ss -tuln | grep -q ":$app_port "; then - echo -e "${gl_hong}错误: ${gl_bai}端口 $app_port 已被占用,请更换一个端口" - send_stats "应用端口已被占用" - else - local docker_port=$app_port - break - fi - done + kpanel_app_choose_install_port || return 1 install jq install_docker - docker_app_install - echo "$docker_port" > "/home/docker/${docker_name}_port.conf" - - add_app_id - send_stats "$app_name 安装" + if docker_app_install; then + echo "$docker_port" > "/home/docker/${docker_name}_port.conf" + add_app_id + kpanel_app_write_access_mode direct + send_stats "$app_name 安装" + else + echo -e "${gl_hong}安装失败: ${gl_bai}未登记应用状态,请根据上方错误修复后重试。" + action_status=1 + fi ;; 2) - docker_app_update - add_app_id - send_stats "$app_name 更新" + if docker_app_update; then + add_app_id + kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" + send_stats "$app_name 更新" + else + echo -e "${gl_hong}更新失败: ${gl_bai}已保留原应用登记状态。" + action_status=1 + fi ;; 3) - docker_app_uninstall - rm -f /home/docker/${docker_name}_port.conf - - sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_name 卸载" + if docker_app_uninstall; then + rm -f /home/docker/${docker_name}_port.conf + rm -f /home/docker/${docker_name}_access.conf + sed -i "/\b${app_id}\b/d" /home/docker/appno.txt + send_stats "$app_name 卸载" + else + echo -e "${gl_hong}卸载失败: ${gl_bai}已保留应用登记状态。" + action_status=1 + fi ;; 5) @@ -3093,25 +3612,32 @@ docker_app_plus() { ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; 6) echo "域名格式 example.com 不带https://" - web_del + web_del || action_status=1 ;; 7) send_stats "允许IP访问 ${docker_name}" - clear_container_rules "$docker_name" "$ipv4_address" + local docker_check_name="${docker_app_service:-$docker_name}" + clear_container_rules "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode direct || action_status=1 ;; 8) send_stats "阻止IP访问 ${docker_name}" local docker_check_name="${docker_app_service:-$docker_name}" block_container_port "$docker_check_name" "$ipv4_address" + kpanel_app_write_access_mode domain_only || action_status=1 ;; *) break ;; esac + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return "$action_status" + fi break_end done } @@ -3246,6 +3772,107 @@ f2b_install_sshd() { } +kpanel_f2b_jail_name() { + if grep -qi 'Alpine' /etc/issue 2>/dev/null && + { [ -f /etc/fail2ban/filter.d/alpine-sshd.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-ssh.conf ] || + [ -f /etc/fail2ban/jail.d/alpine-sshd.local ]; }; then + printf '%s\n' "alpine-sshd" + else + printf '%s\n' "sshd" + fi +} + +kpanel_f2b_enabled() { + local jail_name + command -v fail2ban-client >/dev/null 2>&1 || return 1 + fail2ban-client ping >/dev/null 2>&1 || return 1 + jail_name=$(kpanel_f2b_jail_name) + fail2ban-client status "$jail_name" >/dev/null 2>&1 +} + +kpanel_f2b_autostart() { + if command -v apk >/dev/null 2>&1; then + rc-update show default 2>/dev/null | grep -Eq '(^|[[:space:]])fail2ban([[:space:]]|$)' + else + /bin/systemctl is-enabled fail2ban.service >/dev/null 2>&1 + fi +} + +kpanel_f2b_status() { + local installed=false running=false enabled=false autostart=false + local jail_name banned=0 jail_status="" + jail_name=$(kpanel_f2b_jail_name) + if command -v fail2ban-client >/dev/null 2>&1; then + installed=true + if fail2ban-client ping >/dev/null 2>&1; then + running=true + if jail_status=$(fail2ban-client status "$jail_name" 2>/dev/null); then + enabled=true + banned=$(printf '%s\n' "$jail_status" | + awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}') + case "$banned" in + ''|*[!0-9]*) banned=0 ;; + esac + fi + fi + kpanel_f2b_autostart && autostart=true + fi + printf 'KPANEL_F2B_STATUS {"installed":%s,"running":%s,"enabled":%s,"autostart":%s,"jail":"%s","banned":%s}\n' \ + "$installed" "$running" "$enabled" "$autostart" "$jail_name" "$banned" +} + +kpanel_f2b_dispatch() { + local command="${1:-status}" changed=false + printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + case "$command" in + status) + kpanel_f2b_status + ;; + enable) + root_use + if kpanel_f2b_enabled && kpanel_f2b_autostart; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + f2b_install_sshd || return 1 + kpanel_f2b_enabled || { + echo "Fail2Ban SSH jail 未能正常启动" >&2 + return 1 + } + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + disable) + root_use + if ! command -v fail2ban-client >/dev/null 2>&1; then + printf '%s\n' "KPANEL_F2B_RESULT unchanged" + kpanel_f2b_status + return 0 + fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || return 1 + fi + if fail2ban-client ping >/dev/null 2>&1; then + echo "Fail2Ban 服务仍在运行" >&2 + return 1 + fi + changed=true + printf 'KPANEL_F2B_RESULT %s\n' "$changed" + kpanel_f2b_status + ;; + *) + echo "用法: k f2b [status|enable|disable]" >&2 + return 2 + ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -3489,25 +4116,31 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" + kpanel_web_progress 10 "正在校验 WordPress 域名与现有站点" send_stats "安装$webname" echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi repeat_add_yuming + kpanel_web_progress 20 "正在准备 kejilion.sh LDNMP 环境" ldnmp_install_status + kpanel_web_progress 35 "正在签发并配置站点证书" install_ssltls certs_status + kpanel_web_progress 50 "正在创建 WordPress 数据库与账号" add_db + kpanel_web_progress 60 "正在获取 kejilion.sh WordPress Nginx 配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/wordpress.com.conf sed -i "s/yuming.com/$yuming/g" /home/web/conf.d/$yuming.conf nginx_http_on + kpanel_web_progress 75 "正在获取并配置 kejilion.sh WordPress 源码" cd /home/web/html prepare_ldnmp_site_root "$yuming" || return 1 cd $yuming @@ -3523,6 +4156,7 @@ ldnmp_wp() { cp /home/web/html/$yuming/wordpress/wp-config-sample.php /home/web/html/$yuming/wordpress/wp-config.php + kpanel_web_progress 90 "正在重启 LDNMP 并核验 WordPress 站点" normalize_ldnmp_site_permissions "$yuming" || return 1 chmod 0640 "/home/web/html/$yuming/wordpress/wp-config.php" || return 1 restart_ldnmp @@ -3539,6 +4173,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" + kpanel_web_progress 10 "正在校验反向代理域名与上游地址" send_stats "安装$webname" echo "开始部署 $webname" if [ -z "$yuming" ]; then @@ -3555,12 +4190,15 @@ ldnmp_Proxy() { if [ -z "$port" ]; then read -e -p "请输入你的反代端口: " port fi + kpanel_web_progress 25 "正在准备 kejilion.sh Nginx 环境" nginx_install_status + kpanel_web_progress 40 "正在签发并配置反向代理证书" install_ssltls certs_status + kpanel_web_progress 60 "正在获取 kejilion.sh 反向代理配置" wget -O /home/web/conf.d/map.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/map.conf wget -O /home/web/conf.d/$yuming.conf ${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/reverse-proxy-backend.conf @@ -3581,6 +4219,7 @@ ldnmp_Proxy() { update_nginx_listen_port "$yuming" "$access_port" + kpanel_web_progress 85 "正在校验并重载反向代理配置" nginx_http_on docker exec nginx nginx -s reload nginx_web_on @@ -4859,6 +5498,246 @@ chattr +i /etc/resolv.conf } +kpanel_dns_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_dns_is_ipv6() { + local value="$1" + [ ${#value} -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] +} + +kpanel_dns_restore_file() { + local target="$1" + local backup="$2" + local existed="$3" + local immutable="$4" + + chattr -i "$target" >/dev/null 2>&1 || true + if [ "$existed" = "true" ]; then + cp -p "$backup" "$target" || return 1 + else + rm -f "$target" || return 1 + fi + if [ "$immutable" = "true" ]; then + chattr +i "$target" >/dev/null 2>&1 || return 1 + fi +} + +kpanel_dns_write_static() { + local target="/etc/resolv.conf" + local parent desired backup old_mode old_immutable="false" existed="false" + local expected="" value + + if [ -L "$target" ]; then + target="$(readlink -f "$target")" + [ -n "$target" ] || { + echo "错误: /etc/resolv.conf 是失效的符号链接" + return 1 + } + fi + parent="$(dirname "$target")" + [ -d "$parent" ] || { + echo "错误: DNS 配置目录不存在" + return 1 + } + command -v chattr >/dev/null 2>&1 || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + for value in "$@"; do + expected="${expected}nameserver ${value}"$'\n' + done + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + + if [ -f "$target" ]; then + existed="true" + cp -p "$target" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + old_mode="$(stat -c '%a' "$target" 2>/dev/null || printf '644')" + chmod "$old_mode" "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chown --reference="$target" "$desired" >/dev/null 2>&1 || true + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + old_immutable="true" + fi + if [ "$(cat "$target")"$'\n' = "$expected" ]; then + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + } + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } + else + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + fi + + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER resolv.conf" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_dns_write_systemd_resolved() { + local config="/etc/systemd/resolved.conf.d/90-kpanel.conf" + local parent desired backup existed="false" expected + + command -v systemctl >/dev/null 2>&1 || { + echo "错误: systemctl 不可用" + return 1 + } + parent="$(dirname "$config")" + mkdir -p "$parent" || return 1 + desired="$(mktemp "${parent}/.90-kpanel.conf.kpanel.XXXXXX")" || return 1 + backup="$(mktemp "${parent}/.90-kpanel.conf.backup.XXXXXX")" || { + rm -f "$desired" + return 1 + } + expected="[Resolve]"$'\n'"DNS=$*"$'\n'"FallbackDNS="$'\n' + printf '%s' "$expected" > "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + chmod 644 "$desired" || { + rm -f "$desired" "$backup" + return 1 + } + if [ -f "$config" ]; then + existed="true" + cp -p "$config" "$backup" || { + rm -f "$desired" "$backup" + return 1 + } + if [ "$(cat "$config")"$'\n' = "$expected" ]; then + rm -f "$desired" "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT unchanged" + return 0 + fi + fi + if ! mv -f "$desired" "$config" || + ! systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || + [ "$(cat "$config")"$'\n' != "$expected" ]; then + if [ "$existed" = "true" ]; then + cp -p "$backup" "$config" || { + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 回滚失败,需要人工检查" + return 1 + } + else + rm -f "$config" + fi + systemctl reload-or-restart systemd-resolved.service >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 已恢复文件,但服务重载失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: systemd-resolved DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + rm -f "$backup" + echo "KPANEL_DNS_MANAGER systemd-resolved" + echo "KPANEL_DNS_RESULT applied" +} + +kpanel_set_dns_noninteractive() { + [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "错误: KPanel DNS 协议必须以 root 运行" + return 1 + } + [ "$#" -ge 1 ] && [ "$#" -le 4 ] || { + echo "错误: DNS 地址数量必须为 1-4 个" + return 1 + } + + local ipv4_count=0 ipv6_count=0 value previous + local normalized=() + for value in "$@"; do + [ -n "$value" ] && [ ${#value} -le 45 ] || { + echo "错误: DNS 地址为空或过长" + return 1 + } + if kpanel_dns_is_ipv4 "$value"; then + ipv4_count=$((ipv4_count + 1)) + [ "$ipv4_count" -le 2 ] || { + echo "错误: IPv4 DNS 地址最多 2 个" + return 1 + } + elif kpanel_dns_is_ipv6 "$value"; then + ipv6_count=$((ipv6_count + 1)) + [ "$ipv6_count" -le 2 ] || { + echo "错误: IPv6 DNS 地址最多 2 个" + return 1 + } + else + echo "错误: 无效的 DNS 地址" + return 1 + fi + for previous in "${normalized[@]}"; do + [ "$previous" = "$value" ] && { + echo "错误: DNS 地址不能重复" + return 1 + } + done + normalized+=("$value") + done + + local resolver_target + resolver_target="$(readlink /etc/resolv.conf 2>/dev/null || true)" + if [[ "${resolver_target,,}" == *systemd/resolve* ]]; then + kpanel_dns_write_systemd_resolved "${normalized[@]}" + else + kpanel_dns_write_static "${normalized[@]}" + fi +} + set_dns_ui() { root_use @@ -5631,9 +6510,131 @@ dd_xitong() { } +kpanel_bbrv3_status() { + local architecture os_id codename running_kernel installed_kernel installed=false active=false supported=false + local congestion qdisc reboot_required=false reason="" + architecture=$(uname -m 2>/dev/null | tr -cd 'A-Za-z0-9._-') + running_kernel=$(uname -r 2>/dev/null | tr -cd 'A-Za-z0-9+._-') + os_id="" + codename="" + if [ -r /etc/os-release ]; then + os_id=$(. /etc/os-release && printf '%s' "${ID:-}" | tr -cd 'A-Za-z0-9._-') + codename=$(. /etc/os-release && printf '%s' "${VERSION_CODENAME:-}" | tr -cd 'A-Za-z0-9._-') + fi + if command -v lsb_release >/dev/null 2>&1; then + codename=$(lsb_release -sc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + fi + installed_kernel=$( + for module_dir in /lib/modules/*xanmod*; do + [ -d "$module_dir" ] && basename "$module_dir" + done 2>/dev/null | sort -V | tail -n 1 | tr -cd 'A-Za-z0-9+._-' + ) + congestion=$(cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null | tr -cd 'A-Za-z0-9._-') + qdisc=$(cat /proc/sys/net/core/default_qdisc 2>/dev/null | tr -cd 'A-Za-z0-9._-') + xanmod_installed && installed=true + if printf '%s' "$running_kernel" | grep -qi 'xanmod' && + [ "$congestion" = "bbr" ] && [ "$qdisc" = "fq" ]; then + active=true + fi + if { [ "$architecture" = "x86_64" ] || [ "$architecture" = "amd64" ]; } && + { [ "$os_id" = "debian" ] || [ "$os_id" = "ubuntu" ]; } && + command -v apt >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then + case "$codename" in + bookworm|trixie|forky|sid|noble|plucky|questing|resolute) + supported=true + ;; + *) + reason="unsupported_release" + ;; + esac + elif [ "$architecture" = "aarch64" ] || [ "$architecture" = "arm64" ]; then + reason="arm64_external_installer_untrusted" + elif [ "$os_id" != "debian" ] && [ "$os_id" != "ubuntu" ]; then + reason="unsupported_distribution" + else + reason="missing_dependencies" + fi + if { [ "$installed" = "true" ] && [ -n "$installed_kernel" ] && + [ "$running_kernel" != "$installed_kernel" ]; } || + { [ "$installed" = "false" ] && printf '%s' "$running_kernel" | grep -qi 'xanmod'; } || + [ -f /var/run/reboot-required ]; then + reboot_required=true + fi + printf 'KPANEL_BBRV3_STATUS {"supported":%s,"installed":%s,"active":%s,"architecture":"%s","os":"%s","codename":"%s","runningKernel":"%s","installedKernel":"%s","congestionControl":"%s","defaultQDisc":"%s","rebootRequired":%s,"reason":"%s"}\n' \ + "$supported" "$installed" "$active" "$architecture" "$os_id" "$codename" \ + "$running_kernel" "$installed_kernel" "$congestion" "$qdisc" "$reboot_required" "$reason" +} + +kpanel_bbrv3_dispatch() { + local command="${1:-status}" changed=false status_line reboot_required=false + printf '%s\n' "KPANEL_BBRV3_PROTOCOL 1" + case "$command" in + status) + kpanel_bbrv3_status + ;; + install|update|uninstall) + root_use + status_line=$(kpanel_bbrv3_status) + if ! printf '%s' "$status_line" | grep -q '"supported":true' && + { [ "$command" != "uninstall" ] || + ! printf '%s' "$status_line" | grep -q '"installed":true'; }; then + printf '%s\n' "$status_line" + echo "当前主机不支持 KPanel BBRv3 受控执行" >&2 + return 1 + fi + case "$command" in + install) + if xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"install","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_install_or_update install || return 1 + changed=true + ;; + update) + xanmod_installed || { + echo "尚未安装 XanMod BBRv3 内核,不能执行更新" >&2 + return 1 + } + xanmod_install_or_update update || return 1 + changed=true + ;; + uninstall) + if ! xanmod_installed; then + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"uninstall","changed":false,"rebootRequired":%s}\n' \ + "$reboot_required" + printf '%s\n' "$status_line" + return 0 + fi + xanmod_uninstall || return 1 + changed=true + ;; + esac + status_line=$(kpanel_bbrv3_status) + printf '%s' "$status_line" | grep -q '"rebootRequired":true' && + reboot_required=true + printf 'KPANEL_BBRV3_RESULT {"action":"%s","changed":%s,"rebootRequired":%s}\n' \ + "$command" "$changed" "$reboot_required" + printf '%s\n' "$status_line" + ;; + *) + echo "用法: k bbrv3 [status|install|update|uninstall]" >&2 + return 2 + ;; + esac +} + bbrv3() { - root_use - send_stats "bbrv3管理" + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" != "1" ]; then + root_use + send_stats "bbrv3管理" + fi xanmod_add_repo() { local keyring="/usr/share/keyrings/xanmod-archive-keyring.gpg" @@ -5647,12 +6648,18 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - + # 兼容官方已移除的老系统代号(回退使用 releases 尝试旧包库) - if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena jammy" | grep -qw "$os_codename"; then + if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi + # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 + if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then + echo -e "${gl_hong}XanMod 官方已停止对当前系统($os_codename)的 APT 源支持,请升级至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" + return 1 + fi + if [ -z "$os_codename" ]; then echo "无法获取系统代号,无法配置XanMod源" return 1 @@ -5756,7 +6763,7 @@ bbrv3() { return 1 } echo "XanMod BBRv3内核处理完成。重启后生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } xanmod_uninstall() { @@ -5766,9 +6773,14 @@ bbrv3() { rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg echo "XanMod内核已卸载。重启后生效" - server_reboot + [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + kpanel_bbrv3_dispatch "$@" + return + fi + local cpu_arch=$(uname -m) if [ "$cpu_arch" = "aarch64" ]; then bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) @@ -8708,13 +9720,535 @@ linux_docker() { break_end - done + done + + +} + + + +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel 轻量节点安装需要 root 权限。" >&2 + return 1 + } + for command_name in curl sha256sum systemctl mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "缺少必要命令: ${command_name}" >&2 + return 1 + } + done + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "缺少必要命令: install (coreutils)" >&2 + return 1 + } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "缺少系统账户创建工具: useradd、systemd-sysusers 或 adduser" >&2 + return 1 + fi + [ -d /run/systemd/system ] || { + echo "当前系统未运行 systemd,无法安装 KPanel 轻量节点。" >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "当前 CPU 架构暂不支持 KPanel 轻量节点。" >&2 + return 1 + ;; + esac +} + +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "现有 kejilion-node 账户的主组不安全,拒绝继续。" >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "缺少系统组创建工具: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel 轻量节点低权限账户创建失败。" >&2 + return 1 + } +} + +kpanel_node_write_updater() { + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + systemctl daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_join() { + local token="${1:-}" node_name + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "轻量节点接入授权无效。" >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "轻量节点接入授权无效。" >&2 + return 2 + } + [ ! -e "$KPANEL_NODE_CONFIG" ] || { + echo "本机已接入一个 KPanel 中心;请先执行 k kpanel node uninstall。" >&2 + return 1 + } + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + kpanel_node_cleanup_failed_join + return 1 + fi + node_name="$(hostname 2>/dev/null | tr -cd '[:alnum:]._- ' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + kpanel_node_cleanup_failed_join + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + kpanel_node_cleanup_failed_join + return 1 + fi + systemctl daemon-reload + if ! systemctl enable --now kejilion-node.service kejilion-node-update.timer || + ! systemctl is-active --quiet kejilion-node.service; then + kpanel_node_cleanup_failed_join + echo "KPanel 轻量节点启动失败。" >&2 + return 1 + fi + echo "KPanel 轻量节点已接入,后续将自动更新。" +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel 轻量节点未安装。" >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + systemctl --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel 轻量节点未安装。" >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "卸载 KPanel 轻量节点需要 root 权限。" >&2 + return 1 + } + systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + systemctl daemon-reload >/dev/null 2>&1 || true + echo "KPanel 轻量节点已从本机卸载;中心端的离线记录需在集群页面删除。" +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + return 2 + ;; + esac +} + +kpanel_test_catalog() { + cat <<'KPANEL_TEST_CATALOG' +KPANEL_TEST_CATEGORY access IP 与解锁 +KPANEL_TEST_CATEGORY network 网络线路 +KPANEL_TEST_CATEGORY hardware 硬件性能 +KPANEL_TEST_CATEGORY comprehensive 综合评测 +KPANEL_TEST_ITEM chatgpt access ChatGPT 解锁检测 检测当前出口 IP 的 ChatGPT 可用性 https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh 2 light +KPANEL_TEST_ITEM region access Region 流媒体解锁 检测常见流媒体服务的地区解锁状态 https://check.unlock.media 5 network +KPANEL_TEST_ITEM media access yeahwu 流媒体检测 检测常见流媒体与 AI 服务的可用区域 https://github.com/yeahwu/check/raw/main/check.sh 5 network +KPANEL_TEST_ITEM ip-quality access IP 质量体检 检测 IP 风险、信誉、邮件与流媒体质量 https://IP.Check.Place 8 network +KPANEL_TEST_ITEM besttrace network BestTrace 三网回程 检测三网回程延迟和路由 https://git.io/besttrace 8 network +KPANEL_TEST_ITEM mtr network MTR 三网回程 使用 MTR 检测三网回程线路 https://github.com/zhucaidan/mtr_trace/raw/main/mtr_trace.sh 8 network +KPANEL_TEST_ITEM superspeed network SuperSpeed 三网测速 执行国内三网节点带宽测试 https://git.io/superspeed_uxh 15 intensive +KPANEL_TEST_ITEM nxtrace-fast network NextTrace 快速回程 执行 TCP 快速回程路由测试 https://nxtrace.org/nt 8 network +KPANEL_TEST_ITEM backtrace network 三网线路测试 检测电信、联通和移动回程线路 https://github.com/ludashi2020/backtrace/raw/main/install.sh 8 network +KPANEL_TEST_ITEM speedtest network 多功能测速 运行 i-abc 多节点网络测速 https://github.com/i-abc/Speedtest/raw/main/speedtest.sh 15 intensive +KPANEL_TEST_ITEM net-quality network 网络质量体检 检测延迟、抖动、丢包和网络质量 https://Net.Check.Place 10 network +KPANEL_TEST_ITEM tcp-quality network TCP 重传探测 检测 TCP 重传和连接质量 https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh 10 network +KPANEL_TEST_ITEM yabs hardware YABS 性能测试 测试 CPU、磁盘与网络;无 Swap 时按脚本创建 1 GiB /swapfile https://yabs.sh 30 intensive +KPANEL_TEST_ITEM cpu hardware CPU 性能测试 运行 Geekbench 5;无 Swap 时按脚本创建 1 GiB /swapfile https://raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh 30 intensive +KPANEL_TEST_ITEM bench comprehensive Bench 综合测试 输出系统信息、磁盘与网络综合结果 https://bench.sh 15 intensive +KPANEL_TEST_ITEM ecs comprehensive 融合怪综合测评 运行 spiritLHLS ECS 综合性能与质量测评 https://github.com/spiritLHLS/ecs/raw/main/ecs.sh 45 intensive +KPANEL_TEST_ITEM nodequality comprehensive NodeQuality 综合测评 运行 NodeQuality 节点质量综合测试 https://run.NodeQuality.com 30 intensive +KPANEL_TEST_CATALOG +} + +kpanel_run_remote_bash() { + local source_url="${1:-}" + shift || true + [ -n "$source_url" ] || return 64 + + local test_workspace test_script command_status + test_workspace="$(mktemp -d)" || return 1 + test_script="$test_workspace/test.sh" + curl -fsSL "$source_url" -o "$test_script" + command_status=$? + if [ "$command_status" -ne 0 ]; then + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" + fi + chmod 700 "$test_script" + bash "$test_script" "$@" + command_status=$? + rm -f "$test_script" + rmdir "$test_workspace" 2>/dev/null || true + return "$command_status" +} +kpanel_run_test_noninteractive() { + [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ] || return 2 + local action="${1:-list}" + local selector="${2:-}" + case "$action" in + list) + [ "$#" -eq 1 ] || { + echo "KPANEL_TEST_ERROR list does not accept arguments" >&2 + return 64 + } + kpanel_test_catalog + ;; + run) + [ "$#" -eq 2 ] || { + echo "KPANEL_TEST_ERROR run requires one fixed test selector" >&2 + return 64 + } + echo "KPANEL_TEST_START ${selector}" + ( + set -o pipefail + case "$selector" in + chatgpt) + send_stats "ChatGPT解锁状态检测" + kpanel_run_remote_bash https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh + ;; + region) + send_stats "Region流媒体解锁测试" + kpanel_run_remote_bash https://check.unlock.media + ;; + media) + send_stats "yeahwu流媒体解锁检测" + kpanel_run_remote_bash ${gh_proxy}github.com/yeahwu/check/raw/main/check.sh + ;; + ip-quality) + send_stats "xykt_IP质量体检脚本" + kpanel_run_remote_bash https://IP.Check.Place + ;; + besttrace) + send_stats "besttrace三网回程延迟路由测试" + kpanel_run_remote_bash https://git.io/besttrace + ;; + mtr) + send_stats "mtr_trace三网回程线路测试" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh + ;; + superspeed) + send_stats "Superspeed三网测速" + kpanel_run_remote_bash https://git.io/superspeed_uxh + ;; + nxtrace-fast) + send_stats "nxtrace快速回程测试脚本" + kpanel_run_remote_bash https://nxtrace.org/nt + nexttrace --fast-trace --tcp + ;; + backtrace) + send_stats "ludashi2020三网线路测试" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh + ;; + speedtest) + send_stats "i-abc多功能测速脚本" + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/Speedtest/main/speedtest.sh + ;; + net-quality) + send_stats "网络质量测试脚本" + kpanel_run_remote_bash https://Net.Check.Place + ;; + tcp-quality) + send_stats "TcpQuality TCP重传探测脚本" + kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh + ;; + yabs) + send_stats "yabs性能测试" + check_swap + kpanel_run_remote_bash https://yabs.sh -i -5 + ;; + cpu) + send_stats "icu/gb5 CPU性能测试脚本" + check_swap + kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh + ;; + bench) + send_stats "bench性能测试" + kpanel_run_remote_bash https://bench.sh + ;; + ecs) + send_stats "spiritysdx融合怪测评" + local test_workspace + test_workspace="$(mktemp -d)" + ( + cd "$test_workspace" && + curl -fsSL ${gh_proxy}github.com/spiritLHLS/ecs/raw/main/ecs.sh -o ecs.sh && + chmod +x ecs.sh && + bash ecs.sh + ) + local ecs_status=$? + rm -f "$test_workspace/ecs.sh" + rmdir "$test_workspace" 2>/dev/null || true + [ "$ecs_status" -eq 0 ] || return "$ecs_status" + ;; + nodequality) + send_stats "nodequality融合怪测评" + kpanel_run_remote_bash https://run.NodeQuality.com + ;; + *) + echo "KPANEL_TEST_ERROR unsupported test selector" >&2 + exit 64 + ;; + esac + ) + local command_status=$? + if [ "$command_status" -ne 0 ]; then + echo "KPANEL_TEST_RESULT failed ${selector}" >&2 + return "$command_status" + fi + echo "KPANEL_TEST_RESULT succeeded ${selector}" + ;; + *) + echo "KPANEL_TEST_ERROR unsupported action" >&2 + return 64 + ;; + esac } - linux_test() { while true; do @@ -9105,9 +10639,577 @@ fix_phpfpm_conf() { +kpanel_run_web_recipe_cli() { + local selector="${1:-}" + local domain="${2:-}" + if [ "$#" -ne 2 ]; then + echo "用法: k <建站命令> <域名>" + return 64 + fi + KJ_WEB_NONINTERACTIVE=1 + KJ_WEB_RECIPE="$selector" + KJ_WEB_DOMAIN="$domain" + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + echo "已有网站或 LDNMP 环境任务正在执行" >&2 + exec {lock_fd}>&- + return 75 + fi + linux_ldnmp + rc=$? + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +kpanel_web_recipe_requires_document_root() { + case "${1:-}" in + 2|3|4|5|6|7|8|9|20|25|26|27|30) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_ldnmp_escape() { + local value="${1:-}" + value=${value//\\/\\\\}; value=${value//\"/\\\"} + value=${value//$'\n'/\\n}; value=${value//$'\r'/} + printf '%s' "$value" +} + +kpanel_ldnmp_event() { + printf 'KPANEL_LDNMP_EVENT {"stage":"%s","progress":%s,"message":"%s"}\n' \ + "$(kpanel_ldnmp_escape "$1")" "$2" "$(kpanel_ldnmp_escape "$3")" +} + +kpanel_ldnmp_result() { + local payload + payload=$(printf '{"status":"%s","action":"%s","message":"%s","finishedAt":"%s"}' \ + "$1" "$2" "$(kpanel_ldnmp_escape "$3")" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')") + printf 'KPANEL_LDNMP_RESULT %s\n' "$payload" + case "${KJ_LDNMP_RECEIPT:-}" in + /var/lib/kejilion-panel/environment-jobs/*.receipt) + umask 077 + printf '%s\n' "$payload" > "${KJ_LDNMP_RECEIPT}.tmp.$$" && + mv -f "${KJ_LDNMP_RECEIPT}.tmp.$$" "$KJ_LDNMP_RECEIPT" + ;; + esac +} + +kpanel_ldnmp_component() { + local name="$1" required="$2" exists=false running=false state=absent image="" version="" digest="" + if docker inspect "$name" >/dev/null 2>&1; then + exists=true + state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null) + image=$(docker inspect -f '{{.Config.Image}}' "$name" 2>/dev/null) + digest=$(docker image inspect -f '{{index .RepoDigests 0}}' "$image" 2>/dev/null) + [ "$state" = running ] && running=true + case "$name" in + nginx) version=$(docker exec nginx nginx -v 2>&1 | sed -n 's#.*nginx/##p' | head -1) ;; + php|php74) version=$(docker exec "$name" php -r 'echo PHP_VERSION;' 2>/dev/null) ;; + redis) version=$(docker exec redis redis-server -v 2>/dev/null | sed -n 's/.*v=\([^ ]*\).*/\1/p') ;; + mysql) + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && version=$(docker exec mysql mysql -u root -p"$password" -Nse 'SELECT VERSION();' 2>/dev/null) + ;; + esac + fi + printf '{"name":"%s","required":%s,"exists":%s,"running":%s,"state":"%s","image":"%s","version":"%s","repoDigest":"%s","updateStatus":"unknown","updateReason":"Registry 状态仅在更新任务中实时确认"}' \ + "$name" "$required" "$exists" "$running" "$(kpanel_ldnmp_escape "$state")" \ + "$(kpanel_ldnmp_escape "$image")" "$(kpanel_ldnmp_escape "$version")" "$(kpanel_ldnmp_escape "$digest")" +} + +ldnmp_environment_status() { + local count=0 running=0 state=absent profile=none health=unknown + for name in nginx mysql php redis; do + docker inspect "$name" >/dev/null 2>&1 && count=$((count + 1)) + [ "$(docker inspect -f '{{.State.Running}}' "$name" 2>/dev/null)" = true ] && running=$((running + 1)) + done + if [ "$count" -eq 4 ]; then state=installed; profile=full + elif [ "$count" -eq 1 ] && docker inspect nginx >/dev/null 2>&1; then state=installed; profile=nginx + elif [ "$count" -gt 0 ] || [ -d /home/web ]; then state=partial; profile=custom + fi + if { [ "$profile" = full ] && [ "$running" -eq 4 ]; } || + { [ "$profile" = nginx ] && [ "$running" -eq 1 ]; }; then health=healthy + elif [ "$state" != absent ]; then health=degraded + fi + + local compose=false nginx_ok=false sites=0 databases=0 certificates=0 bytes=0 + [ -f /home/web/docker-compose.yml ] && + docker compose -f /home/web/docker-compose.yml config -q >/dev/null 2>&1 && compose=true + docker exec nginx nginx -t >/dev/null 2>&1 && nginx_ok=true + [ -d /home/web/conf.d ] && sites=$(find /home/web/conf.d -maxdepth 1 -type f -name '*.conf' ! -name default.conf ! -name map.conf 2>/dev/null | wc -l) + [ -d /home/web/certs ] && certificates=$(find /home/web/certs -maxdepth 1 -type f -name '*_cert.pem' 2>/dev/null | wc -l) + if docker inspect mysql >/dev/null 2>&1; then + local password + password=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml 2>/dev/null | tr -d '[:space:]') + [ -n "$password" ] && databases=$(docker exec mysql mysql -u root -p"$password" -Nse 'SHOW DATABASES;' 2>/dev/null | + grep -Ev '^(information_schema|mysql|performance_schema|sys)$' | wc -l) + fi + [ -d /home/web ] && bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + local resource="" + command -v sha256sum >/dev/null 2>&1 && resource=$( + { [ -f /home/web/docker-compose.yml ] && sha256sum /home/web/docker-compose.yml + [ -f /home/web/nginx.conf ] && sha256sum /home/web/nginx.conf + docker inspect -f '{{.Id}} {{.Image}} {{.State.Status}}' nginx mysql php php74 redis 2>/dev/null; } | + sha256sum | awk '{print $1}' + ) + local fail2ban=false waf=false cloudflare=false ddos=false mode=custom gzip=false brotli=false zstd=false + command -v fail2ban-client >/dev/null 2>&1 && fail2ban=true + grep -qE '^[[:space:]]*modsecurity on;' /home/web/nginx.conf 2>/dev/null && waf=true + [ -f /etc/fail2ban/action.d/cloudflare-docker.conf ] && cloudflare=true + iptables -C INPUT -p tcp --syn -j DROP >/dev/null 2>&1 && ddos=true + docker exec mysql grep -q 4096M /etc/mysql/conf.d/custom_mysql_config.cnf 2>/dev/null && mode=high + [ "$mode" = custom ] && docker exec mysql test -f /etc/mysql/conf.d/custom_mysql_config.cnf >/dev/null 2>&1 && mode=standard + grep -qE '^[[:space:]]*gzip[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && gzip=true + grep -qE '^[[:space:]]*brotli[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && brotli=true + grep -qE '^[[:space:]]*zstd[[:space:]]+on;' /home/web/nginx.conf 2>/dev/null && zstd=true + local latest="" + latest=$(find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r | head -1) + local port_conflicts="" separator="" port listener + for port in 80 443; do + listener=$(ss -ltnp 2>/dev/null | awk -v suffix=":${port}" '$4 ~ suffix"$" {print; exit}') + if [ -n "$listener" ]; then + port_conflicts="${port_conflicts}${separator}\"$(kpanel_ldnmp_escape "$listener")\"" + separator="," + fi + done + printf '{"protocolVersion":"1","state":"%s","profile":"%s","health":"%s","webRoot":"/home/web","diskBytes":%s,"siteCount":%s,"databaseCount":%s,"certificateCount":%s,"composeValid":%s,"nginxValid":%s,"resourceVersion":"%s","scriptVersion":"%s","latestBackup":"%s","portConflicts":[%s],"components":[' \ + "$state" "$profile" "$health" "${bytes:-0}" "${sites:-0}" "${databases:-0}" "${certificates:-0}" \ + "$compose" "$nginx_ok" "$resource" "$sh_v" "$(kpanel_ldnmp_escape "$latest")" "$port_conflicts" + kpanel_ldnmp_component nginx true; printf ','; kpanel_ldnmp_component mysql true; printf ',' + kpanel_ldnmp_component php true; printf ','; kpanel_ldnmp_component php74 false; printf ',' + kpanel_ldnmp_component redis true + printf '],"protection":{"fail2ban":%s,"waf":%s,"cloudflare":%s,"ddos":%s},"optimization":{"mode":"%s","gzip":%s,"brotli":%s,"zstd":%s},"observedAt":"%s"}\n' \ + "$fail2ban" "$waf" "$cloudflare" "$ddos" "$mode" "$gzip" "$brotli" "$zstd" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +} + +ldnmp_environment_catalog() { + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"完整 LDNMP"},{"id":"nginx","label":"仅 Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudflare-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"]},{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' +} + +ldnmp_environment_install() { + local profile="${1:-full}" states + kpanel_ldnmp_event preflight 5 "正在检查安装条件" + case "$profile" in + full) kpanel_ldnmp_event install 15 "正在安装完整 LDNMP"; ldnmp_install_all ;; + nginx) kpanel_ldnmp_event install 15 "正在安装 Nginx"; nginx_install_all ;; + *) echo "不支持的安装形态" >&2; return 2 ;; + esac + kpanel_ldnmp_event verify 90 "正在验证环境" + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker compose -f /home/web/docker-compose.yml config -q || return 1 + if [ "$profile" = full ]; then + states=$(docker inspect -f '{{.State.Running}}' nginx mysql php redis 2>/dev/null) + [ "$(printf '%s\n' "$states" | sed '/^$/d' | wc -l)" -eq 4 ] || return 1 + printf '%s\n' "$states" | grep -qv true && return 1 + fi +} + +ldnmp_protection_action_apply() { + local cfuser="" cftoken="" cfzone="" secret_content="" + case "$1" in + fail2ban-install) + f2b_install_sshd + mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d + curl -sS -o /etc/fail2ban/filter.d/fail2ban-nginx-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/fail2ban-nginx-cc.conf" + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + sed -i '/cloudflare/d' /etc/fail2ban/jail.d/nginx-docker-cc.conf + fail2ban-client reload ;; + fail2ban-uninstall) remove fail2ban; rm -rf /etc/fail2ban ;; + unban-all) fail2ban-client unban --all ;; + waf-on) nginx_waf on ;; waf-off) nginx_waf off ;; + ddos-on) enable_ddos_defense ;; ddos-off) disable_ddos_defense ;; + cloudflare-fail2ban|cloudflare-shield) + case "${KJ_LDNMP_SECRET_FILE:-}" in + /var/lib/kejilion-panel/environment-jobs/*.secret) ;; + *) echo "Cloudflare 凭据通道无效" >&2; return 2 ;; + esac + [ -f "$KJ_LDNMP_SECRET_FILE" ] && [ ! -L "$KJ_LDNMP_SECRET_FILE" ] || return 2 + IFS= read -r cfuser < "$KJ_LDNMP_SECRET_FILE" + cftoken=$(sed -n '2p' "$KJ_LDNMP_SECRET_FILE") + cfzone=$(sed -n '3p' "$KJ_LDNMP_SECRET_FILE") + rm -f -- "$KJ_LDNMP_SECRET_FILE" + [ -n "$cfuser" ] && [ -n "$cftoken" ] || return 2 + if [ "$1" = cloudflare-fail2ban ]; then + wget -O /home/web/conf.d/default.conf "${gh_proxy}raw.githubusercontent.com/kejilion/nginx/main/default11.conf" + docker exec nginx nginx -s reload + mkdir -p /etc/fail2ban/jail.d /etc/fail2ban/action.d + curl -sS -o /etc/fail2ban/jail.d/nginx-docker-cc.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/nginx-docker-cc.conf" + curl -sS -o /etc/fail2ban/action.d/cloudflare-docker.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/cloudflare-docker.conf" + secret_content=$(< /etc/fail2ban/action.d/cloudflare-docker.conf) + secret_content=${secret_content//kejilion@outlook.com/$cfuser} + secret_content=${secret_content//APIKEY00000/$cftoken} + printf '%s\n' "$secret_content" > /etc/fail2ban/action.d/cloudflare-docker.conf + chmod 600 /etc/fail2ban/action.d/cloudflare-docker.conf + f2b_status + else + [ -n "$cfzone" ] || return 2 + cd /root || return 1 + install jq bc + check_crontab_installed + curl -sS -o CF-Under-Attack.sh "${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/CF-Under-Attack.sh" + chmod 700 CF-Under-Attack.sh + secret_content=$(< CF-Under-Attack.sh) + secret_content=${secret_content//AAAA/$cfuser} + secret_content=${secret_content//BBBB/$cftoken} + secret_content=${secret_content//CCCC/$cfzone} + printf '%s\n' "$secret_content" > CF-Under-Attack.sh + local cron_job="*/5 * * * * /root/CF-Under-Attack.sh" + (crontab -l 2>/dev/null | grep -Fv "/root/CF-Under-Attack.sh"; echo "$cron_job") | crontab - + fi + ;; + *) echo "不支持的防护动作" >&2; return 2 ;; + esac +} + +ldnmp_protection_action() { + local action="$1" snapshot rc=0 fail2ban_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-protection.XXXXXX) || return 1 + if [ -d /etc/fail2ban ]; then + cp -a /etc/fail2ban "$snapshot/fail2ban" + fail2ban_existed=true + fi + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + cp -a /home/web/conf.d/default.conf "$snapshot/default.conf" 2>/dev/null || true + crontab -l > "$snapshot/crontab" 2>/dev/null || true + iptables-save > "$snapshot/iptables.rules" 2>/dev/null || true + + ldnmp_protection_action_apply "$@" + rc=$? + case "$action" in + fail2ban-install|cloudflare-fail2ban) + fail2ban-client ping >/dev/null 2>&1 || rc=1 + ;; + waf-on|waf-off) + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + ;; + cloudflare-shield) + crontab -l 2>/dev/null | grep -Fq "/root/CF-Under-Attack.sh" || rc=1 + ;; + esac + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + + kpanel_ldnmp_event rollback 85 "防护配置验证失败,正在恢复原配置" + rm -rf /etc/fail2ban + [ "$fail2ban_existed" = true ] && cp -a "$snapshot/fail2ban" /etc/fail2ban + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/default.conf" ] && cp -a "$snapshot/default.conf" /home/web/conf.d/default.conf + if [ -s "$snapshot/crontab" ]; then crontab "$snapshot/crontab"; else crontab -r 2>/dev/null; fi + [ -s "$snapshot/iptables.rules" ] && iptables-restore < "$snapshot/iptables.rules" + docker exec nginx nginx -t >/dev/null 2>&1 && docker exec nginx nginx -s reload >/dev/null 2>&1 + systemctl restart fail2ban >/dev/null 2>&1 || true + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_optimization_action() { + local action="$1" snapshot rc=0 sysctl_existed=false + snapshot=$(mktemp -d /home/.kpanel-ldnmp-optimize.XXXXXX) || return 1 + cp -a /home/web/nginx.conf "$snapshot/nginx.conf" 2>/dev/null || true + docker cp php:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php.ini" 2>/dev/null || true + docker cp php:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php-www.conf" 2>/dev/null || true + docker cp php74:/usr/local/etc/php/conf.d/optimized_php.ini "$snapshot/php74.ini" 2>/dev/null || true + docker cp php74:/usr/local/etc/php-fpm.d/www.conf "$snapshot/php74-www.conf" 2>/dev/null || true + docker cp mysql:/etc/mysql/conf.d/custom_mysql_config.cnf "$snapshot/mysql.cnf" 2>/dev/null || true + if [ -f /etc/sysctl.d/99-kejilion-optimize.conf ]; then + cp -a /etc/sysctl.d/99-kejilion-optimize.conf "$snapshot/sysctl.conf" + sysctl_existed=true + fi + case "$1" in + standard) ldnmp_optimization_mode standard ;; + high) ldnmp_optimization_mode high ;; + gzip-on) nginx_gzip on ;; gzip-off) nginx_gzip off ;; + brotli-on) nginx_br on ;; brotli-off) nginx_br off ;; + zstd-on) nginx_zstd on ;; zstd-off) nginx_zstd off ;; + *) rm -rf "$snapshot"; echo "当前协议不支持该优化动作" >&2; return 2 ;; + esac + rc=$? + docker exec nginx nginx -t >/dev/null 2>&1 || rc=1 + if [ "$action" = standard ] || [ "$action" = high ]; then + local component_states + component_states=$(docker inspect -f '{{.State.Running}}' nginx php mysql redis 2>/dev/null) + [ "$(printf '%s\n' "$component_states" | sed '/^$/d' | wc -l)" -eq 4 ] || rc=1 + printf '%s\n' "$component_states" | grep -qv true && rc=1 + fi + if [ "$rc" -eq 0 ]; then + rm -rf "$snapshot" + return 0 + fi + kpanel_ldnmp_event rollback 85 "优化验证失败,正在恢复原配置" + [ -f "$snapshot/nginx.conf" ] && cp -a "$snapshot/nginx.conf" /home/web/nginx.conf + [ -f "$snapshot/php.ini" ] && docker cp "$snapshot/php.ini" php:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php-www.conf" ] && docker cp "$snapshot/php-www.conf" php:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/php74.ini" ] && docker cp "$snapshot/php74.ini" php74:/usr/local/etc/php/conf.d/optimized_php.ini + [ -f "$snapshot/php74-www.conf" ] && docker cp "$snapshot/php74-www.conf" php74:/usr/local/etc/php-fpm.d/www.conf + [ -f "$snapshot/mysql.cnf" ] && docker cp "$snapshot/mysql.cnf" mysql:/etc/mysql/conf.d/custom_mysql_config.cnf + if [ "$sysctl_existed" = true ]; then + cp -a "$snapshot/sysctl.conf" /etc/sysctl.d/99-kejilion-optimize.conf + else + rm -f /etc/sysctl.d/99-kejilion-optimize.conf + fi + sysctl --system >/dev/null 2>&1 + cd /home/web && docker compose restart >/dev/null 2>&1 + rm -rf "$snapshot" + return "$rc" +} + +ldnmp_update_action() { + local component="$1" version="${2:-latest}" backup_before="${3:-false}" rc + if [ "$backup_before" = true ]; then + kpanel_ldnmp_event update_backup 5 "正在创建更新前冷备" + ldnmp_backup_action || return 1 + fi + case "$component" in + nginx) nginx_upgrade ;; + redis) cd /home/web && docker compose pull redis && docker compose up -d --force-recreate redis ;; + mysql) + printf '%s' "$version" | grep -Eq '^(latest|8\.0|8\.3|8\.4|9\.0)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*mysql([^[:space:]]*)#image: mysql:${version}#" docker-compose.yml + if docker compose pull mysql && docker compose up -d --force-recreate mysql; then + rm -f docker-compose.yml.kpanel-update + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate mysql >/dev/null 2>&1 || return 86 + return "$rc" ;; + php) + printf '%s' "$version" | grep -Eq '^(7\.4|8\.0|8\.1|8\.2|8\.3)$' || return 2 + cd /home/web || return 1; cp docker-compose.yml docker-compose.yml.kpanel-update + sed -E -i "s#image:[[:space:]]*(kjlion/)?php:fpm-alpine#image: php:${version}-fpm-alpine#" docker-compose.yml + if docker compose pull php && docker compose up -d --force-recreate php; then + rm -f docker-compose.yml.kpanel-update + fix_phpfpm_conf php + return 0 + else + rc=$? + fi + mv -f docker-compose.yml.kpanel-update docker-compose.yml + docker compose up -d --force-recreate php >/dev/null 2>&1 || return 86 + return "$rc" ;; + all) + cd /home/web || return 1 + docker compose pull && docker compose up -d --force-recreate || return 86 + ;; + *) echo "不支持的更新组件" >&2; return 2 ;; + esac +} + +ldnmp_backup_action() { + [ -d /home/web ] || return 1 + local stamp archive tmp checksum source_bytes free_bytes running_services + stamp=$(date '+%Y%m%d%H%M%S'); archive="/home/web_${stamp}.tar.gz"; tmp="${archive}.tmp.$$" + source_bytes=$(du -sb /home/web 2>/dev/null | awk '{print $1}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${source_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + kpanel_ldnmp_event backup_stop 15 "正在短暂停止 LDNMP" + cd /home/web || return 1 + running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose stop || return 1 + kpanel_ldnmp_event backup_archive 45 "正在归档 /home/web" + if ! tar -C /home -czf "$tmp" web; then + [ -n "$running_services" ] && docker compose start $running_services >/dev/null 2>&1 + rm -f "$tmp" + return 1 + fi + chmod 600 "$tmp"; checksum=$(sha256sum "$tmp" | awk '{print $1}'); mv -f "$tmp" "$archive" + umask 077 + printf '{"format":"kejilion-ldnmp-v1","file":"%s","sha256":"%s","createdAt":"%s","scriptVersion":"%s"}\n' \ + "$(basename "$archive")" "$checksum" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$sh_v" > "${archive}.kpanel.json" + kpanel_ldnmp_event backup_start 80 "正在恢复 LDNMP" + [ -z "$running_services" ] || docker compose start $running_services + printf 'KPANEL_LDNMP_BACKUP %s\n' "$(basename "$archive")" +} + +ldnmp_backup_delete_action() { + local name archive + name=$(basename "${1:-}") + printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name" + [ -f "$archive" ] && [ ! -L "$archive" ] || return 1 + rm -f -- "$archive" "${archive}.kpanel.json" +} + +ldnmp_restore_action() { + local name archive stage rollback expected actual entry_count unpacked_bytes free_bytes old_running_services + name=$(basename "${1:-}"); printf '%s' "$name" | grep -Eq '^web_[0-9]{14}\.tar\.gz$' || return 2 + archive="/home/$name"; [ -f "$archive" ] || return 1 + gzip -t "$archive" || return 1 + if [ -f "${archive}.kpanel.json" ]; then + expected=$(sed -n 's/.*"sha256":"\([a-f0-9]\{64\}\)".*/\1/p' "${archive}.kpanel.json") + actual=$(sha256sum "$archive" | awk '{print $1}') + [ -n "$expected" ] && [ "$expected" = "$actual" ] || return 1 + fi + kpanel_ldnmp_event restore_scan 15 "正在扫描备份归档" + entry_count=$(tar -tzf "$archive" | wc -l) + [ "$entry_count" -le 200000 ] || return 1 + unpacked_bytes=$(tar -tvzf "$archive" | awk '{total += $3} END {printf "%.0f", total}') + free_bytes=$(df -PB1 /home | awk 'NR==2 {print $4}') + [ "${unpacked_bytes:-0}" -le $((free_bytes * 8 / 10)) ] || return 1 + tar -tzf "$archive" | grep -Ev '^web(/|$)' | grep -q . && return 1 + tar -tzf "$archive" | grep -Eq '(^/|(^|/)\.\.(/|$))' && return 1 + tar -tvzf "$archive" | awk '$1 ~ /^[lhbcp]/ { exit 0 } END { exit 1 }' && return 1 + stage=$(mktemp -d /home/.kpanel-ldnmp-restore.XXXXXX) || return 1 + rollback="/home/.kpanel-ldnmp-rollback.$(date '+%Y%m%d%H%M%S')" + kpanel_ldnmp_event restore_extract 35 "正在解压到安全暂存目录" + tar -xzf "$archive" -C "$stage" || { rm -rf "$stage"; return 1; } + docker compose -f "$stage/web/docker-compose.yml" config -q || { rm -rf "$stage"; return 1; } + kpanel_ldnmp_event restore_switch 60 "正在原子切换 /home/web" + if [ -d /home/web ]; then + cd /home/web || return 1 + old_running_services=$(docker compose ps --services --filter status=running 2>/dev/null | tr '\n' ' ') + docker compose down + mv /home/web "$rollback" + fi + if ! mv "$stage/web" /home/web; then + [ -d "$rollback" ] && mv "$rollback" /home/web + if [ -d /home/web ] && [ -n "$old_running_services" ]; then + cd /home/web && docker compose up -d $old_running_services >/dev/null 2>&1 + fi + return 1 + fi + rm -rf "$stage"; cd /home/web || return 1 + if docker compose up -d && docker exec nginx nginx -t >/dev/null 2>&1; then rm -rf "$rollback"; return 0; fi + docker compose down >/dev/null 2>&1; rm -rf /home/web + [ -d "$rollback" ] && mv "$rollback" /home/web + cd /home/web || return 1 + if [ -n "$old_running_services" ]; then + docker compose up -d $old_running_services >/dev/null 2>&1 || return 86 + fi + return 1 +} + +ldnmp_uninstall_action() { + [ "${1:-false}" = true ] && ldnmp_backup_action + if [ -d /home/web ]; then + cd /home/web || return 1 + docker compose down --rmi all + [ -f docker-compose.phpmyadmin.yml ] && docker compose -f docker-compose.phpmyadmin.yml down --rmi all >/dev/null 2>&1 + rm -rf /home/web + fi +} + +kpanel_ldnmp_run() { + local action="$1" function_name="$2"; shift 2 + mkdir -p /run/lock + local lock_fd rc + exec {lock_fd}>/run/lock/kejilion-web-environment.lock + if ! flock -n "$lock_fd"; then + kpanel_ldnmp_result failed "$action" "已有网站或 LDNMP 环境任务正在执行" + exec {lock_fd}>&- + return 75 + fi + kpanel_ldnmp_event start 1 "LDNMP 环境任务已启动" + if "$function_name" "$@"; then + kpanel_ldnmp_event complete 100 "LDNMP 环境任务已完成" + kpanel_ldnmp_result succeeded "$action" "任务执行成功" + rc=0 + else + rc=$? + kpanel_ldnmp_event failed 100 "LDNMP 环境任务执行失败" + if [ "$rc" -eq 86 ]; then + kpanel_ldnmp_result needs_attention "$action" "任务失败且无法确认安全回滚,需要人工处理" + else + kpanel_ldnmp_result failed "$action" "任务执行失败" + fi + fi + flock -u "$lock_fd" + exec {lock_fd}>&- + return "$rc" +} + +ldnmp_environment_menu() { + while true; do + clear + echo "LDNMP 环境管理" + echo "------------------------" + echo "1. 查看环境状态" + echo "2. 安装完整 LDNMP" + echo "3. 仅安装 Nginx" + echo "4. 防护管理" + echo "5. 优化管理" + echo "6. 更新环境" + echo "7. 创建冷备" + echo "8. 还原备份" + echo "9. 卸载环境" + echo "0. 返回" + echo "------------------------" + read -e -p "请输入你的选择: " choice + case "$choice" in + 1) + ldnmp_tato + docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null + ;; + 2) ldnmp_environment_install full ;; + 3) ldnmp_environment_install nginx ;; + 4) web_security ;; + 5) web_optimization ;; + 6) + read -e -p "更新组件 (nginx/mysql/php/redis/all): " component + read -e -p "目标版本(默认 latest): " version + ldnmp_update_action "$component" "${version:-latest}" false + ;; + 7) ldnmp_backup_action ;; + 8) + find /home -maxdepth 1 -type f -name 'web_*.tar.gz' -printf '%f\n' 2>/dev/null | sort -r + read -e -p "输入要还原的备份文件名: " backup_name + ldnmp_restore_action "$backup_name" + ;; + 9) + read -e -p "输入 DELETE 确认卸载 LDNMP 环境: " confirmation + [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true + ;; + 0) return 0 ;; + *) echo "无效的输入" ;; + esac + break_end + done +} + +kpanel_ldnmp_dispatch() { + local command="${1:-}"; shift || true + if [ -z "$command" ] && [ "${KJ_LDNMP_NONINTERACTIVE:-0}" != "1" ] && + [ "${KJ_LDNMP_PROTOCOL:-0}" != "1" ]; then + ldnmp_environment_menu + return + fi + printf 'KPANEL_LDNMP_PROTOCOL 1\n' + case "$command" in + status) ldnmp_environment_status ;; + catalog) ldnmp_environment_catalog ;; + install) kpanel_ldnmp_run install ldnmp_environment_install "$@" ;; + protect) kpanel_ldnmp_run protect ldnmp_protection_action "$@" ;; + optimize) kpanel_ldnmp_run optimize ldnmp_optimization_action "$@" ;; + update) kpanel_ldnmp_run update ldnmp_update_action "$@" ;; + backup) + if [ "${1:-create}" = delete ]; then + shift + kpanel_ldnmp_run backup.delete ldnmp_backup_delete_action "$@" + else + kpanel_ldnmp_run backup.create ldnmp_backup_action "$@" + fi + ;; + restore) kpanel_ldnmp_run restore ldnmp_restore_action "$@" ;; + uninstall) kpanel_ldnmp_run uninstall ldnmp_uninstall_action "$@" ;; + *) echo "不支持的 LDNMP 环境命令" >&2; return 2 ;; + esac +} + + linux_ldnmp() { while true; do + if [ "${KJ_WEB_NONINTERACTIVE:-0}" != "1" ]; then clear # send_stats "LDNMP建站" echo -e "${gl_huang}LDNMP建站" @@ -9133,7 +11235,42 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主菜单" echo -e "${gl_huang}------------------------${gl_bai}" - read -e -p "请输入你的选择: " sub_choice + fi + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + sub_choice="${KJ_WEB_RECIPE:-}" + case "$sub_choice" in + 2|3|4|5|6|7|8|9|20|22|23|24|25|26|27|28|30) ;; + *) + echo "KPANEL_PROGRESS 100 不支持的 KJ_WEB_RECIPE" + return 1 + ;; + esac + if [ -z "${KJ_WEB_DOMAIN:-}" ] || [ ${#KJ_WEB_DOMAIN} -gt 253 ] || + ! printf '%s' "$KJ_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_DOMAIN 不是有效的域名" + return 1 + fi + if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || + [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖现有产物" + return 1 + fi + if [ "$sub_choice" = "23" ]; then + if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || + ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名" + return 1 + fi + if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || + [ "$KJ_WEB_PROXY_PORT" -lt 1 ] || [ "$KJ_WEB_PROXY_PORT" -gt 65535 ]; then + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_PORT 不是有效端口" + return 1 + fi + fi + echo "KPANEL_PROGRESS 5 正在启动 kejilion.sh 原生一键建站流程" + else + read -e -p "请输入你的选择: " sub_choice + fi case $sub_choice in @@ -9142,7 +11279,7 @@ linux_ldnmp() { ldnmp_install_all ;; 2) - ldnmp_wp + ldnmp_wp "${KJ_WEB_DOMAIN:-}" ;; 3) @@ -9651,7 +11788,7 @@ linux_ldnmp() { ;; 23) - ldnmp_Proxy + ldnmp_Proxy "${KJ_WEB_DOMAIN:-}" "${KJ_WEB_PROXY_HOST:-}" "${KJ_WEB_PROXY_PORT:-}" find_container_by_host_port "$port" if [ -z "$docker_name" ]; then close_port "$port" @@ -10116,6 +12253,23 @@ linux_ldnmp() { *) echo "无效的输入!" esac + if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ]; then + if [ ! -f "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" + return 1 + fi + if kpanel_web_recipe_requires_document_root "$sub_choice" && + [ ! -d "/home/web/html/${KJ_WEB_DOMAIN}" ]; then + echo "KPANEL_PROGRESS 100 kejilion.sh 建站产物不完整" + return 1 + fi + if ! docker exec nginx nginx -t >/dev/null 2>&1; then + echo "KPANEL_PROGRESS 100 Nginx 配置校验失败" + return 1 + fi + echo "KPANEL_PROGRESS 100 kejilion.sh 原生建站产物已完成" + return 0 + fi break_end done @@ -15615,21 +17769,37 @@ openclaw_backup_restore_menu() { +refresh_apps_catalog() { + local apps_dir="$HOME/apps" + local apps_remote="${gh_proxy}github.com/kejilion/apps.git" + + install git || return 1 + if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then + echo -e "${gl_hong}错误: ${gl_bai}${apps_dir} 已存在但不是应用市场 Git 仓库,拒绝覆盖。" + return 1 + fi + if [ ! -d "$apps_dir/.git" ]; then + timeout 30s git clone --depth=1 "$apps_remote" "$apps_dir" || { + echo -e "${gl_hong}应用列表下载失败,拒绝使用不完整配置。${gl_bai}" + return 1 + } + return 0 + fi + if ! timeout 30s git -C "$apps_dir" pull --ff-only "$apps_remote" main; then + echo -e "${gl_hong}应用列表更新失败,拒绝继续使用可能过期的配置。${gl_bai}" + echo "请检查网络或 ${apps_dir} 中的本地修改后重试。" + return 1 + fi +} + linux_panel() { local sub_choice="$1" clear cd ~ -install git echo -e "${gl_kjlan}正在更新应用列表请稍等……${gl_bai}" -if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git -else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 -fi +refresh_apps_catalog || return 1 while true; do @@ -19471,15 +21641,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ kejilion ;; *) - cd ~ - install git - if [ ! -d apps/.git ]; then - timeout 10s git clone ${gh_proxy}github.com/kejilion/apps.git - else - cd apps - # git pull origin main > /dev/null 2>&1 - timeout 10s git pull ${gh_proxy}github.com/kejilion/apps.git main > /dev/null 2>&1 - fi + refresh_apps_catalog || return 1 local custom_app="$HOME/apps/${sub_choice}.conf" if [ -f "$custom_app" ]; then . "$custom_app" @@ -19488,6 +21650,12 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ fi ;; esac + if [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ]; then + return + fi + if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then + return + fi break_end sub_choice="" @@ -22030,7 +24198,7 @@ echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏夹 k fav | k 命令收藏夹" echo "应用市场管理 k app" echo "应用编号快捷管理 k app 26 | k app 1panel | k app npm" -echo "fail2ban管理 k fail2ban | k f2b" +echo "fail2ban管理 k fail2ban | k f2b [status|enable|disable]" echo "显示系统信息 k info" echo "ROOT密钥管理 k sshkey" echo "SSH公钥导入(URL) k sshkey " @@ -22066,7 +24234,12 @@ else dd_xitong ;; bbr3|bbrv3) - bbrv3 + if [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ]; then + shift + bbrv3 "$@" + else + bbrv3 + fi ;; nhyh|内核优化) Kernel_optimize @@ -22099,6 +24272,66 @@ else shift ldnmp_wp "$@" + ;; + discuz) + shift + kpanel_run_web_recipe_cli 3 "$@" + ;; + kodbox) + shift + kpanel_run_web_recipe_cli 4 "$@" + ;; + maccms) + shift + kpanel_run_web_recipe_cli 5 "$@" + ;; + dujiaoka) + shift + kpanel_run_web_recipe_cli 6 "$@" + ;; + flarum) + shift + kpanel_run_web_recipe_cli 7 "$@" + ;; + typecho) + shift + kpanel_run_web_recipe_cli 8 "$@" + ;; + linkstack) + shift + kpanel_run_web_recipe_cli 9 "$@" + ;; + ai-prompt) + shift + kpanel_run_web_recipe_cli 27 "$@" + ;; + php-site) + shift + kpanel_run_web_recipe_cli 20 "$@" + ;; + redirect-site) + shift + kpanel_run_web_recipe_cli 22 "$@" + ;; + domain-proxy) + shift + kpanel_run_web_recipe_cli 24 "$@" + ;; + bitwarden-site) + shift + kpanel_run_web_recipe_cli 25 "$@" + ;; + halo-site) + shift + kpanel_run_web_recipe_cli 26 "$@" + ;; + loadbalance-site) + shift + kpanel_run_web_recipe_cli 28 "$@" + ;; + static-site) + shift + kpanel_run_web_recipe_cli 30 "$@" ;; fd|rp|反代) shift @@ -22135,6 +24368,20 @@ else set_timedate "$@" ;; + dns) + shift + kpanel_set_dns_noninteractive "$@" + ;; + + test|check|体检|测试) + shift + if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then + kpanel_run_test_noninteractive "$@" + else + linux_test + fi + ;; + iptables_open) iptables_open @@ -22243,8 +24490,14 @@ else web) shift - if [ "$1" = "cache" ]; then + if [ "$1" = "env" ] || [ "$1" = "environment" ] || [ "$1" = "环境" ]; then + shift + kpanel_ldnmp_dispatch "$@" + elif [ "$1" = "cache" ]; then web_cache + elif [ "$1" = "del" ] || [ "$1" = "delete" ] || [ "$1" = "删除" ]; then + shift + web_del "$@" elif [ "$1" = "sec" ]; then web_security elif [ "$1" = "opt" ]; then @@ -22256,6 +24509,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift @@ -22272,7 +24536,12 @@ else ;; fail2ban|f2b) - fail2ban_panel + shift + if [ "$#" -eq 0 ]; then + fail2ban_panel + else + kpanel_f2b_dispatch "$@" + fi ;; diff --git a/kejilion.sh b/kejilion.sh index 5c127514c..c27653e1e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6648,12 +6648,12 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - + # 兼容官方已移除的老系统代号(回退使用 releases 尝试旧包库) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi - + # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod 官方已停止对当前系统($os_codename)的 APT 源支持,请升级至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" diff --git a/tests/test_kpanel_light_node_smoke.sh b/tests/test_kpanel_light_node_smoke.sh index 29c0f2156..78de0afed 100755 --- a/tests/test_kpanel_light_node_smoke.sh +++ b/tests/test_kpanel_light_node_smoke.sh @@ -2,7 +2,7 @@ set -euo pipefail project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" -script_path="${project_root}/kejilion.sh" +script_path="${SCRIPT_PATH:-${project_root}/kejilion.sh}" temporary_dir="$(mktemp -d)" trap 'rm -rf -- "${temporary_dir}"' EXIT From 3f91034c50158d701132c4adce2fea35802b50e9 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 19:03:33 +0800 Subject: [PATCH 1248/1285] fix(kpanel): make lightweight node join resumable --- cn/kejilion.sh | 74 +++++++++++------ kejilion.sh | 74 +++++++++++------ tests/test_kpanel_light_node_smoke.sh | 114 ++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 46 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e72cb41a3..ea7bed375 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -9733,6 +9733,7 @@ kpanel_node_paths() { KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" } kpanel_node_preflight() { @@ -9740,12 +9741,16 @@ kpanel_node_preflight() { echo "KPanel 轻量节点安装需要 root 权限。" >&2 return 1 } - for command_name in curl sha256sum systemctl mktemp; do + for command_name in curl sha256sum mktemp; do command -v "$command_name" >/dev/null 2>&1 || { echo "缺少必要命令: ${command_name}" >&2 return 1 } done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "缺少必要命令: systemctl" >&2 + return 1 + } KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { echo "缺少必要命令: install (coreutils)" >&2 @@ -9971,16 +9976,30 @@ KPANEL_NODE_UPDATE_TIMER } kpanel_node_cleanup_failed_join() { - systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi rm -f -- /etc/systemd/system/kejilion-node.service \ /etc/systemd/system/kejilion-node-update.service \ /etc/systemd/system/kejilion-node-update.timer rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" - systemctl daemon-reload >/dev/null 2>&1 || true + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null } kpanel_node_join() { - local token="${1:-}" node_name + local token="${1:-}" node_name resume_enrollment=false kpanel_node_paths kpanel_node_preflight || return 1 case "$token" in @@ -9991,35 +10010,39 @@ kpanel_node_join() { echo "轻量节点接入授权无效。" >&2 return 2 } - [ ! -e "$KPANEL_NODE_CONFIG" ] || { - echo "本机已接入一个 KPanel 中心;请先执行 k kpanel node uninstall。" >&2 - return 1 - } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "检测到已完成的节点授权,继续启用本机服务。" + else + echo "本机存在不完整的 KPanel 节点配置;请先执行 k kpanel node uninstall。" >&2 + return 1 + fi + fi kpanel_node_ensure_account || return 1 "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then - kpanel_node_cleanup_failed_join + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join return 1 fi - node_name="$(hostname 2>/dev/null | tr -cd '[:alnum:]._- ' | cut -c1-80)" - if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then - kpanel_node_cleanup_failed_join - return 1 + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi fi chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { - kpanel_node_cleanup_failed_join + echo "节点授权已保存,但配置权限修复失败;再次执行接入命令可继续。" >&2 return 1 } chmod 0640 "$KPANEL_NODE_CONFIG" if ! kpanel_node_write_units; then - kpanel_node_cleanup_failed_join + echo "节点授权已保存,但 systemd 单元写入失败;再次执行接入命令可继续。" >&2 return 1 fi - systemctl daemon-reload - if ! systemctl enable --now kejilion-node.service kejilion-node-update.timer || - ! systemctl is-active --quiet kejilion-node.service; then - kpanel_node_cleanup_failed_join - echo "KPanel 轻量节点启动失败。" >&2 + if ! kpanel_node_activate; then + echo "KPanel 轻量节点授权已保存,但服务启动失败;修复 systemd 后再次执行接入命令即可续装。" >&2 return 1 fi echo "KPanel 轻量节点已接入,后续将自动更新。" @@ -10032,7 +10055,7 @@ kpanel_node_status() { return 1 } "$KPANEL_NODE_BINARY" version - systemctl --no-pager --full status kejilion-node.service + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service } kpanel_node_update() { @@ -10051,12 +10074,17 @@ kpanel_node_uninstall() { echo "卸载 KPanel 轻量节点需要 root 权限。" >&2 return 1 } - systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi rm -f -- /etc/systemd/system/kejilion-node.service \ /etc/systemd/system/kejilion-node-update.service \ /etc/systemd/system/kejilion-node-update.timer rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" - systemctl daemon-reload >/dev/null 2>&1 || true + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true echo "KPanel 轻量节点已从本机卸载;中心端的离线记录需在集群页面删除。" } diff --git a/kejilion.sh b/kejilion.sh index c27653e1e..413982834 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -9733,6 +9733,7 @@ kpanel_node_paths() { KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" } kpanel_node_preflight() { @@ -9740,12 +9741,16 @@ kpanel_node_preflight() { echo "KPanel 轻量节点安装需要 root 权限。" >&2 return 1 } - for command_name in curl sha256sum systemctl mktemp; do + for command_name in curl sha256sum mktemp; do command -v "$command_name" >/dev/null 2>&1 || { echo "缺少必要命令: ${command_name}" >&2 return 1 } done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "缺少必要命令: systemctl" >&2 + return 1 + } KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { echo "缺少必要命令: install (coreutils)" >&2 @@ -9971,16 +9976,30 @@ KPANEL_NODE_UPDATE_TIMER } kpanel_node_cleanup_failed_join() { - systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi rm -f -- /etc/systemd/system/kejilion-node.service \ /etc/systemd/system/kejilion-node-update.service \ /etc/systemd/system/kejilion-node-update.timer rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" - systemctl daemon-reload >/dev/null 2>&1 || true + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null } kpanel_node_join() { - local token="${1:-}" node_name + local token="${1:-}" node_name resume_enrollment=false kpanel_node_paths kpanel_node_preflight || return 1 case "$token" in @@ -9991,35 +10010,39 @@ kpanel_node_join() { echo "轻量节点接入授权无效。" >&2 return 2 } - [ ! -e "$KPANEL_NODE_CONFIG" ] || { - echo "本机已接入一个 KPanel 中心;请先执行 k kpanel node uninstall。" >&2 - return 1 - } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "检测到已完成的节点授权,继续启用本机服务。" + else + echo "本机存在不完整的 KPanel 节点配置;请先执行 k kpanel node uninstall。" >&2 + return 1 + fi + fi kpanel_node_ensure_account || return 1 "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then - kpanel_node_cleanup_failed_join + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join return 1 fi - node_name="$(hostname 2>/dev/null | tr -cd '[:alnum:]._- ' | cut -c1-80)" - if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then - kpanel_node_cleanup_failed_join - return 1 + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi fi chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { - kpanel_node_cleanup_failed_join + echo "节点授权已保存,但配置权限修复失败;再次执行接入命令可继续。" >&2 return 1 } chmod 0640 "$KPANEL_NODE_CONFIG" if ! kpanel_node_write_units; then - kpanel_node_cleanup_failed_join + echo "节点授权已保存,但 systemd 单元写入失败;再次执行接入命令可继续。" >&2 return 1 fi - systemctl daemon-reload - if ! systemctl enable --now kejilion-node.service kejilion-node-update.timer || - ! systemctl is-active --quiet kejilion-node.service; then - kpanel_node_cleanup_failed_join - echo "KPanel 轻量节点启动失败。" >&2 + if ! kpanel_node_activate; then + echo "KPanel 轻量节点授权已保存,但服务启动失败;修复 systemd 后再次执行接入命令即可续装。" >&2 return 1 fi echo "KPanel 轻量节点已接入,后续将自动更新。" @@ -10032,7 +10055,7 @@ kpanel_node_status() { return 1 } "$KPANEL_NODE_BINARY" version - systemctl --no-pager --full status kejilion-node.service + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service } kpanel_node_update() { @@ -10051,12 +10074,17 @@ kpanel_node_uninstall() { echo "卸载 KPanel 轻量节点需要 root 权限。" >&2 return 1 } - systemctl disable --now kejilion-node.service kejilion-node-update.timer >/dev/null 2>&1 || true + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi rm -f -- /etc/systemd/system/kejilion-node.service \ /etc/systemd/system/kejilion-node-update.service \ /etc/systemd/system/kejilion-node-update.timer rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" - systemctl daemon-reload >/dev/null 2>&1 || true + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true echo "KPanel 轻量节点已从本机卸载;中心端的离线记录需在集群页面删除。" } diff --git a/tests/test_kpanel_light_node_smoke.sh b/tests/test_kpanel_light_node_smoke.sh index 78de0afed..d19b7e6c5 100755 --- a/tests/test_kpanel_light_node_smoke.sh +++ b/tests/test_kpanel_light_node_smoke.sh @@ -45,6 +45,13 @@ join_body="$( capture && /^}$/ { exit } ' "${normalized_script}" )" +activate_body="$( + awk ' + /^kpanel_node_activate\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${normalized_script}" +)" account_body="$( awk ' /^kpanel_node_ensure_account\(\) \{/ { capture=1 } @@ -65,6 +72,9 @@ printf '%s\n' "${dispatch_body}" | grep -F 'uninstall|remove) kpanel_node_uninst printf '%s\n' "${join_body}" | grep -F 'kpl1.*)' >/dev/null printf '%s\n' "${join_body}" | grep -F 'kpanel_node_ensure_account || return 1' >/dev/null +printf '%s\n' "${join_body}" | grep -F "LC_ALL=C tr -cd '[:alnum:]_. -'" >/dev/null +printf '%s\n' "${join_body}" | grep -F 'resume_enrollment=true' >/dev/null +printf '%s\n' "${join_body}" | grep -F '授权已保存' >/dev/null printf '%s\n' "${join_body}" | grep -F '"$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node' >/dev/null printf '%s\n' "${account_body}" | grep -F 'useradd --system --no-create-home' >/dev/null printf '%s\n' "${account_body}" | grep -F 'systemd-sysusers "$sysusers_config"' >/dev/null @@ -75,6 +85,7 @@ printf '%s\n' "${join_body}" | grep -F 'chown root:kejilion-node "$KPANEL_NODE_C printf '%s\n' "${join_body}" | grep -F 'chmod 0640 "$KPANEL_NODE_CONFIG"' >/dev/null grep -F '[ -d /run/systemd/system ]' "${normalized_script}" >/dev/null grep -F 'KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)"' "${normalized_script}" >/dev/null +grep -F 'KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)"' "${normalized_script}" >/dev/null grep -F '"$KPANEL_NODE_INSTALL_BIN" -d -o root -g root' "${normalized_script}" >/dev/null if grep -F $'\tinstall -d -o root' "${normalized_script}" >/dev/null; then echo "lightweight node installer is shadowed by the package install helper" >&2 @@ -84,6 +95,10 @@ if printf '%s\n' "${join_body}" | grep -Eq 'docker|podman'; then echo "lightweight node installer unexpectedly depends on a container runtime" >&2 exit 1 fi +if printf '%s\n' "${activate_body}" | grep -Eq 'enable --now|is-active --quiet'; then + echo "lightweight node activation uses wrapper-incompatible systemctl arguments" >&2 + exit 1 +fi grep -F 'base_url="https://github.com/kejilion/KPanel/releases/latest/download"' "${updater}" >/dev/null grep -F -- "--proto '=https' --tlsv1.2" "${updater}" >/dev/null @@ -151,4 +166,103 @@ chmod +x "${fallback_bin}"/* ) test -f "${fallback_marker}" +# Exercise the native systemctl path one unit at a time. kejilion.sh defines a +# compatibility wrapper named systemctl, so node lifecycle calls must bypass it. +systemctl_bin="${temporary_dir}/systemctl" +systemctl_log="${temporary_dir}/systemctl.log" +cat >"${systemctl_bin}" <<'MOCK_SYSTEMCTL' +#!/bin/bash +printf '%s\n' "$*" >>"${KPANEL_TEST_SYSTEMCTL_LOG}" +MOCK_SYSTEMCTL +chmod +x "${systemctl_bin}" +( + export KPANEL_TEST_SYSTEMCTL_LOG="${systemctl_log}" + KPANEL_NODE_SYSTEMCTL="${systemctl_bin}" + eval "${activate_body}" + kpanel_node_activate +) +cat >"${temporary_dir}/expected-systemctl.log" <<'EXPECTED_SYSTEMCTL' +daemon-reload +enable kejilion-node.service +enable kejilion-node-update.timer +start kejilion-node.service +start kejilion-node-update.timer +is-active kejilion-node.service +EXPECTED_SYSTEMCTL +cmp "${temporary_dir}/expected-systemctl.log" "${systemctl_log}" + +sanitized_name="$(printf '%s' 'edge_node-01 bad@name' | LC_ALL=C tr -cd '[:alnum:]_. -')" +test "${sanitized_name}" = 'edge_node-01 badname' + +# Exercise the real join control flow across a post-enrollment service failure. +# The one-time token must not be consumed twice and the saved identity must +# survive so the same command can safely finish activation on the next run. +join_runtime="${temporary_dir}/join-runtime" +mkdir -p "${join_runtime}/bin" +cat >"${join_runtime}/install" <<'MOCK_INSTALL' +#!/bin/bash +target="${@: -1}" +mkdir -p "$target" +MOCK_INSTALL +cat >"${join_runtime}/systemctl" <<'MOCK_JOIN_SYSTEMCTL' +#!/bin/bash +printf '%s\n' "$*" >>"${KPANEL_TEST_JOIN_SYSTEMCTL_LOG}" +if [ "$*" = "start kejilion-node.service" ] && [ ! -f "${KPANEL_TEST_JOIN_FAIL_ONCE}" ]; then + touch "${KPANEL_TEST_JOIN_FAIL_ONCE}" + exit 1 +fi +MOCK_JOIN_SYSTEMCTL +chmod +x "${join_runtime}/install" "${join_runtime}/systemctl" +( + export KPANEL_TEST_JOIN_ROOT="${join_runtime}" + export KPANEL_TEST_JOIN_SYSTEMCTL_LOG="${join_runtime}/systemctl.log" + export KPANEL_TEST_JOIN_FAIL_ONCE="${join_runtime}/failed-once" + eval "${activate_body}" + eval "${join_body}" + kpanel_node_paths() { + KPANEL_NODE_HOME="${KPANEL_TEST_JOIN_ROOT}/home" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="${KPANEL_TEST_JOIN_ROOT}/config" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="${KPANEL_TEST_JOIN_ROOT}/systemctl" + } + kpanel_node_preflight() { + KPANEL_NODE_INSTALL_BIN="${KPANEL_TEST_JOIN_ROOT}/install" + } + kpanel_node_ensure_account() { :; } + kpanel_node_write_updater() { + mkdir -p "${KPANEL_NODE_HOME}" + cat >"${KPANEL_NODE_UPDATER}" <<'MOCK_UPDATER' +#!/bin/bash +exit 0 +MOCK_UPDATER + cat >"${KPANEL_NODE_BINARY}" <<'MOCK_NODE' +#!/bin/bash +if [ "${1:-}" = "enroll" ]; then + printf '%s\n' enrolled >>"${KPANEL_TEST_JOIN_ROOT}/enroll.log" + while [ "$#" -gt 0 ]; do + if [ "$1" = "--config" ]; then + shift + printf '%s\n' '{"schemaVersion":1}' >"$1" + break + fi + shift + done +fi +MOCK_NODE + chmod +x "${KPANEL_NODE_UPDATER}" "${KPANEL_NODE_BINARY}" + } + kpanel_node_write_units() { :; } + kpanel_node_cleanup_failed_join() { rm -rf -- "${KPANEL_NODE_HOME}" "${KPANEL_NODE_CONFIG_DIR}"; } + chown() { :; } + if kpanel_node_join 'kpl1.test-token'; then + echo "first join unexpectedly succeeded despite injected activation failure" >&2 + exit 1 + fi + test -f "${KPANEL_NODE_CONFIG}" + kpanel_node_join 'kpl1.test-token' + test "$(wc -l <"${KPANEL_TEST_JOIN_ROOT}/enroll.log")" -eq 1 +) + echo "KPanel lightweight-node installer smoke checks passed." From 82aaa87b3dea671e6fc5e1a60f536c40352c47ad Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 2 Aug 2026 19:12:57 +0800 Subject: [PATCH 1249/1285] docs: require root and CN script synchronization --- CONTRIBUTING.md | 13 +++++++++++++ tests/test_cn_script_sync.sh | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 tests/test_cn_script_sync.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..66f5a8b4e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# 贡献与同步规则 + +## 主脚本与中文脚本 + +- 修改根目录 `kejilion.sh` 的业务逻辑、协议、命令、依赖或修复时,必须在同一提交中同步更新 `cn/kejilion.sh`。 +- 两份脚本除区域入口参数外必须保持一致:根脚本使用 `canshu="default"`,中文脚本使用 `canshu="CN"`。 +- 提交前必须运行: + + ```bash + bash tests/test_cn_script_sync.sh + ``` + +- 同步检查失败时不得合并或发布;不能通过跳过测试、复制旧版脚本或仅修改其中一份来规避。 diff --git a/tests/test_cn_script_sync.sh b/tests/test_cn_script_sync.sh new file mode 100644 index 000000000..88961629c --- /dev/null +++ b/tests/test_cn_script_sync.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -euo pipefail + +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +temporary_dir="$(mktemp -d)" +trap 'rm -rf -- "${temporary_dir}"' EXIT + +normalize_script() { + local source_path="$1" target_path="$2" + sed -e 's/\r$//' \ + -e 's/^canshu="default"$/canshu="REGION"/' \ + -e 's/^canshu="CN"$/canshu="REGION"/' \ + "${source_path}" >"${target_path}" +} + +normalize_script "${project_root}/kejilion.sh" "${temporary_dir}/root.sh" +normalize_script "${project_root}/cn/kejilion.sh" "${temporary_dir}/cn.sh" + +bash -n "${temporary_dir}/root.sh" +bash -n "${temporary_dir}/cn.sh" + +if ! cmp -s "${temporary_dir}/root.sh" "${temporary_dir}/cn.sh"; then + echo "FAIL: cn/kejilion.sh must match kejilion.sh except for canshu region value" >&2 + diff -u "${temporary_dir}/root.sh" "${temporary_dir}/cn.sh" || true + exit 1 +fi + +echo "PASS: root and cn scripts are synchronized" From 17871d2074c243b15a7f3120c071c686c02e7b61 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 5 Aug 2026 13:33:39 +0800 Subject: [PATCH 1250/1285] feat(kpanel): add SSH port noninteractive adapter --- cn/kejilion.sh | 54 +++++++++++++++++++ kejilion.sh | 54 +++++++++++++++++++ ...st_kpanel_ssh_port_noninteractive_smoke.sh | 53 ++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 tests/test_kpanel_ssh_port_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ea7bed375..01cd8b501 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -22,6 +22,7 @@ fi kpanel_protocol_active() { [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -5844,6 +5845,54 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "错误: KPanel SSH 端口协议必须以 root 运行" + return 1 + } + [ "$#" -eq 1 ] || { + echo "错误: SSH 端口协议需要一个端口号" + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "错误: SSH 端口必须为 1-65535" + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "错误: 未找到可管理的 OpenSSH 配置" + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # 复用现有 SSH 修改主业务;适配层只负责非交互校验和机器可读结果。 + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "错误: SSH 端口修改后回读验证失败" + return 1 + fi + if command -v sshd >/dev/null 2>&1 && ! sshd -t; then + echo "错误: SSH 配置语法验证失败" + return 1 + fi + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -24401,6 +24450,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then diff --git a/kejilion.sh b/kejilion.sh index 413982834..6b88e3d3c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -22,6 +22,7 @@ fi kpanel_protocol_active() { [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -5844,6 +5845,54 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "错误: KPanel SSH 端口协议必须以 root 运行" + return 1 + } + [ "$#" -eq 1 ] || { + echo "错误: SSH 端口协议需要一个端口号" + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "错误: SSH 端口必须为 1-65535" + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "错误: 未找到可管理的 OpenSSH 配置" + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # 复用现有 SSH 修改主业务;适配层只负责非交互校验和机器可读结果。 + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "错误: SSH 端口修改后回读验证失败" + return 1 + fi + if command -v sshd >/dev/null 2>&1 && ! sshd -t; then + echo "错误: SSH 配置语法验证失败" + return 1 + fi + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -24401,6 +24450,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then diff --git a/tests/test_kpanel_ssh_port_noninteractive_smoke.sh b/tests/test_kpanel_ssh_port_noninteractive_smoke.sh new file mode 100644 index 000000000..c5a5f5035 --- /dev/null +++ b/tests/test_kpanel_ssh_port_noninteractive_smoke.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_paths=("${project_root}/kejilion.sh" "${project_root}/cn/kejilion.sh") +reference_adapter="" + +for script_path in "${script_paths[@]}"; do + bash -n "${script_path}" + grep -F 'if ! kpanel_protocol_active; then' "${script_path}" >/dev/null + grep -F 'kpanel_ssh_port_noninteractive() {' "${script_path}" >/dev/null + grep -F '[ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null + grep -F 'new_ssh_port "$new_port" || return 1' "${script_path}" >/dev/null + grep -F 'KPANEL_SSH_RESULT applied' "${script_path}" >/dev/null + grep -F 'KPANEL_SSH_RESULT unchanged' "${script_path}" >/dev/null + grep -F 'KPANEL_SSH_PORT $new_port' "${script_path}" >/dev/null + grep -F 'kpanel_ssh_port_noninteractive "$@"' "${script_path}" >/dev/null + + # KPanel 入口只能包装现有主业务,不能复制或改写 new_ssh_port。 + test "$(grep -c '^new_ssh_port() {' "${script_path}")" -eq 1 + adapter_body="$({ + awk ' + /^kpanel_ssh_port_noninteractive\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" + })" + grep -F 'new_ssh_port "$new_port"' <<<"${adapter_body}" >/dev/null + if grep -Eq 'sed -i|rm -rf /etc/ssh|systemctl (reload|restart)' <<<"${adapter_body}"; then + echo "SSH adapter duplicated the existing SSH mutation logic in ${script_path}" >&2 + exit 1 + fi + if [ -z "${reference_adapter}" ]; then + reference_adapter="${adapter_body}" + elif [ "${adapter_body}" != "${reference_adapter}" ]; then + echo "SSH adapters are not synchronized: ${script_path}" >&2 + exit 1 + fi + + protocol_guard_body="$({ + awk ' + /^kpanel_protocol_active\(\) \{/ { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" + })" + eval "${protocol_guard_body}" + KJ_SSH_PORT_NONINTERACTIVE=1 + kpanel_protocol_active + unset KJ_SSH_PORT_NONINTERACTIVE +done + +printf '%s\n' "kpanel_ssh_port_noninteractive_smoke=pass" From 3e2ff75a02942f9f69d9c923db02da380b952271 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 4 Aug 2026 23:51:29 +0800 Subject: [PATCH 1251/1285] fix(kpanel): handle multi-network container firewall rules --- cn/kejilion.sh | 148 ++++++++---------- kejilion.sh | 148 ++++++++---------- tests/test_kpanel_app_noninteractive_smoke.sh | 10 +- ..._multi_network_container_firewall_smoke.sh | 93 +++++++++++ 4 files changed, 226 insertions(+), 173 deletions(-) create mode 100755 tests/test_multi_network_container_firewall_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 01cd8b501..8d18b40e3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -2720,56 +2720,50 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 + local container_ips - # 获取容器的 IP 地址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi - - install iptables - - - # 检查并封禁其他所有 IP - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 检查并放行指定 IP - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # 检查并放行本地网络 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - - - # 检查并封禁其他所有 IP - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # 检查并放行指定 IP - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - # 检查并放行本地网络 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT + # 获取容器在所有 Docker 网络中的 IPv4 地址,逐个应用规则。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "错误:无法获取容器 ${container_name_or_id} 的 IPv4 地址。" >&2 + return 1 fi - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi + install iptables + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已阻止IP+端口访问该服务" save_iptables_rules @@ -2781,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # 获取容器的 IP 地址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # 获取容器在所有 Docker 网络中的 IPv4 地址,逐个清除规则。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "错误:无法获取容器 ${container_name_or_id} 的 IPv4 地址。" >&2 return 1 fi install iptables - - # 清除封禁其他所有 IP 的规则 - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的规则 - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地网络 127.0.0.0/8 的规则 - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # 清除封禁其他所有 IP 的规则 - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的规则 - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地网络 127.0.0.0/8 的规则 - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已允许IP+端口访问该服务" save_iptables_rules @@ -3097,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3110,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" diff --git a/kejilion.sh b/kejilion.sh index 6b88e3d3c..ee38b04c2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -2720,56 +2720,50 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 + local container_ips - # 获取容器的 IP 地址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi - - install iptables - - - # 检查并封禁其他所有 IP - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 检查并放行指定 IP - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # 检查并放行本地网络 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - - - # 检查并封禁其他所有 IP - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # 检查并放行指定 IP - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - # 检查并放行本地网络 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT + # 获取容器在所有 Docker 网络中的 IPv4 地址,逐个应用规则。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "错误:无法获取容器 ${container_name_or_id} 的 IPv4 地址。" >&2 + return 1 fi - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi + install iptables + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已阻止IP+端口访问该服务" save_iptables_rules @@ -2781,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # 获取容器的 IP 地址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # 获取容器在所有 Docker 网络中的 IPv4 地址,逐个清除规则。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "错误:无法获取容器 ${container_name_or_id} 的 IPv4 地址。" >&2 return 1 fi install iptables - - # 清除封禁其他所有 IP 的规则 - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的规则 - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地网络 127.0.0.0/8 的规则 - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # 清除封禁其他所有 IP 的规则 - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的规则 - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地网络 127.0.0.0/8 的规则 - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已允许IP+端口访问该服务" save_iptables_rules @@ -3097,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3110,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" diff --git a/tests/test_kpanel_app_noninteractive_smoke.sh b/tests/test_kpanel_app_noninteractive_smoke.sh index b7b5f158e..f3432ea99 100755 --- a/tests/test_kpanel_app_noninteractive_smoke.sh +++ b/tests/test_kpanel_app_noninteractive_smoke.sh @@ -223,6 +223,7 @@ fi management_helpers="$( for helper in \ + get_container_ipv4_addresses \ kpanel_app_service_name \ kpanel_app_verified_service \ kpanel_app_access_path \ @@ -253,7 +254,11 @@ docker() { case "$1" in inspect) "${current_exists}" || return 1 - printf '%s\n' "${current_id}" + if [[ "$*" == *'.NetworkSettings.Networks'* ]]; then + printf '%s\n' "172.22.0.2" "172.21.0.2" + else + printf '%s\n' "${current_id}" + fi ;; ps) "${current_exists}" && printf '%s\n' "${docker_app_service:-$docker_name}" @@ -286,6 +291,9 @@ docker_img="example/managed:latest" app_id=997 printf '%s\n' "${app_id}" >>"${test_app_root}/appno.txt" test "$(kpanel_app_read_access_mode)" = "domain_only" +iptables() { [[ "$*" != *'-d 172.21.0.2'* ]]; } +test "$(kpanel_app_read_access_mode)" = "direct" +iptables() { return 0; } printf '%s\n' "domain_only" >"${test_app_root}/${docker_name}_access.conf" export KJ_APP_ACTION=update export KJ_APP_EXPECTED_CONTAINER_ID="${current_id}" diff --git a/tests/test_multi_network_container_firewall_smoke.sh b/tests/test_multi_network_container_firewall_smoke.sh new file mode 100755 index 000000000..52bb572ca --- /dev/null +++ b/tests/test_multi_network_container_firewall_smoke.sh @@ -0,0 +1,93 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +test_script() ( + local script_path=$1 + local test_root + local command_log + local check_status=1 + local insert_status=0 + local docker_addresses + + test_root="$(mktemp -d)" + trap 'rm -rf "${test_root}"' EXIT + command_log="${test_root}/iptables.log" + + for helper in \ + get_container_ipv4_addresses \ + ensure_docker_user_rule \ + remove_docker_user_rule \ + block_container_port \ + clear_container_rules + do + eval "$( + awk -v helper="${helper}" ' + $0 ~ "^" helper "\\(\\) \\{" { capture=1 } + capture { print } + capture && /^}$/ { exit } + ' "${script_path}" + )" + done + + docker() { + [ "$1" = "inspect" ] || return 1 + printf '%s\n' "${docker_addresses}" + } + install() { return 0; } + save_iptables_rules() { return 0; } + iptables() { + case "$1" in + -C) + return "${check_status}" + ;; + -I) + printf '%s\n' "$*" >>"${command_log}" + return "${insert_status}" + ;; + -D) + printf '%s\n' "$*" >>"${command_log}" + return 0 + ;; + esac + return 1 + } + + # 单网络容器保持原有行为。 + docker_addresses="172.22.0.2" + : >"${command_log}" + block_container_port test-container 192.0.2.10 >/dev/null + test "$(wc -l <"${command_log}")" -eq 7 + grep -q -- '-d 172.22.0.2' "${command_log}" + + # 多网络容器应为每个独立 IP 应用规则,不能再拼接地址。 + docker_addresses=$'172.22.0.2\n172.21.0.2\n172.22.0.2' + : >"${command_log}" + block_container_port test-container 192.0.2.10 >/dev/null + test "$(wc -l <"${command_log}")" -eq 14 + test "$(grep -c -- '-d 172.22.0.2' "${command_log}")" -eq 7 + test "$(grep -c -- '-d 172.21.0.2' "${command_log}")" -eq 7 + ! grep -q '172.22.0.2172.21.0.2' "${command_log}" + + # 清除规则也必须覆盖全部网络地址。 + check_status=0 + : >"${command_log}" + clear_container_rules test-container 192.0.2.10 >/dev/null + test "$(wc -l <"${command_log}")" -eq 14 + test "$(grep -c -- '-D DOCKER-USER' "${command_log}")" -eq 14 + + # iptables 写入失败时不得输出成功提示。 + check_status=1 + insert_status=1 + if output="$(block_container_port test-container 192.0.2.10 2>/dev/null)"; then + printf '%s\n' "iptables failure was reported as successful: ${script_path}" >&2 + exit 1 + fi + ! grep -q '已阻止IP+端口访问该服务' <<<"${output}" +) + +test_script "${project_root}/kejilion.sh" +test_script "${project_root}/cn/kejilion.sh" + +printf '%s\n' "multi_network_container_firewall=pass" From d1b95fa61b73bbfb28edb214b33574ef4c388bd0 Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 5 Aug 2026 14:32:54 +0800 Subject: [PATCH 1252/1285] chore: release kejilion.sh 4.5.5 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kejilion_sh_log.txt | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 8d18b40e3..58d407505 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index ee38b04c2..51ac0223e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 73e5255fc..87db82cab 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1531,4 +1531,9 @@ OpenClaw菜单对接机器人管理 调整了飞书接入方式 用官方接入 系统工具BBRv3新增KPanel固定协议,支持面板读取真实状态并提交安装、更新和卸载任务。 KPanel调用BBRv3流程时不会自动重启服务器,任务完成后由用户确认重启并复核内核状态。 原 k bbrv3 交互菜单、XanMod安装方式和ARM64脚本入口保持不变。 +------------------------ +2026-08-05 v4.5.5 +新增KPanel SSH端口非交互适配入口,复用脚本原有单端口修改业务并返回机器可读结果。 +修复多网络容器的IP端口访问规则只处理单一地址的问题,对每个Docker IPv4同步写入、识别和清理DOCKER-USER规则。 +根目录与CN脚本保持同步;原SSH交互入口、单网络容器和应用访问策略保持兼容。 From dd26cf7eb962f985f94773c15f9b643677b4471c Mon Sep 17 00:00:00 2001 From: kejilion Date: Wed, 5 Aug 2026 14:53:15 +0800 Subject: [PATCH 1253/1285] fix(kpanel): verify SSH port listener --- cn/kejilion.sh | 30 ++++++++++++++++++- kejilion.sh | 30 ++++++++++++++++++- kejilion_sh_log.txt | 2 +- ...st_kpanel_ssh_port_noninteractive_smoke.sh | 2 ++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 58d407505..5cb95a9a8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -5841,6 +5841,14 @@ kpanel_ssh_port_noninteractive() { echo "错误: 未找到可管理的 OpenSSH 配置" return 1 } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "错误: SSH 配置校验或监听检查工具不可用" + return 1 + } + sshd -t || { + echo "错误: 当前 SSH 配置语法验证失败" + return 1 + } local configured_ports configured_ports="$({ @@ -5859,10 +5867,30 @@ kpanel_ssh_port_noninteractive() { echo "错误: SSH 端口修改后回读验证失败" return 1 fi - if command -v sshd >/dev/null 2>&1 && ! sshd -t; then + if ! sshd -t; then echo "错误: SSH 配置语法验证失败" return 1 fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "错误: SSH 新端口未进入监听状态" + return 1 + } echo "KPANEL_SSH_PORT $new_port" echo "KPANEL_SSH_RESULT applied" diff --git a/kejilion.sh b/kejilion.sh index 51ac0223e..5f17a84fd 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -5841,6 +5841,14 @@ kpanel_ssh_port_noninteractive() { echo "错误: 未找到可管理的 OpenSSH 配置" return 1 } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "错误: SSH 配置校验或监听检查工具不可用" + return 1 + } + sshd -t || { + echo "错误: 当前 SSH 配置语法验证失败" + return 1 + } local configured_ports configured_ports="$({ @@ -5859,10 +5867,30 @@ kpanel_ssh_port_noninteractive() { echo "错误: SSH 端口修改后回读验证失败" return 1 fi - if command -v sshd >/dev/null 2>&1 && ! sshd -t; then + if ! sshd -t; then echo "错误: SSH 配置语法验证失败" return 1 fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "错误: SSH 新端口未进入监听状态" + return 1 + } echo "KPANEL_SSH_PORT $new_port" echo "KPANEL_SSH_RESULT applied" diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index 87db82cab..f8d181e6b 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1533,7 +1533,7 @@ KPanel调用BBRv3流程时不会自动重启服务器,任务完成后由用户 原 k bbrv3 交互菜单、XanMod安装方式和ARM64脚本入口保持不变。 ------------------------ 2026-08-05 v4.5.5 -新增KPanel SSH端口非交互适配入口,复用脚本原有单端口修改业务并返回机器可读结果。 +新增KPanel SSH端口非交互适配入口,复用脚本原有单端口修改业务,并在配置语法和新端口监听均验证通过后返回机器可读结果。 修复多网络容器的IP端口访问规则只处理单一地址的问题,对每个Docker IPv4同步写入、识别和清理DOCKER-USER规则。 根目录与CN脚本保持同步;原SSH交互入口、单网络容器和应用访问策略保持兼容。 diff --git a/tests/test_kpanel_ssh_port_noninteractive_smoke.sh b/tests/test_kpanel_ssh_port_noninteractive_smoke.sh index c5a5f5035..38e35b09e 100644 --- a/tests/test_kpanel_ssh_port_noninteractive_smoke.sh +++ b/tests/test_kpanel_ssh_port_noninteractive_smoke.sh @@ -11,6 +11,8 @@ for script_path in "${script_paths[@]}"; do grep -F 'kpanel_ssh_port_noninteractive() {' "${script_path}" >/dev/null grep -F '[ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2' "${script_path}" >/dev/null grep -F 'new_ssh_port "$new_port" || return 1' "${script_path}" >/dev/null + grep -F 'ss -H -ltn' "${script_path}" >/dev/null + grep -F '错误: SSH 新端口未进入监听状态' "${script_path}" >/dev/null grep -F 'KPANEL_SSH_RESULT applied' "${script_path}" >/dev/null grep -F 'KPANEL_SSH_RESULT unchanged' "${script_path}" >/dev/null grep -F 'KPANEL_SSH_PORT $new_port' "${script_path}" >/dev/null From 1f511163272876e962c38eca7971aab871d4e7f7 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 9 Aug 2026 04:21:24 +0000 Subject: [PATCH 1254/1285] =?UTF-8?q?=F0=9F=8C=90=20Weekly=20translation?= =?UTF-8?q?=20update=20-=202026-08-09=2004:21:24?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- en/kejilion.sh | 1240 ++++++++++++++++++++++++++++------------- jp/kejilion.sh | 1202 ++++++++++++++++++++++++++------------- kr/kejilion.sh | 1358 ++++++++++++++++++++++++++++++--------------- tw/kejilion.sh | 1450 +++++++++++++++++++++++++++++++----------------- 4 files changed, 3525 insertions(+), 1725 deletions(-) diff --git a/en/kejilion.sh b/en/kejilion.sh index 7e55ab625..f7fde9a52 100644 --- a/en/kejilion.sh +++ b/en/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' @@ -16,7 +16,13 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -319,7 +325,7 @@ restart() { if [ $? -eq 0 ]; then echo "$1The service has been restarted." else - echo "Error: Restart$1Service failed." + echo "错误:重启 $1Service failed." fi } @@ -333,7 +339,7 @@ start() { fi } -# Stop service +# 停止服务 stop() { systemctl stop "$1" if [ $? -eq 0 ]; then @@ -510,7 +516,7 @@ while true; do echo "11. Enter the specified container 12. View the container log" echo "13. Check the container network 14. Check the container occupancy" echo "------------------------" - echo "15. Enable container port access 16. Close container port access" + echo "15. 开启容器端口访问 16. 关闭容器端口访问" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -523,7 +529,7 @@ while true; do ;; 2) send_stats "Start the specified container" - read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername + read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername docker start $dockername ;; 3) @@ -537,7 +543,7 @@ while true; do docker rm -f $dockername ;; 5) - send_stats "Restart the specified container" + send_stats "重启指定容器" read -e -p "Please enter the container name (please separate multiple container names with spaces):" dockername docker restart $dockername ;; @@ -598,7 +604,7 @@ while true; do break_end ;; 14) - send_stats "View container occupancy" + send_stats "查看容器占用" docker stats --no-stream break_end ;; @@ -615,7 +621,7 @@ while true; do 16) send_stats "Block container port access" - read -e -p "Please enter the container name:" docker_name + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -769,7 +775,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # Check if the configuration file exists, if not create the file and write the default settings + # Check if the configuration file exists, if not create the file and write default settings if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -1135,7 +1141,7 @@ iptables_panel() { 2) read -e -p "Please enter the closed port number:" c_port close_port $c_port - send_stats "Close specified port" + send_stats "关闭指定端口" ;; 3) # Open all ports @@ -1176,7 +1182,7 @@ iptables_panel() { allow_ip $o_ip ;; 6) - # IP blacklist + # IP 黑名单 read -e -p "Please enter the blocked IP or IP range:" c_ip block_ip $c_ip ;; @@ -1186,7 +1192,7 @@ iptables_panel() { iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "Clear specified IP" + send_stats "清除指定IP" ;; 11) # Allow PING @@ -1221,7 +1227,7 @@ iptables_panel() { ;; 17) - read -e -p "Please enter the cleared country code (multiple country codes can be separated by spaces, such as CN US JP):" country_code + read -e -p "请输入清除的国家代码(多个国家代码可用空格隔开如 CN US JP): " country_code manage_country_rules unblock $country_code send_stats "clear country$country_codeIP" ;; @@ -1255,10 +1261,10 @@ add_swap() { # Make sure /swapfile is no longer in use swapoff /swapfile - # Delete old /swapfile + # 删除旧的 /swapfile rm -f /swapfile - # Create a new swap partition + # 创建新的 swap 分区 fallocate -l ${new_swap}M /swapfile chmod 600 /swapfile mkswap /swapfile @@ -1606,7 +1612,7 @@ certs_status() { done # 3. Intelligent verification - # Just include "BEGIN CERTIFICATE" and "PRIVATE KEY" to pass + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1793,9 +1799,9 @@ phpmyadmin_upgrade() { ip_address check_docker_app_ip - echo "Login information:" + echo "登录信息: " echo "username:$dbuse" - echo "password:$dbusepasswd" + echo "密码: $dbusepasswd" echo send_stats "start up$ldnmp_pods" } @@ -2098,7 +2104,7 @@ nginx_br() { sed -i '/brotli_types/,+6 s/^\(\s*\)#\s*/\1/' /home/web/nginx.conf elif [ "$mode" == "off" ]; then - # Close Brotli: add comments + # 关闭 Brotli:加上注释 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|# load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2321,7 +2327,7 @@ web_security() { ;; 21) - send_stats "cloudflare mode" + send_stats "cloudflare模式" echo "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get the Global API Key" echo "https://dash.cloudflare.com/login" read -e -p "Enter CF’s account number:" cfuser @@ -2345,11 +2351,11 @@ web_security() { 22) send_stats "High load enables 5 seconds shield" - echo -e "${gl_huang}The website automatically detects every 5 minutes. When it detects high load, it will automatically open the shield, and when it detects low load, it will automatically close the shield for 5 seconds.${gl_bai}" + echo -e "${gl_huang}网站每5分钟自动检测,当达检测到高负载会自动开盾,低负载也会自动关闭5秒盾。${gl_bai}" echo "--------------" echo "Get CF parameters:" - echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and get${gl_huang}Global API Key${gl_bai}" - echo -e "Go to the bottom right of the cf backend domain name summary page to get it${gl_huang}Area ID${gl_bai}" + echo -e "Go to my profile in the upper right corner of the cf backend, select the API token on the left, and obtain${gl_huang}Global API Key${gl_bai}" + echo -e "到cf后台域名概要页面右下方获取${gl_huang}Area ID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "Enter CF’s account number:" cfuser @@ -2518,7 +2524,7 @@ web_optimization() { check_nginx_compression clear send_stats "Optimize LDNMP environment" - echo -e "Optimize LDNMP environment${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" + echo -e "优化LDNMP环境${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" echo "1. Standard mode 2. High performance mode (2H4G or above recommended)" echo "------------------------" @@ -2528,7 +2534,7 @@ web_optimization() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your choice:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "site standards mode" @@ -2653,7 +2659,7 @@ check_docker_image_update() { # --- Scenario A: Mirror on GitHub (ghcr.io) --- # Extract the warehouse path, for example ghcr.io/onexru/oneimg -> onexru/oneimg local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) - # Note: The API of ghcr.io is relatively complex. Usually the fastest way is to check the Release of GitHub Repo + # 注意:ghcr.io 的 API 比较复杂,通常最快的方法是查 GitHub Repo 的 Release local api_url="https://api.github.com/repos/$repo_path/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2714,56 +2720,50 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 - - # Get the IP address of the container - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi - - install iptables - + local container_ips - # Check and block all other IPs - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # Check and release the specified IP - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # Check and allow local network 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - - - # Check and block all other IPs - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # Check and release the specified IP - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - # Check and allow local network 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT + # Get the IPv4 addresses of the container in all Docker networks, applying rules one by one. + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "Error: Unable to get container${container_name_or_id}IPv4 address." >&2 + return 1 fi - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi + install iptables + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "IP+port has been blocked from accessing the service" save_iptables_rules @@ -2775,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # Get the IP address of the container - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # Get the IPv4 addresses of the containers in all Docker networks and clear the rules one by one. + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "Error: Unable to get container${container_name_or_id}IPv4 address." >&2 return 1 fi install iptables - - # Clear rules that block all other IPs - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # Clear the rules that allow specified IPs - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # Clear the rules that allow local network 127.0.0.0/8 - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # Clear rules that block all other IPs - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # Clear the rules that allow specified IPs - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # Clear the rules that allow local network 127.0.0.0/8 - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "IP+port has been allowed to access the service" save_iptables_rules @@ -2848,7 +2819,7 @@ block_host_port() { install iptables - # Deny access from all other IPs + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -2882,7 +2853,7 @@ block_host_port() { iptables -I INPUT -p udp --dport "$port" -s 127.0.0.0/8 -j ACCEPT fi - # Allow traffic for established and related connections + # 允许已建立和相关连接的流量 if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &>/dev/null; then iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT fi @@ -3091,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3104,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" @@ -4008,7 +3990,7 @@ ldnmp_install_status_one() { if docker inspect "php" &>/dev/null; then clear send_stats "Unable to install LDNMP environment again" - echo -e "${gl_huang}hint:${gl_bai}The website building environment has been installed. No need to install again!" + echo -e "${gl_huang}hint:${gl_bai}建站环境已安装。无需再次安装!" break_end linux_ldnmp fi @@ -4079,7 +4061,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "your$webnameIt's built!" + echo "您的 $webnameIt's built!" echo "https://$yuming" echo "------------------------" echo "$webnameThe installation information is as follows:" @@ -4111,7 +4093,7 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - kpanel_web_progress 10 "Verifying WordPress domain name with existing site" + kpanel_web_progress 10 "正在校验 WordPress 域名与现有站点" send_stats "Install$webname" echo "Start deployment$webname" if [ -z "$yuming" ]; then @@ -4122,7 +4104,7 @@ ldnmp_wp() { ldnmp_install_status - kpanel_web_progress 35 "Issuing and configuring site certificate" + kpanel_web_progress 35 "正在签发并配置站点证书" install_ssltls certs_status kpanel_web_progress 50 "Creating WordPress database and account" @@ -4168,7 +4150,7 @@ ldnmp_Proxy() { reverseproxy="${2:-}" port="${3:-}" - kpanel_web_progress 10 "Verifying reverse proxy domain name and upstream address" + kpanel_web_progress 10 "正在校验反向代理域名与上游地址" send_stats "Install$webname" echo "Start deployment$webname" if [ -z "$yuming" ]; then @@ -4531,7 +4513,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo "site directory" + echo "站点目录" echo "------------------------" echo -e "data${gl_hui}/home/web/html${gl_bai}Certificate${gl_hui}/home/web/certs${gl_bai}Configuration${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" @@ -4544,7 +4526,7 @@ ldnmp_web_status() { echo "7. Edit global configuration 8. Edit site configuration" echo "9. Manage site database 10. View site analysis reports" echo "------------------------" - echo "20. Delete specified site data" + echo "20. 删除指定站点数据" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -4646,7 +4628,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "View site data" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -4700,7 +4682,7 @@ while true; do panel_app_install add_app_id - send_stats "${panelname}Install" + send_stats "${panelname}安装" ;; 2) panel_app_manage @@ -4729,7 +4711,7 @@ done check_frp_app() { if [ -d "/home/frp/" ]; then - check_frp="${gl_lv}Installed${gl_bai}" + check_frp="${gl_lv}已安装${gl_bai}" else check_frp="${gl_hui}Not installed${gl_bai}" fi @@ -4800,7 +4782,7 @@ EOF configure_frpc() { send_stats "Install frp client" - read -e -p "Please enter the external network docking IP:" server_addr + read -e -p "请输入外网对接IP: " server_addr read -e -p "Please enter the external network docking token:" token echo @@ -5119,7 +5101,7 @@ frpc_panel() { echo -e "FRP client$check_frp $update_status" echo "Connect with the server. After the connection, you can create an intranet penetration service to access the Internet." echo "Official website introduction:${gh_https_url}github.com/fatedier/frp/" - echo "Video tutorial: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" + echo "视频教学: https://www.bilibili.com/video/BV1yMw6e2EwL?t=173.9" echo "------------------------" if [ -d "/home/frp/" ]; then [ -f /home/frp/frpc.toml ] || cp /home/frp/frp_0.61.0_linux_amd64/frpc.toml /home/frp/frpc.toml @@ -5210,7 +5192,7 @@ yt_menu_pro() { clear send_stats "yt-dlp download tool" echo -e "yt-dlp $YTDLP_STATUS" - echo -e "yt-dlp is a powerful video download tool that supports thousands of sites such as YouTube, Bilibili, Twitter, etc." + echo -e "yt-dlp 是一个功能强大的视频下载工具,支持 YouTube、Bilibili、Twitter 等数千站点。" echo -e "Official website address:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" echo "Downloaded video list:" @@ -5234,7 +5216,7 @@ yt_menu_pro() { chmod a+rx /usr/local/bin/yt-dlp add_app_id - echo "The installation is complete. Press any key to continue..." + echo "安装完成。按任意键继续..." read ;; 2) send_stats "Updating yt-dlp..." @@ -5581,7 +5563,7 @@ kpanel_dns_write_static() { if [ "$(cat "$target")"$'\n' = "$expected" ]; then chattr +i "$target" >/dev/null 2>&1 || { rm -f "$desired" "$backup" - echo "Error: Unable to lock DNS configuration" + echo "错误: 无法锁定 DNS 配置" return 1 } rm -f "$desired" "$backup" @@ -5606,7 +5588,7 @@ kpanel_dns_write_static() { [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" - echo "Error: DNS write failed and rollback failed, manual check required" + echo "Error: DNS write failed and rollback failed, manual inspection required" return 1 } rm -f "$desired" "$backup" @@ -5661,7 +5643,7 @@ kpanel_dns_write_systemd_resolved() { if [ "$existed" = "true" ]; then cp -p "$backup" "$config" || { rm -f "$desired" "$backup" - echo "Error: systemd-resolved DNS rollback failed, manual inspection required" + echo "错误: systemd-resolved DNS 回滚失败,需要人工检查" return 1 } else @@ -5839,6 +5821,82 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "Error: KPanel SSH port protocol must be run as root" + return 1 + } + [ "$#" -eq 1 ] || { + echo "Error: SSH port protocol requires a port number" + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "Error: SSH port must be 1-65535" + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "Error: No manageable OpenSSH configuration found" + return 1 + } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "Error: SSH configuration verification or listening check tool is not available" + return 1 + } + sshd -t || { + echo "Error: Current SSH configuration syntax verification failed" + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # Reuse existing SSH to modify the main business; the adaptation layer is only responsible for non-interactive verification and machine-readable results. + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "Error: Readback verification failed after SSH port modification" + return 1 + fi + if ! sshd -t; then + echo "Error: SSH configuration syntax verification failed" + return 1 + fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "Error: The new SSH port has not entered the listening state" + return 1 + } + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -5887,7 +5945,7 @@ import_sshkey() { local auth_keys="${ssh_dir}/authorized_keys" if [[ -z "$public_key" ]]; then - read -e -p "Please enter the contents of your SSH public key (usually starts with 'ssh-rsa' or 'ssh-ed25519'):" public_key + read -e -p "请输入您的SSH公钥内容(通常以 'ssh-rsa' 或 'ssh-ed25519' 开头): " public_key fi if [[ -z "$public_key" ]]; then @@ -5940,13 +5998,13 @@ fetch_remote_ssh_keys() { # Download public key if command -v curl >/dev/null 2>&1; then curl -fsSL --connect-timeout 10 "${keys_url}" -o "${temp_file}" || { - echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 + echo "Error: Unable to download public key from URL (network issue or invalid address)" >&2 rm -f "${temp_file}" return 1 } elif command -v wget >/dev/null 2>&1; then wget -q --timeout=10 -O "${temp_file}" "${keys_url}" || { - echo "Error: Unable to download public key from URL (network issue or invalid address)" >&2 + echo "错误:无法从 URL 下载公钥(网络问题或地址无效)" >&2 rm -f "${temp_file}" return 1 } @@ -5992,7 +6050,7 @@ fetch_remote_ssh_keys() { echo "successfully added${added}A new public key arrives${authorized_keys}" sshkey_on else - echo "No new public keys need to be added (all may already exist)" + echo "没有新的公钥需要添加(可能已全部存在)" fi echo "" @@ -6048,7 +6106,7 @@ sshkey_panel() { echo -e "User key login mode${IS_KEY_ENABLED}" echo "Advanced gameplay: https://blog.kejilion.pro/ssh-key" echo "------------------------------------------------" - echo "A key pair will be generated, a more secure way to log in via SSH" + echo "将会生成密钥对,更安全的方式SSH登录" echo "------------------------" echo "1. Generate a new key pair 2. Manually enter an existing public key" echo "3. Import the existing public key from GitHub 4. Import the existing public key from the URL" @@ -6069,7 +6127,7 @@ sshkey_panel() { break_end ;; 3) - send_stats "Import GitHub remote public key" + send_stats "导入GitHub远端公钥" fetch_github_ssh_keys break_end ;; @@ -6490,7 +6548,7 @@ dd_xitong() { ;; 47) - send_stats "Reinstall windows11 ARM" + send_stats "重装windows11 ARM" dd_xitong_4 bash reinstall.sh dd --img https://r2.hotdog.eu.org/win11-arm-with-pagefile-15g.xz reboot @@ -6643,12 +6701,12 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - + # Compatible with the old system codenames that have been officially removed (fall back to using releases to try the old package library) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi - + # Officially, apt support for jammy, focal, bullseye and other old systems has been completely removed. if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod has officially stopped supporting the current system ($os_codename), please upgrade to Debian12/Ubuntu24 or higher.${gl_bai}" @@ -6656,7 +6714,7 @@ bbrv3() { fi if [ -z "$os_codename" ]; then - echo "Unable to obtain system codename, unable to configure XanMod source" + echo "无法获取系统代号,无法配置XanMod源" return 1 fi @@ -6736,7 +6794,7 @@ bbrv3() { } package=$(xanmod_detect_package) || { - echo "The current CPU cannot be recognized or the matching kernel package cannot be found. The installation has been cancelled." + echo "The current CPU cannot be recognized or a matching kernel package cannot be found. The installation has been cancelled." return 1 } @@ -6748,7 +6806,7 @@ bbrv3() { } else apt install -y "$package" || { - echo "XanMod kernel installation failed, please check the software source or try again later" + echo "XanMod内核安装失败,请检查软件源或稍后重试" return 1 } fi @@ -6800,7 +6858,7 @@ bbrv3() { while true; do clear local kernel_version=$(uname -r) - echo "You have xanmod's BBRv3 kernel installed" + echo "您已安装xanmod的BBRv3内核" echo "Current kernel version:$kernel_version" echo "" @@ -6832,7 +6890,7 @@ bbrv3() { echo "Video introduction: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "Only supports Debian/Ubuntu" - echo "Please back up your data and we will upgrade your Linux kernel and enable BBR3." + echo "Please back up your data, we will upgrade your Linux kernel and enable BBR3" echo "------------------------------------------------" read -e -p "Are you sure you want to continue? (Y/N):" choice @@ -6841,7 +6899,7 @@ bbrv3() { xanmod_install_or_update install ;; [Nn]) - echo "Canceled" + echo "已取消" ;; *) echo "Invalid selection, please enter Y or N." @@ -6852,7 +6910,7 @@ bbrv3() { } elrepo_install() { - # Import the ELRepo GPG public key + # 导入 ELRepo GPG 公钥 echo "Import the ELRepo GPG public key..." rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org # Check system version @@ -6871,10 +6929,10 @@ elrepo_install() { echo "Installing the ELRepo repository configuration (version 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "Installing the ELRepo repository configuration (version 9)..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then - echo "Installing the ELRepo repository configuration (version 10)..." + echo "安装 ELRepo 仓库配置 (版本 10)..." yum -y install https://www.elrepo.org/elrepo-release-10.el10.elrepo.noarch.rpm else echo "Unsupported system versions:$os_version" @@ -6940,7 +6998,7 @@ elrepo() { echo "Video introduction: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" echo "Only supports Red Hat series distributions CentOS/RedHat/Alma/Rocky/oracle" - echo "Upgrading the Linux kernel can improve system performance and security. It is recommended to try it if possible, and upgrade the production environment with caution!" + echo "升级Linux内核可提升系统性能和安全,建议有条件的尝试,生产环境谨慎升级!" echo "------------------------------------------------" read -e -p "Are you sure you want to continue? (Y/N):" choice @@ -7035,7 +7093,7 @@ clamav() { read -e -p "Please enter your choice:" sub_choice case $sub_choice in 1) - send_stats "Full scan" + send_stats "全盘扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -7121,7 +7179,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; web) - # Website server: high concurrency priority + # 网站服务器:高并发优先 SWAPPINESS=10 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -7168,7 +7226,7 @@ _kernel_optimize_core() { ;; esac - # ── Adaptively adjust according to memory size ── + # ── 根据内存大小自适应调整 ── if [ "$MEM_MB" -ge 16384 ]; then MIN_FREE_KB=131072 [ "$scene" != "balanced" ] && SWAPPINESS=5 @@ -7294,7 +7352,7 @@ vm.vfs_cache_pressure = $VFS_PRESSURE kernel.sched_autogroup_enabled = $SCHED_AUTOGROUP $([ -f /proc/sys/kernel/numa_balancing ] && echo "kernel.numa_balancing = $NUMA" || echo "# numa_balancing not supported") -# ──Safety protection── +# ── 安全防护 ── net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 @@ -7356,7 +7414,7 @@ root hard nofile 1048576 LIMITS fi - # ── BBR persistence ── + # ── BBR 持久化 ── if [ "$CC" = "bbr" ]; then echo "tcp_bbr" > /etc/modules-load.d/bbr.conf 2>/dev/null # Clean up the bbr configuration in the old sysctl.conf (to avoid conflicts) @@ -7378,7 +7436,7 @@ optimize_balanced() { } optimize_web_server() { - _kernel_optimize_core "Website construction optimization mode" "web" + _kernel_optimize_core "网站搭建优化模式" "web" } # ── Restore default settings (complete clean) ── @@ -7446,7 +7504,7 @@ Kernel_optimize() { 1) cd ~ clear - local tiaoyou_moshi="High performance optimization mode" + local tiaoyou_moshi="高性能优化模式" optimize_high_performance send_stats "High performance mode optimization" ;; @@ -7460,18 +7518,18 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "Website optimization model" + send_stats "Website optimization mode" ;; 4) cd ~ clear _kernel_optimize_core "Live broadcast optimization mode" "stream" - send_stats "Live streaming optimization" + send_stats "直播推流优化" ;; 5) cd ~ clear - _kernel_optimize_core "Game server optimization mode" "game" + _kernel_optimize_core "游戏服优化模式" "game" send_stats "Game server optimization" ;; 6) @@ -7525,7 +7583,7 @@ update_locale() { install glibc-langpack-zh localectl set-locale LANG=${lang} echo "LANG=${lang}" | tee /etc/locale.conf - echo -e "${gl_lv}The system language has been modified to:$langReconnect to SSH to take effect.${gl_bai}" + echo -e "${gl_lv}系统语言已经修改为: $lang 重新连接SSH生效。${gl_bai}" hash -r break_end ;; @@ -7559,7 +7617,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "switch to english" + send_stats "切换到英文" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -7615,7 +7673,7 @@ shell_bianse() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Enter your selection:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -7660,7 +7718,7 @@ shell_bianse() { linux_trash() { root_use - send_stats "System Recycle Bin" + send_stats "系统回收站" local bashrc_profile="/root/.bashrc" local TRASH_DIR="$HOME/.local/share/Trash/files" @@ -7848,7 +7906,7 @@ linux_backup() { mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "System backup function" + send_stats "系统备份功能" echo "System backup function" echo "------------------------" list_backups @@ -7976,7 +8034,7 @@ kj_ssh_read_auth() { read -s -p "Please enter password:" password_or_key echo if [ -z "$password_or_key" ]; then - echo "Error: Password cannot be empty." + echo "错误: 密码不能为空。" return 1 fi KJ_SSH_AUTH_METHOD="password" @@ -8054,7 +8112,7 @@ add_connection() { echo "------------------------" read -e -p "Please enter a connection name:" name - kj_ssh_read_host_user_port "Please enter IP address:" "Please enter username (default: root):" "Please enter the port number (default: 22):" "root" "22" + kj_ssh_read_host_user_port "Please enter IP address:" "Please enter username (default: root):" "请输入端口号 (默认: 22): " "root" "22" if ! kj_ssh_read_auth "$KEY_DIR/$name.key"; then return fi @@ -8065,7 +8123,7 @@ add_connection() { -# Delete connection +# 删除连接 delete_connection() { send_stats "Delete connection" read -e -p "Please enter the connection number to be deleted:" num @@ -8113,7 +8171,7 @@ use_connection() { else # Connect using password if ! command -v sshpass &> /dev/null; then - echo "Error: sshpass is not installed, please install sshpass first." + echo "错误:未安装 sshpass,请先安装 sshpass。" echo "Installation method:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -8229,7 +8287,7 @@ mount_partition() { return 1 fi - echo "The partition was successfully mounted to$MOUNT_POINT" + echo "Partition successfully mounted to$MOUNT_POINT" # Check /etc/fstab to see if the UUID or mount point already exists if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8335,8 +8393,8 @@ check_partition() { return fi - # Check partition status - echo "Check partition /dev/$PARTITIONstatus:" + # 检查分区状态 + echo "Check partition /dev/$PARTITION 的状态:" fsck "/dev/$PARTITION" } @@ -8355,7 +8413,7 @@ disk_manager() { echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" - read -e -p "Please enter your choice:" choice + read -e -p "请输入你的选择: " choice case $choice in 1) mount_partition ;; 2) unmount_partition ;; @@ -8391,7 +8449,7 @@ add_task() { echo "---------------------------------" read -e -p "Please enter the task name:" name read -e -p "Please enter the local directory:" local_path - read -e -p "Please enter the remote directory:" remote_path + read -e -p "请输入远程目录: " remote_path while true; do read -e -p "Please enter remote user@IP:" remote @@ -8533,7 +8591,7 @@ run_task() { # Create a scheduled task schedule_task() { - send_stats "Add synchronization scheduled tasks" + send_stats "添加同步定时任务" read -e -p "Please enter the task number to be synchronized regularly:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then @@ -8542,9 +8600,9 @@ schedule_task() { fi echo "Please select the scheduled execution interval:" - echo "1) Execute once every hour" + echo "1) 每小时执行一次" echo "2) Execute once a day" - echo "3) Execute once a week" + echo "3) 每周执行一次" read -e -p "Please enter options (1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 @@ -8553,7 +8611,7 @@ schedule_task() { 1) cron_time="$random_minute * * * *" ;; # 每小时,随机分钟执行 2) cron_time="$random_minute 0 * * *" ;; # 每天,随机分钟执行 3) cron_time="$random_minute 0 * * 1" ;; # 每周,随机分钟执行 - *) echo "Error: Please enter valid options!" ; return ;; + *) echo "错误: 请输入有效的选项!" ; return ;; esac local cron_job="$cron_time k rsync_run $num" @@ -8570,7 +8628,7 @@ schedule_task() { echo "Scheduled task has been created:$cron_job" } -# View scheduled tasks +# 查看定时任务 view_tasks() { echo "Current scheduled tasks:" echo "---------------------------------" @@ -8588,7 +8646,7 @@ delete_task_schedule() { fi crontab -l | grep -v "k rsync_run $num" | crontab - - echo "Task number deleted$numscheduled tasks" + echo "Task number deleted$num 的定时任务" } @@ -8623,7 +8681,7 @@ rsync_manager() { 0) break ;; *) echo "Invalid selection, please try again." ;; esac - read -e -p "Press Enter to continue..." + read -e -p "按回车键继续..." done } @@ -8641,7 +8699,7 @@ linux_info() { clear echo -e "${gl_kjlan}Querying system information...${gl_bai}" - send_stats "System information query" + send_stats "系统信息查询" ip_address @@ -8693,7 +8751,7 @@ linux_info() { local udp_count=$(ss -u | wc -l) clear - echo -e "System information query" + echo -e "系统信息查询" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Hostname:${gl_bai}$hostname" echo -e "${gl_kjlan}System version:${gl_bai}$os_info" @@ -8704,9 +8762,9 @@ linux_info() { echo -e "${gl_kjlan}Number of CPU cores:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU frequency:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}CPU usage:${gl_bai}$cpu_usage_percent%" + echo -e "${gl_kjlan}CPU占用: ${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}System load:${gl_bai}$load" - echo -e "${gl_kjlan}Number of TCP|UDP connections:${gl_bai}$tcp_count|$udp_count" + echo -e "${gl_kjlan}TCP|UDP连接数: ${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}Physical memory:${gl_bai}$mem_info" echo -e "${gl_kjlan}Virtual memory:${gl_bai}$swap_info" echo -e "${gl_kjlan}Hard drive usage:${gl_bai}$disk_info" @@ -8716,7 +8774,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}Network algorithm:${gl_bai}$congestion_algorithm $queue_algorithm" echo -e "${gl_kjlan}-------------" - echo -e "${gl_kjlan}Operator:${gl_bai}$isp_info" + echo -e "${gl_kjlan}运营商: ${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then echo -e "${gl_kjlan}IPv4 address:${gl_bai}$ipv4_address" fi @@ -8742,7 +8800,7 @@ linux_tools() { while true; do clear # send_stats "Basic tools" - echo -e "basic tools" + echo -e "基础工具" tools=( curl wget sudo socat htop iftop unzip tar tmux ffmpeg @@ -8881,7 +8939,7 @@ linux_tools() { clear echo "The tool has been installed and is used as follows:" tar --help - send_stats "Install tar" + send_stats "安装tar" ;; 9) clear @@ -8889,7 +8947,7 @@ linux_tools() { clear echo "The tool has been installed and is used as follows:" tmux --help - send_stats "Install tmux" + send_stats "安装tmux" ;; 10) clear @@ -8961,7 +9019,7 @@ linux_tools() { clear git --help cd ~ - send_stats "Install git" + send_stats "安装git" ;; 18) @@ -8980,7 +9038,7 @@ linux_tools() { install cmatrix clear cmatrix - send_stats "Install cmatrix" + send_stats "安装cmatrix" ;; 22) clear @@ -9308,7 +9366,7 @@ docker_ssh_migration() { [[ -n "$p" ]] && PORT_ARGS="$PORT_ARGS -p $p" done - # environment variables + # 环境变量 ENV_ARGS="" mapfile -t ENVS < <(jq -r '.[0].Config.Env[]' "$json") for e in "${ENVS[@]}"; do @@ -9333,7 +9391,7 @@ docker_ssh_migration() { # Delete existing but not running containers if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}container [$container] exists but is not running, delete the old container...${gl_bai}" + echo -e "${gl_huang}容器 [$container] 存在但未运行,删除旧容器...${gl_bai}" docker rm -f "$container" fi @@ -9362,7 +9420,7 @@ docker_ssh_migration() { # migrate # ---------------------------- migrate_docker() { - send_stats "Docker migration" + send_stats "Docker迁移" install jq read -e -p "Please enter the backup directory to be migrated:" BACKUP_DIR [[ ! -d "$BACKUP_DIR" ]] && { echo -e "${gl_hong}The backup directory does not exist${gl_bai}"; return; } @@ -9408,7 +9466,7 @@ docker_ssh_migration() { echo "------------------------" echo -e "1. Back up docker project" echo -e "2. Migrate docker project" - echo -e "3. Restore docker project" + echo -e "3. 还原docker项目" echo -e "4. Delete the backup file of the docker project" echo "------------------------" echo -e "0. Return to the previous menu" @@ -9572,7 +9630,7 @@ linux_docker() { ;; 4) - send_stats "delete network" + send_stats "删除网络" read -e -p "Please enter the network name to be deleted:" dockernetwork docker network rm $dockernetwork ;; @@ -9591,7 +9649,7 @@ linux_docker() { echo "Docker volume list" docker volume ls echo "" - echo "Volume operations" + echo "卷操作" echo "------------------------" echo "1. Create a new volume" echo "2. Delete the specified volume" @@ -9609,7 +9667,7 @@ linux_docker() { ;; 2) - read -e -p "Enter the delete volume name (please separate multiple volume names with spaces):" dockerjuans + read -e -p "输入删除卷名(多个卷名请用空格分隔): " dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9722,6 +9780,382 @@ linux_docker() { +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel lightweight node installation requires root privileges." >&2 + return 1 + } + for command_name in curl sha256sum mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "Required command missing:${command_name}" >&2 + return 1 + } + done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "Missing required command: systemctl" >&2 + return 1 + } + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "Missing required command: install (coreutils)" >&2 + return 1 + } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "Missing system account creation tools: useradd, systemd-sysusers or adduser" >&2 + return 1 + fi + [ -d /run/systemd/system ] || { + echo "The current system is not running systemd and the KPanel lightweight node cannot be installed." >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "The current CPU architecture does not currently support KPanel lightweight nodes." >&2 + return 1 + ;; + esac +} + +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "The primary group of the existing kejilion-node account is not secure and continues is refused." >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "Missing system group creation tool: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel lightweight node low-privilege account creation failed." >&2 + return 1 + } +} + +kpanel_node_write_updater() { + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null +} + +kpanel_node_join() { + local token="${1:-}" node_name resume_enrollment=false + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "The lightweight node access authorization is invalid." >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "轻量节点接入授权无效。" >&2 + return 2 + } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "Completed node authorization detected, continue enabling native services." + else + echo "There is incomplete KPanel node configuration on this machine; please execute k kpanel node uninstall first." >&2 + return 1 + fi + fi + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join + return 1 + fi + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + echo "The node authorization has been saved, but the configuration permission repair failed; execute the access command again to continue." >&2 + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + echo "The node authorization has been saved, but writing to the systemd unit failed; execute the access command again to continue." >&2 + return 1 + fi + if ! kpanel_node_activate; then + echo "KPanel lightweight node authorization has been saved, but the service failed to start; repair systemd and execute the access command again to continue the installation." >&2 + return 1 + fi + echo "KPanel lightweight node has been connected and will be updated automatically later." +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel lightweight node is not installed." >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel lightweight node is not installed." >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "Uninstalling KPanel lightweight nodes requires root privileges." >&2 + return 1 + } + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true + echo "The KPanel lightweight node has been uninstalled from the local machine; the offline records of the center need to be deleted on the cluster page." +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "Usage: k kpanel node join | status | update | uninstall" >&2 + return 2 + ;; + esac +} + kpanel_test_catalog() { cat <<'KPANEL_TEST_CATALOG' KPANEL_TEST_CATEGORY access IP 与解锁 @@ -9843,12 +10277,12 @@ kpanel_run_test_noninteractive() { kpanel_run_remote_bash https://raw.githubusercontent.com/ibsgss/TcpQuality/main/runTcpQuality.sh ;; yabs) - send_stats "yabs performance test" + send_stats "yabs性能测试" check_swap kpanel_run_remote_bash https://yabs.sh -i -5 ;; cpu) - send_stats "icu/gb5 CPU performance test script" + send_stats "icu/gb5 CPU性能测试脚本" check_swap kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh ;; @@ -9904,7 +10338,7 @@ linux_test() { echo -e "Test script collection" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}IP and unlock status detection" - echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT unlock status detection" + echo -e "${gl_kjlan}1. ${gl_bai}ChatGPT 解锁状态检测" echo -e "${gl_kjlan}2. ${gl_bai}Region streaming media unlock test" echo -e "${gl_kjlan}3. ${gl_bai}yeahwu streaming media unlock detection" echo -e "${gl_kjlan}4. ${gl_bai}xykt IP quality check script${gl_huang}★${gl_bai}" @@ -9915,20 +10349,20 @@ linux_test() { echo -e "${gl_kjlan}12. ${gl_bai}mtr_trace triple network backhaul line test" echo -e "${gl_kjlan}13. ${gl_bai}Superspeed triple network speed test" echo -e "${gl_kjlan}14. ${gl_bai}nxtrace fast backhaul test script" - echo -e "${gl_kjlan}15. ${gl_bai}nxtrace specifies IP backhaul test script" + echo -e "${gl_kjlan}15. ${gl_bai}nxtrace 指定IP回程测试脚本" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 three network line test" echo -e "${gl_kjlan}17. ${gl_bai}i-abc multi-function speed test script" echo -e "${gl_kjlan}18. ${gl_bai}NetQuality network quality check script${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP retransmission detection script${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP重传探测脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Hardware performance testing" + echo -e "${gl_kjlan}硬件性能测试" echo -e "${gl_kjlan}21. ${gl_bai}yabs performance test" echo -e "${gl_kjlan}22. ${gl_bai}icu/gb5 CPU performance test script" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}Comprehensive testing" - echo -e "${gl_kjlan}31. ${gl_bai}bench performance test" + echo -e "${gl_kjlan}综合性测试" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" echo -e "${gl_kjlan}32. ${gl_bai}spiritysdx fusion monster evaluation${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}nodequality fusion monster evaluation${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9944,7 +10378,7 @@ linux_test() { ;; 2) clear - send_stats "Region streaming media unlock test" + send_stats "Region流媒体解锁测试" bash <(curl -L -s check.unlock.media) ;; 3) @@ -9988,7 +10422,7 @@ linux_test() { echo "Reference IP list" echo "------------------------" echo "Beijing Telecom: 219.141.136.12" - echo "Beijing Unicom: 202.106.50.1" + echo "北京联通: 202.106.50.1" echo "Beijing Mobile: 221.179.155.161" echo "Shanghai Telecom: 202.96.209.133" echo "Shanghai Unicom: 210.22.97.1" @@ -9998,7 +10432,7 @@ linux_test() { echo "Guangzhou Mobile: 120.196.165.24" echo "Chengdu Telecom: 61.139.2.69" echo "Chengdu China Unicom: 119.6.6.6" - echo "Chengdu Mobile: 211.137.96.205" + echo "成都移动: 211.137.96.205" echo "Hunan Telecom: 36.111.200.100" echo "Hunan Unicom: 42.48.16.100" echo "Hunan Mobile: 39.134.254.6" @@ -10011,7 +10445,7 @@ linux_test() { 16) clear - send_stats "ludashi2020 three network line test" + send_stats "ludashi2020三网线路测试" curl ${gh_proxy}raw.githubusercontent.com/ludashi2020/backtrace/main/install.sh -sSf | sh ;; @@ -10086,7 +10520,7 @@ linux_Oracle() { while true; do clear - send_stats "Oracle Cloud Script Collection" + send_stats "甲骨文云脚本合集" echo -e "Oracle Cloud Script Collection" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Install idle machine active script" @@ -10434,7 +10868,7 @@ ldnmp_environment_status() { } ldnmp_environment_catalog() { - printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"Full LDNMP"},{"id":"nginx","label":"Only Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudfl are-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on ","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"] },{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' + printf '%s\n' '{"protocolVersion":"1","installProfiles":[{"id":"full","label":"完整 LDNMP"},{"id":"nginx","label":"仅 Nginx"}],"protectionActions":["fail2ban-install","fail2ban-uninstall","unban-all","waf-on","waf-off","ddos-on","ddos-off","cloudflare-fail2ban","cloudflare-shield"],"optimizationActions":["standard","high","gzip-on","gzip-off","brotli-on","brotli-off","zstd-on","zstd-off"],"updateComponents":[{"id":"nginx","versions":["latest"]},{"id":"mysql","versions":["latest","8.0","8.3","8.4","9.0"]},{"id":"php","versions":["7.4","8.0","8.1","8.2","8.3"]},{"id":"redis","versions":["latest"]},{"id":"all","versions":["latest"]}]}' } ldnmp_environment_install() { @@ -10648,7 +11082,7 @@ ldnmp_update_action() { cd /home/web || return 1 docker compose pull && docker compose up -d --force-recreate || return 86 ;; - *) echo "Unsupported update component" >&2; return 2 ;; + *) echo "不支持的更新组件" >&2; return 2 ;; esac } @@ -10763,7 +11197,7 @@ kpanel_ldnmp_run() { rc=0 else rc=$? - kpanel_ldnmp_event failed 100 "LDNMP environment task execution failed" + kpanel_ldnmp_event failed 100 "LDNMP 环境任务执行失败" if [ "$rc" -eq 86 ]; then kpanel_ldnmp_result needs_attention "$action" "The task failed and safe rollback could not be confirmed, requiring manual processing." else @@ -10862,7 +11296,7 @@ linux_ldnmp() { echo -e "${gl_huang}LDNMP website building" ldnmp_tato echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}1. ${gl_bai}Install LDNMP environment${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" + echo -e "${gl_huang}1. ${gl_bai}安装LDNMP环境 ${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}Install WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Install Discuz Forum${gl_huang}4. ${gl_bai}Install Kedao Cloud Desktop" echo -e "${gl_huang}5. ${gl_bai}Install Apple CMS Movie and TV Station${gl_huang}6. ${gl_bai}Install Unicorn Digital Card Network" echo -e "${gl_huang}7. ${gl_bai}Install flarum forum website${gl_huang}8. ${gl_bai}Install typecho lightweight blog website" @@ -10872,7 +11306,7 @@ linux_ldnmp() { echo -e "${gl_huang}23. ${gl_bai}Site reverse proxy-IP+port${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}Site reverse proxy-domain name" echo -e "${gl_huang}25. ${gl_bai}Install Bitwarden Password Management Platform${gl_huang}26. ${gl_bai}Install Halo Blog Site" echo -e "${gl_huang}27. ${gl_bai}Install the AI ​​painting prompt word generator${gl_huang}28. ${gl_bai}Site reverse proxy-load balancing" - echo -e "${gl_huang}29. ${gl_bai}Stream four-layer proxy forwarding${gl_huang}30. ${gl_bai}Custom static site" + echo -e "${gl_huang}29. ${gl_bai}Stream four-layer proxy forwarding${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}Site data management${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}Back up site-wide data" echo -e "${gl_huang}33. ${gl_bai}Scheduled remote backup${gl_huang}34. ${gl_bai}Restore whole site data" @@ -10899,13 +11333,13 @@ linux_ldnmp() { fi if [ -e "/home/web/conf.d/${KJ_WEB_DOMAIN}.conf" ] || [ -e "/home/web/html/${KJ_WEB_DOMAIN}" ]; then - echo "KPANEL_PROGRESS 100 The domain name already exists, refusing to overwrite existing products" + echo "KPANEL_PROGRESS 100 域名已存在,拒绝覆盖现有产物" return 1 fi if [ "$sub_choice" = "23" ]; then if [ -z "${KJ_WEB_PROXY_HOST:-}" ] || ! printf '%s' "$KJ_WEB_PROXY_HOST" | grep -Eq '^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$'; then - echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST is not a valid IP or hostname" + echo "KPANEL_PROGRESS 100 KJ_WEB_PROXY_HOST 不是有效的 IP 或主机名" return 1 fi if ! printf '%s' "${KJ_WEB_PROXY_PORT:-}" | grep -Eq '^[0-9]{1,5}$' || @@ -11068,7 +11502,7 @@ linux_ldnmp() { clear # One-legged number card webname="One-legged number card" - send_stats "Install$webname" + send_stats "安装$webname" echo "Start deployment$webname" add_yuming repeat_add_yuming @@ -11114,7 +11548,7 @@ linux_ldnmp() { echo "Password: admin" echo "------------------------" echo "If a red error0 appears in the upper right corner when logging in, please use the following command:" - echo "I am also very angry about why the Unicorn Number Card is so troublesome and has such problems!" + echo "我也很气愤独角数卡为啥这么麻烦,会有这样的问题!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" ;; @@ -11177,7 +11611,7 @@ linux_ldnmp() { echo "username:$dbuse" echo "password:$dbusepasswd" echo "Table prefix: flarum_" - echo "Administrator information can be set by oneself" + echo "管理员信息自行设置" ;; @@ -11272,7 +11706,7 @@ linux_ldnmp() { clear webname="PHP dynamic site" send_stats "Install$webname" - echo "Start deployment$webname" + echo "开始部署 $webname" add_yuming repeat_add_yuming ldnmp_install_status @@ -11356,7 +11790,7 @@ linux_ldnmp() { clear - echo -e "[${gl_huang}6/6${gl_bai}] Database management" + echo -e "[${gl_huang}6/6${gl_bai}] 数据库管理" echo "-------------" read -e -p "1. I build a new site 2. I build an old site and have a database backup:" use_db case $use_db in @@ -11375,7 +11809,7 @@ linux_ldnmp() { latest_sql=$(ls -t *.sql | head -n 1) dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec -i mysql mysql -u root -p"$dbrootpasswd" $dbname < "/home/$latest_sql" - echo "Database imported table data" + echo "数据库导入的表数据" docker exec -i mysql mysql -u root -p"$dbrootpasswd" -e "USE $dbname; SHOW TABLES;" rm -f *.sql echo "Database import completed" @@ -11392,7 +11826,7 @@ linux_ldnmp() { ldnmp_web_on prefix="web$(shuf -i 10-99 -n 1)_" echo "Database address: mysql" - echo "Database name:$dbname" + echo "数据库名: $dbname" echo "username:$dbuse" echo "password:$dbusepasswd" echo "Table prefix:$prefix" @@ -11408,7 +11842,7 @@ linux_ldnmp() { 22) clear - webname="site redirect" + webname="站点重定向" send_stats "Install$webname" echo "Start deployment$webname" add_yuming @@ -11618,7 +12052,7 @@ linux_ldnmp() { 32) clear - send_stats "LDNMP environment backup" + send_stats "LDNMP环境备份" local backup_filename="web_$(date +"%Y%m%d%H%M%S").tar.gz" echo -e "${gl_kjlan}Backing up$backup_filename ...${gl_bai}" @@ -11630,7 +12064,7 @@ linux_ldnmp() { read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) - kj_ssh_read_host_port "Please enter the remote server IP:" "Target server SSH port [default 22]:" "22" + kj_ssh_read_host_port "请输入远端服务器IP: " "目标服务器SSH端口 [默认22]: " "22" local remote_ip="$KJ_SSH_HOST" local TARGET_PORT="$KJ_SSH_PORT" local latest_tar=$(ls -t /home/*.tar.gz | head -1) @@ -11648,7 +12082,7 @@ linux_ldnmp() { break ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac done @@ -11693,7 +12127,7 @@ linux_ldnmp() { 34) root_use - send_stats "LDNMP environment restoration" + send_stats "LDNMP环境还原" echo "Available site backups" echo "-------------------------" ls -lt /home/*.gz | awk '{print $NF}' @@ -11767,7 +12201,7 @@ linux_ldnmp() { echo echo "1. Update nginx 2. Update mysql 3. Update php 4. Update redis" echo "------------------------" - echo "5. Update the complete environment" + echo "5. 更新完整环境" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -11842,7 +12276,7 @@ linux_ldnmp() { docker compose up -d --force-recreate $ldnmp_pods docker restart $ldnmp_pods > /dev/null 2>&1 send_stats "renew$ldnmp_pods" - echo "renew${ldnmp_pods}Finish" + echo "renew${ldnmp_pods}完成" ;; 5) @@ -11888,7 +12322,7 @@ linux_ldnmp() { ;; *) - echo "Invalid selection, please enter Y or N." + echo "无效的选择,请输入 Y 或 N。" ;; esac ;; @@ -11938,7 +12372,7 @@ moltbot_menu() { return 1 fi - # Add --no-update-notifier and make sure error redirects are in the correct location + # Add --no-update-notifier and make sure error redirection is in the correct location local_version=$(npm list -g openclaw --depth=0 --no-update-notifier 2>/dev/null | grep openclaw | awk '{print $NF}' | sed 's/^.*@//') if [ -z "$local_version" ]; then @@ -11952,7 +12386,7 @@ moltbot_menu() { fi if [ "$local_version" != "$remote_version" ]; then - echo "${gl_huang}New version detected:$remote_version${gl_bai}" + echo "${gl_huang}检测到新版本:$remote_version${gl_bai}" else echo "${gl_lv}The current version is the latest:$local_version${gl_bai}" fi @@ -12278,7 +12712,7 @@ for name, provider in list(providers.items()): summary.append(f'✅ {name}: The user has confirmed to delete the provider and all related model references') else: send_stat('OpenClaw API deletion failed Provider-rejected') - summary.append(f'ℹ️ {name}: The user has not confirmed the deletion and retains the existing provider configuration.') + summary.append(f'ℹ️ {name}: 用户未确认删除,保留现有 provider 配置') continue if attempts > 1: @@ -12428,7 +12862,7 @@ PY stop_bot() { echo "Stop OpenClaw..." - send_stats "Stop OpenClaw..." + send_stats "停止 OpenClaw..." tmux kill-session -t gateway > /dev/null 2>&1 openclaw gateway stop break_end @@ -12559,14 +12993,14 @@ EOF local base_url="$2" local api_key="$3" - echo "🔍 Getting$provider_nameAll available models of..." + echo "🔍 正在获取 $provider_nameAll available models of..." local models_json=$(curl -s -m 10 \ -H "Authorization: Bearer $api_key" \ "${base_url}/models") if [[ -z "$models_json" ]]; then - echo "❌ Unable to obtain model list" + echo "❌ 无法获取模型列表" return 1 fi @@ -12578,7 +13012,7 @@ EOF fi local model_count=$(echo "$model_ids" | wc -l) - echo "✅ Discover$model_countmodels" + echo "✅ Discover$model_count 个模型" local models_array models_array=$(build-openclaw-provider-models-json "$provider_name" "$model_ids") @@ -12650,7 +13084,7 @@ EOF echo done - # 4. No longer detecting/judging API types; protocols are selected and maintained by users themselves + # 4. No longer detecting/determining API types; protocols are selected and maintained by users themselves # 5. Get model list echo "🔍 Getting list of available models..." @@ -12992,7 +13426,7 @@ local_set = set(local_ids) template = copy.deepcopy(local_models[0]) if local_models else None if template is None: - print(f'❌ {target}: Local models do not have a valid template model, and new models cannot be added.') + print(f'❌ {target}: 本地 models 无有效模板模型,无法补全新增模型') raise SystemExit(3) removed_ids = [mid for mid in local_ids if mid not in remote_set] @@ -13076,7 +13510,7 @@ PY2 echo "❌ Synchronization failed: provider does not exist or is not configured" ;; 3) - echo "❌ Synchronization failed: provider configuration is incomplete or type is not supported" + echo "❌ 同步失败:provider 配置不完整或类型不支持" ;; 4) echo "❌ Synchronization failed: Upstream /models request failed" @@ -13116,7 +13550,7 @@ fix-openclaw-provider-protocol-interactive() { return 1 fi - echo "Please select the API type you want to set up:" + echo "请选择要设置的 API 类型:" echo "1. openai-completions" echo "2. openai-responses" read -erp "Please enter your choice (1/2):" proto_choice @@ -13174,7 +13608,7 @@ PY echo "❌ Switching failed: provider does not exist or is not configured" ;; 3) - echo "❌ Switching failed: protocol value is illegal" + echo "❌ 切换失败:协议值非法" ;; *) echo "❌ Switching failed: please check the configuration file structure or log output" @@ -13198,7 +13632,7 @@ PY read -erp "Please enter the API name (provider) to be deleted:" provider_name if [ -z "$provider_name" ]; then send_stats "OpenClaw API Delete Cancel" - echo "❌ provider name cannot be empty" + echo "❌ provider 名称不能为空" break_end return 1 fi @@ -13340,8 +13774,8 @@ PY clear echo "" echo -e "${gl_kjlan}╔════════════════════════════════════════════════════════════╗${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API vendor recommendation list${gl_bai} ${gl_kjlan}║${gl_bai}" - echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}Some entrances contain AFF${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_huang}🌟 API 厂商推荐列表${gl_bai} ${gl_kjlan}║${gl_bai}" + echo -e "${gl_kjlan}║${gl_bai} ${gl_zi}部分入口含 AFF${gl_bai} ${gl_kjlan}║${gl_bai}" echo -e "${gl_kjlan}╚════════════════════════════════════════════════════════════╝${gl_bai}" echo "" echo -e " ${gl_lv}● DeepSeek${gl_bai}" @@ -13404,7 +13838,7 @@ PY openclaw_api_manage_list echo "---------------------------------------" echo "1. Add API" - echo "2. Synchronize API provider model list" + echo "2. 同步API供应商模型列表" echo "3. Switch API type (completions/responses)" echo "4. Delete API" echo "5. Recommended by API vendors" @@ -13798,7 +14232,7 @@ PYTHON_EOF continue fi - echo "The model being switched is:$selected_model ..." + echo "正在切换模型为: $selected_model ..." if ! openclaw models set "$selected_model"; then echo "Switch failed: openclaw models set returned error." break_end @@ -14064,7 +14498,7 @@ PYTHON_EOF echo "1) Install/enable plugin" echo "2) Delete/disable plugins" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" plugin_action [ "$plugin_action" = "0" ] && break @@ -14150,7 +14584,7 @@ PYTHON_EOF echo "====== Operation Summary ======" echo "✅ Success:$success_list" [ -n "$failed_list" ] && echo "❌ Failure:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ Skip:$skipped_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" if [ "$changed" = true ]; then echo "🔄 Restarting OpenClaw service to load changes..." @@ -14175,8 +14609,8 @@ PYTHON_EOF # Output a list of recommended practical skills echo "Recommended practical skills (you can directly copy the name and enter it):" echo "github # Manage GitHub Issues/PR/CI (gh CLI)" - echo "notion # 操作 Notion 页面、数据库和块" - echo "apple-notes # macOS 原生笔记管理 (创建/编辑/搜索)" + echo "notion # Manipulate Notion pages, databases and blocks" + echo "apple-notes # macOS native note management (create/edit/search)" echo "apple-reminders # macOS reminder management (to-do list)" echo "1password # Automate reading and injecting 1Password keys" echo "gog # Google Workspace (Gmail/cloud disk/documents) all-round assistant" @@ -14186,13 +14620,13 @@ PYTHON_EOF echo "summarize # One-click summary of webpage/podcast/YouTube video content" echo "openhue # Control Philips Hue smart lighting scenes" echo "video-frames # Video frame extraction and short clip editing (ffmpeg driver)" - echo "openai-whisper # Convert local audio to text (offline privacy protection)" + echo "openai-whisper # 本地音频转文字 (离线隐私保护)" echo "coding-agent # Automatically run programming assistants such as Claude Code/Codex" echo "----------------------------------------" echo "1) Installation skills" echo "2) Delete skills" - echo "0) Return" + echo "0) return" read -e -p "Please select an action:" skill_action [ "$skill_action" = "0" ] && break @@ -14240,7 +14674,7 @@ PYTHON_EOF fi fi - echo "Installing skills:$skill_name ..." + echo "正在安装技能:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then echo "✅ Skills$skill_nameInstallation successful." success_list="$success_list $skill_name" @@ -14267,7 +14701,7 @@ PYTHON_EOF echo "" echo "====== Operation Summary ======" echo "✅ Success:$success_list" - [ -n "$failed_list" ] && echo "❌ Failure:$failed_list" + [ -n "$failed_list" ] && echo "❌ 失败:$failed_list" [ -n "$skipped_list" ] && echo "⏭️ Skip:$skipped_list" if [ "$changed" = true ]; then @@ -14511,7 +14945,7 @@ openclaw_json_get_bool() { echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" - echo "1. Telegram robot docking" + echo "1. Telegram 机器人对接" echo "2. Feishu (Lark) robot docking" echo "3. WhatsApp bot docking" echo "4. QQ robot docking" @@ -14525,7 +14959,7 @@ openclaw_json_get_bool() { 1) read -e -p "Please enter the connection code received by the TG robot (for example, NYA99R2F) (enter 0 to exit):" code if [ "$code" = "0" ]; then continue; fi - if [ -z "$code" ]; then echo "Error: Connection code cannot be empty."; sleep 1; continue; fi + if [ -z "$code" ]; then echo "错误:连接码不能为空。"; sleep 1; continue; fi openclaw pairing approve telegram "$code" break_end ;; @@ -14654,7 +15088,7 @@ EOF local file_path="$1" echo "Backup files can be downloaded using the following methods:" - echo "- Local path:$file_path" + echo "- 本地路径: $file_path" echo "- scp example: scp root@yourserver:$file_path ./" echo "- Or download using SFTP client" } @@ -14949,7 +15383,7 @@ if os.path.isdir(agents_root): for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "memory backup file" ] && continue + [ "$file_type" != "记忆备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -15208,7 +15642,7 @@ PY store_file=$(openclaw_memory_expand_path "$store_raw") if [ -z "$store_file" ] || [ ! -f "$store_file" ]; then echo "⚠️ [$agent_id] Index library file not found, may be empty or non-existent." - echo "Store raw value: ${store_raw:-}" + echo " Store 原始值: ${store_raw:-<空>}" echo "Reindexing will still be performed." else ts=$(date +%Y%m%d_%H%M%S) @@ -15269,7 +15703,7 @@ EOF local count=0 local agent_lines agent_id workspace agent_lines=$(openclaw_memory_list_agents) - echo "Check and prepare $(printf '%s\n'"$agent_lines"| sed '/^\s*$/d' | wc -l | tr -d ' ') agent workspace" + echo "检查并准备 $(printf '%s\n' "$agent_lines"| sed '/^\s*$/d' | wc -l | tr -d ' ') agent workspace" while IFS=$'\t' read -r agent_id workspace; do [ -z "$agent_id" ] && continue openclaw_memory_prepare_workspace "$agent_id" @@ -15414,21 +15848,21 @@ PY OPENCLAW_MEMORY_RECOMMEND_REASON+=("QMD not detected") fi if [ -n "$model_path" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model path:$model_path") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("本地模型路径: $model_path") else OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model path not configured") fi case "$model_status" in ok) OPENCLAW_MEMORY_RECOMMEND_REASON+=("Local model file exists") ;; - hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("Model comes from HF download source (may be slow/failed in China)") ;; + hf) OPENCLAW_MEMORY_RECOMMEND_REASON+=("模型来自 HF 下载源(国内可能慢/失败)") ;; *) OPENCLAW_MEMORY_RECOMMEND_REASON+=("The local model file does not exist or is unavailable") ;; esac if [ "$hf_ok" = "ok" ]; then - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co is accessible") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co 可访问") elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com can be accessed") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com may not be reachable (suspected domestic/restricted network)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("huggingface.co / hf-mirror.com may be unreachable (suspected domestic/restricted network)") fi if [ "$qmd_ok" = "true" ]; then @@ -15569,7 +16003,7 @@ PY return 1 fi if ! qmd --version >/dev/null 2>&1; then - echo "❌ qmd still cannot run after installation" + echo "❌ qmd 安装后仍无法运行" return 1 fi OPENCLAW_MEMORY_QMD_PATH="$qmd_path" @@ -15585,9 +16019,9 @@ PY echo "Mode: Write configuration only (not installed/not downloaded)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "Index: Executed" + echo "索引: 已执行" else - echo "Index: skipped" + echo "索引: 已跳过" fi if [ "$OPENCLAW_MEMORY_RESTARTED" = "true" ]; then echo "Restart: executed" @@ -15601,7 +16035,7 @@ PY echo "Model:$OPENCLAW_MEMORY_MODEL_PATH" fi if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then - echo "area:$OPENCLAW_MEMORY_COUNTRY" + echo "地区: $OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then echo "Download source:$OPENCLAW_MEMORY_HF_BASE" @@ -15630,7 +16064,7 @@ PY echo "Possible traffic/disk usage: Depends on actual situation" fi echo "After confirmation, it will automatically install/download, write configuration, build index and restart the gateway." - echo "Advanced options: Enter config to write configuration only (no installation, no download, no indexing, no restart)" + echo "高级选项: 输入 config 仅写配置(不安装不下载、不索引、不重启)" read -e -p "Enter yes to confirm to continue (default N):" confirm_step case "$confirm_step" in yes|YES) @@ -15696,7 +16130,7 @@ EOF else echo "⏭️ Preheat skipped" fi - echo "✅ QMD automatic deployment completed" + echo "✅ QMD 自动部署完成" } openclaw_memory_auto_setup_local() { @@ -15824,7 +16258,7 @@ EOF echo "1. QMD" echo "2. Local" echo "3. Auto (automatic selection)" - echo "0. Return to the previous level" + echo "0. 返回上一级" echo "---------------------------------------" read -e -p "Please enter your choice:" auto_choice case "$auto_choice" in @@ -15949,7 +16383,7 @@ EOF case "$backend" in qmd) current_label="QMD" ;; builtin|local) current_label="Local" ;; - *) current_label="Not configured" ;; + *) current_label="未配置" ;; esac echo "Current plan:$current_label" echo "" @@ -16061,7 +16495,7 @@ EOF start_line=1 fi if [ "$count" -le 0 ]; then - echo "❌ Number of rows must be greater than 0." + echo "❌ The number of rows must be greater than 0." return 1 fi local end_line=$((start_line + count - 1)) @@ -16106,7 +16540,7 @@ EOF continue fi openclaw_memory_view_file "${OPENCLAW_MEMORY_FILES[$idx]}" - read -p "Press Enter to return to the list..." + read -p "按回车返回列表..." done } @@ -16259,7 +16693,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ OpenClaw is not detected and OpenClaw Gateway cannot be restarted." + echo "❌ openclaw is not detected and OpenClaw Gateway cannot be restarted." return 1 fi echo "Restarting OpenClaw Gateway..." @@ -16664,7 +17098,7 @@ except Exception as e: while true; do clear echo "=======================================" - echo "OpenClaw permission management (dual-layer architecture deep adaptation)" + echo " OpenClaw 权限管理 (双层架构深度适配)" echo "=======================================" openclaw_permission_render_status echo "---------------------------------------" @@ -16672,7 +17106,7 @@ except Exception as e: echo -e "${gl_kjlan}2.${gl_bai}Switch to development enhancement mode (allowing agents to apply for privilege escalation)" echo -e "${gl_kjlan}3.${gl_bai}Switch to fully open mode (${gl_hong}High risk! Completely remove all host interceptions${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}Restore the official default sandbox defense strategy" - echo -e "${gl_kjlan}5.${gl_bai}Run underlying security audits and automatic repairs" + echo -e "${gl_kjlan}5.${gl_bai} 运行底层安全审计与自动修复" echo -e "${gl_kjlan}6.${gl_bai}Manage Exec command whitelist" echo -e "${gl_kjlan}0.${gl_bai}Return to previous level" echo "---------------------------------------" @@ -16896,7 +17330,7 @@ PY local config_file default_agent config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) - echo "Configuration file: ${config_file:-$(openclaw_permission_config_file)}" + echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" echo "Default agent:$default_agent" python3 -c ' import json,sys @@ -16942,18 +17376,18 @@ for idx,item in enumerate(agents,1): local agent_id workspace confirm read -e -p "Please enter new Agent ID:" agent_id [ -z "$agent_id" ] && echo "Canceled: Agent ID cannot be empty." && return 1 - read -e -p "Please enter the workspace path (default ~/.openclaw/workspace-${agent_id}): " workspace + read -e -p "请输入 workspace 路径(默认 ~/.openclaw/workspace-${agent_id}): " workspace [ -z "$workspace" ] && workspace="~/.openclaw/workspace-${agent_id}" echo "The agent will be created:$agent_id" echo "Working directory:$workspace" read -e -p "Enter yes to confirm to continue:" confirm - [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents add "$agent_id" --workspace "$workspace"; then - echo "✅ The agent was created successfully:$agent_id" + echo "✅ 智能体创建成功: $agent_id" local name theme - read -e -p "Please enter the agent identity name (e.g.: Code Expert):" name + read -e -p "请输入智能体身份名称 (如: 代码专家): " name [ -z "$name" ] && name="$agent_id" - read -e -p "Please enter the agent personality theme (for example: rigorous, efficient):" theme + read -e -p "Please enter the agent personality theme (eg: rigorous, efficient):" theme [ -z "$theme" ] && theme="assistant" echo "Configuring agent identity..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" @@ -16967,7 +17401,7 @@ for idx,item in enumerate(agents,1): send_stats "OpenClaw multi-agent-delete agent" openclaw_multiagent_require_openclaw || return 1 local agent_id confirm - read -e -p "Please enter the Agent ID to delete:" agent_id + read -e -p "请输入要删除的 Agent ID: " agent_id [ -z "$agent_id" ] && echo "Canceled: Agent ID cannot be empty." && return 1 echo "⚠️ Deleting an agent may affect its working directory, route bindings, and session routing." read -e -p "Enter DELETE to confirm deletion${agent_id}: " confirm @@ -17021,7 +17455,7 @@ for idx,item in enumerate(bindings,1): { [ -z "$agent_id" ] || [ -z "$bind_value" ]; } && echo "Canceled: Parameter cannot be empty." && return 1 echo "will remove the agent [$agent_id] route binding [$bind_value]" read -e -p "Enter yes to confirm to continue:" confirm - [ "$confirm" = "yes" ] || { echo "Canceled"; return 1; } + [ "$confirm" = "yes" ] || { echo "已取消"; return 1; } if openclaw agents unbind --agent "$agent_id" --bind "$bind_value"; then echo "✅ Route binding removed successfully" else @@ -17108,7 +17542,7 @@ print("✅Multi-agent health check completed") local cmd="openclaw agents set-identity --agent $agent_id" [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" - echo "Identity information can also be automatically read from IDENTITY.md." + echo "Identity information can also be read automatically from IDENTITY.md." read -e -p "Read from IDENTITY.md? (y/n):" from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" @@ -17125,7 +17559,7 @@ print("✅Multi-agent health check completed") } openclaw_multiagent_menu() { - send_stats "OpenClaw multi-agent management" + send_stats "OpenClaw多智能体管理" while true; do clear echo "=======================================" @@ -17134,14 +17568,14 @@ print("✅Multi-agent health check completed") openclaw_multiagent_render_status echo "---------------------------------------" echo "1. Add new intelligent agent" - echo "2. Delete the agent" + echo "2. 删除智能体" echo "3. View routing bindings" echo "4. Add new route binding" echo "5. Remove route binding" - echo "6. View session overview" + echo "6. 查看会话概况" echo "7. Run multi-agent health checks" echo "8. Modify the agent’s identity (name/Emoji)" - echo "9. Clean up expired sessions" + echo "9. 清理过期会话" echo "0. Return to the previous level" echo "---------------------------------------" read -e -p "Please enter your choice:" multi_choice @@ -17174,7 +17608,7 @@ openclaw_backup_restore_menu() { echo "---------------------------------------" echo "1. Back up the entire memory" echo "2. Restore the full memory" - echo "3. Back up the OpenClaw project (default safe mode)" + echo "3. 备份 OpenClaw 项目(默认安全模式)" echo "4. Restore OpenClaw Project (Advanced/High Risk)" echo "5. Delete backup files" echo "0. Return to the previous level" @@ -17303,7 +17737,7 @@ openclaw_backup_restore_menu() { echo "https://${yuming}/#token=$token" echo "First access the URL to trigger the device ID, then press Enter to proceed with pairing." read - echo -e "${gl_kjlan}Loading device list...${gl_bai}" + echo -e "${gl_kjlan}正在加载设备列表……${gl_bai}" # Automatically add domain names to allowedOrigins config_file=$(openclaw_get_config_file) if [ -f "$config_file" ]; then @@ -17470,9 +17904,9 @@ while true; do echo -e "${gl_kjlan}3. ${color3}1Panel new generation management panel${gl_kjlan}4. ${color4}NginxProxyManager visualization panel" echo -e "${gl_kjlan}5. ${color5}OpenList multi-store file list program${gl_kjlan}6. ${color6}Ubuntu Remote Desktop Web Edition" echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS Monitoring Panel${gl_kjlan}8. ${color8}QB offline BT magnetic download panel" - echo -e "${gl_kjlan}9. ${color9}Poste.io mail server program${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" + echo -e "${gl_kjlan}9. ${color9}Poste.io邮件服务器程序 ${gl_kjlan}10. ${color10}RocketChat multi-person online chat system" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao project management software${gl_kjlan}12. ${color12}Qinglong panel scheduled task management platform" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}Qinglong panel scheduled task management platform" echo -e "${gl_kjlan}13. ${color13}Cloudreve network disk${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}Simple picture bed picture management program" echo -e "${gl_kjlan}15. ${color15}emby multimedia management system${gl_kjlan}16. ${color16}Speedtest speed test panel" echo -e "${gl_kjlan}17. ${color17}AdGuardHome removes adware${gl_kjlan}18. ${color18}onlyofficeOnline office OFFICE" @@ -17484,16 +17918,16 @@ while true; do echo -e "${gl_kjlan}27. ${color27}Dockge container stack management panel${gl_kjlan}28. ${color28}LibreSpeed ​​speed test tool" echo -e "${gl_kjlan}29. ${color29}searxng aggregated search station${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism Private Album System" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF Tools Collection${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}drawio free online charting software${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel Navigation Panel${gl_kjlan}34. ${color34}Pingvin-Share file sharing platform" echo -e "${gl_kjlan}35. ${color35}Minimalist circle of friends${gl_kjlan}36. ${color36}LobeChatAI chat aggregation website" echo -e "${gl_kjlan}37. ${color37}MyIP Toolbox${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alist family bucket" - echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh web version SSH connection tool" + echo -e "${gl_kjlan}39. ${color39}Bililive live broadcast recording tool${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}Mouse management panel${gl_kjlan}42. ${color42}Nexterm remote connection tool" echo -e "${gl_kjlan}43. ${color43}RustDesk remote desktop (server)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk remote desktop (relay)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker acceleration station${gl_kjlan}46. ${color46}GitHub acceleration station${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}47. ${color47}Prometheus monitoring${gl_kjlan}48. ${color48}Prometheus (host monitoring)" + echo -e "${gl_kjlan}47. ${color47}Prometheus monitoring${gl_kjlan}48. ${color48}普罗米修斯(主机监控)" echo -e "${gl_kjlan}49. ${color49}Prometheus (container monitoring)${gl_kjlan}50. ${color50}Replenishment monitoring tools" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE open chick panel${gl_kjlan}52. ${color52}DPanel container management panel" @@ -17750,7 +18184,7 @@ while true; do ;; 7|nezha) clear - send_stats "Build Nezha" + send_stats "搭建哪吒" local app_id="7" local docker_name="nezha-dashboard" @@ -17820,7 +18254,7 @@ while true; do } local docker_describe="qbittorrent offline BT magnetic download service" - local docker_url="Official website introduction: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -17839,7 +18273,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "postal service$check_docker $update_status" + echo -e "postal services$check_docker $update_status" echo "poste.io is an open source mail server solution," echo "Video introduction: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17848,7 +18282,7 @@ while true; do port=25 timeout=3 if echo "quit" | timeout $timeout telnet smtp.qq.com $port | grep 'Connected'; then - echo -e "${gl_lv}port$portCurrently available${gl_bai}" + echo -e "${gl_lv}端口 $portCurrently available${gl_bai}" else echo -e "${gl_hong}port$portCurrently unavailable${gl_bai}" fi @@ -18029,7 +18463,7 @@ while true; do local docker_describe="ZenTao is a universal project management software" local docker_url="Official website introduction: https://www.zentao.net/" - local docker_use="echo \"Initial username: admin\"" + local docker_use="echo \"初始用户名: admin\"" local docker_passwd="echo \"Initial password: 123456\"" local app_size="2" docker_app @@ -18056,7 +18490,7 @@ while true; do } - local docker_describe="Qinglong Panel is a scheduled task management platform" + local docker_describe="青龙面板是一个定时任务管理平台" local docker_url="Official website introduction:${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" @@ -18121,7 +18555,7 @@ while true; do } - local docker_describe="Simple drawing bed is a simple drawing bed program" + local docker_describe="简单图床是一个简单的图床程序" local docker_url="Official website introduction:${gh_proxy}github.com/icret/EasyImages2.0" local docker_use="" local docker_passwd="" @@ -18230,7 +18664,7 @@ while true; do } - local docker_describe="onlyoffice is an open source online office tool, so powerful!" + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" local docker_url="Official website introduction: https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -18702,7 +19136,7 @@ while true; do } - local docker_describe="Minimalist Moments, high imitation WeChat Moments, record your wonderful life" + local docker_describe="Minimalist WeChat Moments, high imitation WeChat Moments, record your wonderful life" local docker_url="Official website introduction:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"Account: admin Password: a123456\"" local docker_passwd="" @@ -18811,7 +19245,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="AcePanel original mouse panel" - local panelurl="Official address:${gh_proxy}github.com/acepanel/panel" + local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" panel_app_install() { cd ~ @@ -18852,7 +19286,7 @@ while true; do } - local docker_describe="nexterm is a powerful online SSH/VNC/RDP connection tool." + local docker_describe="nexterm是一款强大的在线SSH/VNC/RDP连接工具。" local docker_url="Official website introduction:${gh_proxy}github.com/gnmyt/Nexterm" local docker_use="" local docker_passwd="" @@ -19260,7 +19694,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "App has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -19273,7 +19707,7 @@ while true; do local app_id="60" local app_name="JumpServer open source bastion machine" local app_text="It is an open source privileged access management (PAM) tool. This program occupies port 80 and does not support adding domain names for access." - local app_url="Official introduction:${gh_https_url}github.com/jumpserver/jumpserver" + local app_url="官方介绍: ${gh_https_url}github.com/jumpserver/jumpserver" local docker_name="jms_web" local docker_port="80" local app_size="2" @@ -19403,7 +19837,7 @@ while true; do } local docker_describe="Very useful tool for developers and IT workers" - local docker_url="Official website introduction:${gh_https_url}github.com/CorentinTh/it-tools" + local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -19517,7 +19951,7 @@ while true; do } - local docker_describe="Open source free anytime, anywhere SFTP FTP WebDAV file transfer tool" + local docker_describe="开源免费随时随地SFTP FTP WebDAV 文件传输工具" local docker_url="Official website introduction: https://sftpgo.com/" local docker_use="" local docker_passwd="" @@ -19579,7 +20013,7 @@ while true; do } local docker_describe="It is a lightweight, high-performance music streaming server" - local docker_url="Official website introduction: https://www.navidrome.org/" + local docker_url="官网介绍: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -19876,7 +20310,7 @@ while true; do sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 16)|g" .env sed -i "s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -hex 32)|g" .env - # Add administrator account information + # 追加管理员账号信息 echo "ADMIN_EMAIL=${ADMIN_EMAIL}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env @@ -20082,7 +20516,7 @@ while true; do local app_id="85" local app_name="immich picture video manager" local app_text="High-performance self-hosted photo and video management solution." - local app_url="Official website introduction:${gh_https_url}github.com/immich-app/immich" + local app_url="官网介绍: ${gh_https_url}github.com/immich-app/immich" local docker_name="immich_server" local docker_port="8085" local app_size="3" @@ -20174,7 +20608,7 @@ while true; do } - local docker_describe="A program for watching movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" + local docker_describe="A program to watch movies and live broadcasts together remotely. It provides simultaneous viewing, live broadcast, chat and other functions" local docker_url="Official website introduction:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"Initial account and password: root. Please change the login password in time after logging in\"" local docker_passwd="" @@ -20304,7 +20738,7 @@ while true; do local app_id="91" - local app_name="gitea private code repository" + local app_name="gitea私有代码仓库" local app_text="A free new generation code hosting platform that provides an experience close to GitHub." local app_url="Video introduction:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" @@ -20462,7 +20896,7 @@ while true; do cd /home/docker/paperless docker compose up -d clear - echo "Installation completed" + echo "已经安装完成" check_docker_app_ip } @@ -20722,7 +21156,7 @@ while true; do local app_name="dsm synology virtual machine" local app_text="Virtual DSM in Docker container" - local app_url="Official website:${gh_https_url}github.com/vdsm/virtual-dsm" + local app_url="官网: ${gh_https_url}github.com/vdsm/virtual-dsm" local docker_name="dsm" local docker_port="8099" local app_size="16" @@ -20805,7 +21239,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI video generation tool" - local app_text="MoneyPrinterTurbo is a tool that uses AI large models to synthesize high-definition short videos." + local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短视频的工具" local app_url="Official website:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -20872,7 +21306,7 @@ while true; do 103|umami) local app_id="103" - local app_name="Umami website statistics tool" + local app_name="Umami网站统计工具" local app_text="Open source, lightweight, privacy-friendly website analysis tool, similar to Google Analytics." local app_url="Official website:${gh_https_url}github.com/umami-software/umami" local docker_name="umami-umami-1" @@ -21002,7 +21436,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="PanSou is a high-performance network disk resource search API service." - local docker_url="Official website introduction:${gh_https_url}github.com/fish2018/pansou" + local docker_url="官网介绍: ${gh_https_url}github.com/fish2018/pansou" local docker_use="" local docker_passwd="" local app_size="1" @@ -21114,7 +21548,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_app_uninstall() { cd /home/docker/karakeep/docker/ && docker compose down --rmi all rm -rf /home/docker/karakeep - echo "App has been uninstalled" + echo "应用已卸载" } docker_app_plus @@ -21228,7 +21662,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ while true; do clear - echo "Backup file created: /$backup_filename" + echo "备份文件已创建: /$backup_filename" read -e -p "Do you want to transfer backup data to a remote server? (Y/N):" choice case "$choice" in [Yy]) @@ -21318,7 +21752,7 @@ linux_work() { send_stats "Backend workspace" echo -e "Backend workspace" echo -e "The system will provide you with a workspace that can run permanently in the background, which you can use to perform long-term tasks." - echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the background tasks will persist." + echo -e "Even if you disconnect SSH, the tasks in the workspace will not be interrupted, and the tasks will remain in the background." echo -e "${gl_huang}hint:${gl_bai}After entering the workspace, use Ctrl+b and then press d alone to exit the workspace!" echo -e "${gl_kjlan}------------------------" echo "List of currently existing workspaces" @@ -21327,10 +21761,10 @@ linux_work() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Work Area 1" echo -e "${gl_kjlan}2. ${gl_bai}Work Area 2" - echo -e "${gl_kjlan}3. ${gl_bai}Work Area 3" + echo -e "${gl_kjlan}3. ${gl_bai}3号工作区" echo -e "${gl_kjlan}4. ${gl_bai}Work Area 4" echo -e "${gl_kjlan}5. ${gl_bai}Workspace No. 5" - echo -e "${gl_kjlan}6. ${gl_bai}Work Area 6" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" echo -e "${gl_kjlan}7. ${gl_bai}Work Area 7" echo -e "${gl_kjlan}8. ${gl_bai}Work Area 8" echo -e "${gl_kjlan}9. ${gl_bai}Workspace No. 9" @@ -21427,7 +21861,7 @@ linux_work() { else local tmux_sshd_status="${gl_hui}closure${gl_bai}" fi - send_stats "SSH resident mode" + send_stats "SSH常驻模式 " echo -e "SSH resident mode${tmux_sshd_status}" echo "After opening the SSH connection, it will directly enter the resident mode and return directly to the previous working state." echo "------------------------" @@ -21557,8 +21991,8 @@ fail2ban_panel() { while true; do check_f2b_status - echo -e "SSH defense program$check_f2b_status" - echo "fail2ban is an SSH tool to prevent brute force cracking" + echo -e "SSH防御程序 $check_f2b_status" + echo "fail2ban是一个SSH防止暴力破解工具" echo "Official website introduction:${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" echo "1. Install a defense program" @@ -21624,7 +22058,7 @@ net_menu() { send_stats "Network card management tool" show_nics() { echo "================ Current network card information ================" - printf "%-18s %-12s %-20s %-26s\n" "Network card name" "state" "IP address" "MAC address" + printf "%-18s %-12s %-20s %-26s\n" "网卡名" "state" "IP address" "MAC address" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do state=$(cat /sys/class/net/$nic/operstate 2>/dev/null) @@ -21661,7 +22095,7 @@ net_menu() { ;; 2) send_stats "Disable network card" - read -erp "Please enter the name of the network card to be disabled:" nic + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ Network card$nicDisabled" else @@ -21772,7 +22206,7 @@ log_menu() { fi ;; 5) - send_stats "Clean up old journal logs" + send_stats "清理旧 journal 日志" echo "⚠️ Clean the journal (safe way)" echo "1) Keep the last 7 days" echo "2) Keep the last 3 days" @@ -21889,7 +22323,7 @@ env_menu() { echo "5. Edit ~/.profile" echo "6. Reload environment variables (source)" echo "--------------------------------------" - echo "0. Return to the previous menu" + echo "0. 返回上一级选单" echo "--------------------------------------" read -erp "Please select an action:" choice @@ -21916,7 +22350,7 @@ env_menu() { break ;; *) - echo "Invalid option" + echo "无效选项" sleep 1 ;; esac @@ -21944,7 +22378,7 @@ create_user_with_sshkey() { case "$sshkey_vl" in http://*|https://*) - send_stats "Import SSH public key from URL" + send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$sshkey_vl" "/home/$new_username" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa*) @@ -22001,14 +22435,14 @@ linux_Settings() { echo -e "system tools" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}Set script startup shortcut key${gl_kjlan}2. ${gl_bai}Change login password" - echo -e "${gl_kjlan}3. ${gl_bai}User password login mode${gl_kjlan}4. ${gl_bai}Install the specified version of Python" + echo -e "${gl_kjlan}3. ${gl_bai}User password login mode${gl_kjlan}4. ${gl_bai}安装Python指定版本" echo -e "${gl_kjlan}5. ${gl_bai}Open all ports${gl_kjlan}6. ${gl_bai}Modify SSH connection port" echo -e "${gl_kjlan}7. ${gl_bai}Optimize DNS address${gl_kjlan}8. ${gl_bai}Reinstall the system with one click${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}Disable ROOT account and create new account${gl_kjlan}10. ${gl_bai}Switch priority ipv4/ipv6" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}Check port occupation status${gl_kjlan}12. ${gl_bai}Modify virtual memory size" echo -e "${gl_kjlan}13. ${gl_bai}User management${gl_kjlan}14. ${gl_bai}User/password generator" - echo -e "${gl_kjlan}15. ${gl_bai}System time zone adjustment${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" + echo -e "${gl_kjlan}15. ${gl_bai}系统时区调整 ${gl_kjlan}16. ${gl_bai}Set up BBR3 acceleration" echo -e "${gl_kjlan}17. ${gl_bai}Firewall Advanced Manager${gl_kjlan}18. ${gl_bai}Modify hostname" echo -e "${gl_kjlan}19. ${gl_bai}Switch system update source${gl_kjlan}20. ${gl_bai}Scheduled task management" echo -e "${gl_kjlan}------------------------" @@ -22020,7 +22454,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}Switch system language${gl_kjlan}32. ${gl_bai}Command line beautification tool${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}Set up system recycle bin${gl_kjlan}34. ${gl_bai}System backup and recovery" - echo -e "${gl_kjlan}35. ${gl_bai}ssh remote connection tool${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" + echo -e "${gl_kjlan}35. ${gl_bai}ssh远程连接工具 ${gl_kjlan}36. ${gl_bai}Hard disk partition management tool" echo -e "${gl_kjlan}37. ${gl_bai}Command line history${gl_kjlan}38. ${gl_bai}rsync remote synchronization tool" echo -e "${gl_kjlan}39. ${gl_bai}Command Favorites${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}Network card management tool" echo -e "${gl_kjlan}------------------------" @@ -22057,7 +22491,7 @@ linux_Settings() { 2) clear - send_stats "Set your login password" + send_stats "设置你的登录密码" echo "Set your login password" passwd ;; @@ -22072,7 +22506,7 @@ linux_Settings() { echo "python version management" echo "Video introduction: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" - echo "This function can seamlessly install any version officially supported by Python!" + echo "This function can seamlessly install any version officially supported by python!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') echo -e "Current python version number:${gl_huang}$VERSION${gl_bai}" echo "------------" @@ -22184,11 +22618,11 @@ EOF send_stats "SSH port has been modified" new_ssh_port $new_port elif [[ $new_port -eq 0 ]]; then - send_stats "Exit SSH port modification" + send_stats "退出SSH端口修改" break else echo "The port number is invalid. Please enter a number between 1 and 65535." - send_stats "Invalid SSH port entered" + send_stats "输入无效SSH端口" break_end fi else @@ -22372,7 +22806,7 @@ EOF 2) # Prompt user for new username - read -e -p "Please enter a new username:" new_username + read -e -p "请输入新用户名: " new_username create_user_with_sshkey $new_username true ;; @@ -22450,7 +22884,7 @@ EOF echo "------------------------" for i in {1..5}; do local password=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32) - echo "random password$i: $password" + echo "随机密码 $i: $password" done echo "" @@ -22540,7 +22974,7 @@ EOF 18) root_use - send_stats "Modify hostname" + send_stats "修改主机名" while true; do clear @@ -22614,7 +23048,7 @@ EOF ;; *) - echo "Canceled" + echo "已取消" ;; esac @@ -22632,7 +23066,7 @@ EOF echo "" echo "operate" echo "------------------------" - echo "1. Add a scheduled task 2. Delete a scheduled task 3. Edit a scheduled task" + echo "1. 添加定时任务 2. 删除定时任务 3. 编辑定时任务" echo "------------------------" echo "0. Return to the previous menu" echo "------------------------" @@ -22746,7 +23180,7 @@ EOF # Get the value of threshold_gb local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}The currently set inbound traffic limit threshold is:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}The currently set outbound traffic limiting threshold is:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}The current limiting shutdown function is not currently enabled${gl_bai}" @@ -22784,7 +23218,7 @@ EOF crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 echo "Current limiting shutdown has been set" - send_stats "Current limiting shutdown has been set" + send_stats "限流关机已设置" ;; 2) check_crontab_installed @@ -22818,7 +23252,7 @@ EOF case "$choice" in [Yy]) - send_stats "Telegram warning enabled" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -22957,14 +23391,14 @@ EOF 66) root_use - send_stats "One-stop tuning" + send_stats "一条龙调优" echo "One-stop system tuning" echo "------------------------------------------------" - echo "The following content will be operated and optimized" + echo "将对以下内容进行操作与优化" echo "1. Optimize the system update source and update the system to the latest" echo "2. Clean up system junk files" echo -e "3. Set up virtual memory${gl_huang}1G${gl_bai}" - echo -e "4. Set the SSH port number to${gl_huang}5522${gl_bai}" + echo -e "4. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo -e "5. Start fail2ban to defend against SSH brute force cracking" echo -e "6. Open all ports" echo -e "7. Turn on${gl_huang}BBR${gl_bai}accelerate" @@ -22983,7 +23417,7 @@ EOF echo "------------------------------------------------" switch_mirror false false linux_update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. Update the system to the latest" + echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" linux_clean @@ -23052,7 +23486,7 @@ EOF while true; do clear if grep -q '^ENABLE_STATS="true"' /usr/local/bin/k > /dev/null 2>&1; then - local status_message="${gl_lv}Collecting data${gl_bai}" + local status_message="${gl_lv}正在采集数据${gl_bai}" elif grep -q '^ENABLE_STATS="false"' /usr/local/bin/k > /dev/null 2>&1; then local status_message="${gl_hui}Collection is closed${gl_bai}" else @@ -23131,7 +23565,7 @@ EOF ;; *) - echo "Invalid input!" + echo "无效的输入!" ;; esac break_end @@ -23160,7 +23594,7 @@ linux_file() { ls --color=auto -x echo "------------------------" echo "1. Enter the directory 2. Create the directory 3. Modify directory permissions 4. Rename the directory" - echo "5. Delete the directory 6. Return to the previous menu directory" + echo "5. 删除目录 6. 返回上一级选单目录" echo "------------------------" echo "11. Create files 12. Edit files 13. Modify file permissions 14. Rename files" echo "15. Delete files" @@ -23180,7 +23614,7 @@ linux_file() { ;; 2) # 创建目录 read -e -p "Please enter the directory name to be created:" dirname - mkdir -p "$dirname" && echo "Directory created" || echo "Creation failed" + mkdir -p "$dirname" && echo "Directory created" || echo "创建失败" send_stats "Create directory" ;; 3) # 修改目录权限 @@ -23193,11 +23627,11 @@ linux_file() { read -e -p "Please enter the current directory name:" current_name read -e -p "Please enter a new directory name:" new_name mv "$current_name" "$new_name" && echo "Directory has been renamed" || echo "Rename failed" - send_stats "Rename directory" + send_stats "重命名目录" ;; 5) # 删除目录 read -e -p "Please enter the directory name to be deleted:" dirname - rm -rf "$dirname" && echo "Directory deleted" || echo "Delete failed" + rm -rf "$dirname" && echo "目录已删除" || echo "Delete failed" send_stats "delete directory" ;; 6) # 返回上一级选单目录 @@ -23206,11 +23640,11 @@ linux_file() { ;; 11) # 创建文件 read -e -p "Please enter the file name to be created:" filename - touch "$filename" && echo "File created" || echo "Creation failed" + touch "$filename" && echo "文件已创建" || echo "Creation failed" send_stats "Create file" ;; 12) # 编辑文件 - read -e -p "Please enter the file name to be edited:" filename + read -e -p "请输入要编辑的文件名: " filename install nano nano "$filename" send_stats "Edit file" @@ -23261,7 +23695,7 @@ linux_file() { fi mv "$src_path" "$dest_path" && echo "File or directory moved to$dest_path" || echo "Failed to move file or directory" - send_stats "Move a file or directory" + send_stats "移动文件或目录" ;; @@ -23269,7 +23703,7 @@ linux_file() { read -e -p "Please enter the file or directory path to copy:" src_path if [ ! -e "$src_path" ]; then echo "Error: File or directory does not exist." - send_stats "Copying file or directory failed: File or directory does not exist" + send_stats "Failed to copy file or directory: File or directory does not exist" continue fi @@ -23290,11 +23724,11 @@ linux_file() { read -e -p "Please enter the file path to be transferred:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then echo "Error: File does not exist." - send_stats "Failed to transfer file: file does not exist" + send_stats "传送文件失败: 文件不存在" continue fi - kj_ssh_read_host_user_port "Please enter the remote server IP:" "Please enter the remote server username (default root):" "Please enter the login port (default 22):" "root" "22" + kj_ssh_read_host_user_port "请输入远端服务器IP: " "Please enter the remote server username (default root):" "Please enter the login port (default 22):" "root" "22" local remote_ip="$KJ_SSH_HOST" local remote_user="$KJ_SSH_USER" local remote_port="$KJ_SSH_PORT" @@ -23306,7 +23740,7 @@ linux_file() { ssh-keygen -f "/root/.ssh/known_hosts" -R "$remote_ip" sleep 2 # 等待时间 - # Transfer files using scp + # 使用scp传输文件 scp -P "$remote_port" -o StrictHostKeyChecking=no "$file_to_transfer" "$remote_user@$remote_ip:/home/" </dev/null && sed -i 's/permission_granted=\"false\"/permission_granted=\"true\"/' ~/kejilion.sh; grep -q 'ENABLE_STATS=\"false\"' ~/kejilion.sh.bak 2>/dev/null && sed -i 's/ENABLE_STATS=\"true\"/ENABLE_STATS=\"false\"/' ~/kejilion.sh" - # Deploy to /usr/local/bin/k and /usr/bin/k + # 部署到 /usr/local/bin/k 和 /usr/bin/k SH_Update_task="$SH_Update_task; cp -f ~/kejilion.sh /usr/local/bin/k 2>/dev/null; ln -sf /usr/local/bin/k /usr/bin/k 2>/dev/null" # Clean temporary files when download fails SH_Update_task="$SH_Update_task || rm -f \"\$tmp\" 2>/dev/null" @@ -23714,7 +24148,7 @@ while true; do check_crontab_installed (crontab -l | grep -v "kejilion.sh") | crontab - (crontab -l 2>/dev/null; echo "$(shuf -i 0-59 -n 1) 2 * * * bash -c '$SH_Update_task'") | crontab - - echo -e "${gl_lv}Automatic updates are turned on, and the script will be automatically updated at 2 a.m. every day!${gl_bai}" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" send_stats "Enable automatic script updates" break_end ;; @@ -23722,7 +24156,7 @@ while true; do clear (crontab -l | grep -v "kejilion.sh") | crontab - echo -e "${gl_lv}Automatic updates are turned off${gl_bai}" - send_stats "Turn off automatic script updates" + send_stats "关闭脚本自动更新" break_end ;; *) @@ -23762,7 +24196,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}Backend workspace" echo -e "${gl_kjlan}13. ${gl_bai}system tools" echo -e "${gl_kjlan}14. ${gl_bai}Server cluster control" echo -e "${gl_kjlan}15. ${gl_bai}Advertising column" -echo -e "${gl_kjlan}16. ${gl_bai}Collection of game server opening scripts" +echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}Script update" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -23803,20 +24237,20 @@ send_stats "k command reference examples" echo "-------------------" echo "Video introduction: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "The following is a reference use case for the k command:" -echo "Start script k" -echo "Install packages k install nano wget | k add nano wget | k install nano wget" -echo "Uninstall a package k remove nano wget | k del nano wget | k uninstall nano wget | k uninstall nano wget" +echo "启动脚本 k" +echo "安装软件包 k install nano wget | k add nano wget | k 安装 nano wget" +echo "卸载软件包 k remove nano wget | k del nano wget | k uninstall nano wget | k 卸载 nano wget" echo "Update system k update | k update" echo "Clean system junk k clean | k clean" echo "Reinstall the system panel k dd | k reinstall" -echo "bbr3 control panel k bbr3 | k bbrv3" +echo "bbr3控制面板 k bbr3 | k bbrv3" echo "Kernel Tuning Panel k nhyh | k Kernel Optimization" echo "Set virtual memory k swap 2048" echo "Set virtual time zone k time Asia/Shanghai | k time zone Asia/Shanghai" echo "System Recycle Bin k trash | k hsz | k Recycle Bin" echo "System backup function k backup | k bf | k backup" echo "ssh remote connection tool k ssh | k remote connection" -echo "rsync remote synchronization tool k rsync | k remote synchronization" +echo "rsync远程同步工具 k rsync | k 远程同步" echo "Hard disk management tool k disk | k hard disk management" echo "Intranet penetration (server) k frps" echo "Intranet penetration (client) k frpc" @@ -23826,11 +24260,11 @@ echo "Software restart k restart sshd | k restart sshd" echo "Check software status k status sshd | k status sshd" echo "k enable docker | k autostart docker | k start docker on startup" echo "Domain name certificate application k ssl" -echo "Domain name certificate expiry query k ssl ps" +echo "域名证书到期查询 k ssl ps" echo "docker management plane k docker" echo "docker environment installation k docker install |k docker installation" echo "docker container management k docker ps |k docker container" -echo "docker image management k docker img |k docker image" +echo "docker镜像管理 k docker img |k docker 镜像" echo "LDNMP site management k web" echo "LDNMP cache cleaning k web cache" echo "Install WordPress k wp | k wordpress | k wp xxx.com" @@ -23907,7 +24341,7 @@ else rsync_run) shift - send_stats "Scheduled rsync synchronization" + send_stats "定时rsync同步" run_task "$@" ;; @@ -24020,6 +24454,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then @@ -24156,6 +24595,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "Usage: k kpanel node join | status | update | uninstall" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift @@ -24205,7 +24655,7 @@ else ;; * ) echo "Error: unknown parameter '$1'" - echo "usage:" + echo "用法:" echo "k sshkey enters the interactive menu" echo "k sshkey \"\" Directly import the SSH public key" echo "k sshkey Import SSH public key from URL" diff --git a/jp/kejilion.sh b/jp/kejilion.sh index 0b8658c35..0ee3b1d13 100644 --- a/jp/kejilion.sh +++ b/jp/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' @@ -16,7 +16,13 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -77,7 +83,7 @@ CheckFirstRun_true() { # 関数の埋もれた情報を収集し、現在のスクリプトのバージョン番号、使用時間、システム バージョン、CPU アーキテクチャ、マシンの国、ユーザーが使用した関数名を記録する機能。機密情報は含まれませんので、ご安心ください。信じてください! # なぜこの機能が設計されたのでしょうか?その目的は、ユーザーが使いたい機能をより深く理解し、機能をさらに最適化し、ユーザーのニーズを満たす機能をさらに投入することです。 -# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご心配な場合はご利用をお断りすることも可能です。 +# send_stats 関数の呼び出し位置を全文検索できます。これは透明性があり、オープンソースです。ご不安がある場合はご利用をお断りすることも可能です。 @@ -194,7 +200,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "パッケージパラメータが指定されていません!" + echo "未提供软件包参数!" return 1 fi @@ -246,7 +252,7 @@ check_disk_space() { local available_space_mb=$(df -m "$path" | awk 'NR==2 {print $4}') if [ "$available_space_mb" -lt "$required_space_mb" ]; then - echo -e "${gl_huang}ヒント:${gl_bai}ディスク容量が足りません!" + echo -e "${gl_huang}ヒント:${gl_bai}磁盘空间不足!" echo "現在利用可能なスペース: $((available_space_mb/1024))G" echo "最低限必要なスペース:${required_gb}G" echo "インストールを続行できません。ディスク容量をクリアして、再試行してください。" @@ -275,7 +281,7 @@ remove() { fi for package in "$@"; do - echo -e "${gl_kjlan}アンインストール中$package...${gl_bai}" + echo -e "${gl_kjlan}アンインストールする$package...${gl_bai}" if command -v dnf &>/dev/null; then dnf remove -y "$package" elif command -v yum &>/dev/null; then @@ -317,13 +323,13 @@ systemctl() { restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1サービスが再開されました。" + echo "$1 服务已重启。" else echo "エラー: 再起動$1サービスが失敗しました。" fi } -# サービス開始 +# 启动服务 start() { systemctl start "$1" if [ $? -eq 0 ]; then @@ -339,7 +345,7 @@ stop() { if [ $? -eq 0 ]; then echo "$1サービスが停止されました。" else - echo "エラー: 停止$1サービスが失敗しました。" + echo "错误:停止 $1サービスが失敗しました。" fi } @@ -347,9 +353,9 @@ stop() { status() { systemctl status "$1" if [ $? -eq 0 ]; then - echo "$1サービスのステータスが表示されます。" + echo "$1 服务状态已显示。" else - echo "エラー: 表示できません$1サービスのステータス。" + echo "エラー: 表示できません$1 服务状态。" fi } @@ -369,7 +375,7 @@ enable() { break_end() { echo -e "${gl_lv}操作が完了しました${gl_bai}" - echo "続行するには任意のキーを押してください..." + echo "按任意键继续..." read -n 1 -s -r -p "" echo "" clear @@ -508,13 +514,13 @@ while true; do echo "5. 指定したコンテナを再起動します。 9. すべてのコンテナを再起動します。" echo "------------------------" echo "11. 指定したコンテナを入力します。 12. コンテナのログを表示します。" - echo "13. コンテナネットワークを確認します。 14. コンテナ占有率を確認します。" + echo "13. 查看容器网络 14. 查看容器占用" echo "------------------------" echo "15. コンテナ ポート アクセスを有効にする 16. コンテナ ポート アクセスを閉じる" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択肢を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "新しいコンテナを作成する" @@ -584,7 +590,7 @@ while true; do echo "" container_ids=$(docker ps -q) echo "------------------------------------------------------------" - printf "%-25s %-25s %-25s\n" "コンテナ名" "ネットワーク名" "IPアドレス" + printf "%-25s %-25s %-25s\n" "コンテナ名" "网络名称" "IPアドレス" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") local container_name=$(echo "$container_info" | awk '{print $1}') @@ -598,7 +604,7 @@ while true; do break_end ;; 14) - send_stats "コンテナ占有率の表示" + send_stats "查看容器占用" docker stats --no-stream break_end ;; @@ -615,7 +621,7 @@ while true; do 16) send_stats "コンテナポートへのアクセスをブロックする" - read -e -p "コンテナ名を入力してください:" docker_name + read -e -p "请输入容器名: " docker_name ip_address block_container_port "$docker_name" "$ipv4_address" local docker_port=$(docker port $docker_name | awk -F'[:]' '/->/ {print $NF}' | uniq) @@ -769,7 +775,7 @@ docker_ipv6_on() { local CONFIG_FILE="/etc/docker/daemon.json" local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' - # 構成ファイルが存在するかどうかを確認し、存在しない場合はファイルを作成し、デフォルト設定を書き込みます + # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 if [ ! -f "$CONFIG_FILE" ]; then echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" restart docker @@ -813,7 +819,7 @@ docker_ipv6_off() { # 現在の構成を読み取る local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") - # jq を使用して構成ファイルの更新を処理する + # 使用jq处理配置文件的更新 local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') # 現在のIPv6ステータスを確認する @@ -875,14 +881,14 @@ open_port() { iptables -D INPUT -p tcp --dport $port -j DROP 2>/dev/null iptables -D INPUT -p udp --dport $port -j DROP 2>/dev/null - # オープンルールを追加 + # 添加打开规则 if ! iptables -C INPUT -p tcp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p tcp --dport $port -j ACCEPT fi if ! iptables -C INPUT -p udp --dport $port -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -p udp --dport $port -j ACCEPT - echo "ポートがオープンされました$port" + echo "已打开端口 $port" fi done @@ -920,7 +926,7 @@ close_port() { iptables -D INPUT -i lo -j ACCEPT 2>/dev/null iptables -D FORWARD -i lo -j ACCEPT 2>/dev/null - # 最初のルールに新しいルールを挿入します + # 插入新规则到第一条 iptables -I INPUT 1 -i lo -j ACCEPT iptables -I FORWARD 1 -i lo -j ACCEPT @@ -969,7 +975,7 @@ block_ip() { # ブロックルールを追加する if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then iptables -I INPUT 1 -s $ip -j DROP - echo "IPがブロックされました$ip" + echo "已阻止IP $ip" fi done @@ -984,7 +990,7 @@ block_ip() { enable_ddos_defense() { - # DDoS 保護を有効にする + # 开启防御 DDoS iptables -A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT iptables -A DOCKER-USER -p tcp --syn -j DROP iptables -A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT @@ -999,7 +1005,7 @@ enable_ddos_defense() { # DDoS 防御をオフにする disable_ddos_defense() { - # DDoS 保護をオフにする + # 关闭防御 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null iptables -D DOCKER-USER -p tcp --syn -j DROP 2>/dev/null iptables -D DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT 2>/dev/null @@ -1116,7 +1122,7 @@ iptables_panel() { echo "5. IP ホワイトリスト 6. IP ブラックリスト" echo "7. 指定したIPをクリアします" echo "------------------------" - echo "11. PING を許可する 12. PING を無効にする" + echo "11. 允许PING 12. 禁止PING" echo "------------------------" echo "13. DDOS 防御を開始します。 14. DDOS 防御をオフにします。" echo "------------------------" @@ -1172,12 +1178,12 @@ iptables_panel() { 5) # IPホワイトリスト - read -e -p "許可された IP または IP セグメントを入力してください:" o_ip + read -e -p "请输入放行的IP或IP段: " o_ip allow_ip $o_ip ;; 6) - # IPブラックリスト - read -e -p "ブロックされた IP または IP 範囲を入力してください:" c_ip + # IP 黑名单 + read -e -p "请输入封锁的IP或IP段: " c_ip block_ip $c_ip ;; 7) @@ -1186,14 +1192,14 @@ iptables_panel() { iptables -D INPUT -s $d_ip -j ACCEPT 2>/dev/null iptables -D INPUT -s $d_ip -j DROP 2>/dev/null iptables-save > /etc/iptables/rules.v4 - send_stats "指定したIPをクリア" + send_stats "清除指定IP" ;; 11) # PINGを許可する iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables-save > /etc/iptables/rules.v4 - send_stats "PINGを許可する" + send_stats "允许PING" ;; 12) # PINGを無効にする @@ -1210,14 +1216,14 @@ iptables_panel() { ;; 15) - read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます):" country_code + read -e -p "ブロックされている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules block $country_code send_stats "国を許可する$country_codeIP" ;; 16) read -e -p "許可されている国コードを入力してください (CN US JP のように、複数の国コードをスペースで区切ることができます)。" country_code manage_country_rules allow $country_code - send_stats "ブロック国$country_codeIP" + send_stats "阻止国家 $country_codeIP" ;; 17) @@ -1445,7 +1451,7 @@ install_certbot() { local cron_job="0 0 * * * ~/auto_cert_renewal.sh" crontab -l 2>/dev/null | grep -vF "$cron_job" | crontab - (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "更新タスクが更新されました" + echo "续签任务已更新" } @@ -1486,7 +1492,7 @@ install_ssltls_text() { cat /etc/letsencrypt/live/$yuming/privkey.pem echo "" echo -e "${gl_huang}証明書の保存パス${gl_bai}" - echo "公開キー: /etc/letsencrypt/live/$yuming/fullchain.pem" + echo "公钥: /etc/letsencrypt/live/$yuming/fullchain.pem" echo "秘密鍵: /etc/letsencrypt/live/$yuming/privkey.pem" echo "" } @@ -1552,7 +1558,7 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "ドメイン名証明書の申請が成功しました" + send_stats "域名证书申请成功" else send_stats "ドメイン名証明書の申請に失敗しました" if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && @@ -1562,7 +1568,7 @@ certs_status() { fi echo -e "${gl_hong}知らせ:${gl_bai}証明書の申請に失敗しました。次の考えられる理由を確認して、再試行してください。" echo -e "1. ドメイン名のスペルが間違っています ➠ ドメイン名が正しく入力されているかどうかを確認してください" - echo -e "2. DNS 解決の問題 ➠ ドメイン名がサーバー IP に正しく解決されていることを確認します。" + echo -e "2. DNS解析问题 ➠ 确认域名已正确解析到本服务器IP" echo -e "3. ネットワーク構成の問題 ➠ Cloudflare Warp などの仮想ネットワークを使用している場合は、一時的にシャットダウンしてください" echo -e "4. ファイアウォールの制限 ➠ ポート 80/443 が開いているかどうかを確認し、アクセス可能であることを確認します。" echo -e "5. アプリケーション数が制限を超えている ➠ Let's Encrypt には週制限あり (5 回/ドメイン名/週)" @@ -1570,10 +1576,10 @@ certs_status() { echo "------------------------" echo "1. 再適用 2. 既存の証明書をインポート 0. 終了" echo "------------------------" - read -e -p "選択肢を入力してください:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) - send_stats "再申請" + send_stats "重新申请" echo "もう一度デプロイしてみてください$webname" add_yuming install_ssltls @@ -1817,7 +1823,7 @@ cf_purge_cache() { # キャッシュをクリアするかどうかをユーザーに確認する read -e -p "Cloudflareのキャッシュをクリアする必要がありますか? (y/n):" answer if [[ "$answer" == "y" ]]; then - echo "CF 情報は次の場所に保存されます。$CONFIG_FILECF 情報は後で変更できます。" + echo "CF情報は以下に保存されます。$CONFIG_FILECF 情報は後で変更できます。" read -e -p "API_TOKEN を入力してください:" API_TOKEN read -e -p "CF ユーザー名を入力してください:" EMAIL read -e -p "zone_id を入力してください (複数の場合はスペースで区切ります):" -a ZONE_IDS @@ -1827,7 +1833,7 @@ cf_purge_cache() { fi fi - # 各zone_idをループし、キャッシュクリアコマンドを実行します。 + # 循环遍历每个 zone_id 并执行清除缓存命令 for ZONE_ID in "${ZONE_IDS[@]}"; do echo "zone_id のキャッシュをクリアします:$ZONE_ID" curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ @@ -1945,7 +1951,7 @@ nginx_waf() { return 1 fi - # nginx イメージを確認し、それに応じて処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2140,7 +2146,7 @@ nginx_zstd() { fi if [ "$mode" == "on" ]; then - # Zstd をオンにする: コメントを削除する + # 开启 Zstd:去掉注释 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_filter_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|# load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|load_module /etc/nginx/modules/ngx_http_zstd_static_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2175,7 +2181,7 @@ nginx_zstd() { return 1 fi - # nginx イメージを確認し、それに応じて処理します + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2226,7 +2232,7 @@ web_security() { echo "------------------------" echo "1. 防御プログラムをインストールする" echo "------------------------" - echo "5. SSH 傍受記録の表示 6. Web サイト傍受記録の表示" + echo "5. 查看SSH拦截记录 6. 查看网站拦截记录" echo "7. 防御ルールのリストを表示します。 8. リアルタイム監視のログを表示します。" echo "------------------------" echo "11. インターセプトパラメータを設定します。 12. ブロックされたすべての IP をクリアします。" @@ -2344,17 +2350,17 @@ web_security() { ;; 22) - send_stats "高負荷で5秒シールド可能" + send_stats "高負荷により5秒シールドが可能" echo -e "${gl_huang}Web サイトは 5 分ごとに自動的に検出します。高負荷を検出すると自動的にシールドが開き、低負荷を検出すると5秒間自動的にシールドが閉じます。${gl_bai}" echo "--------------" echo "CFパラメータを取得します。" - echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側で API トークンを選択して、${gl_huang}Global API Key${gl_bai}" + echo -e "cf バックエンドの右上隅にある私のプロフィールに移動し、左側の API トークンを選択して、${gl_huang}Global API Key${gl_bai}" echo -e "cf バックエンド ドメイン名の概要ページの右下に移動して取得します。${gl_huang}エリアID${gl_bai}" echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CF の口座番号を入力してください:" cfuser read -e -p "CF のグローバル API キーを入力します。" cftoken - read -e -p "CF にドメイン名のゾーン ID を入力します。" cfzonID + read -e -p "输入CF中域名的区域ID: " cfzonID cd ~ install jq bc @@ -2381,13 +2387,13 @@ web_security() { 31) nginx_waf on echo "サイトWAFが有効になっています" - send_stats "サイトWAFが有効になっています" + send_stats "站点WAF已开启" ;; 32) nginx_waf off echo "サイト WAF がダウンしています" - send_stats "サイト WAF がダウンしています" + send_stats "站点WAF已关闭" ;; 33) @@ -2413,7 +2419,7 @@ check_ldnmp_mode() { local MYSQL_CONTAINER="mysql" local MYSQL_CONF="/etc/mysql/conf.d/custom_mysql_config.cnf" - # MySQL 設定ファイルに 4096M が含まれているかどうかを確認する + # 检查 MySQL 配置文件中是否包含 4096M if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then mode_info="ハイパフォーマンスモード" else @@ -2520,7 +2526,7 @@ web_optimization() { send_stats "LDNMP環境の最適化" echo -e "LDNMP環境の最適化${gl_lv}${mode_info}${gzip_status}${br_status}${zstd_status}${gl_bai}" echo "------------------------" - echo "1.スタンダードモード 2.ハイパフォーマンスモード(2H4G以上推奨)" + echo "1. 标准模式 2. 高性能模式 (推荐2H4G以上)" echo "------------------------" echo "3. gzip 圧縮をオンにする 4. gzip 圧縮をオフにする" echo "5. br 圧縮をオンにする 6. br 圧縮をオフにする" @@ -2650,7 +2656,7 @@ check_docker_image_update() { # 2. インテリジェントな配線判断 if [[ "$full_image_name" == ghcr.io* ]]; then - # --- シナリオ A: GitHub (ghcr.io) 上のミラー --- + # --- 场景 A: 镜像在 GitHub (ghcr.io) --- # ウェアハウスのパスを抽出します (例: ghcr.io/onexru/oneimg -> onexru/oneimg) local repo_path=$(echo "$full_image_name" | sed 's/ghcr.io\///' | cut -d':' -f1) # 注: ghcr.io の API は比較的複雑です。通常、最も早い方法は、GitHub リポジトリのリリースを確認することです。 @@ -2658,7 +2664,7 @@ check_docker_image_update() { local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) elif [[ "$full_image_name" == *"oneimg"* ]]; then - # --- シナリオB:特別指定(Docker HubでもGitHub Releaseで判断したい) --- + # --- 场景 B: 特殊指定 (即便在 Docker Hub,也想通过 GitHub Release 判断) --- local api_url="https://api.github.com/repos/onexru/oneimg/releases/latest" local remote_date=$(curl -s "$api_url" | jq -r '.published_at' 2>/dev/null) @@ -2703,7 +2709,7 @@ check_docker_image_update() { local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && [[ $container_created_ts -lt $remote_ts ]]; then - update_status="${gl_huang}新しいバージョンが見つかりました!${gl_bai}" + update_status="${gl_huang}发现新版本!${gl_bai}" fi fi } @@ -2714,56 +2720,50 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 - - # コンテナのIPアドレスを取得する - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi + local container_ips - install iptables - - - # 他のすべての IP をチェックしてブロックします - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 指定したIPの確認と解放 - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # ローカルネットワーク127.0.0.0/8を確認して許可します。 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - - - # 他のすべての IP をチェックしてブロックします - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # 指定したIPの確認と解放 - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - # ローカルネットワーク127.0.0.0/8を確認して許可します。 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT + # すべての Docker ネットワーク内のコンテナーの IPv4 アドレスを取得し、ルールを 1 つずつ適用します。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "エラー: コンテナを取得できません${container_name_or_id}IPv4 アドレス。" >&2 + return 1 fi - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi + install iptables + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "IP+ポートはサービスへのアクセスをブロックされています" save_iptables_rules @@ -2775,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # コンテナのIPアドレスを取得する - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # すべての Docker ネットワーク内のコンテナーの IPv4 アドレスを取得し、ルールを 1 つずつクリアします。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "エラー: コンテナを取得できません${container_name_or_id}IPv4 アドレス。" >&2 return 1 fi install iptables - - # 他のすべての IP をブロックする明確なルール - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 指定したIPを許可するルールをクリアします - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # 他のすべての IP をブロックする明確なルール - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # 指定したIPを許可するルールをクリアします - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # ローカルネットワーク 127.0.0.0/8 を許可するルールをクリアします - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "IP+ポートによるサービスへのアクセスが許可されました" save_iptables_rules @@ -2848,7 +2819,7 @@ block_host_port() { install iptables - # 他のすべての IP からのアクセスを拒否する + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p tcp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p tcp --dport "$port" -j DROP fi @@ -3030,7 +3001,7 @@ kpanel_app_interactive_choice() { esac ;; *) - echo "エラー: KPanel インタラクティブ ターミナルは、このアプリケーション操作をサポートしていません" + echo "错误: KPanel 交互终端不支持此应用操作" return 1 ;; esac @@ -3091,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3104,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" @@ -3223,7 +3205,7 @@ kpanel_app_choose_install_port() { return $? fi while true; do - read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押してデフォルトで使用します。${docker_port}ポート:" app_port + read -e -p "アプリケーションの外部サービス ポートを入力し、Enter キーを押して、それをデフォルトで使用します。${docker_port}ポート:" app_port app_port=${app_port:-${docker_port}} if kpanel_app_port_in_use "$app_port"; then @@ -3252,7 +3234,7 @@ kpanel_run_docker_app_install() { kpanel_app_progress 15 "Docker実行環境の準備" install jq || return 1 install_docker || return 1 - kpanel_app_progress 30 "kejilion.shアプリケーションインストール関数の実行" + kpanel_app_progress 30 "kejilion.sh アプリケーションインストール関数の実行" if [ "$adapter" = "plus" ]; then if ! docker_app_install; then @@ -3309,7 +3291,7 @@ kpanel_run_docker_app_action() { echo "エラー: kejilion.sh アプリケーション インストール タグが見つかりません" return 1 fi - kpanel_app_progress 10 "kejilion.sh アプリのインストールフラグを修正" + kpanel_app_progress 10 "正在修复 kejilion.sh 应用安装标记" add_app_id || return 1 fi @@ -3404,7 +3386,7 @@ while true; do echo "5. ドメイン名アクセスを追加します。 6. ドメイン名アクセスを削除します。" echo "7. IP+ポートアクセスを許可します。 8. IP+ポートアクセスをブロックします。" echo "------------------------" - echo "0. 前のメニューに戻る" + echo "0. 返回上一级选单" echo "------------------------" if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then kpanel_app_interactive_choice choice || return 1 @@ -3473,7 +3455,7 @@ while true; do rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - echo "アプリがアンインストールされました" + echo "应用已卸载" send_stats "アンインストールする$docker_name" ;; @@ -3572,7 +3554,7 @@ docker_app_plus() { kpanel_app_write_access_mode direct send_stats "$app_nameインストール" else - echo -e "${gl_hong}インストールに失敗しました:${gl_bai}申請状況が登録されていません。上記のエラーを修正して再試行してください。" + echo -e "${gl_hong}インストールに失敗しました:${gl_bai}未登记应用状态,请根据上方错误修复后重试。" action_status=1 fi ;; @@ -3581,9 +3563,9 @@ docker_app_plus() { if docker_app_update; then add_app_id kpanel_app_restore_access_mode "$(kpanel_app_read_access_mode)" - send_stats "$app_name更新する" + send_stats "$app_name 更新" else - echo -e "${gl_hong}更新に失敗しました:${gl_bai}元のアプリケーションの登録ステータスは保持されます。" + echo -e "${gl_hong}更新に失敗しました:${gl_bai}已保留原应用登记状态。" action_status=1 fi ;; @@ -3593,7 +3575,7 @@ docker_app_plus() { rm -f /home/docker/${docker_name}_port.conf rm -f /home/docker/${docker_name}_access.conf sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "$app_nameアンインストールする" + send_stats "$app_name 卸载" else echo -e "${gl_hong}アンインストールに失敗しました:${gl_bai}アプリケーションの登録状態は保持されています。" action_status=1 @@ -3601,8 +3583,8 @@ docker_app_plus() { ;; 5) - echo "${docker_name}ドメイン名アクセス設定" - send_stats "${docker_name}ドメイン名アクセス設定" + echo "${docker_name}域名访问设置" + send_stats "${docker_name}域名访问设置" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} local docker_check_name="${docker_app_service:-$docker_name}" @@ -3741,7 +3723,7 @@ f2b_status_xxx() { check_f2b_status() { if command -v fail2ban-client >/dev/null 2>&1; then - check_f2b_status="${gl_lv}インストール済み${gl_bai}" + check_f2b_status="${gl_lv}已安装${gl_bai}" else check_f2b_status="${gl_hui}インストールされていません${gl_bai}" fi @@ -3878,7 +3860,7 @@ f2b_sshd() { fi } -# 基本パラメータ設定: 禁止期間 (bantime)、時間枠 (findtime)、再試行回数 (maxretry) +# 基础参数配置:封禁时长(bantime)、时间窗口(findtime)、重试次数(maxretry) # 例証します: # - /etc/fail2ban/jail.d/sshd.local への書き込みを優先します (デフォルトのjail設定を上書きし、アップグレード時に失われにくくなります) # - Alpine で、jail 名が異なる場合でも、sshd.local と書き込みます。 Fail2Ban は、jail 名に従って一致します。 @@ -3949,7 +3931,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}保存されました${gl_bai}、fail2ban をリロード中..." + echo -e "${gl_lv}已保存${gl_bai}、fail2ban をリロード中..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -4037,7 +4019,7 @@ cd ~ send_stats "nginx環境をインストールする" root_use clear -echo -e "${gl_huang}nginx がインストールされていません。nginx 環境のインストールを開始してください...${gl_bai}" +echo -e "${gl_huang}nginx未安装,开始安装nginx环境...${gl_bai}" install_dependency install_docker install_certbot @@ -4092,7 +4074,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "あなたの$webname建てられました!" + echo "あなたの$webname 搭建好了!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -4111,7 +4093,7 @@ ldnmp_wp() { # wordpress webname="WordPress" yuming="${1:-}" - kpanel_web_progress 10 "WordPress ドメイン名を既存のサイトで検証する" + kpanel_web_progress 10 "正在校验 WordPress 域名与现有站点" send_stats "インストール$webname" echo "導入を開始する$webname" if [ -z "$yuming" ]; then @@ -4170,7 +4152,7 @@ ldnmp_Proxy() { kpanel_web_progress 10 "リバース プロキシ ドメイン名とアップストリーム アドレスの確認" send_stats "インストール$webname" - echo "導入を開始する$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -4340,7 +4322,7 @@ stream_panel() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "選択内容を入力してください:" choice + read -e -p "输入你的选择: " choice case $choice in 1) nginx_install_status @@ -4358,7 +4340,7 @@ stream_panel() { if [[ "$confirm" =~ ^[Yy]$ ]]; then docker rm -f nginx sed -i "/\b${app_id}\b/d" /home/docker/appno.txt - send_stats "ストリームの 4 層プロキシを更新します" + send_stats "更新Stream四层代理" echo "nginxコンテナは削除されました。" else echo "操作はキャンセルされました。" @@ -4369,7 +4351,7 @@ stream_panel() { 4) ldnmp_Proxy_backend_stream add_app_id - send_stats "レイヤー 4 プロキシを追加する" + send_stats "添加四层代理" ;; 5) send_stats "転送設定の編集" @@ -4381,7 +4363,7 @@ stream_panel() { ;; 6) send_stats "転送設定の削除" - read -e -p "削除するサービス名を入力してください:" stream_name + read -e -p "请输入你要删除的服务名: " stream_name rm /home/web/stream.d/$stream_name.conf > /dev/null 2>&1 docker restart nginx send_stats "レイヤ 4 プロキシを削除する" @@ -4406,7 +4388,7 @@ ldnmp_Proxy_backend_stream() { # エージェント名を取得する read -erp "プロキシ転送名を入力してください (例: mysql_proxy):" proxy_name if [ -z "$proxy_name" ]; then - echo "名前を空にすることはできません"; return 1 + echo "名称不能为空"; return 1 fi # リスニングポートの取得 @@ -4524,7 +4506,7 @@ ldnmp_web_status() { echo "------------------------" echo "" - echo -e "データベース:${db_output}" + echo -e "数据库: ${db_output}" echo -e "------------------------" local dbrootpasswd=$(grep -oP 'MYSQL_ROOT_PASSWORD:\s*\K.*' /home/web/docker-compose.yml | tr -d '[:space:]') docker exec mysql mysql -u root -p"$dbrootpasswd" -e "SHOW DATABASES;" 2> /dev/null | grep -Ev "Database|information_schema|mysql|performance_schema|sys" @@ -4539,7 +4521,7 @@ ldnmp_web_status() { echo "操作する" echo "------------------------" echo "1. ドメイン名証明書の適用/更新 2. サイトのドメイン名の複製" - echo "3. サイトのキャッシュをクリアします。 4. 関連するサイトを作成します。" + echo "3. 清理站点缓存 4. 创建关联站点" echo "5. アクセスログの表示 6. エラーログの表示" echo "7. グローバル構成の編集 8. サイト構成の編集" echo "9. サイトデータベースの管理 10. サイト分析レポートの表示" @@ -4646,7 +4628,7 @@ ldnmp_web_status() { break_end ;; 10) - send_stats "サイトデータの表示" + send_stats "查看站点数据" install goaccess goaccess --log-format=COMBINED /home/web/log/nginx/access.log ;; @@ -4983,7 +4965,7 @@ generate_access_urls() { done fi - # HTTPS 構成の処理 + # HTTPS 構成を処理する for port in "${ports[@]}"; do if [[ $port != "8055" && $port != "8056" ]]; then local frps_search_pattern="${ipv4_address}:${port}" @@ -5606,7 +5588,7 @@ kpanel_dns_write_static() { [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" - echo "エラー: DNS 書き込みに失敗し、ロールバックに失敗しました。手動チェックが必要です" + echo "エラー: DNS 書き込みに失敗し、ロールバックに失敗しました。手動検査が必要です" return 1 } rm -f "$desired" "$backup" @@ -5702,7 +5684,7 @@ kpanel_set_dns_noninteractive() { if kpanel_dns_is_ipv4 "$value"; then ipv4_count=$((ipv4_count + 1)) [ "$ipv4_count" -le 2 ] || { - echo "エラー: 最大 2 つの IPv4 DNS アドレス" + echo "エラー: IPv4 DNS アドレスは最大 2 つです" return 1 } elif kpanel_dns_is_ipv6 "$value"; then @@ -5839,6 +5821,82 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "エラー: KPanel SSH ポート プロトコルは root として実行する必要があります" + return 1 + } + [ "$#" -eq 1 ] || { + echo "エラー: SSH ポート プロトコルにはポート番号が必要です" + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "エラー: SSH ポートは 1 ~ 65535 である必要があります" + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "エラー: 管理可能な OpenSSH 構成が見つかりません" + return 1 + } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "エラー: SSH 構成検証またはリスニング チェック ツールは利用できません" + return 1 + } + sshd -t || { + echo "エラー: 現在の SSH 構成構文の検証に失敗しました" + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # 既存の SSH を再利用して主要なビジネスを変更します。アダプテーション層は、非対話型の検証と機械可読な結果のみを担当します。 + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "エラー: SSH ポート変更後のリードバック検証に失敗しました" + return 1 + fi + if ! sshd -t; then + echo "エラー: SSH 構成構文の検証に失敗しました" + return 1 + fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "エラー: 新しい SSH ポートはリスニング状態になっていません" + return 1 + } + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -6064,7 +6122,7 @@ sshkey_panel() { break_end ;; 2) - send_stats "既存の公開キーをインポートする" + send_stats "导入已有公钥" import_sshkey break_end ;; @@ -6093,7 +6151,7 @@ sshkey_panel() { echo "公開鍵情報" cat ${HOME}/.ssh/authorized_keys echo "------------------------" - echo "秘密鍵情報" + echo "私钥信息" cat ${HOME}/.ssh/sshkey echo "------------------------" break_end @@ -6125,7 +6183,7 @@ add_sshpasswd() { read -e -p "パスワードを変更するユーザー名を入力してください (デフォルトは root):" target_user fi - # Enter キーを押します。入力しないでください。デフォルトは root です。 + # Enter キーを押して入力しないでください。デフォルトは root です target_user=${target_user:-root} # ユーザーが存在することを確認する @@ -6223,7 +6281,7 @@ dd_xitong() { root_use echo "システムを再インストールする" echo "--------------------------------" - echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" + echo -e "${gl_hong}知らせ:${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}スクリプトをサポートしてくれたボス bin456789 とボス leitbogioro に感謝します。${gl_bai} " echo -e "${gl_hui}bin456789 プロジェクトのアドレス:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro プロジェクトのアドレス:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" @@ -6251,12 +6309,12 @@ dd_xitong() { echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" - read -e -p "再インストールするシステムを選択してください:" sys_choice + read -e -p "请选择要重装的系统: " sys_choice case "$sys_choice" in 1) - send_stats "debian13を再インストールする" + send_stats "重装debian 13" dd_xitong_3 bash reinstall.sh debian 13 reboot @@ -6278,7 +6336,7 @@ dd_xitong() { exit ;; 4) - send_stats "debian10を再インストールする" + send_stats "重装debian 10" dd_xitong_3 bash reinstall.sh debian 10 reboot @@ -6442,7 +6500,7 @@ dd_xitong() { ;; 41) - send_stats "Windows 11を再インストールする" + send_stats "重装windows11" dd_xitong_2 bash InstallNET.sh -windows 11 -lang "cn" reboot @@ -6643,20 +6701,20 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - - # 正式に削除された古いシステム コードネームとの互換性 (古いパッケージ ライブラリを試すためにリリースを使用するようにフォールバックします) + + # 正式に削除された古いシステム コードネームと互換性があります (リリースを使用して古いパッケージ ライブラリを試すようにフォールバックします) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi - - # 公式には、jammy、focal、bulseye、その他の古いシステムの apt サポートは完全に削除されました。 + + # 官方已彻底移除对 jammy, focal, bullseye 等老系统的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod は現在のシステムのサポートを正式に停止しました ($os_codename) の場合は、Debian12/Ubuntu24 以降にアップグレードしてください。${gl_bai}" return 1 fi if [ -z "$os_codename" ]; then - echo "システムコードネームを取得できません。XanMod ソースを構成できません" + echo "无法获取系统代号,无法配置XanMod源" return 1 fi @@ -6716,7 +6774,7 @@ bbrv3() { done done - echo "この CPU に適合する XanMod カーネル パッケージがソフトウェア ソースに見つかりませんでした。" >&2 + echo "软件源中未找到适配此CPU的XanMod内核包" >&2 return 1 } @@ -6832,7 +6890,7 @@ bbrv3() { echo "ビデオ紹介: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "Debian/Ubuntu のみをサポートします" - echo "データをバックアップしてください。Linux カーネルをアップグレードして BBR3 を有効にします。" + echo "データをバックアップしてください。Linux カーネルをアップグレードし、BBR3 を有効にします。" echo "------------------------------------------------" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -6865,7 +6923,7 @@ elrepo_install() { linux_Settings fi # 検出されたオペレーティング システム情報を印刷する - echo "検出されたオペレーティング システム:$os_name $os_version" + echo "检测到的操作系统: $os_name $os_version" # システムのバージョンに応じて、対応する ELRepo ウェアハウス構成をインストールします。 if [[ "$os_version" == 8 ]]; then echo "ELRepo リポジトリ構成 (バージョン 8) をインストールしています..." @@ -7026,7 +7084,7 @@ clamav() { echo "ビデオ紹介: https://www.bilibili.com/video/BV1TqvZe4EQm?t=0.1" echo "------------------------" echo "これは、主にさまざまな種類のマルウェアを検出して削除するために使用されるオープンソースのウイルス対策ソフトウェア ツールです。" - echo "ウイルス、トロイの木馬、スパイウェア、悪意のあるスクリプト、その他の有害なソフトウェアが含まれます。" + echo "包括病毒、特洛伊木马、间谍软件、恶意脚本和其他有害软件。" echo "------------------------" echo -e "${gl_lv}1.フルスキャン${gl_bai} ${gl_huang}2. 重要なディレクトリをスキャンする${gl_bai} ${gl_kjlan}3. カスタムディレクトリスキャン${gl_bai}" echo "------------------------" @@ -7248,7 +7306,7 @@ net.ipv4.tcp_slow_start_after_idle = 0" net.core.default_qdisc = $QDISC net.ipv4.tcp_congestion_control = $CC -# ── TCPバッファ ── +# ── TCP 缓冲区 ── net.core.rmem_max = $RMEM_MAX net.core.wmem_max = $WMEM_MAX net.core.rmem_default = $(echo "$TCP_RMEM" | awk '{print $2}') @@ -7460,7 +7518,7 @@ Kernel_optimize() { cd ~ clear optimize_web_server - send_stats "ウェブサイト最適化モデル" + send_stats "ウェブサイト最適化モード" ;; 4) cd ~ @@ -7559,7 +7617,7 @@ while true; do case $choice in 1) update_locale "en_US.UTF-8" "en_US.UTF-8" - send_stats "英語に切り替えて" + send_stats "英語に切り替えてください" ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" @@ -7864,7 +7922,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -8229,7 +8287,7 @@ mount_partition() { return 1 fi - echo "パーティションは正常にマウントされました$MOUNT_POINT" + echo "パーティションが正常にマウントされました$MOUNT_POINT" # /etc/fstab をチェックして、UUID またはマウント ポイントがすでに存在するかどうかを確認します。 if grep -qE "UUID=$UUID|[[:space:]]$MOUNT_POINT[[:space:]]" /etc/fstab; then @@ -8364,7 +8422,7 @@ disk_manager() { 5) check_partition ;; *) break ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -8470,7 +8528,7 @@ run_task() { # タスク番号が渡されない場合、ユーザーは入力を求められます。 if [[ -z "$num" ]]; then - read -e -p "実行するタスク番号を入力してください:" num + read -e -p "请输入要执行的任务编号: " num fi local task=$(sed -n "${num}p" "$CONFIG_FILE") @@ -8570,7 +8628,7 @@ schedule_task() { echo "スケジュールされたタスクが作成されました:$cron_job" } -# スケジュールされたタスクを表示する +# 查看定时任务 view_tasks() { echo "現在スケジュールされているタスク:" echo "---------------------------------" @@ -8621,9 +8679,9 @@ rsync_manager() { 5) schedule_task ;; 6) delete_task_schedule ;; 0) break ;; - *) echo "選択が無効です。もう一度お試しください。" ;; + *) echo "无效的选择,请重试。" ;; esac - read -e -p "続行するには Enter キーを押してください..." + read -e -p "Enter を押して続行します..." done } @@ -8641,7 +8699,7 @@ linux_info() { clear echo -e "${gl_kjlan}システム情報を問い合わせています...${gl_bai}" - send_stats "システム情報の問い合わせ" + send_stats "系统信息查询" ip_address @@ -8697,7 +8755,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}ホスト名:${gl_bai}$hostname" echo -e "${gl_kjlan}システムバージョン:${gl_bai}$os_info" - echo -e "${gl_kjlan}Linux バージョン:${gl_bai}$kernel_version" + echo -e "${gl_kjlan}Linux版本: ${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU アーキテクチャ:${gl_bai}$cpu_arch" echo -e "${gl_kjlan}CPUモデル:${gl_bai}$cpu_info" @@ -8726,7 +8784,7 @@ linux_info() { fi echo -e "${gl_kjlan}DNS アドレス:${gl_bai}$dns_addresses" echo -e "${gl_kjlan}位置:${gl_bai}$country $city" - echo -e "${gl_kjlan}システム時間:${gl_bai}$timezone $current_time" + echo -e "${gl_kjlan}系统时间: ${gl_bai}$timezone $current_time" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}実行時間:${gl_bai}$runtime" echo @@ -8767,7 +8825,7 @@ linux_tools() { elif command -v pkg >/dev/null 2>&1; then PM="pkg" else - echo "❌ 認識されないパッケージマネージャー" + echo "❌ 未识别的包管理器" exit 1 fi @@ -8798,7 +8856,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}カールダウンロードツール${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wgetダウンロードツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}3. ${gl_bai}sudo スーパー管理者特権ツール${gl_kjlan}4. ${gl_bai}socat通信接続ツール" - echo -e "${gl_kjlan}5. ${gl_bai}htop システム監視ツール${gl_kjlan}6. ${gl_bai}iftop ネットワークトラフィック監視ツール" + echo -e "${gl_kjlan}5. ${gl_bai}htop 系统监控工具 ${gl_kjlan}6. ${gl_bai}iftop ネットワークトラフィック監視ツール" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP圧縮・解凍ツール${gl_kjlan}8. ${gl_bai}tar GZ 圧縮および解凍ツール" echo -e "${gl_kjlan}9. ${gl_bai}tmux マルチチャネル バックグラウンド実行ツール${gl_kjlan}10. ${gl_bai}ffmpeg ビデオエンコードライブストリーミングツール" echo -e "${gl_kjlan}------------------------" @@ -8808,13 +8866,13 @@ linux_tools() { echo -e "${gl_kjlan}17. ${gl_bai}git バージョン管理システム${gl_kjlan}18. ${gl_bai}opencode AI プログラミング アシスタント${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}マトリックス スクリーンセーバー${gl_kjlan}22. ${gl_bai}走る電車のスクリーンセーバー" - echo -e "${gl_kjlan}26. ${gl_bai}テトリスのミニゲーム${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" - echo -e "${gl_kjlan}28. ${gl_bai}スペースインベーダーのミニゲーム" + echo -e "${gl_kjlan}26. ${gl_bai}俄罗斯方块小游戏 ${gl_kjlan}27. ${gl_bai}ヘビのミニゲーム" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}すべてインストールする${gl_kjlan}32. ${gl_bai}すべてインストール (スクリーンセーバーとゲームを除く)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}すべてアンインストールする" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}41. ${gl_bai}指定されたツールをインストールする${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" + echo -e "${gl_kjlan}41. ${gl_bai}安装指定工具 ${gl_kjlan}42. ${gl_bai}指定されたツールをアンインストールします" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -8833,7 +8891,7 @@ linux_tools() { clear install wget clear - echo "ツールはインストールされており、次のように使用されます。" + echo "工具已安装,使用方法如下:" wget --help send_stats "wgetをインストールする" ;; @@ -8932,7 +8990,7 @@ linux_tools() { clear fzf cd ~ - send_stats "fzfをインストールする" + send_stats "安装fzf" ;; 15) clear @@ -8971,7 +9029,7 @@ linux_tools() { source ~/.bashrc source ~/.profile opencode - send_stats "オープンコードをインストールする" + send_stats "安装opencode" ;; @@ -9121,7 +9179,7 @@ docker_ssh_migration() { list_backups() { local BACKUP_ROOT="/tmp" - echo -e "${gl_kjlan}現在のバックアップ リスト:${gl_bai}" + echo -e "${gl_kjlan}当前备份列表:${gl_bai}" ls -1dt ${BACKUP_ROOT}/docker_backup_* 2>/dev/null || echo "バックアップなし" } @@ -9211,7 +9269,7 @@ docker_ssh_migration() { mapfile -t ENVS < <(jq -r '.[0].Config.Env[] | @sh' "$inspect_file") for e in "${ENVS[@]}"; do ENV_VARS+="-e $e "; done - # ボリュームマッピング + # 卷映射 local VOL_ARGS="" for path in $VOL_PATHS; do VOL_ARGS+="-v $path:$path "; done @@ -9233,14 +9291,14 @@ docker_ssh_migration() { fi chmod +x "$RESTORE_SCRIPT" - echo -e "${gl_lv}バックアップが完了しました:${BACKUP_DIR}${gl_bai}" + echo -e "${gl_lv}备份完成: ${BACKUP_DIR}${gl_bai}" echo -e "${gl_lv}利用可能な復元スクリプト:${RESTORE_SCRIPT}${gl_bai}" } # ---------------------------- - # 削減 + # 还原 # ---------------------------- restore_docker() { @@ -9262,7 +9320,7 @@ docker_ssh_migration() { [[ -f "$path_file" ]] && original_path=$(cat "$path_file") || original_path="" [[ -z "$original_path" ]] && read -e -p "元のパスが見つかりません。復元ディレクトリのパスを入力してください:" original_path - # 作成プロジェクトのコンテナがすでに実行されているかどうかを確認します + # 構成プロジェクトのコンテナがすでに実行されているかどうかを確認します running_count=$(docker ps --filter "label=com.docker.compose.project=$project_name" --format '{{.Names}}' | wc -l) if [[ "$running_count" -gt 0 ]]; then echo -e "${gl_huang}プロジェクトの作成 [$project_name] コンテナはすでに実行されているため、復元をスキップします...${gl_bai}" @@ -9722,6 +9780,382 @@ linux_docker() { +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel 軽量ノードのインストールには root 権限が必要です。" >&2 + return 1 + } + for command_name in curl sha256sum mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "必要なコマンドが欠落しています:${command_name}" >&2 + return 1 + } + done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "必要なコマンドがありません: systemctl" >&2 + return 1 + } + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "必要なコマンドがありません: install (coreutils)" >&2 + return 1 + } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "システム アカウント作成ツールが欠落しています: useradd、systemd-sysusers、または adduser" >&2 + return 1 + fi + [ -d /run/systemd/system ] || { + echo "現在のシステムは systemd を実行していないため、KPanel 軽量ノードをインストールできません。" >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "現在の CPU アーキテクチャは、KPanel 軽量ノードをサポートしていません。" >&2 + return 1 + ;; + esac +} + +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "既存の kejilion-node アカウントのプライマリ グループは安全ではないため、続行は拒否されます。" >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "システム グループ作成ツールが見つかりません: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel 軽量ノードの低特権アカウントの作成に失敗しました。" >&2 + return 1 + } +} + +kpanel_node_write_updater() { + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null +} + +kpanel_node_join() { + local token="${1:-}" node_name resume_enrollment=false + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "ライトウェイトノードのアクセス権限が無効です。" >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "ライトウェイトノードのアクセス権限が無効です。" >&2 + return 2 + } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "完了したノード認証が検出されました。ネイティブ サービスの有効化を続行します。" + else + echo "このマシンには不完全な KPanel ノード構成があります。最初に k kpanel ノードのアンインストールを実行してください。" >&2 + return 1 + fi + fi + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join + return 1 + fi + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + echo "ノード許可は保存されましたが、構成許可の修復は失敗しました。続行するにはアクセスコマンドを再度実行してください。" >&2 + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + echo "ノード認証は保存されましたが、systemd ユニットへの書き込みに失敗しました。続行するにはアクセスコマンドを再度実行してください。" >&2 + return 1 + fi + if ! kpanel_node_activate; then + echo "KPanel 軽量ノードの認証は保存されましたが、サービスの開始に失敗しました。 systemd を修復し、access コマンドを再度実行してインストールを続行します。" >&2 + return 1 + fi + echo "KPanel 軽量ノードが接続されており、後で自動的に更新されます。" +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel軽量ノードがインストールされていません。" >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel軽量ノードがインストールされていません。" >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "KPanel 軽量ノードをアンインストールするには、root 権限が必要です。" >&2 + return 1 + } + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true + echo "KPanel 軽量ノードがローカル マシンからアンインストールされました。センターのオフライン記録はクラスターページで削除する必要があります。" +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "使用法: k kpanel ノード結合 <認証> |ステータス |更新 |アンインストールする" >&2 + return 2 + ;; + esac +} + kpanel_test_catalog() { cat <<'KPANEL_TEST_CATALOG' KPANEL_TEST_CATEGORY access IP 与解锁 @@ -9918,7 +10352,7 @@ linux_test() { echo -e "${gl_kjlan}15. ${gl_bai}nxtrace は IP バックホール テスト スクリプトを指定します" echo -e "${gl_kjlan}16. ${gl_bai}ludashi2020 3つのネットワーク回線テスト" echo -e "${gl_kjlan}17. ${gl_bai}i-abc 多機能速度テスト スクリプト" - echo -e "${gl_kjlan}18. ${gl_bai}NetQuality ネットワーク品質チェック スクリプト${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}18. ${gl_bai}NetQuality 网络质量体检脚本 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}19. ${gl_bai}TcpQuality TCP 再送検出スクリプト${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9928,7 +10362,7 @@ linux_test() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}総合的なテスト" - echo -e "${gl_kjlan}31. ${gl_bai}ベンチパフォーマンステスト" + echo -e "${gl_kjlan}31. ${gl_bai}bench 性能测试" echo -e "${gl_kjlan}32. ${gl_bai}Spiritysdx融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}ノードクオリティ融合モンスターの評価${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" @@ -9955,7 +10389,7 @@ linux_test() { ;; 4) clear - send_stats "xykt_IP 品質チェック スクリプト" + send_stats "xykt_IP质量体检脚本" bash <(curl -Ls IP.Check.Place) ;; @@ -9995,7 +10429,7 @@ linux_test() { echo "上海モバイル: 211.136.112.200" echo "広州電信: 58.60.188.222" echo "広州チャイナユニコム: 210.21.196.6" - echo "広州モバイル: 120.196.165.24" + echo "广州移动: 120.196.165.24" echo "成都電信: 61.139.2.69" echo "成都チャイナユニコム: 119.6.6.6" echo "成都携帯電話: 211.137.96.205" @@ -10095,7 +10529,7 @@ linux_Oracle() { echo -e "${gl_kjlan}3. ${gl_bai}DD 再インストール システム スクリプト" echo -e "${gl_kjlan}4. ${gl_bai}探偵R起動スクリプト" echo -e "${gl_kjlan}5. ${gl_bai}ROOTパスワードログインモードを有効にする" - echo -e "${gl_kjlan}6. ${gl_bai}IPV6回復ツール" + echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢复工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -10117,20 +10551,20 @@ linux_Oracle() { local DEFAULT_MEM_UTIL=20 local DEFAULT_SPEEDTEST_INTERVAL=120 - # CPU コアの数と占有率を入力するようユーザーに求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 + # ユーザーに CPU コアの数と占有率を入力するよう求めます。ユーザーが Enter キーを押すと、デフォルト値が使用されます。 read -e -p "CPU コアの数を入力してください [デフォルト:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} read -e -p "CPU 使用率の範囲 (例: 10 ~ 20) を入力してください [デフォルト:$DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} - read -e -p "メモリ使用率を入力してください [デフォルト:$DEFAULT_MEM_UTIL]: " mem_util + read -e -p "请输入内存占用百分比 [默认: $DEFAULT_MEM_UTIL]: " mem_util local mem_util=${mem_util:-$DEFAULT_MEM_UTIL} read -e -p "Speedtest の間隔時間 (秒) を入力してください [デフォルト:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Dockerコンテナを実行する + # 运行Docker容器 docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -10158,7 +10592,7 @@ linux_Oracle() { 3) clear - echo "システムを再インストールする" + echo "重装系统" echo "--------------------------------" echo -e "${gl_hong}知らせ:${gl_bai}再インストールすると接続が切れる可能性がありますので、不安な方はご注意ください。再インストールには 15 分程度かかることが予想されますので、事前にデータをバックアップしてください。" read -e -p "続行してもよろしいですか? (はい/いいえ):" choice @@ -10443,7 +10877,7 @@ ldnmp_environment_install() { case "$profile" in full) kpanel_ldnmp_event install 15 "完全な LDNMP のインストール"; ldnmp_install_all ;; nginx) kpanel_ldnmp_event install 15 "nginxのインストール"; nginx_install_all ;; - *) echo "サポートされていないインストール形式" >&2; return 2 ;; + *) echo "不支持的安装形态" >&2; return 2 ;; esac kpanel_ldnmp_event verify 90 "環境の検証" docker exec nginx nginx -t >/dev/null 2>&1 || return 1 @@ -12093,7 +12527,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ API プロバイダーが検出されず、モデルの同期がスキップされました') + print('ℹ️ 未检测到 API providers,跳过模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -12200,7 +12634,7 @@ def rebind_defaults_before_delete(name): return False defaults[fk] = repl changed = True - summary.append(f'🔁 削除前に切り替えられた {fk}: {val} -> {repl}') + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') return True @@ -12389,7 +12823,7 @@ if changed: else: for line in summary: print(line) - print('ℹ️ 同期は必要ありません: 構成はすでに上流の /models と一致しています') + print('ℹ️ 无需同步:配置已与上游 /models 保持一致') PY } @@ -12435,7 +12869,7 @@ PY } view_logs() { - echo "OpenClaw ステータス ログを表示する" + echo "查看 OpenClaw 状态日志" send_stats "OpenClaw ログを表示する" openclaw status openclaw gateway status @@ -12614,7 +13048,7 @@ EOF if [[ $? -eq 0 ]]; then echo "✅ プロバイダーが追加しました:$provider_name" - echo "✅ デフォルトのモデルにのみ書き込みます:$default_model" + echo "✅ 仅写入默认模型:$default_model" return 0 else echo "❌ 構成の挿入に失敗しました" @@ -12642,15 +13076,15 @@ EOF base_url="${base_url%/}" # 3. API Key - read -rsp "API キーを入力してください (入力は表示されません):" api_key + read -rsp "请输入 API Key (输入不显示): " api_key echo while [[ -z "$api_key" ]]; do echo "❌ API キーを空にすることはできません" - read -rsp "API キーを入力してください:" api_key + read -rsp "请输入 API Key: " api_key echo done - # 4. API タイプの検出/判断が行われなくなりました。プロトコルはユーザー自身によって選択および維持されます + # 4. API タイプを検出/決定しなくなりました。プロトコルはユーザー自身によって選択および維持されます # 5. モデルリストの取得 echo "🔍 利用可能なモデルのリストを取得中..." @@ -12679,7 +13113,7 @@ EOF # 5. デフォルトのモデルを選択します echo - read -erp "デフォルトのモデル ID (またはシリアル番号、最初のものを使用する場合は空白のままにしておきます) を入力してください:" input_model + read -erp "デフォルトのモデル ID (またはシリアル番号。最初のものを使用する場合は空白のままにします) を入力してください。" input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -12698,7 +13132,7 @@ EOF echo "Base URL : $base_url" echo "API Key : ${api_key:0:8}****" echo "デフォルトのモデル:$default_model" - echo "モデルの総数:$model_count" + echo "模型总数 : $model_count" echo "======================" read -erp "他の利用可能なモデルをすべて同時に追加しますか? (y/N):" confirm @@ -12820,7 +13254,7 @@ for idx, name in enumerate(sorted(providers.keys()), start=1): api = provider.get('api', '') api_key = provider.get('apiKey') - latency_raw = '検出されませんでした' + latency_raw = '未检测' if api in SUPPORTED_APIS: if isinstance(base_url, str) and base_url != '-' and isinstance(api_key, str) and api_key: try: @@ -13069,7 +13503,7 @@ PY2 local rc=$? case "$rc" in 0) - echo "✅ 同期実行完了" + echo "✅ 同期実行が完了しました" start_gateway ;; 2) @@ -13395,7 +13829,7 @@ PY } openclaw_api_manage_menu() { - send_stats "OpenClaw APIの入り口" + send_stats "OpenClaw APIの入口" while true; do clear echo "=======================================" @@ -13743,13 +14177,13 @@ PYTHON_EOF return 0 else if ! command -v gum >/dev/null 2>&1 || ! gum --version >/dev/null 2>&1; then - echo "ガムは使用できなくなり、古い入力モードに戻ります。" + echo "gum 不可用,返回旧版输入模式。" sleep 1 continue fi gum style --foreground "$orange" --bold "モデル管理" gum style --foreground "$orange" "利用可能なモデル (認証=はい):${model_count}" - gum style --foreground "$orange" "現在のデフォルト:${default_model}" + gum style --foreground "$orange" "当前默认:${default_model}" echo "" gum style --faint "↑↓ 選択 / Enter でテスト / Esc で終了" echo "" @@ -14036,9 +14470,9 @@ PYTHON_EOF while true; do clear echo "========================================" - echo "プラグイン管理(インストール/削除)" + echo " 插件管理 (安装/删除) " echo "========================================" - echo "現在のプラグインのリスト:" + echo "当前插件列表:" openclaw plugins list echo "--------------------------------------------------------" echo "推奨される一般的に使用されるプラグイン ID (括弧内の ID をコピーするだけです):" @@ -14056,7 +14490,7 @@ PYTHON_EOF echo "- [memory-lancedb] # メモリの強化 (ベクターデータベース)" echo "- [copilot-proxy] # コパイロットインターフェイスの転送" echo "" - echo "⚙️機能拡張:" + echo "⚙️ 功能扩展:" echo "- [lobster] # 承認フロー(手動確認あり)" echo "- [voice-call] # 音声通話機能" echo "- [nostr] # 暗号化されたプライベートチャット" @@ -14116,11 +14550,11 @@ PYTHON_EOF continue fi - echo "📥 ローカルに見つかりません。ダウンロードしてインストールしてください:$plugin_full" + echo "📥 本地未发现,尝试下载安装: $plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then - echo "✅ ダウンロードが成功しました。アクティブ化されています..." + echo "✅ ダウンロードに成功しました。アクティブ化しています..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -14153,7 +14587,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." start_gateway fi break_end @@ -14166,7 +14600,7 @@ PYTHON_EOF while true; do clear echo "========================================" - echo "スキル管理(インストール/削除)" + echo " 技能管理 (安装/删除) " echo "========================================" echo "現在インストールされているスキル:" openclaw skills list @@ -14184,8 +14618,8 @@ PYTHON_EOF echo "bluebubbles # BlueBubbles で iMessage を完璧に送受信" echo "ヒマラヤ # 端末メール管理(IMAP/SMTP強力ツール)" echo "要約 # ウェブページ/ポッドキャスト/YouTube ビデオ コンテンツのワンクリック要約" - echo "openhue # Philips Hue スマート照明シーンを制御する" - echo "video-frames # ビデオフレーム抽出とショートクリップ編集 (ffmpeg ドライバー)" + echo "openhue # Philips Hue スマート照明シーンの制御" + echo "video-frames # 视频抽帧与短片剪辑 (ffmpeg 驱动)" echo "openai-whisper # ローカル音声をテキストに変換 (オフラインのプライバシー保護)" echo "coding-agent # Claude Code/Codex などのプログラミング アシスタントを自動的に実行する" echo "----------------------------------------" @@ -14242,7 +14676,7 @@ PYTHON_EOF echo "スキルのインストール:$skill_name ..." if npx clawhub install "$skill_name" --yes --no-input 2>/dev/null || npx clawhub install "$skill_name"; then - echo "✅ スキル$skill_nameインストールが成功しました。" + echo "✅ スキル$skill_name 安装成功。" success_list="$success_list $skill_name" changed=true else @@ -14250,7 +14684,7 @@ PYTHON_EOF failed_list="$failed_list $skill_name" fi else - echo "🗑️ スキルの削除:$skill_name" + echo "🗑️ 正在删除技能: $skill_name" npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" @@ -14271,7 +14705,7 @@ PYTHON_EOF [ -n "$skipped_list" ] && echo "⏭️スキップ:$skipped_list" if [ "$changed" = true ]; then - echo "🔄 OpenClaw サービスを再起動して変更をロードしています..." + echo "🔄 変更をロードするために OpenClaw サービスを再起動しています..." start_gateway fi break_end @@ -14523,7 +14957,7 @@ openclaw_json_get_bool() { case $bot_choice in 1) - read -e -p "TG ロボットが受信した接続コード (NYA99R2F など) を入力してください (終了するには 0 を入力します)。" code + read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve telegram "$code" @@ -14536,7 +14970,7 @@ openclaw_json_get_bool() { break_end ;; 3) - read -e -p "WhatsApp で受信した接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code + read -e -p "WhatsApp で受け取った接続コード (例: NYA99R2F) を入力してください (終了するには 0 を入力してください):" code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "エラー: 接続コードを空にすることはできません。"; sleep 1; continue; fi openclaw pairing approve whatsapp "$code" @@ -14653,7 +15087,7 @@ EOF openclaw_offer_transfer_hint() { local file_path="$1" - echo "バックアップ ファイルは次の方法でダウンロードできます。" + echo "可使用以下方式下载备份文件:" echo "- ローカルパス:$file_path" echo "- scp の例: scp root@yourserver:$file_path ./" echo "- またはSFTPクライアントを使用してダウンロード" @@ -15428,7 +15862,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com にアクセスできます") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com にアクセスできない可能性があります (国内/制限されたネットワークの疑い)") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com にアクセスできない可能性があります (国内/制限付きネットワークの疑い)") fi if [ "$qmd_ok" = "true" ]; then @@ -15529,7 +15963,7 @@ PY echo "✅ パンはすでに存在します" return 0 fi - echo "⬇️バンをインストール..." + echo "⬇️ 安装 bun..." if command -v curl >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash elif command -v wget >/dev/null 2>&1; then @@ -15672,7 +16106,7 @@ PY echo "✅memory.backendはすでにqmdです" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅memory.backend=qmdが設定されています" + echo "✅ 已设置 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") @@ -15708,7 +16142,7 @@ EOF echo "✅memory.backendはすでに組み込まれています" else openclaw_memory_config_set "memory.backend" "builtin" - echo "✅memory.backend=builtinが設定されています" + echo "✅ 已设置 memory.backend=builtin" fi provider=$(openclaw_memory_config_get "agents.defaults.memorySearch.provider") if [ "$provider" = "local" ]; then @@ -15823,7 +16257,7 @@ EOF echo "=======================================" echo "1. QMD" echo "2. Local" - echo "3.オート(自動選択)" + echo "3. Auto(自动选择)" echo "0. 前のレベルに戻ります" echo "---------------------------------------" read -e -p "選択肢を入力してください:" auto_choice @@ -15844,7 +16278,7 @@ EOF return 0 ;; *) - echo "選択が無効です。もう一度お試しください。" + echo "无效的选择,请重试。" sleep 1 ;; esac @@ -15904,7 +16338,7 @@ EOF echo "=======================================" echo "インデックス修復診断" echo "=======================================" - echo "現在 includeDefaultMemory: ${include_dm:-not set}" + echo "当前 includeDefaultMemory: ${include_dm:-未设置}" echo "" if [ "$include_dm" = "false" ]; then echo "⚠️ includeDefaultMemory=false が検出されました" @@ -15949,7 +16383,7 @@ EOF case "$backend" in qmd) current_label="QMD" ;; builtin|local) current_label="Local" ;; - *) current_label="未設定" ;; + *) current_label="未配置" ;; esac echo "現在の計画:$current_label" echo "" @@ -16019,7 +16453,7 @@ EOF echo "メモリファイルが見つかりません。" return 0 fi - echo "番号 |帰属 |サイズ |変更時間" + echo "编号 | 归属 | 大小 | 修改时间" echo "---------------------------------------" local i file rel size mtime for i in "${!OPENCLAW_MEMORY_FILES[@]}"; do @@ -16042,7 +16476,7 @@ EOF local default_lines=120 local start_line count echo "書類:$file" - echo "総行数:$total_lines" + echo "合計行数:$total_lines" read -e -p "開始行を入力してください (Enter キーを押すとデフォルトで行の終わりになります)$default_linesわかりました):" start_line read -e -p "表示する行数を入力してください (デフォルトでは Enter キーを押します)$default_lines): " count [ -z "$count" ] && count=$default_lines @@ -16140,9 +16574,9 @@ EOF echo "4. メモリ ソリューション (QMD/ローカル/自動)" echo "5. 検索テスト (インデックスが機能していることを確認します)" echo "6. ディープステート検出 (組み込みモデルのチェック)" - echo "0. 前のレベルに戻ります" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "選択肢を入力してください:" memory_choice + read -e -p "请输入你的选择: " memory_choice case "$memory_choice" in 1) echo "メモリインデックスは間もなく更新されます。" @@ -16259,7 +16693,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ OpenClaw が検出されず、OpenClaw Gateway を再起動できません。" + echo "❌ openclaw が検出されず、OpenClaw Gateway を再起動できません。" return 1 fi echo "OpenClaw ゲートウェイを再起動しています..." @@ -16501,7 +16935,7 @@ except Exception: print("(設定ファイルの解析に失敗しました)") ' else - echo "(未構成。システムの組み込みセキュリティ ポリシーの使用が強制されます)" + echo " (未配置,强制使用系统内置安全兜底策略)" fi } @@ -16539,7 +16973,7 @@ except Exception: openclaw_permission_update_exec_approvals "allowlist" "on-miss" "deny" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには依然として承認が必要です)${gl_bai}" + echo -e "${gl_lv}✅ 開発拡張モードに切り替えました (権限昇格は許可されていますが、一般的な危険なコマンドには引き続き承認が必要です)${gl_bai}" } openclaw_permission_apply_full() { @@ -17074,7 +17508,7 @@ agents=json.loads(sys.argv[1] or "[]") bindings=json.loads(sys.argv[2] or "[]") print("---------------------------------------") if not agents: - print("⚠️ 設定されたエージェントが見つかりません。") + print("⚠️ 未发现已配置智能体。") else: for item in agents: ws = item.get("workspace") or "" @@ -17109,7 +17543,7 @@ print("✅マルチエージェントのヘルスチェックが完了しまし [ -n "$new_name" ] && cmd="$cmd --name $new_name" [ -n "$new_emoji" ] && cmd="$cmd --emoji $new_emoji" echo "IDENTITY.md から ID 情報を自動的に読み取ることもできます。" - read -e -p "IDENTITY.md から読み取りますか? (y/n):" from_id + read -e -p "是否从 IDENTITY.md 读取?(y/n): " from_id if [ "$from_id" = "y" ]; then cmd="openclaw agents set-identity --agent $agent_id --from-identity" fi @@ -17118,7 +17552,7 @@ print("✅マルチエージェントのヘルスチェックが完了しまし openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "期限切れ/冗長セッション データを間もなくクリーンアップします..." + echo "即将清理过期/冗余会话数据..." read -e -p "確認するには「yes」と入力します。" confirm [ "$confirm" != "yes" ] && { echo "キャンセル"; return 0; } openclaw sessions cleanup @@ -17139,7 +17573,7 @@ print("✅マルチエージェントのヘルスチェックが完了しまし echo "4. 新しいルート バインディングを追加する" echo "5.ルートバインディングを削除する" echo "6. セッションの概要を表示する" - echo "7. マルチエージェントのヘルスチェックを実行する" + echo "7. 运行多智能体健康检查" echo "8. エージェントのアイデンティティ (名前/絵文字) を変更します" echo "9. 期限切れのセッションをクリーンアップする" echo "0. 前のレベルに戻ります" @@ -17173,13 +17607,13 @@ openclaw_backup_restore_menu() { openclaw_backup_render_file_list echo "---------------------------------------" echo "1. メモリ全体をバックアップする" - echo "2. メモリ全体を復元する" + echo "2. 还原记忆全量" echo "3. OpenClaw プロジェクトをバックアップします (デフォルトのセーフ モード)" echo "4. OpenClaw プロジェクトの復元 (高度/高リスク)" echo "5. バックアップファイルを削除する" echo "0. 前のレベルに戻ります" echo "---------------------------------------" - read -e -p "選択肢を入力してください:" backup_choice + read -e -p "请输入你的选择: " backup_choice case "$backup_choice" in 1) openclaw_memory_backup_export ;; @@ -17422,7 +17856,7 @@ refresh_apps_catalog() { install git || return 1 if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then - echo -e "${gl_hong}間違い:${gl_bai}${apps_dir}すでに存在しますが、App Market Git リポジトリではないため、上書きは拒否されます。" + echo -e "${gl_hong}错误: ${gl_bai}${apps_dir}すでに存在しますが、App Market Git リポジトリではないため、上書きは拒否されます。" return 1 fi if [ ! -d "$apps_dir/.git" ]; then @@ -17472,23 +17906,23 @@ while true; do echo -e "${gl_kjlan}7. ${color7}Nezha Probe VPS 監視パネル${gl_kjlan}8. ${color8}QBオフラインBT磁気ダウンロードパネル" echo -e "${gl_kjlan}9. ${color9}Poste.io メール サーバー プログラム${gl_kjlan}10. ${color10}RocketChat 複数人オンライン チャット システム" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}11. ${color11}ZenTao プロジェクト管理ソフトウェア${gl_kjlan}12. ${color12}Qinglong パネルのスケジュールされたタスク管理プラットフォーム" + echo -e "${gl_kjlan}11. ${color11}禅道项目管理软件 ${gl_kjlan}12. ${color12}Qinglong パネルのスケジュールされたタスク管理プラットフォーム" echo -e "${gl_kjlan}13. ${color13}Cloudreve ネットワークディスク${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}シンプルなピクチャーベッド画像管理プログラム" - echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}Speedtest スピードテストパネル" + echo -e "${gl_kjlan}15. ${color15}emby マルチメディア管理システム${gl_kjlan}16. ${color16}Speedtest测速面板" echo -e "${gl_kjlan}17. ${color17}AdGuardHome はアドウェアを削除します${gl_kjlan}18. ${color18}Onlyofficeオンラインオフィス OFFICE" echo -e "${gl_kjlan}19. ${color19}Leichi WAF ファイアウォール パネル${gl_kjlan}20. ${color20}ポーターコンテナ管理パネル" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}21. ${color21}VScode Web バージョン${gl_kjlan}22. ${color22}UptimeKuma監視ツール" - echo -e "${gl_kjlan}23. ${color23}メモウェブメモ${gl_kjlan}24. ${color24}Webtop リモート デスクトップ Web バージョン${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}23. ${color23}Memos网页备忘录 ${gl_kjlan}24. ${color24}Webtop リモート デスクトップ Web バージョン${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud ネットワーク ディスク${gl_kjlan}26. ${color26}QD-Today スケジュールされたタスク管理フレームワーク" echo -e "${gl_kjlan}27. ${color27}Dockge コンテナ スタック管理パネル${gl_kjlan}28. ${color28}LibreSpeed 速度テストツール" echo -e "${gl_kjlan}29. ${color29}searxng 集約検索ステーション${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrismプライベートアルバムシステム" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}31. ${color31}StirlingPDF ツール コレクション${gl_kjlan}32. ${color32}無料のオンライングラフ作成ソフトウェアdrawio${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全 ${gl_kjlan}32. ${color32}無料のオンライングラフ作成ソフトウェアdrawio${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel ナビゲーション パネル${gl_kjlan}34. ${color34}Pingvin-Share ファイル共有プラットフォーム" - echo -e "${gl_kjlan}35. ${color35}ミニマリストの友達の輪${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAIチャットアグリゲーションサイト" echo -e "${gl_kjlan}37. ${color37}MyIP ツールボックス${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}Xiaoya alistファミリーバケット" - echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh Web版 SSH接続ツール" + echo -e "${gl_kjlan}39. ${color39}Bililive ライブ配信録画ツール${gl_kjlan}40. ${color40}webssh网页版SSH连接工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}41. ${color41}マウス管理パネル${gl_kjlan}42. ${color42}Nexterm リモート接続ツール" echo -e "${gl_kjlan}43. ${color43}RustDesk リモート デスクトップ (サーバー)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk リモート デスクトップ (リレー)${gl_huang}★${gl_bai}" @@ -17504,36 +17938,36 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}オンライン翻訳サーバー${gl_kjlan}62. ${color62}RAGFlow 大規模モデルのナレッジ ベース" echo -e "${gl_kjlan}63. ${color63}OpenWebUI セルフホスト型 AI プラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}ITツールツールボックス" - echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp ビデオ ダウンロード ツール" + echo -e "${gl_kjlan}65. ${color65}n8n自動ワークフロープラットフォーム${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" echo -e "${gl_kjlan}67. ${color67}ddns-go ダイナミック DNS 管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 証明書管理プラットフォーム" - echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstrBot チャットボット フレームワーク" + echo -e "${gl_kjlan}69. ${color69}SFTPGo ファイル転送ツール${gl_kjlan}70. ${color70}AstBot チャットボット フレームワーク" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome プライベート ミュージック サーバー${gl_kjlan}72. ${color72}bitwarden パスワードマネージャー${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV プライベートムービー${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" - echo -e "${gl_kjlan}75. ${color75}メロディー音楽の魔法使い${gl_kjlan}76. ${color76}オンライン DOS 古いゲーム" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV のプライベート ムービー" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}オンライン DOS 古いゲーム" echo -e "${gl_kjlan}77. ${color77}Thunder オフライン ダウンロード ツール${gl_kjlan}78. ${color78}PandaWiki インテリジェント文書管理システム" echo -e "${gl_kjlan}79. ${color79}Beszel サーバーの監視${gl_kjlan}80. ${color80}リンクワーデンのブックマーク管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}81. ${color81}JitsiMeet ビデオ会議${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" + echo -e "${gl_kjlan}81. ${color81}JitsiMeet视频会议 ${gl_kjlan}82. ${color82}gpt-load 高性能 AI 透過プロキシ" echo -e "${gl_kjlan}83. ${color83}komariサーバー監視ツール${gl_kjlan}84. ${color84}Wallos の個人財務管理ツール" echo -e "${gl_kjlan}85. ${color85}イミッチピクチャービデオマネージャー${gl_kjlan}86. ${color86}ジェリーフィンメディア管理システム" echo -e "${gl_kjlan}87. ${color87}SyncTV は一緒に映画を見るための素晴らしいツールです${gl_kjlan}88. ${color88}Owncast の自己ホスト型ライブ ストリーミング プラットフォーム" echo -e "${gl_kjlan}89. ${color89}FileCodeBox ファイルエクスプレス${gl_kjlan}90. ${color90}マトリックス分散型チャットプロトコル" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}91. ${color91}gitea プライベート コード リポジトリ${gl_kjlan}92. ${color92}FileBrowser ファイルマネージャー" - echo -e "${gl_kjlan}93. ${color93}Dufs のミニマリスト静的ファイル サーバー${gl_kjlan}94. ${color94}Gopeed高速ダウンロードツール" + echo -e "${gl_kjlan}93. ${color93}Dufs极简静态文件服务器 ${gl_kjlan}94. ${color94}Gopeed高速ダウンロードツール" echo -e "${gl_kjlan}95. ${color95}ペーパーレス文書管理プラットフォーム${gl_kjlan}96. ${color96}2FAuth セルフホスト型 2 段階認証システム" echo -e "${gl_kjlan}97. ${color97}WireGuard ネットワーキング (サーバー)${gl_kjlan}98. ${color98}WireGuard ネットワーキング (クライアント)" echo -e "${gl_kjlan}99. ${color99}DSM Synology 仮想マシン${gl_kjlan}100. ${color100}Syncthing ピアツーピア ファイル同期ツール" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat 複数人オンライン チャット システム" + echo -e "${gl_kjlan}101. ${color101}AI動画生成ツール${gl_kjlan}102. ${color102}VoceChat多人在线聊天系统" echo -e "${gl_kjlan}103. ${color103}Umami ウェブサイト統計ツール${gl_kjlan}104. ${color104}ストリーム 4 層プロキシ転送ツール" echo -e "${gl_kjlan}105. ${color105}思源ノート${gl_kjlan}106. ${color106}Drawnix オープンソース ホワイトボード ツール" echo -e "${gl_kjlan}107. ${color107}PanSou ネットワークディスク検索${gl_kjlan}108. ${color108}LangBot チャットボット" echo -e "${gl_kjlan}109. ${color109}ZFileオンラインネットワークディスク${gl_kjlan}110. ${color110}カラオケのブックマーク管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}マルチフォーマットファイル変換ツール${gl_kjlan}112. ${color112}Lucky 大規模イントラネット侵入ツール" - echo -e "${gl_kjlan}113. ${color113}Firefoxブラウザ${gl_kjlan}114. ${color114}OpenClaw ボット管理ツール${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw ボット管理ツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}115. ${color115}ヘルメスロボット管理ツール${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}サードパーティ製アプリケーションのリスト" @@ -17546,7 +17980,7 @@ while true; do local app_text=$(grep "app_text=" "$f" | cut -d'=' -f2 | tr -d '"' | tr -d "'") # インストールステータスを確認します (appno.txt の ID と一致します)。 - # ここで、appno.txtに記録されているのはbase_name(つまりファイル名)であると仮定します。 + # 这里假设 appno.txt 中记录的是 base_name (即文件名) if echo "$app_numbers" | grep -q "^$base_name$"; then # インストールされている場合: showbase_name - description [インストール済み] (緑色) echo -e "${gl_kjlan}$base_name${gl_bai} - ${gl_lv}$app_text[インストール済み]${gl_bai}" @@ -17665,7 +18099,7 @@ while true; do local docker_describe="ドメイン名アクセスの追加をサポートしていない Nginx リバース プロキシ ツール パネル。" local docker_url="公式サイト紹介:https://nginxproxymanager.com/" - local docker_use="echo \"初期ユーザー名: admin@example.com\"" + local docker_use="echo \"初始用户名: admin@example.com\"" local docker_passwd="echo \"初期パスワード:changeme\"" local app_size="1" @@ -17759,7 +18193,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "ネザモニタリング$check_docker $update_status" + echo -e "哪吒监控 $check_docker $update_status" echo "オープンソースの軽量で使いやすいサーバー監視および運用保守ツール" echo "公式 Web サイト構築ドキュメント: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -17768,7 +18202,7 @@ while true; do fi echo "" echo "------------------------" - echo "1. 使用方法" + echo "1. 使用" echo "------------------------" echo "0. 前のメニューに戻る" echo "------------------------" @@ -17819,7 +18253,7 @@ while true; do } - local docker_describe="qbittorrent オフライン BT 磁気ダウンロード サービス" + local docker_describe="qbittorrent离线BT磁力下载服务" local docker_url="公式サイト紹介:https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" @@ -17863,7 +18297,7 @@ while true; do echo "------------------------" echo "1. インストール 2. アップデート 3. アンインストール" echo "------------------------" - echo "0. 前のメニューに戻る" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "選択内容を入力してください:" choice @@ -17907,7 +18341,7 @@ while true; do clear echo "poste.ioがインストールされました" echo "------------------------" - echo "次のアドレスを使用して poste.io にアクセスできます。" + echo "您可以使用以下地址访问poste.io:" echo "https://$yuming" echo "" @@ -17987,7 +18421,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat がインストールされました" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -18067,7 +18501,7 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="クラウドリーブネットワークディスク" + local app_name="cloudreve网盘" local app_text="Cloudreve は、複数のクラウド ストレージをサポートするネットワーク ディスク システムです。" local app_url="ビデオ紹介: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" @@ -18149,7 +18583,7 @@ while true; do } - local docker_describe="emby は、サーバー上でビデオとオーディオを整理し、クライアント デバイスにオーディオとビデオをストリーミングするために使用できるマスター/スレーブ アーキテクチャのメディア サーバー ソフトウェアです。" + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" local docker_url="公式サイト紹介:https://emby.media/" local docker_use="" local docker_passwd="" @@ -18230,7 +18664,7 @@ while true; do } - local docker_describe="Onlyoffice はオープンソースのオンライン オフィス ツールで、非常に強力です。" + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" local docker_url="公式サイト紹介:https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -18415,7 +18849,7 @@ while true; do docker_rum() { read -e -p "ログインユーザー名を設定します:" admin - read -e -p "ログインユーザーのパスワードを設定します。" admin_password + read -e -p "设置登录用户密码: " admin_password docker run -d \ --name=webtop \ --security-opt seccomp=unconfined \ @@ -18546,7 +18980,7 @@ while true; do } local docker_describe="searxng は非公開の検索エンジン サイトです。" - local docker_url="公式サイト紹介:https://hub.docker.com/r/alandoyle/searxng" + local docker_url="官网介绍: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" local app_size="1" @@ -18675,8 +19109,8 @@ while true; do stonith404/pingvin-share } - local docker_describe="Pingvin Share は自己構築可能なファイル共有プラットフォームであり、WeTransfer の代替品です" - local docker_url="公式サイト紹介:${gh_proxy}github.com/stonith404/pingvin-share" + local docker_describe="Pingvin Share 是一个可自建的文件分享平台,是 WeTransfer 的一个替代品" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -18702,7 +19136,7 @@ while true; do } - local docker_describe="ミニマリストの瞬間、模倣性の高いWeChatの瞬間、あなたの素晴らしい人生を記録してください" + local docker_describe="ミニマリストの WeChat モーメント、模倣性の高い WeChat モーメント、あなたの素晴らしい人生を記録します" local docker_url="公式サイト紹介:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"アカウント: admin パスワード: a123456\"" local docker_passwd="" @@ -18756,7 +19190,7 @@ while true; do ;; 38|xiaoya) - send_stats "シャオヤファミリーバケツ" + send_stats "小雅全家桶" clear install_docker check_disk_space 1 @@ -18939,7 +19373,7 @@ while true; do } - local docker_describe="Go を使用して実装された GHProxy は、一部の領域で Github リポジトリのプルを高速化するために使用されます。" + local docker_describe="使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取。" local docker_url="公式サイト紹介:${gh_https_url}github.com/WJQSERVER-STUDIO/ghproxy" local docker_use="" local docker_passwd="" @@ -18981,7 +19415,7 @@ while true; do docker rmi -f grafana/grafana:latest rm -rf /home/docker/monitoring - echo "アプリがアンインストールされました" + echo "应用已卸载" } docker_app_plus @@ -19005,7 +19439,7 @@ while true; do } local docker_describe="これは Prometheus ホスト データ収集コンポーネントです。監視対象ホストにデプロイしてください。" - local docker_url="公式サイト紹介:${gh_https_url}github.com/prometheus/node_exporter" + local docker_url="官网介绍: ${gh_https_url}github.com/prometheus/node_exporter" local docker_use="" local docker_passwd="" local app_size="1" @@ -19260,7 +19694,7 @@ while true; do docker_app_uninstall() { cd /home/docker/new-api/ && docker compose down --rmi all rm -rf /home/docker/new-api - echo "アプリがアンインストールされました" + echo "应用已卸载" } docker_app_plus @@ -19336,7 +19770,7 @@ while true; do 62|ragflow) local app_id="62" local app_name="RAGFlow ナレッジベース" - local app_text="ドキュメントの深い理解に基づいたオープンソース RAG (Retrieval Augmented Generation) エンジン" + local app_text="ドキュメントの深い理解に基づくオープンソース RAG (Retrieval Augmented Generation) エンジン" local app_url="公式ウェブサイト:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" local docker_port="8062" @@ -19402,7 +19836,7 @@ while true; do docker run -d --name it-tools --restart=always -p ${docker_port}:80 corentinth/it-tools:latest } - local docker_describe="開発者と IT ワーカーにとって非常に便利なツール" + local docker_describe="对开发人员和 IT 工作者来说非常有用的工具" local docker_url="公式サイト紹介:${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" @@ -19797,7 +20231,7 @@ while true; do local app_id="78" local app_name="PandaWiki" local app_text="PandaWiki は、AI 大型モデルによって駆動されるオープンソースのインテリジェントな文書管理システムです。ポートの展開をカスタマイズしないことを強くお勧めします。" - local app_url="公式紹介:${gh_https_url}github.com/chaitin/PandaWiki" + local app_url="官方介绍: ${gh_https_url}github.com/chaitin/PandaWiki" local docker_name="panda-wiki-nginx" local docker_port="2443" local app_size="2" @@ -20006,7 +20440,7 @@ while true; do } - local docker_describe="高性能AIインターフェース透過プロキシサービス" + local docker_describe="高性能AI接口透明代理服务" local docker_url="公式サイト紹介:https://www.gpt-load.com/" local docker_use="" local docker_passwd="" @@ -20174,7 +20608,7 @@ while true; do } - local docker_describe="リモートで映画や生放送を一緒に視聴するプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" + local docker_describe="リモートで映画や生放送を一緒に見るプログラム。同時視聴、ライブブロードキャスト、チャットなどの機能を提供します" local docker_url="公式サイト紹介:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"初期アカウントとパスワード: root。ログイン後、時間内にログイン パスワードを変更してください\"" local docker_passwd="" @@ -20289,7 +20723,7 @@ while true; do } - local docker_describe="Matrix は分散型チャット プロトコルです" + local docker_describe="Matrix是一个去中心化的聊天协议" local docker_url="公式サイト紹介:https://matrix.org/" local docker_use="" local docker_passwd="" @@ -20396,7 +20830,7 @@ while true; do } local docker_describe="シンプルな静的ファイル サーバー、アップロードとダウンロードをサポート" - local docker_url="公式サイト紹介:${gh_https_url}github.com/sigoden/dufs" + local docker_url="官网介绍: ${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" local app_size="1" @@ -20442,7 +20876,7 @@ while true; do local app_id="95" local app_name="ペーパーレス文書管理プラットフォーム" - local app_text="オープンソースの電子文書管理システムであり、その主な目的は紙の文書をデジタル化して管理することです。" + local app_text="オープンソースの電子文書管理システムであり、その主な目的は紙文書をデジタル化して管理することです。" local app_url="ビデオ紹介: https://docs.paperless-ngx.com/" local docker_name="paperless-webserver-1" local docker_port="8095" @@ -20627,10 +21061,10 @@ while true; do echo -e "${gl_huang}すべてのクライアント構成コード:${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 - echo -e "${gl_lv}${COUNT}各クライアントのすべての出力を構成します。利用方法は以下の通りです。${gl_bai}" + echo -e "${gl_lv}${COUNT}个客户端配置全部输出,使用方法如下:${gl_bai}" echo -e "${gl_lv}1. 携帯電話に wg APP をダウンロードし、上の QR コードをスキャンして、すぐにインターネットに接続します。${gl_bai}" echo -e "${gl_lv}2. Windows 用クライアントをダウンロードし、ネットワークに接続するための構成コードをコピーします。${gl_bai}" - echo -e "${gl_lv}3. スクリプトを使用して Linux に WG クライアントを展開し、構成コードをコピーしてネットワークに接続します。${gl_bai}" + echo -e "${gl_lv}3. Linux用脚本部署WG客户端,复制配置代码连接网络。${gl_bai}" echo -e "${gl_lv}公式クライアントのダウンロード方法:https://www.wireguard.com/install/${gl_bai}" break_end @@ -20662,7 +21096,7 @@ while true; do # ディレクトリが存在しない場合は作成する mkdir -p "$(dirname "$CONFIG_FILE")" - echo "クライアント設定を貼り付け、Enter キーを 2 回押して保存してください。" + echo "请粘贴你的客户端配置,连续按两次回车保存:" # 変数を初期化する input="" @@ -20805,7 +21239,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI動画生成ツール" - local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです。" + local app_text="MoneyPrinterTurbo は、AI ラージモデルを使用して高解像度のショートビデオを合成するツールです" local app_url="公式ウェブサイト:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -21139,7 +21573,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } - local docker_describe="これは、強力なマルチフォーマット ファイル変換ツール (ドキュメント、画像、オーディオ、ビデオなどをサポート) です。ドメイン名アクセスを追加することを強くお勧めします。" + local docker_describe="これは、強力なマルチフォーマット ファイル変換ツールです (ドキュメント、画像、オーディオ、ビデオなどをサポート)。ドメイン名アクセスを追加することを強くお勧めします。" local docker_url="プロジェクトアドレス:${gh_https_url}github.com/c4illin/ConvertX" local docker_use="" local docker_passwd="" @@ -21318,8 +21752,8 @@ linux_work() { send_stats "バックエンドワークスペース" echo -e "バックエンドワークスペース" echo -e "システムは、バックグラウンドで永続的に実行できるワークスペースを提供し、長期的なタスクを実行するために使用できます。" - echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、バックグラウンド タスクは継続されます。" - echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、次に d を単独で押してワークスペースを終了します。" + echo -e "SSH を切断しても、ワークスペース内のタスクは中断されず、タスクはバックグラウンドで残ります。" + echo -e "${gl_huang}ヒント:${gl_bai}ワークスペースに入ったら、Ctrl+b を使用し、d だけを押してワークスペースを終了します。" echo -e "${gl_kjlan}------------------------" echo "現在存在するワークスペースのリスト" echo -e "${gl_kjlan}------------------------" @@ -21330,7 +21764,7 @@ linux_work() { echo -e "${gl_kjlan}3. ${gl_bai}作業エリア 3" echo -e "${gl_kjlan}4. ${gl_bai}作業エリア 4" echo -e "${gl_kjlan}5. ${gl_bai}ワークスペースNo.5" - echo -e "${gl_kjlan}6. ${gl_bai}作業エリア6" + echo -e "${gl_kjlan}6. ${gl_bai}6号工作区" echo -e "${gl_kjlan}7. ${gl_bai}作業エリア 7" echo -e "${gl_kjlan}8. ${gl_bai}作業エリア8" echo -e "${gl_kjlan}9. ${gl_bai}ワークスペースNo.9" @@ -21427,7 +21861,7 @@ linux_work() { else local tmux_sshd_status="${gl_hui}閉鎖${gl_bai}" fi - send_stats "SSH常駐モード" + send_stats "SSH常驻模式 " echo -e "SSH常駐モード${tmux_sshd_status}" echo "SSH 接続を開いた後、直接常駐モードに入り、前の動作状態に直接戻ります。" echo "------------------------" @@ -21457,7 +21891,7 @@ linux_work() { ;; 22) - read -e -p "作成または入力したワークスペースの名前を入力してください (1001 kj001 work1 など)。" SESSION_NAME + read -e -p "请输入你创建或进入的工作区名称,如1001 kj001 work1: " SESSION_NAME tmux_run send_stats "カスタムワークスペース" ;; @@ -21498,7 +21932,7 @@ linux_work() { -# インテリジェントスイッチングミラーソース機能 +# 智能切换镜像源函数 switch_mirror() { # オプションのパラメータ、デフォルトは false local upgrade_software=${1:-false} @@ -21563,7 +21997,7 @@ fail2ban_panel() { echo "------------------------" echo "1. 防御プログラムをインストールする" echo "------------------------" - echo "2. SSH インターセプト記録の表示" + echo "2. 查看SSH拦截记录" echo "3. リアルタイムログ監視" echo "------------------------" echo "4. 基本パラメータ設定(禁止期間/時間枠/リトライ回数)" @@ -21657,7 +22091,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) send_stats "ネットワークカードを無効にする" @@ -21667,7 +22101,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ネットワークカードの詳細を表示する" @@ -21679,7 +22113,7 @@ net_menu() { else echo "✘ ネットワークカードが存在しません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "ネットワークカード情報を更新する" @@ -21705,7 +22139,7 @@ log_menu() { echo "[/var/logディレクトリ占有]" du -sh /var/log 2>/dev/null echo - echo "【日記帳の職業】" + echo "【日記ログ職業】" journalctl --disk-usage 2>/dev/null echo "========================================" } @@ -21730,17 +22164,17 @@ log_menu() { read -erp "最新のログ行を表示しますか? [デフォルト 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 2) - send_stats "指定したサービスログを表示する" + send_stats "查看指定服务日志" read -erp "サービス名 (sshd、nginx など) を入力してください:" svc if systemctl list-unit-files | grep -q "^$svc"; then journalctl -u "$svc" -n 100 --no-pager else echo "✘ サービスが存在しないか、ログがありません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 3) send_stats "ログイン/セキュリティログの表示" @@ -21755,7 +22189,7 @@ log_menu() { else echo "セキュリティログファイルが見つかりません" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." ;; 4) send_stats "リアルタイム追跡ログ" @@ -21773,7 +22207,7 @@ log_menu() { ;; 5) send_stats "古いジャーナル ログをクリーンアップする" - echo "⚠️ ジャーナルをクリーンアップします (安全な方法)" + echo "⚠️ 清理 journal 日志(安全方式)" echo "1) 過去 7 日間を保存します" echo "2) 過去 3 日間を保存します" echo "3) 最大ログ サイズを 500M に制限する" @@ -21843,7 +22277,7 @@ env_menu() { echo echo "===============================================" - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } @@ -21858,7 +22292,7 @@ env_menu() { else echo "ファイルが存在しません:$file" fi - read -erp "続行するには Enter キーを押してください..." + read -erp "Enter を押して続行します..." } edit_file() { @@ -21874,7 +22308,7 @@ env_menu() { source "$BASHRC" source "$PROFILE" echo "✔ 環境変数がリロードされました" - read -erp "続行するには Enter キーを押してください..." + read -erp "按回车继续..." } while true; do @@ -21883,9 +22317,9 @@ env_menu() { echo "現在のユーザー:$USER" echo "--------------------------------------" echo "1. 現在一般的に使用されている環境変数を確認します。" - echo "2. ~/.bashrc を表示する" + echo "2. 查看 ~/.bashrc" echo "3. ~/.profile を表示する" - echo "4. ~/.bashrc を編集します" + echo "4. ~/.bashrc を編集する" echo "5. ~/.profile を編集する" echo "6. 環境変数(ソース)をリロードします。" echo "--------------------------------------" @@ -22002,7 +22436,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}スクリプト起動のショートカットキーを設定する${gl_kjlan}2. ${gl_bai}ログインパスワードを変更する" echo -e "${gl_kjlan}3. ${gl_bai}ユーザーパスワードログインモード${gl_kjlan}4. ${gl_bai}指定されたバージョンの Python をインストールします" - echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートを変更する" + echo -e "${gl_kjlan}5. ${gl_bai}すべてのポートを開く${gl_kjlan}6. ${gl_bai}SSH接続ポートの変更" echo -e "${gl_kjlan}7. ${gl_bai}DNSアドレスを最適化する${gl_kjlan}8. ${gl_bai}ワンクリックでシステムを再インストールします${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}ROOTアカウントを無効にして新しいアカウントを作成する${gl_kjlan}10. ${gl_bai}スイッチ優先度 ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -22010,12 +22444,12 @@ linux_Settings() { echo -e "${gl_kjlan}13. ${gl_bai}ユーザー管理${gl_kjlan}14. ${gl_bai}ユーザー/パスワード生成器" echo -e "${gl_kjlan}15. ${gl_bai}システムのタイムゾーン調整${gl_kjlan}16. ${gl_bai}BBR3アクセラレーションの設定" echo -e "${gl_kjlan}17. ${gl_bai}ファイアウォール アドバンスト マネージャー${gl_kjlan}18. ${gl_bai}ホスト名の変更" - echo -e "${gl_kjlan}19. ${gl_bai}システムアップデート元の切り替え${gl_kjlan}20. ${gl_bai}スケジュールされたタスクの管理" + echo -e "${gl_kjlan}19. ${gl_bai}システムアップデート元の切り替え${gl_kjlan}20. ${gl_bai}定时任务管理" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}ネイティブホスト解像度${gl_kjlan}22. ${gl_bai}SSH防御プログラム" - echo -e "${gl_kjlan}23. ${gl_bai}電流制限自動シャットダウン${gl_kjlan}24. ${gl_bai}ユーザーキーログインモード" + echo -e "${gl_kjlan}23. ${gl_bai}限流自动关机 ${gl_kjlan}24. ${gl_bai}用户密钥登录模式" echo -e "${gl_kjlan}25. ${gl_bai}TG-bot システムの監視と早期警告${gl_kjlan}26. ${gl_bai}OpenSSH の高リスク脆弱性を修正" - echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux カーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linuxシステムのカーネルパラメータの最適化${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}27. ${gl_bai}Red Hat Linux カーネルのアップグレード${gl_kjlan}28. ${gl_bai}Linux系统内核参数优化 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}29. ${gl_bai}ウイルススキャンツール${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}ファイルマネージャー" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}システム言語を切り替える${gl_kjlan}32. ${gl_bai}コマンドライン美化ツール${gl_huang}★${gl_bai}" @@ -22027,7 +22461,7 @@ linux_Settings() { echo -e "${gl_kjlan}41. ${gl_bai}システムログ管理ツール${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}システム変数管理ツール" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${gl_bai}掲示板${gl_kjlan}66. ${gl_bai}ワンストップのシステムチューニング${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}サーバーを再起動します${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}プライバシーとセキュリティ" echo -e "${gl_kjlan}101. ${gl_bai}k コマンドの高度な使用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}Tech Lion スクリプトをアンインストールする" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}メインメニューに戻る" @@ -22077,7 +22511,7 @@ linux_Settings() { echo -e "現在のPythonのバージョン番号:${gl_huang}$VERSION${gl_bai}" echo "------------" echo "推奨バージョン: 3.12 3.11 3.10 3.9 3.8 2.7" - echo "他のバージョンを確認する: https://www.python.org/downloads/" + echo "他のバージョンを確認してください: https://www.python.org/downloads/" echo "------------" read -e -p "インストールする Python のバージョン番号を入力します (終了するには 0 を入力します)。" py_new_v @@ -22166,7 +22600,7 @@ EOF clear sed -i 's/^\s*#\?\s*Port/Port/' /etc/ssh/sshd_config - # 現在の SSH ポート番号を読み取ります + # 读取当前的 SSH 端口号 local current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') # 現在の SSH ポート番号を出力する @@ -22234,7 +22668,7 @@ EOF send_stats "v4/v6 の優先順位を設定する" while true; do clear - echo "v4/v6 の優先順位を設定する" + echo "设置v4/v6优先级" echo "------------------------" @@ -22312,7 +22746,7 @@ EOF ;; 3) - send_stats "4G仮想メモリが設定されました" + send_stats "已设置4G虚拟内存" add_swap 4096 ;; @@ -22352,7 +22786,7 @@ EOF echo "" echo "アカウント操作" echo "------------------------" - echo "1. 通常ユーザーを作成します。 2. 上級ユーザーを作成します。" + echo "1. 创建普通用户 2. 创建高级用户" echo "------------------------" echo "3. 最高の権限を付与する 4. 最高の権限を削除する" echo "------------------------" @@ -22426,7 +22860,7 @@ EOF local first_name_index=$((RANDOM % ${#first_names[@]})) local last_name_index=$((RANDOM % ${#last_names[@]})) local user_name="${first_names[$first_name_index]} ${last_names[$last_name_index]}" - echo "ランダムなユーザー名$i: $user_name" + echo "随机用户姓名 $i: $user_name" done echo "" @@ -22477,11 +22911,11 @@ EOF echo "タイムゾーンスイッチ" echo "------------------------" echo "アジア" - echo "1. 中国上海時間 2. 中国香港時間" + echo "1. 中国上海时间 2. 中国香港时间" echo "3. 東京、日本時間 4. ソウル、韓国時間" - echo "5. シンガポール時間 6. インド、コルカタ時間" + echo "5. 新加坡时间 6. 印度加尔各答时间" echo "7. アラブ首長国連邦、ドバイ時間 8. オーストラリア、シドニー時間" - echo "9. タイ・バンコク時間" + echo "9. 泰国曼谷时间" echo "------------------------" echo "ヨーロッパ" echo "11. ロンドン、イギリス時間 12. パリ、フランス時間" @@ -22609,7 +23043,7 @@ EOF bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad ;; 4) - send_stats "アップデートソースのインテリジェントな切り替え" + send_stats "智能切换更新源" switch_mirror false false ;; @@ -22634,7 +23068,7 @@ EOF echo "------------------------" echo "1. スケジュールされたタスクを追加します。 2. スケジュールされたタスクを削除します。 3. スケジュールされたタスクを編集します。" echo "------------------------" - echo "0. 前のメニューに戻る" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "選択肢を入力してください:" sub_choice @@ -22746,7 +23180,7 @@ EOF # しきい値_gbの値を取得する local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}現在設定されている受信トラフィック制限のしきい値は次のとおりです。${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}現在設定されている送信トラフィック制限のしきい値は次のとおりです。${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}電流制限シャットダウン機能は現在有効になっていません。${gl_bai}" @@ -22784,7 +23218,7 @@ EOF crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 echo "電流制限シャットダウンが設定されています" - send_stats "電流制限シャットダウンが設定されています" + send_stats "限流关机已设置" ;; 2) check_crontab_installed @@ -22961,7 +23395,7 @@ EOF echo "ワンストップのシステムチューニング" echo "------------------------------------------------" echo "以下のコンテンツを運用・最適化していきます" - echo "1. システムアップデートソースを最適化し、システムを最新にアップデートします。" + echo "1. システムアップデートソースを最適化し、システムを最新の状態にアップデートします。" echo "2. システムジャンクファイルをクリーンアップする" echo -e "3. 仮想メモリを設定する${gl_huang}1G${gl_bai}" echo -e "4. SSH ポート番号を次のように設定します。${gl_huang}5522${gl_bai}" @@ -22972,7 +23406,7 @@ EOF echo -e "9. DNS アドレスを自動的に最適化する${gl_huang}海外:1.1.1.1 8.8.8.8 国内:223.5.5.5${gl_bai}" echo -e "10. ネットワークを次のように設定します。${gl_huang}IPv4優先度${gl_bai}" echo -e "11. 基本ツールのインストール${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo -e "12. Linuxシステムのカーネルパラメータの最適化${gl_huang}ネットワーク環境に応じて自動チューニング${gl_bai}" + echo -e "12. Linuxシステムのカーネルパラメータの最適化${gl_huang}自动根据网络环境调优${gl_bai}" echo "------------------------------------------------" read -e -p "ワンクリックメンテナンスを実行してもよろしいですか? (はい/いいえ):" choice @@ -23253,7 +23687,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリの移動に失敗しました: 宛先パスが指定されていません" @@ -23273,7 +23707,7 @@ linux_file() { continue fi - read -e -p "宛先パス (新しいファイルまたはディレクトリ名を含む) を入力してください:" dest_path + read -e -p "宛先パス (新しいファイル名またはディレクトリ名を含む) を入力してください:" dest_path if [ -z "$dest_path" ]; then echo "エラー: 宛先パスを入力してください。" send_stats "ファイルまたはディレクトリのコピーに失敗しました: 宛先パスが指定されていません" @@ -23396,7 +23830,7 @@ while true; do echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}サーバーリスト管理${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}サーバーの追加${gl_kjlan}2. ${gl_bai}サーバーの削除${gl_kjlan}3. ${gl_bai}サーバーの編集" - echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスタを復元する" + echo -e "${gl_kjlan}4. ${gl_bai}バックアップクラスター${gl_kjlan}5. ${gl_bai}クラスターを復元する" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}タスクをバッチで実行する${gl_bai}" echo -e "${gl_kjlan}11. ${gl_bai}テクノロジ ライオン スクリプトをインストールする${gl_kjlan}12. ${gl_bai}アップデートシステム${gl_kjlan}13. ${gl_bai}システムをクリーンアップする" @@ -23441,7 +23875,7 @@ while true; do 5) clear - send_stats "クラスタを復元する" + send_stats "クラスターを復元する" echo "servers.py をアップロードし、任意のキーを押してアップロードを開始してください。" echo -e "をアップロードしてください${gl_huang}servers.py${gl_bai}ファイルに${gl_huang}/root/cluster/${gl_bai}復元完了!" break_end @@ -23518,7 +23952,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 月額 6.9 ドル 東京ソフトバンク 2 コア 1G メモリ 20G ハードドライブ 月額 1T トラフィック${gl_bai}" echo -e "${gl_bai}URL:https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}さらに人気のある VPS オファー${gl_bai}" +echo -e "${gl_kjlan}さらに人気のある VPS セール${gl_bai}" echo -e "${gl_bai}ウェブサイト:https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -23834,11 +24268,11 @@ echo "docker イメージ管理 k docker img |k docker image" echo "LDNMP サイト管理 k Web" echo "LDNMP キャッシュのクリーニング k Web キャッシュ" echo "WordPress をインストールします。 kワードプレス | k wp xxx.com" -echo "リバース プロキシ k fd |k rp |k リバース プロキシ |k fd xxx.com をインストールします。" +echo "リバース プロキシをインストールします k fd |k rp |k リバース プロキシ |k fd xxx.com" echo "ロード バランシングのインストール k ロード バランシング |k ロード バランシング" echo "L4 ロード バランシング k ストリーム |k L4 ロード バランシングをインストールする" -echo "ファイアウォール パネル k fhq |k ファイアウォール" -echo "ポートを開く k dkdk 8080 |k ポートを開く 8080" +echo "防火墙面板 k fhq |k 防火墙" +echo "ポートを開きます k dkdk 8080 |k ポートを開きます 8080" echo "ポート k gbdk 7800 を閉じる |k ポート 7800 を閉じる" echo "リリース IP k fxip 127.0.0.0/8 |k リリース IP 127.0.0.0/8" echo "ブロック IP k zzip 177.5.25.36 |k ブロック IP 177.5.25.36" @@ -23846,7 +24280,7 @@ echo "コマンド お気に入り k お気に入り | k コマンドのお気 echo "アプリケーションマーケット管理kアプリ" echo "申請番号の迅速な管理 k app 26 | kアプリ1パネル | k アプリ npm" echo "フェイル 2 バン管理 k フェイル 2 バン | k f2b [ステータス|有効|無効]" -echo "システム情報を表示 k info" +echo "显示系统信息 k info" echo "ROOT キー管理 k sshkey" echo "SSH 公開キーのインポート (URL) k sshkey " echo "SSH 公開キーのインポート (GitHub) k sshkey github " @@ -24020,6 +24454,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then @@ -24105,7 +24544,7 @@ else ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "すぐに証明書を申請してください" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" send_stats "すぐに証明書を申請してください" @@ -24122,7 +24561,7 @@ else install_docker ;; ps|容器) - send_stats "迅速なコンテナ管理" + send_stats "快捷容器管理" docker_ps ;; img|镜像) @@ -24156,6 +24595,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "使用法: k kpanel ノード結合 <認証> |ステータス |更新 |アンインストールする" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift diff --git a/kr/kejilion.sh b/kr/kejilion.sh index 10026e4ad..9f38e890f 100644 --- a/kr/kejilion.sh +++ b/kr/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' @@ -16,7 +16,13 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -523,22 +529,22 @@ while true; do ;; 2) send_stats "지정된 컨테이너 시작" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker start $dockername ;; 3) send_stats "지정된 컨테이너 중지" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker stop $dockername ;; 4) send_stats "지정된 컨테이너 삭제" - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker rm -f $dockername ;; 5) send_stats "지정된 컨테이너를 다시 시작합니다." - read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요):" dockername + read -e -p "컨테이너 이름을 입력하세요(여러 컨테이너 이름을 공백으로 구분하세요)." dockername docker restart $dockername ;; 6) @@ -1283,7 +1289,7 @@ check_swap() { local swap_total=$(free -m | awk 'NR==3{print $2}') -# 가상 메모리를 만들어야 하는지 확인 +# 가상 메모리를 생성해야 하는지 결정 [ "$swap_total" -gt 0 ] || add_swap 1024 @@ -1552,7 +1558,7 @@ certs_status() { local file_path="/etc/letsencrypt/live/$yuming/fullchain.pem" if [ -f "$file_path" ]; then - send_stats "도메인 이름 인증서 신청이 성공했습니다." + send_stats "域名证书申请成功" else send_stats "도메인 이름 인증서 신청 실패" if [ "${KJ_WEB_NONINTERACTIVE:-0}" = "1" ] && @@ -1564,8 +1570,8 @@ certs_status() { echo -e "1. 도메인 이름이 잘못 입력되었습니다. ➠ 도메인 이름이 올바르게 입력되었는지 확인하세요." echo -e "2. DNS 확인 문제 ➠ 도메인 이름이 서버 IP로 올바르게 확인되었는지 확인" echo -e "3. 네트워크 구성 문제 ➠ Cloudflare Warp 등 가상 네트워크를 사용하는 경우 일시적으로 종료하세요." - echo -e "4. 방화벽 제한 사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." - echo -e "5. 신청 횟수가 한도를 초과했습니다. ➠ Let's Encrypt에는 주간 한도(5회/도메인 이름/주)가 있습니다." + echo -e "4. 방화벽 제한사항 ➠ 포트 80/443이 열려 있는지 확인하고 접근이 가능한지 확인하세요." + echo -e "5. 申请次数超限 ➠ Let's Encrypt有每周限额(5次/域名/周)" echo -e "6. 국내 등록 제한 ➠ 중국 ​​본토 환경의 경우 도메인 이름 등록 여부를 확인하시기 바랍니다." echo "------------------------" echo "1. 재적용 2. 기존 인증서 가져오기 0. 종료" @@ -1590,7 +1596,7 @@ certs_status() { mkdir -p /home/web/certs # 1. 인증서를 입력합니다(ECC 및 RSA 인증서 모두 BEGIN CERTIFICATE로 시작함). - echo "인증서(CRT/PEM) 콘텐츠를 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + echo "请粘贴 证书 (CRT/PEM) 内容 (按两次回车结束):" local cert_content="" while IFS= read -r line; do [[ -z "$line" && "$cert_content" == *"-----BEGIN"* ]] && break @@ -1598,7 +1604,7 @@ certs_status() { done # 2. 개인 키를 입력하세요. (RSA, ECC, PKCS#8과 호환 가능) - echo "인증서 개인 키(개인 키) 내용을 붙여넣으세요(종료하려면 Enter를 두 번 누르세요)." + echo "请粘贴 证书私钥 (Private Key) 内容 (按两次回车结束):" local key_content="" while IFS= read -r line; do [[ -z "$line" && "$key_content" == *"-----BEGIN"* ]] && break @@ -1773,7 +1779,7 @@ nginx_upgrade() { docker exec nginx chown -R nginx:nginx /var/cache/nginx/fastcgi docker restart $ldnmp_pods > /dev/null 2>&1 - send_stats "고쳐 쓰다$ldnmp_pods" + send_stats "更新$ldnmp_pods" echo "고쳐 쓰다${ldnmp_pods}마치다" } @@ -1797,7 +1803,7 @@ phpmyadmin_upgrade() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo - send_stats "시작하다$ldnmp_pods" + send_stats "启动$ldnmp_pods" } @@ -1811,7 +1817,7 @@ cf_purge_cache() { if [ -f "$CONFIG_FILE" ]; then # 구성 파일에서 API_TOKEN 및 zone_id를 읽습니다. read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # ZONE_IDS를 어레이로 변환 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else # 캐시를 지울지 여부를 사용자에게 묻습니다. @@ -1858,7 +1864,7 @@ web_del() { yuming_list=("$@") else local yuming_input="" - read -e -p "사이트 데이터를 삭제하려면 도메인 이름을 입력하세요(여러 도메인 이름은 공백으로 구분)." yuming_input + read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_input if [[ -z "$yuming_input" ]]; then return fi @@ -2353,7 +2359,7 @@ web_security() { echo "https://dash.cloudflare.com/login" echo "--------------" read -e -p "CF의 계좌번호를 입력하세요:" cfuser - read -e -p "CF의 글로벌 API 키를 입력하세요:" cftoken + read -e -p "输入CF的Global API Key: " cftoken read -e -p "CF에 도메인 이름의 영역 ID를 입력하세요." cfzonID cd ~ @@ -2371,7 +2377,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "고부하 자동 쉴드 오픈 스크립트가 추가되었습니다." + echo "高负载自动开盾脚本已添加" else echo "자동 방패 열기 스크립트가 이미 있으므로 추가할 필요가 없습니다." fi @@ -2415,9 +2421,9 @@ check_ldnmp_mode() { # MySQL 구성 파일에 4096M이 포함되어 있는지 확인하세요. if docker exec "$MYSQL_CONTAINER" grep -q "4096M" "$MYSQL_CONF" 2>/dev/null; then - mode_info="고성능 모드" + mode_info=" 高性能模式" else - mode_info="표준 모드" + mode_info=" 标准模式" fi @@ -2524,7 +2530,7 @@ web_optimization() { echo "------------------------" echo "3. gzip 압축 켜기 4. gzip 압축 끄기" echo "5. br 압축을 켭니다. 6. br 압축을 끕니다." - echo "7. zstd 압축을 켭니다. 8. zstd 압축을 끕니다." + echo "7. 开启zstd压缩 8. 关闭zstd压缩" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -2597,7 +2603,7 @@ check_docker_app() { # if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then # check_docker="${gl_lv}가 ${gl_bai}를 설치했습니다." # else -# check_docker="${gl_hui}이(가) ${gl_bai}" 설치되지 않았습니다. +# check_docker="${gl_hui}가 ${gl_bai}" 설치되지 않았습니다. # fi # } @@ -2637,7 +2643,7 @@ check_docker_image_update() { local container_name=$1 update_status="" - # 1. 컨테이너 및 로컬 이미지 정보를 획득합니다. 업데이트 감지는 더 이상 지역별로 건너뛰지 않습니다. + # 1. 컨테이너 및 로컬 이미지 정보를 획득합니다. 더 이상 지역별로 업데이트 감지를 건너뛰지 않습니다. local container_info container_info=$(docker inspect --format='{{.Created}},{{.Config.Image}},{{.Image}}' "$container_name" 2>/dev/null) [[ -z "$container_info" ]] && return @@ -2703,7 +2709,7 @@ check_docker_image_update() { local remote_ts=$(date -d "$remote_date" +%s 2>/dev/null) if [[ "$container_created_ts" =~ ^[0-9]+$ && "$remote_ts" =~ ^[0-9]+$ ]] && [[ $container_created_ts -lt $remote_ts ]]; then - update_status="${gl_huang}새 버전이 발견되었습니다!${gl_bai}" + update_status="${gl_huang}发现新版本!${gl_bai}" fi fi } @@ -2714,58 +2720,52 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 - - # 컨테이너의 IP 주소 가져오기 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi - - install iptables - - - # 다른 모든 IP를 확인하고 차단하세요. - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 지정된 IP 확인 및 해제 - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 로컬 네트워크 127.0.0.0/8 확인 및 허용 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - + local container_ips + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # 다른 모든 IP를 확인하고 차단하세요. - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - # 지정된 IP 확인 및 해제 - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # 로컬 네트워크 127.0.0.0/8 확인 및 허용 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT + # 규칙을 하나씩 적용하여 모든 Docker 네트워크에서 컨테이너의 IPv4 주소를 가져옵니다. + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "오류: 컨테이너를 가져올 수 없습니다.${container_name_or_id}IPv4 주소." >&2 + return 1 fi + install iptables - echo "IP+포트가 서비스 접근을 차단했습니다." + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" + + echo "已阻止IP+端口访问该服务" save_iptables_rules } @@ -2775,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # 컨테이너의 IP 주소 가져오기 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # 모든 Docker 네트워크에 있는 컨테이너의 IPv4 주소를 가져오고 규칙을 하나씩 지웁니다. + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "오류: 컨테이너를 가져올 수 없습니다.${container_name_or_id}IPv4 주소." >&2 return 1 fi install iptables - - # 다른 모든 IP를 차단하는 명확한 규칙 - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 특정 IP를 허용하는 규칙 지우기 - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # 다른 모든 IP를 차단하는 명확한 규칙 - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # 특정 IP를 허용하는 규칙 지우기 - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 로컬 네트워크 127.0.0.0/8을 허용하는 규칙을 지웁니다. - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "IP+포트로 서비스 접속이 허용되었습니다" save_iptables_rules @@ -2841,7 +2812,7 @@ block_host_port() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "오류: 액세스를 허용하려면 포트 번호와 IP를 입력하세요." - echo "사용법: block_host_port <포트 번호> <허용 IP>" + echo "用法: block_host_port <端口号> <允许的IP>" return 1 fi @@ -2867,7 +2838,7 @@ block_host_port() { - # 다른 모든 IP의 접근을 거부 + # 拒绝其他所有 IP 访问 if ! iptables -C INPUT -p udp --dport "$port" -j DROP &>/dev/null; then iptables -I INPUT -p udp --dport "$port" -j DROP fi @@ -3024,7 +2995,7 @@ kpanel_app_interactive_choice() { printf -v "$target_variable" '%s' "8" ;; *) - echo "오류: KPanel이 유효한 애플리케이션 액세스 모드를 제공하지 않습니다." + echo "错误: KPanel 未提供有效的应用访问模式" return 1 ;; esac @@ -3091,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3104,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" @@ -3151,7 +3133,7 @@ kpanel_app_apply_access_mode() { block_container_port "$service_name" "$ipv4_address" || return 1 ;; *) - echo "오류: 지원되지 않는 애플리케이션 액세스 모드" >&2 + echo "错误: 不支持的应用访问模式" >&2 return 1 ;; esac @@ -3252,7 +3234,7 @@ kpanel_run_docker_app_install() { kpanel_app_progress 15 "Docker 런타임 환경 준비" install jq || return 1 install_docker || return 1 - kpanel_app_progress 30 "kejilion.sh 애플리케이션 설치 기능 실행" + kpanel_app_progress 30 "正在执行 kejilion.sh 应用安装函数" if [ "$adapter" = "plus" ]; then if ! docker_app_install; then @@ -3443,7 +3425,7 @@ while true; do docker rm -f "$docker_name" docker rmi -f "$docker_img" if ! docker_rum; then - echo -e "${gl_hong}업데이트 실패:${gl_bai}애플리케이션 컨테이너를 다시 시작하지 못했습니다." + echo -e "${gl_hong}更新失败: ${gl_bai}애플리케이션 컨테이너를 다시 시작하지 못했습니다." if [ "${KJ_APP_INTERACTIVE:-}" = "1" ]; then return 1 fi @@ -3570,7 +3552,7 @@ docker_app_plus() { echo "$docker_port" > "/home/docker/${docker_name}_port.conf" add_app_id kpanel_app_write_access_mode direct - send_stats "$app_name설치하다" + send_stats "$app_name 安装" else echo -e "${gl_hong}설치 실패:${gl_bai}신청상황이 등록되지 않았습니다. 위의 오류를 수정한 후 다시 시도해 주세요." action_status=1 @@ -3595,7 +3577,7 @@ docker_app_plus() { sed -i "/\b${app_id}\b/d" /home/docker/appno.txt send_stats "$app_name제거" else - echo -e "${gl_hong}제거 실패:${gl_bai}애플리케이션 등록 상태가 유지되었습니다." + echo -e "${gl_hong}제거 실패:${gl_bai}已保留应用登记状态。" action_status=1 fi ;; @@ -3716,7 +3698,7 @@ session_exists() { tmux has-session -t $1 2>/dev/null } -# 존재하지 않는 세션 이름을 찾을 때까지 반복 +# 循环直到找到一个不存在的会话名称 while session_exists "$base_name-$tmuxd_ID"; do local tmuxd_ID=$((tmuxd_ID + 1)) done @@ -3833,7 +3815,7 @@ kpanel_f2b_dispatch() { fi f2b_install_sshd || return 1 kpanel_f2b_enabled || { - echo "Fail2Ban SSH 감옥이 제대로 시작되지 않았습니다." >&2 + echo "Fail2Ban SSH jail 未能正常启动" >&2 return 1 } changed=true @@ -3879,7 +3861,7 @@ f2b_sshd() { } # 기본 매개변수 구성: 금지 기간(bantime), 기간(findtime), 재시도 횟수(maxretry) -# 설명하다: +# 说明: # - /etc/fail2ban/jail.d/sshd.local에 쓰기 우선 순위를 지정합니다(기본 감옥 구성을 덮어쓰며 업그레이드 시 손실되기 쉽지 않습니다). # - Alpine이고 감옥 이름이 다른 경우에도 sshd.local을 작성하세요. Fail2Ban은 감옥 이름에 따라 일치합니다. f2b_basic_config() { @@ -3887,7 +3869,7 @@ f2b_basic_config() { install nano if ! command -v fail2ban-client >/dev/null 2>&1; then - echo -e "${gl_hui}failure2ban-client가 감지되지 않습니다. 먼저 fall2ban을 설치하십시오.${gl_bai}" + echo -e "${gl_hui}FAIL2BAN-클라이언트가 감지되지 않습니다. 먼저 Fail2ban을 설치하십시오.${gl_bai}" return fi @@ -3902,7 +3884,7 @@ f2b_basic_config() { echo "SSH 감옥을 구성하려고 합니다:$jail_name" read -e -p "금지 시간 금지 시간(초/분/시간, 예: 3600 또는 1h) [기본값 1h]:" bantime read -e -p "시간 창 찾기 시간(초/분/시간, 예: 600 또는 10m) [기본값 10m]:" findtime - read -e -p "재시도 횟수 maxretry(정수) [기본값 5]:" maxretry + read -e -p "重试次数 maxretry (整数) [默认 5]: " maxretry bantime=${bantime:-1h} findtime=${findtime:-10m} @@ -3949,7 +3931,7 @@ f2b_edit_config() { [ -f "$cfg" ] || printf "[sshd]\n# bantime/findtime/maxretry\n" > "$cfg" nano "$cfg" - echo -e "${gl_lv}저장됨${gl_bai}, Fail2ban을 다시 로드하는 중..." + echo -e "${gl_lv}저장됨${gl_bai},正在 reload fail2ban..." fail2ban-client reload >/dev/null 2>&1 || true } @@ -4079,7 +4061,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "https://$yuming" echo "------------------------" echo "$webname설치정보는 다음과 같습니다." @@ -4092,7 +4074,7 @@ nginx_web_on() { local ipv4_pattern='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' local ipv6_pattern='^(([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){7,7}[0-9A-Fa-f]{1,4}|::1)$' - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" if [[ "$yuming" =~ $ipv4_pattern || "$yuming" =~ $ipv6_pattern ]]; then mv /home/web/conf.d/"$yuming".conf /home/web/conf.d/"${yuming}_${access_port}".conf @@ -4170,7 +4152,7 @@ ldnmp_Proxy() { kpanel_web_progress 10 "역방향 프록시 도메인 이름 및 업스트림 주소 확인" send_stats "설치하다$webname" - echo "배포 시작$webname" + echo "开始部署 $webname" if [ -z "$yuming" ]; then add_yuming fi @@ -4178,7 +4160,7 @@ ldnmp_Proxy() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy" ]; then - read -e -p "세대 방지 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy + read -e -p "안티 세대 IP를 입력하십시오(기본값은 로컬 IP 127.0.0.1로 설정하려면 Enter를 누르십시오)." reverseproxy reverseproxy=${reverseproxy:-127.0.0.1} fi @@ -4235,7 +4217,7 @@ ldnmp_Proxy_backend() { check_ip_and_get_access_port "$yuming" if [ -z "$reverseproxy_port" ]; then - read -e -p "여러 세대 방지 IP+포트를 공백으로 구분하여 입력하세요(예: 127.0.0.1:3000 127.0.0.1:3002)." reverseproxy_port + read -e -p "请输入你的多个反代IP+端口用空格隔开(例如 127.0.0.1:3000 127.0.0.1:3002): " reverseproxy_port fi nginx_install_status @@ -4257,7 +4239,7 @@ ldnmp_Proxy_backend() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 동적으로 추가/$upstream_servers/g" /home/web/conf.d/$yuming.conf + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/conf.d/$yuming.conf update_nginx_listen_port "$yuming" "$access_port" @@ -4372,7 +4354,7 @@ stream_panel() { send_stats "레이어 4 프록시 추가" ;; 5) - send_stats "전달 구성 수정" + send_stats "编辑转发配置" read -e -p "편집하려는 서비스 이름을 입력하십시오:" stream_name install nano nano /home/web/stream.d/$stream_name.conf @@ -4398,24 +4380,24 @@ stream_panel() { ldnmp_Proxy_backend_stream() { clear - webname="스트림 4계층 프록시-로드 밸런싱" + webname="스트리밍 4계층 프록시-로드 밸런싱" send_stats "설치하다$webname" echo "배포 시작$webname" - # 에이전트 이름 가져오기 + # 获取代理名称 read -erp "프록시 전달 이름(예: mysql_proxy)을 입력하세요." proxy_name if [ -z "$proxy_name" ]; then - echo "이름은 비워둘 수 없습니다."; return 1 + echo "名称不能为空"; return 1 fi - # 수신 포트 가져오기 + # 获取监听端口 read -erp "로컬 수신 포트(예: 3306)를 입력하십시오." listen_port if ! [[ "$listen_port" =~ ^[0-9]+$ ]]; then echo "포트는 숫자여야 합니다."; return 1 fi - echo "계약 유형을 선택하십시오:" + echo "请选择协议类型:" echo "1. TCP 2. UDP" read -erp "일련 번호 [1-2]를 입력하십시오:" proto_choice @@ -4446,7 +4428,7 @@ ldnmp_Proxy_backend_stream() { docker exec nginx nginx -s reload clear - echo "당신의$webname건설되었습니다!" + echo "당신의$webname지어졌습니다!" echo "------------------------" echo "방문 주소:" ip_address @@ -4548,7 +4530,7 @@ ldnmp_web_status() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "도메인 이름 인증서 신청" @@ -4689,7 +4671,7 @@ while true; do echo "------------------------" echo "1. 설치 2. 관리 3. 제거" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "선택사항을 입력하세요:" choice case $choice in @@ -4779,7 +4761,7 @@ EOF donlond_frp frps - # 생성된 정보 출력 + # 생성된 정보를 출력 ip_address echo "------------------------" echo "클라이언트 배포에 필요한 매개변수" @@ -4841,7 +4823,7 @@ remote_port = ${remote_port} EOF - # 생성된 정보 출력 + # 생성된 정보를 출력 echo "제공하다$service_namefrpc.toml에 성공적으로 추가되었습니다." docker restart frpc @@ -5088,7 +5070,7 @@ frps_panel() { 8) send_stats "IP 접근 차단" - echo "역방향 도메인 이름 접근을 가지고 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." + echo "역방향 도메인 이름 접근이 있는 경우, 이 기능을 사용하면 IP+포트 접근을 차단할 수 있어 더욱 안전합니다." read -e -p "차단할 포트를 입력하세요:" frps_port block_host_port "$frps_port" "$ipv4_address" ;; @@ -5452,7 +5434,7 @@ linux_clean() { bbr_on() { -# 커널 튜닝 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 +# 커널 조정 모듈과의 충돌을 방지하기 위해 sysctl.d에 대한 통합 쓰기 local CONF="/etc/sysctl.d/99-kejilion-bbr.conf" mkdir -p /etc/sysctl.d echo "net.core.default_qdisc=fq" > "$CONF" @@ -5606,7 +5588,7 @@ kpanel_dns_write_static() { [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" - echo "오류: DNS 쓰기 실패 및 롤백 실패, 수동 확인 필요" + echo "오류: DNS 쓰기 실패 및 롤백 실패, 수동 검사 필요" return 1 } rm -f "$desired" "$backup" @@ -5712,7 +5694,7 @@ kpanel_set_dns_noninteractive() { return 1 } else - echo "오류: 잘못된 DNS 주소" + echo "错误: 无效的 DNS 地址" return 1 fi for previous in "${normalized[@]}"; do @@ -5751,7 +5733,7 @@ while true; do echo "2. 국내 DNS 최적화:" echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" - echo "3. DNS 구성을 수동으로 편집" + echo "3. 手动编辑DNS配置" echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -5839,6 +5821,82 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "오류: KPanel SSH 포트 프로토콜은 루트로 실행되어야 합니다." + return 1 + } + [ "$#" -eq 1 ] || { + echo "오류: SSH 포트 프로토콜에는 포트 번호가 필요합니다." + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "오류: SSH 포트는 1-65535여야 합니다." + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "오류: 관리 가능한 OpenSSH 구성을 찾을 수 없습니다." + return 1 + } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "오류: SSH 구성 확인 또는 청취 확인 도구를 사용할 수 없습니다." + return 1 + } + sshd -t || { + echo "오류: 현재 SSH 구성 구문 확인에 실패했습니다." + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # 기존 SSH를 재사용하여 주요 비즈니스를 수정합니다. 적응 계층은 비대화형 검증 및 기계 판독 가능 결과만 담당합니다. + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "오류: SSH 포트 수정 후 다시 읽기 확인에 실패했습니다." + return 1 + fi + if ! sshd -t; then + echo "오류: SSH 구성 구문 확인에 실패했습니다." + return 1 + fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "오류: 새 SSH 포트가 수신 대기 상태로 전환되지 않았습니다." + return 1 + } + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -5896,7 +5954,7 @@ import_sshkey() { fi if [[ ! "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa) ]]; then - echo -e "${gl_hong}오류: 합법적인 SSH 공개 키가 아닌 것 같습니다.${gl_bai}" + echo -e "${gl_hong}오류: 합법적인 SSH 공개 키처럼 보이지 않습니다.${gl_bai}" return 1 fi @@ -5958,7 +6016,7 @@ fetch_remote_ssh_keys() { # 콘텐츠가 유효한지 확인하세요. if [[ ! -s "${temp_file}" ]]; then - echo "오류: 다운로드한 파일이 비어 있으며 URL에 공개 키가 포함되어 있지 않을 수 있습니다." >&2 + echo "错误:下载到的文件为空,URL 可能不包含任何公钥" >&2 rm -f "${temp_file}" return 1 fi @@ -6041,7 +6099,7 @@ sshkey_panel() { clear local REAL_STATUS=$(grep -i "^PubkeyAuthentication" /etc/ssh/sshd_config | tr '[:upper:]' '[:lower:]') if [[ "$REAL_STATUS" =~ "yes" ]]; then - IS_KEY_ENABLED="${gl_lv}활성화됨${gl_bai}" + IS_KEY_ENABLED="${gl_lv}已启用${gl_bai}" else IS_KEY_ENABLED="${gl_hui}활성화되지 않음${gl_bai}" fi @@ -6090,7 +6148,7 @@ sshkey_panel() { 6) send_stats "로컬 키 보기" echo "------------------------" - echo "공개키 정보" + echo "公钥信息" cat ${HOME}/.ssh/authorized_keys echo "------------------------" echo "개인 키 정보" @@ -6198,7 +6256,7 @@ dd_xitong() { } dd_xitong_2() { - echo -e "재설치 후 초기 사용자 이름:${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" + echo -e "重装后初始用户名: ${gl_huang}Administrator${gl_bai}초기 비밀번호:${gl_huang}Teddysun.com${gl_bai}초기 포트:${gl_huang}3389${gl_bai}" echo -e "계속하려면 아무 키나 누르세요..." read -n 1 -s -r -p "" install wget @@ -6226,7 +6284,7 @@ dd_xitong() { echo -e "${gl_hong}알아채다:${gl_bai}재설치 시 연결이 끊어질 수 있으니 걱정되시는 분들은 주의해서 사용해주세요. 재설치에는 약 15분 정도 소요될 예정이오니, 사전에 데이터를 백업해 주시기 바랍니다." echo -e "${gl_hui}스크립트 지원을 해주신 bin456789 보스와 leitbogioro 보스에게 감사드립니다!${gl_bai} " echo -e "${gl_hui}bin456789 프로젝트 주소:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" - echo -e "${gl_hui}leitbogioro 프로젝트 주소:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" + echo -e "${gl_hui}leitbogioro项目地址: ${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" echo "------------------------" echo "1. Debian 13 2. Debian 12" echo "3. Debian 11 4. Debian 10" @@ -6338,7 +6396,7 @@ dd_xitong() { ;; 24) - send_stats "alma9 재설치" + send_stats "重装alma9" dd_xitong_3 bash reinstall.sh almalinux 9 reboot @@ -6466,7 +6524,7 @@ dd_xitong() { ;; 44) - send_stats "Windows Server 25를 다시 설치하세요." + send_stats "重装windows server 25" dd_xitong_2 bash InstallNET.sh -windows 2025 -lang "cn" reboot @@ -6474,7 +6532,7 @@ dd_xitong() { ;; 45) - send_stats "윈도우 서버 22 재설치" + send_stats "重装windows server 22" dd_xitong_2 bash InstallNET.sh -windows 2022 -lang "cn" reboot @@ -6643,12 +6701,12 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - + # 공식적으로 제거된 이전 시스템 코드명과 호환 가능(이전 패키지 라이브러리를 사용해 보려면 릴리스를 사용하도록 대체) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi - + # 공식적으로 jammy, focus, Bullseye 및 기타 기존 시스템에 대한 적절한 지원이 완전히 제거되었습니다. if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod는 공식적으로 현재 시스템 지원을 중단했습니다($os_codename), Debian12/Ubuntu24 이상으로 업그레이드하세요.${gl_bai}" @@ -6663,7 +6721,7 @@ bbrv3() { install wget gnupg ca-certificates mkdir -p /usr/share/keyrings /etc/apt/sources.list.d if ! wget -qO - "$key_url" | gpg --dearmor -o "$keyring" --yes; then - echo "공식 키 다운로드에 실패했습니다. 다른 다운로드 소스를 사용해 보세요..." + echo "官方密钥下载失败,尝试备用下载源..." wget -qO - "$fallback_key_url" | gpg --dearmor -o "$keyring" --yes || return 1 fi chmod 644 "$keyring" @@ -6736,7 +6794,7 @@ bbrv3() { } package=$(xanmod_detect_package) || { - echo "현재 CPU를 인식할 수 없거나 일치하는 커널 패키지를 찾을 수 없습니다. 설치가 취소되었습니다." + echo "无法识别当前CPU或找不到匹配内核包,已取消安装" return 1 } @@ -6757,7 +6815,7 @@ bbrv3() { echo "BBR3 매개변수 쓰기에 실패했습니다. 시스템 구성을 확인하십시오." return 1 } - echo "XanMod BBRv3 커널 처리가 완료되었습니다. 다시 시작한 후 적용" + echo "XanMod BBRv3内核处理完成。重启后生效" [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } @@ -6767,7 +6825,7 @@ bbrv3() { update-grub 2>/dev/null || true rm -f /etc/apt/sources.list.d/xanmod-release.list rm -f /usr/share/keyrings/xanmod-archive-keyring.gpg - echo "XanMod 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "XanMod 커널이 제거되었습니다. 재시작 후 적용" [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || server_reboot } @@ -6832,7 +6890,7 @@ bbrv3() { echo "영상 소개: https://www.bilibili.com/video/BV14K421x7BS?t=0.1" echo "------------------------------------------------" echo "데비안/우분투만 지원" - echo "데이터를 백업해 주시면 Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." + echo "데이터를 백업해 주세요. Linux 커널을 업그레이드하고 BBR3을 활성화하겠습니다." echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6844,7 +6902,7 @@ bbrv3() { echo "취소" ;; *) - echo "선택이 잘못되었습니다. Y 또는 N을 입력하세요." + echo "无效的选择,请输入 Y 或 N。" ;; esac fi @@ -6864,14 +6922,14 @@ elrepo_install() { break_end linux_Settings fi - # 감지된 운영 체제 정보 인쇄 + # 打印检测到的操作系统信息 echo "감지된 운영 체제:$os_name $os_version" # 시스템 버전에 따라 해당 ELRepo 창고 구성을 설치하십시오. if [[ "$os_version" == 8 ]]; then echo "ELRepo 저장소 구성(버전 8) 설치 중..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "ELRepo 저장소 구성(버전 9) 설치 중..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "ELRepo 저장소 구성(버전 10) 설치 중..." @@ -6922,7 +6980,7 @@ elrepo() { 2) dnf remove -y elrepo-release rpm -qa | grep elrepo | grep kernel | xargs rpm -e --nodeps - echo "elrepo 커널이 제거되었습니다. 다시 시작한 후 적용" + echo "elrepo 커널이 제거되었습니다. 재시작 후 적용" send_stats "Red Hat 커널 제거" server_reboot @@ -6937,10 +6995,10 @@ elrepo() { clear echo "데이터를 백업해 주시면 Linux 커널을 업그레이드해 드리겠습니다." - echo "영상 소개: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" + echo "视频介绍: https://www.bilibili.com/video/BV1mH4y1w7qA?t=529.2" echo "------------------------------------------------" - echo "Red Hat 시리즈 배포판 CentOS/RedHat/Alma/Rocky/oracle만 지원" - echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경도 주의해서 업그레이드하시는 것을 추천드립니다!" + echo "仅支持红帽系列发行版 CentOS/RedHat/Alma/Rocky/oracle " + echo "Linux 커널을 업그레이드하면 시스템 성능과 보안이 향상될 수 있습니다. 가능하다면 시도해 보시고, 프로덕션 환경을 주의해서 업그레이드하시는 것을 추천드립니다!" echo "------------------------------------------------" read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -6976,7 +7034,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "스캔할 디렉터리를 지정하십시오." + echo "스캔할 디렉터리를 지정하세요." return fi @@ -7007,7 +7065,7 @@ clamav_scan() { clamscan -r --log=/var/log/clamav/scan.log $SCAN_PARAMS echo -e "${gl_lv}$@ 扫描完成,病毒报告存放在${gl_huang}/home/docker/clamav/log/scan.log${gl_bai}" - echo -e "${gl_lv}바이러스 있으면 제발${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" + echo -e "${gl_lv}如果有病毒请在${gl_huang}scan.log${gl_lv}파일에서 FOUND 키워드를 검색하여 바이러스 위치를 확인하세요.${gl_bai}" } @@ -7032,7 +7090,7 @@ clamav() { echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택사항을 입력하세요:" sub_choice + read -e -p "请输入你的选择: " sub_choice case $sub_choice in 1) send_stats "전체 스캔" @@ -7052,7 +7110,7 @@ clamav() { break_end ;; 3) - send_stats "사용자 정의 디렉토리 스캔" + send_stats "自定义目录扫描" read -e -p "스캔할 디렉터리를 공백으로 구분하여 입력하십시오(예: /etc /var /usr /home /root)." directories install_docker clamav_freshclam @@ -7074,7 +7132,7 @@ clamav() { # 원래의optim_high_performance/optim_balanced/optim_web_server/restore_defaults를 교체하십시오. # ============================================================================ -# 메모리 크기(MB) 가져오기 +# 获取内存大小(MB) _get_mem_mb() { awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo } @@ -7089,7 +7147,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}로 전환하다${mode_name}...${gl_bai}" - # ──장면에 따라 매개변수를 설정합니다── + # ──장면에 따라 매개변수를 설정하세요── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -7374,7 +7432,7 @@ optimize_high_performance() { } optimize_balanced() { - _kernel_optimize_core "균형 잡힌 최적화 모드" "balanced" + _kernel_optimize_core "均衡优化模式" "balanced" } optimize_web_server() { @@ -7420,7 +7478,7 @@ Kernel_optimize() { send_stats "Linux 커널 튜닝 관리" local current_mode=$(grep "^# 모드:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 모드: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="자동 튜닝 모드" - echo "Linux 시스템 커널 매개변수 최적화" + echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then echo -e "현재 모드:${gl_lv}${current_mode}${gl_bai}" else @@ -7435,7 +7493,7 @@ Kernel_optimize() { echo -e "2. 균형 잡힌 최적화 모드: 일상적인 사용에 적합한 성능과 리소스 소비 사이의 균형을 유지합니다." echo -e "3. 웹사이트 최적화 모드: 웹사이트 서버에 최적화되어 있으며 동시 연결 대기열이 매우 높습니다." echo -e "4. 라이브 방송 최적화 모드: 라이브 스트리밍 최적화를 위해 UDP 버퍼가 확장되어 지연이 줄어듭니다." - echo -e "5. 게임 서버 최적화 모드: 게임 서버에 최적화되어 낮은 대기 시간을 우선시합니다." + echo -e "5. 游戏服优化模式: 针对游戏服务器优化,低延迟优先。" echo -e "6. 기본 설정 복원: 시스템 설정을 기본 구성으로 복원합니다." echo -e "7. 자동 튜닝: 테스트 데이터를 기반으로 커널 매개변수를 자동으로 튜닝합니다.${gl_huang}★${gl_bai}" echo "--------------------" @@ -7454,13 +7512,13 @@ Kernel_optimize() { cd ~ clear optimize_balanced - send_stats "균형 모드 최적화" + send_stats "均衡模式优化" ;; 3) cd ~ clear optimize_web_server - send_stats "웹사이트 최적화 모델" + send_stats "웹사이트 최적화 모드" ;; 4) cd ~ @@ -7563,7 +7621,7 @@ while true; do ;; 2) update_locale "zh_CN.UTF-8" "zh_CN.UTF-8" - send_stats "중국어 간체로 전환" + send_stats "切换到简体中文" ;; 3) update_locale "zh_TW.UTF-8" "zh_TW.UTF-8" @@ -7676,7 +7734,7 @@ linux_trash() { clear echo -e "현재 휴지통${trash_status}" - echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 들어갑니다!" + echo -e "활성화한 후에는 중요한 파일이 실수로 삭제되는 것을 방지하기 위해 rm으로 삭제된 파일이 먼저 휴지통에 저장됩니다!" echo "------------------------------------------------" ls -l --color=auto "$TRASH_DIR" 2>/dev/null || echo "휴지통이 비어 있습니다." echo "------------------------" @@ -7693,7 +7751,7 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='trash-put'" >> "$bashrc_profile" source "$bashrc_profile" - echo "휴지통이 활성화되면 삭제된 파일은 휴지통으로 이동됩니다." + echo "回收站已启用,删除的文件将移至回收站。" sleep 2 ;; 2) @@ -7701,14 +7759,14 @@ linux_trash() { sed -i '/alias rm/d' "$bashrc_profile" echo "alias rm='rm -i'" >> "$bashrc_profile" source "$bashrc_profile" - echo "휴지통이 닫히고 파일이 직접 삭제됩니다." + echo "回收站已关闭,文件将直接删除。" sleep 2 ;; 3) read -e -p "복원할 파일 이름을 입력하세요:" file_to_restore if [ -e "$TRASH_DIR/$file_to_restore" ]; then mv "$TRASH_DIR/$file_to_restore" "$HOME/" - echo "$file_to_restore홈 디렉토리로 복원되었습니다." + echo "$file_to_restore 已还原到主目录。" else echo "파일이 존재하지 않습니다." fi @@ -7813,7 +7871,7 @@ restore_backup() { fi } -# 백업 나열 +# 列出备份 list_backups() { echo "사용 가능한 백업:" ls -1 "$BACKUP_DIR" @@ -7864,7 +7922,7 @@ linux_backup() { 3) delete_backup ;; *) break ;; esac - read -e -p "계속하려면 Enter를 누르세요..." + read -e -p "按回车键继续..." done } @@ -7948,7 +8006,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "오류: SSH 사용자 이름 형식이 잘못되었습니다." + echo "错误: SSH 用户名格式不正确。" return 1 fi @@ -8205,7 +8263,7 @@ mount_partition() { return 1 fi - # UUID 가져오기 + # 获取 UUID UUID=$(blkid -s UUID -o value "$DEVICE") if [ -z "$UUID" ]; then echo "UUID를 얻을 수 없습니다!" @@ -8215,7 +8273,7 @@ mount_partition() { # 파일 시스템 유형 가져오기 FSTYPE=$(blkid -s TYPE -o value "$DEVICE") if [ -z "$FSTYPE" ]; then - echo "파일 시스템 유형을 가져올 수 없습니다!" + echo "无法获取文件系统类型!" return 1 fi @@ -8249,7 +8307,7 @@ unmount_partition() { send_stats "파티션 마운트 해제" read -e -p "마운트 해제할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION - # 파티션이 마운트되었는지 확인 + # 检查分区是否已经挂载 MOUNT_POINT=$(lsblk -o MOUNTPOINT | grep -w "$PARTITION") if [ -z "$MOUNT_POINT" ]; then echo "파티션이 마운트되지 않았습니다!" @@ -8275,7 +8333,7 @@ list_mounted_partitions() { # 파티션 포맷 format_partition() { - send_stats "파티션 포맷" + send_stats "格式化分区" read -e -p "포맷할 파티션의 이름을 입력하십시오(예: sda1):" PARTITION # 파티션이 존재하는지 확인 @@ -8320,14 +8378,14 @@ format_partition() { if [ $? -eq 0 ]; then echo "파티션이 성공적으로 포맷되었습니다!" else - echo "파티션 포맷에 실패했습니다!" + echo "分区格式化失败!" fi } # 파티션 상태 확인 check_partition() { send_stats "파티션 상태 확인" - read -e -p "확인할 파티션 이름을 입력하세요(예: sda1):" PARTITION + read -e -p "请输入要检查的分区名称(例如 sda1): " PARTITION # 파티션이 존재하는지 확인 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then @@ -8386,10 +8444,10 @@ add_task() { echo "- 작업 이름: backup_www" echo "- 로컬 디렉터리: /var/www" echo "- 원격 주소: user@192.168.1.100" - echo "- 원격 디렉터리: /backup/www" + echo " - 远程目录: /backup/www" echo "- 포트 번호(기본값 22)" echo "---------------------------------" - read -e -p "작업 이름을 입력하세요:" name + read -e -p "请输入任务名称: " name read -e -p "로컬 디렉토리를 입력하십시오:" local_path read -e -p "원격 디렉토리를 입력하십시오:" remote_path @@ -8542,9 +8600,9 @@ schedule_task() { fi echo "예약된 실행 간격을 선택하십시오." - echo "1) 매 시간마다 한 번씩 실행" + echo "1) 每小时执行一次" echo "2) 하루에 한 번 실행" - echo "3) 일주일에 한 번 실행" + echo "3) 每周执行一次" read -e -p "옵션을 입력하세요(1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 @@ -8685,7 +8743,7 @@ linux_info() { local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') - local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1% 3600) / 60); if (run_days > 0) printf("%d day ", run_days); if (run_hours > 0) printf("%d시간 ", run_hours); printf("%d분\n", run_mins)}') + local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') local timezone=$(current_timezone) @@ -8700,9 +8758,9 @@ linux_info() { echo -e "${gl_kjlan}리눅스 버전:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 아키텍처:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU 모델:${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" echo -e "${gl_kjlan}CPU 코어 수:${gl_bai}$cpu_cores" - echo -e "${gl_kjlan}CPU 주파수:${gl_bai}$cpu_freq" + echo -e "${gl_kjlan}CPU频率: ${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU 사용량:${gl_bai}$cpu_usage_percent%" echo -e "${gl_kjlan}시스템 부하:${gl_bai}$load" @@ -8718,7 +8776,7 @@ linux_info() { echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}연산자:${gl_bai}$isp_info" if [ -n "$ipv4_address" ]; then - echo -e "${gl_kjlan}IPv4 주소:${gl_bai}$ipv4_address" + echo -e "${gl_kjlan}IPv4地址: ${gl_bai}$ipv4_address" fi if [ -n "$ipv6_address" ]; then @@ -8771,7 +8829,7 @@ linux_tools() { exit 1 fi - echo "📦 패키지 관리자를 사용하세요:$PM" + echo "📦 使用包管理器: $PM" echo -e "${gl_kjlan}------------------------${gl_bai}" for ((i=0; i<${#tools[@]}; i+=2)); do @@ -8779,10 +8837,10 @@ linux_tools() { if command -v "${tools[i]}" >/dev/null 2>&1; then left=$(printf "✅ %-12s 설치됨" "${tools[i]}") else - left=$(printf "❌ %-12s가 설치되지 않았습니다." "${tools[i]}") + left=$(printf "❌ %-12s 未安装" "${tools[i]}") fi - # 오른쪽 열(배열이 범위를 벗어나는 것을 방지하기 위해) + # 右列(防止数组越界) if [[ -n "${tools[i+1]}" ]]; then if command -v "${tools[i+1]}" >/dev/null 2>&1; then right=$(printf "✅ %-12s 설치됨" "${tools[i+1]}") @@ -8800,11 +8858,11 @@ linux_tools() { echo -e "${gl_kjlan}3. ${gl_bai}sudo 최고 관리 권한 도구${gl_kjlan}4. ${gl_bai}socat 통신 연결 도구" echo -e "${gl_kjlan}5. ${gl_bai}htop 시스템 모니터링 도구${gl_kjlan}6. ${gl_bai}iftop 네트워크 트래픽 모니터링 도구" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP 압축 및 압축 풀기 도구${gl_kjlan}8. ${gl_bai}tar GZ 압축 및 압축 해제 도구" - echo -e "${gl_kjlan}9. ${gl_bai}tmux 다중 채널 백그라운드 실행 도구${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" + echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路后台运行工具 ${gl_kjlan}10. ${gl_bai}ffmpeg 비디오 인코딩 라이브 스트리밍 도구" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}11. ${gl_bai}btop 최신 모니터링 도구${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}레인저 파일 관리 도구" + echo -e "${gl_kjlan}11. ${gl_bai}btop 现代化监控工具 ${gl_huang}★${gl_bai} ${gl_kjlan}12. ${gl_bai}ranger 文件管理工具" echo -e "${gl_kjlan}13. ${gl_bai}ncdu 디스크 사용량 보기 도구${gl_kjlan}14. ${gl_bai}fzf 글로벌 검색 도구" - echo -e "${gl_kjlan}15. ${gl_bai}vim 텍스트 편집기${gl_kjlan}16. ${gl_bai}나노 텍스트 편집기${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}15. ${gl_bai}vim 文本编辑器 ${gl_kjlan}16. ${gl_bai}nano 文本编辑器 ${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}17. ${gl_bai}Git 버전 관리 시스템${gl_kjlan}18. ${gl_bai}오픈코드 AI 프로그래밍 도우미${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}매트릭스 스크린세이버${gl_kjlan}22. ${gl_bai}달리는 기차 화면 보호기" @@ -8833,7 +8891,7 @@ linux_tools() { clear install wget clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" wget --help send_stats "wget 설치" ;; @@ -8849,7 +8907,7 @@ linux_tools() { clear install socat clear - echo "도구가 설치되었으며 다음과 같이 사용됩니다." + echo "工具已安装,使用方法如下:" socat -h send_stats "socat 설치" ;; @@ -8994,7 +9052,7 @@ linux_tools() { install bastet clear bastet - send_stats "바스테트 설치" + send_stats "安装bastet" ;; 27) clear @@ -9269,12 +9327,12 @@ docker_ssh_migration() { continue fi - read -e -p "Compose 프로젝트 복원 확인 [$project_name] 경로 [$original_path] ? (y/n): " confirm + read -e -p "Compose 프로젝트 복원 확인 [$project_name] 到路径 [$original_path] ? (y/n): " confirm [[ "$confirm" != "y" ]] && read -e -p "새 복원 경로를 입력하십시오." original_path mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}프로젝트 작성 [$project_name]가 다음 위치로 추출되었습니다.$original_path${gl_bai}" + echo -e "${gl_lv}프로젝트 작성 [$project_name] 已解压到: $original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -9284,17 +9342,17 @@ docker_ssh_migration() { done # --------- 일반 컨테이너를 계속 복원합니다 --------- - echo -e "${gl_kjlan}일반 Docker 컨테이너 확인 및 복원...${gl_bai}" + echo -e "${gl_kjlan}检查并还原普通 Docker 容器...${gl_bai}" local has_container=false for json in "$BACKUP_DIR"/*_inspect.json; do [[ ! -f "$json" ]] && continue has_container=true container=$(basename "$json" | sed 's/_inspect.json//') - echo -e "${gl_lv}처리용기:$container${gl_bai}" + echo -e "${gl_lv}처리 용기:$container${gl_bai}" # 컨테이너가 이미 존재하고 실행 중인지 확인하세요. if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then - echo -e "${gl_huang}컨테이너 [$container] 이미 실행 중입니다. 복원을 건너뛰는 중...${gl_bai}" + echo -e "${gl_huang}컨테이너 [$container] 已在运行,跳过还原...${gl_bai}" continue fi @@ -9326,7 +9384,7 @@ docker_ssh_migration() { VOL_FILE="$BACKUP_DIR/${container}_$(basename $VOL_SRC).tar.gz" if [[ -f "$VOL_FILE" ]]; then - echo "볼륨 데이터 복구:$VOL_SRC" + echo "恢复卷数据: $VOL_SRC" tar -xzf "$VOL_FILE" -C / fi done @@ -9376,7 +9434,7 @@ docker_ssh_migration() { echo -e "${gl_huang}백업 전송 중...${gl_bai}" if [[ -z "$TARGET_PASS" ]]; then - # 키를 사용하여 로그인 + # 使用密钥登录 scp -P "$TARGET_PORT" -o StrictHostKeyChecking=no -r "$LATEST_TAR" "$TARGET_USER@$TARGET_IP:/tmp/" fi @@ -9409,7 +9467,7 @@ docker_ssh_migration() { echo -e "1. 도커 프로젝트 백업" echo -e "2. 도커 프로젝트 마이그레이션" echo -e "3. 도커 프로젝트 복원" - echo -e "4. docker 프로젝트 백업 파일 삭제" + echo -e "4. 删除docker项目的备份文件" echo "------------------------" echo -e "0. 이전 메뉴로 돌아가기" echo "------------------------" @@ -9448,9 +9506,9 @@ linux_docker() { echo -e "${gl_kjlan}3. ${gl_bai}도커 컨테이너 관리${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}4. ${gl_bai}도커 이미지 관리" echo -e "${gl_kjlan}5. ${gl_bai}도커 네트워크 관리" - echo -e "${gl_kjlan}6. ${gl_bai}도커 볼륨 관리" + echo -e "${gl_kjlan}6. ${gl_bai}Docker卷管理" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}7. ${gl_bai}쓸모없는 도커 컨테이너를 정리하고 네트워크 데이터 볼륨을 미러링하세요." + echo -e "${gl_kjlan}7. ${gl_bai}清理无用的docker容器和镜像网络数据卷" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}8. ${gl_bai}Docker 소스 변경" echo -e "${gl_kjlan}9. ${gl_bai}daemon.json 파일 편집" @@ -9609,7 +9667,7 @@ linux_docker() { ;; 2) - read -e -p "삭제 볼륨 이름을 입력하십시오(여러 볼륨 이름을 공백으로 구분하십시오):" dockerjuans + read -e -p "삭제 볼륨 이름을 입력하세요(여러 볼륨 이름을 공백으로 구분하세요):" dockerjuans for dockerjuan in $dockerjuans; do docker volume rm $dockerjuan @@ -9655,7 +9713,7 @@ linux_docker() { ;; 8) clear - send_stats "도커 소스" + send_stats "Docker源" bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; @@ -9722,6 +9780,382 @@ linux_docker() { +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel 경량 노드 설치에는 루트 권한이 필요합니다." >&2 + return 1 + } + for command_name in curl sha256sum mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "필수 명령 누락:${command_name}" >&2 + return 1 + } + done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "필수 명령 누락: systemctl" >&2 + return 1 + } + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "필수 명령 누락: 설치(coreutils)" >&2 + return 1 + } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "누락된 시스템 계정 생성 도구: useradd, systemd-sysusers 또는 adduser" >&2 + return 1 + fi + [ -d /run/systemd/system ] || { + echo "현재 시스템은 systemd를 실행하고 있지 않으며 KPanel 경량 노드를 설치할 수 없습니다." >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "현재 CPU 아키텍처는 현재 KPanel 경량 노드를 지원하지 않습니다." >&2 + return 1 + ;; + esac +} + +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "기존 케질리온-노드 계정의 기본 그룹은 안전하지 않아 계속 진행이 거부됩니다." >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "누락된 시스템 그룹 생성 도구: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel 경량 노드 낮은 권한 계정 생성에 실패했습니다." >&2 + return 1 + } +} + +kpanel_node_write_updater() { + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null +} + +kpanel_node_join() { + local token="${1:-}" node_name resume_enrollment=false + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "경량 노드 액세스 권한이 유효하지 않습니다." >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "경량 노드 액세스 권한이 유효하지 않습니다." >&2 + return 2 + } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "완료된 노드 승인이 감지되었습니다. 기본 서비스를 계속 활성화하세요." + else + echo "이 시스템에는 불완전한 KPanel 노드 구성이 있습니다. 먼저 k kpanel node uninstall을 실행해 보세요." >&2 + return 1 + fi + fi + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join + return 1 + fi + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + echo "노드 인증이 저장되었지만 구성 권한 복구에 실패했습니다. 계속하려면 액세스 명령을 다시 실행하십시오." >&2 + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + echo "노드 인증이 저장되었지만 systemd 장치에 쓰는 데 실패했습니다. 계속하려면 액세스 명령을 다시 실행하십시오." >&2 + return 1 + fi + if ! kpanel_node_activate; then + echo "KPanel 경량 노드 인증이 저장되었지만 서비스를 시작하지 못했습니다. systemd를 복구하고 access 명령을 다시 실행하여 설치를 계속하십시오." >&2 + return 1 + fi + echo "KPanel 경량 노드가 연결되었으며 나중에 자동으로 업데이트됩니다." +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel 경량 노드가 설치되지 않았습니다." >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel 경량 노드가 설치되지 않았습니다." >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "KPanel 경량 노드를 제거하려면 루트 권한이 필요합니다." >&2 + return 1 + } + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true + echo "KPanel 경량 노드가 로컬 시스템에서 제거되었습니다. 클러스터 페이지에서 센터의 오프라인 기록을 삭제해야 합니다." +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "사용법: k kpanel 노드 조인 | 상태 | 업데이트 | 제거" >&2 + return 2 + ;; + esac +} + kpanel_test_catalog() { cat <<'KPANEL_TEST_CATALOG' KPANEL_TEST_CATEGORY access IP 与解锁 @@ -10121,7 +10555,7 @@ linux_Oracle() { read -e -p "CPU 코어 수를 입력하십시오.[기본값:$DEFAULT_CPU_CORE]: " cpu_core local cpu_core=${cpu_core:-$DEFAULT_CPU_CORE} - read -e -p "CPU 사용량 백분율 범위(예: 10-20)를 입력하십시오. [기본값:$DEFAULT_CPU_UTIL]: " cpu_util + read -e -p "请输入CPU占用百分比范围(例如10-20) [默认: $DEFAULT_CPU_UTIL]: " cpu_util local cpu_util=${cpu_util:-$DEFAULT_CPU_UTIL} read -e -p "메모리 사용량 비율을 입력하십시오.[기본값:$DEFAULT_MEM_UTIL]: " mem_util @@ -10130,7 +10564,7 @@ linux_Oracle() { read -e -p "속도 테스트 간격 시간(초)을 입력하십시오. [기본값:$DEFAULT_SPEEDTEST_INTERVAL]: " speedtest_interval local speedtest_interval=${speedtest_interval:-$DEFAULT_SPEEDTEST_INTERVAL} - # Docker 컨테이너 실행 + # 运行Docker容器 docker run -d --name=lookbusy --restart=always \ -e TZ=Asia/Shanghai \ -e CPU_UTIL="$cpu_util" \ @@ -10217,7 +10651,7 @@ linux_Oracle() { ;; *) - echo "입력이 잘못되었습니다!" + echo "无效的输入!" ;; esac break_end @@ -10241,7 +10675,7 @@ docker_tato() { if command -v docker &> /dev/null; then echo -e "${gl_kjlan}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다.${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai}회로망:${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" + echo -e "${gl_lv}환경이 설치되었습니다.${gl_bai}컨테이너:${gl_lv}$container_count${gl_bai}거울:${gl_lv}$image_count${gl_bai} 网络: ${gl_lv}$network_count${gl_bai}연타:${gl_lv}$volume_count${gl_bai}" fi } @@ -10262,7 +10696,7 @@ local db_output="${gl_lv}${db_count}${gl_bai}" if command -v docker &>/dev/null; then if docker ps --filter "name=nginx" --filter "status=running" | grep -q nginx; then echo -e "${gl_huang}------------------------" - echo -e "${gl_lv}환경이 설치되었습니다${gl_bai}대지:$output데이터 베이스:$db_output" + echo -e "${gl_lv}환경이 설치되었습니다${gl_bai} 站点: $output데이터 베이스:$db_output" fi fi @@ -10758,14 +11192,14 @@ kpanel_ldnmp_run() { fi kpanel_ldnmp_event start 1 "LDNMP 환경 작업이 시작되었습니다." if "$function_name" "$@"; then - kpanel_ldnmp_event complete 100 "LDNMP 환경 작업 완료" + kpanel_ldnmp_event complete 100 "LDNMP 环境任务已完成" kpanel_ldnmp_result succeeded "$action" "작업 실행 성공" rc=0 else rc=$? - kpanel_ldnmp_event failed 100 "LDNMP 환경 작업 실행 실패" + kpanel_ldnmp_event failed 100 "LDNMP 环境任务执行失败" if [ "$rc" -eq 86 ]; then - kpanel_ldnmp_result needs_attention "$action" "작업이 실패했으며 안전한 롤백을 확인할 수 없어 수동 처리가 필요합니다." + kpanel_ldnmp_result needs_attention "$action" "任务失败且无法确认安全回滚,需要人工处理" else kpanel_ldnmp_result failed "$action" "작업 실행 실패" fi @@ -10780,11 +11214,11 @@ ldnmp_environment_menu() { clear echo "LDNMP 환경 관리" echo "------------------------" - echo "1. 환경상태를 확인한다" - echo "2. 전체 LDNMP 설치" + echo "1. 查看环境状态" + echo "2. 安装完整 LDNMP" echo "3. Nginx만 설치" echo "4. 보호관리" - echo "5. 관리 최적화" + echo "5. 优化管理" echo "6. 환경 업데이트" echo "7. 콜드 대기 만들기" echo "8. 백업 복원" @@ -10803,7 +11237,7 @@ ldnmp_environment_menu() { 5) web_optimization ;; 6) read -e -p "구성 요소 업데이트(nginx/mysql/php/redis/all):" component - read -e -p "대상 버전(기본 최신 버전):" version + read -e -p "目标版本(默认 latest): " version ldnmp_update_action "$component" "${version:-latest}" false ;; 7) ldnmp_backup_action ;; @@ -10817,7 +11251,7 @@ ldnmp_environment_menu() { [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true ;; 0) return 0 ;; - *) echo "잘못된 입력" ;; + *) echo "无效的输入" ;; esac break_end done @@ -10864,18 +11298,18 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}LDNMP 환경 설치${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}워드프레스 설치${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}Discuz 포럼 설치${gl_huang}4. ${gl_bai}Kedao 클라우드 데스크탑 설치" - echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 TV 스테이션 설치${gl_huang}6. ${gl_bai}Unicorn 디지털 카드 네트워크 설치" - echo -e "${gl_huang}7. ${gl_bai}flarum 포럼 웹사이트 설치${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" + echo -e "${gl_huang}5. ${gl_bai}Apple CMS 영화 및 TV 스테이션 설치${gl_huang}6. ${gl_bai}安装独角数发卡网" + echo -e "${gl_huang}7. ${gl_bai}安装flarum论坛网站 ${gl_huang}8. ${gl_bai}typecho 경량 블로그 웹사이트 설치" echo -e "${gl_huang}9. ${gl_bai}LinkStack 공유 링크 플랫폼 설치${gl_huang}20. ${gl_bai}맞춤 동적 사이트" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}21. ${gl_bai}nginx만 설치하세요${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}사이트 리디렉션" echo -e "${gl_huang}23. ${gl_bai}사이트 역방향 프록시-IP+포트${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}사이트 역방향 프록시 도메인 이름" - echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}Halo 블로그 사이트 설치" + echo -e "${gl_huang}25. ${gl_bai}Bitwarden 비밀번호 관리 플랫폼 설치${gl_huang}26. ${gl_bai}安装Halo博客网站" echo -e "${gl_huang}27. ${gl_bai}AI 그림 프롬프트 단어 생성기 설치${gl_huang}28. ${gl_bai}사이트 역방향 프록시-로드 밸런싱" echo -e "${gl_huang}29. ${gl_bai}스트림 4계층 프록시 전달${gl_huang}30. ${gl_bai}사용자 정의 정적 사이트" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}사이트 데이터 관리${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}사이트 전체 데이터 백업" - echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}전체 사이트 데이터 복원" + echo -e "${gl_huang}33. ${gl_bai}예약된 원격 백업${gl_huang}34. ${gl_bai}还原全站数据" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}LDNMP 환경 보호${gl_huang}36. ${gl_bai}LDNMP 환경 최적화" echo -e "${gl_huang}37. ${gl_bai}LDNMP 환경 업데이트${gl_huang}38. ${gl_bai}LDNMP 환경 제거" @@ -11068,7 +11502,7 @@ linux_ldnmp() { clear # 한쪽다리 숫자카드 webname="한쪽다리 숫자카드" - send_stats "설치하다$webname" + send_stats "安装$webname" echo "배포 시작$webname" add_yuming repeat_add_yuming @@ -11110,10 +11544,10 @@ linux_ldnmp() { echo "웹사이트 URL: https://$yuming" echo "백엔드 로그인 경로: /admin" echo "------------------------" - echo "사용자 이름: 관리자" + echo "用户名: admin" echo "비밀번호: 관리자" echo "------------------------" - echo "로그인 시 오른쪽 상단에 빨간색 error0이 나타나는 경우, 다음 명령어를 사용하시기 바랍니다." + echo "登录时右上角如果出现红色error0请使用如下命令: " echo "유니콘 숫자카드가 왜 이렇게 귀찮고 이런 문제가 있는지에 대해서도 너무 화가 납니다!" echo "sed -i 's/ADMIN_HTTPS=false/ADMIN_HTTPS=true/g' /home/web/html/$yuming/dujiaoka/.env" @@ -11177,7 +11611,7 @@ linux_ldnmp() { echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" echo "테이블 접두사: flarum_" - echo "관리자 정보는 직접 설정 가능" + echo "管理员信息自行设置" ;; @@ -11263,7 +11697,7 @@ linux_ldnmp() { ldnmp_web_on echo "데이터베이스 주소: mysql" echo "데이터베이스 포트: 3306" - echo "데이터베이스 이름:$dbname" + echo "数据库名: $dbname" echo "사용자 이름:$dbuse" echo "비밀번호:$dbusepasswd" ;; @@ -11310,13 +11744,13 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "(/home/web/html/과 유사하게 index.php 경로를 입력하세요.$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf clear - echo -e "[${gl_huang}3/6${gl_bai}] PHP 버전을 선택해주세요." + echo -e "[${gl_huang}3/6${gl_bai}] 请选择PHP版本" echo "-------------" read -e -p "1. PHP 최신 버전 | 2.php7.4:" pho_v case "$pho_v" in @@ -11358,7 +11792,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}6/6${gl_bai}] 데이터베이스 관리" echo "-------------" - read -e -p "1. 새 사이트를 구축합니다. 2. 이전 사이트를 구축하고 데이터베이스 백업을 가지고 있습니다." use_db + read -e -p "1. 我搭建新站 2. 我搭建老站有数据库备份: " use_db case $use_db in 1) echo @@ -11409,7 +11843,7 @@ linux_ldnmp() { 22) clear webname="사이트 리디렉션" - send_stats "설치하다$webname" + send_stats "安装$webname" echo "배포 시작$webname" add_yuming read -e -p "리디렉션 도메인 이름을 입력하세요." reverseproxy @@ -11455,7 +11889,7 @@ linux_ldnmp() { echo "배포 시작$webname" add_yuming echo -e "도메인 이름 형식:${gl_huang}google.com${gl_bai}" - read -e -p "역방향 프록시 도메인 이름을 입력하세요." fandai_yuming + read -e -p "역방향 프록시 도메인 이름을 입력하세요:" fandai_yuming nginx_install_status install_ssltls @@ -11669,7 +12103,7 @@ linux_ldnmp() { echo "------------------------" echo "1. 주간 백업 2. 일일 백업" - read -e -p "선택사항을 입력하세요:" dingshi + read -e -p "请输入你的选择: " dingshi case $dingshi in 1) @@ -12650,7 +13084,7 @@ EOF echo done - # 4. 더 이상 API 유형을 감지/판단하지 않습니다. 프로토콜은 사용자가 직접 선택하고 유지 관리합니다. + # 4. 더 이상 API 유형을 감지/결정하지 않습니다. 프로토콜은 사용자가 직접 선택하고 유지 관리합니다. # 5. 모델 목록 가져오기 echo "🔍 사용 가능한 모델 목록을 가져오는 중..." @@ -13288,7 +13722,7 @@ if ref_provider(primary_ref) == name: print('❌ 삭제가 중단됨: 기본 기본 모델이 공급자를 가리키며 대체 모델을 사용할 수 없습니다.') raise SystemExit(3) set_primary_ref(defaults, replacement) - print(f'🔁 기본 기본 모델 전환: {primary_ref} -> {replacement}') + print(f'🔁 默认主模型切换: {primary_ref} -> {replacement}') for fk in ('modelFallback', 'imageModelFallback'): val = defaults.get(fk) @@ -13335,7 +13769,7 @@ PY } openclaw_api_providers_showcase() { - send_stats "OpenClaw API 공급업체 권장 사항" + send_stats "OpenClaw API 공급업체 권장사항" clear echo "" @@ -13387,7 +13821,7 @@ PY echo -e " ${gl_kjlan}https://ai.baishan.com/${gl_bai}" echo "" echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" - echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 추천 입장${gl_bai}" + echo -e " ${gl_zi}전설:${gl_lv}● 공식 입장${gl_bai} ${gl_huang}● AFF 推荐入口${gl_bai}" echo "" echo -e "${gl_huang}팁: 링크를 복사하고 브라우저에서 열어서 액세스하세요.${gl_bai}" echo "" @@ -13517,7 +13951,7 @@ REPO api_key=$(jq -r --arg provider "$provider_name" '.models.providers[$provider].apiKey // empty' "$oc_config" 2>/dev/null) if [ -z "$provider_name" ] || [ -z "$base_url" ] || [ -z "$api_key" ]; then OPENCLAW_PROBE_STATUS="ERROR" - OPENCLAW_PROBE_MESSAGE="공급자/baseUrl/apiKey를 읽을 수 없습니다." + OPENCLAW_PROBE_MESSAGE="未读取到 provider/baseUrl/apiKey" OPENCLAW_PROBE_LATENCY="-" OPENCLAW_PROBE_REPLY="-" return 1 @@ -13643,7 +14077,7 @@ PYTHON_EOF first_reply="$reply_preview" reply_trimmed=$(printf '%s' "$first_reply" | cut -c1-120) - [ -z "$reply_trimmed" ] && reply_trimmed="(빈 반환)" + [ -z "$reply_trimmed" ] && reply_trimmed="(空返回)" if [ "$first_exit" = "0" ] && [ "$first_http" -ge 200 ] && [ "$first_http" -lt 300 ]; then OPENCLAW_PROBE_STATUS="OK" @@ -13698,7 +14132,7 @@ PYTHON_EOF return 1 fi - # 빠른 위치를 쉽게 찾을 수 있도록 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") + # 빠른 찾기를 위해 각 모델에 번호를 매깁니다(예: "(10) or-api/...:free") models_list=$(echo "$models_raw" | awk '{print "(" NR ") " $0}') model_count=$(echo "$models_list" | sed '/^\s*$/d' | wc -l | tr -d ' ') @@ -13725,7 +14159,7 @@ PYTHON_EOF fi if [ -z "$selected_model" ]; then - echo "오류: 모델 이름은 비워둘 수 없습니다. 다시 시도해 주세요." + echo "错误:模型名称不能为空。请重试。" echo "" continue fi @@ -13767,7 +14201,7 @@ PYTHON_EOF echo "" echo "모델 감지:$selected_model" if openclaw_model_probe "$selected_model"; then - openclaw_probe_status_line "사용 가능" + openclaw_probe_status_line "可用" else openclaw_probe_status_line "사용할 수 없음" fi @@ -13776,7 +14210,7 @@ PYTHON_EOF echo "요약:$OPENCLAW_PROBE_REPLY" echo "" - printf "이 모델로 전환하시겠습니까? [y/N, Esc를 누르면 목록으로 돌아갑니다.]:" + printf "이 모델로 전환하시겠습니까? [y/N, Esc가 목록으로 돌아갑니다]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -13957,7 +14391,7 @@ PYTHON_EOF fi fi - echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하십시오:$config_file" + echo "⚠️ 플러그인이 설치되었지만,plugins.allow의 동기화에 실패했습니다. 수동으로 확인하세요.$config_file" return 1 } @@ -14041,12 +14475,12 @@ PYTHON_EOF echo "현재 플러그인 목록:" openclaw plugins list echo "--------------------------------------------------------" - echo "일반적으로 사용되는 권장 플러그인 ID(괄호 안에 ID를 복사하면 됩니다):" + echo "推荐的常用插件 ID (直接复制括号内的 ID 即可):" echo "--------------------------------------------------------" echo "📱 커뮤니케이션 채널:" echo "- [feishu] # 페이슈/종달새 통합" echo "- [텔레그램] # 텔레그램 봇" - echo "- [slack] #Slack 기업 커뮤니케이션" + echo " - [slack] # Slack 企业通讯" echo " - [msteams] # Microsoft Teams" echo "- [디스코드] # 디스코드 커뮤니티 관리" echo "- [whatsapp] #WhatsApp 자동화" @@ -14056,7 +14490,7 @@ PYTHON_EOF echo "- [memory-lancedb] # 향상된 메모리(벡터 데이터베이스)" echo "- [copilot-proxy] # Copilot 인터페이스 전달" echo "" - echo "⚙️ 기능 확장:" + echo "⚙️ 功能扩展:" echo "- [랍스터] # 승인 흐름(수동 확인 포함)" echo "- [음성통화] # 음성통화 기능" echo "- [nostr] # 암호화된 비공개 채팅" @@ -14064,8 +14498,8 @@ PYTHON_EOF echo "1) 플러그인 설치/활성화" echo "2) 플러그인 삭제/비활성화" - echo "0) 반품" - read -e -p "작업을 선택하십시오:" plugin_action + echo "0) 반환" + read -e -p "请选择操作:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue @@ -14088,7 +14522,7 @@ PYTHON_EOF [ -z "$plugin_id" ] && continue if [ "$plugin_action" = "1" ]; then - echo "🔍 플러그인 상태 확인:$plugin_id" + echo "🔍 플러그인 상태 확인 중:$plugin_id" local plugin_list plugin_list=$(openclaw plugins list 2>/dev/null) @@ -14129,7 +14563,7 @@ PYTHON_EOF failed_list="$failed_list $plugin_id" fi else - echo "❌ 설치 실패:$plugin_full" + echo "❌ 安装失败:$plugin_full" failed_list="$failed_list $plugin_id" fi else @@ -14177,10 +14611,10 @@ PYTHON_EOF echo "github # GitHub 문제/PR/CI 관리(gh CLI)" echo "notion # Notion 페이지, 데이터베이스 및 블록을 조작합니다." echo "apple-notes # macOS 기본 노트 관리(생성/편집/검색)" - echo "apple-reminders # macOS 미리 알림 관리(할 일 목록)" + echo "apple-reminders # macOS 提醒事项管理 (待办清单)" echo "1password # 1Password 키 읽기 및 삽입 자동화" echo "gog # Google Workspace(Gmail/클라우드 디스크/문서) 만능 도우미" - echo "things-mac # Things 3 작업 관리의 심층 통합" + echo "things-mac # 深度整合 Things 3 任务管理" echo "bluebubbles # BlueBubbles를 사용하여 iMessage를 완벽하게 보내고 받습니다." echo "히말라야 # 터미널 메일 관리(IMAP/SMTP 강력한 도구)" echo "summary # 웹페이지/팟캐스트/YouTube 비디오 콘텐츠를 원클릭으로 요약" @@ -14192,7 +14626,7 @@ PYTHON_EOF echo "1) 설치 기술" echo "2) 스킬 삭제" - echo "0) 반품" + echo "0) 반환" read -e -p "작업을 선택하십시오:" skill_action [ "$skill_action" = "0" ] && break @@ -14265,7 +14699,7 @@ PYTHON_EOF done echo "" - echo "====== 작업 요약 ======" + echo "====== 操作汇总 ======" echo "✅ 성공:$success_list" [ -n "$failed_list" ] && echo "❌ 실패:$failed_list" [ -n "$skipped_list" ] && echo "⏭️ 건너뛰기:$skipped_list" @@ -14325,7 +14759,7 @@ openclaw_json_get_bool() { return 0 fi - # 두 가지 일반적인 디렉터리 이름과 호환됩니다. + # 兼容两种常见目录命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot # 두뇌 없는 하위 문자열을 피하고 정확한 일치와 openclaw- 접두사 일치를 선호합니다. @@ -14343,9 +14777,9 @@ openclaw_json_get_bool() { if [ "$abnormal" = "true" ]; then echo "이상" elif [ "$enabled" != "true" ]; then - echo "활성화되지 않음" + echo "未启用" elif [ "$connected" = "true" ]; then - echo "연결됨" + echo "已连接" elif [ "$configured" = "true" ]; then echo "구성된" else @@ -14515,7 +14949,7 @@ openclaw_json_get_bool() { echo "2. Feishu(Lark) 로봇 도킹" echo "3. WhatsApp 봇 도킹" echo "4. QQ 로봇 도킹" - echo "5. 위챗 로봇 도킹" + echo "5. 微信机器人对接" echo "----------------------------------------" echo "0. 이전 메뉴로 돌아가기" echo "----------------------------------------" @@ -14523,7 +14957,7 @@ openclaw_json_get_bool() { case $bot_choice in 1) - read -e -p "TG 로봇이 수신한 연결 코드(예: NYA99R2F)를 입력하세요(종료하려면 0 입력)." code + read -e -p "请输入TG机器人收到的连接码 (例如 NYA99R2F)(输入 0 退出): " code if [ "$code" = "0" ]; then continue; fi if [ -z "$code" ]; then echo "오류: 연결 코드는 비워둘 수 없습니다."; sleep 1; continue; fi openclaw pairing approve telegram "$code" @@ -14784,7 +15218,7 @@ if os.path.isdir(agents_root): echo "백업 모드:" echo "1. 안전 모드(기본값, 권장): 작업 공간 + openclaw.json + 확장/기술/프롬프트/도구(존재하는 경우)" - echo "2. 전체 모드(더 많은 상태 포함, 더 높은 민감도 위험)" + echo "2. 完整模式(含更多状态,敏感风险更高)" read -e -p "백업 모드를 선택하십시오(기본값 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -14833,7 +15267,7 @@ if os.path.isdir(agents_root): } openclaw_project_backup_import() { - send_stats "OpenClaw 프로젝트 복원" + send_stats "OpenClaw项目还原" local config_file config_file=$(openclaw_get_config_file) local openclaw_root @@ -14864,7 +15298,7 @@ if os.path.isdir(agents_root): while IFS= read -r rel; do [ -z "$rel" ] && continue if ! openclaw_is_safe_relpath "$rel" || ! openclaw_restore_path_allowed project "$rel"; then - echo "❌ 불법 또는 승인되지 않은 경로가 감지되었습니다:$rel" + echo "❌ 检测到非法或越权路径: $rel" invalid=1 break fi @@ -14874,7 +15308,7 @@ if os.path.isdir(agents_root): if [ "$invalid" -ne 0 ]; then rm -f "$valid_list" rm -rf "$tmp_unpack" - echo "❌ 복원이 중단되었습니다: 안전하지 않은 경로가 존재합니다." + echo "❌ 복원이 중단되었습니다. 안전하지 않은 경로가 존재합니다." break_end return 1 fi @@ -14909,7 +15343,7 @@ if os.path.isdir(agents_root): if [[ "$file_name" == openclaw-memory-full-*.tar.gz ]]; then echo "메모리 백업 파일" elif [[ "$file_name" == openclaw-project-*.tar.gz ]]; then - echo "프로젝트 백업 파일" + echo "项目备份文件" else echo "기타 백업 파일" fi @@ -14975,7 +15409,7 @@ if os.path.isdir(agents_root): for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "기타 백업 파일" ] && continue + [ "$file_type" != "其他备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -15006,7 +15440,7 @@ if os.path.isdir(agents_root): read -e -p "삭제할 파일 이름이나 전체 경로를 입력하십시오. (취소하려면 0):" user_input if [ "$user_input" = "0" ]; then - echo "삭제가 취소되었습니다." + echo "已取消删除。" break_end return 0 fi @@ -15022,7 +15456,7 @@ if os.path.isdir(agents_root): case "$target_path" in "$backup_root_real"/*) ;; *) - echo "❌ 경로 밖: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." + echo "❌ 경로 초과: 백업 루트 디렉터리에 있는 파일만 삭제가 허용됩니다." break_end return 1 ;; @@ -15040,7 +15474,7 @@ if os.path.isdir(agents_root): fi if ! openclaw_backup_file_exists_in_list "$target_file"; then - echo "❌ 현재 백업 목록에 대상 파일이 없습니다." + echo "❌ 目标文件不在当前备份列表中。" break_end return 1 fi @@ -15244,7 +15678,7 @@ $agent_lines EOF openclaw gateway restart echo "✅ 인덱스가 재구축되었으며 게이트웨이가 자동으로 다시 시작되었습니다." - echo "✅ 이미${count}에이전트가 인덱스를 다시 작성합니다." + echo "✅ 이미${count}에이전트가 색인을 다시 작성합니다." echo "" openclaw_memory_render_status } @@ -15428,7 +15862,7 @@ PY elif [ "$mirror_ok" = "ok" ]; then OPENCLAW_MEMORY_RECOMMEND_REASON+=("hf-mirror.com에 접속할 수 있습니다") else - OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 접속할 수 없습니다(국내/제한된 네트워크로 의심됨).") + OPENCLAW_MEMORY_RECOMMEND_REASON+=("Huggingface.co / hf-mirror.com에 연결할 수 없을 수 있습니다(국내/제한된 네트워크로 의심됨).") fi if [ "$qmd_ok" = "true" ]; then @@ -15516,8 +15950,8 @@ PY fi local ver ver=$(sqlite3 --version 2>/dev/null | awk '{print $1}') - echo "✅ sqlite3 사용 가능: ${ver:-unknown}" - echo "ℹ️ sqlite 확장 지원은 안정적으로 감지될 수 없으며 계속됩니다." + echo "✅ sqlite3 可用: ${ver:-unknown}" + echo "ℹ️ sqlite 확장 지원은 안정적으로 감지할 수 없으며 계속됩니다." return 0 } @@ -15535,7 +15969,7 @@ PY elif command -v wget >/dev/null 2>&1; then wget -qO- https://bun.sh/install | bash else - echo "❌ 컬이나 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." + echo "❌ 컬 또는 wget이 감지되지 않아 롤빵을 설치할 수 없습니다." return 1 fi if [ -d "$HOME/.bun/bin" ]; then @@ -15585,7 +16019,7 @@ PY echo "모드: 쓰기 구성만(설치되지 않음/다운로드되지 않음)" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "색인: 실행됨" + echo "索引: 已执行" else echo "색인: 건너뛰었습니다." fi @@ -15601,7 +16035,7 @@ PY echo "모델:$OPENCLAW_MEMORY_MODEL_PATH" fi if [ -n "$OPENCLAW_MEMORY_COUNTRY" ]; then - echo "영역:$OPENCLAW_MEMORY_COUNTRY" + echo "地区: $OPENCLAW_MEMORY_COUNTRY" fi if [ -n "$OPENCLAW_MEMORY_HF_BASE" ]; then echo "다운로드 소스:$OPENCLAW_MEMORY_HF_BASE" @@ -15619,7 +16053,7 @@ PY echo "자동 배포가 곧 수행됩니다(상세 모드)." echo "목표 계획:$scheme_label" echo "지역: ${OPENCLAW_MEMORY_COUNTRY:-unknown}" - echo "미러 소스 감지:huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" + echo "镜像源探测: huggingface.co=${OPENCLAW_MEMORY_HF_OK:-unknown} hf-mirror.com=${OPENCLAW_MEMORY_MIRROR_OK:-unknown}" echo "다운로드 소스: ${OPENCLAW_MEMORY_HF_BASE:-unknown}" if [ -n "$OPENCLAW_MEMORY_EXPECT_PATH" ]; then echo "예상 다운로드 경로:$OPENCLAW_MEMORY_EXPECT_PATH" @@ -15648,13 +16082,13 @@ PY if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then echo "⚠️ 설치나 다운로드 없이 구성만 작성하도록 선택됨" else - echo "✅ 인덱스가 자동으로 구축되고 게이트웨이가 다시 시작됩니다." + echo "✅ 인덱스가 자동으로 생성되고 게이트웨이가 다시 시작됩니다." fi return 0 } openclaw_memory_auto_setup_qmd() { - echo "🔍 QMD 환경 감지" + echo "🔍 检测 QMD 环境" openclaw_memory_cleanup_legacy_keys openclaw_memory_check_sqlite || true if [ "$OPENCLAW_MEMORY_CONFIG_ONLY" = "true" ]; then @@ -15747,7 +16181,7 @@ EOF echo "✅ 모델 경로가 작성되었습니다" fi if [ "$OPENCLAW_MEMORY_PREHEAT" = "true" ]; then - echo "🔥 따뜻한 지수(모델 다운로드 가능)" + echo "🔥 预热索引(可能下载模型)" openclaw_memory_prepare_workspace_all local preh_agent_lines preh_agent_id preh_workspace preh_agent_lines=$(openclaw_memory_list_agents) @@ -15824,7 +16258,7 @@ EOF echo "1. QMD" echo "2. Local" echo "3. 자동(자동 선택)" - echo "0. 이전 레벨로 돌아갑니다" + echo "0. 返回上一级" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" auto_choice case "$auto_choice" in @@ -15880,7 +16314,7 @@ EOF } openclaw_memory_offer_restart() { - echo "구성이 작성되었으며 OpenClaw 게이트웨이를 다시 시작한 후 적용하려면 다시 시작해야 합니다." + echo "配置已写入,需要重启 OpenClaw 网关后生效。" read -e -p "지금 OpenClaw Gateway를 다시 시작하시겠습니까? (예/아니요):" restart_choice if [[ "$restart_choice" =~ ^[Nn]$ ]]; then echo "다시 시작을 건너뛰었습니다. 나중에 수행할 수 있습니다. openclaw 게이트웨이 다시 시작" @@ -15951,16 +16385,16 @@ EOF builtin|local) current_label="Local" ;; *) current_label="구성되지 않음" ;; esac - echo "현재 계획:$current_label" + echo "当前方案: $current_label" echo "" echo "QMD: qmd 명령을 사용하는 경량 인덱스(네트워크 제약 조건에 적합)" - echo "로컬: 임베딩 모델 파일에 따라 달라지는 로컬 벡터 검색" + echo "Local: 本地向量检索,依赖 embedding 模型文件" echo "자동: 자동 추천(가용성 + 네트워크 감지 기준)" echo "---------------------------------------" echo "1. QMD 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "2. 로컬로 전환(자동 배포/이미 설치된 경우 건너뛰기)" echo "3. 자동(자동 추천 및 자동 배포)" - echo "0. 이전 레벨로 돌아갑니다" + echo "0. 返回上一级" echo "---------------------------------------" read -e -p "선택사항을 입력하세요:" scheme_choice case "$scheme_choice" in @@ -16044,7 +16478,7 @@ EOF echo "문서:$file" echo "총 행 수:$total_lines" read -e -p "시작 라인을 입력하십시오. (끝까지 기본값으로 설정하려면 Enter를 누르십시오.$default_lines좋아요):" start_line - read -e -p "표시할 행 수를 입력하십시오(기본값은 Enter 키를 누르는 것입니다)$default_lines): " count + read -e -p "请输入显示行数(回车默认 $default_lines): " count [ -z "$count" ] && count=$default_lines if [ -z "$start_line" ]; then if [ "$total_lines" -le "$count" ]; then @@ -16122,7 +16556,7 @@ EOF } openclaw_memory_deep_status() { - echo "내장된 모델 준비 상태 감지 중..." + echo "正在探测嵌入模型就绪状态..." openclaw memory status --deep } @@ -16142,7 +16576,7 @@ EOF echo "6. 심층 상태 감지(임베디드 모델 확인)" echo "0. 이전 레벨로 돌아갑니다" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" memory_choice + read -e -p "请输入你的选择: " memory_choice case "$memory_choice" in 1) echo "메모리 인덱스는 곧 업데이트될 예정입니다." @@ -16156,7 +16590,7 @@ EOF read -e -p "2차 확인: 전체 금액을 사용하려면 강제를 입력하세요(증분하려면 비워 두세요)." confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 전체 재구성은 더 철저하지만 시간이 더 오래 걸립니다." - echo "권장 사항: 안전한 재구성을 위해 다시 빌드를 입력합니다(인덱스 데이터베이스를 먼저 백업)." + echo "권장 사항: 안전한 재구축을 위해 재구축을 입력하세요(인덱스 데이터베이스를 먼저 백업하세요)." read -e -p "세 번째 확인: 재구축을 입력하여 안전한 재구축을 수행합니다. 수직력을 계속하려면 Enter를 누르십시오." confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -16259,7 +16693,7 @@ EOF openclaw_permission_restart_gateway() { if ! openclaw_has_command openclaw; then - echo "❌ OpenClaw가 감지되지 않아 OpenClaw Gateway를 다시 시작할 수 없습니다." + echo "❌ openclaw가 감지되지 않아 OpenClaw Gateway를 다시 시작할 수 없습니다." return 1 fi echo "OpenClaw 게이트웨이 다시 시작 중..." @@ -16381,7 +16815,7 @@ try: elif (p == "full" or p == "(unset)") and s == "full" and a == "off" and e == "true" and b == "true" and ap == "true": print("완전 개방 모드") else: - print("커스텀 모드") + print("自定义模式") except Exception: print("커스텀 모드") PY @@ -16444,7 +16878,7 @@ print(json.dumps(data, indent=2)) if [ "$current_profile" = "full" ] && [ "$current_sec" = "full" ] && [ "$current_ask" = "off" ]; then current_mode="\033[1;31m완전 개방 모드\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" = "true" ]; then - current_mode="\033[1;33m향상된 모드 개발\033[0m" + current_mode="\033[1;33m开发增强模式\033[0m" elif [ "$current_profile" = "coding" ] && [ "$current_sec" = "allowlist" ] && [ "$current_ask" = "on-miss" ] && [ "$current_elevated" != "true" ]; then current_mode="\033[1;32m표준 안전 모드\033[0m" elif [ -z "$current_profile" ] && [ -z "$current_sec" ]; then @@ -16455,8 +16889,8 @@ print(json.dumps(data, indent=2)) echo -e "${gl_huang}[애플리케이션 레이어 도구 정책 현황]${gl_bai}" echo "프로필(기본값): ${current_profile:-(unset)}" echo "실행 제한: ${current_sec:-(unset)}" - echo "승인 프롬프트: ${current_ask:-(unset)}" - echo "권한 상승 스위치: ${current_elevated:-(unset)}" + echo " 审批提示: ${current_ask:-(unset)}" + echo " 提权开关: ${current_elevated:-(unset)}" echo -e "\n${gl_huang}[기본 Exec 승인 상태]${gl_bai}" if openclaw_has_command openclaw; then @@ -16509,7 +16943,7 @@ except Exception: send_stats "OpenClaw 권한 - 표준 보안 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -16525,10 +16959,10 @@ except Exception: } openclaw_permission_apply_developer() { - send_stats "OpenClaw 권한 - 개발 강화 모드" + send_stats "OpenClaw权限-开发增强模式" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile coding >/dev/null 2>&1 openclaw config set tools.exec.security allowlist >/dev/null 2>&1 openclaw config set tools.exec.ask on-miss >/dev/null 2>&1 @@ -16546,7 +16980,7 @@ except Exception: send_stats "OpenClaw 권한 - 완전 개방 모드" openclaw_permission_require_openclaw || return 1 - echo "애플리케이션 레이어 정책 구성 중..." + echo "애플리케이션 계층 정책 구성 중..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -16573,7 +17007,7 @@ except Exception: openclaw config unset tools.exec.strictInlineEval >/dev/null 2>&1 echo "호스트 차단 구성을 정리합니다..." - # CLI를 통해 승인 구성을 지우는 데 우선순위를 두고 파일을 직접 삭제하는 방법으로 대체합니다. + # 优先通过 CLI 清空审批配置,回退直接删文件 if echo '{"version":1,"defaults":{}}' | openclaw approvals set --stdin >/dev/null 2>&1; then true else @@ -16642,13 +17076,13 @@ except Exception as e: 1) read -e -p "해제할 명령 경로를 입력하십시오(/usr/bin/git와 같은 glob 지원)." pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } - read -e -p "에이전트 ID 지정(비워 두기 = 모든 에이전트 *):" agent_id + read -e -p "指定智能体ID (留空=所有智能体 *): " agent_id agent_id="${agent_id:-*}" openclaw approvals allowlist add --agent "$agent_id" "$pattern" break_end ;; 2) - read -e -p "제거할 명령 경로를 입력하십시오:" pattern + read -e -p "输入要移除的命令路径: " pattern [ -z "$pattern" ] && { echo "비워둘 수 없습니다."; break_end; continue; } openclaw approvals allowlist remove "$pattern" break_end @@ -16670,7 +17104,7 @@ except Exception as e: echo "---------------------------------------" echo -e "${gl_kjlan}1.${gl_bai}표준보안모드로 전환(일일권장, 팝업카드 승인)" echo -e "${gl_kjlan}2.${gl_bai}개발 강화 모드로 전환(에이전트가 권한 승격을 신청할 수 있도록 허용)" - echo -e "${gl_kjlan}3.${gl_bai}완전 개방 모드로 전환(${gl_hong}위험! 모든 호스트 차단을 완전히 제거합니다.${gl_bai})" + echo -e "${gl_kjlan}3.${gl_bai}완전 개방 모드로 전환(${gl_hong}高风险!彻底解除所有宿主机拦截${gl_bai})" echo -e "${gl_kjlan}4.${gl_bai}공식 기본 샌드박스 방어 전략 복원" echo -e "${gl_kjlan}5.${gl_bai}기본 보안 감사 및 자동 복구 실행" echo -e "${gl_kjlan}6.${gl_bai}Exec 명령 화이트리스트 관리" @@ -16953,7 +17387,7 @@ for idx,item in enumerate(agents,1): local name theme read -e -p "에이전트 ID 이름(예: Code Expert)을 입력하세요." name [ -z "$name" ] && name="$agent_id" - read -e -p "상담원 성격 테마(예: 엄격함, 효율적)를 입력하세요." theme + read -e -p "상담원 성격 주제(예: 엄격함, 효율적)를 입력하세요." theme [ -z "$theme" ] && theme="어시스턴트" echo "에이전트 ID 구성 중..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" @@ -17142,9 +17576,9 @@ print("✅멀티에이전트 헬스체크 완료") echo "7. 다중 에이전트 상태 확인 실행" echo "8. 상담원 신원(이름/이모지) 수정" echo "9. 만료된 세션 정리" - echo "0. 이전 레벨로 돌아갑니다" + echo "0. 返回上一级" echo "---------------------------------------" - read -e -p "선택사항을 입력하세요:" multi_choice + read -e -p "请输入你的选择: " multi_choice case "$multi_choice" in 1) openclaw_multiagent_add_agent; break_end ;; 2) openclaw_multiagent_delete_agent; break_end ;; @@ -17174,7 +17608,7 @@ openclaw_backup_restore_menu() { echo "---------------------------------------" echo "1. 메모리 전체를 백업하세요" echo "2. 전체 메모리 복원" - echo "3. OpenClaw 프로젝트 백업(기본 안전 모드)" + echo "3. 备份 OpenClaw 项目(默认安全模式)" echo "4. OpenClaw 프로젝트 복원(고급/고위험)" echo "5. 백업 파일 삭제" echo "0. 이전 레벨로 돌아갑니다" @@ -17262,7 +17696,7 @@ openclaw_backup_restore_menu() { local local_ip token domains echo "==================================" - echo "OpenClaw WebUI 접속 주소" + echo "OpenClaw WebUI 访问地址" local_ip="127.0.0.1" token=$( @@ -17358,7 +17792,7 @@ openclaw_backup_restore_menu() { ;; 2) openclaw_remove_domain - read -p "메뉴로 돌아가려면 Enter를 누르세요..." + read -p "按回车返回菜单..." ;; 0) break @@ -17388,11 +17822,11 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "초기 구성 마법사" + 11) send_stats "初始化配置向导" openclaw onboard --install-daemon break_end ;; - 12) send_stats "상태 감지 및 복구" + 12) send_stats "健康检测与修复" openclaw doctor --fix break_end ;; @@ -17422,7 +17856,7 @@ refresh_apps_catalog() { install git || return 1 if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then - echo -e "${gl_hong}실수:${gl_bai}${apps_dir}이미 존재하지만 App Market Git 저장소가 아니므로 덮어쓰기가 거부됩니다." + echo -e "${gl_hong}실수:${gl_bai}${apps_dir} 已存在但不是应用市场 Git 仓库,拒绝覆盖。" return 1 fi if [ ! -d "$apps_dir/.git" ]; then @@ -17466,7 +17900,7 @@ while true; do fi done - echo -e "${gl_kjlan}1. ${color1}파고다 패널 공식 버전${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" + echo -e "${gl_kjlan}1. ${color1}宝塔面板官方版 ${gl_kjlan}2. ${color2}aaPanel Pagoda 국제 버전" echo -e "${gl_kjlan}3. ${color3}1패널 차세대 관리 패널${gl_kjlan}4. ${color4}NginxProxyManager 시각화 패널" echo -e "${gl_kjlan}5. ${color5}OpenList 다중 저장소 파일 목록 프로그램${gl_kjlan}6. ${color6}Ubuntu 원격 데스크톱 웹 에디션" echo -e "${gl_kjlan}7. ${color7}나타 프로브 VPS 모니터링 패널${gl_kjlan}8. ${color8}QB 오프라인 BT 자기 다운로드 패널" @@ -17482,7 +17916,7 @@ while true; do echo -e "${gl_kjlan}23. ${color23}메모 웹 메모${gl_kjlan}24. ${color24}Webtop 원격 데스크톱 웹 버전${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud 네트워크 디스크${gl_kjlan}26. ${color26}QD-Today 예약된 작업 관리 프레임워크" echo -e "${gl_kjlan}27. ${color27}Dockge 컨테이너 스택 관리 패널${gl_kjlan}28. ${color28}LibreSpeed ​​​​속도 테스트 도구" - echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism 개인 앨범 시스템" + echo -e "${gl_kjlan}29. ${color29}searxng 집계 검색 스테이션${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相册系统" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF 도구 모음${gl_kjlan}32. ${color32}drawio 무료 온라인 차트 작성 소프트웨어${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun 패널 탐색 패널${gl_kjlan}34. ${color34}Pingvin-Share 파일 공유 플랫폼" @@ -17504,18 +17938,18 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}61. ${color61}온라인 번역 서버${gl_kjlan}62. ${color62}RAGFlow 대규모 모델 지식 기반" echo -e "${gl_kjlan}63. ${color63}OpenWebUI 자체 호스팅 AI 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools 도구 상자" - echo -e "${gl_kjlan}65. ${color65}n8n 자동화된 워크플로우 플랫폼${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp 비디오 다운로드 도구" - echo -e "${gl_kjlan}67. ${color67}ddns-go 동적 DNS 관리 도구${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" + echo -e "${gl_kjlan}65. ${color65}n8n自动化工作流平台 ${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp视频下载工具" + echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL 인증서 관리 플랫폼" echo -e "${gl_kjlan}69. ${color69}SFTPGo 파일 전송 도구${gl_kjlan}70. ${color70}AstrBot 챗봇 프레임워크" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워드 비밀번호 관리자${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}73. ${color73}LibreTV 개인 영화${gl_kjlan}74. ${color74}MoonTV 개인 영화" + echo -e "${gl_kjlan}71. ${color71}Navidrome 개인 음악 서버${gl_kjlan}72. ${color72}비트워든 비밀번호 관리자${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}73. ${color73}LibreTV私有影视 ${gl_kjlan}74. ${color74}MoonTV 개인 영화" echo -e "${gl_kjlan}75. ${color75}멜로디 음악 마법사${gl_kjlan}76. ${color76}온라인 DOS 오래된 게임" echo -e "${gl_kjlan}77. ${color77}Thunder 오프라인 다운로드 도구${gl_kjlan}78. ${color78}PandaWiki 지능형 문서 관리 시스템" echo -e "${gl_kjlan}79. ${color79}베젤 서버 모니터링${gl_kjlan}80. ${color80}링크워든 북마크 관리" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet 화상 회의${gl_kjlan}82. ${color82}gpt-load 고성능 AI 투명 프록시" - echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos 개인 재무 관리 도구" + echo -e "${gl_kjlan}83. ${color83}코마리 서버 모니터링 도구${gl_kjlan}84. ${color84}Wallos个人财务管理工具" echo -e "${gl_kjlan}85. ${color85}이미치 픽처 비디오 매니저${gl_kjlan}86. ${color86}젤리핀 미디어 관리 시스템" echo -e "${gl_kjlan}87. ${color87}SyncTV는 함께 영화를 볼 수 있는 훌륭한 도구입니다${gl_kjlan}88. ${color88}Owncast 자체 호스팅 라이브 스트리밍 플랫폼" echo -e "${gl_kjlan}89. ${color89}FileCodeBox 파일 익스프레스${gl_kjlan}90. ${color90}매트릭스 분산형 채팅 프로토콜" @@ -17528,16 +17962,16 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}101. ${color101}AI 영상 생성 도구${gl_kjlan}102. ${color102}VoceChat 다자간 온라인 채팅 시스템" echo -e "${gl_kjlan}103. ${color103}Umami 웹사이트 통계 도구${gl_kjlan}104. ${color104}스트림 4계층 프록시 전달 도구" - echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawnix 오픈 소스 화이트보드 도구" - echo -e "${gl_kjlan}107. ${color107}PanSou 네트워크 디스크 검색${gl_kjlan}108. ${color108}LangBot 챗봇" + echo -e "${gl_kjlan}105. ${color105}쓰위안 노트${gl_kjlan}106. ${color106}Drawix 오픈 소스 화이트보드 도구" + echo -e "${gl_kjlan}107. ${color107}PanSou网盘搜索 ${gl_kjlan}108. ${color108}LangBot 챗봇" echo -e "${gl_kjlan}109. ${color109}ZFile 온라인 네트워크 디스크${gl_kjlan}110. ${color110}Karakeep 북마크 관리" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}행운의 대형 인트라넷 침투 도구" + echo -e "${gl_kjlan}111. ${color111}다중 형식 파일 변환 도구${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}파이어폭스 브라우저${gl_kjlan}114. ${color114}OpenClaw 봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}115. ${color115}헤르메스 로봇 관리 도구${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}타사 애플리케이션 목록" - echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요.${gl_huang}https://dev.kejilion.sh/${gl_bai}" + echo -e "${gl_kjlan}귀하의 앱이 여기에 표시되기를 원하십니까? 개발자 가이드를 확인하세요:${gl_huang}https://dev.kejilion.sh/${gl_bai}" for f in "$HOME"/apps/*.conf; do [ -e "$f" ] || continue @@ -17559,7 +17993,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}b. ${gl_bai}모든 애플리케이션 데이터 백업${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" + echo -e "${gl_kjlan}b. ${gl_bai}备份全部应用数据 ${gl_kjlan}r. ${gl_bai}모든 앱 데이터 복원" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -17739,7 +18173,7 @@ while true; do } - local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해주세요." + local docker_describe="webtop은 Ubuntu 기반 컨테이너입니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -17750,7 +18184,7 @@ while true; do ;; 7|nezha) clear - send_stats "네자 빌드" + send_stats "나타 빌드" local app_id="7" local docker_name="nezha-dashboard" @@ -17770,7 +18204,7 @@ while true; do echo "------------------------" echo "1. 사용" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "선택 항목을 입력하세요." choice @@ -17820,7 +18254,7 @@ while true; do } local docker_describe="qbittorrent 오프라인 BT 자기 다운로드 서비스" - local docker_url="공식 홈페이지 소개: https://hub.docker.com/r/linuxserver/qbittorrent" + local docker_url="官网介绍: https://hub.docker.com/r/linuxserver/qbittorrent" local docker_use="sleep 3" local docker_passwd="docker logs qbittorrent" local app_size="1" @@ -17839,7 +18273,7 @@ while true; do check_docker_image_update $docker_name clear - echo -e "우정$check_docker $update_status" + echo -e "우편 서비스$check_docker $update_status" echo "poste.io는 오픈 소스 메일 서버 솔루션입니다." echo "영상 소개: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" @@ -17905,7 +18339,7 @@ while true; do add_app_id clear - echo "poste.io가 설치되었습니다" + echo "poste.io已经安装完成" echo "------------------------" echo "다음 주소를 사용하여 poste.io에 액세스할 수 있습니다." echo "https://$yuming" @@ -17987,7 +18421,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "Rocket.chat이 설치되었습니다" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -18029,7 +18463,7 @@ while true; do local docker_describe="ZenTao는 범용 프로젝트 관리 소프트웨어입니다" local docker_url="공식 홈페이지 소개 : https://www.zentao.net/" - local docker_use="echo \"초기 사용자 이름: admin\"" + local docker_use="echo \"初始用户名: admin\"" local docker_passwd="echo \"초기 비밀번호: 123456\"" local app_size="2" docker_app @@ -18056,8 +18490,8 @@ while true; do } - local docker_describe="Qinglong Panel은 예약된 작업 관리 플랫폼입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/whyour/qinglong" + local docker_describe="青龙面板是一个定时任务管理平台" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -18067,7 +18501,7 @@ while true; do 13|cloudreve) local app_id="13" - local app_name="클라우드리브 네트워크 디스크" + local app_name="cloudreve网盘" local app_text="cloudreve는 여러 클라우드 스토리지를 지원하는 네트워크 디스크 시스템입니다." local app_url="영상 소개: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" @@ -18149,7 +18583,7 @@ while true; do } - local docker_describe="emby는 서버의 비디오 및 오디오를 구성하고 오디오 및 비디오를 클라이언트 장치로 스트리밍하는 데 사용할 수 있는 마스터-슬레이브 아키텍처 미디어 서버 소프트웨어입니다." + local docker_describe="emby是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备" local docker_url="공식 홈페이지 소개 : https://emby.media/" local docker_use="" local docker_passwd="" @@ -18230,7 +18664,7 @@ while true; do } - local docker_describe="onlyoffice는 오픈 소스 온라인 오피스 도구로 매우 강력합니다!" + local docker_describe="onlyoffice是一款开源的在线office工具,太强大了!" local docker_url="공식 홈페이지 소개 : https://www.onlyoffice.com/" local docker_use="" local docker_passwd="" @@ -18439,8 +18873,8 @@ while true; do } - local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해주세요." - local docker_url="공식 홈페이지 소개: https://docs.linuxserver.io/images/docker-webtop/" + local docker_describe="웹탑은 중국어 버전의 Alpine 컨테이너를 기반으로 합니다. 해당 IP에 접속할 수 없는 경우, 접속할 도메인 이름을 추가해 주세요." + local docker_url="官网介绍: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" local app_size="2" @@ -18500,7 +18934,7 @@ while true; do } - local docker_describe="Dockge는 시각적 Docker 작성 컨테이너 관리 패널입니다." + local docker_describe="dockge是一个可视化的docker-compose容器管理面板" local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/louislam/dockge" local docker_use="" local docker_passwd="" @@ -18578,7 +19012,7 @@ while true; do local docker_describe="포토프리즘은 매우 강력한 개인 사진 앨범 시스템입니다." - local docker_url="공식 홈페이지 소개 : https://www.photoprism.app/" + local docker_url="官网介绍: https://www.photoprism.app/" local docker_use="echo \"계정: admin 비밀번호:$rootpasswd\"" local docker_passwd="" local app_size="1" @@ -18605,8 +19039,8 @@ while true; do frooodle/s-pdf:latest } - local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하는 강력한 로컬 호스팅 웹 기반 PDF 조작 도구입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" + local docker_describe="이는 분할 병합, 변환, 재구성, 이미지 추가, 회전, 압축 등과 같은 PDF 파일에 대한 다양한 작업을 수행할 수 있는 docker를 사용하여 로컬로 호스팅되는 강력한 웹 기반 PDF 조작 도구입니다." + local docker_url="官网介绍: ${gh_proxy}github.com/Stirling-Tools/Stirling-PDF" local docker_use="" local docker_passwd="" local app_size="1" @@ -18676,7 +19110,7 @@ while true; do } local docker_describe="Pingvin Share는 자체 구축 가능한 파일 공유 플랫폼이자 WeTransfer의 대안입니다." - local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/stonith404/pingvin-share" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -18702,7 +19136,7 @@ while true; do } - local docker_describe="미니멀리스트 순간, 높은 모방 WeChat 순간, 멋진 삶을 기록하세요" + local docker_describe="极简朋友圈,高仿微信朋友圈,记录你的美好生活" local docker_url="공식 웹사이트 소개:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" local docker_use="echo \"계정: admin 비밀번호: a123456\"" local docker_passwd="" @@ -18873,10 +19307,10 @@ while true; do } - local docker_describe="Rustdesk의 오픈 소스 원격 데스크톱(서버)은 자체 Sunflower 개인 서버와 유사합니다." + local docker_describe="rustdesk开源的远程桌面(服务端),类似自己的向日葵私服。" local docker_url="공식 홈페이지 소개: https://rustdesk.com/zh-cn/" local docker_use="docker logs hbbs" - local docker_passwd="echo \"원격 데스크톱 클라이언트에서 사용될 IP와 키를 기록하세요. 릴레이를 설치하려면 옵션 44로 이동하세요!\"" + local docker_passwd="echo \"把你的IP和key记录下,会在远程桌面客户端中用到。去44选项装中继端吧!\"" local app_size="1" docker_app ;; @@ -19034,7 +19468,7 @@ while true; do } - local docker_describe="이는 Prometheus 컨테이너 데이터 수집 구성 요소입니다. 모니터링되는 호스트에 배포하세요." + local docker_describe="这是一个普罗米修斯的容器数据采集组件,请部署在被监控主机上。" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/google/cadvisor" local docker_use="" local docker_passwd="" @@ -19281,7 +19715,7 @@ while true; do docker_app_install() { curl -sSL ${gh_proxy}github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash clear - echo "설치 완료" + echo "已经安装完成" check_docker_app_ip echo "초기 사용자 이름: admin" echo "초기 비밀번호: ChangeMe" @@ -19335,7 +19769,7 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow 지식 기반" + local app_name="RAGFlow知识库" local app_text="깊은 문서 이해를 기반으로 한 오픈소스 RAG(Retrieval Augmented Generation) 엔진" local app_url="공식 웹사이트:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" @@ -19637,7 +20071,7 @@ while true; do } - local docker_describe="무료 온라인 비디오 검색 및 시청 플랫폼" + local docker_describe="免费在线视频搜索与观看平台" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/LibreSpark/LibreTV" local docker_use="" local docker_passwd="" @@ -19652,8 +20086,8 @@ while true; do local app_id="74" - local app_name="Moontv 개인 영화 및 TV" - local app_text="무료 온라인 비디오 검색 및 시청 플랫폼" + local app_name="moontv私有影视" + local app_text="免费在线视频搜索与观看平台" local app_url="비디오 소개:${gh_https_url}github.com/MoonTechLab/LunaTV" local docker_name="moontv-core" local docker_port="8074" @@ -19852,8 +20286,8 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="링크워든 북마크 관리" - local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스 자체 호스팅 북마크 관리 플랫폼입니다." + local app_name="linkwarden书签管理" + local app_text="태그 지정, 검색 및 팀 협업을 지원하는 오픈 소스, 자체 호스팅 북마크 관리 플랫폼입니다." local app_url="공식 홈페이지: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" @@ -19925,7 +20359,7 @@ while true; do 81|jitsi) local app_id="81" local app_name="JitsiMeet 화상 회의" - local app_text="다자간 온라인 회의, 화면 공유, 암호화된 통신을 지원하는 오픈 소스 보안 화상 회의 솔루션입니다." + local app_text="一个开源的安全视频会议解决方案,支持多人在线会议、屏幕共享与加密通信。" local app_url="공식 홈페이지: https://jitsi.org/" local docker_name="jitsi" local docker_app_service="jitsi-web-1" @@ -20174,7 +20608,7 @@ while true; do } - local docker_describe="원격으로 영화와 생방송을 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." + local docker_describe="영화와 생방송을 원격으로 함께 시청할 수 있는 프로그램입니다. 동시 시청, 라이브 방송, 채팅 및 기타 기능을 제공합니다." local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/synctv-org/synctv" local docker_use="echo \"초기 계정 및 비밀번호: root. 로그인 후 시간에 맞춰 로그인 비밀번호를 변경하세요\"" local docker_passwd="" @@ -20234,7 +20668,7 @@ while true; do } local docker_describe="익명의 비밀번호로 텍스트와 파일을 공유하고 빠른 배송과 같은 파일 픽업" - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/vastsa/FileCodeBox" + local docker_url="官网介绍: ${gh_https_url}github.com/vastsa/FileCodeBox" local docker_use="echo \"접속 주소 뒤에는 /#/admin이 붙어서 관리자 페이지에 접속합니다\"" local docker_passwd="echo \"관리자 비밀번호: FileCodeBox2023\"" local app_size="1" @@ -20426,7 +20860,7 @@ while true; do } - local docker_describe="다중 프로토콜을 지원하는 분산 고속 다운로드 도구" + local docker_describe="여러 프로토콜을 지원하는 분산 고속 다운로드 도구" local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/GopeedLab/gopeed" local docker_use="" local docker_passwd="" @@ -20489,7 +20923,7 @@ while true; do local app_id="96" - local app_name="2FAuth 자체 호스팅 2단계 인증자" + local app_name="2FAuth自托管二步验证器" local app_text="자체 호스팅 2FA(2단계 인증) 계정 관리 및 확인 코드 생성 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/Bubka/2FAuth" local docker_name="2fauth" @@ -20624,7 +21058,7 @@ while true; do docker exec wireguard bash -c 'for i in $(ls /config | grep peer_ | sed "s/peer_//"); do echo "--- $i ---"; /app/show-peer $i; done' sleep 2 echo - echo -e "${gl_huang}모든 클라이언트 구성 코드:${gl_bai}" + echo -e "${gl_huang}所有客户端配置代码: ${gl_bai}" docker exec wireguard sh -c 'for d in /config/peer_*; do echo "# $(basename $d) "; cat $d/*.conf; echo; done' sleep 2 echo -e "${gl_lv}${COUNT}각 클라이언트에 대한 모든 출력을 구성합니다. 사용방법은 다음과 같습니다.${gl_bai}" @@ -20805,7 +21239,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" local app_name="AI 영상 생성 도구" - local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 단편 동영상을 합성하는 도구입니다." + local app_text="MoneyPrinterTurbo는 AI 대형 모델을 사용하여 고화질 짧은 동영상을 합성하는 도구입니다." local app_url="공식 웹사이트:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" local docker_port="8101" @@ -20834,7 +21268,7 @@ while true; do docker_app_uninstall() { cd /home/docker/MoneyPrinterTurbo/ && docker compose down --rmi all rm -rf /home/docker/MoneyPrinterTurbo - echo "앱이 제거되었습니다." + echo "应用已卸载" } docker_app_plus @@ -21074,7 +21508,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ } local docker_describe="개인이나 소규모 팀에 적합한 온라인 네트워크 디스크 프로그램입니다." - local docker_url="공식 웹사이트 소개:${gh_https_url}github.com/zfile-dev/zfile" + local docker_url="官网介绍: ${gh_https_url}github.com/zfile-dev/zfile" local docker_use="" local docker_passwd="" local app_size="1" @@ -21086,7 +21520,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ 110|karakeep) local app_id="110" local app_name="karakeep 북마크 관리" - local app_text="데이터 수집가를 위해 설계된 인공 지능 기능을 갖춘 자체 호스팅 북마크 앱입니다." + local app_text="是一款可自行托管的书签应用,带有人工智能功能,专为数据囤积者而设计。" local app_url="공식 웹사이트:${gh_https_url}github.com/karakeep-app/karakeep" local docker_name="docker-web-1" local docker_port="8110" @@ -21165,7 +21599,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ -v /var/run/docker.sock:/var/run/docker.sock \ ${docker_img} - echo "Lucky가 초기화되기를 기다리는 중..." + echo "正在等待 Lucky 初始化..." sleep 10 docker exec lucky /app/lucky -rSetHttpAdminPort ${docker_port} @@ -21190,7 +21624,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ docker_rum() { - read -e -p "로그인 비밀번호 설정:" admin_password + read -e -p "设置登录密码: " admin_password docker run -d --name=${docker_name} --restart=always \ -p ${docker_port}:5800 \ @@ -21293,7 +21727,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ if [ -f "$custom_app" ]; then . "$custom_app" else - echo -e "${gl_hong}오류: 번호가 없습니다.${sub_choice}애플리케이션 구성${gl_bai}" + echo -e "${gl_hong}오류: 번호가 없습니다.${sub_choice} 的应用配置${gl_bai}" fi ;; esac @@ -21318,7 +21752,7 @@ linux_work() { send_stats "백엔드 작업공간" echo -e "백엔드 작업공간" echo -e "시스템은 장기간 작업을 수행하는 데 사용할 수 있는 백그라운드에서 영구적으로 실행될 수 있는 작업 공간을 제공합니다." - echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 백그라운드 작업은 유지됩니다." + echo -e "SSH 연결을 끊더라도 작업 공간의 작업은 중단되지 않으며 작업은 백그라운드에 유지됩니다." echo -e "${gl_huang}힌트:${gl_bai}워크스페이스 진입 후 Ctrl+b를 누른 후 d만 눌러 워크스페이스를 종료하세요!" echo -e "${gl_kjlan}------------------------" echo "현재 존재하는 작업공간 목록" @@ -21328,20 +21762,20 @@ linux_work() { echo -e "${gl_kjlan}1. ${gl_bai}작업 영역 1" echo -e "${gl_kjlan}2. ${gl_bai}작업 영역 2" echo -e "${gl_kjlan}3. ${gl_bai}작업 영역 3" - echo -e "${gl_kjlan}4. ${gl_bai}작업 영역 4" + echo -e "${gl_kjlan}4. ${gl_bai}4号工作区" echo -e "${gl_kjlan}5. ${gl_bai}작업 공간 5번" echo -e "${gl_kjlan}6. ${gl_bai}작업 영역 6" echo -e "${gl_kjlan}7. ${gl_bai}작업 영역 7" echo -e "${gl_kjlan}8. ${gl_bai}작업 영역 8" echo -e "${gl_kjlan}9. ${gl_bai}작업 공간 9호" - echo -e "${gl_kjlan}10. ${gl_bai}작업공간 10" + echo -e "${gl_kjlan}10. ${gl_bai}10号工作区" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}SSH 상주 모드${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}22. ${gl_bai}작업공간 생성/입력" echo -e "${gl_kjlan}23. ${gl_bai}백그라운드 작업 공간에 명령 삽입" - echo -e "${gl_kjlan}24. ${gl_bai}지정된 작업공간 삭제" + echo -e "${gl_kjlan}24. ${gl_bai}删除指定工作区" echo -e "${gl_kjlan}------------------------" - echo -e "${gl_kjlan}0. ${gl_bai}메인 메뉴로 돌아가기" + echo -e "${gl_kjlan}0. ${gl_bai}返回主菜单" echo -e "${gl_kjlan}------------------------${gl_bai}" read -e -p "선택사항을 입력하세요:" sub_choice @@ -21359,7 +21793,7 @@ linux_work() { clear install tmux local SESSION_NAME="work2" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 3) @@ -21373,7 +21807,7 @@ linux_work() { clear install tmux local SESSION_NAME="work4" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 5) @@ -21387,14 +21821,14 @@ linux_work() { clear install tmux local SESSION_NAME="work6" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 7) clear install tmux local SESSION_NAME="work7" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 8) @@ -21408,7 +21842,7 @@ linux_work() { clear install tmux local SESSION_NAME="work9" - send_stats "작업공간 시작$SESSION_NAME" + send_stats "启动工作区$SESSION_NAME" tmux_run ;; 10) @@ -21470,7 +21904,7 @@ linux_work() { ;; 24) - read -e -p "삭제하려는 작업공간의 이름을 입력하세요:" gongzuoqu_name + read -e -p "请输入要删除的工作区名称: " gongzuoqu_name tmux kill-window -t $gongzuoqu_name send_stats "작업공간 삭제" ;; @@ -21511,7 +21945,7 @@ switch_mirror() { echo "감지된 국가:$country" if [ "$country" = "CN" ]; then - echo "국내 미러 소스를 사용하세요..." + echo "使用国内镜像源..." bash <(curl -sSL https://linuxmirrors.cn/main.sh) \ --source mirrors.huaweicloud.com \ --protocol https \ @@ -21597,7 +22031,7 @@ fail2ban_panel() { break_end ;; 5) - send_stats "SSH 방어 편집 구성 파일" + send_stats "SSH防御编辑配置文件" f2b_edit_config break_end ;; @@ -21644,7 +22078,7 @@ net_menu() { echo "2. 네트워크 카드 비활성화" echo "3. 네트워크 카드 세부정보 보기" echo "4. 네트워크 카드 정보 새로 고침" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "====================================" read -erp "작업을 선택하십시오:" choice @@ -21661,7 +22095,7 @@ net_menu() { ;; 2) send_stats "네트워크 카드 비활성화" - read -erp "비활성화할 네트워크 카드의 이름을 입력하십시오:" nic + read -erp "请输入要禁用的网卡名: " nic if ip link show "$nic" &>/dev/null; then ip link set "$nic" down && echo "✔ 네트워크 카드$nic장애가 있는" else @@ -21670,7 +22104,7 @@ net_menu() { read -erp "계속하려면 Enter를 누르세요..." ;; 3) - send_stats "네트워크 카드 세부정보 보기" + send_stats "查看网卡详情" read -erp "보려는 네트워크 카드의 이름을 입력하십시오:" nic if ip link show "$nic" &>/dev/null; then echo "========== $nic세부정보 ==========" @@ -21695,7 +22129,7 @@ net_menu() { log_menu() { - send_stats "시스템 로그 관리 도구" + send_stats "系统日志管理工具" show_log_overview() { echo "============= 시스템 로그 개요 =============" @@ -21776,7 +22210,7 @@ log_menu() { echo "⚠️ 일지를 청소하세요(안전한 방법)" echo "1) 최근 7일을 보관" echo "2) 최근 3일을 보관한다" - echo "3) 최대 로그 크기를 500M로 제한합니다." + echo "3) 최대 로그 크기를 500M로 제한하십시오." read -erp "청소 방법을 선택하세요:" c case $c in 1) journalctl --vacuum-time=7d ;; @@ -21870,7 +22304,7 @@ env_menu() { source_files() { echo "환경 변수를 다시 로드하는 중..." - send_stats "환경 변수 다시 로드 중" + send_stats "正在重新加载环境变量" source "$BASHRC" source "$PROFILE" echo "✔ 환경 변수가 다시 로드되었습니다." @@ -21880,18 +22314,18 @@ env_menu() { while true; do clear echo "=========== 시스템 환경 변수 관리 ==========" - echo "현재 사용자:$USER" + echo "当前用户:$USER" echo "--------------------------------------" - echo "1. 현재 일반적으로 사용되는 환경변수를 확인하세요." + echo "1. 查看当前常用环境变量" echo "2. ~/.bashrc 보기" - echo "3. ~/.profile 보기" + echo "3. 查看 ~/.profile" echo "4. ~/.bashrc 편집" echo "5. ~/.profile 편집" echo "6. 환경 변수 다시 로드(출처)" echo "--------------------------------------" echo "0. 이전 메뉴로 돌아가기" echo "--------------------------------------" - read -erp "작업을 선택하십시오:" choice + read -erp "请选择操作: " choice case "$choice" in 1) @@ -22001,10 +22435,10 @@ linux_Settings() { echo -e "시스템 도구" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}스크립트 시작 단축키 설정${gl_kjlan}2. ${gl_bai}로그인 비밀번호 변경" - echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 Python 버전을 설치합니다." + echo -e "${gl_kjlan}3. ${gl_bai}사용자 비밀번호 로그인 모드${gl_kjlan}4. ${gl_bai}지정된 버전의 Python 설치" echo -e "${gl_kjlan}5. ${gl_bai}모든 포트 열기${gl_kjlan}6. ${gl_bai}SSH 연결 포트 수정" echo -e "${gl_kjlan}7. ${gl_bai}DNS 주소 최적화${gl_kjlan}8. ${gl_bai}한 번의 클릭으로 시스템을 다시 설치${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}9. ${gl_bai}ROOT 계정을 비활성화하고 새 계정을 만듭니다.${gl_kjlan}10. ${gl_bai}우선순위 ipv4/ipv6 전환" + echo -e "${gl_kjlan}9. ${gl_bai}禁用ROOT账户创建新账户 ${gl_kjlan}10. ${gl_bai}우선 순위 ipv4/ipv6 전환" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}11. ${gl_bai}항만점유현황 확인${gl_kjlan}12. ${gl_bai}가상 메모리 크기 수정" echo -e "${gl_kjlan}13. ${gl_bai}사용자 관리${gl_kjlan}14. ${gl_bai}사용자/비밀번호 생성기" @@ -22019,7 +22453,7 @@ linux_Settings() { echo -e "${gl_kjlan}29. ${gl_bai}바이러스 검사 도구${gl_huang}★${gl_bai} ${gl_kjlan}30. ${gl_bai}파일 관리자" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}시스템 언어 전환${gl_kjlan}32. ${gl_bai}명령줄 미화 도구${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}시스템 백업 및 복구" + echo -e "${gl_kjlan}33. ${gl_bai}시스템 휴지통 설정${gl_kjlan}34. ${gl_bai}系统备份与恢复" echo -e "${gl_kjlan}35. ${gl_bai}SSH 원격 연결 도구${gl_kjlan}36. ${gl_bai}하드 디스크 파티션 관리 도구" echo -e "${gl_kjlan}37. ${gl_bai}명령줄 기록${gl_kjlan}38. ${gl_bai}rsync 원격 동기화 도구" echo -e "${gl_kjlan}39. ${gl_bai}명령 즐겨찾기${gl_huang}★${gl_bai} ${gl_kjlan}40. ${gl_bai}네트워크 카드 관리 도구" @@ -22146,7 +22580,7 @@ EOF local VERSION=$(python -V 2>&1 | awk '{print $2}') echo -e "현재 Python 버전 번호:${gl_huang}$VERSION${gl_bai}" - send_stats "스크립트 PY 버전 전환" + send_stats "脚本PY版本切换" ;; @@ -22212,7 +22646,7 @@ EOF ;; 9) root_use - send_stats "신규 사용자에 대한 루트 비활성화" + send_stats "新用户禁用root" read -e -p "새 사용자 이름을 입력하십시오(종료하려면 0을 입력하십시오):" new_username if [ "$new_username" == "0" ]; then break_end @@ -22298,7 +22732,7 @@ EOF echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택사항을 입력하세요:" choice + read -e -p "请输入你的选择: " choice case "$choice" in 1) @@ -22336,7 +22770,7 @@ EOF send_stats "사용자 관리" echo "사용자 목록" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "사용자 이름" "사용자 권한" "사용자 그룹" "sudo 권한" + printf "%-24s %-34s %-20s %-10s\n" "用户名" "사용자 권한" "사용자 그룹" "sudo 권한" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status @@ -22358,7 +22792,7 @@ EOF echo "------------------------" echo "5. 계정 삭제" echo "------------------------" - echo "0. 이전 메뉴로 돌아가기" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "선택사항을 입력하세요:" sub_choice @@ -22372,12 +22806,12 @@ EOF 2) # 사용자에게 새 사용자 이름을 묻는 메시지 표시 - read -e -p "새 사용자 이름을 입력하세요:" new_username + read -e -p "请输入新用户名: " new_username create_user_with_sshkey $new_username true ;; 3) - read -e -p "사용자 이름을 입력하세요:" username + read -e -p "请输入用户名: " username install sudo cat >"/etc/sudoers.d/$username" < /etc/hostname hostname "$new_hostname" else - # Debian, Ubuntu, CentOS 등과 같은 기타 시스템 + # Debian, Ubuntu, CentOS 등과 같은 다른 시스템 hostnamectl set-hostname "$new_hostname" sed -i "s/$current_hostname/$new_hostname/g" /etc/hostname systemctl restart systemd-hostnamed @@ -22584,10 +23018,10 @@ EOF 19) root_use - send_stats "시스템 업데이트 소스 변경" + send_stats "换系统更新源" clear echo "업데이트 소스 지역 선택" - echo "LinuxMirror에 액세스하여 시스템 업데이트 소스 전환" + echo "LinuxMirrors에 액세스하여 시스템 업데이트 소스 전환" echo "------------------------" echo "1. 중국 본토 [기본값] 2. 중국 본토 [교육 네트워크] 3. 해외 지역 4. 업데이트 소스의 지능형 전환" echo "------------------------" @@ -22630,7 +23064,7 @@ EOF echo "예약된 작업 목록" crontab -l echo "" - echo "작동하다" + echo "操作" echo "------------------------" echo "1. 예약된 작업 추가 2. 예약된 작업 삭제 3. 예약된 작업 편집" echo "------------------------" @@ -22649,7 +23083,7 @@ EOF case $dingshi in 1) - read -e -p "작업을 실행하기로 선택한 날짜는 언제입니까? (1-30):" day + read -e -p "작업을 실행하기로 선택한 날은 언제입니까? (1-30):" day (crontab -l ; echo "0 0 $day * * $newquest") | crontab - > /dev/null 2>&1 ;; 2) @@ -22693,7 +23127,7 @@ EOF while true; do clear echo "기본 호스트 확인 목록" - echo "여기에 파싱 매칭을 추가하면 더 이상 동적 파싱이 사용되지 않습니다." + echo "如果你在这里添加解析匹配,将不再使用动态解析了" cat /etc/hosts echo "" echo "작동하다" @@ -22760,12 +23194,12 @@ EOF echo "------------------------" echo "0. 이전 메뉴로 돌아가기" echo "------------------------" - read -e -p "선택사항을 입력하세요:" Limiting + read -e -p "请输入你的选择: " Limiting case "$Limiting" in 1) # 새 가상 메모리 크기 입력 - echo "실제 서버에 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." + echo "실제 서버의 트래픽이 100G만 있는 경우 임계값을 95G로 설정하고 미리 종료하여 트래픽 오류나 오버플로를 방지할 수 있습니다." read -e -p "인바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." rx_threshold_gb rx_threshold_gb=${rx_threshold_gb:-100} read -e -p "아웃바운드 트래픽 임계값을 입력하십시오(단위는 G, 기본값은 100G)." tx_threshold_gb @@ -22784,14 +23218,14 @@ EOF crontab -l | grep -v 'reboot' | crontab - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 echo "전류 제한 종료가 설정되었습니다." - send_stats "전류 제한 종료가 설정되었습니다." + send_stats "限流关机已设置" ;; 2) check_crontab_installed crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "전류 제한 차단 기능이 꺼졌습니다." + echo "已关闭限流关机功能" ;; *) break @@ -22809,16 +23243,16 @@ EOF root_use send_stats "전신 경고" echo "TG-bot 모니터링 및 조기경보 기능" - echo "영상 소개: https://youtu.be/vLL-eb3Z_TY" + echo "영상소개: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" echo "로컬 CPU, 메모리, 하드 디스크, 트래픽 및 SSH 로그인에 대한 실시간 모니터링 및 경고를 달성하려면 경고를 수신하도록 tg 로봇 API 및 사용자 ID를 구성해야 합니다." echo "임계값에 도달하면 경고 메시지가 사용자에게 전송됩니다." echo -e "${gl_hui}- 트래픽에 관해서는 서버를 다시 시작하면 다시 계산됩니다 -${gl_bai}" - read -e -p "계속하시겠습니까? (예/아니요):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) - send_stats "텔레그램 경고 활성화됨" + send_stats "电报预警启用" cd ~ install nano tmux bc jq check_crontab_installed @@ -22965,7 +23399,7 @@ EOF echo "2. 시스템 정크 파일 정리" echo -e "3. 가상 메모리 설정${gl_huang}1G${gl_bai}" echo -e "4. SSH 포트 번호를 다음으로 설정합니다.${gl_huang}5522${gl_bai}" - echo -e "5. SSH 무차별 대입 크래킹을 방어하기 위해 fall2ban을 시작하세요." + echo -e "5. 启动fail2ban防御SSH暴力破解" echo -e "6. 모든 포트를 엽니다" echo -e "7. 켜다${gl_huang}BBR${gl_bai}가속하다" echo -e "8. 시간대를 다음으로 설정합니다.${gl_huang}상하이${gl_bai}" @@ -23018,7 +23452,7 @@ EOF echo -e "[${gl_lv}OK${gl_bai}] 9/12. DNS 주소 자동 최적화${gl_huang}${gl_bai}" echo "------------------------------------------------" prefer_ipv4 - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 네트워크를 다음으로 설정하세요.${gl_huang}IPv4 우선순위${gl_bai}}" + echo -e "[${gl_lv}OK${gl_bai}] 10/12. 네트워크를 다음으로 설정하세요.${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" install_docker @@ -23076,7 +23510,7 @@ EOF cd ~ sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' /usr/local/bin/k sed -i 's/^ENABLE_STATS="false"/ENABLE_STATS="true"/' ~/kejilion.sh - echo "수집이 시작되었습니다" + echo "已开启采集" send_stats "개인정보 보호 및 보안 수집이 사용 설정되었습니다." ;; 2) @@ -23101,7 +23535,7 @@ EOF 102) clear send_stats "기술 사자 스크립트 제거" - echo "기술 사자 스크립트 제거" + echo "卸载科技lion脚本" echo "------------------------------------------------" echo "kejilion 스크립트는 다른 기능에 영향을 주지 않고 완전히 제거됩니다." read -e -p "계속하시겠습니까? (예/아니요):" choice @@ -23154,12 +23588,12 @@ linux_file() { clear echo "파일 관리자" echo "------------------------" - echo "현재 경로" + echo "当前路径" pwd echo "------------------------" ls --color=auto -x echo "------------------------" - echo "1. 디렉터리 입력 2. 디렉터리 생성 3. 디렉터리 권한 수정 4. 디렉터리 이름 바꾸기" + echo "1. 进入目录 2. 创建目录 3. 修改目录权限 4. 重命名目录" echo "5. 디렉토리 삭제 6. 이전 메뉴 디렉토리로 복귀" echo "------------------------" echo "11. 파일 생성 12. 파일 편집 13. 파일 권한 수정 14. 파일 이름 바꾸기" @@ -23266,10 +23700,10 @@ linux_file() { 24) # 复制文件目录 - read -e -p "복사할 파일 또는 디렉터리 경로를 입력하세요." src_path + read -e -p "请输入要复制的文件或目录路径: " src_path if [ ! -e "$src_path" ]; then echo "오류: 파일 또는 디렉터리가 존재하지 않습니다." - send_stats "파일 또는 디렉터리 복사 실패: 파일 또는 디렉터리가 존재하지 않습니다." + send_stats "파일 또는 디렉터리를 복사하지 못했습니다. 파일 또는 디렉터리가 존재하지 않습니다." continue fi @@ -23442,7 +23876,7 @@ while true; do 5) clear send_stats "클러스터 복원" - echo "귀하의 server.py를 업로드하고 업로드를 시작하려면 아무 키나 누르십시오!" + echo "server.py를 업로드하고 아무 키나 눌러 업로드를 시작하세요!" echo -e "업로드해주세요${gl_huang}servers.py${gl_bai}파일을 제출하다${gl_huang}/root/cluster/${gl_bai}복원 완료!" break_end ;; @@ -23518,7 +23952,7 @@ echo "------------------------" echo -e "${gl_zi}V.PS 월 6.9달러 도쿄 소프트뱅크 2코어 1G 메모리 20G 하드드라이브 월 1T 트래픽${gl_bai}" echo -e "${gl_bai}URL: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}더 인기 있는 VPS 혜택${gl_bai}" +echo -e "${gl_kjlan}더 인기 있는 VPS 거래${gl_bai}" echo -e "${gl_bai}홈페이지: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" @@ -23812,7 +24246,7 @@ echo "시스템 패널을 다시 설치하십시오. k dd | k 다시 설치하 echo "bbr3 제어판 k bbr3 | kbbrv3" echo "커널 튜닝 패널 k nhyh | k 커널 최적화" echo "가상 메모리 k 스왑 2048 설정" -echo "가상 시간대 설정 k 시간 아시아/상하이 | k 시간대 아시아/상하이" +echo "设置虚拟时区 k time Asia/Shanghai | k 时区 Asia/Shanghai" echo "시스템 휴지통 k 쓰레기 | khsz | k 휴지통" echo "시스템 백업 기능 k 백업 | k bf | k 백업" echo "SSH 원격 연결 도구 k SSH | k 원격 연결" @@ -23831,7 +24265,7 @@ echo "도커 관리 플레인 k 도커" echo "docker 환경 설치 k docker 설치 |k docker 설치" echo "도커 컨테이너 관리 k 도커 ps |k 도커 컨테이너" echo "도커 이미지 관리 k docker img |k 도커 이미지" -echo "LDNMP 사이트 관리 k web" +echo "LDNMP站点管理 k web" echo "LDNMP 캐시 정리 k 웹 캐시" echo "WordPress k wp 설치 | k 워드프레스 | k wp xxx.com" echo "역방향 프록시 설치 k fd |k rp |k 역방향 프록시 |k fd xxx.com" @@ -23842,10 +24276,10 @@ echo "포트 k 열기 DKdk 8080 |k 포트 8080 열기" echo "k 포트 닫기 gbdk 7800 |k 포트 7800 닫기" echo "릴리스 IP k fxip 127.0.0.0/8 |k 릴리스 IP 127.0.0.0/8" echo "IP 차단 k zzip 177.5.25.36 |k IP 177.5.25.36 차단" -echo "명령 즐겨찾기 k 즐겨찾기 | k 명령 즐겨찾기" -echo "애플리케이션 시장 관리 k app" +echo "命令收藏夹 k fav | k 命令收藏夹" +echo "应用市场管理 k app" echo "신청번호의 빠른 관리 k app 26 | k 앱 1패널 | k 앱 npm" -echo "Fail2ban 관리 k Fail2ban | k f2b [상태|활성화|비활성화]" +echo "fail2ban管理 k fail2ban | k f2b [status|enable|disable]" echo "시스템 정보 표시 k 정보" echo "ROOT 키 관리 k sshkey" echo "SSH 공개 키 가져오기(URL) k sshkey " @@ -24011,7 +24445,7 @@ else time|时区) shift - send_stats "시간대를 빠르게 설정" + send_stats "快速设置时区" set_timedate "$@" ;; @@ -24020,6 +24454,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then @@ -24094,7 +24533,7 @@ else enable|autostart|开机启动) shift - send_stats "부팅 시 소프트웨어가 자동으로 시작됩니다." + send_stats "软件开机自启" enable "$@" ;; @@ -24105,7 +24544,7 @@ else ssl_ps elif [ -z "$1" ]; then add_ssl - send_stats "빨리 자격증 신청하세요" + send_stats "快速申请证书" elif [ -n "$1" ]; then add_ssl "$1" send_stats "빨리 자격증 신청하세요" @@ -24156,6 +24595,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "사용법: k kpanel 노드 조인 | 상태 | 업데이트 | 제거" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift @@ -24196,7 +24646,7 @@ else fetch_github_ssh_keys "$1" ;; http://*|https://* ) - send_stats "URL에서 SSH 공개 키 가져오기" + send_stats "从 URL 导入 SSH 公钥" fetch_remote_ssh_keys "$1" ;; ssh-rsa*|ssh-ed25519*|ssh-ecdsa* ) diff --git a/tw/kejilion.sh b/tw/kejilion.sh index 7ecde80d9..f081de0ed 100644 --- a/tw/kejilion.sh +++ b/tw/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.4" +sh_v="4.5.5" gl_hui='\e[37m' @@ -16,7 +16,13 @@ canshu="default" permission_granted="false" ENABLE_STATS="true" +if [ "${1:-}" = "kpanel" ] && [ "${2:-}" = "node" ]; then + KJ_LIGHT_NODE_PROTOCOL=1 +fi + kpanel_protocol_active() { + [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || @@ -48,7 +54,7 @@ quanju_canshu -# 定義一個函數來執行命令 +# 定义一个函数来执行命令 run_command() { if [ "$zhushi" -eq 0 ]; then "$@" @@ -140,7 +146,7 @@ UserLicenseAgreement() { echo "首次使用腳本,請先閱讀並同意使用者授權協議。" echo "使用者授權協議: https://blog.kejilion.pro/user-license-agreement/" echo -e "----------------------" - read -e -p "是否同意以上条款? (y/n):" user_input + read -e -p "是否同意以上条款?(y/n): " user_input if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then @@ -194,7 +200,7 @@ ipv6_address=$(curl -s --max-time 1 https://v6.ipinfo.io/ip && echo) install() { if [ $# -eq 0 ]; then - echo "未提供軟體包參數!" + echo "未提供软件包参数!" return 1 fi @@ -248,7 +254,7 @@ check_disk_space() { if [ "$available_space_mb" -lt "$required_space_mb" ]; then echo -e "${gl_huang}提示:${gl_bai}磁碟空間不足!" echo "目前可用空間: $((available_space_mb/1024))G" - echo "最小需求空间: ${required_gb}G" + echo "最小需求空間:${required_gb}G" echo "無法繼續安裝,請清理磁碟空間後重試。" send_stats "磁碟空間不足" break_end @@ -317,7 +323,7 @@ systemctl() { restart() { systemctl restart "$1" if [ $? -eq 0 ]; then - echo "$1服務已重啟。" + echo "$1 服务已重启。" else echo "錯誤:重啟$1服務失敗。" fi @@ -362,7 +368,7 @@ enable() { /bin/systemctl enable "$SERVICE_NAME" fi - echo "$SERVICE_NAME已設定為開機自啟動。" + echo "$SERVICE_NAME 已设置为开机自启。" } @@ -503,8 +509,8 @@ while true; do echo "1. 建立新的容器" echo "------------------------" echo "2. 啟動指定容器 6. 啟動所有容器" - echo "3. 停止指定容器 7. 停止所有容器" - echo "4. 刪除指定容器 8. 刪除所有容器" + echo "3. 停止指定容器 7. 停止所有容器" + echo "4. 删除指定容器 8. 删除所有容器" echo "5. 重啟指定容器 9. 重新啟動所有容器" echo "------------------------" echo "11. 進入指定容器 12. 查看容器日誌" @@ -523,12 +529,12 @@ while true; do ;; 2) send_stats "啟動指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker start $dockername ;; 3) send_stats "停止指定容器" - read -e -p "请输入容器名(多个容器名请用空格分隔): " dockername + read -e -p "請輸入容器名稱(多個容器名稱請以空格分隔):" dockername docker stop $dockername ;; 4) @@ -598,7 +604,7 @@ while true; do break_end ;; 14) - send_stats "查看容器佔用" + send_stats "查看容器占用" docker stats --no-stream break_end ;; @@ -787,7 +793,7 @@ docker_ipv6_on() { UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') fi - # 对比原始配置与新配置 + # 比較原始配置與新配置 if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then echo -e "${gl_huang}目前已開啟ipv6訪問${gl_bai}" else @@ -942,7 +948,7 @@ allow_ip() { # 刪除已存在的阻止規則 iptables -D INPUT -s $ip -j DROP 2>/dev/null - # 新增允許規則 + # 添加允许规则 if ! iptables -C INPUT -s $ip -j ACCEPT 2>/dev/null; then iptables -I INPUT 1 -s $ip -j ACCEPT echo "已放行IP$ip" @@ -997,7 +1003,7 @@ enable_ddos_defense() { send_stats "開啟DDoS防禦" } -# 關閉DDoS防禦 +# 关闭DDoS防御 disable_ddos_defense() { # 關閉防禦 DDoS iptables -D DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT 2>/dev/null @@ -1034,7 +1040,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "错误:下载 $country_code的 IP 區域檔案失敗" + echo "錯誤:下載$country_code的 IP 區域檔案失敗" continue fi @@ -1054,7 +1060,7 @@ manage_country_rules() { fi if ! wget -q "$download_url" -O "${country_code,,}.zone"; then - echo "錯誤:下載$country_code的 IP 區域檔案失敗" + echo "错误:下载 $country_code的 IP 區域檔案失敗" continue fi @@ -1078,7 +1084,7 @@ manage_country_rules() { ipset destroy "$ipset_name" fi - echo "已成功解除$country_code的 IP 位址限制" + echo "已成功解除$country_code 的 IP 地址限制" ;; *) @@ -1114,11 +1120,11 @@ iptables_panel() { echo "3. 開放所有連接埠 4. 關閉所有連接埠" echo "------------------------" echo "5. IP白名單 6. IP黑名單" - echo "7. 清除指定IP" + echo "7. 清除指定IP" echo "------------------------" echo "11. 允許PING 12. 禁止PING" echo "------------------------" - echo "13. 启动DDOS防御 14. 关闭DDOS防御" + echo "13. 啟動DDOS防禦 14. 關閉DDOS防禦" echo "------------------------" echo "15. 阻止指定國家IP 16. 僅允許指定國家IP" echo "17. 解除指定國家IP限制" @@ -1130,7 +1136,7 @@ iptables_panel() { 1) read -e -p "請輸入開放的連接埠號碼:" o_port open_port $o_port - send_stats "開放指定連接埠" + send_stats "开放指定端口" ;; 2) read -e -p "請輸入關閉的連接埠號碼:" c_port @@ -1154,7 +1160,7 @@ iptables_panel() { send_stats "開放所有連接埠" ;; 4) - # 關閉所有連接埠 + # 关闭所有端口 current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') iptables -F iptables -X @@ -1212,7 +1218,7 @@ iptables_panel() { 15) read -e -p "請輸入阻止的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code manage_country_rules block $country_code - send_stats "允許國家$country_code 的IP" + send_stats "允許國家$country_code的IP" ;; 16) read -e -p "請輸入允許的國家代碼(多個國家代碼可用空格隔開如 CN US JP):" country_code @@ -1496,7 +1502,7 @@ install_ssltls_text() { add_ssl() { -echo -e "${gl_huang}快速申請SSL證書,過期前自動續簽${gl_bai}" +echo -e "${gl_huang}快速申請SSL證書,過期前自動續約${gl_bai}" yuming="${1:-}" if [ -z "$yuming" ]; then add_yuming @@ -1513,7 +1519,7 @@ ssl_ps ssl_ps() { echo -e "${gl_huang}已申請的證書到期情況${gl_bai}" - echo "網站資訊 證書到期時間" + echo "站點資訊 證書到期時間" echo "------------------------" for cert_dir in /etc/letsencrypt/live/*; do local cert_file="$cert_dir/fullchain.pem" @@ -1560,7 +1566,7 @@ certs_status() { echo "KPANEL_PROGRESS 100 網域名稱憑證申請失敗,請檢查 DNS、80/443 連接埠和簽發限額" return 1 fi - echo -e "${gl_hong}注意:${gl_bai}证书申请失败,请检查以下可能原因并重试:" + echo -e "${gl_hong}注意:${gl_bai}證書申請失敗,請檢查以下可能原因並重試:" echo -e "1. 網域拼字錯誤 ➠ 請檢查網域名稱輸入是否正確" echo -e "2. DNS解析問題 ➠ 確認網域名稱已正確解析至本伺服器IP" echo -e "3. 網路設定問題 ➠ 如使用Cloudflare Warp等虛擬網路請暫時關閉" @@ -1606,7 +1612,7 @@ certs_status() { done # 3. 智能校驗 - # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可通过 + # 只要包含 "BEGIN CERTIFICATE" 和 "PRIVATE KEY" 即可透過 if [[ "$cert_content" == *"-----BEGIN CERTIFICATE-----"* && "$key_content" == *"PRIVATE KEY-----"* ]]; then echo -n "$cert_content" > "$cert_file" echo -n "$key_content" > "$key_file" @@ -1811,7 +1817,7 @@ cf_purge_cache() { if [ -f "$CONFIG_FILE" ]; then # 從設定檔讀取 API_TOKEN 和 zone_id read API_TOKEN EMAIL ZONE_IDS < "$CONFIG_FILE" - # 將 ZONE_IDS 轉換為數組 + # 将 ZONE_IDS 转换为数组 ZONE_IDS=($ZONE_IDS) else # 提示使用者是否清理快取 @@ -1858,7 +1864,7 @@ web_del() { yuming_list=("$@") else local yuming_input="" - read -e -p "删除站点数据,请输入你的域名(多个域名用空格隔开): " yuming_input + read -e -p "刪除站點數據,請輸入你的網域名稱(多個網域以空格隔開):" yuming_input if [[ -z "$yuming_input" ]]; then return fi @@ -1880,7 +1886,7 @@ web_del() { rm -f -- "/home/web/certs/${yuming}_key.pem" > /dev/null 2>&1 rm -f -- "/home/web/certs/${yuming}_cert.pem" > /dev/null 2>&1 - # 將網域名稱轉換為資料庫名 + # 将域名转换为数据库名 dbname=$(echo "$yuming" | sed -e 's/[^A-Za-z0-9]/_/g') if [ -f /home/web/docker-compose.yml ] && docker inspect mysql > /dev/null 2>&1; then @@ -1901,7 +1907,7 @@ web_del() { [ -e "/home/web/conf.d/$yuming.conf" ] || [ -e "/home/web/certs/${yuming}_key.pem" ] || [ -e "/home/web/certs/${yuming}_cert.pem" ]; then - echo "站點產物刪除不完整:$yuming" + echo "站点产物删除不完整: $yuming" action_status=1 else echo "KPANEL_DELETE_SITE deleted $yuming" @@ -1936,7 +1942,7 @@ nginx_waf() { sed -i 's|^\(\s*\)# modsecurity on;|\1modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 elif [ "$mode" == "off" ]; then - # 关闭 WAF:加上注释 + # 關閉 WAF:加上註釋 sed -i 's|^load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity on;|\1# modsecurity on;|' /home/web/nginx.conf > /dev/null 2>&1 sed -i 's|^\(\s*\)modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|\1# modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;|' /home/web/nginx.conf > /dev/null 2>&1 @@ -2175,7 +2181,7 @@ nginx_zstd() { return 1 fi - # 檢查 nginx 鏡像並根據情況處理 + # 检查 nginx 镜像并根据情况处理 if grep -q "kjlion/nginx:alpine" /home/web/docker-compose.yml; then docker exec nginx nginx -s reload else @@ -2340,7 +2346,7 @@ web_security() { sed -i "s/APIKEY00000/$cftoken/g" /etc/fail2ban/action.d/cloudflare-docker.conf f2b_status - echo "已設定cloudflare模式,可在cf後台,網站-安全性-事件中查看攔截記錄" + echo "已配置cloudflare模式,可在cf後台,站點-安全性-事件中查看攔截記錄" ;; 22) @@ -2371,7 +2377,7 @@ web_security() { if [ -z "$existing_cron" ]; then (crontab -l 2>/dev/null; echo "$cron_job") | crontab - - echo "高負載自動開盾腳本已新增" + echo "高负载自动开盾脚本已添加" else echo "自動開盾腳本已存在,無需添加" fi @@ -2381,7 +2387,7 @@ web_security() { 31) nginx_waf on echo "站點WAF已開啟" - send_stats "站點WAF已開啟" + send_stats "站点WAF已开启" ;; 32) @@ -2431,7 +2437,7 @@ check_nginx_compression() { # 檢查 zstd 是否開啟且未被註解(整行以 zstd on; 開頭) if grep -qE '^\s*zstd\s+on;' "$CONFIG_FILE"; then - zstd_status="zstd壓縮已開啟" + zstd_status=" zstd压缩已开启" else zstd_status="" fi @@ -2505,7 +2511,7 @@ ldnmp_optimization_mode() { cd /home/web && docker compose restart || return 1 if [ "$mode" = high ]; then optimize_web_server - echo "LDNMP環境已設定成 高效能模式" + echo "LDNMP环境已设置成 高性能模式" else optimize_balanced echo "LDNMP環境已設定成 標準模式" @@ -2714,56 +2720,50 @@ check_docker_image_update() { -block_container_port() { +get_container_ipv4_addresses() { local container_name_or_id=$1 - local allowed_ip=$2 + local container_ips - # 取得容器的 IP 位址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then - return 1 - fi - - install iptables - - - # 檢查並封鎖其他所有 IP - if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 檢查並放行指定 IP - if ! iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi + container_ips=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{println .IPAddress}}{{end}}{{end}}' "$container_name_or_id" 2>/dev/null) || return 1 + printf '%s\n' "$container_ips" | awk 'NF && !seen[$0]++' +} - # 檢查並放行本地網路 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT +ensure_docker_user_rule() { + if ! iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -I DOCKER-USER "$@" fi +} - - - # 檢查並封鎖其他所有 IP - if ! iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -I DOCKER-USER -p udp -d "$container_ip" -j DROP +remove_docker_user_rule() { + if iptables -C DOCKER-USER "$@" &>/dev/null; then + iptables -D DOCKER-USER "$@" fi +} - # 檢查並放行指定 IP - if ! iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi +block_container_port() { + local container_name_or_id=$1 + local allowed_ip=$2 + local container_ips + local container_ip - # 檢查並放行本地網路 127.0.0.0/8 - if ! iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT + # 取得容器在所有 Docker 網路中的 IPv4 位址,逐一應用規則。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "錯誤:無法取得容器${container_name_or_id}的 IPv4 位址。" >&2 + return 1 fi - if ! iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi + install iptables + while IFS= read -r container_ip; do + ensure_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + ensure_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + ensure_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已阻止IP+連接埠存取該服務" save_iptables_rules @@ -2775,56 +2775,27 @@ block_container_port() { clear_container_rules() { local container_name_or_id=$1 local allowed_ip=$2 + local container_ips + local container_ip - # 取得容器的 IP 位址 - local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name_or_id") - - if [ -z "$container_ip" ]; then + # 取得容器在所有 Docker 網路中的 IPv4 位址,逐一清除規則。 + container_ips=$(get_container_ipv4_addresses "$container_name_or_id") + if [ -z "$container_ips" ]; then + echo "錯誤:無法取得容器${container_name_or_id}的 IPv4 位址。" >&2 return 1 fi install iptables - - # 清除封鎖其他所有 IP 的規則 - if iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p tcp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的規則 - if iptables -C DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地網路 127.0.0.0/8 的規則 - if iptables -C DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - - - - # 清除封鎖其他所有 IP 的規則 - if iptables -C DOCKER-USER -p udp -d "$container_ip" -j DROP &>/dev/null; then - iptables -D DOCKER-USER -p udp -d "$container_ip" -j DROP - fi - - # 清除放行指定 IP 的規則 - if iptables -C DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT - fi - - # 清除放行本地網路 127.0.0.0/8 的規則 - if iptables -C DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT - fi - - - if iptables -C DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT &>/dev/null; then - iptables -D DOCKER-USER -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT - fi - + while IFS= read -r container_ip; do + remove_docker_user_rule -p tcp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p tcp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p tcp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -d "$container_ip" -j DROP || return 1 + remove_docker_user_rule -p udp -s "$allowed_ip" -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -p udp -s 127.0.0.0/8 -d "$container_ip" -j ACCEPT || return 1 + remove_docker_user_rule -m state --state ESTABLISHED,RELATED -d "$container_ip" -j ACCEPT || return 1 + done <<< "$container_ips" echo "已允許IP+連接埠存取該服務" save_iptables_rules @@ -2900,7 +2871,7 @@ clear_host_port_rules() { if [[ -z "$port" || -z "$allowed_ip" ]]; then echo "錯誤:請提供連接埠號碼和允許存取的 IP。" - echo "用法: clear_host_port_rules <端口号> <允许的IP>" + echo "用法: clear_host_port_rules <連接埠號碼> <允許的IP>" return 1 fi @@ -3091,7 +3062,9 @@ kpanel_app_read_access_mode() { local access_path="" local access_mode="" local service_name="" + local container_ips="" local container_ip="" + local all_blocked="true" access_path="$(kpanel_app_access_path)" || return 1 if [ -f "$access_path" ] && [ ! -L "$access_path" ]; then @@ -3104,9 +3077,18 @@ kpanel_app_read_access_mode() { ;; esac service_name="$(kpanel_app_service_name)" || return 1 - container_ip="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$service_name" 2>/dev/null)" - if [ -n "$container_ip" ] && command -v iptables >/dev/null 2>&1 && - iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + container_ips="$(get_container_ipv4_addresses "$service_name")" + if [ -n "$container_ips" ] && command -v iptables >/dev/null 2>&1; then + while IFS= read -r container_ip; do + if ! iptables -C DOCKER-USER -p tcp -d "$container_ip" -j DROP >/dev/null 2>&1; then + all_blocked="false" + break + fi + done <<< "$container_ips" + else + all_blocked="false" + fi + if [ "$all_blocked" = "true" ]; then printf '%s\n' "domain_only" else printf '%s\n' "direct" @@ -3256,7 +3238,7 @@ kpanel_run_docker_app_install() { if [ "$adapter" = "plus" ]; then if ! docker_app_install; then - echo "安裝失敗: 未登記應用程式狀態" + echo "安装失败: 未登记应用状态" return 1 fi else @@ -3278,7 +3260,7 @@ kpanel_run_docker_app_install() { [ -n "${docker_use:-}" ] && $docker_use [ -n "${docker_passwd:-}" ] && $docker_passwd fi - kpanel_app_progress 100 "应用安装完成" + kpanel_app_progress 100 "應用程式安裝完成" echo "$docker_name已經安裝完成" return 0 } @@ -3478,7 +3460,7 @@ while true; do ;; 5) - echo "${docker_name}域名访问设置" + echo "${docker_name}域名存取設定" send_stats "${docker_name}域名存取設定" add_yuming ldnmp_Proxy ${yuming} 127.0.0.1 ${docker_port} @@ -3572,7 +3554,7 @@ docker_app_plus() { kpanel_app_write_access_mode direct send_stats "$app_name安裝" else - echo -e "${gl_hong}安裝失敗:${gl_bai}未登記套用狀態,請依上方錯誤修復後重試。" + echo -e "${gl_hong}安裝失敗:${gl_bai}未登記套用狀態,請根據上方錯誤修復後重試。" action_status=1 fi ;; @@ -3833,7 +3815,7 @@ kpanel_f2b_dispatch() { fi f2b_install_sshd || return 1 kpanel_f2b_enabled || { - echo "Fail2Ban SSH jail 未能正常啟動" >&2 + echo "Fail2Ban SSH jail 未能正常启动" >&2 return 1 } changed=true @@ -3880,7 +3862,7 @@ f2b_sshd() { # 基礎參數配置:封禁時長(bantime)、時間視窗(findtime)、重試次數(maxretry) # 說明: -# - 優先寫入 /etc/fail2ban/jail.d/sshd.local(覆蓋預設 jail 配置,升級不易丟) +# - 优先写入 /etc/fail2ban/jail.d/sshd.local(覆盖默认 jail 配置,升级不易丢) # - 若是 Alpine 且 jail 名稱不同,仍寫 sshd.local;Fail2Ban 會以 jail 名稱配對 f2b_basic_config() { root_use @@ -3900,7 +3882,7 @@ f2b_basic_config() { fi echo "即將配置 SSH jail:$jail_name" - read -e -p "封禁時長 bantime (秒/分鐘/小時,如 3600 或 1h) [預設 1h]:" bantime + read -e -p "封禁时长 bantime (秒/分钟/小时,如 3600 或 1h) [默认 1h]: " bantime read -e -p "時間窗口 findtime (秒/分鐘/小時,如 600 或 10m) [預設 10m]:" findtime read -e -p "重試次數 maxretry (整數) [預設 5]:" maxretry @@ -4046,7 +4028,7 @@ nginx_upgrade clear local nginx_version=$(docker exec nginx nginx -v 2>&1) local nginx_version=$(echo "$nginx_version" | grep -oP "nginx/\K[0-9]+\.[0-9]+\.[0-9]+") -echo "nginx已安裝完成" +echo "nginx已安装完成" echo -e "目前版本:${gl_huang}v$nginx_version${gl_bai}" echo "" @@ -4079,7 +4061,7 @@ nginx_install_status() { ldnmp_web_on() { clear - echo "您的$webname搭建好了!" + echo "您的 $webname搭建好了!" echo "https://$yuming" echo "------------------------" echo "$webname安裝資訊如下:" @@ -4122,10 +4104,10 @@ ldnmp_wp() { ldnmp_install_status - kpanel_web_progress 35 "正在簽發並配置網站證書" + kpanel_web_progress 35 "正在签发并配置站点证书" install_ssltls certs_status - kpanel_web_progress 50 "正在建立 WordPress 資料庫與帳號" + kpanel_web_progress 50 "正在创建 WordPress 数据库与账号" add_db kpanel_web_progress 60 "正在取得 kejilion.sh WordPress Nginx 配置" @@ -4295,7 +4277,7 @@ list_stream_services() { ip_address local_ip="$ipv4_address" - # 获取通信类型,优先从文件名后缀或内容判断 + # 取得通訊類型,優先從檔案名稱後綴或內容判斷 if grep -qi 'udp;' "$conf"; then proto="udp" else @@ -4334,7 +4316,7 @@ stream_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" echo "4. 新增轉送服務 5. 修改轉送服務 6. 刪除轉送服務" echo "------------------------" @@ -4345,7 +4327,7 @@ stream_panel() { 1) nginx_install_status add_app_id - send_stats "安裝Stream四層代理" + send_stats "安装Stream四层代理" ;; 2) update_docker_compose_with_db_creds @@ -4425,7 +4407,7 @@ ldnmp_Proxy_backend_stream() { *) echo "無效選擇"; return 1 ;; esac - read -e -p "請輸入你的一個或多個後端IP+埠以空格隔開(例如 10.13.0.2:3306 10.13.0.3:3306):" reverseproxy_port + read -e -p "请输入你的一个或者多个后端IP+端口用空格隔开(例如 10.13.0.2:3306 10.13.0.3:3306): " reverseproxy_port nginx_install_status cd /home && mkdir -p web/stream.d @@ -4442,7 +4424,7 @@ ldnmp_Proxy_backend_stream() { upstream_servers="$upstream_servers server $server;\n" done - sed -i "s/# 動態添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf + sed -i "s/# 动态添加/$upstream_servers/g" /home/web/stream.d/$proxy_name.conf docker exec nginx nginx -s reload clear @@ -4487,7 +4469,7 @@ ldnmp_web_status() { local db_output="${gl_lv}${db_count}${gl_bai}" clear - send_stats "LDNMP站台管理" + send_stats "LDNMP站点管理" echo "LDNMP環境" echo "------------------------" ldnmp_v @@ -4533,12 +4515,12 @@ ldnmp_web_status() { echo "" echo "網站目錄" echo "------------------------" - echo -e "數據${gl_hui}/home/web/html${gl_bai}證書${gl_hui}/home/web/certs${gl_bai}配置${gl_hui}/home/web/conf.d${gl_bai}" + echo -e "數據${gl_hui}/home/web/html${gl_bai}證書${gl_hui}/home/web/certs${gl_bai} 配置 ${gl_hui}/home/web/conf.d${gl_bai}" echo "------------------------" echo "" echo "操作" echo "------------------------" - echo "1. 申请/更新域名证书 2. 克隆站点域名" + echo "1. 申請/更新網域憑證 2. 克隆站點域名" echo "3. 清理站點快取 4. 建立關聯站點" echo "5. 查看訪問日誌 6. 查看錯誤日誌" echo "7. 編輯全域配置 8. 編輯站點配置" @@ -4623,7 +4605,7 @@ ldnmp_web_status() { break_end ;; 6) - send_stats "查看錯誤日誌" + send_stats "查看错误日志" tail -n 200 /home/web/log/nginx/error.log break_end ;; @@ -4668,7 +4650,7 @@ ldnmp_web_status() { check_panel_app() { if $lujing > /dev/null 2>&1; then - check_panel="${gl_lv}已安裝${gl_bai}" + check_panel="${gl_lv}已安装${gl_bai}" else check_panel="" fi @@ -4841,7 +4823,7 @@ remote_port = ${remote_port} EOF - # 輸出產生的信息 + # 输出生成的信息 echo "服務$service_name已成功加入 frpc.toml" docker restart frpc @@ -4963,7 +4945,7 @@ generate_access_urls() { fi done - # 只在有有效連接埠時顯示標題和內容 + # 只在有有效端口时显示标题和内容 if [ "$has_valid_ports" = true ]; then echo "FRP服務對外存取位址:" @@ -5019,7 +5001,7 @@ frps_panel() { check_frp_app check_docker_image_update $docker_name echo -e "FRP服務端$check_frp $update_status" - echo "建構FRP內網穿透服務環境,將無公網IP的設備暴露到互聯網" + echo "构建FRP内网穿透服务环境,将无公网IP的设备暴露到互联网" echo "官網介紹:${gh_https_url}github.com/fatedier/frp/" echo "影片教學: https://www.bilibili.com/video/BV1yMw6e2EwL?t=124.0" if [ -d "/home/frp/" ]; then @@ -5028,7 +5010,7 @@ frps_panel() { fi echo "" echo "------------------------" - echo "1. 安裝 2. 更新 3. 卸載" + echo "1. 安装 2. 更新 3. 卸载" echo "------------------------" echo "5. 內部網路服務網域存取 6. 刪除網域名稱訪問" echo "------------------------" @@ -5141,7 +5123,7 @@ frpc_panel() { configure_frpc add_app_id - echo "FRP客户端已经安装完成" + echo "FRP客戶端已經安裝完成" ;; 2) crontab -l | grep -v 'frpc' | crontab - > /dev/null 2>&1 @@ -5151,7 +5133,7 @@ frpc_panel() { donlond_frp frpc add_app_id - echo "FRP客戶端已經更新完成" + echo "FRP客户端已经更新完成" ;; 3) @@ -5213,7 +5195,7 @@ yt_menu_pro() { echo -e "yt-dlp 是一個功能強大的影片下載工具,支援 YouTube、Bilibili、Twitter 等數千網站。" echo -e "官網位址:${gh_https_url}github.com/yt-dlp/yt-dlp" echo "-------------------------" - echo "已下載影片清單:" + echo "已下载视频列表:" ls -td "$VIDEO_DIR"/*/ 2>/dev/null || echo "(暫無)" echo "-------------------------" echo "1. 安裝 2. 更新 3. 卸載" @@ -5253,7 +5235,7 @@ yt_menu_pro() { echo "卸載完成。按任意鍵繼續..." read ;; 5) - send_stats "單一影片下載" + send_stats "单个视频下载" read -e -p "請輸入影片連結:" url yt-dlp -P "$VIDEO_DIR" -f "bv*+ba/b" --merge-output-format mp4 \ --write-subs --sub-langs all \ @@ -5373,7 +5355,7 @@ linux_update() { linux_clean() { - echo -e "${gl_kjlan}正在系統清理...${gl_bai}" + echo -e "${gl_kjlan}正在系统清理...${gl_bai}" if command -v dnf &>/dev/null; then rpm --rebuilddb dnf autoremove -y @@ -5408,7 +5390,7 @@ linux_clean() { rm -rf /var/log/* echo "刪除APK快取..." rm -rf /var/cache/apk/* - echo "刪除臨時檔案..." + echo "删除临时文件..." rm -rf /tmp/* elif command -v pacman &>/dev/null; then @@ -5581,7 +5563,7 @@ kpanel_dns_write_static() { if [ "$(cat "$target")"$'\n' = "$expected" ]; then chattr +i "$target" >/dev/null 2>&1 || { rm -f "$desired" "$backup" - echo "錯誤: 無法鎖定 DNS 配置" + echo "错误: 无法锁定 DNS 配置" return 1 } rm -f "$desired" "$backup" @@ -5708,7 +5690,7 @@ kpanel_set_dns_noninteractive() { elif kpanel_dns_is_ipv6 "$value"; then ipv6_count=$((ipv6_count + 1)) [ "$ipv6_count" -le 2 ] || { - echo "錯誤: IPv6 DNS 位址最多 2 個" + echo "错误: IPv6 DNS 地址最多 2 个" return 1 } else @@ -5741,14 +5723,14 @@ while true; do clear echo "優化DNS位址" echo "------------------------" - echo "当前DNS地址" + echo "目前DNS地址" cat /etc/resolv.conf echo "------------------------" echo "" echo "1. 國外DNS優化:" echo " v4: 1.1.1.1 8.8.8.8" echo " v6: 2606:4700:4700::1111 2001:4860:4860::8888" - echo "2. 國內DNS優化:" + echo "2. 国内DNS优化: " echo " v4: 223.5.5.5 183.60.83.19" echo " v6: 2400:3200::1 2400:da00::6666" echo "3. 手動編輯DNS配置" @@ -5778,7 +5760,7 @@ while true; do chattr -i /etc/resolv.conf nano /etc/resolv.conf chattr +i /etc/resolv.conf - send_stats "手動編輯DNS配置" + send_stats "手动编辑DNS配置" ;; *) break @@ -5839,6 +5821,82 @@ new_ssh_port() { } +kpanel_ssh_port_noninteractive() { + [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || return 2 + [ "$EUID" -eq 0 ] || { + echo "錯誤: KPanel SSH 連接埠協定必須以 root 執行" + return 1 + } + [ "$#" -eq 1 ] || { + echo "錯誤: SSH 連接埠協定需要一個連接埠號" + return 1 + } + + local new_port="$1" + [[ "$new_port" =~ ^[0-9]{1,5}$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ] || { + echo "錯誤: SSH 連接埠必須為 1-65535" + return 1 + } + [ -f /etc/ssh/sshd_config ] && [ ! -L /etc/ssh/sshd_config ] || { + echo "錯誤: 未找到可管理的 OpenSSH 配置" + return 1 + } + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 || { + echo "錯誤: SSH 設定校驗或監聽檢查工具不可用" + return 1 + } + sshd -t || { + echo "錯誤: 目前 SSH 設定語法驗證失敗" + return 1 + } + + local configured_ports + configured_ports="$({ + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null + grep -Eh '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config.d/*.conf 2>/dev/null + } | awk '{print $2}' | sort -nu)" + if [ "$configured_ports" = "$new_port" ]; then + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT unchanged" + return 0 + fi + + # 重複使用現有 SSH 修改主業務;適配層只負責非互動校驗和機器可讀結果。 + new_ssh_port "$new_port" || return 1 + if ! grep -Eq "^[[:space:]]*Port[[:space:]]+${new_port}([[:space:]]|$)" /etc/ssh/sshd_config; then + echo "錯誤: SSH 連接埠修改後回讀驗證失敗" + return 1 + fi + if ! sshd -t; then + echo "錯誤: SSH 設定語法驗證失敗" + return 1 + fi + local listening="false" + local attempt + for attempt in {1..10}; do + if ss -H -ltn 2>/dev/null | awk -v port="${new_port}" ' + { + address=$4 + sub(/^.*:/, "", address) + if (address == port) found=1 + } + END { exit(found ? 0 : 1) } + '; then + listening="true" + break + fi + sleep 0.2 + done + [ "${listening}" = "true" ] || { + echo "错误: SSH 新端口未进入监听状态" + return 1 + } + + echo "KPANEL_SSH_PORT $new_port" + echo "KPANEL_SSH_RESULT applied" +} + + sshkey_on() { @@ -5848,7 +5906,7 @@ sshkey_on() { -e 's/^\s*#\?\s*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config rm -rf /etc/ssh/sshd_config.d/* /etc/ssh/ssh_config.d/* restart_ssh - echo -e "${gl_lv}用户密钥登录模式已开启,已关闭密码登录模式,重连将会生效${gl_bai}" + echo -e "${gl_lv}使用者金鑰登入模式已開啟,已關閉密碼登入模式,重連將會生效${gl_bai}" } @@ -5866,7 +5924,7 @@ add_sshkey() { chmod 600 "${HOME}/.ssh/authorized_keys" ip_address - echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai} 文件,用于以后的SSH登录" + echo -e "私鑰資訊已生成,務必複製保存,可保存成${gl_huang}${ipv4_address}_ssh.key${gl_bai}文件,用於以後的SSH登錄" echo "--------------------------------" cat "${HOME}/.ssh/sshkey" @@ -5968,10 +6026,10 @@ fetch_remote_ssh_keys() { touch "${authorized_keys}" chmod 600 "${authorized_keys}" - # 备份原有 authorized_keys + # 備份原有 authorized_keys if [[ -f "${authorized_keys}" ]]; then cp "${authorized_keys}" "${authorized_keys}.bak.$(date +%Y%m%d-%H%M%S)" - echo "已備份原有 authorized_keys 文件" + echo "已备份原有 authorized_keys 文件" fi # 追加公鑰(避免重複) @@ -6010,7 +6068,7 @@ fetch_github_ssh_keys() { echo "1. 登入${gh_https_url}github.com/settings/keys" echo "2. 點選 New SSH key 或 Add SSH key" echo "3. Title 可隨意填寫(例如:Home Laptop 2026)" - echo "4. 將本機公鑰內容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部內容)貼到 Key 字段" + echo " 4. 将本地公钥内容(通常是 ~/.ssh/id_ed25519.pub 或 id_rsa.pub 的全部内容)粘贴到 Key 字段" echo "5. 點選 Add SSH key 完成新增" echo "" echo "新增完成後,GitHub 會公開提供您的所有公鑰,位址為:" @@ -6050,13 +6108,13 @@ sshkey_panel() { echo "------------------------------------------------" echo "將會產生金鑰對,更安全的方式SSH登錄" echo "------------------------" - echo "1. 生成新密钥对 2. 手动输入已有公钥" + echo "1. 產生新密鑰對 2. 手動輸入已有公鑰" echo "3. 從GitHub導入已有公鑰 4. 從網址導入已有公鑰" echo "5. 編輯公鑰檔案 6. 查看本機金鑰" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "請輸入你的選擇:" host_dns + read -e -p "请输入你的选择: " host_dns case $host_dns in 1) send_stats "產生新密鑰" @@ -6075,7 +6133,7 @@ sshkey_panel() { ;; 4) send_stats "導入URL遠端公鑰" - read -e -p "請輸入您的遠端公鑰URL:" keys_url + read -e -p "请输入您的远端公钥URL: " keys_url fetch_remote_ssh_keys "${keys_url}" break_end ;; @@ -6122,7 +6180,7 @@ add_sshpasswd() { # 如果沒有透過參數傳入,則交互輸入 if [[ -z "$target_user" ]]; then - read -e -p "請輸入要修改密碼的使用者名稱(預設 root):" target_user + read -e -p "请输入要修改密码的用户名(默认 root): " target_user fi # 回車不輸入,預設 root @@ -6130,7 +6188,7 @@ add_sshpasswd() { # 校驗用戶是否存在 if ! id "$target_user" >/dev/null 2>&1; then - echo "錯誤:用戶$target_user不存在" + echo "錯誤:用戶$target_user 不存在" return 1 fi @@ -6198,7 +6256,7 @@ dd_xitong() { } dd_xitong_2() { - echo -e "重裝後初始使用者名稱:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai}初始連接埠:${gl_huang}3389${gl_bai}" + echo -e "重裝後初始使用者名稱:${gl_huang}Administrator${gl_bai}初始密碼:${gl_huang}Teddysun.com${gl_bai} 初始端口: ${gl_huang}3389${gl_bai}" echo -e "按任意鍵繼續..." read -n 1 -s -r -p "" install wget @@ -6223,7 +6281,7 @@ dd_xitong() { root_use echo "重裝系統" echo "--------------------------------" - echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" + echo -e "${gl_hong}注意: ${gl_bai}重装有风险失联,不放心者慎用。重装预计花费15分钟,请提前备份数据。" echo -e "${gl_hui}感謝bin456789大佬和leitbogioro大佬的腳本支持!${gl_bai} " echo -e "${gl_hui}bin456789項目地址:${gh_https_url}github.com/bin456789/reinstall${gl_bai}" echo -e "${gl_hui}leitbogioro專案地址:${gh_https_url}github.com/leitbogioro/Tools${gl_bai}" @@ -6278,7 +6336,7 @@ dd_xitong() { exit ;; 4) - send_stats "重裝debian 10" + send_stats "重装debian 10" dd_xitong_3 bash reinstall.sh debian 10 reboot @@ -6299,14 +6357,14 @@ dd_xitong() { exit ;; 13) - send_stats "重裝ubuntu 22.04" + send_stats "重装ubuntu 22.04" dd_xitong_3 bash reinstall.sh ubuntu 22.04 reboot exit ;; 14) - send_stats "重裝ubuntu 20.04" + send_stats "重装ubuntu 20.04" dd_xitong_3 bash reinstall.sh ubuntu 20.04 reboot @@ -6330,7 +6388,7 @@ dd_xitong() { ;; 23) - send_stats "重裝alma10" + send_stats "重装alma10" dd_xitong_3 bash reinstall.sh almalinux reboot @@ -6643,12 +6701,12 @@ bbrv3() { elif [ -r /etc/os-release ]; then os_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") fi - + # 相容官方已移除的老系統代號(回退使用 releases 嘗試舊包庫) if ! echo "bookworm trixie forky sid noble plucky questing resolute faye gigi wilma xia zara zena" | grep -qw "$os_codename"; then os_codename="releases" fi - + # 官方已徹底移除對 jammy, focal, bullseye 等舊系統的 apt 支持 if echo "jammy focal bullseye buster" | grep -qw "$os_codename" || [ "$os_codename" = "releases" ]; then echo -e "${gl_hong}XanMod 官方已停止對目前系統($os_codename)的 APT 來源支持,請升級至 Debian12 / Ubuntu24 或更高版本。${gl_bai}" @@ -6731,12 +6789,12 @@ bbrv3() { check_disk_space 3 check_swap xanmod_add_repo || { - echo "XanMod官方仓库配置失败,请稍后重试" + echo "XanMod官方倉庫配置失敗,請稍後重試" return 1 } package=$(xanmod_detect_package) || { - echo "无法识别当前CPU或找不到匹配内核包,已取消安装" + echo "無法辨識目前CPU或找不到匹配核心包,已取消安裝" return 1 } @@ -6865,13 +6923,13 @@ elrepo_install() { linux_Settings fi # 列印偵測到的作業系統訊息 - echo "偵測到的作業系統:$os_name $os_version" + echo "检测到的操作系统: $os_name $os_version" # 根據系統版本安裝對應的 ELRepo 倉庫配置 if [[ "$os_version" == 8 ]]; then echo "安裝 ELRepo 倉庫設定 (版本 8)..." yum -y install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm elif [[ "$os_version" == 9 ]]; then - echo "安裝 ELRepo 倉庫設定 (版本 9)..." + echo "安装 ELRepo 仓库配置 (版本 9)..." yum -y install https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm elif [[ "$os_version" == 10 ]]; then echo "安裝 ELRepo 倉庫設定 (版本 10)..." @@ -6976,7 +7034,7 @@ clamav_freshclam() { clamav_scan() { if [ $# -eq 0 ]; then - echo "请指定要扫描的目录。" + echo "請指定要掃描的目錄。" return fi @@ -7044,7 +7102,7 @@ clamav() { ;; 2) - send_stats "重要目錄掃描" + send_stats "重要目录扫描" install_docker docker volume create clam_db > /dev/null 2>&1 clamav_freshclam @@ -7071,7 +7129,7 @@ clamav() { # ============================================================================ # Linux 核心調優模組(重構版) # 統一核心函數 + 場景差異化參數 + 持久化到設定檔 + 硬體自適應 -# 替换原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults +# 取代原 optimize_high_performance / optimize_balanced / optimize_web_server / restore_defaults # ============================================================================ # 取得記憶體大小(MB) @@ -7089,7 +7147,7 @@ _kernel_optimize_core() { echo -e "${gl_lv}切換到${mode_name}...${gl_bai}" - # ── 根據場景設定參數 ── + # ── 根据场景设定参数 ── local SWAPPINESS DIRTY_RATIO DIRTY_BG_RATIO OVERCOMMIT MIN_FREE_KB VFS_PRESSURE local RMEM_MAX WMEM_MAX TCP_RMEM TCP_WMEM local SOMAXCONN BACKLOG SYN_BACKLOG @@ -7121,7 +7179,7 @@ _kernel_optimize_core() { KEEPALIVE_PROBES=5 ;; web) - # 网站服务器:高并发优先 + # 網站伺服器:高並發優先 SWAPPINESS=10 DIRTY_RATIO=20 DIRTY_BG_RATIO=10 @@ -7240,11 +7298,11 @@ net.ipv4.tcp_slow_start_after_idle = 0" # ── 寫入設定檔(持久化) ── echo -e "${gl_lv}寫入優化配置...${gl_bai}" cat > "$CONF" << SYSCTL -# kejilion 核心調優配置 -# 模式: $mode_name | 場景: $scene -# 内存: ${MEM_MB}MB | 生成时间: $(date '+%Y-%m-%d %H:%M:%S') +# kejilion 内核调优配置 +# 模式: $mode_name | 场景: $scene +# 記憶體: ${MEM_MB}MB | 產生時間: $(date '+%Y-%m-%d %H:%M:%S') -# ── TCP 擁塞控制 ── +# ── TCP 拥塞控制 ── net.core.default_qdisc = $QDISC net.ipv4.tcp_congestion_control = $CC @@ -7310,7 +7368,7 @@ net.ipv6.conf.default.accept_redirects = 0 fs.file-max = 1048576 fs.nr_open = 1048576 -# ── 連結追蹤 ── +# ── 连接跟踪 ── $(if [ -f /proc/sys/net/netfilter/nf_conntrack_max ]; then echo "net.netfilter.nf_conntrack_max = $((SOMAXCONN * 32))" echo "net.netfilter.nf_conntrack_tcp_timeout_established = 7200" @@ -7325,7 +7383,7 @@ $GAME_EXTRA SYSCTL # ── 應用配置(逐行,跳過不支援的參數) ── - echo -e "${gl_lv}應用優化參數...${gl_bai}" + echo -e "${gl_lv}应用优化参数...${gl_bai}" local applied=0 skipped=0 while IFS= read -r line; do # 跳過註解和空行 @@ -7391,7 +7449,7 @@ restore_defaults() { rm -f "$CONF" rm -f /etc/sysctl.d/99-network-optimize.conf - # 清理 sysctl.conf 裡可能殘留的 bbr 配置 + # 清理 sysctl.conf 里可能残留的 bbr 配置 sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 2>/dev/null # 重新載入系統預設配置 @@ -7420,7 +7478,7 @@ Kernel_optimize() { send_stats "Linux核心調優管理" local current_mode=$(grep "^# 模式:" /etc/sysctl.d/99-kejilion-optimize.conf 2>/dev/null | sed 's/# 模式: //' | awk -F'|' '{print $1}' | xargs) [ -z "$current_mode" ] && [ -f /etc/sysctl.d/99-network-optimize.conf ] && current_mode="自動調優模式" - echo "Linux系統核心參數優化" + echo "Linux系统内核参数优化" if [ -n "$current_mode" ]; then echo -e "當前模式:${gl_lv}${current_mode}${gl_bai}" else @@ -7429,7 +7487,7 @@ Kernel_optimize() { echo "影片介紹: https://www.bilibili.com/video/BV1Kb421J7yg?t=0.1" echo "------------------------------------------------" echo "提供多種系統參數調優模式,使用者可依自身使用場景進行選擇切換。" - echo -e "${gl_huang}提示:${gl_bai}生产环境请谨慎使用!" + echo -e "${gl_huang}提示:${gl_bai}生產環境請謹慎使用!" echo -e "--------------------" echo -e "1. 高效能最佳化模式: 最大化系統效能,激進的記憶體和網路參數。" echo -e "2. 均衡最佳化模式: 在效能與資源消耗之間取得平衡,適合日常使用。" @@ -7545,16 +7603,16 @@ update_locale() { linux_language() { root_use -send_stats "切換系統語言" +send_stats "切换系统语言" while true; do clear echo "當前系統語言:$LANG" echo "------------------------" - echo "1. 英文 2. 简体中文 3. 繁体中文" + echo "1. 英文 2. 簡體中文 3. 繁體中文" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "輸入你的選擇:" choice + read -e -p "输入你的选择: " choice case $choice in 1) @@ -7600,10 +7658,10 @@ break_end shell_bianse() { root_use - send_stats "命令列美化工具" + send_stats "命令行美化工具" while true; do clear - echo "命令列美化工具" + echo "命令行美化工具" echo "------------------------" echo -e "1. \033[1;32mroot \033[1;34mlocalhost \033[1;31m~ \033[0m${gl_bai}#" echo -e "2. \033[1;35mroot \033[1;36mlocalhost \033[1;33m~ \033[0m${gl_bai}#" @@ -7671,7 +7729,7 @@ linux_trash() { if ! grep -q "trash-put" "$bashrc_profile"; then trash_status="${gl_hui}未啟用${gl_bai}" else - trash_status="${gl_lv}已啟用${gl_bai}" + trash_status="${gl_lv}已启用${gl_bai}" fi clear @@ -7741,7 +7799,7 @@ create_backup() { echo "建立備份範例:" echo "- 備份單一目錄: /var/www" echo "- 備份多個目錄: /etc /home /var/log" - echo " - 直接回车将使用默认目录 (/etc /usr /home)" + echo "- 直接回車將使用預設目錄 (/etc /usr /home)" read -e -p "請輸入要備份的目錄(多個目錄以空格分隔,直接回車則使用預設目錄):" input # 如果使用者沒有輸入目錄,則使用預設目錄 @@ -7764,7 +7822,7 @@ create_backup() { PREFIX+="${dir_name}_" done - # 去除最後一條底線 + # 去除最后一个下划线 local PREFIX=${PREFIX%_} # 產生備份檔名 @@ -7781,7 +7839,7 @@ create_backup() { install tar tar -czvf "$BACKUP_DIR/$BACKUP_NAME" "${BACKUP_PATHS[@]}" - # 檢查命令是否成功 + # 检查命令是否成功 if [ $? -eq 0 ]; then echo "備份建立成功:$BACKUP_DIR/$BACKUP_NAME" else @@ -7802,7 +7860,7 @@ restore_backup() { exit 1 fi - echo "正在恢復備份$BACKUP_NAME..." + echo "正在恢复备份 $BACKUP_NAME..." tar -xzvf "$BACKUP_DIR/$BACKUP_NAME" -C / if [ $? -eq 0 ]; then @@ -7827,7 +7885,7 @@ delete_backup() { # 檢查備份檔案是否存在 if [ ! -f "$BACKUP_DIR/$BACKUP_NAME" ]; then - echo "備份檔案不存在!" + echo "备份文件不存在!" exit 1 fi @@ -7848,7 +7906,7 @@ linux_backup() { mkdir -p "$BACKUP_DIR" while true; do clear - send_stats "系統備份功能" + send_stats "系统备份功能" echo "系統備份功能" echo "------------------------" list_backups @@ -7876,7 +7934,7 @@ linux_backup() { -# SSH 输入标准化函数 +# SSH 輸入標準化函數 kj_ssh_validate_host() { local host="$1" [[ -n "$host" && ! "$host" =~ [[:space:]] && "$host" =~ ^[A-Za-z0-9._:-]+$ ]] @@ -7948,7 +8006,7 @@ kj_ssh_parse_remote() { fi if ! kj_ssh_validate_user "$remote_user"; then - echo "錯誤: SSH 使用者名稱格式不正確。" + echo "错误: SSH 用户名格式不正确。" return 1 fi @@ -7967,7 +8025,7 @@ kj_ssh_read_auth() { local password_or_key="" echo "請選擇身份驗證方式:" - echo "1. 密碼" + echo "1. 密码" echo "2. 密鑰" read -e -p "請輸入選擇 (1/2):" auth_choice @@ -7976,7 +8034,7 @@ kj_ssh_read_auth() { read -s -p "請輸入密碼:" password_or_key echo if [ -z "$password_or_key" ]; then - echo "錯誤: 密碼不能為空。" + echo "错误: 密码不能为空。" return 1 fi KJ_SSH_AUTH_METHOD="password" @@ -8034,7 +8092,7 @@ kj_ssh_read_port() { done } -# 顯示連線清單 +# 显示连接列表 list_connections() { echo "已儲存的連線:" echo "------------------------" @@ -8068,7 +8126,7 @@ add_connection() { # 刪除連接 delete_connection() { send_stats "刪除連接" - read -e -p "請輸入要刪除的連接編號:" num + read -e -p "请输入要删除的连接编号: " num local connection=$(sed -n "${num}p" "$CONFIG_FILE") if [[ -z "$connection" ]]; then @@ -8107,7 +8165,7 @@ use_connection() { if [[ $? -ne 0 ]]; then echo "連線失敗!請檢查以下內容:" echo "1. 密鑰檔案路徑是否正確:$password_or_key" - echo "2. 密钥文件权限是否正确(应为 600)。" + echo "2. 密鑰檔案權限是否正確(應為 600)。" echo "3. 目標伺服器是否允許使用金鑰登入。" fi else @@ -8148,7 +8206,7 @@ ssh_manager() { while true; do clear - echo "SSH 遠端連線工具" + echo "SSH 远程连接工具" echo "可以透過SSH連接到其他Linux系統上" echo "------------------------" list_connections @@ -8178,9 +8236,9 @@ ssh_manager() { -# 列出可用的硬盘分区 +# 列出可用的硬碟分割區 list_partitions() { - echo "可用的硬碟分割區:" + echo "可用的硬盘分区:" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -v "sr\|loop" } @@ -8205,7 +8263,7 @@ mount_partition() { return 1 fi - # 取得 UUID + # 获取 UUID UUID=$(blkid -s UUID -o value "$DEVICE") if [ -z "$UUID" ]; then echo "無法取得 UUID!" @@ -8246,7 +8304,7 @@ mount_partition() { # 解除安裝分割區 unmount_partition() { - send_stats "解除安裝分割區" + send_stats "卸载分区" read -e -p "請輸入要卸載的分割區名稱(例如 sda1):" PARTITION # 檢查分割區是否已經掛載 @@ -8307,7 +8365,7 @@ format_partition() { esac # 確認格式化 - read -e -p "確認格式化分割區 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM + read -e -p "确认格式化分区 /dev/$PARTITION為$FS_TYPE嗎? (y/n):" CONFIRM if [ "$CONFIRM" != "y" ]; then echo "操作已取消。" return @@ -8329,7 +8387,7 @@ check_partition() { send_stats "檢查分區狀態" read -e -p "請輸入要檢查的分割區名稱(例如 sda1):" PARTITION - # 檢查分割區是否存在 + # 检查分区是否存在 if ! lsblk -o NAME | grep -w "$PARTITION" > /dev/null; then echo "分區不存在!" return @@ -8390,7 +8448,7 @@ add_task() { echo "- 連接埠號碼 (預設 22)" echo "---------------------------------" read -e -p "請輸入任務名稱:" name - read -e -p "请输入本地目录: " local_path + read -e -p "請輸入本地目錄:" local_path read -e -p "請輸入遠端目錄:" remote_path while true; do @@ -8447,7 +8505,7 @@ delete_task() { fi sed -i "${num}d" "$CONFIG_FILE" - echo "任務已刪除!" + echo "任务已删除!" } @@ -8468,7 +8526,7 @@ run_task() { num="$1" fi - # 如果没有传入任务编号,提示用户输入 + # 如果沒有傳入任務編號,提示使用者輸入 if [[ -z "$num" ]]; then read -e -p "請輸入要執行的任務編號:" num fi @@ -8487,7 +8545,7 @@ run_task() { source="$remote:$local_path" destination="$remote_path" else - echo "正在推送同步到遠端:$local_path -> $remote:$remote_path" + echo "正在推送同步到远端: $local_path -> $remote:$remote_path" source="$local_path" destination="$remote:$remote_path" fi @@ -8497,7 +8555,7 @@ run_task() { if [[ "$auth_method" == "password" ]]; then if ! command -v sshpass &> /dev/null; then - echo "錯誤:未安裝 sshpass,請先安裝 sshpass。" + echo "错误:未安装 sshpass,请先安装 sshpass。" echo "安裝方法:" echo " - Ubuntu/Debian: apt install sshpass" echo " - CentOS/RHEL: yum install sshpass" @@ -8542,9 +8600,9 @@ schedule_task() { fi echo "請選擇定時執行間隔:" - echo "1) 每小時執行一次" + echo "1) 每小时执行一次" echo "2) 每天執行一次" - echo "3) 每週執行一次" + echo "3) 每周执行一次" read -e -p "請輸入選項 (1/2/3):" interval local random_minute=$(shuf -i 0-59 -n 1) # 生成 0-59 之间的随机分钟数 @@ -8583,7 +8641,7 @@ delete_task_schedule() { send_stats "刪除同步定時任務" read -e -p "請輸入要刪除的任務編號:" num if ! [[ "$num" =~ ^[0-9]+$ ]]; then - echo "錯誤: 請輸入有效的任務編號!" + echo "错误: 请输入有效的任务编号!" return fi @@ -8607,8 +8665,8 @@ rsync_manager() { view_tasks echo echo "1. 建立新任務 2. 刪除任務" - echo "3. 執行本地同步到遠端 4. 執行遠端同步到本地" - echo "5. 建立定時任務 6. 刪除定時任務" + echo "3. 执行本地同步到远端 4. 执行远端同步到本地" + echo "5. 创建定时任务 6. 删除定时任务" echo "---------------------------------" echo "0. 返回上一級選單" echo "---------------------------------" @@ -8700,7 +8758,7 @@ linux_info() { echo -e "${gl_kjlan}Linux版本:${gl_bai}$kernel_version" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}CPU架構:${gl_bai}$cpu_arch" - echo -e "${gl_kjlan}CPU型号: ${gl_bai}$cpu_info" + echo -e "${gl_kjlan}CPU型號:${gl_bai}$cpu_info" echo -e "${gl_kjlan}CPU核心數:${gl_bai}$cpu_cores" echo -e "${gl_kjlan}CPU頻率:${gl_bai}$cpu_freq" echo -e "${gl_kjlan}-------------" @@ -8709,7 +8767,7 @@ linux_info() { echo -e "${gl_kjlan}TCP|UDP連線數:${gl_bai}$tcp_count|$udp_count" echo -e "${gl_kjlan}實體記憶體:${gl_bai}$mem_info" echo -e "${gl_kjlan}虛擬記憶體:${gl_bai}$swap_info" - echo -e "${gl_kjlan}硬碟佔用:${gl_bai}$disk_info" + echo -e "${gl_kjlan}硬盘占用: ${gl_bai}$disk_info" echo -e "${gl_kjlan}-------------" echo -e "${gl_kjlan}總接收:${gl_bai}$rx" echo -e "${gl_kjlan}總發送:${gl_bai}$tx" @@ -8722,7 +8780,7 @@ linux_info() { fi if [ -n "$ipv6_address" ]; then - echo -e "${gl_kjlan}IPv6位址:${gl_bai}$ipv6_address" + echo -e "${gl_kjlan}IPv6地址: ${gl_bai}$ipv6_address" fi echo -e "${gl_kjlan}DNS位址:${gl_bai}$dns_addresses" echo -e "${gl_kjlan}地理位置:${gl_bai}$country $city" @@ -8797,7 +8855,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}curl 下載工具${gl_huang}★${gl_bai} ${gl_kjlan}2. ${gl_bai}wget 下載工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}3. ${gl_bai}sudo 超級管理權限工具${gl_kjlan}4. ${gl_bai}socat 通訊連接工具" + echo -e "${gl_kjlan}3. ${gl_bai}sudo 超级管理权限工具 ${gl_kjlan}4. ${gl_bai}socat 通信连接工具" echo -e "${gl_kjlan}5. ${gl_bai}htop 系統監控工具${gl_kjlan}6. ${gl_bai}iftop 網路流量監控工具" echo -e "${gl_kjlan}7. ${gl_bai}unzip ZIP壓縮解壓縮工具${gl_kjlan}8. ${gl_bai}tar GZ壓縮解壓縮工具" echo -e "${gl_kjlan}9. ${gl_bai}tmux 多路後台運行工具${gl_kjlan}10. ${gl_bai}ffmpeg 視訊編碼直播推流工具" @@ -8809,7 +8867,7 @@ linux_tools() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}21. ${gl_bai}駭客任務螢幕保${gl_kjlan}22. ${gl_bai}跑火車屏保" echo -e "${gl_kjlan}26. ${gl_bai}俄羅斯方塊小遊戲${gl_kjlan}27. ${gl_bai}貪吃蛇小遊戲" - echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小遊戲" + echo -e "${gl_kjlan}28. ${gl_bai}太空入侵者小游戏" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}31. ${gl_bai}全部安裝${gl_kjlan}32. ${gl_bai}全部安裝(不含螢幕保護程式和遊戲)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${gl_bai}全部解除安裝" @@ -8833,7 +8891,7 @@ linux_tools() { clear install wget clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" wget --help send_stats "安裝wget" ;; @@ -8841,7 +8899,7 @@ linux_tools() { clear install sudo clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" sudo --help send_stats "安裝sudo" ;; @@ -8871,7 +8929,7 @@ linux_tools() { clear install unzip clear - echo "工具已安裝,使用方法如下:" + echo "工具已安装,使用方法如下:" unzip send_stats "安裝unzip" ;; @@ -9076,7 +9134,7 @@ linux_bbr() { echo "" echo "BBR管理" echo "------------------------" - echo "1. 開啟BBRv3 2. 關閉BBRv3(會重新啟動)" + echo "1. 开启BBRv3 2. 关闭BBRv3(会重启)" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -9128,14 +9186,14 @@ docker_ssh_migration() { # ---------------------------- - # 備份 + # 备份 # ---------------------------- backup_docker() { send_stats "Docker備份" echo -e "${gl_kjlan}正在備份 Docker 容器...${gl_bai}" docker ps --format '{{.Names}}' - read -e -p "请输入要备份的容器名(多个空格分隔,回车备份全部运行中容器): " containers + read -e -p "請輸入要備份的容器名稱(多個空格分隔,回車備份全部運行中容器):" containers install tar jq gzip install_docker @@ -9156,9 +9214,9 @@ docker_ssh_migration() { local RESTORE_SCRIPT="${BACKUP_DIR}/docker_restore.sh" echo "#!/bin/bash" > "$RESTORE_SCRIPT" echo "set -e" >> "$RESTORE_SCRIPT" - echo "# 自動產生的還原腳本" >> "$RESTORE_SCRIPT" + echo "# 自动生成的还原脚本" >> "$RESTORE_SCRIPT" - # 记录已打包过的 Compose 项目路径,避免重复打包 + # 記錄已打包過的 Compose 專案路徑,避免重複打包 declare -A PACKED_COMPOSE_PATHS=() for c in "${TARGET_CONTAINERS[@]}"; do @@ -9172,7 +9230,7 @@ docker_ssh_migration() { local project_name=$(docker inspect "$c" | jq -r '.[0].Config.Labels["com.docker.compose.project"] // empty') if [ -z "$project_dir" ]; then - read -e -p "未检测到 compose 目录,请手动输入路径: " project_dir + read -e -p "未偵測到 compose 目錄,請手動輸入路徑:" project_dir fi # 如果該 Compose 項目已經打包過,跳過 @@ -9229,7 +9287,7 @@ docker_ssh_migration() { if [ -d "/home/docker" ]; then echo -e "${gl_kjlan}備份 /home/docker 下的檔案...${gl_bai}" find /home/docker -maxdepth 1 -type f | tar -czf "${BACKUP_DIR}/home_docker_files.tar.gz" -T - - echo -e "${gl_lv}/home/docker 下的文件已打包到: ${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" + echo -e "${gl_lv}/home/docker 下的檔案已打包到:${BACKUP_DIR}/home_docker_files.tar.gz${gl_bai}" fi chmod +x "$RESTORE_SCRIPT" @@ -9240,7 +9298,7 @@ docker_ssh_migration() { } # ---------------------------- - # 還原 + # 还原 # ---------------------------- restore_docker() { @@ -9253,7 +9311,7 @@ docker_ssh_migration() { install tar jq gzip install_docker - # --------- 优先还原 Compose 项目 --------- + # --------- 優先還原 Compose 專案 --------- for f in "$BACKUP_DIR"/backup_type_*; do [[ ! -f "$f" ]] && continue if grep -q "compose" "$f"; then @@ -9274,7 +9332,7 @@ docker_ssh_migration() { mkdir -p "$original_path" tar -xzf "$BACKUP_DIR/compose_project_${project_name}.tar.gz" -C "$original_path" - echo -e "${gl_lv}Compose 項目 [$project_name] 已解壓縮到:$original_path${gl_bai}" + echo -e "${gl_lv}Compose 项目 [$project_name] 已解壓縮到:$original_path${gl_bai}" cd "$original_path" || return docker compose down || true @@ -9299,7 +9357,7 @@ docker_ssh_migration() { fi IMAGE=$(jq -r '.[0].Config.Image' "$json") - [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到镜像信息,跳过: $container${gl_bai}"; continue; } + [[ -z "$IMAGE" || "$IMAGE" == "null" ]] && { echo -e "${gl_hong}未找到鏡像訊息,跳過:$container${gl_bai}"; continue; } # 連接埠映射 PORT_ARGS="" @@ -9344,7 +9402,7 @@ docker_ssh_migration() { [[ "$has_container" == false ]] && echo -e "${gl_huang}未找到普通容器的備份訊息${gl_bai}" - # 還原 /home/docker 下的文件 + # 还原 /home/docker 下的文件 if [ -f "$BACKUP_DIR/home_docker_files.tar.gz" ]; then echo -e "${gl_kjlan}正在還原 /home/docker 下的檔案...${gl_bai}" mkdir -p /home/docker @@ -9413,14 +9471,14 @@ docker_ssh_migration() { echo "------------------------" echo -e "0. 返回上一級選單" echo "------------------------" - read -e -p "请选择: " choice + read -e -p "請選擇:" choice case $choice in 1) backup_docker ;; 2) migrate_docker ;; 3) restore_docker ;; 4) delete_backup ;; 0) return ;; - *) echo -e "${gl_hong}無效選項${gl_bai}" ;; + *) echo -e "${gl_hong}无效选项${gl_bai}" ;; esac break_end done @@ -9494,7 +9552,7 @@ linux_docker() { echo -e "Docker磁碟區:${gl_lv}$volume_count${gl_bai}" docker volume ls echo "" - echo -e "Docker網路:${gl_lv}$network_count${gl_bai}" + echo -e "Docker网络: ${gl_lv}$network_count${gl_bai}" docker network ls echo "" @@ -9510,14 +9568,14 @@ linux_docker() { while true; do clear send_stats "Docker網路管理" - echo "Docker網路列表" + echo "Docker网络列表" echo "------------------------------------------------------------" docker network ls echo "" echo "------------------------------------------------------------" container_ids=$(docker ps -q) - printf "%-25s %-25s %-25s\n" "容器名稱" "網路名稱" "IP位址" + printf "%-25s %-25s %-25s\n" "容器名称" "網路名稱" "IP位址" for container_id in $container_ids; do local container_info=$(docker inspect --format '{{ .Name }}{{ range $network, $config := .NetworkSettings.Networks }} {{ $network }} {{ $config.IPAddress }}{{ end }}' "$container_id") @@ -9554,14 +9612,14 @@ linux_docker() { 2) send_stats "加入網路" read -e -p "加入網路名稱:" dockernetwork - read -e -p "那些容器加入該網路(多個容器名稱請以空格分隔):" dockernames + read -e -p "那些容器加入该网络(多个容器名请用空格分隔): " dockernames for dockername in $dockernames; do docker network connect $dockernetwork $dockername done ;; 3) - send_stats "加入網路" + send_stats "加入网络" read -e -p "退出網路名稱:" dockernetwork read -e -p "那些容器退出該網路(多個容器名稱請以空格分隔):" dockernames @@ -9587,7 +9645,7 @@ linux_docker() { 6) while true; do clear - send_stats "Docker磁碟區管理" + send_stats "Docker卷管理" echo "Docker卷列表" docker volume ls echo "" @@ -9688,7 +9746,7 @@ linux_docker() { 20) clear - send_stats "Docker解除安裝" + send_stats "Docker卸载" read -e -p "$(echo -e "${gl_hong}注意: ${gl_bai}确定卸载docker环境吗?(Y/N): ")" choice case "$choice" in [Yy]) @@ -9722,6 +9780,382 @@ linux_docker() { +kpanel_node_paths() { + KPANEL_NODE_HOME="/usr/local/lib/kejilion-node" + KPANEL_NODE_BINARY="${KPANEL_NODE_HOME}/kejilion-node" + KPANEL_NODE_UPDATER="${KPANEL_NODE_HOME}/update.sh" + KPANEL_NODE_CONFIG_DIR="/etc/kejilion-node" + KPANEL_NODE_CONFIG="${KPANEL_NODE_CONFIG_DIR}/node.json" + KPANEL_NODE_SYSTEMCTL="$(type -P systemctl 2>/dev/null || true)" +} + +kpanel_node_preflight() { + [ "$(id -u)" = "0" ] || { + echo "KPanel 輕量節點安裝需要 root 權限。" >&2 + return 1 + } + for command_name in curl sha256sum mktemp; do + command -v "$command_name" >/dev/null 2>&1 || { + echo "缺少必要命令:${command_name}" >&2 + return 1 + } + done + [ -n "$KPANEL_NODE_SYSTEMCTL" ] && [ -x "$KPANEL_NODE_SYSTEMCTL" ] || { + echo "缺少必要指令: systemctl" >&2 + return 1 + } + KPANEL_NODE_INSTALL_BIN="$(type -P install 2>/dev/null || true)" + [ -n "$KPANEL_NODE_INSTALL_BIN" ] && [ -x "$KPANEL_NODE_INSTALL_BIN" ] || { + echo "缺少必要命令: install (coreutils)" >&2 + return 1 + } + if ! command -v useradd >/dev/null 2>&1 && + ! command -v systemd-sysusers >/dev/null 2>&1 && + ! command -v adduser >/dev/null 2>&1; then + echo "缺少系統帳號建立工具: useradd、systemd-sysusers 或 adduser" >&2 + return 1 + fi + [ -d /run/systemd/system ] || { + echo "目前系統未執行 systemd,無法安裝 KPanel 輕量節點。" >&2 + return 1 + } + case "$(uname -m)" in + x86_64|amd64) KPANEL_NODE_ARCH="amd64" ;; + aarch64|arm64) KPANEL_NODE_ARCH="arm64" ;; + *) + echo "目前 CPU 架構暫不支援 KPanel 輕量節點。" >&2 + return 1 + ;; + esac +} + +kpanel_node_ensure_account() { + local nologin_shell="/usr/sbin/nologin" sysusers_config="" + if id kejilion-node >/dev/null 2>&1; then + [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "現有 kejilion-node 帳戶的主群組不安全,拒絕繼續。" >&2 + return 1 + } + return 0 + fi + [ -x "$nologin_shell" ] || nologin_shell="/sbin/nologin" + [ -x "$nologin_shell" ] || nologin_shell="/bin/false" + + if command -v useradd >/dev/null 2>&1; then + useradd --system --no-create-home --home-dir /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + elif command -v systemd-sysusers >/dev/null 2>&1; then + sysusers_config="$(mktemp /tmp/kejilion-node-sysusers.XXXXXX)" || return 1 + printf 'u kejilion-node - "KPanel Lightweight Monitoring Node" /nonexistent %s\n' "$nologin_shell" >"$sysusers_config" + if ! systemd-sysusers "$sysusers_config"; then + rm -f -- "$sysusers_config" + return 1 + fi + rm -f -- "$sysusers_config" + elif adduser --help 2>&1 | grep -q -- '--system'; then + adduser --system --group --no-create-home --home /nonexistent --shell "$nologin_shell" kejilion-node || return 1 + else + command -v addgroup >/dev/null 2>&1 || { + echo "缺少系統群組建立工具: addgroup" >&2 + return 1 + } + addgroup -S kejilion-node >/dev/null 2>&1 || true + adduser -S -D -H -h /nonexistent -s "$nologin_shell" -G kejilion-node kejilion-node || return 1 + fi + + id kejilion-node >/dev/null 2>&1 && [ "$(id -gn kejilion-node 2>/dev/null)" = "kejilion-node" ] || { + echo "KPanel 輕量節點低權限帳戶建立失敗。" >&2 + return 1 + } +} + +kpanel_node_write_updater() { + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g root -m 0755 "$KPANEL_NODE_HOME" || return 1 + cat >"$KPANEL_NODE_UPDATER" <<'KPANEL_NODE_UPDATE' +#!/bin/bash +set -euo pipefail + +mode="${1:-update}" +case "$mode" in + install|update) ;; + *) echo "unsupported update mode" >&2; exit 2 ;; +esac + +case "$(uname -m)" in + x86_64|amd64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + *) echo "unsupported CPU architecture" >&2; exit 1 ;; +esac + +home_dir="/usr/local/lib/kejilion-node" +binary_name="kejilion-node-linux-${arch}" +binary_path="${home_dir}/kejilion-node" +base_url="https://github.com/kejilion/KPanel/releases/latest/download" +lock_dir="/run/lock/kejilion-node-update.lock" + +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "another KPanel lightweight node update is running" >&2 + exit 1 +fi +temporary_dir="$(mktemp -d /tmp/kejilion-node-update.XXXXXX)" +cleanup() { + rm -rf -- "$temporary_dir" + rmdir "$lock_dir" 2>/dev/null || true +} +trap cleanup EXIT HUP INT TERM + +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 180 \ + -o "${temporary_dir}/${binary_name}" "${base_url}/${binary_name}" +curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --connect-timeout 15 --max-time 60 \ + -o "${temporary_dir}/SHA256SUMS" "${base_url}/SHA256SUMS" + +expected="$(awk -v name="$binary_name" '$2 == name { print $1 }' "${temporary_dir}/SHA256SUMS")" +printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$' || { + echo "release checksum is unavailable" >&2 + exit 1 +} +actual="$(sha256sum "${temporary_dir}/${binary_name}" | awk '{print $1}')" +[ "$actual" = "$expected" ] || { + echo "release checksum verification failed" >&2 + exit 1 +} +chmod 0755 "${temporary_dir}/${binary_name}" +version_output="$("${temporary_dir}/${binary_name}" version)" +printf '%s\n' "$version_output" | grep -Eq '^[^[:space:]]+ light-v1$' || { + echo "release binary protocol is invalid" >&2 + exit 1 +} + +if [ -f "$binary_path" ] && [ "$(sha256sum "$binary_path" | awk '{print $1}')" = "$actual" ]; then + echo "KPanel lightweight node is already up to date." + exit 0 +fi + +install -o root -g root -m 0755 "${temporary_dir}/${binary_name}" "${binary_path}.new" +had_previous=false +if [ -f "$binary_path" ]; then + cp -p -- "$binary_path" "${binary_path}.previous" + had_previous=true +fi +mv -f -- "${binary_path}.new" "$binary_path" + +if [ "$mode" = "update" ] && systemctl cat kejilion-node.service >/dev/null 2>&1; then + if ! systemctl restart kejilion-node.service || ! systemctl is-active --quiet kejilion-node.service; then + if [ "$had_previous" = "true" ] && [ -f "${binary_path}.previous" ]; then + mv -f -- "${binary_path}.previous" "$binary_path" + systemctl restart kejilion-node.service || true + fi + echo "KPanel lightweight node update failed and was rolled back." >&2 + exit 1 + fi +fi +rm -f -- "${binary_path}.previous" +echo "KPanel lightweight node update completed." +KPANEL_NODE_UPDATE + chmod 0755 "$KPANEL_NODE_UPDATER" +} + +kpanel_node_write_units() { + cat >/etc/systemd/system/kejilion-node.service <<'KPANEL_NODE_SERVICE' +[Unit] +Description=KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=kejilion-node +Group=kejilion-node +ExecStart=/usr/local/lib/kejilion-node/kejilion-node run --config /etc/kejilion-node/node.json +Restart=on-failure +RestartSec=15s +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictRealtime=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target +KPANEL_NODE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.service <<'KPANEL_NODE_UPDATE_SERVICE' +[Unit] +Description=Update KPanel Lightweight Monitoring Node +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/kejilion-node/update.sh update +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +UMask=0077 +KPANEL_NODE_UPDATE_SERVICE + + cat >/etc/systemd/system/kejilion-node-update.timer <<'KPANEL_NODE_UPDATE_TIMER' +[Unit] +Description=Check KPanel Lightweight Monitoring Node Updates + +[Timer] +OnBootSec=15min +OnUnitActiveSec=24h +RandomizedDelaySec=6h +Persistent=true + +[Install] +WantedBy=timers.target +KPANEL_NODE_UPDATE_TIMER + chmod 0644 /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer +} + +kpanel_node_cleanup_failed_join() { + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true +} + +kpanel_node_activate() { + "$KPANEL_NODE_SYSTEMCTL" daemon-reload && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" enable kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node.service && + "$KPANEL_NODE_SYSTEMCTL" start kejilion-node-update.timer && + "$KPANEL_NODE_SYSTEMCTL" is-active kejilion-node.service >/dev/null +} + +kpanel_node_join() { + local token="${1:-}" node_name resume_enrollment=false + kpanel_node_paths + kpanel_node_preflight || return 1 + case "$token" in + kpl1.*) ;; + *) echo "輕量節點存取授權無效。" >&2; return 2 ;; + esac + [ "${#token}" -le 2048 ] || { + echo "輕量節點存取授權無效。" >&2 + return 2 + } + if [ -e "$KPANEL_NODE_CONFIG" ]; then + if [ -f "$KPANEL_NODE_CONFIG" ] && [ ! -L "$KPANEL_NODE_CONFIG" ] && [ -x "$KPANEL_NODE_BINARY" ]; then + resume_enrollment=true + echo "偵測到已完成的節點授權,繼續啟用本機服務。" + else + echo "本機存在不完整的 KPanel 節點配置;請先執行 k kpanel node uninstall。" >&2 + return 1 + fi + fi + kpanel_node_ensure_account || return 1 + "$KPANEL_NODE_INSTALL_BIN" -d -o root -g kejilion-node -m 0750 "$KPANEL_NODE_CONFIG_DIR" || return 1 + if ! kpanel_node_write_updater || ! "$KPANEL_NODE_UPDATER" install; then + [ "$resume_enrollment" = "true" ] || kpanel_node_cleanup_failed_join + return 1 + fi + if [ "$resume_enrollment" != "true" ]; then + node_name="$(hostname 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]_. -' | cut -c1-80)" + if ! "$KPANEL_NODE_BINARY" enroll --token "$token" --name "$node_name" --config "$KPANEL_NODE_CONFIG"; then + kpanel_node_cleanup_failed_join + return 1 + fi + fi + chown root:kejilion-node "$KPANEL_NODE_CONFIG" || { + echo "節點授權已儲存,但設定權限修復失敗;再次執行存取命令可繼續。" >&2 + return 1 + } + chmod 0640 "$KPANEL_NODE_CONFIG" + if ! kpanel_node_write_units; then + echo "節點授權已儲存,但 systemd 單元寫入失敗;再次執行存取命令可繼續。" >&2 + return 1 + fi + if ! kpanel_node_activate; then + echo "KPanel 輕量節點授權已儲存,但服務啟動失敗;修復 systemd 後再次執行存取指令即可續訂。" >&2 + return 1 + fi + echo "KPanel 輕量節點已接入,後續自動更新。" +} + +kpanel_node_status() { + kpanel_node_paths + [ -x "$KPANEL_NODE_BINARY" ] || { + echo "KPanel 輕量節點未安裝。" >&2 + return 1 + } + "$KPANEL_NODE_BINARY" version + "$KPANEL_NODE_SYSTEMCTL" --no-pager --full status kejilion-node.service +} + +kpanel_node_update() { + kpanel_node_paths + kpanel_node_preflight || return 1 + [ -x "$KPANEL_NODE_UPDATER" ] || { + echo "KPanel 輕量節點未安裝。" >&2 + return 1 + } + "$KPANEL_NODE_UPDATER" update +} + +kpanel_node_uninstall() { + kpanel_node_paths + [ "$(id -u)" = "0" ] || { + echo "卸載 KPanel 輕量節點需要 root 權限。" >&2 + return 1 + } + if [ -x "$KPANEL_NODE_SYSTEMCTL" ]; then + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" stop kejilion-node-update.timer >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node.service >/dev/null 2>&1 || true + "$KPANEL_NODE_SYSTEMCTL" disable kejilion-node-update.timer >/dev/null 2>&1 || true + fi + rm -f -- /etc/systemd/system/kejilion-node.service \ + /etc/systemd/system/kejilion-node-update.service \ + /etc/systemd/system/kejilion-node-update.timer + rm -rf -- "$KPANEL_NODE_HOME" "$KPANEL_NODE_CONFIG_DIR" + [ ! -x "$KPANEL_NODE_SYSTEMCTL" ] || "$KPANEL_NODE_SYSTEMCTL" daemon-reload >/dev/null 2>&1 || true + echo "KPanel 輕量節點已從本機卸載;中心端的離線記錄需在叢集頁面刪除。" +} + +kpanel_node_dispatch() { + local action="${1:-}" + shift || true + case "$action" in + join) kpanel_node_join "$@" ;; + status) kpanel_node_status ;; + update) kpanel_node_update ;; + uninstall|remove) kpanel_node_uninstall ;; + *) + echo "用法: k kpanel node join <授權> | status | update | uninstall" >&2 + return 2 + ;; + esac +} + kpanel_test_catalog() { cat <<'KPANEL_TEST_CATALOG' KPANEL_TEST_CATEGORY access IP 与解锁 @@ -9853,7 +10287,7 @@ kpanel_run_test_noninteractive() { kpanel_run_remote_bash ${gh_proxy}raw.githubusercontent.com/i-abc/GB5/main/gb5-test.sh ;; bench) - send_stats "bench效能測試" + send_stats "bench性能测试" kpanel_run_remote_bash https://bench.sh ;; ecs) @@ -9987,7 +10421,7 @@ linux_test() { send_stats "nxtrace指定IP回程測試腳本" echo "可參考的IP列表" echo "------------------------" - echo "北京电信: 219.141.136.12" + echo "北京電信: 219.141.136.12" echo "北京聯通: 202.106.50.1" echo "北京移動: 221.179.155.161" echo "上海電信: 202.96.209.133" @@ -9998,7 +10432,7 @@ linux_test() { echo "廣州移動: 120.196.165.24" echo "成都電信: 61.139.2.69" echo "成都聯通: 119.6.6.6" - echo "成都移动: 211.137.96.205" + echo "成都移動: 211.137.96.205" echo "湖南電信: 36.111.200.100" echo "湖南聯通: 42.48.16.100" echo "湖南移動: 39.134.254.6" @@ -10093,8 +10527,8 @@ linux_Oracle() { echo -e "${gl_kjlan}2. ${gl_bai}卸載閒置機器活躍腳本" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}3. ${gl_bai}DD重裝系統腳本" - echo -e "${gl_kjlan}4. ${gl_bai}R探长开机脚本" - echo -e "${gl_kjlan}5. ${gl_bai}開啟ROOT密碼登入模式" + echo -e "${gl_kjlan}4. ${gl_bai}R探長開機腳本" + echo -e "${gl_kjlan}5. ${gl_bai}开启ROOT密码登录模式" echo -e "${gl_kjlan}6. ${gl_bai}IPV6恢復工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -10161,7 +10595,7 @@ linux_Oracle() { echo "重裝系統" echo "--------------------------------" echo -e "${gl_hong}注意:${gl_bai}重裝有風險失聯,不放心者慎用。重裝預計花費15分鐘,請提前備份資料。" - read -e -p "確定繼續嗎? (Y/N):" choice + read -e -p "确定继续吗?(Y/N): " choice case "$choice" in [Yy]) @@ -10199,7 +10633,7 @@ linux_Oracle() { 4) clear - send_stats "R探長開機腳本" + send_stats "R探长开机脚本" bash <(wget -qO- ${gh_proxy}github.com/Yohann0617/oci-helper/releases/latest/download/sh_oci-helper_install.sh) ;; 5) @@ -10813,7 +11247,7 @@ ldnmp_environment_menu() { ldnmp_restore_action "$backup_name" ;; 9) - read -e -p "输入 DELETE 确认卸载 LDNMP 环境: " confirmation + read -e -p "輸入 DELETE 確認卸載 LDNMP 環境:" confirmation [ "$confirmation" = DELETE ] && ldnmp_uninstall_action true ;; 0) return 0 ;; @@ -10864,21 +11298,21 @@ linux_ldnmp() { echo -e "${gl_huang}------------------------" echo -e "${gl_huang}1. ${gl_bai}安裝LDNMP環境${gl_huang}★${gl_bai} ${gl_huang}2. ${gl_bai}安裝WordPress${gl_huang}★${gl_bai}" echo -e "${gl_huang}3. ${gl_bai}安裝Discuz論壇${gl_huang}4. ${gl_bai}安裝可道雲桌面" - echo -e "${gl_huang}5. ${gl_bai}安装苹果CMS影视站 ${gl_huang}6. ${gl_bai}安裝獨角數發卡網" + echo -e "${gl_huang}5. ${gl_bai}安裝蘋果CMS影視站${gl_huang}6. ${gl_bai}安裝獨角數發卡網" echo -e "${gl_huang}7. ${gl_bai}安裝flarum論壇網站${gl_huang}8. ${gl_bai}安裝typecho輕量部落格網站" echo -e "${gl_huang}9. ${gl_bai}安裝LinkStack分享連結平台${gl_huang}20. ${gl_bai}自訂動態站點" echo -e "${gl_huang}------------------------" - echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}網站重定向" + echo -e "${gl_huang}21. ${gl_bai}僅安裝nginx${gl_huang}★${gl_bai} ${gl_huang}22. ${gl_bai}站点重定向" echo -e "${gl_huang}23. ${gl_bai}站點反向代理-IP+端口${gl_huang}★${gl_bai} ${gl_huang}24. ${gl_bai}站點反向代理-域名" - echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安裝Halo部落格網站" + echo -e "${gl_huang}25. ${gl_bai}安裝Bitwarden密碼管理平台${gl_huang}26. ${gl_bai}安装Halo博客网站" echo -e "${gl_huang}27. ${gl_bai}安裝AI繪畫提示詞產生器${gl_huang}28. ${gl_bai}站點反向代理-負載平衡" - echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自訂靜態站點" + echo -e "${gl_huang}29. ${gl_bai}Stream四層代理轉發${gl_huang}30. ${gl_bai}自定义静态站点" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}31. ${gl_bai}站點資料管理${gl_huang}★${gl_bai} ${gl_huang}32. ${gl_bai}備份全站數據" echo -e "${gl_huang}33. ${gl_bai}定時遠端備份${gl_huang}34. ${gl_bai}還原全站數據" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}35. ${gl_bai}防護LDNMP環境${gl_huang}36. ${gl_bai}優化LDNMP環境" - echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}解除安裝LDNMP環境" + echo -e "${gl_huang}37. ${gl_bai}更新LDNMP環境${gl_huang}38. ${gl_bai}卸载LDNMP环境" echo -e "${gl_huang}------------------------" echo -e "${gl_huang}0. ${gl_bai}返回主選單" echo -e "${gl_huang}------------------------${gl_bai}" @@ -10932,7 +11366,7 @@ linux_ldnmp() { 3) clear # Discuz論壇 - webname="Discuz論壇" + webname="Discuz论坛" send_stats "安裝$webname" echo "開始部署$webname" add_yuming @@ -10969,7 +11403,7 @@ linux_ldnmp() { echo "資料庫位址: mysql" echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "密码: $dbusepasswd" echo "表前綴: discuz_" @@ -11059,7 +11493,7 @@ linux_ldnmp() { echo "密碼:$dbusepasswd" echo "資料庫前綴: mac_" echo "------------------------" - echo "安裝成功後登入後台位址" + echo "安装成功后登录后台地址" echo "https://$yuming/vip.php" ;; @@ -11101,7 +11535,7 @@ linux_ldnmp() { echo "資料庫連接埠: 3306" echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "密码: $dbusepasswd" echo "" echo "redis地址: redis" echo "redis密碼: 預設不填寫" @@ -11174,7 +11608,7 @@ linux_ldnmp() { ldnmp_web_on echo "資料庫位址: mysql" echo "資料庫名稱:$dbname" - echo "使用者名稱:$dbuse" + echo "用户名: $dbuse" echo "密碼:$dbusepasswd" echo "表字首: flarum_" echo "管理員資訊自行設定" @@ -11220,7 +11654,7 @@ linux_ldnmp() { echo "資料庫前綴: typecho_" echo "資料庫位址: mysql" echo "使用者名稱:$dbuse" - echo "密碼:$dbusepasswd" + echo "密码: $dbusepasswd" echo "資料庫名稱:$dbname" ;; @@ -11262,7 +11696,7 @@ linux_ldnmp() { clear ldnmp_web_on echo "資料庫位址: mysql" - echo "資料庫連接埠: 3306" + echo "数据库端口: 3306" echo "資料庫名稱:$dbname" echo "使用者名稱:$dbuse" echo "密碼:$dbusepasswd" @@ -11270,8 +11704,8 @@ linux_ldnmp() { 20) clear - webname="PHP動態站點" - send_stats "安裝$webname" + webname="PHP动态站点" + send_stats "安装$webname" echo "開始部署$webname" add_yuming repeat_add_yuming @@ -11294,7 +11728,7 @@ linux_ldnmp() { clear echo -e "[${gl_huang}1/6${gl_bai}] 上傳PHP原始碼" echo "-------------" - echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目錄下" + echo "目前只允許上傳zip格式的源碼包,請將源碼包放到/home/web/html/${yuming}目录下" read -e -p "也可以輸入下載鏈接,遠端下載源碼包,直接回車將跳過遠端下載:" url_download if [ -n "$url_download" ]; then @@ -11310,7 +11744,7 @@ linux_ldnmp() { # find "$(realpath .)" -name "index.php" -print find "$(realpath .)" -name "index.php" -print | xargs -I {} dirname {} - read -e -p "請輸入index.php的路徑,類似(/home/web/html/$yuming/wordpress/): " index_lujing + read -e -p "请输入index.php的路径,类似(/home/web/html/$yuming/wordpress/): " index_lujing sed -i "s#root /var/www/html/$yuming/#root $index_lujing#g" /home/web/conf.d/$yuming.conf sed -i "s#/home/web/#/var/www/#g" /home/web/conf.d/$yuming.conf @@ -11329,7 +11763,7 @@ linux_ldnmp() { local PHP_Version="php74" ;; *) - echo "無效的選擇,請重新輸入。" + echo "无效的选择,请重新输入。" ;; esac @@ -11409,7 +11843,7 @@ linux_ldnmp() { 22) clear webname="網站重定向" - send_stats "安裝$webname" + send_stats "安装$webname" echo "開始部署$webname" add_yuming read -e -p "請輸入跳轉域名:" reverseproxy @@ -11715,7 +12149,7 @@ linux_ldnmp() { docker compose down > /dev/null 2>&1 rm -rf /home/web > /dev/null 2>&1 - echo -e "${gl_kjlan}正在解压 $filename ...${gl_bai}" + echo -e "${gl_kjlan}正在解壓縮$filename ...${gl_bai}" cd /home/ && tar -xzf "$filename" install_dependency @@ -11742,7 +12176,7 @@ linux_ldnmp() { while true; do clear send_stats "更新LDNMP環境" - echo "更新LDNMP環境" + echo "更新LDNMP环境" echo "------------------------" ldnmp_v echo "發現新版本的元件" @@ -11765,11 +12199,11 @@ linux_ldnmp() { fi echo "------------------------" echo - echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" + echo "1. 更新nginx 2. 更新mysql 3. 更新php 4. 更新redis" echo "------------------------" echo "5. 更新完整環境" echo "------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "------------------------" read -e -p "請輸入你的選擇:" sub_choice case $sub_choice in @@ -11997,9 +12431,9 @@ moltbot_menu() { echo "4. 狀態日誌查看" echo "5. 換模型" echo "6. API管理" - echo "7. 机器人连接对接" + echo "7. 機器人連線對接" echo "8. 插件管理(安裝/刪除)" - echo "9. 技能管理(安裝/刪除)" + echo "9. 技能管理(安装/删除)" echo "10. 編輯主設定文件" echo "11. 配置精靈" echo "12. 健康檢測與修復" @@ -12093,7 +12527,7 @@ work = copy.deepcopy(obj) models_cfg = work.setdefault('models', {}) providers = models_cfg.get('providers', {}) if not isinstance(providers, dict) or not providers: - print('ℹ️ 未检测到 API providers,跳过模型同步') + print('ℹ️ 未偵測到 API providers,跳過模型同步') raise SystemExit(0) agents = work.setdefault('agents', {}) @@ -12200,7 +12634,7 @@ def rebind_defaults_before_delete(name): return False defaults[fk] = repl changed = True - summary.append(f'🔁 刪除前已切換 {fk}: {val} -> {repl}') + summary.append(f'🔁 删除前已切换 {fk}: {val} -> {repl}') return True @@ -12420,7 +12854,7 @@ PY start_bot() { - echo "啟動 OpenClaw..." + echo "启动 OpenClaw..." send_stats "啟動 OpenClaw..." start_gateway break_end @@ -12587,7 +13021,7 @@ EOF if [[ $? -eq 0 ]]; then echo "✅ 成功添加$model_count個模型到$provider_name" - echo "📦 模型引用格式:$provider_name/" + echo "📦 模型引用格式: $provider_name/" return 0 else echo "❌ 配置注入失敗" @@ -12626,7 +13060,7 @@ EOF send_stats "OpenClaw API添加" echo "=== 互動式新增 OpenClaw Provider (全量模型) ===" - # 1. Provider 名稱 + # 1. Provider 名称 read -erp "請輸入 Provider 名稱 (如: deepseek):" provider_name while [[ -z "$provider_name" ]]; do echo "❌ Provider 名稱不能為空" @@ -12650,7 +13084,7 @@ EOF echo done - # 4. 不再偵測/判斷 API 類型;協定由使用者自行選擇與維護 + # 4. 不再探测/判断 API 类型;协议由用户自行选择与维护 # 5. 取得模型列表 echo "🔍 正在取得可用模型清單..." @@ -12677,9 +13111,9 @@ EOF fi fi - # 5. 選擇預設模型 + # 5. 选择默认模型 echo - read -erp "請輸入預設 Model ID (或序號,留空則使用第一個):" input_model + read -erp "请输入默认 Model ID (或序号,留空则使用第一个): " input_model if [[ -z "$input_model" && -n "$available_models" ]]; then default_model=$(echo "$available_models" | head -1) @@ -12701,7 +13135,7 @@ EOF echo "模型總數 :$model_count" echo "======================" - read -erp "是否同时添加其他所有可用模型? (y/N):" confirm + read -erp "是否同時新增其他所有可用模型? (y/N):" confirm install jq if [[ "$confirm" =~ ^[Yy]$ ]]; then @@ -12716,7 +13150,7 @@ EOF if [[ $add_result -eq 0 ]]; then echo - echo "🔄 設定預設模型並重新啟動網關..." + echo "🔄 设置默认模型并重启网关..." openclaw models set "$provider_name/$default_model" openclaw_sync_sessions_model "$provider_name/$default_model" start_gateway @@ -12778,7 +13212,7 @@ def classify_latency(latency): if latency == '不可用': return '不可用', 'unavailable' if latency == '未檢測': - return '未檢測', 'unchecked' + return '未检测', 'unchecked' if isinstance(latency, int): if latency <= 800: level = 'low' @@ -13082,7 +13516,7 @@ PY2 echo "❌ 同步失敗:上游 /models 請求失敗" ;; 5) - echo "❌ 同步失败:上游模型为空或同步后无可用模型" + echo "❌ 同步失敗:上游模型為空或同步後無可用模型" ;; *) echo "❌ 同步失敗:請檢查設定檔結構或日誌輸出" @@ -13094,7 +13528,7 @@ PY2 openclaw_detect_api_protocol_by_provider() { # 協定探測邏輯已移除:腳本不再自動偵測/判定 API 類型。 - # 保留函数以兼容菜单调用,但不做任何改写。 + # 保留函數以相容選單調用,但不做任何改寫。 echo "ℹ️ 已關閉協議探測:請手動在${HOME}/.openclaw/openclaw.json 中設定 provider.api 為 openai-completions 或 openai-responses" return 0 } @@ -13389,7 +13823,7 @@ PY echo -e "${gl_kjlan}────────────────────────────────────────────────────────────${gl_bai}" echo -e " ${gl_zi}圖例:${gl_lv}● 官方入口${gl_bai} ${gl_huang}● AFF 推薦入口${gl_bai}" echo "" - echo -e "${gl_huang}提示:複製連結到瀏覽器開啟即可訪問${gl_bai}" + echo -e "${gl_huang}提示:复制链接到浏览器打开即可访问${gl_bai}" echo "" read -erp "按回車鍵返回..." dummy } @@ -13410,7 +13844,7 @@ PY echo "5. API 廠商推薦" echo "0. 退出" echo "---------------------------------------" - read -erp "請輸入你的選擇:" api_choice + read -erp "请输入你的选择: " api_choice case "$api_choice" in 1) @@ -13693,7 +14127,7 @@ PYTHON_EOF models_raw=$(jq -r '.agents.defaults.models | if type == "object" then keys[] else .[] end' "$oc_config" 2>/dev/null | sed '/^\s*$/d') if [ -z "$models_raw" ]; then - echo "取得模型清單失敗:設定檔中未找到 agents.defaults.models。" + echo "获取模型列表失败:配置文件中未找到 agents.defaults.models。" break_end return 1 fi @@ -13732,7 +14166,7 @@ PYTHON_EOF echo "正在切換模型為:$selected_model ..." if ! openclaw models set "$selected_model"; then - echo "切換失敗:openclaw models set 回傳錯誤。" + echo "切换失败:openclaw models set 返回错误。" break_end return 1 fi @@ -13776,7 +14210,7 @@ PYTHON_EOF echo "摘要:$OPENCLAW_PROBE_REPLY" echo "" - printf "是否切换到该模型?[y/N,Esc 返回列表]: " + printf "是否切換到該模型? [y/N,Esc 返回列表]:" IFS= read -rsn1 confirm_switch echo "" if [ "$confirm_switch" = $'' ]; then @@ -13793,7 +14227,7 @@ PYTHON_EOF fi if [ "$confirm_switch" != "yes" ]; then - echo "已返回模型選擇清單。" + echo "已返回模型选择列表。" sleep 1 continue fi @@ -13952,7 +14386,7 @@ data['plugins'] = plugins config_file.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding='utf-8') PYTHON_EOF then - echo "✅ 已同步 plugins.allow 白名單:$plugin_id" + echo "✅ 已同步 plugins.allow 白名单: $plugin_id" return 0 fi fi @@ -14045,7 +14479,7 @@ PYTHON_EOF echo "--------------------------------------------------------" echo "📱 通訊頻道:" echo "- [feishu] # 飛書/Lark 集成" - echo "- [telegram] # Telegram 機器人" + echo " - [telegram] # Telegram 机器人" echo "- [slack] # Slack 企業通訊" echo " - [msteams] # Microsoft Teams" echo "- [discord] # Discord 社群管理" @@ -14053,7 +14487,7 @@ PYTHON_EOF echo "" echo "🧠 記憶與 AI:" echo "- [memory-core] # 基礎記憶 (文件檢索)" - echo " - [memory-lancedb] # 增强记忆 (向量数据库)" + echo "- [memory-lancedb] # 增強記憶 (向量資料庫)" echo "- [copilot-proxy] # Copilot 介面轉發" echo "" echo "⚙️ 功能擴充:" @@ -14065,7 +14499,7 @@ PYTHON_EOF echo "1) 安裝/啟用插件" echo "2) 刪除/停用插件" echo "0) 返回" - read -e -p "請選擇操作:" plugin_action + read -e -p "请选择操作:" plugin_action [ "$plugin_action" = "0" ] && break [ -z "$plugin_action" ] && continue @@ -14105,7 +14539,7 @@ PYTHON_EOF fi if [ -d "/usr/lib/node_modules/openclaw/extensions/$plugin_id" ]; then - echo "💡 發現系統內建目錄存在該插件,嘗試直接啟用..." + echo "💡 发现系统内置目录存在该插件,尝试直接启用..." if openclaw plugins enable "$plugin_id"; then sync_openclaw_plugin_allowlist "$plugin_id" success_list="$success_list $plugin_id" @@ -14116,7 +14550,7 @@ PYTHON_EOF continue fi - echo "📥 本地未发现,尝试下载安装: $plugin_full" + echo "📥 本機未發現,嘗試下載安裝:$plugin_full" rm -rf "${HOME}/.openclaw/extensions/$plugin_id" [ "$HOME" != "/root" ] && rm -rf "/root/.openclaw/extensions/$plugin_id" if openclaw plugins install "$plugin_full"; then @@ -14136,7 +14570,7 @@ PYTHON_EOF echo "🗑️ 正在刪除/停用插件:$plugin_id" openclaw plugins disable "$plugin_id" >/dev/null 2>&1 if openclaw plugins uninstall "$plugin_id"; then - echo "✅ 已卸載:$plugin_id" + echo "✅ 已卸载: $plugin_id" else echo "⚠️ 卸載失敗,可能為預先安裝插件,僅停用:$plugin_id" fi @@ -14147,7 +14581,7 @@ PYTHON_EOF done echo "" - echo "====== 操作匯總 ======" + echo "====== 操作汇总 ======" echo "✅ 成功:$success_list" [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" @@ -14209,9 +14643,9 @@ PYTHON_EOF local token if [ "$skill_action" = "2" ]; then - read -e -p "二次确认:删除仅影响用户目录 ~/.openclaw/workspace/skills,确认继续? (y/N):" confirm_del + read -e -p "二次確認:刪除僅影響使用者目錄 ~/.openclaw/workspace/skills,確認繼續? (y/N):" confirm_del if [[ ! "$confirm_del" =~ ^[Yy]$ ]]; then - echo "已取消刪除。" + echo "已取消删除。" break_end continue fi @@ -14233,7 +14667,7 @@ PYTHON_EOF fi if [ "$skill_found" = true ]; then - read -e -p "技能 [$skill_name] 已安裝,是否重新安裝? (y/N):" reinstall + read -e -p "技能 [$skill_name] 已安装,是否重新安装?(y/N): " reinstall if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then skipped_list="$skipped_list $skill_name" continue @@ -14254,7 +14688,7 @@ PYTHON_EOF npx clawhub uninstall "$skill_name" --yes --no-input 2>/dev/null || npx clawhub uninstall "$skill_name" >/dev/null 2>&1 if [ -d "${HOME}/.openclaw/workspace/skills/${skill_name}" ]; then rm -rf "${HOME}/.openclaw/workspace/skills/${skill_name}" - echo "✅ 已刪除使用者技能目錄:$skill_name" + echo "✅ 已删除用户技能目录: $skill_name" success_list="$success_list $skill_name" changed=true else @@ -14268,7 +14702,7 @@ PYTHON_EOF echo "====== 操作匯總 ======" echo "✅ 成功:$success_list" [ -n "$failed_list" ] && echo "❌ 失敗:$failed_list" - [ -n "$skipped_list" ] && echo "⏭️ 跳過:$skipped_list" + [ -n "$skipped_list" ] && echo "⏭️ 跳过:$skipped_list" if [ "$changed" = true ]; then echo "🔄 正在重啟 OpenClaw 服務以載入變更..." @@ -14325,7 +14759,7 @@ openclaw_json_get_bool() { return 0 fi - # 相容於兩種常見目錄命名: + # 兼容两种常见目录命名: # - ~/.openclaw/extensions/qqbot # - ~/.openclaw/extensions/openclaw-qqbot # 避免無腦 substring,優先精確匹配與 openclaw- 前綴相符。 @@ -14341,7 +14775,7 @@ openclaw_json_get_bool() { local connected="$3" local abnormal="$4" if [ "$abnormal" = "true" ]; then - echo "例外" + echo "异常" elif [ "$enabled" != "true" ]; then echo "未啟用" elif [ "$connected" = "true" ]; then @@ -14507,19 +14941,19 @@ openclaw_json_get_bool() { while true; do clear echo "========================================" - echo "機器人連線對接" + echo " 机器人连接对接 " echo "========================================" openclaw_show_bot_local_status_block echo "----------------------------------------" echo "1. Telegram 機器人對接" - echo "2. 飞书 (Lark) 机器人对接" + echo "2. 飛書 (Lark) 機器人對接" echo "3. WhatsApp 機器人對接" echo "4. QQ 機器人對接" echo "5. 微信機器人對接" echo "----------------------------------------" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "----------------------------------------" - read -e -p "請輸入你的選擇:" bot_choice + read -e -p "请输入你的选择: " bot_choice case $bot_choice in 1) @@ -14655,8 +15089,8 @@ EOF echo "可使用以下方式下載備份檔:" echo "- 本地路徑:$file_path" - echo "- scp 範例: scp root@你的伺服器:$file_path ./" - echo "- 或使用 SFTP 用戶端下載" + echo "- scp 示例: scp root@你的服务器:$file_path ./" + echo "- 或使用 SFTP 客户端下载" } openclaw_prepare_import_archive() { @@ -14674,7 +15108,7 @@ EOF fi for required in backup.meta manifest.files manifest.sha256 payload; do - [ -e "$pkg_dir/$required" ] || { echo "❌ 備份包缺少必要檔:$required"; return 1; } + [ -e "$pkg_dir/$required" ] || { echo "❌ 备份包缺少必要文件: $required"; return 1; } done local real_type @@ -14747,7 +15181,7 @@ for item in workspaces: } openclaw_memory_backup_import() { - send_stats "OpenClaw記憶全量還原" + send_stats "OpenClaw记忆全量还原" local archive_path=$(openclaw_read_import_path "還原記憶全量 (支援多智能體)") [ -z "$archive_path" ] && { echo "❌ 未輸入路徑"; break_end; return 1; } local tmp_unpack=$(mktemp -d) || return 1 @@ -14765,7 +15199,7 @@ if os.path.isdir(agents_root): src = os.path.join(src_agent_dir, f); dest = os.path.join(dest_ws, f) if os.path.isfile(src): shutil.copy2(src, dest) else: shutil.copytree(src, dest, dirs_exist_ok=True) - print(f"✅ 已还原智能体记忆: {aid}")' "$workspaces_json" "$pkg_dir/payload" + print(f"✅ 已還原智能體記憶: {aid}")' "$workspaces_json" "$pkg_dir/payload" rm -rf "$tmp_unpack"; echo "✅ 記憶全量還原完成"; break_end } @@ -14777,13 +15211,13 @@ if os.path.isdir(agents_root): local openclaw_root openclaw_root=$(dirname "$config_file") if [ ! -d "$openclaw_root" ]; then - echo "❌ 未找到 OpenClaw 根目錄:$openclaw_root" + echo "❌ 未找到 OpenClaw 根目录: $openclaw_root" break_end return 1 fi echo "備份模式:" - echo "1. 安全模式(默認,建議):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" + echo "1. 安全模式(默认,推荐):workspace + openclaw.json + extensions/skills/prompts/tools(如存在)" echo "2. 完整模式(含更多狀態,敏感風險較高)" read -e -p "請選擇備份模式(預設 1):" export_mode [ -z "$export_mode" ] && export_mode="1" @@ -14825,7 +15259,7 @@ if os.path.isdir(agents_root): echo "✅ OpenClaw 專案備份完成 (${mode_label}): $out_file" openclaw_offer_transfer_hint "$out_file" else - echo "❌ OpenClaw 项目备份失败" + echo "❌ OpenClaw 專案備份失敗" fi rm -rf "$tmp_payload" @@ -14844,13 +15278,13 @@ if os.path.isdir(agents_root): echo "⚠️ 還原前將執行 manifest/sha256 校驗、白名單恢復、gateway 停啟與健康檢查。" read -e -p "請輸入確認詞【我已知高風險並繼續還原】後繼續:" confirm_text if [ "$confirm_text" != "我已知高風險並持續還原" ]; then - echo "❌ 確認詞不匹配,已取消還原" + echo "❌ 确认词不匹配,已取消还原" break_end return 1 fi local archive_path - archive_path=$(openclaw_read_import_path "请输入 OpenClaw 项目备份包路径") + archive_path=$(openclaw_read_import_path "請輸入 OpenClaw 專案備份包路徑") [ -z "$archive_path" ] && { echo "❌ 未輸入備份路徑"; break_end; return 1; } local tmp_unpack @@ -14894,7 +15328,7 @@ if os.path.isdir(agents_root): echo "▶️ 還原後啟動 OpenClaw gateway..." openclaw gateway start >/dev/null 2>&1 sleep 2 - echo "🩺 gateway 健康检查:" + echo "🩺 gateway 健康檢查:" openclaw gateway status || true fi @@ -14949,7 +15383,7 @@ if os.path.isdir(agents_root): for i in "${!OPENCLAW_BACKUP_FILES[@]}"; do file_name="${OPENCLAW_BACKUP_FILES[$i]}" file_type=$(openclaw_backup_detect_type "$file_name") - [ "$file_type" != "記憶備份文件" ] && continue + [ "$file_type" != "记忆备份文件" ] && continue file_path="$backup_root/$file_name" file_size=$(ls -lh "$file_path" | awk '{print $5}') file_time=$(date -d "$(stat -c %y "$file_path")" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c %y "$file_path" | awk '{print $1" "$2}') @@ -15011,7 +15445,7 @@ if os.path.isdir(agents_root): return 0 fi if [ -z "$user_input" ]; then - echo "❌ 輸入不能為空。" + echo "❌ 输入不能为空。" break_end return 1 fi @@ -15542,7 +15976,7 @@ PY export PATH="$HOME/.bun/bin:$PATH" fi if command -v bun >/dev/null 2>&1; then - echo "✅ bun 安裝完成" + echo "✅ bun 安装完成" return 0 fi echo "❌ bun 安裝失敗" @@ -15629,9 +16063,9 @@ PY else echo "可能流量/磁碟佔用: 視實際情況而定" fi - echo "确认后将自动安装/下载、写入配置、构建索引并重启网关" + echo "確認後將自動安裝/下載、寫入設定、建置索引並重新啟動網關" echo "進階選項: 輸入 config 僅寫入設定(不安裝不下載、不索引、不重新啟動)" - read -e -p "输入 yes 确认继续(默认 N): " confirm_step + read -e -p "輸入 yes 確認繼續(預設 N):" confirm_step case "$confirm_step" in yes|YES) OPENCLAW_MEMORY_PREHEAT="true" @@ -15672,7 +16106,7 @@ PY echo "✅ memory.backend 已是 qmd" else openclaw_memory_config_set "memory.backend" "qmd" - echo "✅ 已设置 memory.backend=qmd" + echo "✅ 已設定 memory.backend=qmd" fi local qmd_cmd qmd_cmd=$(openclaw_memory_config_get "memory.qmd.command") @@ -15875,7 +16309,7 @@ EOF echo "❌ 未知方案:$scheme" return 1 esac - echo "✅ 已更新记忆方案配置" + echo "✅ 已更新記憶方案配置" return 0 } @@ -15928,7 +16362,7 @@ EOF echo "includeDefaultMemory 配置正常。" echo "將執行:清理舊索引 → 全量重建所有智能體索引" echo "" - read -e -p "確認執行? (Y/n):" confirm_fix + read -e -p "确认执行?(Y/n): " confirm_fix if [[ ! "$confirm_fix" =~ ^[Nn]$ ]]; then openclaw_memory_rebuild_index_all else @@ -15953,7 +16387,7 @@ EOF esac echo "當前方案:$current_label" echo "" - echo "QMD : 轻量索引,依赖 qmd 命令(适合网络受限)" + echo "QMD : 輕量索引,依賴 qmd 指令(適合網路受限)" echo "Local: 本機向量檢索,依賴 embedding 模型文件" echo "Auto : 自動推薦(基於可用性 + 網路探測)" echo "---------------------------------------" @@ -16016,7 +16450,7 @@ EOF openclaw_memory_file_render_list() { openclaw_memory_file_collect if [ ${#OPENCLAW_MEMORY_FILES[@]} -eq 0 ]; then - echo "未找到記憶文件。" + echo "未找到记忆文件。" return 0 fi echo "編號 | 歸屬 | 大小 | 修改時間" @@ -16041,7 +16475,7 @@ EOF total_lines=$(wc -l < "$file" 2>/dev/null || echo 0) local default_lines=120 local start_line count - echo "文件:$file" + echo "文件: $file" echo "總行數:$total_lines" read -e -p "請輸入起始行(回車預設末尾$default_lines行):" start_line read -e -p "請輸入顯示行數(回車預設$default_lines): " count @@ -16081,7 +16515,7 @@ EOF while true; do clear echo "=======================================" - echo "OpenClaw 記憶文件" + echo "OpenClaw 记忆文件" echo "=======================================" openclaw_memory_file_render_list echo "---------------------------------------" @@ -16156,7 +16590,7 @@ EOF read -e -p "二次確認:輸入 force 使用全量(留空為增量):" confirm_step2 if [ "$confirm_step2" = "force" ]; then echo "⚠️ 全量重建更徹底,但耗時更長。" - echo "建議:輸入 rebuild 進行安全重建(先備份索引庫)。" + echo "推荐:输入 rebuild 进行安全重建(先备份索引库)。" read -e -p "第三次確認:輸入 rebuild 執行安全重建;直接回車繼續普通 force:" confirm_step3 if [ "$confirm_step3" = "rebuild" ]; then openclaw_memory_rebuild_index_all @@ -16170,7 +16604,7 @@ EOF $fl_agent_lines EOF openclaw gateway restart - echo "✅ 已对所有智能体执行 force 重建并自动重启网关" + echo "✅ 已對所有智慧型體執行 force 重建並自動重新啟動網關" fi else openclaw memory index @@ -16228,7 +16662,7 @@ EOF config_file=$(openclaw_permission_config_file) backup_file=$(openclaw_permission_backup_file) if [ ! -s "$config_file" ]; then - echo "⚠️ 未找到 OpenClaw 設定文件,跳過權限備份。" + echo "⚠️ 未找到 OpenClaw 配置文件,跳过权限备份。" return 1 fi mkdir -p "$(dirname "$backup_file")" @@ -16236,7 +16670,7 @@ EOF echo "⚠️ 權限備份失敗:$backup_file" return 1 } - echo "✅ 已备份当前权限配置: $backup_file" + echo "✅ 已備份目前權限配置:$backup_file" return 0 } @@ -16480,7 +16914,7 @@ try: print("自動放行技能 (autoAllowSkills):" + ("on" if auto else "off")) exists = d.get("exists", True) if not exists: - print(" (审批文件不存在,使用系统内置安全兜底)") + print("(審核文件不存在,使用系統內建安全兜底)") except Exception as e: print("(解析失敗:" + str(e) + ")") ' "$approvals_json" @@ -16546,7 +16980,7 @@ except Exception: send_stats "OpenClaw權限-完全開放模式" openclaw_permission_require_openclaw || return 1 - echo "正在設定應用層策略..." + echo "正在配置应用层策略..." openclaw config set tools.profile full >/dev/null 2>&1 openclaw config set tools.exec.security full >/dev/null 2>&1 openclaw config set tools.exec.ask off >/dev/null 2>&1 @@ -16558,7 +16992,7 @@ except Exception: openclaw_permission_update_exec_approvals "full" "off" "full" openclaw_permission_restart_gateway - echo -e "${gl_lv}✅ 已切换为完全开放模式 (警告:所有宿主机命令拦截已失效,智能体具有最高权限)${gl_bai}" + echo -e "${gl_lv}✅ 已切換為完全開放模式 (警告:所有宿主機指令攔截已失效,智能體具有最高權限)${gl_bai}" } openclaw_permission_restore_official_defaults() { @@ -16586,7 +17020,7 @@ except Exception: openclaw_permission_run_audit() { echo "=======================================" - echo "運行 OpenClaw 官方安全審計與體檢..." + echo "运行 OpenClaw 官方安全审计与体检..." echo "=======================================" openclaw security audit echo "---------------------------------------" @@ -16595,7 +17029,7 @@ except Exception: openclaw security audit --fix echo -e "${gl_lv}✅ 自動修復完成。${gl_bai}" fi - echo "按任意鍵返回..." + echo "按任意键返回..." read -n 1 -s } @@ -16621,7 +17055,7 @@ try: al = agent_data.get("allowlist", []) if al: found = True - print(" 智能体 [%s]:" % agent_id) + print("智能體 [%s]:" % agent_id) for item in al: print(" - %s" % item) if not found: @@ -16634,7 +17068,7 @@ except Exception as e: fi echo "---------------------------------------" echo "1. 新增白名單規則" - echo "2. 移除白名單規則" + echo "2. 移除白名单规则" echo "0. 返回" echo "---------------------------------------" read -e -p "請選擇:" al_choice @@ -16697,7 +17131,7 @@ except Exception as e: break_end ;; 4) - echo "将清除所有定制覆盖,恢复 OpenClaw 刚安装时的严格沙盒状态。" + echo "將清除所有自訂覆蓋,恢復 OpenClaw 剛安裝時的嚴格沙盒狀態。" read -e -p "輸入 yes 確認:" confirm if [ "$confirm" = "yes" ]; then openclaw_permission_restore_official_defaults; else echo "已取消"; fi break_end @@ -16896,7 +17330,7 @@ PY local config_file default_agent config_file=$(openclaw_multiagent_config_file) default_agent=$(openclaw_multiagent_default_agent) - echo "設定檔: ${config_file:-$(openclaw_permission_config_file)}" + echo "配置文件: ${config_file:-$(openclaw_permission_config_file)}" echo "預設智能體:$default_agent" python3 -c ' import json,sys @@ -16958,7 +17392,7 @@ for idx,item in enumerate(agents,1): echo "正在配置智能體身份..." openclaw agents set-identity --agent "$agent_id" --name "$name" --theme "$theme" else - echo "❌ 智能體創建失敗" + echo "❌ 智能體建立失敗" return 1 fi } @@ -17118,7 +17552,7 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_cleanup_sessions() { openclaw_multiagent_require_openclaw || return 1 - echo "即将清理过期/冗余会话数据..." + echo "即將清理過期/冗餘會話資料..." read -e -p "輸入 yes 確認:" confirm [ "$confirm" != "yes" ] && { echo "已取消"; return 0; } openclaw sessions cleanup @@ -17134,14 +17568,14 @@ print("✅ 多智能體健康檢查完成") openclaw_multiagent_render_status echo "---------------------------------------" echo "1. 新增智能體" - echo "2. 刪除智能體" + echo "2. 删除智能体" echo "3. 查看路由綁定" echo "4. 新增路由綁定" echo "5. 移除路由綁定" echo "6. 查看會話概況" echo "7. 執行多智能體健康檢查" echo "8. 修改智能體身分(名稱/Emoji)" - echo "9. 清理過期會話" + echo "9. 清理过期会话" echo "0. 返回上一級" echo "---------------------------------------" read -e -p "請輸入你的選擇:" multi_choice @@ -17276,7 +17710,7 @@ openclaw_backup_restore_menu() { domains=$(openclaw_find_webui_domain) if [ -n "$domains" ]; then - echo "網域名稱地址:" + echo "網域地址:" echo "$domains" | while read d; do echo "https://${d}/#token=${token}" done @@ -17312,7 +17746,7 @@ openclaw_backup_restore_menu() { if command -v jq >/dev/null 2>&1; then tmp_json=$(mktemp) jq 'if .gateway.controlUi == null then .gateway.controlUi = {"allowedOrigins": ["http://127.0.0.1"]} else . end | if (.gateway.controlUi.allowedOrigins | contains([$origin]) | not) then .gateway.controlUi.allowedOrigins += [$origin] else . end' --arg origin "$new_origin" "$config_file" > "$tmp_json" && mv "$tmp_json" "$config_file" - echo -e "${gl_kjlan}已將域名${yuming}加入 allowedOrigins 配置${gl_bai}" + echo -e "${gl_kjlan}已将域名 ${yuming} 加入 allowedOrigins 配置${gl_bai}" openclaw gateway restart >/dev/null 2>&1 fi fi @@ -17336,7 +17770,7 @@ openclaw_backup_restore_menu() { web_del } - # 主選單 + # 主菜单 openclaw_webui_menu() { send_stats "WebUI存取與設定" @@ -17388,7 +17822,7 @@ openclaw_backup_restore_menu() { 8) install_plugin ;; 9) install_skill ;; 10) nano_openclaw_json ;; - 11) send_stats "初始化配置精靈" + 11) send_stats "初始化配置向导" openclaw onboard --install-daemon break_end ;; @@ -17422,7 +17856,7 @@ refresh_apps_catalog() { install git || return 1 if [ -e "$apps_dir" ] && [ ! -d "$apps_dir/.git" ]; then - echo -e "${gl_hong}錯誤:${gl_bai}${apps_dir}已存在但不是應用市場 Git 倉庫,拒絕覆蓋。" + echo -e "${gl_hong}錯誤:${gl_bai}${apps_dir} 已存在但不是应用市场 Git 仓库,拒绝覆盖。" return 1 fi if [ ! -d "$apps_dir/.git" ]; then @@ -17470,7 +17904,7 @@ while true; do echo -e "${gl_kjlan}3. ${color3}1Panel新一代管理面板${gl_kjlan}4. ${color4}NginxProxyManager視覺化面板" echo -e "${gl_kjlan}5. ${color5}OpenList多重儲存文件列表程序${gl_kjlan}6. ${color6}Ubuntu遠端桌面網頁版" echo -e "${gl_kjlan}7. ${color7}哪吒探針VPS監控面板${gl_kjlan}8. ${color8}QB離線BT磁力下載面板" - echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人在线聊天系统" + echo -e "${gl_kjlan}9. ${color9}Poste.io郵件伺服器程式${gl_kjlan}10. ${color10}RocketChat多人線上聊天系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}11. ${color11}禪道專案管理軟體${gl_kjlan}12. ${color12}青龍面板定時任務管理平台" echo -e "${gl_kjlan}13. ${color13}Cloudreve網盤${gl_huang}★${gl_bai} ${gl_kjlan}14. ${color14}簡單圖床圖片管理程序" @@ -17481,20 +17915,20 @@ while true; do echo -e "${gl_kjlan}21. ${color21}VScode網頁版${gl_kjlan}22. ${color22}UptimeKuma監控工具" echo -e "${gl_kjlan}23. ${color23}Memos網頁備忘錄${gl_kjlan}24. ${color24}Webtop遠端桌面網頁版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}25. ${color25}Nextcloud網站${gl_kjlan}26. ${color26}QD-Today定時任務管理框架" - echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed測速工具" - echo -e "${gl_kjlan}29. ${color29}searxng聚合搜尋站${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相簿系統" + echo -e "${gl_kjlan}27. ${color27}Dockge容器堆疊管理面板${gl_kjlan}28. ${color28}LibreSpeed测速工具" + echo -e "${gl_kjlan}29. ${color29}searxng聚合搜索站 ${gl_huang}★${gl_bai} ${gl_kjlan}30. ${color30}PhotoPrism私有相簿系統" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}31. ${color31}StirlingPDF工具大全${gl_kjlan}32. ${color32}drawio免費的線上圖表軟體${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}33. ${color33}Sun-Panel導航面板${gl_kjlan}34. ${color34}Pingvin-Share文件分享平台" - echo -e "${gl_kjlan}35. ${color35}極簡朋友圈${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" - echo -e "${gl_kjlan}37. ${color37}MyIP工具箱${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" + echo -e "${gl_kjlan}35. ${color35}极简朋友圈 ${gl_kjlan}36. ${color36}LobeChatAI聊天聚合網站" + echo -e "${gl_kjlan}37. ${color37}MyIP工具箱 ${gl_huang}★${gl_bai} ${gl_kjlan}38. ${color38}小雅alist全家桶" echo -e "${gl_kjlan}39. ${color39}Bililive直播錄影工具${gl_kjlan}40. ${color40}webssh網頁版SSH連線工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}41. ${color41}耗子管理面板 ${gl_kjlan}42. ${color42}Nexterm遠端連線工具" + echo -e "${gl_kjlan}41. ${color41}耗子管理面板${gl_kjlan}42. ${color42}Nexterm遠端連線工具" echo -e "${gl_kjlan}43. ${color43}RustDesk遠端桌面(服務端)${gl_huang}★${gl_bai} ${gl_kjlan}44. ${color44}RustDesk遠端桌面(中繼端)${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}45. ${color45}Docker加速站${gl_kjlan}46. ${color46}GitHub加速站${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}47. ${color47}普羅米修斯監控${gl_kjlan}48. ${color48}普羅米修斯(主機監控)" - echo -e "${gl_kjlan}49. ${color49}普羅米修斯(容器監控)${gl_kjlan}50. ${color50}補貨監控工具" + echo -e "${gl_kjlan}49. ${color49}普罗米修斯(容器监控) ${gl_kjlan}50. ${color50}補貨監控工具" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}51. ${color51}PVE開小雞面板${gl_kjlan}52. ${color52}DPanel容器管理面板" echo -e "${gl_kjlan}53. ${color53}llama3聊天AI大模型${gl_kjlan}54. ${color54}AMH主機建站管理面板" @@ -17505,35 +17939,35 @@ while true; do echo -e "${gl_kjlan}61. ${color61}線上翻譯伺服器${gl_kjlan}62. ${color62}RAGFlow大模型知識庫" echo -e "${gl_kjlan}63. ${color63}OpenWebUI自架AI平台${gl_huang}★${gl_bai} ${gl_kjlan}64. ${color64}it-tools工具箱" echo -e "${gl_kjlan}65. ${color65}n8n自動化工作流程平台${gl_huang}★${gl_bai} ${gl_kjlan}66. ${color66}yt-dlp影片下載工具" - echo -e "${gl_kjlan}67. ${color67}ddns-go动态DNS管理工具 ${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" + echo -e "${gl_kjlan}67. ${color67}ddns-go動態DNS管理工具${gl_huang}★${gl_bai} ${gl_kjlan}68. ${color68}AllinSSL憑證管理平台" echo -e "${gl_kjlan}69. ${color69}SFTPGo檔案傳輸工具${gl_kjlan}70. ${color70}AstrBot聊天機器人框架" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}71. ${color71}Navidrome私有音樂伺服器${gl_kjlan}72. ${color72}bitwarden密碼管理器${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}73. ${color73}LibreTV私有影視${gl_kjlan}74. ${color74}MoonTV私有影視" - echo -e "${gl_kjlan}75. ${color75}Melody音樂精靈${gl_kjlan}76. ${color76}線上DOS老遊戲" + echo -e "${gl_kjlan}75. ${color75}Melody音乐精灵 ${gl_kjlan}76. ${color76}線上DOS老遊戲" echo -e "${gl_kjlan}77. ${color77}迅雷離線下載工具${gl_kjlan}78. ${color78}PandaWiki智慧文件管理系統" echo -e "${gl_kjlan}79. ${color79}Beszel伺服器監控${gl_kjlan}80. ${color80}linkwarden書籤管理" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}81. ${color81}JitsiMeet視訊會議${gl_kjlan}82. ${color82}gpt-load高性能AI透明代理" echo -e "${gl_kjlan}83. ${color83}komari伺服器監控工具${gl_kjlan}84. ${color84}Wallos個人財務管理工具" - echo -e "${gl_kjlan}85. ${color85}immich圖片影片管理器${gl_kjlan}86. ${color86}jellyfin媒體管理系統" + echo -e "${gl_kjlan}85. ${color85}immich图片视频管理器 ${gl_kjlan}86. ${color86}jellyfin媒體管理系統" echo -e "${gl_kjlan}87. ${color87}SyncTV一起看片神器${gl_kjlan}88. ${color88}Owncast自架直播平台" echo -e "${gl_kjlan}89. ${color89}FileCodeBox檔案快遞${gl_kjlan}90. ${color90}matrix去中心化聊天協議" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}91. ${color91}gitea私有程式碼倉庫${gl_kjlan}92. ${color92}FileBrowser文件管理器" + echo -e "${gl_kjlan}91. ${color91}gitea私有代码仓库 ${gl_kjlan}92. ${color92}FileBrowser文件管理器" echo -e "${gl_kjlan}93. ${color93}Dufs極簡靜態檔案伺服器${gl_kjlan}94. ${color94}Gopeed高速下載工具" - echo -e "${gl_kjlan}95. ${color95}paperless文件管理平台${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" + echo -e "${gl_kjlan}95. ${color95}paperless文档管理平台 ${gl_kjlan}96. ${color96}2FAuth自架二步驟驗證器" echo -e "${gl_kjlan}97. ${color97}WireGuard組網(服務端)${gl_kjlan}98. ${color98}WireGuard組網(客戶端)" - echo -e "${gl_kjlan}99. ${color99}DSM群暉虛擬機${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" + echo -e "${gl_kjlan}99. ${color99}DSM群晖虚拟机 ${gl_kjlan}100. ${color100}Syncthing點對點檔案同步工具" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}101. ${color101}AI影片生成工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" + echo -e "${gl_kjlan}101. ${color101}AI影片產生工具${gl_kjlan}102. ${color102}VoceChat多人線上聊天系統" echo -e "${gl_kjlan}103. ${color103}Umami網站統計工具${gl_kjlan}104. ${color104}Stream四層代理轉送工具" echo -e "${gl_kjlan}105. ${color105}思源筆記${gl_kjlan}106. ${color106}Drawnix開源白板工具" echo -e "${gl_kjlan}107. ${color107}PanSou網盤搜尋${gl_kjlan}108. ${color108}LangBot聊天機器人" echo -e "${gl_kjlan}109. ${color109}ZFile線上網路磁碟${gl_kjlan}110. ${color110}Karakeep書籤管理" echo -e "${gl_kjlan}-------------------------" - echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大內網穿透工具" - echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}111. ${color111}多格式檔案轉換工具${gl_kjlan}112. ${color112}Lucky大内网穿透工具" + echo -e "${gl_kjlan}113. ${color113}Firefox瀏覽器${gl_kjlan}114. ${color114}OpenClaw機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}115. ${color115}Hermes機器人管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方應用程式列表" @@ -17759,7 +18193,7 @@ while true; do check_docker_app check_docker_image_update $docker_name clear - echo -e "哪吒監控$check_docker $update_status" + echo -e "哪吒监控 $check_docker $update_status" echo "開源、輕量、易用的伺服器監控與維運工具" echo "官網搭建文件: https://nezha.wiki/guide/dashboard.html" if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "$docker_name"; then @@ -17840,7 +18274,7 @@ while true; do clear echo -e "郵局服務$check_docker $update_status" - echo "poste.io 是一個開源的郵件伺服器解決方案," + echo "poste.io 是一个开源的邮件服务器解决方案," echo "影片介紹: https://www.bilibili.com/video/BV1wv421C71t?t=0.1" echo "" @@ -17905,7 +18339,7 @@ while true; do add_app_id clear - echo "poste.io已经安装完成" + echo "poste.io已經安裝完成" echo "------------------------" echo "您可以使用以下地址存取poste.io:" echo "https://$yuming" @@ -17987,7 +18421,7 @@ while true; do docker run --name rocketchat --restart=always -p ${docker_port}:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/rs5 -d rocket.chat clear ip_address - echo "rocket.chat已經安裝完成" + echo "rocket.chat已经安装完成" check_docker_app_ip } @@ -17997,7 +18431,7 @@ while true; do docker rm -f db docker rmi -f mongo:latest rm -rf /home/docker/mongo - echo "應用程式已解除安裝" + echo "应用已卸载" } docker_app_plus @@ -18029,7 +18463,7 @@ while true; do local docker_describe="禪道是通用的專案管理軟體" local docker_url="官網介紹: https://www.zentao.net/" - local docker_use="echo \"初始使用者名稱: admin\"" + local docker_use="echo \"初始用户名: admin\"" local docker_passwd="echo \"初始密碼: 123456\"" local app_size="2" docker_app @@ -18057,7 +18491,7 @@ while true; do } local docker_describe="青龍面板是一個定時任務管理平台" - local docker_url="官網介紹:${gh_proxy}github.com/whyour/qinglong" + local docker_url="官网介绍: ${gh_proxy}github.com/whyour/qinglong" local docker_use="" local docker_passwd="" local app_size="1" @@ -18069,7 +18503,7 @@ while true; do local app_id="13" local app_name="cloudreve網盤" local app_text="cloudreve是一個支援多家雲端儲存的網盤系統" - local app_url="影片介紹: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" + local app_url="视频介绍: https://www.bilibili.com/video/BV13F4m1c7h7?t=0.1" local docker_name="cloudreve" local docker_port="5212" local app_size="2" @@ -18271,7 +18705,7 @@ while true; do add_app_id clear - echo "雷池WAF面板已經安裝完成" + echo "雷池WAF面板已经安装完成" check_docker_app_ip docker exec safeline-mgt resetadmin @@ -18327,7 +18761,7 @@ while true; do } - local docker_describe="portainer是一个轻量级的docker容器管理面板" + local docker_describe="portainer是一個輕量級的docker容器管理面板" local docker_url="官網介紹: https://www.portainer.io/" local docker_use="" local docker_passwd="" @@ -18398,7 +18832,7 @@ while true; do } - local docker_describe="Memos是一款輕量、自架的備忘錄中心" + local docker_describe="Memos是一款轻量级、自托管的备忘录中心" local docker_url="官網介紹:${gh_proxy}github.com/usememos/memos" local docker_use="" local docker_passwd="" @@ -18439,7 +18873,7 @@ while true; do } - local docker_describe="webtop基於Alpine的中文版容器。若IP無法訪問,請新增網域訪問。" + local docker_describe="webtop基于Alpine的中文版容器。若IP无法访问,请添加域名访问。" local docker_url="官網介紹: https://docs.linuxserver.io/images/docker-webtop/" local docker_use="" local docker_passwd="" @@ -18460,8 +18894,8 @@ while true; do } - local docker_describe="Nextcloud拥有超过 400,000 个部署,是您可以下载的最受欢迎的本地内容协作平台" - local docker_url="官网介绍: https://nextcloud.com/" + local docker_describe="Nextcloud擁有超過 400,000 個部署,是您可以下載的最受歡迎的本地內容協作平台" + local docker_url="官網介紹: https://nextcloud.com/" local docker_use="echo \"帳號: nextcloud 密碼:$rootpasswd\"" local docker_passwd="" local app_size="3" @@ -18545,7 +18979,7 @@ while true; do } - local docker_describe="searxng是一个私有且隐私的搜索引擎站点" + local docker_describe="searxng是一個私有且隱私的搜尋引擎站點" local docker_url="官網介紹: https://hub.docker.com/r/alandoyle/searxng" local docker_use="" local docker_passwd="" @@ -18626,7 +19060,7 @@ while true; do } - local docker_describe="這是一個強大圖表繪製軟體。心智圖,拓樸圖,流程圖,都能畫" + local docker_describe="这是一个强大图表绘制软件。思维导图,拓扑图,流程图,都能画" local docker_url="官網介紹: https://www.drawio.com/" local docker_use="" local docker_passwd="" @@ -18676,7 +19110,7 @@ while true; do } local docker_describe="Pingvin Share 是一個可自建的文件分享平台,是 WeTransfer 的替代品" - local docker_url="官網介紹:${gh_proxy}github.com/stonith404/pingvin-share" + local docker_url="官网介绍: ${gh_proxy}github.com/stonith404/pingvin-share" local docker_use="" local docker_passwd="" local app_size="1" @@ -18704,7 +19138,7 @@ while true; do local docker_describe="極簡朋友圈,高仿微信朋友圈,記錄你的美好生活" local docker_url="官網介紹:${gh_proxy}github.com/kingwrcy/moments?tab=readme-ov-file" - local docker_use="echo \"帳號: admin 密碼: a123456\"" + local docker_use="echo \"账号: admin 密码: a123456\"" local docker_passwd="" local app_size="1" docker_app @@ -18798,7 +19232,7 @@ while true; do docker run -d -p ${docker_port}:5032 --restart=always --name webssh -e TZ=Asia/Shanghai jrohy/webssh } - local docker_describe="簡易線上ssh連線工具和sftp工具" + local docker_describe="简易在线ssh连接工具和sftp工具" local docker_url="官網介紹:${gh_proxy}github.com/Jrohy/webssh" local docker_use="" local docker_passwd="" @@ -18811,7 +19245,7 @@ while true; do local app_id="41" local lujing="[ -d "/www/server/panel" ]" local panelname="AcePanel 原耗子麵板" - local panelurl="官方地址:${gh_proxy}github.com/acepanel/panel" + local panelurl="官方地址: ${gh_proxy}github.com/acepanel/panel" panel_app_install() { cd ~ @@ -18963,7 +19397,7 @@ while true; do ip_address echo "已經安裝完成" check_docker_app_ip - echo "初始使用者名稱密碼均為: admin" + echo "初始使用者名稱密碼皆為: admin" } docker_app_update() { @@ -19193,7 +19627,7 @@ while true; do docker compose up -d clear - echo "已經安裝完成" + echo "已经安装完成" check_docker_app_ip } @@ -19284,7 +19718,7 @@ while true; do echo "已經安裝完成" check_docker_app_ip echo "初始使用者名稱: admin" - echo "初始密碼: ChangeMe" + echo "初始密码: ChangeMe" } @@ -19335,7 +19769,7 @@ while true; do 62|ragflow) local app_id="62" - local app_name="RAGFlow知識庫" + local app_name="RAGFlow知识库" local app_text="基於深度文件理解的開源 RAG(檢索增強生成)引擎" local app_url="官方網站:${gh_https_url}github.com/infiniflow/ragflow" local docker_name="ragflow-server" @@ -19403,7 +19837,7 @@ while true; do } local docker_describe="對開發人員和 IT 工作者來說非常有用的工具" - local docker_url="官網介紹:${gh_https_url}github.com/CorentinTh/it-tools" + local docker_url="官网介绍: ${gh_https_url}github.com/CorentinTh/it-tools" local docker_use="" local docker_passwd="" local app_size="1" @@ -19467,7 +19901,7 @@ while true; do } - local docker_describe="自動將你的公網 IP(IPv4/IPv6)即時更新到各大 DNS 服務商,實現動態網域解析。" + local docker_describe="自动将你的公网 IP(IPv4/IPv6)实时更新到各大 DNS 服务商,实现动态域名解析。" local docker_url="官網介紹:${gh_https_url}github.com/jeessy2/ddns-go" local docker_use="" local docker_passwd="" @@ -19578,8 +20012,8 @@ while true; do } - local docker_describe="是一个轻量、高性能的音乐流媒体服务器" - local docker_url="官网介绍: https://www.navidrome.org/" + local docker_describe="是一個輕量、高效能的音樂串流伺服器" + local docker_url="官網介紹: https://www.navidrome.org/" local docker_use="" local docker_passwd="" local app_size="1" @@ -19606,7 +20040,7 @@ while true; do } local docker_describe="一個你可以控制資料的密碼管理器" - local docker_url="官網導論: https://bitwarden.com/" + local docker_url="官网介绍: https://bitwarden.com/" local docker_use="" local docker_passwd="" local app_size="1" @@ -19782,7 +20216,7 @@ while true; do } local docker_describe="迅雷你的離線高速BT磁力下載工具" - local docker_url="官網介紹:${gh_https_url}github.com/cnk3x/xunlei" + local docker_url="官网介绍: ${gh_https_url}github.com/cnk3x/xunlei" local docker_use="echo \"手機登入迅雷,再輸入邀請碼,邀請碼: 迅雷牛通\"" local docker_passwd="" local app_size="1" @@ -19839,7 +20273,7 @@ while true; do } - local docker_describe="Beszel輕易易用的伺服器監控" + local docker_describe="Beszel轻量易用的服务器监控" local docker_url="官網介紹: https://beszel.dev/zh/" local docker_use="" local docker_passwd="" @@ -19852,9 +20286,9 @@ while true; do 80|linkwarden) local app_id="80" - local app_name="linkwarden書籤管理" + local app_name="linkwarden书签管理" local app_text="一個開源的自架書籤管理平台,支援標籤、搜尋和團隊協作。" - local app_url="官方網站: https://linkwarden.app/" + local app_url="官方网站: https://linkwarden.app/" local docker_name="linkwarden-linkwarden-1" local docker_port="8080" local app_size="3" @@ -19995,7 +20429,7 @@ while true; do docker_rum() { - read -e -p "設定${docker_name}的登录密钥(sk-开头字母和数字组合)如: sk-159kejilionyyds163: " app_passwd + read -e -p "設定${docker_name}的登入密鑰(sk-開頭字母和數字組合)如: sk-159kejilionyyds163:" app_passwd mkdir -p /home/docker/gpt-load && \ docker run -d --name gpt-load \ @@ -20305,7 +20739,7 @@ while true; do local app_id="91" local app_name="gitea私有程式碼倉庫" - local app_text="免费新一代的代码托管平台,提供接近 GitHub 的使用体验。" + local app_text="免費新一代的程式碼託管平台,提供接近 GitHub 的使用體驗。" local app_url="影片介紹:${gh_https_url}github.com/go-gitea/gitea" local docker_name="gitea" local docker_port="8091" @@ -20368,7 +20802,7 @@ while true; do } - local docker_describe="是一个基于Web的文件管理器" + local docker_describe="是一個基於Web的文件管理器" local docker_url="官網介紹: https://filebrowser.org/" local docker_use="docker logs filebrowser" local docker_passwd="" @@ -20395,7 +20829,7 @@ while true; do } - local docker_describe="極簡靜態檔案伺服器,支援上傳下載" + local docker_describe="极简静态文件服务器,支持上传下载" local docker_url="官網介紹:${gh_https_url}github.com/sigoden/dufs" local docker_use="" local docker_passwd="" @@ -20414,7 +20848,7 @@ while true; do docker_rum() { read -e -p "設定登入用戶名:" app_use - read -e -p "設定登入密碼:" app_passwd + read -e -p "设置登录密码: " app_passwd docker run -d \ --name ${docker_name} \ @@ -20804,7 +21238,7 @@ while true; do 101|moneyprinterturbo) local app_id="101" - local app_name="AI影片生成工具" + local app_name="AI影片產生工具" local app_text="MoneyPrinterTurbo是一款使用AI大模型合成高清短影片的工具" local app_url="官方網站:${gh_https_url}github.com/harry0703/MoneyPrinterTurbo" local docker_name="moneyprinterturbo" @@ -21154,7 +21588,7 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ local app_id="112" local docker_name="lucky" local docker_img="gdy666/lucky:v2" - # 由于 Lucky 使用 host 网络模式,这里的端口仅作记录/说明参考,实际由应用自身控制(默认16601) + # 由於 Lucky 使用 host 網路模式,這裡的連接埠僅作記錄/說明參考,實際上由應用自身控制(預設16601) local docker_port=8112 docker_rum() { @@ -21431,7 +21865,7 @@ linux_work() { echo -e "SSH常駐模式${tmux_sshd_status}" echo "開啟後SSH連線後會直接進入常駐模式,直接回到先前的工作狀態。" echo "------------------------" - echo "1. 开启 2. 关闭" + echo "1. 開啟 2. 關閉" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" @@ -21559,7 +21993,7 @@ fail2ban_panel() { check_f2b_status echo -e "SSH防禦程序$check_f2b_status" echo "fail2ban是一個SSH防止暴力破解工具" - echo "官網介紹:${gh_proxy}github.com/fail2ban/fail2ban" + echo "官网介绍: ${gh_proxy}github.com/fail2ban/fail2ban" echo "------------------------" echo "1. 安裝防禦程序" echo "------------------------" @@ -21567,7 +22001,7 @@ fail2ban_panel() { echo "3. 日誌即時監控" echo "------------------------" echo "4. 基礎參數配置(封禁時間/時間視窗/重試次數)" - echo "5. 編輯設定檔(nano)" + echo "5. 编辑配置文件(nano)" echo "------------------------" echo "9. 卸載防禦程序" echo "------------------------" @@ -21592,7 +22026,7 @@ fail2ban_panel() { break ;; 4) - send_stats "SSH防禦基礎參數配置" + send_stats "SSH防御基础参数配置" f2b_basic_config break_end ;; @@ -21623,7 +22057,7 @@ net_menu() { send_stats "網路卡管理工具" show_nics() { - echo "================ 目前網卡資訊 ==================" + echo "================ 当前网卡信息 ================" printf "%-18s %-12s %-20s %-26s\n" "網路卡名" "狀態" "IP位址" "MAC位址" echo "------------------------------------------------" for nic in $(ls /sys/class/net); do @@ -21642,9 +22076,9 @@ net_menu() { echo "=========== 網路卡管理選單 ===========" echo "1. 啟用網卡" echo "2. 停用網路卡" - echo "3. 查看網卡詳細信息" + echo "3. 查看网卡详细信息" echo "4. 刷新網卡資訊" - echo "0. 返回上一級選單" + echo "0. 返回上一级选单" echo "====================================" read -erp "請選擇操作:" choice @@ -21653,7 +22087,7 @@ net_menu() { send_stats "啟用網卡" read -erp "請輸入要啟用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" up && echo "✔ 網路卡$nic已啟用" + ip link set "$nic" up && echo "✔ 網路卡$nic 已启用" else echo "✘ 網路卡不存在" fi @@ -21663,7 +22097,7 @@ net_menu() { send_stats "停用網路卡" read -erp "請輸入要停用的網路卡名稱:" nic if ip link show "$nic" &>/dev/null; then - ip link set "$nic" down && echo "✔ 網路卡$nic已停用" + ip link set "$nic" down && echo "✔ 网卡 $nic已停用" else echo "✘ 網路卡不存在" fi @@ -21730,7 +22164,7 @@ log_menu() { read -erp "查看最近多少行日誌? [預設 100]:" lines lines=${lines:-100} journalctl -n "$lines" --no-pager - read -erp "按回車繼續..." + read -erp "按回车继续..." ;; 2) send_stats "查看指定服務日誌" @@ -21744,7 +22178,7 @@ log_menu() { ;; 3) send_stats "查看登入/安全日誌" - echo "====== 最近登入日誌 ======" + echo "====== 最近登录日志 ======" last -n 10 echo echo "====== 認證日誌 ======" @@ -21891,7 +22325,7 @@ env_menu() { echo "--------------------------------------" echo "0. 返回上一級選單" echo "--------------------------------------" - read -erp "請選擇操作:" choice + read -erp "请选择操作: " choice case "$choice" in 1) @@ -21934,7 +22368,7 @@ create_user_with_sshkey() { return 1 fi - # 創建用戶 + # 创建用户 useradd -m -s /bin/bash "$new_username" || return 1 echo "導入公鑰範例:" @@ -21976,7 +22410,7 @@ EOF passwd -l "$new_username" &>/dev/null restart_ssh - echo "使用者$new_username創建完成" + echo "用户 $new_username創建完成" } @@ -22002,7 +22436,7 @@ linux_Settings() { echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}1. ${gl_bai}設定腳本啟動快捷鍵${gl_kjlan}2. ${gl_bai}修改登入密碼" echo -e "${gl_kjlan}3. ${gl_bai}使用者密碼登入模式${gl_kjlan}4. ${gl_bai}安裝Python指定版本" - echo -e "${gl_kjlan}5. ${gl_bai}開放所有連接埠${gl_kjlan}6. ${gl_bai}修改SSH連接埠" + echo -e "${gl_kjlan}5. ${gl_bai}開放所有連接埠${gl_kjlan}6. ${gl_bai}修改SSH连接端口" echo -e "${gl_kjlan}7. ${gl_bai}優化DNS位址${gl_kjlan}8. ${gl_bai}一鍵重裝系統${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}9. ${gl_bai}停用ROOT帳戶建立新帳戶${gl_kjlan}10. ${gl_bai}切換優先ipv4/ipv6" echo -e "${gl_kjlan}------------------------" @@ -22027,7 +22461,7 @@ linux_Settings() { echo -e "${gl_kjlan}41. ${gl_bai}系統日誌管理工具${gl_huang}★${gl_bai} ${gl_kjlan}42. ${gl_bai}系統變數管理工具" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}61. ${gl_bai}留言板${gl_kjlan}66. ${gl_bai}一條龍系統調優${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}99. ${gl_bai}重啟伺服器${gl_kjlan}100. ${gl_bai}隱私與安全" + echo -e "${gl_kjlan}99. ${gl_bai}重启服务器 ${gl_kjlan}100. ${gl_bai}隱私與安全" echo -e "${gl_kjlan}101. ${gl_bai}k指令進階用法${gl_huang}★${gl_bai} ${gl_kjlan}102. ${gl_bai}解除安裝科技lion腳本" echo -e "${gl_kjlan}------------------------" echo -e "${gl_kjlan}0. ${gl_bai}返回主選單" @@ -22038,7 +22472,7 @@ linux_Settings() { 1) while true; do clear - read -e -p "請輸入你的快速按鍵(輸入0退出):" kuaijiejian + read -e -p "请输入你的快捷按键(输入0退出): " kuaijiejian if [ "$kuaijiejian" == "0" ]; then break_end linux_Settings @@ -22070,7 +22504,7 @@ linux_Settings() { root_use send_stats "py版本管理" echo "python版本管理" - echo "视频介绍: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" + echo "影片介紹: https://www.bilibili.com/video/BV1Pm42157cK?t=0.1" echo "---------------------------------------" echo "此功能可無縫安裝python官方支援的任何版本!" local VERSION=$(python3 -V 2>&1 | awk '{print $2}') @@ -22178,7 +22612,7 @@ EOF # 提示使用者輸入新的 SSH 連接埠號碼 read -e -p "請輸入新的 SSH 連接埠號碼:" new_port - # 判断端口号是否在有效范围内 + # 判斷連接埠號碼是否在有效範圍內 if [[ $new_port =~ ^[0-9]+$ ]]; then # 检查输入是否为数字 if [[ $new_port -ge 1 && $new_port -le 65535 ]]; then send_stats "SSH連接埠已修改" @@ -22246,11 +22680,11 @@ EOF echo "" echo "------------------------" - echo "1. IPv4 優先 2. IPv6 優先權 3. IPv6 修復工具" + echo "1. IPv4 优先 2. IPv6 优先 3. IPv6 修复工具" echo "------------------------" echo "0. 返回上一級選單" echo "------------------------" - read -e -p "選擇優先的網路:" choice + read -e -p "选择优先的网络: " choice case $choice in 1) @@ -22302,7 +22736,7 @@ EOF case "$choice" in 1) - send_stats "已設定1G虛擬內存" + send_stats "已设置1G虚拟内存" add_swap 1024 ;; @@ -22336,7 +22770,7 @@ EOF send_stats "使用者管理" echo "使用者列表" echo "----------------------------------------------------------------------------" - printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "使用者權限" "使用者群組" "sudo權限" + printf "%-24s %-34s %-20s %-10s\n" "使用者名稱" "使用者權限" "用户组" "sudo權限" while IFS=: read -r username _ userid groupid _ _ homedir shell; do local groups=$(groups "$username" | cut -d : -f 2) local sudo_status @@ -22364,7 +22798,7 @@ EOF case $sub_choice in 1) - # 提示用户输入新用户名 + # 提示使用者輸入新使用者名稱 read -e -p "請輸入新用戶名:" new_username create_user_with_sshkey $new_username false @@ -22393,7 +22827,7 @@ EOF sed -i "/^$username\s*ALL=(ALL)/d" /etc/sudoers ;; 5) - read -e -p "請輸入要刪除的使用者名稱:" username + read -e -p "请输入要删除的用户名: " username userdel -r "$username" ;; @@ -22485,13 +22919,13 @@ EOF echo "------------------------" echo "歐洲" echo "11. 英國倫敦時間 12. 法國巴黎時間" - echo "13. 德國柏林時間 14. 俄羅斯莫斯科時間" + echo "13. 德国柏林时间 14. 俄罗斯莫斯科时间" echo "15. 荷蘭尤特賴赫特時間 16. 西班牙馬德里時間" echo "------------------------" echo "美洲" echo "21. 美國西部時間 22. 美國東部時間" echo "23. 加拿大時間 24. 墨西哥時間" - echo "25. 巴西时间 26. 阿根廷时间" + echo "25. 巴西時間 26. 阿根廷時間" echo "------------------------" echo "31. UTC全球標準時間" echo "------------------------" @@ -22576,7 +23010,7 @@ EOF send_stats "主機名稱已更改" sleep 1 else - echo "已退出,未更改主机名。" + echo "已退出,未更改主機名稱。" break fi done @@ -22643,7 +23077,7 @@ EOF read -e -p "請輸入新任務的執行指令:" newquest echo "------------------------" echo "1. 每月任務 2. 每週任務" - echo "3. 每天任务 4. 每小时任务" + echo "3. 每天任務 4. 每小時任務" echo "------------------------" read -e -p "請輸入你的選擇:" dingshi @@ -22661,7 +23095,7 @@ EOF (crontab -l ; echo "0 $hour * * * $newquest") | crontab - > /dev/null 2>&1 ;; 4) - read -e -p "輸入每小時的第幾分鐘執行任務? (分钟,0-60):" minute + read -e -p "輸入每小時的第幾分鐘執行任務? (分鐘,0-60):" minute (crontab -l ; echo "$minute * * * * $newquest") | crontab - > /dev/null 2>&1 ;; *) @@ -22733,8 +23167,8 @@ EOF send_stats "限流關機功能" while true; do clear - echo "限流關機功能" - echo "视频介绍: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" + echo "限流关机功能" + echo "影片介紹: https://www.bilibili.com/video/BV1mC411j7Qd?t=0.1" echo "------------------------------------------------" echo "目前流量使用情況,重啟伺服器流量計算會清除!" output_status @@ -22746,7 +23180,7 @@ EOF # 取得 threshold_gb 的值 local rx_threshold_gb=$(grep -oP 'rx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) local tx_threshold_gb=$(grep -oP 'tx_threshold_gb=\K\d+' ~/Limiting_Shut_down.sh) - echo -e "${gl_lv}目前設定的進站限流閾值為:${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" + echo -e "${gl_lv}当前设置的进站限流阈值为: ${gl_huang}${rx_threshold_gb}${gl_lv}G${gl_bai}" echo -e "${gl_lv}目前設定的出站限流閾值為:${gl_huang}${tx_threshold_gb}${gl_lv}GB${gl_bai}" else echo -e "${gl_hui}目前未啟用限流關機功能${gl_bai}" @@ -22791,7 +23225,7 @@ EOF crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - crontab -l | grep -v 'reboot' | crontab - rm ~/Limiting_Shut_down.sh - echo "已關閉限流關機功能" + echo "已关闭限流关机功能" ;; *) break @@ -22811,7 +23245,7 @@ EOF echo "TG-bot監控預警功能" echo "影片介紹: https://youtu.be/vLL-eb3Z_TY" echo "------------------------------------------------" - echo "您需要設定tg機器人API和接收預警的用戶ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" + echo "您需要設定tg機器人API和接收預警的使用者ID,即可實現本機CPU,內存,硬碟,流量,SSH登入的即時監控預警" echo "到達閾值後會向用戶發送預警訊息" echo -e "${gl_hui}-關於流量,重啟伺服器將重新計算-${gl_bai}" read -e -p "確定繼續嗎? (Y/N):" choice @@ -22851,7 +23285,7 @@ EOF source ~/.profile clear - echo "TG-bot預警系統已啟動" + echo "TG-bot预警系统已启动" echo -e "${gl_hui}你也可以將root目錄中的TG-check-notify.sh預警檔案放到其他機器上直接使用!${gl_bai}" ;; [Nn]) @@ -22969,7 +23403,7 @@ EOF echo -e "6. 開放所有端口" echo -e "7. 開啟${gl_huang}BBR${gl_bai}加速" echo -e "8. 設定時區到${gl_huang}上海${gl_bai}" - echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 国内: 223.5.5.5 ${gl_bai}" + echo -e "9. 自動優化DNS位址${gl_huang}海外: 1.1.1.1 8.8.8.8 國內: 223.5.5.5${gl_bai}" echo -e "10. 設定網路為${gl_huang}ipv4優先${gl_bai}" echo -e "11. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo -e "12. Linux系統核心參數優化${gl_huang}自動根據網路環境調優${gl_bai}" @@ -23023,7 +23457,7 @@ EOF echo "------------------------------------------------" install_docker install wget sudo tar unzip socat btop nano vim - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" + echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安裝基礎工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash @@ -23059,11 +23493,11 @@ EOF local status_message="無法確定的狀態" fi - echo "隱私與安全" + echo "隐私与安全" echo "腳本將收集使用者使用功能的數據,優化腳本體驗,製作更多好玩好用的功能" echo "將收集腳本版本號,使用的時間,系統版本,CPU架構,機器所屬國家和使用的功能的名稱," echo "------------------------------------------------" - echo -e "目前狀態:$status_message" + echo -e "当前状态: $status_message" echo "--------------------" echo "1. 開啟採集" echo "2. 關閉採集" @@ -23103,7 +23537,7 @@ EOF send_stats "解除安裝科技lion腳本" echo "解除安裝科技lion腳本" echo "------------------------------------------------" - echo "将彻底卸载kejilion脚本,不影响你其他功能" + echo "將徹底卸載kejilion腳本,不影響你其他功能" read -e -p "確定繼續嗎? (Y/N):" choice case "$choice" in @@ -23162,7 +23596,7 @@ linux_file() { echo "1. 進入目錄 2. 建立目錄 3. 修改目錄權限 4. 重新命名目錄" echo "5. 刪除目錄 6. 返回上一層選單目錄" echo "------------------------" - echo "11. 创建文件 12. 编辑文件 13. 修改文件权限 14. 重命名文件" + echo "11. 建立文件 12. 編輯文件 13. 修改文件權限 14. 重新命名文件" echo "15. 刪除文件" echo "------------------------" echo "21. 壓縮檔案目錄 22. 解壓縮檔案目錄 23. 行動檔案目錄 24. 複製檔案目錄" @@ -23176,11 +23610,11 @@ linux_file() { 1) # 进入目录 read -e -p "請輸入目錄名:" dirname cd "$dirname" 2>/dev/null || echo "無法進入目錄" - send_stats "進入目錄" + send_stats "进入目录" ;; 2) # 创建目录 read -e -p "請輸入要建立的目錄名稱:" dirname - mkdir -p "$dirname" && echo "目錄已建立" || echo "創建失敗" + mkdir -p "$dirname" && echo "目錄已建立" || echo "创建失败" send_stats "建立目錄" ;; 3) # 修改目录权限 @@ -23228,8 +23662,8 @@ linux_file() { send_stats "重新命名文件" ;; 15) # 删除文件 - read -e -p "請輸入要刪除的檔名:" filename - rm -f "$filename" && echo "文件已删除" || echo "刪除失敗" + read -e -p "请输入要删除的文件名: " filename + rm -f "$filename" && echo "文件已刪除" || echo "刪除失敗" send_stats "刪除文件" ;; 21) # 压缩文件/目录 @@ -23239,7 +23673,7 @@ linux_file() { send_stats "壓縮檔案/目錄" ;; 22) # 解压文件/目录 - read -e -p "請輸入要解壓縮的檔案名稱 (.tar.gz):" filename + read -e -p "請輸入要解壓縮的檔名 (.tar.gz):" filename install tar tar -xzvf "$filename" && echo "已解壓縮$filename" || echo "解壓縮失敗" send_stats "解壓縮檔案/目錄" @@ -23289,7 +23723,7 @@ linux_file() { 25) # 传送文件至远端服务器 read -e -p "請輸入要傳送的檔案路徑:" file_to_transfer if [ ! -f "$file_to_transfer" ]; then - echo "错误: 文件不存在。" + echo "錯誤: 文件不存在。" send_stats "傳送文件失敗: 文件不存在" continue fi @@ -23414,7 +23848,7 @@ while true; do read -e -p "伺服器IP:" server_ip read -e -p "伺服器連接埠(22):" server_port local server_port=${server_port:-22} - read -e -p "服务器用户名(root): " server_username + read -e -p "伺服器使用者名稱(root):" server_username local server_username=${server_username:-root} read -e -p "伺服器用戶密碼:" server_password @@ -23423,7 +23857,7 @@ while true; do ;; 2) send_stats "刪除叢集伺服器" - read -e -p "請輸入需要刪除的關鍵字:" rmserver + read -e -p "请输入需要删除的关键字: " rmserver sed -i "/$rmserver/d" ~/cluster/servers.py ;; 3) @@ -23475,7 +23909,7 @@ while true; do 51) send_stats "自訂執行命令" - read -e -p "請輸入批次執行的命令:" mingling + read -e -p "请输入批量执行的命令: " mingling run_commands_on_servers "${mingling}" ;; @@ -23504,7 +23938,7 @@ echo -e "${gl_lan}萊卡雲 香港CN2 GIA 韓國雙ISP 美國CN2 GIA 優惠活 echo -e "${gl_bai}網址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" echo -e "${gl_lan}RackNerd 10.99刀每年 美國 1核心 1G記憶體 20G硬碟 1T流量每月${gl_bai}" -echo -e "${gl_bai}網址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" +echo -e "${gl_bai}网址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" echo -e "${gl_zi}Hostinger 52.7刀每年 美國 1核心 4G記憶體 50G硬碟 4T流量每月${gl_bai}" echo -e "${gl_bai}網址: https://cart.hostinger.com/pay/d83c51e9-0c28-47a6-8414-b8ab010ef94f?_ga=GA1.3.942352702.1711283207${gl_bai}" @@ -23519,7 +23953,7 @@ echo -e "${gl_zi}V.PS 6.9刀每月 東京軟銀 2核心 1G內存 20G硬碟 1T流 echo -e "${gl_bai}網址: https://vps.hosting/cart/tokyo-cloud-kvm-vps/?id=148&?affid=1355&?affid=1355${gl_bai}" echo "------------------------" echo -e "${gl_kjlan}VPS更多熱門優惠${gl_bai}" -echo -e "${gl_bai}網址: https://kejilion.pro/topvps/${gl_bai}" +echo -e "${gl_bai}网址: https://kejilion.pro/topvps/${gl_bai}" echo "------------------------" echo "" echo -e "網域優惠" @@ -23532,9 +23966,9 @@ echo -e "科技lion週邊" echo "------------------------" echo -e "${gl_kjlan}B站:${gl_bai}https://b23.tv/2mqnQyh ${gl_kjlan}油管:${gl_bai}https://www.youtube.com/@kejilion${gl_bai}" echo -e "${gl_kjlan}官網:${gl_bai}https://kejilion.pro/ ${gl_kjlan}導航:${gl_bai}https://dh.kejilion.pro/${gl_bai}" -echo -e "${gl_kjlan}部落格:${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}軟體中心:${gl_bai}https://app.kejilion.pro/${gl_bai}" +echo -e "${gl_kjlan}博客: ${gl_bai}https://blog.kejilion.pro/ ${gl_kjlan}軟體中心:${gl_bai}https://app.kejilion.pro/${gl_bai}" echo "------------------------" -echo -e "${gl_kjlan}腳本官網:${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" +echo -e "${gl_kjlan}脚本官网: ${gl_bai}https://kejilion.sh ${gl_kjlan}GitHub地址:${gl_bai}${gh_https_url}github.com/kejilion/sh${gl_bai}" echo "------------------------" echo "" } @@ -23603,7 +24037,7 @@ games_server_tools() { kejilion_update() { -send_stats "腳本更新" +send_stats "脚本更新" cd ~ while true; do clear @@ -23622,7 +24056,7 @@ while true; do echo -e "${gl_lv}你已經是最新版本!${gl_huang}v$sh_v${gl_bai}" send_stats "腳本已經最新了,無需更新" else - echo "發現新版本!" + echo "发现新版本!" echo -e "目前版本 v$sh_v最新版本${gl_huang}v$sh_v_new${gl_bai}" fi @@ -23632,7 +24066,7 @@ while true; do if [ -n "$existing_cron" ]; then echo "------------------------" - echo -e "${gl_lv}自動更新已開啟,每天凌晨2點腳本會自動更新!${gl_bai}" + echo -e "${gl_lv}自动更新已开启,每天凌晨2点脚本会自动更新!${gl_bai}" fi echo "------------------------" @@ -23667,7 +24101,7 @@ while true; do yinsiyuanquan2 cp -f ~/kejilion.sh /usr/local/bin/k > /dev/null 2>&1 ln -sf /usr/local/bin/k /usr/bin/k > /dev/null 2>&1 - echo -e "${gl_lv}腳本已更新至最新版本!${gl_huang}v$sh_v_new${gl_bai}" + echo -e "${gl_lv}脚本已更新到最新版本!${gl_huang}v$sh_v_new${gl_bai}" send_stats "腳本已經最新$sh_v_new" else rm -f "$tmp_file" @@ -23675,7 +24109,7 @@ while true; do if [ -f ~/kejilion.sh.bak ]; then mv -f ~/kejilion.sh.bak ~/kejilion.sh fi - echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原版本${gl_bai}" + echo -e "${gl_hong}更新失敗!下載出錯或檔案校驗不通過,已恢復原始版本${gl_bai}" send_stats "腳本更新失敗" fi break_end @@ -23750,7 +24184,7 @@ echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}1. ${gl_bai}系統資訊查詢" echo -e "${gl_kjlan}2. ${gl_bai}系統更新" echo -e "${gl_kjlan}3. ${gl_bai}系統清理" -echo -e "${gl_kjlan}4. ${gl_bai}基礎工具" +echo -e "${gl_kjlan}4. ${gl_bai}基础工具" echo -e "${gl_kjlan}5. ${gl_bai}BBR管理" echo -e "${gl_kjlan}6. ${gl_bai}Docker管理" echo -e "${gl_kjlan}7. ${gl_bai}WARP管理" @@ -23762,7 +24196,7 @@ echo -e "${gl_kjlan}12. ${gl_bai}後台工作區" echo -e "${gl_kjlan}13. ${gl_bai}系統工具" echo -e "${gl_kjlan}14. ${gl_bai}伺服器叢集控制" echo -e "${gl_kjlan}15. ${gl_bai}廣告專欄" -echo -e "${gl_kjlan}16. ${gl_bai}遊戲開服腳本合集" +echo -e "${gl_kjlan}16. ${gl_bai}游戏开服脚本合集" echo -e "${gl_kjlan}------------------------${gl_bai}" echo -e "${gl_kjlan}00. ${gl_bai}腳本更新" echo -e "${gl_kjlan}------------------------${gl_bai}" @@ -23799,7 +24233,7 @@ done k_info() { -send_stats "k指令參考用例" +send_stats "k命令参考用例" echo "-------------------" echo "影片介紹: https://www.bilibili.com/video/BV1ib421E7it?t=0.1" echo "以下是k命令參考用例:" @@ -23814,7 +24248,7 @@ echo "核心調優面板 k nhyh | k 核心最佳化" echo "設定虛擬記憶體 k swap 2048" echo "設定虛擬時區 k time Asia/Shanghai | k 時區 Asia/Shanghai" echo "系統回收站 k trash | k hsz | k 回收站" -echo "系統備份功能 k backup | k bf | k 備份" +echo "系统备份功能 k backup | k bf | k 备份" echo "ssh遠端連線工具 k ssh | k 遠端連線" echo "rsync遠端同步工具 k rsync | k 遠端同步" echo "硬碟管理工具 k disk | k 硬碟管理" @@ -23839,14 +24273,14 @@ echo "安裝負載平衡 k loadbalance |k 負載平衡" echo "安裝L4負載平衡 k stream |k L4負載平衡" echo "防火牆面板 k fhq |k 防火牆" echo "開放埠 k dkdk 8080 |k 開啟連接埠 8080" -echo "关闭端口 k gbdk 7800 |k 关闭端口 7800" +echo "關閉連接埠 k gbdk 7800 |k 關閉連接埠 7800" echo "放行IP k fxip 127.0.0.0/8 |k 放行IP 127.0.0.0/8" echo "阻止IP k zzip 177.5.25.36 |k 阻止IP 177.5.25.36" echo "命令收藏 k fav | k 指令收藏夾" echo "應用市場管理 k app" echo "應用編號快捷管理 k app 26 | k app 1panel | k app npm" echo "fail2ban管理 k fail2ban | k f2b [status|enable|disable]" -echo "显示系统信息 k info" +echo "顯示系統資訊 k info" echo "ROOT金鑰管理 k sshkey" echo "SSH公鑰導入(URL) k sshkey " echo "SSH公鑰導入(GitHub) k sshkey github " @@ -24020,6 +24454,11 @@ else kpanel_set_dns_noninteractive "$@" ;; + ssh-port) + shift + kpanel_ssh_port_noninteractive "$@" + ;; + test|check|体检|测试) shift if [ "${KJ_TEST_NONINTERACTIVE:-}" = "1" ]; then @@ -24156,6 +24595,17 @@ else fi ;; + kpanel) + shift + if [ "${1:-}" = "node" ]; then + shift + kpanel_node_dispatch "$@" + else + echo "用法: k kpanel node join <授權> | status | update | uninstall" >&2 + return 2 2>/dev/null || exit 2 + fi + ;; + app) shift @@ -24192,7 +24642,7 @@ else ;; github ) shift - send_stats "从 GitHub 导入 SSH 公钥" + send_stats "從 GitHub 導入 SSH 公鑰" fetch_github_ssh_keys "$1" ;; http://*|https://* ) From 0deb895c468dd7c3c11b7e2b6e6d331f564ef921 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 10 Aug 2026 11:49:50 +0800 Subject: [PATCH 1255/1285] feat(kpanel): add system resource adapters AI-Scope: kpanel-system-resource-adapters --- cn/kejilion.sh | 1488 ++++++++++++++++- kejilion.sh | 1488 ++++++++++++++++- ...el_system_resource_noninteractive_smoke.sh | 372 +++++ 3 files changed, 3346 insertions(+), 2 deletions(-) create mode 100644 tests/test_kpanel_system_resource_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5cb95a9a8..b06c6758c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -24,6 +24,7 @@ kpanel_protocol_active() { [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || @@ -22128,6 +22129,1488 @@ net_menu() { +# KPanel system resource protocol start +kpanel_system_resource_zero_version() { + printf '%064d' 0 +} + +kpanel_system_resource_emit() { + local status="$1" + local version="$2" + local backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_SYSTEM_RESOURCE_STATUS=%s\n' "$status" + printf 'KPANEL_SYSTEM_RESOURCE_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_SYSTEM_RESOURCE_BACKUP=%s\n' "$backup" +} + +kpanel_system_resource_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_system_resource_valid_version() { + [[ "$1" =~ ^[0-9a-f]{64}$ ]] +} + +kpanel_system_resource_single_line() { + local value="$1" + local maximum="$2" + local bytes + bytes="$(printf '%s' "$value" | wc -c)" || return 1 + [ "$bytes" -le "$maximum" ] && + [[ "$value" != *$'\n'* ]] && + [[ "$value" != *$'\r'* ]] +} + +kpanel_system_resource_copy_identity() { + local source="$1" + local target="$2" + local mode owner + mode="$(stat -c '%a' "$source" 2>/dev/null)" || return 1 + owner="$(stat -c '%u:%g' "$source" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || return 1 + chown "$owner" "$target" >/dev/null 2>&1 && + chmod "$mode" "$target" >/dev/null 2>&1 +} + +kpanel_system_resource_file_within_bounds() { + local path="$1" + local maximum_bytes="$2" + local maximum_lines="$3" + local bytes lines + bytes="$(wc -c < "$path" 2>/dev/null)" || return 1 + lines="$(awk 'END {print NR + 0}' "$path" 2>/dev/null)" || return 1 + [ "$bytes" -le "$maximum_bytes" ] && [ "$lines" -le "$maximum_lines" ] +} + +kpanel_system_resource_hosts_file() { + printf '%s\n' "/etc/hosts" +} + +kpanel_system_resource_lock_file() { + printf '%s\n' "/run/lock/kejilion-system-resource.lock" +} + +kpanel_system_resource_interfaces_dir() { + printf '%s\n' "/sys/class/net" +} + +kpanel_system_resource_iptables_rules_file() { + printf '%s\n' "/etc/iptables/rules.v4" +} + +kpanel_system_resource_tempdir() { + local resource="$1" + local directory + directory="$(mktemp -d "/tmp/kejilion-system-resource-${resource}.XXXXXX")" || return 1 + chmod 700 "$directory" || { + rm -rf -- "$directory" + return 1 + } + printf '%s\n' "$directory" +} + +kpanel_system_resource_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$octet" = "0" ] || [[ "$octet" != 0* ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_system_resource_ipv6_side_count() { + local side="$1" + local part index count=0 + local parts=() + [ -n "$side" ] || { + printf '0\n' + return 0 + } + [[ "$side" != :* && "$side" != *: ]] || return 1 + IFS=: read -r -a parts <<< "$side" + for index in "${!parts[@]}"; do + part="${parts[$index]}" + [ -n "$part" ] || return 1 + if [[ "$part" == *.* ]]; then + [ "$index" -eq "$((${#parts[@]} - 1))" ] || return 1 + kpanel_system_resource_is_ipv4 "$part" || return 1 + count=$((count + 2)) + else + [[ "$part" =~ ^[0-9A-Fa-f]{1,4}$ ]] || return 1 + count=$((count + 1)) + fi + done + printf '%s\n' "$count" +} + +kpanel_system_resource_is_ipv6() { + local value="$1" + local left right left_count right_count total + [ -n "$value" ] && [ "${#value}" -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] || return 1 + if [[ "$value" == *::* ]]; then + [[ "${value/::/}" != *::* ]] || return 1 + left="${value%%::*}" + right="${value#*::}" + left_count="$(kpanel_system_resource_ipv6_side_count "$left")" || return 1 + right_count="$(kpanel_system_resource_ipv6_side_count "$right")" || return 1 + total=$((left_count + right_count)) + [ "$total" -lt 8 ] + else + [[ "$value" != :* && "$value" != *: ]] || return 1 + total="$(kpanel_system_resource_ipv6_side_count "$value")" || return 1 + [ "$total" -eq 8 ] + fi +} + +kpanel_system_resource_is_hostname() { + local value="$1" + local label + local labels=() + [ -n "$value" ] && [ "${#value}" -le 253 ] || return 1 + value="${value%.}" + [ -n "$value" ] || return 1 + IFS=. read -r -a labels <<< "$value" + for label in "${labels[@]}"; do + [ -n "$label" ] && [ "${#label}" -le 63 ] || return 1 + [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || return 1 + done +} + +kpanel_system_resource_is_ipv4_cidr() { + local value="$1" + local address prefix + if [[ "$value" == */* ]]; then + [ "${value//[^\/]/}" = "/" ] || return 1 + address="${value%/*}" + prefix="${value##*/}" + [[ "$prefix" =~ ^[0-9]{1,2}$ ]] && + { [ "$prefix" = "0" ] || [[ "$prefix" != 0* ]]; } && + [ "$((10#$prefix))" -le 32 ] || return 1 + else + address="$value" + fi + kpanel_system_resource_is_ipv4 "$address" +} + +kpanel_system_resource_hosts_version() { + local path + path="$(kpanel_system_resource_hosts_file)" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + sha256sum -- "$path" 2>/dev/null | awk '{print $1}' +} + +kpanel_system_resource_cron_capture() { + local target="$1" + local error_file="$target.error" + local rc=0 + KPANEL_SYSTEM_RESOURCE_CRON_EXISTED=false + LC_ALL=C crontab -l > "$target" 2>"$error_file" || rc=$? + if [ "$rc" -eq 0 ]; then + KPANEL_SYSTEM_RESOURCE_CRON_EXISTED=true + elif grep -Fqi 'no crontab for' "$error_file"; then + : > "$target" || { + rm -f -- "$error_file" + return 1 + } + else + rm -f -- "$error_file" + return 1 + fi + rm -f -- "$error_file" + kpanel_system_resource_file_within_bounds "$target" 262144 512 +} + +kpanel_system_resource_cron_version() { + local temporary version + temporary="$(mktemp /tmp/kejilion-system-resource-cron-version.XXXXXX)" || return 1 + if ! kpanel_system_resource_cron_capture "$temporary"; then + rm -f -- "$temporary" + return 1 + fi + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + rm -f -- "$temporary" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_system_resource_interface_exists() { + local name="$1" + local root candidate + root="$(kpanel_system_resource_interfaces_dir)" + [ -d "$root" ] || return 1 + for candidate in "$root"/*; do + [ -e "$candidate" ] || continue + [ "$(basename -- "$candidate")" = "$name" ] && return 0 + done + return 1 +} + +kpanel_system_resource_interface_version() { + local name="$1" + local root state mac + kpanel_system_resource_interface_exists "$name" || return 1 + root="$(kpanel_system_resource_interfaces_dir)" + state="$(kpanel_system_resource_interface_admin_state "$name")" || return 1 + mac="$(cat "$root/$name/address" 2>/dev/null)" || return 1 + printf '%s|%s|%s' "$name" "$state" "$mac" | sha256sum | awk '{print $1}' +} + +kpanel_system_resource_firewall_version() { + local temporary version + temporary="$(mktemp /tmp/kejilion-system-resource-firewall-version.XXXXXX)" || return 1 + if ! kpanel_system_resource_firewall_capture "$temporary"; then + rm -f -- "$temporary" + return 1 + fi + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + rm -f -- "$temporary" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_system_resource_firewall_capture() { + local target="$1" + local bytes + iptables-save > "$target" 2>/dev/null || return 1 + bytes="$(wc -c < "$target" 2>/dev/null)" || return 1 + [ "$bytes" -le 524288 ] +} + +kpanel_system_resource_best_version() { + local resource="$1" + local name="${2:-}" + local version="" + case "$resource" in + hosts) version="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" ;; + cron) version="$(kpanel_system_resource_cron_version 2>/dev/null || true)" ;; + network-interface) + [ -z "$name" ] || version="$(kpanel_system_resource_interface_version "$name" 2>/dev/null || true)" + ;; + firewall) version="$(kpanel_system_resource_firewall_version 2>/dev/null || true)" ;; + esac + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf '%s\n' "$version" +} + +kpanel_system_resource_check_expected() { + local resource="$1" + local expected="$2" + local name="${3:-}" + local current + kpanel_system_resource_valid_version "$expected" || { + kpanel_system_resource_error "expectedResourceVersion 必须为 64 位小写十六进制" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 2 + } + case "$resource" in + hosts) current="$(kpanel_system_resource_hosts_version 2>/dev/null)" ;; + cron) current="$(kpanel_system_resource_cron_version 2>/dev/null)" ;; + network-interface) current="$(kpanel_system_resource_interface_version "$name" 2>/dev/null)" ;; + firewall) current="$(kpanel_system_resource_firewall_version 2>/dev/null)" ;; + *) return 2 ;; + esac || { + kpanel_system_resource_error "无法读取当前资源版本" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 1 + } + if [ "$current" != "$expected" ]; then + kpanel_system_resource_error "资源版本已变化,请刷新后重试" + kpanel_system_resource_emit conflict "$current" + return 2 + fi + KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION="$current" +} + +kpanel_system_resource_require_platform() { + local command_name + if [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" != "1" ]; then + kpanel_system_resource_error "KPanel system-resource 协议环境未启用" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + if [ "$EUID" -ne 0 ]; then + kpanel_system_resource_error "KPanel system-resource 协议必须以 root 运行" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + if [ "$(uname -s 2>/dev/null)" != "Linux" ]; then + kpanel_system_resource_error "KPanel system-resource 协议仅支持 Linux" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + for command_name in sha256sum mktemp flock; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少必要命令: $command_name" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + done +} + +kpanel_system_resource_hosts_build_line() { + local address="$1" + local hostnames_csv="$2" + local comment="$3" + local hostname joined + local hostnames=() + + kpanel_system_resource_is_ipv4 "$address" || + kpanel_system_resource_is_ipv6 "$address" || return 1 + kpanel_system_resource_single_line "$hostnames_csv" 1024 && + [ -n "$hostnames_csv" ] || return 1 + [[ "$hostnames_csv" != ,* && "$hostnames_csv" != *, && "$hostnames_csv" != *,,* ]] || return 1 + IFS=, read -r -a hostnames <<< "$hostnames_csv" + [ "${#hostnames[@]}" -ge 1 ] && [ "${#hostnames[@]}" -le 16 ] || return 1 + for hostname in "${hostnames[@]}"; do + kpanel_system_resource_is_hostname "$hostname" || return 1 + done + kpanel_system_resource_single_line "$comment" 256 || return 1 + joined="$(IFS=' '; printf '%s' "${hostnames[*]}")" + KPANEL_SYSTEM_RESOURCE_HOSTS_LINE="$address"$'\t'"$joined" + [ -z "$comment" ] || + KPANEL_SYSTEM_RESOURCE_HOSTS_LINE="$KPANEL_SYSTEM_RESOURCE_HOSTS_LINE # $comment" +} + +kpanel_system_resource_restore_hosts() { + local path="$1" + local backup="$2" + local expected_version="$3" + local current + current="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" + [ "$current" = "$expected_version" ] && return 0 + cp -p -- "$backup" "$path" >/dev/null 2>&1 || return 1 + current="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" + [ "$current" = "$expected_version" ] +} + +kpanel_system_resource_hosts_failure() { + local path="$1" + local backup="$2" + local snapshot_dir="$3" + local original_version="$4" + local message="$5" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_restore_hosts "$path" "$backup" "$original_version"; then + version="$(kpanel_system_resource_best_version hosts)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version hosts)" + kpanel_system_resource_error "hosts 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_hosts_action() { + local action="$1" + shift + local expected path line line_number snapshot_dir backup desired desired_version current_line + local index=0 total_lines + local address hostnames_csv comment + local hosts_trailing_newline=true + + path="$(kpanel_system_resource_hosts_file)" + [ -f "$path" ] && [ ! -L "$path" ] || { + kpanel_system_resource_error "未找到可安全管理的 hosts 文件" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + kpanel_system_resource_file_within_bounds "$path" 262144 1024 || { + kpanel_system_resource_error "hosts 超过 256KiB 或 1024 行协议上限" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + case "$action" in + add) + [ "$#" -eq 4 ] || { + kpanel_system_resource_error "hosts add 需要 expected,address,hostnamesCSV,comment" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + expected="$1" + address="$2" + hostnames_csv="$3" + comment="$4" + kpanel_system_resource_hosts_build_line "$address" "$hostnames_csv" "$comment" || { + kpanel_system_resource_error "hosts 地址、主机名或注释无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + line="$KPANEL_SYSTEM_RESOURCE_HOSTS_LINE" + ;; + delete) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "hosts delete 需要 expected,line" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + expected="$1" + line_number="$2" + [[ "$line_number" =~ ^[0-9]{1,4}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 1024 ] || { + kpanel_system_resource_error "hosts 行号必须为 1-1024" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + line_number=$((10#$line_number)) + ;; + *) + kpanel_system_resource_error "不支持的 hosts 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + ;; + esac + + kpanel_system_resource_check_expected hosts "$expected" || return $? + if [ "$action" = "add" ] && grep -Fqx -- "$line" "$path"; then + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if [ "$action" = "delete" ]; then + total_lines="$(awk 'END {print NR + 0}' "$path")" + if [ "$line_number" -gt "$total_lines" ]; then + kpanel_system_resource_error "hosts 行号超出当前文件范围" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + if [ -s "$path" ] && [ "$(tail -c 1 "$path" | wc -l)" -eq 0 ]; then + hosts_trailing_newline=false + fi + fi + + snapshot_dir="$(kpanel_system_resource_tempdir hosts)" || { + kpanel_system_resource_error "无法创建 hosts 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + backup="$snapshot_dir/hosts.backup" + cp -p -- "$path" "$backup" >/dev/null 2>&1 || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法备份 hosts" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + desired="$(mktemp "$(dirname -- "$path")/.hosts.kpanel.XXXXXX")" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 hosts 临时文件" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + + if [ "$action" = "add" ]; then + cp -- "$path" "$desired" >/dev/null 2>&1 || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法复制 hosts" + return $? + } + if [ -s "$desired" ] && [ "$(tail -c 1 "$desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法生成 hosts" + return $? + } + fi + printf '%s\n' "$line" >> "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法写入 hosts" + return $? + } + else + : > "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法生成 hosts" + return $? + } + while IFS= read -r current_line || [ -n "$current_line" ]; do + index=$((index + 1)) + if [ "$index" -eq "$line_number" ]; then + continue + fi + if [ "$index" -eq "$total_lines" ] && [ "$hosts_trailing_newline" = false ]; then + printf '%s' "$current_line" >> "$desired" + else + printf '%s\n' "$current_line" >> "$desired" + fi || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法重写 hosts" + return $? + } + done < "$path" + fi + kpanel_system_resource_file_within_bounds "$desired" 262144 1024 || { + rm -f -- "$desired" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "修改后的 hosts 超过 256KiB 或 1024 行协议上限" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + } + + kpanel_system_resource_copy_identity "$path" "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法保留 hosts 权限或属主" + return $? + } + desired_version="$(sha256sum -- "$desired" 2>/dev/null | awk '{print $1}')" + if ! kpanel_system_resource_valid_version "$desired_version"; then + rm -f -- "$desired" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法计算修改后的 hosts 版本" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + if ! mv -f -- "$desired" "$path" >/dev/null 2>&1 || + [ "$(kpanel_system_resource_hosts_version 2>/dev/null)" != "$desired_version" ]; then + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "hosts 原子写入或回读验证失败" + return $? + fi + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$desired_version" +} + +kpanel_system_resource_cron_number_in_range() { + local value="$1" + local minimum="$2" + local maximum="$3" + [[ "$value" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$value))" -ge "$minimum" ] && + [ "$((10#$value))" -le "$maximum" ] +} + +kpanel_system_resource_cron_value_in_range() { + local value="$1" + local minimum="$2" + local maximum="$3" + local kind="$4" + local numeric="" + + if [[ "$value" =~ ^[0-9]{1,3}$ ]]; then + numeric=$((10#$value)) + else + case "$kind:${value^^}" in + month:JAN) numeric=1 ;; month:FEB) numeric=2 ;; month:MAR) numeric=3 ;; + month:APR) numeric=4 ;; month:MAY) numeric=5 ;; month:JUN) numeric=6 ;; + month:JUL) numeric=7 ;; month:AUG) numeric=8 ;; month:SEP) numeric=9 ;; + month:OCT) numeric=10 ;; month:NOV) numeric=11 ;; month:DEC) numeric=12 ;; + weekday:SUN) numeric=0 ;; weekday:MON) numeric=1 ;; weekday:TUE) numeric=2 ;; + weekday:WED) numeric=3 ;; weekday:THU) numeric=4 ;; weekday:FRI) numeric=5 ;; + weekday:SAT) numeric=6 ;; + *) return 1 ;; + esac + fi + [ "$numeric" -ge "$minimum" ] && [ "$numeric" -le "$maximum" ] || return 1 + KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE="$numeric" +} + +kpanel_system_resource_cron_field() { + local field="$1" + local minimum="$2" + local maximum="$3" + local kind="$4" + local item base step start end start_numeric end_numeric + local items=() + + IFS=, read -r -a items <<< "$field" + [ "${#items[@]}" -ge 1 ] || return 1 + for item in "${items[@]}"; do + [ -n "$item" ] || return 1 + base="$item" + if [[ "$item" == */* ]]; then + base="${item%%/*}" + step="${item#*/}" + [[ "$step" != */* ]] && + kpanel_system_resource_cron_number_in_range "$step" 1 "$maximum" || return 1 + fi + if [ "$base" = "*" ]; then + continue + elif [[ "$base" == *-* ]]; then + start="${base%%-*}" + end="${base#*-}" + [[ "$end" != *-* ]] && + kpanel_system_resource_cron_value_in_range "$start" "$minimum" "$maximum" "$kind" || return 1 + start_numeric="$KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE" + kpanel_system_resource_cron_value_in_range "$end" "$minimum" "$maximum" "$kind" || return 1 + end_numeric="$KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE" + [ "$start_numeric" -le "$end_numeric" ] || return 1 + else + kpanel_system_resource_cron_value_in_range "$base" "$minimum" "$maximum" "$kind" || return 1 + fi + done +} + +kpanel_system_resource_cron_expression() { + local expression="$1" + local fields=() + + kpanel_system_resource_single_line "$expression" 128 && [ -n "$expression" ] || return 1 + case "$expression" in + @reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly) + KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="$expression" + return 0 + ;; + esac + read -r -a fields <<< "$expression" + [ "${#fields[@]}" -eq 5 ] || return 1 + kpanel_system_resource_cron_field "${fields[0]}" 0 59 numeric && + kpanel_system_resource_cron_field "${fields[1]}" 0 23 numeric && + kpanel_system_resource_cron_field "${fields[2]}" 1 31 numeric && + kpanel_system_resource_cron_field "${fields[3]}" 1 12 month && + kpanel_system_resource_cron_field "${fields[4]}" 0 7 weekday || return 1 + KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="${fields[*]}" +} + +kpanel_system_resource_cron_restore() { + local backup="$1" + local existed="$2" + local verify="$3" + + if [ "$existed" = true ]; then + crontab "$backup" >/dev/null 2>&1 || return 1 + else + crontab -r >/dev/null 2>&1 || true + fi + kpanel_system_resource_cron_capture "$verify" || return 1 + cmp -s -- "$backup" "$verify" +} + +kpanel_system_resource_cron_failure() { + local snapshot_dir="$1" + local backup="$2" + local existed="$3" + local message="$4" + local verify="$snapshot_dir/rollback.verify" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_cron_restore "$backup" "$existed" "$verify"; then + version="$(kpanel_system_resource_best_version cron)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version cron)" + kpanel_system_resource_error "crontab 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_cron_action() { + local action="$1" + shift + local expected line_number expression command_value trimmed_command new_line snapshot_dir backup desired verify + local cron_existed current_line index=0 total_lines + + command -v crontab >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少 crontab 命令" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$action" in + add) + [ "$#" -eq 3 ] || { + kpanel_system_resource_error "cron add 需要 expected,expression,command" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + expression="$2" + command_value="$3" + ;; + update) + [ "$#" -eq 4 ] || { + kpanel_system_resource_error "cron update 需要 expected,line,expression,command" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + line_number="$2" + expression="$3" + command_value="$4" + [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 512 ] || { + kpanel_system_resource_error "cron 行号必须为 1-512" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + line_number=$((10#$line_number)) + ;; + delete) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "cron delete 需要 expected,line" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + line_number="$2" + [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 512 ] || { + kpanel_system_resource_error "cron 行号必须为 1-512" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + line_number=$((10#$line_number)) + ;; + *) + kpanel_system_resource_error "不支持的 cron 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + ;; + esac + + if [ "$action" != "delete" ]; then + trimmed_command="$command_value" + trimmed_command="${trimmed_command#"${trimmed_command%%[![:space:]]*}"}" + trimmed_command="${trimmed_command%"${trimmed_command##*[![:space:]]}"}" + kpanel_system_resource_cron_expression "$expression" && + kpanel_system_resource_single_line "$command_value" 2048 && + [ -n "$trimmed_command" ] || { + kpanel_system_resource_error "cron 表达式或命令无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + new_line="$KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION $command_value" + fi + kpanel_system_resource_check_expected cron "$expected" || return $? + + snapshot_dir="$(kpanel_system_resource_tempdir cron)" || { + kpanel_system_resource_error "无法创建 cron 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + backup="$snapshot_dir/crontab.backup" + kpanel_system_resource_cron_capture "$backup" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法读取当前 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" + + if [ "$action" = "add" ] && grep -Fqx -- "$new_line" "$backup"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if [ "$action" != "add" ]; then + total_lines="$(awk 'END {print NR + 0}' "$backup")" + if [ "$line_number" -gt "$total_lines" ]; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "cron 行号超出当前 crontab 范围" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + fi + + desired="$snapshot_dir/crontab.desired" + if [ "$action" = "add" ]; then + cp -- "$backup" "$desired" >/dev/null 2>&1 || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法复制当前 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if [ -s "$desired" ] && [ "$(tail -c 1 "$desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$desired" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法生成 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + fi + printf '%s\n' "$new_line" >> "$desired" || { + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" + return $? + } + else + : > "$desired" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 crontab 目标文件" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + while IFS= read -r current_line || [ -n "$current_line" ]; do + index=$((index + 1)) + if [ "$index" -eq "$line_number" ]; then + if [ "$action" != "delete" ] && ! printf '%s\n' "$new_line" >> "$desired"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法生成 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + continue + fi + printf '%s\n' "$current_line" >> "$desired" || { + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" + return $? + } + done < "$backup" + fi + if ! kpanel_system_resource_file_within_bounds "$desired" 262144 512; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "修改后的 crontab 超过 256KiB 或 512 行协议上限" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + if cmp -s -- "$backup" "$desired"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + + if ! crontab "$desired" >/dev/null 2>&1; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 安装失败" + return $? + fi + verify="$snapshot_dir/crontab.verify" + if ! kpanel_system_resource_cron_capture "$verify"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 回读失败" + return $? + fi + if ! cmp -s -- "$desired" "$verify"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 回读验证失败" + return $? + fi + local applied_version + applied_version="$(sha256sum -- "$verify" 2>/dev/null | awk '{print $1}')" + if ! kpanel_system_resource_valid_version "$applied_version"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法计算 crontab 版本" + return $? + fi + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$applied_version" +} + +kpanel_system_resource_interface_admin_state() { + local name="$1" + local root flags numeric + root="$(kpanel_system_resource_interfaces_dir)" + flags="$(cat "$root/$name/flags" 2>/dev/null)" || return 1 + [[ "$flags" =~ ^0x[0-9A-Fa-f]+$ ]] || return 1 + numeric=$((flags)) + if [ "$((numeric & 1))" -eq 1 ]; then + printf 'up\n' + else + printf 'down\n' + fi +} + +kpanel_system_resource_interface_failure() { + local name="$1" + local old_state="$2" + local message="$3" + local current_state="" version attempt + + kpanel_system_resource_error "$message" + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + if [ "$current_state" != "$old_state" ]; then + ip link set dev "$name" "$old_state" >/dev/null 2>&1 || true + for attempt in 1 2 3 4 5; do + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + [ "$current_state" = "$old_state" ] && break + sleep 0.1 + done + fi + version="$(kpanel_system_resource_best_version network-interface "$name")" + if [ "$current_state" = "$old_state" ]; then + kpanel_system_resource_emit failed "$version" + else + kpanel_system_resource_error "网卡状态回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" + fi + return 1 +} + +kpanel_system_resource_interface_action() { + local action="$1" + shift + local expected name desired old_state current_state version attempt + + [ "$action" = "state" ] || { + kpanel_system_resource_error "不支持的 network-interface 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + [ "$#" -eq 3 ] || { + kpanel_system_resource_error "network-interface state 需要 expected,name,up|down" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + expected="$1" + name="$2" + desired="$3" + [ "${#name}" -ge 1 ] && [ "${#name}" -le 15 ] && + kpanel_system_resource_single_line "$name" 15 && + kpanel_system_resource_interface_exists "$name" || { + kpanel_system_resource_error "网卡名称不在系统枚举中" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$desired" in up|down) ;; *) + kpanel_system_resource_error "网卡状态必须为 up 或 down" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version network-interface "$name")" + return 2 + ;; + esac + command -v ip >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少 ip 命令" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version network-interface "$name")" + return 2 + } + kpanel_system_resource_check_expected network-interface "$expected" "$name" || return $? + old_state="$(kpanel_system_resource_interface_admin_state "$name")" || { + kpanel_system_resource_error "无法读取网卡管理状态" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if [ "$old_state" = "$desired" ]; then + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if ! ip link set dev "$name" "$desired" >/dev/null 2>&1; then + kpanel_system_resource_interface_failure "$name" "$old_state" "网卡状态修改失败,正在恢复" + return 1 + fi + current_state="" + for attempt in 1 2 3 4 5; do + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + [ "$current_state" = "$desired" ] && break + sleep 0.1 + done + if [ "$current_state" != "$desired" ]; then + kpanel_system_resource_interface_failure "$name" "$old_state" "网卡状态回读验证失败,正在恢复" + return 1 + fi + version="$(kpanel_system_resource_interface_version "$name" 2>/dev/null)" || { + kpanel_system_resource_interface_failure "$name" "$old_state" "无法计算网卡资源版本,正在恢复" + return 1 + } + kpanel_system_resource_emit applied "$version" +} + +kpanel_system_resource_iptables() { + iptables -w 5 "$@" >/dev/null 2>&1 +} + +kpanel_system_resource_firewall_rule_exists() { + local chain="$1" + shift + kpanel_system_resource_iptables -C "$chain" "$@" +} + +kpanel_system_resource_firewall_delete_rule() { + local chain="$1" + shift + while kpanel_system_resource_firewall_rule_exists "$chain" "$@"; do + kpanel_system_resource_iptables -D "$chain" "$@" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + done +} + +kpanel_system_resource_firewall_ensure_rule() { + local placement="$1" + local chain="$2" + shift 2 + kpanel_system_resource_firewall_rule_exists "$chain" "$@" && return 0 + case "$placement" in + insert) kpanel_system_resource_iptables -I "$chain" 1 "$@" ;; + append) kpanel_system_resource_iptables -A "$chain" "$@" ;; + *) return 1 ;; + esac || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true +} + +kpanel_system_resource_firewall_chain_exists() { + kpanel_system_resource_iptables -S "$1" +} + +kpanel_system_resource_firewall_port() { + local value="$1" + [[ "$value" =~ ^[0-9]{1,5}$ ]] && + [ "$((10#$value))" -ge 1 ] && + [ "$((10#$value))" -le 65535 ] +} + +kpanel_system_resource_ssh_ports() { + local ports="" config + if command -v sshd >/dev/null 2>&1; then + ports="$(sshd -T 2>/dev/null | awk 'tolower($1) == "port" && $2 ~ /^[0-9]+$/ {print $2}')" + fi + if [ -z "$ports" ]; then + ports="$({ + for config in /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf; do + [ -f "$config" ] || continue + awk 'tolower($1) == "port" && $2 ~ /^[0-9]+$/ {print $2}' "$config" + done + } 2>/dev/null)" + fi + [ -n "$ports" ] || ports=22 + printf '%s\n' "$ports" | awk '/^[0-9]+$/ && $1 >= 1 && $1 <= 65535' | sort -nu +} + +kpanel_system_resource_firewall_open_port_rules() { + local port="$1" protocol + for protocol in tcp udp; do + kpanel_system_resource_firewall_delete_rule INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + done + for protocol in tcp udp; do + kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + done +} + +kpanel_system_resource_firewall_close_port_rules() { + local port="$1" protocol + for protocol in tcp udp; do + kpanel_system_resource_firewall_delete_rule INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + done + kpanel_system_resource_firewall_ensure_rule insert INPUT -i lo -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert FORWARD -i lo -j ACCEPT || return 1 + for protocol in tcp udp; do + kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + done +} + +kpanel_system_resource_firewall_allow_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j DROP || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -s "$address" -j ACCEPT || return 1 + kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP +} + +kpanel_system_resource_firewall_block_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -s "$address" -j DROP || return 1 + kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT +} + +kpanel_system_resource_firewall_remove_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j ACCEPT && + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j DROP || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP +} + +kpanel_system_resource_firewall_enable_ping_rules() { + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j DROP && + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT || return 1 + kpanel_system_resource_iptables -I INPUT 1 -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_iptables -I OUTPUT 1 -p icmp --icmp-type echo-reply -j ACCEPT || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_rule_exists OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT +} + +kpanel_system_resource_firewall_disable_ping_rules() { + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT && + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j DROP || return 1 + kpanel_system_resource_iptables -I INPUT 1 -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_iptables -I OUTPUT 1 -p icmp --icmp-type echo-reply -j DROP || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_rule_exists OUTPUT -p icmp --icmp-type echo-reply -j DROP +} + +kpanel_system_resource_firewall_enable_ddos_chain() { + local chain="$1" + kpanel_system_resource_firewall_disable_ddos_chain "$chain" || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p udp -j DROP || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p udp -m limit --limit 3000/s -j ACCEPT || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p tcp --syn -j DROP || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists "$chain" -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT && + kpanel_system_resource_firewall_rule_exists "$chain" -p tcp --syn -j DROP && + kpanel_system_resource_firewall_rule_exists "$chain" -p udp -m limit --limit 3000/s -j ACCEPT && + kpanel_system_resource_firewall_rule_exists "$chain" -p udp -j DROP +} + +kpanel_system_resource_firewall_disable_ddos_chain() { + local chain="$1" + kpanel_system_resource_firewall_delete_rule "$chain" -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT && + kpanel_system_resource_firewall_delete_rule "$chain" -p tcp --syn -j DROP && + kpanel_system_resource_firewall_delete_rule "$chain" -p udp -m limit --limit 3000/s -j ACCEPT && + kpanel_system_resource_firewall_delete_rule "$chain" -p udp -j DROP +} + +kpanel_system_resource_firewall_enable_ddos_rules() { + kpanel_system_resource_firewall_enable_ddos_chain INPUT || return 1 + if kpanel_system_resource_firewall_chain_exists DOCKER-USER; then + kpanel_system_resource_firewall_enable_ddos_chain DOCKER-USER || return 1 + fi +} + +kpanel_system_resource_firewall_disable_ddos_rules() { + kpanel_system_resource_firewall_disable_ddos_chain INPUT || return 1 + if kpanel_system_resource_firewall_chain_exists DOCKER-USER; then + kpanel_system_resource_firewall_disable_ddos_chain DOCKER-USER || return 1 + fi +} + +kpanel_system_resource_firewall_base_rules() { + local ssh_port + kpanel_system_resource_firewall_ensure_rule append INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append INPUT -i lo -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append FORWARD -i lo -j ACCEPT || return 1 + while IFS= read -r ssh_port; do + [ -n "$ssh_port" ] || continue + kpanel_system_resource_firewall_ensure_rule append INPUT -p tcp --dport "$ssh_port" -j ACCEPT || return 1 + done < <(kpanel_system_resource_ssh_ports) +} + +kpanel_system_resource_firewall_all_rules() { + local input_policy="$1" + kpanel_system_resource_iptables -F && + kpanel_system_resource_iptables -X || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_iptables -P OUTPUT ACCEPT || return 1 + if [ "$input_policy" = ACCEPT ]; then + kpanel_system_resource_iptables -P INPUT ACCEPT && + kpanel_system_resource_iptables -P FORWARD ACCEPT || return 1 + kpanel_system_resource_firewall_base_rules || return 1 + else + kpanel_system_resource_firewall_base_rules || return 1 + kpanel_system_resource_iptables -P INPUT DROP && + kpanel_system_resource_iptables -P FORWARD DROP || return 1 + fi + iptables -w 5 -S INPUT 2>/dev/null | grep -Fqx -- "-P INPUT $input_policy" && + iptables -w 5 -S FORWARD 2>/dev/null | grep -Fqx -- "-P FORWARD $input_policy" && + iptables -w 5 -S OUTPUT 2>/dev/null | grep -Fqx -- "-P OUTPUT ACCEPT" +} + +kpanel_system_resource_firewall_apply() { + local action="$1" + local value="${2:-}" + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=false + case "$action" in + open-port) kpanel_system_resource_firewall_open_port_rules "$value" ;; + close-port) kpanel_system_resource_firewall_close_port_rules "$value" ;; + allow-ip) kpanel_system_resource_firewall_allow_ip_rules "$value" ;; + block-ip) kpanel_system_resource_firewall_block_ip_rules "$value" ;; + remove-ip) kpanel_system_resource_firewall_remove_ip_rules "$value" ;; + open-all) kpanel_system_resource_firewall_all_rules ACCEPT ;; + close-all) kpanel_system_resource_firewall_all_rules DROP ;; + enable-ping) kpanel_system_resource_firewall_enable_ping_rules ;; + disable-ping) kpanel_system_resource_firewall_disable_ping_rules ;; + enable-ddos) kpanel_system_resource_firewall_enable_ddos_rules ;; + disable-ddos) kpanel_system_resource_firewall_disable_ddos_rules ;; + *) return 2 ;; + esac +} + +kpanel_system_resource_firewall_snapshot() { + local snapshot_dir="$1" + local rules_path="$2" + + kpanel_system_resource_firewall_capture "$snapshot_dir/iptables.rules" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED=false + if [ -e "$rules_path" ]; then + [ -f "$rules_path" ] && [ ! -L "$rules_path" ] || return 1 + cp -p -- "$rules_path" "$snapshot_dir/rules.v4" >/dev/null 2>&1 || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED=true + fi + kpanel_system_resource_cron_capture "$snapshot_dir/crontab" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CRON_EXISTED="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" +} + +kpanel_system_resource_firewall_persist() { + local snapshot_dir="$1" + local rules_path parent desired_rules verify_rules + local cron_current cron_desired cron_verify restore_line count current_line + + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=false + rules_path="$(kpanel_system_resource_iptables_rules_file)" + parent="$(dirname -- "$rules_path")" + mkdir -p -- "$parent" >/dev/null 2>&1 || return 1 + [ ! -L "$rules_path" ] || return 1 + desired_rules="$(mktemp "$parent/.rules.v4.kpanel.XXXXXX")" || return 1 + if ! kpanel_system_resource_firewall_capture "$desired_rules"; then + rm -f -- "$desired_rules" + return 1 + fi + if [ -f "$rules_path" ] && cmp -s -- "$desired_rules" "$rules_path"; then + rm -f -- "$desired_rules" + else + if [ -f "$rules_path" ]; then + kpanel_system_resource_copy_identity "$rules_path" "$desired_rules" || { + rm -f -- "$desired_rules" + return 1 + } + else + chmod 600 "$desired_rules" >/dev/null 2>&1 || { + rm -f -- "$desired_rules" + return 1 + } + fi + mv -f -- "$desired_rules" "$rules_path" >/dev/null 2>&1 || { + rm -f -- "$desired_rules" + return 1 + } + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true + fi + verify_rules="$snapshot_dir/iptables.persist.verify" + kpanel_system_resource_firewall_capture "$verify_rules" && + cmp -s -- "$verify_rules" "$rules_path" || return 1 + + restore_line='@reboot iptables-restore < /etc/iptables/rules.v4' + cron_current="$snapshot_dir/crontab.persist.current" + kpanel_system_resource_cron_capture "$cron_current" || return 1 + count="$(grep -Fxc -- "$restore_line" "$cron_current" 2>/dev/null || true)" + if [ "$count" -ne 1 ]; then + cron_desired="$snapshot_dir/crontab.persist.desired" + : > "$cron_desired" || return 1 + while IFS= read -r current_line || [ -n "$current_line" ]; do + [ "$current_line" = "$restore_line" ] && continue + printf '%s\n' "$current_line" >> "$cron_desired" || return 1 + done < "$cron_current" + if [ -s "$cron_desired" ] && [ "$(tail -c 1 "$cron_desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$cron_desired" || return 1 + fi + printf '%s\n' "$restore_line" >> "$cron_desired" || return 1 + kpanel_system_resource_file_within_bounds "$cron_desired" 262144 512 || return 1 + crontab "$cron_desired" >/dev/null 2>&1 || return 1 + cron_verify="$snapshot_dir/crontab.persist.verify" + kpanel_system_resource_cron_capture "$cron_verify" || return 1 + cmp -s -- "$cron_desired" "$cron_verify" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true + fi +} + +kpanel_system_resource_firewall_restore() { + local snapshot_dir="$1" + local rules_path="$2" + local rules_existed="$3" + local cron_existed="$4" + local verify="$snapshot_dir/rollback.iptables" + local cron_verify="$snapshot_dir/rollback.crontab" + local failed=false + + iptables-restore -w 5 < "$snapshot_dir/iptables.rules" >/dev/null 2>&1 || failed=true + if [ "$rules_existed" = true ]; then + cp -p -- "$snapshot_dir/rules.v4" "$rules_path" >/dev/null 2>&1 || failed=true + else + rm -f -- "$rules_path" >/dev/null 2>&1 || failed=true + fi + kpanel_system_resource_cron_restore "$snapshot_dir/crontab" "$cron_existed" "$cron_verify" || failed=true + kpanel_system_resource_firewall_capture "$verify" || failed=true + cmp -s -- "$snapshot_dir/iptables.rules" "$verify" || failed=true + if [ "$rules_existed" = true ]; then + cmp -s -- "$snapshot_dir/rules.v4" "$rules_path" || failed=true + else + [ ! -e "$rules_path" ] || failed=true + fi + [ "$failed" = false ] +} + +kpanel_system_resource_firewall_failure() { + local snapshot_dir="$1" + local rules_path="$2" + local rules_existed="$3" + local cron_existed="$4" + local message="$5" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_firewall_restore "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed"; then + version="$(kpanel_system_resource_best_version firewall)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version firewall)" + kpanel_system_resource_error "iptables 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_firewall_action() { + local action="$1" + shift + local expected value="" snapshot_dir rules_path rules_existed cron_existed final_version + local command_name + + for command_name in iptables iptables-save iptables-restore crontab; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少必要命令: $command_name" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + done + rules_path="$(kpanel_system_resource_iptables_rules_file)" + [ ! -L "$rules_path" ] || { + kpanel_system_resource_error "iptables 持久化文件不能是符号链接" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + case "$action" in + open-port|close-port) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "$action 需要 expected,value" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + value="$2" + kpanel_system_resource_firewall_port "$value" || { + kpanel_system_resource_error "防火墙端口必须为 1-65535" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + value=$((10#$value)) + ;; + allow-ip|block-ip|remove-ip) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "$action 需要 expected,value" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + value="$2" + kpanel_system_resource_is_ipv4_cidr "$value" || { + kpanel_system_resource_error "防火墙地址必须为 IPv4 或 IPv4 CIDR" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + ;; + open-all|close-all|enable-ping|disable-ping|enable-ddos|disable-ddos) + [ "$#" -eq 1 ] || { + kpanel_system_resource_error "$action 只需要 expected" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + ;; + *) + kpanel_system_resource_error "不支持的 firewall 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + ;; + esac + + kpanel_system_resource_check_expected firewall "$expected" || return $? + snapshot_dir="$(kpanel_system_resource_tempdir firewall)" || { + kpanel_system_resource_error "无法创建 firewall 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if ! kpanel_system_resource_firewall_snapshot "$snapshot_dir" "$rules_path"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 iptables/crontab 快照" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + rules_existed="$KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED" + cron_existed="$KPANEL_SYSTEM_RESOURCE_FIREWALL_CRON_EXISTED" + if ! kpanel_system_resource_firewall_apply "$action" "$value"; then + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "iptables 动作执行或回读验证失败" + return $? + fi + if ! kpanel_system_resource_firewall_persist "$snapshot_dir"; then + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "iptables 持久化失败" + return $? + fi + final_version="$(kpanel_system_resource_firewall_version 2>/dev/null)" || { + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "无法计算修改后的 iptables 版本" + return $? + } + if [ "$final_version" = "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" ] && + [ "$KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED" = false ]; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$final_version" + else + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$final_version" + fi +} + +kpanel_system_resource_run_locked() ( + local resource="$1" + local action="$2" + local lock_file lock_parent name="" + shift 2 + + lock_file="$(kpanel_system_resource_lock_file)" + lock_parent="$(dirname -- "$lock_file")" + mkdir -p -- "$lock_parent" >/dev/null 2>&1 || { + kpanel_system_resource_error "无法创建 system-resource 锁目录" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + return 1 + } + exec 9>"$lock_file" || { + kpanel_system_resource_error "无法打开 system-resource 锁" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + return 1 + } + if ! flock -w 30 -x 9 >/dev/null 2>&1; then + [ "$resource" = "network-interface" ] && name="${2:-}" + kpanel_system_resource_error "system-resource 写锁等待超时" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 1 + fi + case "$resource" in + hosts) kpanel_system_resource_hosts_action "$action" "$@" ;; + cron) kpanel_system_resource_cron_action "$action" "$@" ;; + network-interface) kpanel_system_resource_interface_action "$action" "$@" ;; + firewall) kpanel_system_resource_firewall_action "$action" "$@" ;; + *) + kpanel_system_resource_error "不支持的 system-resource 资源" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + ;; + esac +) + +kpanel_system_resource_dispatch() { + local resource="${1:-}" + local action="${2:-}" + local rc + + kpanel_system_resource_require_platform + rc=$? + [ "$rc" -eq 0 ] || return "$rc" + [ "$#" -ge 2 ] || { + kpanel_system_resource_error "用法: kpanel system-resource ..." + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$resource" in + hosts|cron|network-interface|firewall) ;; + *) + kpanel_system_resource_error "不支持的 system-resource 资源" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + ;; + esac + shift 2 + kpanel_system_resource_run_locked "$resource" "$action" "$@" +} + +# KPanel system resource protocol end + + log_menu() { send_stats "系统日志管理工具" @@ -24600,8 +26083,11 @@ else if [ "${1:-}" = "node" ]; then shift kpanel_node_dispatch "$@" + elif [ "${1:-}" = "system-resource" ]; then + shift + kpanel_system_resource_dispatch "$@" else - echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + echo "用法: k kpanel node join <授权> | status | update | uninstall;或 k kpanel system-resource ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/kejilion.sh b/kejilion.sh index 5f17a84fd..a4266a23e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -24,6 +24,7 @@ kpanel_protocol_active() { [ "${KJ_LIGHT_NODE_PROTOCOL:-}" = "1" ] || [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || @@ -22128,6 +22129,1488 @@ net_menu() { +# KPanel system resource protocol start +kpanel_system_resource_zero_version() { + printf '%064d' 0 +} + +kpanel_system_resource_emit() { + local status="$1" + local version="$2" + local backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_SYSTEM_RESOURCE_STATUS=%s\n' "$status" + printf 'KPANEL_SYSTEM_RESOURCE_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_SYSTEM_RESOURCE_BACKUP=%s\n' "$backup" +} + +kpanel_system_resource_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_system_resource_valid_version() { + [[ "$1" =~ ^[0-9a-f]{64}$ ]] +} + +kpanel_system_resource_single_line() { + local value="$1" + local maximum="$2" + local bytes + bytes="$(printf '%s' "$value" | wc -c)" || return 1 + [ "$bytes" -le "$maximum" ] && + [[ "$value" != *$'\n'* ]] && + [[ "$value" != *$'\r'* ]] +} + +kpanel_system_resource_copy_identity() { + local source="$1" + local target="$2" + local mode owner + mode="$(stat -c '%a' "$source" 2>/dev/null)" || return 1 + owner="$(stat -c '%u:%g' "$source" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || return 1 + chown "$owner" "$target" >/dev/null 2>&1 && + chmod "$mode" "$target" >/dev/null 2>&1 +} + +kpanel_system_resource_file_within_bounds() { + local path="$1" + local maximum_bytes="$2" + local maximum_lines="$3" + local bytes lines + bytes="$(wc -c < "$path" 2>/dev/null)" || return 1 + lines="$(awk 'END {print NR + 0}' "$path" 2>/dev/null)" || return 1 + [ "$bytes" -le "$maximum_bytes" ] && [ "$lines" -le "$maximum_lines" ] +} + +kpanel_system_resource_hosts_file() { + printf '%s\n' "/etc/hosts" +} + +kpanel_system_resource_lock_file() { + printf '%s\n' "/run/lock/kejilion-system-resource.lock" +} + +kpanel_system_resource_interfaces_dir() { + printf '%s\n' "/sys/class/net" +} + +kpanel_system_resource_iptables_rules_file() { + printf '%s\n' "/etc/iptables/rules.v4" +} + +kpanel_system_resource_tempdir() { + local resource="$1" + local directory + directory="$(mktemp -d "/tmp/kejilion-system-resource-${resource}.XXXXXX")" || return 1 + chmod 700 "$directory" || { + rm -rf -- "$directory" + return 1 + } + printf '%s\n' "$directory" +} + +kpanel_system_resource_is_ipv4() { + local value="$1" + local first second third fourth extra octet + IFS=. read -r first second third fourth extra <<< "$value" + [ -z "$extra" ] || return 1 + for octet in "$first" "$second" "$third" "$fourth"; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1 + [ "$octet" = "0" ] || [[ "$octet" != 0* ]] || return 1 + [ "$((10#$octet))" -le 255 ] || return 1 + done +} + +kpanel_system_resource_ipv6_side_count() { + local side="$1" + local part index count=0 + local parts=() + [ -n "$side" ] || { + printf '0\n' + return 0 + } + [[ "$side" != :* && "$side" != *: ]] || return 1 + IFS=: read -r -a parts <<< "$side" + for index in "${!parts[@]}"; do + part="${parts[$index]}" + [ -n "$part" ] || return 1 + if [[ "$part" == *.* ]]; then + [ "$index" -eq "$((${#parts[@]} - 1))" ] || return 1 + kpanel_system_resource_is_ipv4 "$part" || return 1 + count=$((count + 2)) + else + [[ "$part" =~ ^[0-9A-Fa-f]{1,4}$ ]] || return 1 + count=$((count + 1)) + fi + done + printf '%s\n' "$count" +} + +kpanel_system_resource_is_ipv6() { + local value="$1" + local left right left_count right_count total + [ -n "$value" ] && [ "${#value}" -le 45 ] && + [[ "$value" == *:* ]] && + [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] || return 1 + if [[ "$value" == *::* ]]; then + [[ "${value/::/}" != *::* ]] || return 1 + left="${value%%::*}" + right="${value#*::}" + left_count="$(kpanel_system_resource_ipv6_side_count "$left")" || return 1 + right_count="$(kpanel_system_resource_ipv6_side_count "$right")" || return 1 + total=$((left_count + right_count)) + [ "$total" -lt 8 ] + else + [[ "$value" != :* && "$value" != *: ]] || return 1 + total="$(kpanel_system_resource_ipv6_side_count "$value")" || return 1 + [ "$total" -eq 8 ] + fi +} + +kpanel_system_resource_is_hostname() { + local value="$1" + local label + local labels=() + [ -n "$value" ] && [ "${#value}" -le 253 ] || return 1 + value="${value%.}" + [ -n "$value" ] || return 1 + IFS=. read -r -a labels <<< "$value" + for label in "${labels[@]}"; do + [ -n "$label" ] && [ "${#label}" -le 63 ] || return 1 + [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || return 1 + done +} + +kpanel_system_resource_is_ipv4_cidr() { + local value="$1" + local address prefix + if [[ "$value" == */* ]]; then + [ "${value//[^\/]/}" = "/" ] || return 1 + address="${value%/*}" + prefix="${value##*/}" + [[ "$prefix" =~ ^[0-9]{1,2}$ ]] && + { [ "$prefix" = "0" ] || [[ "$prefix" != 0* ]]; } && + [ "$((10#$prefix))" -le 32 ] || return 1 + else + address="$value" + fi + kpanel_system_resource_is_ipv4 "$address" +} + +kpanel_system_resource_hosts_version() { + local path + path="$(kpanel_system_resource_hosts_file)" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + sha256sum -- "$path" 2>/dev/null | awk '{print $1}' +} + +kpanel_system_resource_cron_capture() { + local target="$1" + local error_file="$target.error" + local rc=0 + KPANEL_SYSTEM_RESOURCE_CRON_EXISTED=false + LC_ALL=C crontab -l > "$target" 2>"$error_file" || rc=$? + if [ "$rc" -eq 0 ]; then + KPANEL_SYSTEM_RESOURCE_CRON_EXISTED=true + elif grep -Fqi 'no crontab for' "$error_file"; then + : > "$target" || { + rm -f -- "$error_file" + return 1 + } + else + rm -f -- "$error_file" + return 1 + fi + rm -f -- "$error_file" + kpanel_system_resource_file_within_bounds "$target" 262144 512 +} + +kpanel_system_resource_cron_version() { + local temporary version + temporary="$(mktemp /tmp/kejilion-system-resource-cron-version.XXXXXX)" || return 1 + if ! kpanel_system_resource_cron_capture "$temporary"; then + rm -f -- "$temporary" + return 1 + fi + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + rm -f -- "$temporary" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_system_resource_interface_exists() { + local name="$1" + local root candidate + root="$(kpanel_system_resource_interfaces_dir)" + [ -d "$root" ] || return 1 + for candidate in "$root"/*; do + [ -e "$candidate" ] || continue + [ "$(basename -- "$candidate")" = "$name" ] && return 0 + done + return 1 +} + +kpanel_system_resource_interface_version() { + local name="$1" + local root state mac + kpanel_system_resource_interface_exists "$name" || return 1 + root="$(kpanel_system_resource_interfaces_dir)" + state="$(kpanel_system_resource_interface_admin_state "$name")" || return 1 + mac="$(cat "$root/$name/address" 2>/dev/null)" || return 1 + printf '%s|%s|%s' "$name" "$state" "$mac" | sha256sum | awk '{print $1}' +} + +kpanel_system_resource_firewall_version() { + local temporary version + temporary="$(mktemp /tmp/kejilion-system-resource-firewall-version.XXXXXX)" || return 1 + if ! kpanel_system_resource_firewall_capture "$temporary"; then + rm -f -- "$temporary" + return 1 + fi + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + rm -f -- "$temporary" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_system_resource_firewall_capture() { + local target="$1" + local bytes + iptables-save > "$target" 2>/dev/null || return 1 + bytes="$(wc -c < "$target" 2>/dev/null)" || return 1 + [ "$bytes" -le 524288 ] +} + +kpanel_system_resource_best_version() { + local resource="$1" + local name="${2:-}" + local version="" + case "$resource" in + hosts) version="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" ;; + cron) version="$(kpanel_system_resource_cron_version 2>/dev/null || true)" ;; + network-interface) + [ -z "$name" ] || version="$(kpanel_system_resource_interface_version "$name" 2>/dev/null || true)" + ;; + firewall) version="$(kpanel_system_resource_firewall_version 2>/dev/null || true)" ;; + esac + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf '%s\n' "$version" +} + +kpanel_system_resource_check_expected() { + local resource="$1" + local expected="$2" + local name="${3:-}" + local current + kpanel_system_resource_valid_version "$expected" || { + kpanel_system_resource_error "expectedResourceVersion 必须为 64 位小写十六进制" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 2 + } + case "$resource" in + hosts) current="$(kpanel_system_resource_hosts_version 2>/dev/null)" ;; + cron) current="$(kpanel_system_resource_cron_version 2>/dev/null)" ;; + network-interface) current="$(kpanel_system_resource_interface_version "$name" 2>/dev/null)" ;; + firewall) current="$(kpanel_system_resource_firewall_version 2>/dev/null)" ;; + *) return 2 ;; + esac || { + kpanel_system_resource_error "无法读取当前资源版本" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 1 + } + if [ "$current" != "$expected" ]; then + kpanel_system_resource_error "资源版本已变化,请刷新后重试" + kpanel_system_resource_emit conflict "$current" + return 2 + fi + KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION="$current" +} + +kpanel_system_resource_require_platform() { + local command_name + if [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" != "1" ]; then + kpanel_system_resource_error "KPanel system-resource 协议环境未启用" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + if [ "$EUID" -ne 0 ]; then + kpanel_system_resource_error "KPanel system-resource 协议必须以 root 运行" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + if [ "$(uname -s 2>/dev/null)" != "Linux" ]; then + kpanel_system_resource_error "KPanel system-resource 协议仅支持 Linux" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi + for command_name in sha256sum mktemp flock; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少必要命令: $command_name" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + done +} + +kpanel_system_resource_hosts_build_line() { + local address="$1" + local hostnames_csv="$2" + local comment="$3" + local hostname joined + local hostnames=() + + kpanel_system_resource_is_ipv4 "$address" || + kpanel_system_resource_is_ipv6 "$address" || return 1 + kpanel_system_resource_single_line "$hostnames_csv" 1024 && + [ -n "$hostnames_csv" ] || return 1 + [[ "$hostnames_csv" != ,* && "$hostnames_csv" != *, && "$hostnames_csv" != *,,* ]] || return 1 + IFS=, read -r -a hostnames <<< "$hostnames_csv" + [ "${#hostnames[@]}" -ge 1 ] && [ "${#hostnames[@]}" -le 16 ] || return 1 + for hostname in "${hostnames[@]}"; do + kpanel_system_resource_is_hostname "$hostname" || return 1 + done + kpanel_system_resource_single_line "$comment" 256 || return 1 + joined="$(IFS=' '; printf '%s' "${hostnames[*]}")" + KPANEL_SYSTEM_RESOURCE_HOSTS_LINE="$address"$'\t'"$joined" + [ -z "$comment" ] || + KPANEL_SYSTEM_RESOURCE_HOSTS_LINE="$KPANEL_SYSTEM_RESOURCE_HOSTS_LINE # $comment" +} + +kpanel_system_resource_restore_hosts() { + local path="$1" + local backup="$2" + local expected_version="$3" + local current + current="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" + [ "$current" = "$expected_version" ] && return 0 + cp -p -- "$backup" "$path" >/dev/null 2>&1 || return 1 + current="$(kpanel_system_resource_hosts_version 2>/dev/null || true)" + [ "$current" = "$expected_version" ] +} + +kpanel_system_resource_hosts_failure() { + local path="$1" + local backup="$2" + local snapshot_dir="$3" + local original_version="$4" + local message="$5" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_restore_hosts "$path" "$backup" "$original_version"; then + version="$(kpanel_system_resource_best_version hosts)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version hosts)" + kpanel_system_resource_error "hosts 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_hosts_action() { + local action="$1" + shift + local expected path line line_number snapshot_dir backup desired desired_version current_line + local index=0 total_lines + local address hostnames_csv comment + local hosts_trailing_newline=true + + path="$(kpanel_system_resource_hosts_file)" + [ -f "$path" ] && [ ! -L "$path" ] || { + kpanel_system_resource_error "未找到可安全管理的 hosts 文件" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + kpanel_system_resource_file_within_bounds "$path" 262144 1024 || { + kpanel_system_resource_error "hosts 超过 256KiB 或 1024 行协议上限" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + case "$action" in + add) + [ "$#" -eq 4 ] || { + kpanel_system_resource_error "hosts add 需要 expected,address,hostnamesCSV,comment" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + expected="$1" + address="$2" + hostnames_csv="$3" + comment="$4" + kpanel_system_resource_hosts_build_line "$address" "$hostnames_csv" "$comment" || { + kpanel_system_resource_error "hosts 地址、主机名或注释无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + line="$KPANEL_SYSTEM_RESOURCE_HOSTS_LINE" + ;; + delete) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "hosts delete 需要 expected,line" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + expected="$1" + line_number="$2" + [[ "$line_number" =~ ^[0-9]{1,4}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 1024 ] || { + kpanel_system_resource_error "hosts 行号必须为 1-1024" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + } + line_number=$((10#$line_number)) + ;; + *) + kpanel_system_resource_error "不支持的 hosts 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version hosts)" + return 2 + ;; + esac + + kpanel_system_resource_check_expected hosts "$expected" || return $? + if [ "$action" = "add" ] && grep -Fqx -- "$line" "$path"; then + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if [ "$action" = "delete" ]; then + total_lines="$(awk 'END {print NR + 0}' "$path")" + if [ "$line_number" -gt "$total_lines" ]; then + kpanel_system_resource_error "hosts 行号超出当前文件范围" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + if [ -s "$path" ] && [ "$(tail -c 1 "$path" | wc -l)" -eq 0 ]; then + hosts_trailing_newline=false + fi + fi + + snapshot_dir="$(kpanel_system_resource_tempdir hosts)" || { + kpanel_system_resource_error "无法创建 hosts 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + backup="$snapshot_dir/hosts.backup" + cp -p -- "$path" "$backup" >/dev/null 2>&1 || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法备份 hosts" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + desired="$(mktemp "$(dirname -- "$path")/.hosts.kpanel.XXXXXX")" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 hosts 临时文件" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + + if [ "$action" = "add" ]; then + cp -- "$path" "$desired" >/dev/null 2>&1 || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法复制 hosts" + return $? + } + if [ -s "$desired" ] && [ "$(tail -c 1 "$desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法生成 hosts" + return $? + } + fi + printf '%s\n' "$line" >> "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法写入 hosts" + return $? + } + else + : > "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法生成 hosts" + return $? + } + while IFS= read -r current_line || [ -n "$current_line" ]; do + index=$((index + 1)) + if [ "$index" -eq "$line_number" ]; then + continue + fi + if [ "$index" -eq "$total_lines" ] && [ "$hosts_trailing_newline" = false ]; then + printf '%s' "$current_line" >> "$desired" + else + printf '%s\n' "$current_line" >> "$desired" + fi || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法重写 hosts" + return $? + } + done < "$path" + fi + kpanel_system_resource_file_within_bounds "$desired" 262144 1024 || { + rm -f -- "$desired" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "修改后的 hosts 超过 256KiB 或 1024 行协议上限" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + } + + kpanel_system_resource_copy_identity "$path" "$desired" || { + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "无法保留 hosts 权限或属主" + return $? + } + desired_version="$(sha256sum -- "$desired" 2>/dev/null | awk '{print $1}')" + if ! kpanel_system_resource_valid_version "$desired_version"; then + rm -f -- "$desired" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法计算修改后的 hosts 版本" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + if ! mv -f -- "$desired" "$path" >/dev/null 2>&1 || + [ "$(kpanel_system_resource_hosts_version 2>/dev/null)" != "$desired_version" ]; then + rm -f -- "$desired" + kpanel_system_resource_hosts_failure "$path" "$backup" "$snapshot_dir" "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" "hosts 原子写入或回读验证失败" + return $? + fi + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$desired_version" +} + +kpanel_system_resource_cron_number_in_range() { + local value="$1" + local minimum="$2" + local maximum="$3" + [[ "$value" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$value))" -ge "$minimum" ] && + [ "$((10#$value))" -le "$maximum" ] +} + +kpanel_system_resource_cron_value_in_range() { + local value="$1" + local minimum="$2" + local maximum="$3" + local kind="$4" + local numeric="" + + if [[ "$value" =~ ^[0-9]{1,3}$ ]]; then + numeric=$((10#$value)) + else + case "$kind:${value^^}" in + month:JAN) numeric=1 ;; month:FEB) numeric=2 ;; month:MAR) numeric=3 ;; + month:APR) numeric=4 ;; month:MAY) numeric=5 ;; month:JUN) numeric=6 ;; + month:JUL) numeric=7 ;; month:AUG) numeric=8 ;; month:SEP) numeric=9 ;; + month:OCT) numeric=10 ;; month:NOV) numeric=11 ;; month:DEC) numeric=12 ;; + weekday:SUN) numeric=0 ;; weekday:MON) numeric=1 ;; weekday:TUE) numeric=2 ;; + weekday:WED) numeric=3 ;; weekday:THU) numeric=4 ;; weekday:FRI) numeric=5 ;; + weekday:SAT) numeric=6 ;; + *) return 1 ;; + esac + fi + [ "$numeric" -ge "$minimum" ] && [ "$numeric" -le "$maximum" ] || return 1 + KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE="$numeric" +} + +kpanel_system_resource_cron_field() { + local field="$1" + local minimum="$2" + local maximum="$3" + local kind="$4" + local item base step start end start_numeric end_numeric + local items=() + + IFS=, read -r -a items <<< "$field" + [ "${#items[@]}" -ge 1 ] || return 1 + for item in "${items[@]}"; do + [ -n "$item" ] || return 1 + base="$item" + if [[ "$item" == */* ]]; then + base="${item%%/*}" + step="${item#*/}" + [[ "$step" != */* ]] && + kpanel_system_resource_cron_number_in_range "$step" 1 "$maximum" || return 1 + fi + if [ "$base" = "*" ]; then + continue + elif [[ "$base" == *-* ]]; then + start="${base%%-*}" + end="${base#*-}" + [[ "$end" != *-* ]] && + kpanel_system_resource_cron_value_in_range "$start" "$minimum" "$maximum" "$kind" || return 1 + start_numeric="$KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE" + kpanel_system_resource_cron_value_in_range "$end" "$minimum" "$maximum" "$kind" || return 1 + end_numeric="$KPANEL_SYSTEM_RESOURCE_CRON_NUMERIC_VALUE" + [ "$start_numeric" -le "$end_numeric" ] || return 1 + else + kpanel_system_resource_cron_value_in_range "$base" "$minimum" "$maximum" "$kind" || return 1 + fi + done +} + +kpanel_system_resource_cron_expression() { + local expression="$1" + local fields=() + + kpanel_system_resource_single_line "$expression" 128 && [ -n "$expression" ] || return 1 + case "$expression" in + @reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly) + KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="$expression" + return 0 + ;; + esac + read -r -a fields <<< "$expression" + [ "${#fields[@]}" -eq 5 ] || return 1 + kpanel_system_resource_cron_field "${fields[0]}" 0 59 numeric && + kpanel_system_resource_cron_field "${fields[1]}" 0 23 numeric && + kpanel_system_resource_cron_field "${fields[2]}" 1 31 numeric && + kpanel_system_resource_cron_field "${fields[3]}" 1 12 month && + kpanel_system_resource_cron_field "${fields[4]}" 0 7 weekday || return 1 + KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="${fields[*]}" +} + +kpanel_system_resource_cron_restore() { + local backup="$1" + local existed="$2" + local verify="$3" + + if [ "$existed" = true ]; then + crontab "$backup" >/dev/null 2>&1 || return 1 + else + crontab -r >/dev/null 2>&1 || true + fi + kpanel_system_resource_cron_capture "$verify" || return 1 + cmp -s -- "$backup" "$verify" +} + +kpanel_system_resource_cron_failure() { + local snapshot_dir="$1" + local backup="$2" + local existed="$3" + local message="$4" + local verify="$snapshot_dir/rollback.verify" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_cron_restore "$backup" "$existed" "$verify"; then + version="$(kpanel_system_resource_best_version cron)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version cron)" + kpanel_system_resource_error "crontab 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_cron_action() { + local action="$1" + shift + local expected line_number expression command_value trimmed_command new_line snapshot_dir backup desired verify + local cron_existed current_line index=0 total_lines + + command -v crontab >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少 crontab 命令" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$action" in + add) + [ "$#" -eq 3 ] || { + kpanel_system_resource_error "cron add 需要 expected,expression,command" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + expression="$2" + command_value="$3" + ;; + update) + [ "$#" -eq 4 ] || { + kpanel_system_resource_error "cron update 需要 expected,line,expression,command" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + line_number="$2" + expression="$3" + command_value="$4" + [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 512 ] || { + kpanel_system_resource_error "cron 行号必须为 1-512" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + line_number=$((10#$line_number)) + ;; + delete) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "cron delete 需要 expected,line" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + expected="$1" + line_number="$2" + [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && + [ "$((10#$line_number))" -ge 1 ] && + [ "$((10#$line_number))" -le 512 ] || { + kpanel_system_resource_error "cron 行号必须为 1-512" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + line_number=$((10#$line_number)) + ;; + *) + kpanel_system_resource_error "不支持的 cron 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + ;; + esac + + if [ "$action" != "delete" ]; then + trimmed_command="$command_value" + trimmed_command="${trimmed_command#"${trimmed_command%%[![:space:]]*}"}" + trimmed_command="${trimmed_command%"${trimmed_command##*[![:space:]]}"}" + kpanel_system_resource_cron_expression "$expression" && + kpanel_system_resource_single_line "$command_value" 2048 && + [ -n "$trimmed_command" ] || { + kpanel_system_resource_error "cron 表达式或命令无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + new_line="$KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION $command_value" + fi + kpanel_system_resource_check_expected cron "$expected" || return $? + + snapshot_dir="$(kpanel_system_resource_tempdir cron)" || { + kpanel_system_resource_error "无法创建 cron 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + backup="$snapshot_dir/crontab.backup" + kpanel_system_resource_cron_capture "$backup" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法读取当前 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" + + if [ "$action" = "add" ] && grep -Fqx -- "$new_line" "$backup"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if [ "$action" != "add" ]; then + total_lines="$(awk 'END {print NR + 0}' "$backup")" + if [ "$line_number" -gt "$total_lines" ]; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "cron 行号超出当前 crontab 范围" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + fi + + desired="$snapshot_dir/crontab.desired" + if [ "$action" = "add" ]; then + cp -- "$backup" "$desired" >/dev/null 2>&1 || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法复制当前 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if [ -s "$desired" ] && [ "$(tail -c 1 "$desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$desired" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法生成 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + fi + printf '%s\n' "$new_line" >> "$desired" || { + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" + return $? + } + else + : > "$desired" || { + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 crontab 目标文件" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + while IFS= read -r current_line || [ -n "$current_line" ]; do + index=$((index + 1)) + if [ "$index" -eq "$line_number" ]; then + if [ "$action" != "delete" ] && ! printf '%s\n' "$new_line" >> "$desired"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法生成 crontab" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + continue + fi + printf '%s\n' "$current_line" >> "$desired" || { + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" + return $? + } + done < "$backup" + fi + if ! kpanel_system_resource_file_within_bounds "$desired" 262144 512; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "修改后的 crontab 超过 256KiB 或 512 行协议上限" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + if cmp -s -- "$backup" "$desired"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + + if ! crontab "$desired" >/dev/null 2>&1; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 安装失败" + return $? + fi + verify="$snapshot_dir/crontab.verify" + if ! kpanel_system_resource_cron_capture "$verify"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 回读失败" + return $? + fi + if ! cmp -s -- "$desired" "$verify"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "crontab 回读验证失败" + return $? + fi + local applied_version + applied_version="$(sha256sum -- "$verify" 2>/dev/null | awk '{print $1}')" + if ! kpanel_system_resource_valid_version "$applied_version"; then + kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法计算 crontab 版本" + return $? + fi + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$applied_version" +} + +kpanel_system_resource_interface_admin_state() { + local name="$1" + local root flags numeric + root="$(kpanel_system_resource_interfaces_dir)" + flags="$(cat "$root/$name/flags" 2>/dev/null)" || return 1 + [[ "$flags" =~ ^0x[0-9A-Fa-f]+$ ]] || return 1 + numeric=$((flags)) + if [ "$((numeric & 1))" -eq 1 ]; then + printf 'up\n' + else + printf 'down\n' + fi +} + +kpanel_system_resource_interface_failure() { + local name="$1" + local old_state="$2" + local message="$3" + local current_state="" version attempt + + kpanel_system_resource_error "$message" + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + if [ "$current_state" != "$old_state" ]; then + ip link set dev "$name" "$old_state" >/dev/null 2>&1 || true + for attempt in 1 2 3 4 5; do + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + [ "$current_state" = "$old_state" ] && break + sleep 0.1 + done + fi + version="$(kpanel_system_resource_best_version network-interface "$name")" + if [ "$current_state" = "$old_state" ]; then + kpanel_system_resource_emit failed "$version" + else + kpanel_system_resource_error "网卡状态回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" + fi + return 1 +} + +kpanel_system_resource_interface_action() { + local action="$1" + shift + local expected name desired old_state current_state version attempt + + [ "$action" = "state" ] || { + kpanel_system_resource_error "不支持的 network-interface 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + [ "$#" -eq 3 ] || { + kpanel_system_resource_error "network-interface state 需要 expected,name,up|down" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + expected="$1" + name="$2" + desired="$3" + [ "${#name}" -ge 1 ] && [ "${#name}" -le 15 ] && + kpanel_system_resource_single_line "$name" 15 && + kpanel_system_resource_interface_exists "$name" || { + kpanel_system_resource_error "网卡名称不在系统枚举中" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$desired" in up|down) ;; *) + kpanel_system_resource_error "网卡状态必须为 up 或 down" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version network-interface "$name")" + return 2 + ;; + esac + command -v ip >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少 ip 命令" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version network-interface "$name")" + return 2 + } + kpanel_system_resource_check_expected network-interface "$expected" "$name" || return $? + old_state="$(kpanel_system_resource_interface_admin_state "$name")" || { + kpanel_system_resource_error "无法读取网卡管理状态" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if [ "$old_state" = "$desired" ]; then + kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 0 + fi + if ! ip link set dev "$name" "$desired" >/dev/null 2>&1; then + kpanel_system_resource_interface_failure "$name" "$old_state" "网卡状态修改失败,正在恢复" + return 1 + fi + current_state="" + for attempt in 1 2 3 4 5; do + current_state="$(kpanel_system_resource_interface_admin_state "$name" 2>/dev/null || true)" + [ "$current_state" = "$desired" ] && break + sleep 0.1 + done + if [ "$current_state" != "$desired" ]; then + kpanel_system_resource_interface_failure "$name" "$old_state" "网卡状态回读验证失败,正在恢复" + return 1 + fi + version="$(kpanel_system_resource_interface_version "$name" 2>/dev/null)" || { + kpanel_system_resource_interface_failure "$name" "$old_state" "无法计算网卡资源版本,正在恢复" + return 1 + } + kpanel_system_resource_emit applied "$version" +} + +kpanel_system_resource_iptables() { + iptables -w 5 "$@" >/dev/null 2>&1 +} + +kpanel_system_resource_firewall_rule_exists() { + local chain="$1" + shift + kpanel_system_resource_iptables -C "$chain" "$@" +} + +kpanel_system_resource_firewall_delete_rule() { + local chain="$1" + shift + while kpanel_system_resource_firewall_rule_exists "$chain" "$@"; do + kpanel_system_resource_iptables -D "$chain" "$@" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + done +} + +kpanel_system_resource_firewall_ensure_rule() { + local placement="$1" + local chain="$2" + shift 2 + kpanel_system_resource_firewall_rule_exists "$chain" "$@" && return 0 + case "$placement" in + insert) kpanel_system_resource_iptables -I "$chain" 1 "$@" ;; + append) kpanel_system_resource_iptables -A "$chain" "$@" ;; + *) return 1 ;; + esac || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true +} + +kpanel_system_resource_firewall_chain_exists() { + kpanel_system_resource_iptables -S "$1" +} + +kpanel_system_resource_firewall_port() { + local value="$1" + [[ "$value" =~ ^[0-9]{1,5}$ ]] && + [ "$((10#$value))" -ge 1 ] && + [ "$((10#$value))" -le 65535 ] +} + +kpanel_system_resource_ssh_ports() { + local ports="" config + if command -v sshd >/dev/null 2>&1; then + ports="$(sshd -T 2>/dev/null | awk 'tolower($1) == "port" && $2 ~ /^[0-9]+$/ {print $2}')" + fi + if [ -z "$ports" ]; then + ports="$({ + for config in /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf; do + [ -f "$config" ] || continue + awk 'tolower($1) == "port" && $2 ~ /^[0-9]+$/ {print $2}' "$config" + done + } 2>/dev/null)" + fi + [ -n "$ports" ] || ports=22 + printf '%s\n' "$ports" | awk '/^[0-9]+$/ && $1 >= 1 && $1 <= 65535' | sort -nu +} + +kpanel_system_resource_firewall_open_port_rules() { + local port="$1" protocol + for protocol in tcp udp; do + kpanel_system_resource_firewall_delete_rule INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + done + for protocol in tcp udp; do + kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + done +} + +kpanel_system_resource_firewall_close_port_rules() { + local port="$1" protocol + for protocol in tcp udp; do + kpanel_system_resource_firewall_delete_rule INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + done + kpanel_system_resource_firewall_ensure_rule insert INPUT -i lo -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert FORWARD -i lo -j ACCEPT || return 1 + for protocol in tcp udp; do + kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j DROP || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -p "$protocol" --dport "$port" -j ACCEPT || return 1 + done +} + +kpanel_system_resource_firewall_allow_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j DROP || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -s "$address" -j ACCEPT || return 1 + kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP +} + +kpanel_system_resource_firewall_block_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j ACCEPT || return 1 + kpanel_system_resource_firewall_ensure_rule insert INPUT -s "$address" -j DROP || return 1 + kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT +} + +kpanel_system_resource_firewall_remove_ip_rules() { + local address="$1" + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j ACCEPT && + kpanel_system_resource_firewall_delete_rule INPUT -s "$address" -j DROP || return 1 + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j ACCEPT && + ! kpanel_system_resource_firewall_rule_exists INPUT -s "$address" -j DROP +} + +kpanel_system_resource_firewall_enable_ping_rules() { + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j DROP && + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT || return 1 + kpanel_system_resource_iptables -I INPUT 1 -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_iptables -I OUTPUT 1 -p icmp --icmp-type echo-reply -j ACCEPT || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_rule_exists OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT +} + +kpanel_system_resource_firewall_disable_ping_rules() { + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j ACCEPT && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT && + kpanel_system_resource_firewall_delete_rule INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_delete_rule OUTPUT -p icmp --icmp-type echo-reply -j DROP || return 1 + kpanel_system_resource_iptables -I INPUT 1 -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_iptables -I OUTPUT 1 -p icmp --icmp-type echo-reply -j DROP || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists INPUT -p icmp --icmp-type echo-request -j DROP && + kpanel_system_resource_firewall_rule_exists OUTPUT -p icmp --icmp-type echo-reply -j DROP +} + +kpanel_system_resource_firewall_enable_ddos_chain() { + local chain="$1" + kpanel_system_resource_firewall_disable_ddos_chain "$chain" || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p udp -j DROP || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p udp -m limit --limit 3000/s -j ACCEPT || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p tcp --syn -j DROP || return 1 + kpanel_system_resource_iptables -I "$chain" 1 -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_firewall_rule_exists "$chain" -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT && + kpanel_system_resource_firewall_rule_exists "$chain" -p tcp --syn -j DROP && + kpanel_system_resource_firewall_rule_exists "$chain" -p udp -m limit --limit 3000/s -j ACCEPT && + kpanel_system_resource_firewall_rule_exists "$chain" -p udp -j DROP +} + +kpanel_system_resource_firewall_disable_ddos_chain() { + local chain="$1" + kpanel_system_resource_firewall_delete_rule "$chain" -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT && + kpanel_system_resource_firewall_delete_rule "$chain" -p tcp --syn -j DROP && + kpanel_system_resource_firewall_delete_rule "$chain" -p udp -m limit --limit 3000/s -j ACCEPT && + kpanel_system_resource_firewall_delete_rule "$chain" -p udp -j DROP +} + +kpanel_system_resource_firewall_enable_ddos_rules() { + kpanel_system_resource_firewall_enable_ddos_chain INPUT || return 1 + if kpanel_system_resource_firewall_chain_exists DOCKER-USER; then + kpanel_system_resource_firewall_enable_ddos_chain DOCKER-USER || return 1 + fi +} + +kpanel_system_resource_firewall_disable_ddos_rules() { + kpanel_system_resource_firewall_disable_ddos_chain INPUT || return 1 + if kpanel_system_resource_firewall_chain_exists DOCKER-USER; then + kpanel_system_resource_firewall_disable_ddos_chain DOCKER-USER || return 1 + fi +} + +kpanel_system_resource_firewall_base_rules() { + local ssh_port + kpanel_system_resource_firewall_ensure_rule append INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append INPUT -i lo -j ACCEPT && + kpanel_system_resource_firewall_ensure_rule append FORWARD -i lo -j ACCEPT || return 1 + while IFS= read -r ssh_port; do + [ -n "$ssh_port" ] || continue + kpanel_system_resource_firewall_ensure_rule append INPUT -p tcp --dport "$ssh_port" -j ACCEPT || return 1 + done < <(kpanel_system_resource_ssh_ports) +} + +kpanel_system_resource_firewall_all_rules() { + local input_policy="$1" + kpanel_system_resource_iptables -F && + kpanel_system_resource_iptables -X || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=true + kpanel_system_resource_iptables -P OUTPUT ACCEPT || return 1 + if [ "$input_policy" = ACCEPT ]; then + kpanel_system_resource_iptables -P INPUT ACCEPT && + kpanel_system_resource_iptables -P FORWARD ACCEPT || return 1 + kpanel_system_resource_firewall_base_rules || return 1 + else + kpanel_system_resource_firewall_base_rules || return 1 + kpanel_system_resource_iptables -P INPUT DROP && + kpanel_system_resource_iptables -P FORWARD DROP || return 1 + fi + iptables -w 5 -S INPUT 2>/dev/null | grep -Fqx -- "-P INPUT $input_policy" && + iptables -w 5 -S FORWARD 2>/dev/null | grep -Fqx -- "-P FORWARD $input_policy" && + iptables -w 5 -S OUTPUT 2>/dev/null | grep -Fqx -- "-P OUTPUT ACCEPT" +} + +kpanel_system_resource_firewall_apply() { + local action="$1" + local value="${2:-}" + KPANEL_SYSTEM_RESOURCE_FIREWALL_CHANGED=false + case "$action" in + open-port) kpanel_system_resource_firewall_open_port_rules "$value" ;; + close-port) kpanel_system_resource_firewall_close_port_rules "$value" ;; + allow-ip) kpanel_system_resource_firewall_allow_ip_rules "$value" ;; + block-ip) kpanel_system_resource_firewall_block_ip_rules "$value" ;; + remove-ip) kpanel_system_resource_firewall_remove_ip_rules "$value" ;; + open-all) kpanel_system_resource_firewall_all_rules ACCEPT ;; + close-all) kpanel_system_resource_firewall_all_rules DROP ;; + enable-ping) kpanel_system_resource_firewall_enable_ping_rules ;; + disable-ping) kpanel_system_resource_firewall_disable_ping_rules ;; + enable-ddos) kpanel_system_resource_firewall_enable_ddos_rules ;; + disable-ddos) kpanel_system_resource_firewall_disable_ddos_rules ;; + *) return 2 ;; + esac +} + +kpanel_system_resource_firewall_snapshot() { + local snapshot_dir="$1" + local rules_path="$2" + + kpanel_system_resource_firewall_capture "$snapshot_dir/iptables.rules" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED=false + if [ -e "$rules_path" ]; then + [ -f "$rules_path" ] && [ ! -L "$rules_path" ] || return 1 + cp -p -- "$rules_path" "$snapshot_dir/rules.v4" >/dev/null 2>&1 || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED=true + fi + kpanel_system_resource_cron_capture "$snapshot_dir/crontab" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_CRON_EXISTED="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" +} + +kpanel_system_resource_firewall_persist() { + local snapshot_dir="$1" + local rules_path parent desired_rules verify_rules + local cron_current cron_desired cron_verify restore_line count current_line + + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=false + rules_path="$(kpanel_system_resource_iptables_rules_file)" + parent="$(dirname -- "$rules_path")" + mkdir -p -- "$parent" >/dev/null 2>&1 || return 1 + [ ! -L "$rules_path" ] || return 1 + desired_rules="$(mktemp "$parent/.rules.v4.kpanel.XXXXXX")" || return 1 + if ! kpanel_system_resource_firewall_capture "$desired_rules"; then + rm -f -- "$desired_rules" + return 1 + fi + if [ -f "$rules_path" ] && cmp -s -- "$desired_rules" "$rules_path"; then + rm -f -- "$desired_rules" + else + if [ -f "$rules_path" ]; then + kpanel_system_resource_copy_identity "$rules_path" "$desired_rules" || { + rm -f -- "$desired_rules" + return 1 + } + else + chmod 600 "$desired_rules" >/dev/null 2>&1 || { + rm -f -- "$desired_rules" + return 1 + } + fi + mv -f -- "$desired_rules" "$rules_path" >/dev/null 2>&1 || { + rm -f -- "$desired_rules" + return 1 + } + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true + fi + verify_rules="$snapshot_dir/iptables.persist.verify" + kpanel_system_resource_firewall_capture "$verify_rules" && + cmp -s -- "$verify_rules" "$rules_path" || return 1 + + restore_line='@reboot iptables-restore < /etc/iptables/rules.v4' + cron_current="$snapshot_dir/crontab.persist.current" + kpanel_system_resource_cron_capture "$cron_current" || return 1 + count="$(grep -Fxc -- "$restore_line" "$cron_current" 2>/dev/null || true)" + if [ "$count" -ne 1 ]; then + cron_desired="$snapshot_dir/crontab.persist.desired" + : > "$cron_desired" || return 1 + while IFS= read -r current_line || [ -n "$current_line" ]; do + [ "$current_line" = "$restore_line" ] && continue + printf '%s\n' "$current_line" >> "$cron_desired" || return 1 + done < "$cron_current" + if [ -s "$cron_desired" ] && [ "$(tail -c 1 "$cron_desired" | wc -l)" -eq 0 ]; then + printf '\n' >> "$cron_desired" || return 1 + fi + printf '%s\n' "$restore_line" >> "$cron_desired" || return 1 + kpanel_system_resource_file_within_bounds "$cron_desired" 262144 512 || return 1 + crontab "$cron_desired" >/dev/null 2>&1 || return 1 + cron_verify="$snapshot_dir/crontab.persist.verify" + kpanel_system_resource_cron_capture "$cron_verify" || return 1 + cmp -s -- "$cron_desired" "$cron_verify" || return 1 + KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true + fi +} + +kpanel_system_resource_firewall_restore() { + local snapshot_dir="$1" + local rules_path="$2" + local rules_existed="$3" + local cron_existed="$4" + local verify="$snapshot_dir/rollback.iptables" + local cron_verify="$snapshot_dir/rollback.crontab" + local failed=false + + iptables-restore -w 5 < "$snapshot_dir/iptables.rules" >/dev/null 2>&1 || failed=true + if [ "$rules_existed" = true ]; then + cp -p -- "$snapshot_dir/rules.v4" "$rules_path" >/dev/null 2>&1 || failed=true + else + rm -f -- "$rules_path" >/dev/null 2>&1 || failed=true + fi + kpanel_system_resource_cron_restore "$snapshot_dir/crontab" "$cron_existed" "$cron_verify" || failed=true + kpanel_system_resource_firewall_capture "$verify" || failed=true + cmp -s -- "$snapshot_dir/iptables.rules" "$verify" || failed=true + if [ "$rules_existed" = true ]; then + cmp -s -- "$snapshot_dir/rules.v4" "$rules_path" || failed=true + else + [ ! -e "$rules_path" ] || failed=true + fi + [ "$failed" = false ] +} + +kpanel_system_resource_firewall_failure() { + local snapshot_dir="$1" + local rules_path="$2" + local rules_existed="$3" + local cron_existed="$4" + local message="$5" + local version + + kpanel_system_resource_error "$message" + if kpanel_system_resource_firewall_restore "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed"; then + version="$(kpanel_system_resource_best_version firewall)" + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit failed "$version" + else + version="$(kpanel_system_resource_best_version firewall)" + kpanel_system_resource_error "iptables 回滚失败,需要人工恢复" + kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + fi + return 1 +} + +kpanel_system_resource_firewall_action() { + local action="$1" + shift + local expected value="" snapshot_dir rules_path rules_existed cron_existed final_version + local command_name + + for command_name in iptables iptables-save iptables-restore crontab; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_system_resource_error "缺少必要命令: $command_name" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + done + rules_path="$(kpanel_system_resource_iptables_rules_file)" + [ ! -L "$rules_path" ] || { + kpanel_system_resource_error "iptables 持久化文件不能是符号链接" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + case "$action" in + open-port|close-port) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "$action 需要 expected,value" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + value="$2" + kpanel_system_resource_firewall_port "$value" || { + kpanel_system_resource_error "防火墙端口必须为 1-65535" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + value=$((10#$value)) + ;; + allow-ip|block-ip|remove-ip) + [ "$#" -eq 2 ] || { + kpanel_system_resource_error "$action 需要 expected,value" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + value="$2" + kpanel_system_resource_is_ipv4_cidr "$value" || { + kpanel_system_resource_error "防火墙地址必须为 IPv4 或 IPv4 CIDR" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + ;; + open-all|close-all|enable-ping|disable-ping|enable-ddos|disable-ddos) + [ "$#" -eq 1 ] || { + kpanel_system_resource_error "$action 只需要 expected" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + } + expected="$1" + ;; + *) + kpanel_system_resource_error "不支持的 firewall 动作" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version firewall)" + return 2 + ;; + esac + + kpanel_system_resource_check_expected firewall "$expected" || return $? + snapshot_dir="$(kpanel_system_resource_tempdir firewall)" || { + kpanel_system_resource_error "无法创建 firewall 事务目录" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + } + if ! kpanel_system_resource_firewall_snapshot "$snapshot_dir" "$rules_path"; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_error "无法创建 iptables/crontab 快照" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + rules_existed="$KPANEL_SYSTEM_RESOURCE_FIREWALL_RULES_EXISTED" + cron_existed="$KPANEL_SYSTEM_RESOURCE_FIREWALL_CRON_EXISTED" + if ! kpanel_system_resource_firewall_apply "$action" "$value"; then + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "iptables 动作执行或回读验证失败" + return $? + fi + if ! kpanel_system_resource_firewall_persist "$snapshot_dir"; then + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "iptables 持久化失败" + return $? + fi + final_version="$(kpanel_system_resource_firewall_version 2>/dev/null)" || { + kpanel_system_resource_firewall_failure "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed" "无法计算修改后的 iptables 版本" + return $? + } + if [ "$final_version" = "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" ] && + [ "$KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED" = false ]; then + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit unchanged "$final_version" + else + rm -rf -- "$snapshot_dir" + kpanel_system_resource_emit applied "$final_version" + fi +} + +kpanel_system_resource_run_locked() ( + local resource="$1" + local action="$2" + local lock_file lock_parent name="" + shift 2 + + lock_file="$(kpanel_system_resource_lock_file)" + lock_parent="$(dirname -- "$lock_file")" + mkdir -p -- "$lock_parent" >/dev/null 2>&1 || { + kpanel_system_resource_error "无法创建 system-resource 锁目录" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + return 1 + } + exec 9>"$lock_file" || { + kpanel_system_resource_error "无法打开 system-resource 锁" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + return 1 + } + if ! flock -w 30 -x 9 >/dev/null 2>&1; then + [ "$resource" = "network-interface" ] && name="${2:-}" + kpanel_system_resource_error "system-resource 写锁等待超时" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 1 + fi + case "$resource" in + hosts) kpanel_system_resource_hosts_action "$action" "$@" ;; + cron) kpanel_system_resource_cron_action "$action" "$@" ;; + network-interface) kpanel_system_resource_interface_action "$action" "$@" ;; + firewall) kpanel_system_resource_firewall_action "$action" "$@" ;; + *) + kpanel_system_resource_error "不支持的 system-resource 资源" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + ;; + esac +) + +kpanel_system_resource_dispatch() { + local resource="${1:-}" + local action="${2:-}" + local rc + + kpanel_system_resource_require_platform + rc=$? + [ "$rc" -eq 0 ] || return "$rc" + [ "$#" -ge 2 ] || { + kpanel_system_resource_error "用法: kpanel system-resource ..." + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + } + case "$resource" in + hosts|cron|network-interface|firewall) ;; + *) + kpanel_system_resource_error "不支持的 system-resource 资源" + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + ;; + esac + shift 2 + kpanel_system_resource_run_locked "$resource" "$action" "$@" +} + +# KPanel system resource protocol end + + log_menu() { send_stats "系统日志管理工具" @@ -24600,8 +26083,11 @@ else if [ "${1:-}" = "node" ]; then shift kpanel_node_dispatch "$@" + elif [ "${1:-}" = "system-resource" ]; then + shift + kpanel_system_resource_dispatch "$@" else - echo "用法: k kpanel node join <授权> | status | update | uninstall" >&2 + echo "用法: k kpanel node join <授权> | status | update | uninstall;或 k kpanel system-resource ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/tests/test_kpanel_system_resource_noninteractive_smoke.sh b/tests/test_kpanel_system_resource_noninteractive_smoke.sh new file mode 100644 index 000000000..14ba48cb8 --- /dev/null +++ b/tests/test_kpanel_system_resource_noninteractive_smoke.sh @@ -0,0 +1,372 @@ +#!/bin/bash +set -euo pipefail + +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +script_path="${project_root}/kejilion.sh" +test_root="$(mktemp -d)" +trap 'rm -rf -- "${test_root}"' EXIT + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + exit 1 +} + +grep -F '[ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/null +grep -F 'kpanel_system_resource_dispatch "$@"' "${script_path}" >/dev/null +grep -F 'kpanel_system_resource_file_within_bounds "$path" 262144 1024' "${script_path}" >/dev/null +grep -F 'kpanel_system_resource_file_within_bounds "$target" 262144 512' "${script_path}" >/dev/null +grep -F '[ "$bytes" -le 524288 ]' "${script_path}" >/dev/null +grep -F 'iptables -w 5 "$@"' "${script_path}" >/dev/null +grep -F 'iptables-restore -w 5' "${script_path}" >/dev/null +grep -F 'allow-ip|block-ip|remove-ip)' "${script_path}" >/dev/null +grep -F 'open-all|close-all|enable-ping|disable-ping|enable-ddos|disable-ddos)' "${script_path}" >/dev/null + +adapter_body="$( + sed -n '/^# KPanel system resource protocol start/,/^# KPanel system resource protocol end/p' "${script_path}" | + sed 's/\r$//' +)" +[ -n "${adapter_body}" ] || fail "system-resource adapter block was not found" +eval "${adapter_body}" + +test_hosts="${test_root}/hosts" +test_crontab="${test_root}/crontab" +test_lock="${test_root}/system-resource.lock" +test_interfaces="${test_root}/interfaces" +test_rules="${test_root}/rules.v4" +test_iptables="${test_root}/iptables.state" +test_stderr="${test_root}/stderr" +mkdir -p -- "${test_interfaces}" + +kpanel_system_resource_hosts_file() { printf '%s\n' "${test_hosts}"; } +kpanel_system_resource_lock_file() { printf '%s\n' "${test_lock}"; } +kpanel_system_resource_interfaces_dir() { printf '%s\n' "${test_interfaces}"; } +kpanel_system_resource_iptables_rules_file() { printf '%s\n' "${test_rules}"; } + +crontab() { + case "${1:-}" in + -l) + if [ -e "${test_root}/crontab-read-error" ]; then + printf 'permission denied\n' >&2 + return 1 + fi + if [ -f "${test_crontab}" ]; then + command cat -- "${test_crontab}" + return 0 + fi + printf 'no crontab for root\n' >&2 + return 1 + ;; + -r) + command rm -f -- "${test_crontab}" + ;; + *) + [ "$#" -eq 1 ] || return 1 + if [ -e "${test_root}/crontab-install-error" ]; then + command rm -f -- "${test_root}/crontab-install-error" + return 1 + fi + command cp -- "$1" "${test_crontab}" + ;; + esac +} + +ip() { + [ "$#" -eq 5 ] && [ "$1" = link ] && [ "$2" = set ] && [ "$3" = dev ] || return 1 + case "$5" in + up) printf '0x1003\n' > "${test_interfaces}/$4/flags" ;; + down) printf '0x1002\n' > "${test_interfaces}/$4/flags" ;; + *) return 1 ;; + esac + if [ -e "${test_root}/ip-partial-error" ]; then + command rm -f -- "${test_root}/ip-partial-error" + return 1 + fi +} + +iptables_rule_text() { + local chain="$1" + shift + local argument rule="-A ${chain}" + for argument in "$@"; do + rule="${rule} ${argument}" + done + printf '%s\n' "${rule}" +} + +iptables() { + [ "${1:-}" = -w ] && [ "${2:-}" = 5 ] || return 1 + shift 2 + local operation="${1:-}" chain rule temporary prefix + case "${operation}" in + -C) + chain="$2" + shift 2 + rule="$(iptables_rule_text "${chain}" "$@")" + grep -Fqx -- "${rule}" "${test_iptables}" + ;; + -D) + chain="$2" + shift 2 + rule="$(iptables_rule_text "${chain}" "$@")" + temporary="${test_iptables}.delete" + awk -v target="${rule}" ' + BEGIN { removed=0 } + !removed && $0 == target { removed=1; next } + { print } + END { if (!removed) exit 1 } + ' "${test_iptables}" > "${temporary}" || { + command rm -f -- "${temporary}" + return 1 + } + command mv -f -- "${temporary}" "${test_iptables}" + ;; + -I) + chain="$2" + [ "${3:-}" = 1 ] || return 1 + shift 3 + rule="$(iptables_rule_text "${chain}" "$@")" + prefix="-A ${chain} " + temporary="${test_iptables}.insert" + awk -v prefix="${prefix}" -v rule="${rule}" ' + BEGIN { inserted=0 } + !inserted && index($0, prefix) == 1 { print rule; inserted=1 } + { print } + END { if (!inserted) print rule } + ' "${test_iptables}" > "${temporary}" || return 1 + command mv -f -- "${temporary}" "${test_iptables}" + ;; + -A) + chain="$2" + shift 2 + iptables_rule_text "${chain}" "$@" >> "${test_iptables}" + ;; + -S) + chain="$2" + grep -Eq "^(-N|-P) ${chain}( |$)|^-A ${chain} " "${test_iptables}" + ;; + -P) + chain="$2" + local policy="$3" + temporary="${test_iptables}.policy" + awk -v chain="${chain}" -v policy="${policy}" ' + $0 ~ "^-P " chain " " { if (!done) print "-P " chain " " policy; done=1; next } + { print } + END { if (!done) print "-P " chain " " policy } + ' "${test_iptables}" > "${temporary}" || return 1 + command mv -f -- "${temporary}" "${test_iptables}" + ;; + -F) + temporary="${test_iptables}.flush" + awk '$1 != "-A"' "${test_iptables}" > "${temporary}" || return 1 + command mv -f -- "${temporary}" "${test_iptables}" + ;; + -X) + temporary="${test_iptables}.chains" + awk '$1 != "-N"' "${test_iptables}" > "${temporary}" || return 1 + command mv -f -- "${temporary}" "${test_iptables}" + ;; + *) return 1 ;; + esac +} + +iptables-save() { + local remaining + if [ -f "${test_root}/iptables-save-countdown" ]; then + remaining="$(command cat -- "${test_root}/iptables-save-countdown")" + if [ "${remaining}" -le 1 ]; then + command rm -f -- "${test_root}/iptables-save-countdown" + return 1 + fi + printf '%s\n' "$((remaining - 1))" > "${test_root}/iptables-save-countdown" + fi + command cat -- "${test_iptables}" +} + +iptables-restore() { + [ "${1:-}" = -w ] && [ "${2:-}" = 5 ] || return 1 + command cat > "${test_iptables}" +} + +mv() { + local destination="${!#}" + if [ "${KPANEL_FAKE_HOSTS_MV_FAIL:-0}" = 1 ] && [ "${destination}" = "${test_hosts}" ]; then + command mv "$@" || return 1 + return 1 + fi + command mv "$@" +} + +assert_receipt() { + local expected_status="$1" + local line_count + printf '%s\n' "${RUN_OUTPUT}" | grep -Fqx "KPANEL_SYSTEM_RESOURCE_STATUS=${expected_status}" || + fail "receipt status was not ${expected_status}: ${RUN_OUTPUT}" + printf '%s\n' "${RUN_OUTPUT}" | + grep -Eq '^KPANEL_SYSTEM_RESOURCE_VERSION=[0-9a-f]{64}$' || + fail "receipt version is missing or invalid: ${RUN_OUTPUT}" + if printf '%s\n' "${RUN_OUTPUT}" | grep -Ev '^KPANEL_SYSTEM_RESOURCE_(STATUS|VERSION|BACKUP)=' >/dev/null; then + fail "stdout contains a non-protocol line: ${RUN_OUTPUT}" + fi + line_count="$(printf '%s\n' "${RUN_OUTPUT}" | awk 'NF { count++ } END { print count + 0 }')" + [ "${line_count}" -ge 2 ] && [ "${line_count}" -le 3 ] || + fail "receipt has an invalid line count: ${RUN_OUTPUT}" +} + +run_dispatch() { + local expected_status="$1" + shift + set +e + RUN_OUTPUT="$(kpanel_system_resource_dispatch "$@" 2> "${test_stderr}")" + RUN_RC=$? + set -e + assert_receipt "${expected_status}" +} + +zero_version="$(kpanel_system_resource_zero_version)" +unset KJ_SYSTEM_RESOURCE_NONINTERACTIVE +run_dispatch failed hosts add "${zero_version}" 127.0.0.1 guarded.local "" +[ "${RUN_RC}" -eq 2 ] || fail "protocol guard returned ${RUN_RC}, expected 2" + +export KJ_SYSTEM_RESOURCE_NONINTERACTIVE=1 +kpanel_system_resource_require_platform() { + if [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" != 1 ]; then + kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" + return 2 + fi +} + +printf '%s\n' \ + '127.0.0.1 localhost' \ + '10.0.0.1 duplicate.local' \ + '10.0.0.1 duplicate.local' > "${test_hosts}" +hosts_v0="$(kpanel_system_resource_hosts_version)" +run_dispatch applied hosts add "${hosts_v0}" 192.0.2.10 new.local,alias.local managed +[ "${RUN_RC}" -eq 0 ] || fail "hosts add failed" +grep -Fqx $'192.0.2.10\tnew.local alias.local # managed' "${test_hosts}" || fail "hosts add did not write the exact line" +run_dispatch conflict hosts add "${hosts_v0}" 192.0.2.11 conflict.local "" +[ "${RUN_RC}" -eq 2 ] || fail "stale hosts write did not return 2" +hosts_v1="$(kpanel_system_resource_hosts_version)" +run_dispatch applied hosts delete "${hosts_v1}" 2 +[ "${RUN_RC}" -eq 0 ] || fail "hosts line-number delete failed" +[ "$(grep -Fxc '10.0.0.1 duplicate.local' "${test_hosts}")" -eq 1 ] || fail "hosts delete did not target one exact duplicate row" +printf '%s\n%s' '127.0.0.1 localhost' '192.0.2.20 final.local' > "${test_hosts}" +hosts_no_newline_v="$(kpanel_system_resource_hosts_version)" +run_dispatch applied hosts delete "${hosts_no_newline_v}" 1 +[ "${RUN_RC}" -eq 0 ] || fail "hosts delete on a non-newline-terminated file failed" +[ "$(command cat -- "${test_hosts}")" = '192.0.2.20 final.local' ] || fail "hosts delete changed the retained final row" +[ "$(tail -c 1 "${test_hosts}" | wc -l)" -eq 0 ] || fail "hosts delete changed final-newline semantics" +hosts_before="${test_root}/hosts.before-rollback" +command cp -- "${test_hosts}" "${hosts_before}" +hosts_v2="$(kpanel_system_resource_hosts_version)" +KPANEL_FAKE_HOSTS_MV_FAIL=1 +run_dispatch failed hosts add "${hosts_v2}" 192.0.2.12 rollback.local "" +unset KPANEL_FAKE_HOSTS_MV_FAIL +[ "${RUN_RC}" -eq 1 ] || fail "hosts rollback path did not return 1" +cmp -s -- "${hosts_before}" "${test_hosts}" || fail "hosts rollback did not restore original bytes" + +cron_line='0 * * * * echo duplicate' +printf '%s\n%s\n' "${cron_line}" "${cron_line}" > "${test_crontab}" +cron_v0="$(kpanel_system_resource_cron_version)" +run_dispatch applied cron add "${cron_v0}" '15 2 * JAN MON' 'printf cron-data' +[ "${RUN_RC}" -eq 0 ] || fail "cron add with English names failed" +cron_v1="$(kpanel_system_resource_cron_version)" +run_dispatch applied cron update "${cron_v1}" 2 '*/5 * * * *' 'echo updated' +[ "${RUN_RC}" -eq 0 ] || fail "cron line-number update failed" +[ "$(sed -n '2p' "${test_crontab}")" = '*/5 * * * * echo updated' ] || fail "cron update targeted the wrong row" +cron_v2="$(kpanel_system_resource_cron_version)" +run_dispatch applied cron delete "${cron_v2}" 1 +[ "${RUN_RC}" -eq 0 ] || fail "cron line-number delete failed" +[ "$(sed -n '1p' "${test_crontab}")" = '*/5 * * * * echo updated' ] || fail "cron delete targeted the wrong row" +cron_before_invalid="${test_root}/cron.before-invalid" +command cp -- "${test_crontab}" "${cron_before_invalid}" +cron_v2="$(kpanel_system_resource_cron_version)" +run_dispatch failed cron add "${cron_v2}" '0 0 L * *' 'echo quartz' +[ "${RUN_RC}" -eq 2 ] || fail "Quartz cron token was not rejected" +cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "invalid cron input changed the crontab" +command cp -- "${test_crontab}" "${cron_before_invalid}" +touch "${test_root}/crontab-read-error" +run_dispatch failed cron delete "${cron_v2}" 1 +command rm -f -- "${test_root}/crontab-read-error" +[ "${RUN_RC}" -eq 1 ] || fail "unexpected crontab -l failure was treated as an empty table" +cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "crontab read error changed the crontab" +cron_v3="$(kpanel_system_resource_cron_version)" +touch "${test_root}/crontab-install-error" +run_dispatch failed cron add "${cron_v3}" '0 3 * * *' 'echo rollback' +[ "${RUN_RC}" -eq 1 ] || fail "cron install rollback path did not return 1" +cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "cron rollback did not restore original bytes" + +mkdir -p -- "${test_interfaces}/eth-test" +printf '0x1002\n' > "${test_interfaces}/eth-test/flags" +printf '02:00:00:00:00:01\n' > "${test_interfaces}/eth-test/address" +interface_v0="$(kpanel_system_resource_interface_version eth-test)" +run_dispatch applied network-interface state "${interface_v0}" eth-test up +[ "${RUN_RC}" -eq 0 ] || fail "network interface state change failed" +[ "$(kpanel_system_resource_interface_admin_state eth-test)" = up ] || fail "network interface admin state was not updated" +interface_v1="$(kpanel_system_resource_interface_version eth-test)" +run_dispatch unchanged network-interface state "${interface_v1}" eth-test up +[ "${RUN_RC}" -eq 0 ] || fail "network interface idempotence failed" +run_dispatch conflict network-interface state "${interface_v0}" eth-test down +[ "${RUN_RC}" -eq 2 ] || fail "stale network interface write did not return 2" +touch "${test_root}/ip-partial-error" +run_dispatch failed network-interface state "${interface_v1}" eth-test down +[ "${RUN_RC}" -eq 1 ] || fail "partial network interface failure did not return 1" +[ "$(kpanel_system_resource_interface_admin_state eth-test)" = up ] || fail "network interface rollback did not restore admin state" + +printf '%s\n' \ + '-P INPUT ACCEPT' \ + '-P FORWARD ACCEPT' \ + '-P OUTPUT ACCEPT' \ + '-N DOCKER-USER' \ + '-A DOCKER-USER -j RETURN' > "${test_iptables}" +firewall_v0="$(kpanel_system_resource_firewall_version)" +run_dispatch applied firewall open-port "${firewall_v0}" 443 +[ "${RUN_RC}" -eq 0 ] || fail "firewall open-port failed" +grep -Fqx -- '-A INPUT -p tcp --dport 443 -j ACCEPT' "${test_iptables}" || fail "firewall TCP rule is missing" +grep -Fqx -- '-A INPUT -p udp --dport 443 -j ACCEPT' "${test_iptables}" || fail "firewall UDP rule is missing" +cmp -s -- "${test_iptables}" "${test_rules}" || fail "firewall rules were not persisted exactly" +[ "$(grep -Fxc '@reboot iptables-restore < /etc/iptables/rules.v4' "${test_crontab}")" -eq 1 ] || fail "firewall restore cron entry is not unique" +firewall_v1="$(kpanel_system_resource_firewall_version)" +run_dispatch unchanged firewall open-port "${firewall_v1}" 443 +[ "${RUN_RC}" -eq 0 ] || fail "firewall idempotence failed" +run_dispatch conflict firewall close-port "${firewall_v0}" 443 +[ "${RUN_RC}" -eq 2 ] || fail "stale firewall write did not return 2" +run_dispatch failed firewall allow-ip "${firewall_v1}" '2001:db8::1' +[ "${RUN_RC}" -eq 2 ] || fail "firewall accepted IPv6 without an ip6tables transaction" +run_dispatch failed firewall allow-ip "${firewall_v1}" '010.0.0.1' +[ "${RUN_RC}" -eq 2 ] || fail "firewall accepted an ambiguous leading-zero IPv4 address" + +iptables_before="${test_root}/iptables.before-rollback" +rules_before="${test_root}/rules.before-rollback" +cron_before_firewall="${test_root}/cron.before-firewall-rollback" +command cp -- "${test_iptables}" "${iptables_before}" +command cp -- "${test_rules}" "${rules_before}" +command cp -- "${test_crontab}" "${cron_before_firewall}" +printf '3\n' > "${test_root}/iptables-save-countdown" +run_dispatch failed firewall close-port "${firewall_v1}" 443 +[ "${RUN_RC}" -eq 1 ] || fail "firewall persistence rollback path did not return 1" +cmp -s -- "${iptables_before}" "${test_iptables}" || fail "firewall rollback did not restore runtime rules" +cmp -s -- "${rules_before}" "${test_rules}" || fail "firewall rollback did not restore persisted rules" +cmp -s -- "${cron_before_firewall}" "${test_crontab}" || fail "firewall rollback did not restore crontab" + +firewall_v2="$(kpanel_system_resource_firewall_version)" +run_dispatch applied firewall enable-ddos "${firewall_v2}" +[ "${RUN_RC}" -eq 0 ] || fail "firewall enable-ddos failed" +mapfile -t docker_user_rules < <(grep -F -- '-A DOCKER-USER ' "${test_iptables}") +[ "${docker_user_rules[0]}" = '-A DOCKER-USER -p tcp --syn -m limit --limit 500/s --limit-burst 100 -j ACCEPT' ] || fail "DDoS TCP limit rule is not first" +[ "${docker_user_rules[1]}" = '-A DOCKER-USER -p tcp --syn -j DROP' ] || fail "DDoS TCP drop rule is not second" +[ "${docker_user_rules[2]}" = '-A DOCKER-USER -p udp -m limit --limit 3000/s -j ACCEPT' ] || fail "DDoS UDP limit rule is not third" +[ "${docker_user_rules[3]}" = '-A DOCKER-USER -p udp -j DROP' ] || fail "DDoS UDP drop rule is not fourth" +[ "${docker_user_rules[4]}" = '-A DOCKER-USER -j RETURN' ] || fail "DDoS rules were placed after DOCKER-USER RETURN" +firewall_v3="$(kpanel_system_resource_firewall_version)" +run_dispatch unchanged firewall enable-ddos "${firewall_v3}" +[ "${RUN_RC}" -eq 0 ] || fail "DDoS rule reconciliation is not idempotent" +firewall_v4="$(kpanel_system_resource_firewall_version)" +run_dispatch applied firewall enable-ping "${firewall_v4}" +[ "${RUN_RC}" -eq 0 ] || fail "firewall enable-ping failed" +grep -Fqx -- '-A INPUT -p icmp --icmp-type echo-request -j ACCEPT' "${test_iptables}" || fail "ping ACCEPT rule is missing" +firewall_v5="$(kpanel_system_resource_firewall_version)" +run_dispatch applied firewall disable-ping "${firewall_v5}" +[ "${RUN_RC}" -eq 0 ] || fail "firewall disable-ping failed" +grep -Fqx -- '-A INPUT -p icmp --icmp-type echo-request -j DROP' "${test_iptables}" || fail "ping DROP rule is missing" + +printf '%s\n' "kpanel_system_resource_noninteractive_smoke=pass" From 8a47f3395d4b7cb12c82a927bc071b73cc1397c8 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 10 Aug 2026 12:07:32 +0800 Subject: [PATCH 1256/1285] fix(kpanel): secure cron command transport AI-Scope: kpanel-system-resource-adapters --- cn/kejilion.sh | 100 +++++++++++++++--- kejilion.sh | 100 +++++++++++++++--- ...el_system_resource_noninteractive_smoke.sh | 84 ++++++++++++++- 3 files changed, 252 insertions(+), 32 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b06c6758c..1fc0ba4b3 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -22769,6 +22769,58 @@ kpanel_system_resource_cron_expression() { KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="${fields[*]}" } +kpanel_system_resource_cron_read_command() { + local frame bytes line_feeds command_value + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND="" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=operation + frame="$(mktemp /tmp/kejilion-system-resource-cron-command.XXXXXX)" || return 1 + chmod 600 "$frame" >/dev/null 2>&1 || { + rm -f -- "$frame" + return 1 + } + if ! head -c 2050 > "$frame" 2>/dev/null; then + rm -f -- "$frame" + return 1 + fi + bytes="$(wc -c < "$frame" 2>/dev/null)" || { + rm -f -- "$frame" + return 1 + } + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=invalid + if [ "$bytes" -lt 1 ] || [ "$bytes" -gt 2049 ] || + ! LC_ALL=C tr -d '\000' < "$frame" | cmp -s - "$frame" || + LC_ALL=C grep -q $'\r' "$frame"; then + rm -f -- "$frame" + return 1 + fi + line_feeds="$(LC_ALL=C tr -cd '\n' < "$frame" | wc -c)" || { + rm -f -- "$frame" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=operation + return 1 + } + if [ "$line_feeds" -ne 1 ] || [ "$(tail -c 1 "$frame" | wc -l)" -ne 1 ]; then + rm -f -- "$frame" + return 1 + fi + IFS= read -r command_value < "$frame" || { + rm -f -- "$frame" + return 1 + } + rm -f -- "$frame" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND="$command_value" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR="" +} + +kpanel_system_resource_cron_contains_line() { + local path="$1" + local expected_line="$2" + local current_line + while IFS= read -r current_line || [ -n "$current_line" ]; do + [ "$current_line" = "$expected_line" ] && return 0 + done < "$path" + return 1 +} + kpanel_system_resource_cron_restore() { local backup="$1" local existed="$2" @@ -22807,8 +22859,9 @@ kpanel_system_resource_cron_failure() { kpanel_system_resource_cron_action() { local action="$1" shift - local expected line_number expression command_value trimmed_command new_line snapshot_dir backup desired verify + local expected line_number expression command_source command_value trimmed_command new_line snapshot_dir backup desired verify local cron_existed current_line index=0 total_lines + local command_read_rc command -v crontab >/dev/null 2>&1 || { kpanel_system_resource_error "缺少 crontab 命令" @@ -22818,24 +22871,24 @@ kpanel_system_resource_cron_action() { case "$action" in add) [ "$#" -eq 3 ] || { - kpanel_system_resource_error "cron add 需要 expected,expression,command" + kpanel_system_resource_error "cron add 需要 expected,expression,--command-stdin" kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" return 2 } expected="$1" expression="$2" - command_value="$3" + command_source="$3" ;; update) [ "$#" -eq 4 ] || { - kpanel_system_resource_error "cron update 需要 expected,line,expression,command" + kpanel_system_resource_error "cron update 需要 expected,line,expression,--command-stdin" kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" return 2 } expected="$1" line_number="$2" expression="$3" - command_value="$4" + command_source="$4" [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && [ "$((10#$line_number))" -ge 1 ] && [ "$((10#$line_number))" -le 512 ] || { @@ -22870,19 +22923,38 @@ kpanel_system_resource_cron_action() { esac if [ "$action" != "delete" ]; then + [ "$command_source" = "--command-stdin" ] && + kpanel_system_resource_cron_expression "$expression" || { + kpanel_system_resource_error "cron 表达式或命令输入方式无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + fi + kpanel_system_resource_check_expected cron "$expected" || return $? + if [ "$action" != "delete" ]; then + kpanel_system_resource_cron_read_command + command_read_rc=$? + if [ "$command_read_rc" -ne 0 ]; then + if [ "$KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR" = invalid ]; then + kpanel_system_resource_error "cron 命令 stdin 帧无效" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + kpanel_system_resource_error "无法安全读取 cron 命令 stdin 帧" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + command_value="$KPANEL_SYSTEM_RESOURCE_CRON_COMMAND" trimmed_command="$command_value" trimmed_command="${trimmed_command#"${trimmed_command%%[![:space:]]*}"}" trimmed_command="${trimmed_command%"${trimmed_command##*[![:space:]]}"}" - kpanel_system_resource_cron_expression "$expression" && - kpanel_system_resource_single_line "$command_value" 2048 && - [ -n "$trimmed_command" ] || { - kpanel_system_resource_error "cron 表达式或命令无效" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + [ -n "$trimmed_command" ] || { + kpanel_system_resource_error "cron 命令 stdin 帧无效" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" return 2 } new_line="$KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION $command_value" fi - kpanel_system_resource_check_expected cron "$expected" || return $? snapshot_dir="$(kpanel_system_resource_tempdir cron)" || { kpanel_system_resource_error "无法创建 cron 事务目录" @@ -22898,7 +22970,7 @@ kpanel_system_resource_cron_action() { } cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" - if [ "$action" = "add" ] && grep -Fqx -- "$new_line" "$backup"; then + if [ "$action" = "add" ] && kpanel_system_resource_cron_contains_line "$backup" "$new_line"; then rm -rf -- "$snapshot_dir" kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" return 0 @@ -22929,7 +23001,7 @@ kpanel_system_resource_cron_action() { return 1 } fi - printf '%s\n' "$new_line" >> "$desired" || { + builtin printf '%s\n' "$new_line" >> "$desired" || { kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" return $? } @@ -22943,7 +23015,7 @@ kpanel_system_resource_cron_action() { while IFS= read -r current_line || [ -n "$current_line" ]; do index=$((index + 1)) if [ "$index" -eq "$line_number" ]; then - if [ "$action" != "delete" ] && ! printf '%s\n' "$new_line" >> "$desired"; then + if [ "$action" != "delete" ] && ! builtin printf '%s\n' "$new_line" >> "$desired"; then rm -rf -- "$snapshot_dir" kpanel_system_resource_error "无法生成 crontab" kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" diff --git a/kejilion.sh b/kejilion.sh index a4266a23e..2af2dab9b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -22769,6 +22769,58 @@ kpanel_system_resource_cron_expression() { KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION="${fields[*]}" } +kpanel_system_resource_cron_read_command() { + local frame bytes line_feeds command_value + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND="" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=operation + frame="$(mktemp /tmp/kejilion-system-resource-cron-command.XXXXXX)" || return 1 + chmod 600 "$frame" >/dev/null 2>&1 || { + rm -f -- "$frame" + return 1 + } + if ! head -c 2050 > "$frame" 2>/dev/null; then + rm -f -- "$frame" + return 1 + fi + bytes="$(wc -c < "$frame" 2>/dev/null)" || { + rm -f -- "$frame" + return 1 + } + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=invalid + if [ "$bytes" -lt 1 ] || [ "$bytes" -gt 2049 ] || + ! LC_ALL=C tr -d '\000' < "$frame" | cmp -s - "$frame" || + LC_ALL=C grep -q $'\r' "$frame"; then + rm -f -- "$frame" + return 1 + fi + line_feeds="$(LC_ALL=C tr -cd '\n' < "$frame" | wc -c)" || { + rm -f -- "$frame" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR=operation + return 1 + } + if [ "$line_feeds" -ne 1 ] || [ "$(tail -c 1 "$frame" | wc -l)" -ne 1 ]; then + rm -f -- "$frame" + return 1 + fi + IFS= read -r command_value < "$frame" || { + rm -f -- "$frame" + return 1 + } + rm -f -- "$frame" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND="$command_value" + KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR="" +} + +kpanel_system_resource_cron_contains_line() { + local path="$1" + local expected_line="$2" + local current_line + while IFS= read -r current_line || [ -n "$current_line" ]; do + [ "$current_line" = "$expected_line" ] && return 0 + done < "$path" + return 1 +} + kpanel_system_resource_cron_restore() { local backup="$1" local existed="$2" @@ -22807,8 +22859,9 @@ kpanel_system_resource_cron_failure() { kpanel_system_resource_cron_action() { local action="$1" shift - local expected line_number expression command_value trimmed_command new_line snapshot_dir backup desired verify + local expected line_number expression command_source command_value trimmed_command new_line snapshot_dir backup desired verify local cron_existed current_line index=0 total_lines + local command_read_rc command -v crontab >/dev/null 2>&1 || { kpanel_system_resource_error "缺少 crontab 命令" @@ -22818,24 +22871,24 @@ kpanel_system_resource_cron_action() { case "$action" in add) [ "$#" -eq 3 ] || { - kpanel_system_resource_error "cron add 需要 expected,expression,command" + kpanel_system_resource_error "cron add 需要 expected,expression,--command-stdin" kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" return 2 } expected="$1" expression="$2" - command_value="$3" + command_source="$3" ;; update) [ "$#" -eq 4 ] || { - kpanel_system_resource_error "cron update 需要 expected,line,expression,command" + kpanel_system_resource_error "cron update 需要 expected,line,expression,--command-stdin" kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" return 2 } expected="$1" line_number="$2" expression="$3" - command_value="$4" + command_source="$4" [[ "$line_number" =~ ^[0-9]{1,3}$ ]] && [ "$((10#$line_number))" -ge 1 ] && [ "$((10#$line_number))" -le 512 ] || { @@ -22870,19 +22923,38 @@ kpanel_system_resource_cron_action() { esac if [ "$action" != "delete" ]; then + [ "$command_source" = "--command-stdin" ] && + kpanel_system_resource_cron_expression "$expression" || { + kpanel_system_resource_error "cron 表达式或命令输入方式无效" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + return 2 + } + fi + kpanel_system_resource_check_expected cron "$expected" || return $? + if [ "$action" != "delete" ]; then + kpanel_system_resource_cron_read_command + command_read_rc=$? + if [ "$command_read_rc" -ne 0 ]; then + if [ "$KPANEL_SYSTEM_RESOURCE_CRON_COMMAND_ERROR" = invalid ]; then + kpanel_system_resource_error "cron 命令 stdin 帧无效" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 2 + fi + kpanel_system_resource_error "无法安全读取 cron 命令 stdin 帧" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" + return 1 + fi + command_value="$KPANEL_SYSTEM_RESOURCE_CRON_COMMAND" trimmed_command="$command_value" trimmed_command="${trimmed_command#"${trimmed_command%%[![:space:]]*}"}" trimmed_command="${trimmed_command%"${trimmed_command##*[![:space:]]}"}" - kpanel_system_resource_cron_expression "$expression" && - kpanel_system_resource_single_line "$command_value" 2048 && - [ -n "$trimmed_command" ] || { - kpanel_system_resource_error "cron 表达式或命令无效" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version cron)" + [ -n "$trimmed_command" ] || { + kpanel_system_resource_error "cron 命令 stdin 帧无效" + kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" return 2 } new_line="$KPANEL_SYSTEM_RESOURCE_CRON_EXPRESSION $command_value" fi - kpanel_system_resource_check_expected cron "$expected" || return $? snapshot_dir="$(kpanel_system_resource_tempdir cron)" || { kpanel_system_resource_error "无法创建 cron 事务目录" @@ -22898,7 +22970,7 @@ kpanel_system_resource_cron_action() { } cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" - if [ "$action" = "add" ] && grep -Fqx -- "$new_line" "$backup"; then + if [ "$action" = "add" ] && kpanel_system_resource_cron_contains_line "$backup" "$new_line"; then rm -rf -- "$snapshot_dir" kpanel_system_resource_emit unchanged "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" return 0 @@ -22929,7 +23001,7 @@ kpanel_system_resource_cron_action() { return 1 } fi - printf '%s\n' "$new_line" >> "$desired" || { + builtin printf '%s\n' "$new_line" >> "$desired" || { kpanel_system_resource_cron_failure "$snapshot_dir" "$backup" "$cron_existed" "无法生成 crontab" return $? } @@ -22943,7 +23015,7 @@ kpanel_system_resource_cron_action() { while IFS= read -r current_line || [ -n "$current_line" ]; do index=$((index + 1)) if [ "$index" -eq "$line_number" ]; then - if [ "$action" != "delete" ] && ! printf '%s\n' "$new_line" >> "$desired"; then + if [ "$action" != "delete" ] && ! builtin printf '%s\n' "$new_line" >> "$desired"; then rm -rf -- "$snapshot_dir" kpanel_system_resource_error "无法生成 crontab" kpanel_system_resource_emit failed "$KPANEL_SYSTEM_RESOURCE_CURRENT_VERSION" diff --git a/tests/test_kpanel_system_resource_noninteractive_smoke.sh b/tests/test_kpanel_system_resource_noninteractive_smoke.sh index 14ba48cb8..3c3f348ea 100644 --- a/tests/test_kpanel_system_resource_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_resource_noninteractive_smoke.sh @@ -8,6 +8,10 @@ trap 'rm -rf -- "${test_root}"' EXIT fail() { printf 'FAIL: %s\n' "$1" >&2 + if [ -n "${test_stderr:-}" ] && [ -s "${test_stderr}" ]; then + printf '%s\n' '--- adapter stderr ---' >&2 + command cat -- "${test_stderr}" >&2 + fi exit 1 } @@ -26,6 +30,11 @@ adapter_body="$( sed 's/\r$//' )" [ -n "${adapter_body}" ] || fail "system-resource adapter block was not found" +printf '%s\n' "${adapter_body}" | grep -F '[ "$command_source" = "--command-stdin" ]' >/dev/null || + fail "cron command stdin marker is missing" +if printf '%s\n' "${adapter_body}" | grep -E 'grep .*\$new_line' >/dev/null; then + fail "cron command is passed to an external grep argv" +fi eval "${adapter_body}" test_hosts="${test_root}/hosts" @@ -42,6 +51,14 @@ kpanel_system_resource_lock_file() { printf '%s\n' "${test_lock}"; } kpanel_system_resource_interfaces_dir() { printf '%s\n' "${test_interfaces}"; } kpanel_system_resource_iptables_rules_file() { printf '%s\n' "${test_rules}"; } +case "$(uname -s)" in + MINGW*|MSYS*|CYGWIN*) + flock() { + [ "$#" -eq 4 ] && [ "$1" = -w ] && [ "$2" = 30 ] && [ "$3" = -x ] && [ "$4" = 9 ] + } + ;; +esac + crontab() { case "${1:-}" in -l) @@ -222,6 +239,38 @@ run_dispatch() { assert_receipt "${expected_status}" } +run_dispatch_stdin() { + local stdin_value="$1" + local expected_status="$2" + shift 2 + RUN_ARGS=("$@") + set +e + RUN_OUTPUT="$(printf '%s\n' "${stdin_value}" | kpanel_system_resource_dispatch "$@" 2> "${test_stderr}")" + RUN_RC=$? + set -e + assert_receipt "${expected_status}" +} + +run_dispatch_file() { + local stdin_path="$1" + local expected_status="$2" + shift 2 + RUN_ARGS=("$@") + set +e + RUN_OUTPUT="$(kpanel_system_resource_dispatch "$@" < "${stdin_path}" 2> "${test_stderr}")" + RUN_RC=$? + set -e + assert_receipt "${expected_status}" +} + +assert_argv_omits() { + local secret="$1" + local argument + for argument in "${RUN_ARGS[@]}"; do + [[ "${argument}" != *"${secret}"* ]] || fail "cron secret appeared in adapter argv" + done +} + zero_version="$(kpanel_system_resource_zero_version)" unset KJ_SYSTEM_RESOURCE_NONINTERACTIVE run_dispatch failed hosts add "${zero_version}" 127.0.0.1 guarded.local "" @@ -267,10 +316,15 @@ cmp -s -- "${hosts_before}" "${test_hosts}" || fail "hosts rollback did not rest cron_line='0 * * * * echo duplicate' printf '%s\n%s\n' "${cron_line}" "${cron_line}" > "${test_crontab}" cron_v0="$(kpanel_system_resource_cron_version)" -run_dispatch applied cron add "${cron_v0}" '15 2 * JAN MON' 'printf cron-data' +cron_secret=' printf cron-secret-value ' +run_dispatch_stdin "${cron_secret}" applied cron add "${cron_v0}" '15 2 * JAN MON' --command-stdin [ "${RUN_RC}" -eq 0 ] || fail "cron add with English names failed" +assert_argv_omits 'cron-secret-value' +printf '%s\n' "${RUN_OUTPUT}" | grep -F 'cron-secret-value' >/dev/null && fail "cron secret leaked to stdout" +grep -F 'cron-secret-value' "${test_stderr}" >/dev/null && fail "cron secret leaked to stderr" +grep -Fqx "15 2 * JAN MON ${cron_secret}" "${test_crontab}" || fail "cron command whitespace was not preserved" cron_v1="$(kpanel_system_resource_cron_version)" -run_dispatch applied cron update "${cron_v1}" 2 '*/5 * * * *' 'echo updated' +run_dispatch_stdin 'echo updated' applied cron update "${cron_v1}" 2 '*/5 * * * *' --command-stdin [ "${RUN_RC}" -eq 0 ] || fail "cron line-number update failed" [ "$(sed -n '2p' "${test_crontab}")" = '*/5 * * * * echo updated' ] || fail "cron update targeted the wrong row" cron_v2="$(kpanel_system_resource_cron_version)" @@ -280,9 +334,31 @@ run_dispatch applied cron delete "${cron_v2}" 1 cron_before_invalid="${test_root}/cron.before-invalid" command cp -- "${test_crontab}" "${cron_before_invalid}" cron_v2="$(kpanel_system_resource_cron_version)" -run_dispatch failed cron add "${cron_v2}" '0 0 L * *' 'echo quartz' +run_dispatch_stdin 'echo quartz' failed cron add "${cron_v2}" '0 0 L * *' --command-stdin [ "${RUN_RC}" -eq 2 ] || fail "Quartz cron token was not rejected" cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "invalid cron input changed the crontab" +legacy_secret='legacy-argv-secret' +run_dispatch failed cron add "${cron_v2}" '0 4 * * *' "${legacy_secret}" +[ "${RUN_RC}" -eq 2 ] || fail "legacy cron command argv was not rejected" +printf '%s\n' "${RUN_OUTPUT}" | grep -F "${legacy_secret}" >/dev/null && fail "rejected cron argv leaked to stdout" +grep -F "${legacy_secret}" "${test_stderr}" >/dev/null && fail "rejected cron argv leaked to stderr" +run_dispatch_stdin $'echo first\necho second' failed cron add "${cron_v2}" '0 4 * * *' --command-stdin +[ "${RUN_RC}" -eq 2 ] || fail "multiline cron stdin frame was not rejected" +printf -v overlong_command '%*s' 2049 '' +overlong_command="${overlong_command// /x}" +run_dispatch_stdin "${overlong_command}" failed cron add "${cron_v2}" '0 4 * * *' --command-stdin +[ "${RUN_RC}" -eq 2 ] || fail "overlong cron stdin frame was not rejected" +cron_bad_frame="${test_root}/cron-command.bad-frame" +printf 'echo safe\000echo hidden\n' > "${cron_bad_frame}" +run_dispatch_file "${cron_bad_frame}" failed cron add "${cron_v2}" '0 4 * * *' --command-stdin +[ "${RUN_RC}" -eq 2 ] || fail "NUL cron stdin frame was not rejected" +printf 'echo safe\recho hidden\n' > "${cron_bad_frame}" +run_dispatch_file "${cron_bad_frame}" failed cron add "${cron_v2}" '0 4 * * *' --command-stdin +[ "${RUN_RC}" -eq 2 ] || fail "CR cron stdin frame was not rejected" +printf 'echo unterminated' > "${cron_bad_frame}" +run_dispatch_file "${cron_bad_frame}" failed cron add "${cron_v2}" '0 4 * * *' --command-stdin +[ "${RUN_RC}" -eq 2 ] || fail "unterminated cron stdin frame was not rejected" +cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "rejected cron stdin frame changed the crontab" command cp -- "${test_crontab}" "${cron_before_invalid}" touch "${test_root}/crontab-read-error" run_dispatch failed cron delete "${cron_v2}" 1 @@ -291,7 +367,7 @@ command rm -f -- "${test_root}/crontab-read-error" cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "crontab read error changed the crontab" cron_v3="$(kpanel_system_resource_cron_version)" touch "${test_root}/crontab-install-error" -run_dispatch failed cron add "${cron_v3}" '0 3 * * *' 'echo rollback' +run_dispatch_stdin 'echo rollback' failed cron add "${cron_v3}" '0 3 * * *' --command-stdin [ "${RUN_RC}" -eq 1 ] || fail "cron install rollback path did not return 1" cmp -s -- "${cron_before_invalid}" "${test_crontab}" || fail "cron rollback did not restore original bytes" From f6732cc6580469f598d48866937f434db6c8ed2f Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 10 Aug 2026 12:11:04 +0800 Subject: [PATCH 1257/1285] fix(kpanel): version system resource protocol AI-Scope: kpanel-system-resource-adapters --- cn/kejilion.sh | 2 ++ kejilion.sh | 2 ++ tests/test_kpanel_system_resource_noninteractive_smoke.sh | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 1fc0ba4b3..dd68114a8 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -22130,6 +22130,8 @@ net_menu() { # KPanel system resource protocol start +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1" + kpanel_system_resource_zero_version() { printf '%064d' 0 } diff --git a/kejilion.sh b/kejilion.sh index 2af2dab9b..d6a35c770 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -22130,6 +22130,8 @@ net_menu() { # KPanel system resource protocol start +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1" + kpanel_system_resource_zero_version() { printf '%064d' 0 } diff --git a/tests/test_kpanel_system_resource_noninteractive_smoke.sh b/tests/test_kpanel_system_resource_noninteractive_smoke.sh index 3c3f348ea..fddefc901 100644 --- a/tests/test_kpanel_system_resource_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_resource_noninteractive_smoke.sh @@ -30,6 +30,10 @@ adapter_body="$( sed 's/\r$//' )" [ -n "${adapter_body}" ] || fail "system-resource adapter block was not found" +grep -Fqx 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1"' <<< "${adapter_body}" || + fail "system-resource protocol v1 marker is missing" +[ "$(grep -Fxc 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1"' <<< "${adapter_body}")" -eq 1 ] || + fail "system-resource protocol v1 marker must be unique" printf '%s\n' "${adapter_body}" | grep -F '[ "$command_source" = "--command-stdin" ]' >/dev/null || fail "cron command stdin marker is missing" if printf '%s\n' "${adapter_body}" | grep -E 'grep .*\$new_line' >/dev/null; then From f8b9e3b8c9b4a9ed29a9cf3ef99e122017449f34 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 10 Aug 2026 12:39:30 +0800 Subject: [PATCH 1258/1285] fix(kpanel): stabilize system resource protocol v2 AI-Scope: kpanel-system-resource-adapters --- cn/kejilion.sh | 213 +++++++++++++++-- kejilion.sh | 213 +++++++++++++++-- ...el_system_resource_noninteractive_smoke.sh | 224 +++++++++++++++++- 3 files changed, 595 insertions(+), 55 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dd68114a8..af7935d73 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -22130,7 +22130,7 @@ net_menu() { # KPanel system resource protocol start -KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1" +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2" kpanel_system_resource_zero_version() { printf '%064d' 0 @@ -22212,6 +22212,93 @@ kpanel_system_resource_tempdir() { printf '%s\n' "$directory" } +kpanel_system_resource_state_root() { + printf '%s\n' "/var/lib/kejilion-panel" +} + +kpanel_system_resource_path_has_no_symlink() { + local path="$1" + local remainder current="" component + local components=() + + [[ "$path" = /* ]] && [ "$path" != "/" ] || return 1 + remainder="${path#/}" + IFS=/ read -r -a components <<< "$remainder" + for component in "${components[@]}"; do + [ -n "$component" ] && [ "$component" != "." ] && [ "$component" != ".." ] || return 1 + current="$current/$component" + [ ! -L "$current" ] || return 1 + done +} + +kpanel_system_resource_secure_directory() { + local path="$1" + [ ! -L "$path" ] || return 1 + if [ -e "$path" ]; then + [ -d "$path" ] || return 1 + else + mkdir -- "$path" >/dev/null 2>&1 || return 1 + fi + [ -d "$path" ] && [ ! -L "$path" ] || return 1 + chown 0:0 "$path" >/dev/null 2>&1 && chmod 700 "$path" >/dev/null 2>&1 +} + +kpanel_system_resource_prepare_recovery_root() { + local state_root path mode + state_root="$(kpanel_system_resource_state_root)" || return 1 + kpanel_system_resource_single_line "$state_root" 1024 || return 1 + kpanel_system_resource_path_has_no_symlink "$state_root" || return 1 + if [ -e "$state_root" ]; then + [ -d "$state_root" ] && [ ! -L "$state_root" ] || return 1 + else + mkdir -- "$state_root" >/dev/null 2>&1 || return 1 + chmod 700 "$state_root" >/dev/null 2>&1 || return 1 + fi + chown 0:0 "$state_root" >/dev/null 2>&1 || return 1 + mode="$(stat -c '%a' "$state_root" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + path="$state_root" + for component in system recovery system-resource; do + path="$path/$component" + kpanel_system_resource_secure_directory "$path" || return 1 + done + printf '%s\n' "$path" +} + +kpanel_system_resource_persist_recovery_snapshot() { + local snapshot_dir="$1" + local resource="$2" + local recovery_root destination timestamp invalid + + [[ "$resource" =~ ^(hosts|cron|firewall)$ ]] || return 1 + [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 + invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 + [ -z "$invalid" ] || return 1 + recovery_root="$(kpanel_system_resource_prepare_recovery_root)" || return 1 + timestamp="$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null)" || return 1 + [[ "$timestamp" =~ ^[0-9]{8}T[0-9]{6}Z$ ]] || return 1 + destination="$(mktemp -d "$recovery_root/${timestamp}-${resource}.XXXXXX")" || return 1 + if ! chmod 700 "$destination" >/dev/null 2>&1 || + ! cp -a -- "$snapshot_dir/." "$destination/" >/dev/null 2>&1; then + rm -rf -- "$destination" + return 1 + fi + invalid="$(find "$destination" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || { + rm -rf -- "$destination" + return 1 + } + if [ -n "$invalid" ] || + ! chown -R -- 0:0 "$destination" >/dev/null 2>&1 || + ! find "$destination" -type d -exec chmod 700 -- {} + >/dev/null 2>&1 || + ! find "$destination" -type f -exec chmod 600 -- {} + >/dev/null 2>&1; then + rm -rf -- "$destination" + return 1 + fi + rm -rf -- "$snapshot_dir" >/dev/null 2>&1 || true + printf '%s\n' "$destination" +} + kpanel_system_resource_is_ipv4() { local value="$1" local first second third fourth extra octet @@ -22363,15 +22450,71 @@ kpanel_system_resource_interface_version() { printf '%s|%s|%s' "$name" "$state" "$mac" | sha256sum | awk '{print $1}' } +kpanel_system_resource_firewall_canonicalize() { + local source="$1" + local target="$2" + local bytes + + [ -f "$source" ] && [ ! -L "$source" ] || return 1 + bytes="$(wc -c < "$source" 2>/dev/null)" || return 1 + [ "$bytes" -le 524288 ] || return 1 + LC_ALL=C awk ' + { + line=$0 + sub(/\r$/, "", line) + if (index(line, "# Generated by iptables-save ") == 1 || + index(line, "# Completed on ") == 1) { + next + } + if (line ~ /^:/) { + sub(/ \[[0-9]+:[0-9]+\]$/, " [0:0]", line) + } + print line + } + ' "$source" > "$target" +} + +kpanel_system_resource_firewall_canonical_equal() { + local left="$1" + local right="$2" + local left_canonical right_canonical result + + left_canonical="$(mktemp /tmp/kejilion-system-resource-firewall-left.XXXXXX)" || return 2 + right_canonical="$(mktemp /tmp/kejilion-system-resource-firewall-right.XXXXXX)" || { + rm -f -- "$left_canonical" + return 2 + } + if ! kpanel_system_resource_firewall_canonicalize "$left" "$left_canonical" || + ! kpanel_system_resource_firewall_canonicalize "$right" "$right_canonical"; then + rm -f -- "$left_canonical" "$right_canonical" + return 2 + fi + if cmp -s -- "$left_canonical" "$right_canonical"; then + result=0 + else + result=$? + fi + rm -f -- "$left_canonical" "$right_canonical" + case "$result" in + 0|1) return "$result" ;; + *) return 2 ;; + esac +} + kpanel_system_resource_firewall_version() { - local temporary version - temporary="$(mktemp /tmp/kejilion-system-resource-firewall-version.XXXXXX)" || return 1 - if ! kpanel_system_resource_firewall_capture "$temporary"; then - rm -f -- "$temporary" + local raw canonical version + raw="$(mktemp /tmp/kejilion-system-resource-firewall-version-raw.XXXXXX)" || return 1 + canonical="$(mktemp /tmp/kejilion-system-resource-firewall-version-canonical.XXXXXX)" || { + rm -f -- "$raw" + return 1 + } + if ! kpanel_system_resource_firewall_capture "$raw" || + ! kpanel_system_resource_firewall_canonicalize "$raw" "$canonical"; then + rm -f -- "$raw" "$canonical" return 1 fi - version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" - rm -f -- "$temporary" + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$raw" "$canonical" [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 printf '%s\n' "$version" } @@ -22446,7 +22589,7 @@ kpanel_system_resource_require_platform() { kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" return 2 fi - for command_name in sha256sum mktemp flock; do + for command_name in sha256sum mktemp flock find date; do command -v "$command_name" >/dev/null 2>&1 || { kpanel_system_resource_error "缺少必要命令: $command_name" kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" @@ -22497,7 +22640,7 @@ kpanel_system_resource_hosts_failure() { local snapshot_dir="$3" local original_version="$4" local message="$5" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_restore_hosts "$path" "$backup" "$original_version"; then @@ -22507,7 +22650,12 @@ kpanel_system_resource_hosts_failure() { else version="$(kpanel_system_resource_best_version hosts)" kpanel_system_resource_error "hosts 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" hosts)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "hosts 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -22843,7 +22991,7 @@ kpanel_system_resource_cron_failure() { local existed="$3" local message="$4" local verify="$snapshot_dir/rollback.verify" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_cron_restore "$backup" "$existed" "$verify"; then @@ -22853,7 +23001,12 @@ kpanel_system_resource_cron_failure() { else version="$(kpanel_system_resource_best_version cron)" kpanel_system_resource_error "crontab 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" cron)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "crontab 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -23414,6 +23567,7 @@ kpanel_system_resource_firewall_persist() { local snapshot_dir="$1" local rules_path parent desired_rules verify_rules local cron_current cron_desired cron_verify restore_line count current_line + local comparison KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=false rules_path="$(kpanel_system_resource_iptables_rules_file)" @@ -23425,7 +23579,19 @@ kpanel_system_resource_firewall_persist() { rm -f -- "$desired_rules" return 1 fi - if [ -f "$rules_path" ] && cmp -s -- "$desired_rules" "$rules_path"; then + comparison=1 + if [ -f "$rules_path" ]; then + if kpanel_system_resource_firewall_canonical_equal "$desired_rules" "$rules_path"; then + comparison=0 + else + comparison=$? + fi + if [ "$comparison" -gt 1 ]; then + rm -f -- "$desired_rules" + return 1 + fi + fi + if [ "$comparison" -eq 0 ]; then rm -f -- "$desired_rules" else if [ -f "$rules_path" ]; then @@ -23446,8 +23612,8 @@ kpanel_system_resource_firewall_persist() { KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true fi verify_rules="$snapshot_dir/iptables.persist.verify" - kpanel_system_resource_firewall_capture "$verify_rules" && - cmp -s -- "$verify_rules" "$rules_path" || return 1 + kpanel_system_resource_firewall_capture "$verify_rules" || return 1 + kpanel_system_resource_firewall_canonical_equal "$verify_rules" "$rules_path" || return 1 restore_line='@reboot iptables-restore < /etc/iptables/rules.v4' cron_current="$snapshot_dir/crontab.persist.current" @@ -23490,7 +23656,7 @@ kpanel_system_resource_firewall_restore() { fi kpanel_system_resource_cron_restore "$snapshot_dir/crontab" "$cron_existed" "$cron_verify" || failed=true kpanel_system_resource_firewall_capture "$verify" || failed=true - cmp -s -- "$snapshot_dir/iptables.rules" "$verify" || failed=true + kpanel_system_resource_firewall_canonical_equal "$snapshot_dir/iptables.rules" "$verify" || failed=true if [ "$rules_existed" = true ]; then cmp -s -- "$snapshot_dir/rules.v4" "$rules_path" || failed=true else @@ -23505,7 +23671,7 @@ kpanel_system_resource_firewall_failure() { local rules_existed="$3" local cron_existed="$4" local message="$5" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_firewall_restore "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed"; then @@ -23515,7 +23681,12 @@ kpanel_system_resource_firewall_failure() { else version="$(kpanel_system_resource_best_version firewall)" kpanel_system_resource_error "iptables 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" firewall)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "iptables 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -23638,11 +23809,11 @@ kpanel_system_resource_run_locked() ( kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" return 1 } - if ! flock -w 30 -x 9 >/dev/null 2>&1; then + if ! flock -w 5 -x 9 >/dev/null 2>&1; then [ "$resource" = "network-interface" ] && name="${2:-}" kpanel_system_resource_error "system-resource 写锁等待超时" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" - return 1 + kpanel_system_resource_emit conflict "$(kpanel_system_resource_best_version "$resource" "$name")" + return 2 fi case "$resource" in hosts) kpanel_system_resource_hosts_action "$action" "$@" ;; diff --git a/kejilion.sh b/kejilion.sh index d6a35c770..de8be37c2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -22130,7 +22130,7 @@ net_menu() { # KPanel system resource protocol start -KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1" +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2" kpanel_system_resource_zero_version() { printf '%064d' 0 @@ -22212,6 +22212,93 @@ kpanel_system_resource_tempdir() { printf '%s\n' "$directory" } +kpanel_system_resource_state_root() { + printf '%s\n' "/var/lib/kejilion-panel" +} + +kpanel_system_resource_path_has_no_symlink() { + local path="$1" + local remainder current="" component + local components=() + + [[ "$path" = /* ]] && [ "$path" != "/" ] || return 1 + remainder="${path#/}" + IFS=/ read -r -a components <<< "$remainder" + for component in "${components[@]}"; do + [ -n "$component" ] && [ "$component" != "." ] && [ "$component" != ".." ] || return 1 + current="$current/$component" + [ ! -L "$current" ] || return 1 + done +} + +kpanel_system_resource_secure_directory() { + local path="$1" + [ ! -L "$path" ] || return 1 + if [ -e "$path" ]; then + [ -d "$path" ] || return 1 + else + mkdir -- "$path" >/dev/null 2>&1 || return 1 + fi + [ -d "$path" ] && [ ! -L "$path" ] || return 1 + chown 0:0 "$path" >/dev/null 2>&1 && chmod 700 "$path" >/dev/null 2>&1 +} + +kpanel_system_resource_prepare_recovery_root() { + local state_root path mode + state_root="$(kpanel_system_resource_state_root)" || return 1 + kpanel_system_resource_single_line "$state_root" 1024 || return 1 + kpanel_system_resource_path_has_no_symlink "$state_root" || return 1 + if [ -e "$state_root" ]; then + [ -d "$state_root" ] && [ ! -L "$state_root" ] || return 1 + else + mkdir -- "$state_root" >/dev/null 2>&1 || return 1 + chmod 700 "$state_root" >/dev/null 2>&1 || return 1 + fi + chown 0:0 "$state_root" >/dev/null 2>&1 || return 1 + mode="$(stat -c '%a' "$state_root" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + path="$state_root" + for component in system recovery system-resource; do + path="$path/$component" + kpanel_system_resource_secure_directory "$path" || return 1 + done + printf '%s\n' "$path" +} + +kpanel_system_resource_persist_recovery_snapshot() { + local snapshot_dir="$1" + local resource="$2" + local recovery_root destination timestamp invalid + + [[ "$resource" =~ ^(hosts|cron|firewall)$ ]] || return 1 + [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 + invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 + [ -z "$invalid" ] || return 1 + recovery_root="$(kpanel_system_resource_prepare_recovery_root)" || return 1 + timestamp="$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null)" || return 1 + [[ "$timestamp" =~ ^[0-9]{8}T[0-9]{6}Z$ ]] || return 1 + destination="$(mktemp -d "$recovery_root/${timestamp}-${resource}.XXXXXX")" || return 1 + if ! chmod 700 "$destination" >/dev/null 2>&1 || + ! cp -a -- "$snapshot_dir/." "$destination/" >/dev/null 2>&1; then + rm -rf -- "$destination" + return 1 + fi + invalid="$(find "$destination" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || { + rm -rf -- "$destination" + return 1 + } + if [ -n "$invalid" ] || + ! chown -R -- 0:0 "$destination" >/dev/null 2>&1 || + ! find "$destination" -type d -exec chmod 700 -- {} + >/dev/null 2>&1 || + ! find "$destination" -type f -exec chmod 600 -- {} + >/dev/null 2>&1; then + rm -rf -- "$destination" + return 1 + fi + rm -rf -- "$snapshot_dir" >/dev/null 2>&1 || true + printf '%s\n' "$destination" +} + kpanel_system_resource_is_ipv4() { local value="$1" local first second third fourth extra octet @@ -22363,15 +22450,71 @@ kpanel_system_resource_interface_version() { printf '%s|%s|%s' "$name" "$state" "$mac" | sha256sum | awk '{print $1}' } +kpanel_system_resource_firewall_canonicalize() { + local source="$1" + local target="$2" + local bytes + + [ -f "$source" ] && [ ! -L "$source" ] || return 1 + bytes="$(wc -c < "$source" 2>/dev/null)" || return 1 + [ "$bytes" -le 524288 ] || return 1 + LC_ALL=C awk ' + { + line=$0 + sub(/\r$/, "", line) + if (index(line, "# Generated by iptables-save ") == 1 || + index(line, "# Completed on ") == 1) { + next + } + if (line ~ /^:/) { + sub(/ \[[0-9]+:[0-9]+\]$/, " [0:0]", line) + } + print line + } + ' "$source" > "$target" +} + +kpanel_system_resource_firewall_canonical_equal() { + local left="$1" + local right="$2" + local left_canonical right_canonical result + + left_canonical="$(mktemp /tmp/kejilion-system-resource-firewall-left.XXXXXX)" || return 2 + right_canonical="$(mktemp /tmp/kejilion-system-resource-firewall-right.XXXXXX)" || { + rm -f -- "$left_canonical" + return 2 + } + if ! kpanel_system_resource_firewall_canonicalize "$left" "$left_canonical" || + ! kpanel_system_resource_firewall_canonicalize "$right" "$right_canonical"; then + rm -f -- "$left_canonical" "$right_canonical" + return 2 + fi + if cmp -s -- "$left_canonical" "$right_canonical"; then + result=0 + else + result=$? + fi + rm -f -- "$left_canonical" "$right_canonical" + case "$result" in + 0|1) return "$result" ;; + *) return 2 ;; + esac +} + kpanel_system_resource_firewall_version() { - local temporary version - temporary="$(mktemp /tmp/kejilion-system-resource-firewall-version.XXXXXX)" || return 1 - if ! kpanel_system_resource_firewall_capture "$temporary"; then - rm -f -- "$temporary" + local raw canonical version + raw="$(mktemp /tmp/kejilion-system-resource-firewall-version-raw.XXXXXX)" || return 1 + canonical="$(mktemp /tmp/kejilion-system-resource-firewall-version-canonical.XXXXXX)" || { + rm -f -- "$raw" + return 1 + } + if ! kpanel_system_resource_firewall_capture "$raw" || + ! kpanel_system_resource_firewall_canonicalize "$raw" "$canonical"; then + rm -f -- "$raw" "$canonical" return 1 fi - version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" - rm -f -- "$temporary" + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$raw" "$canonical" [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 printf '%s\n' "$version" } @@ -22446,7 +22589,7 @@ kpanel_system_resource_require_platform() { kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" return 2 fi - for command_name in sha256sum mktemp flock; do + for command_name in sha256sum mktemp flock find date; do command -v "$command_name" >/dev/null 2>&1 || { kpanel_system_resource_error "缺少必要命令: $command_name" kpanel_system_resource_emit failed "$(kpanel_system_resource_zero_version)" @@ -22497,7 +22640,7 @@ kpanel_system_resource_hosts_failure() { local snapshot_dir="$3" local original_version="$4" local message="$5" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_restore_hosts "$path" "$backup" "$original_version"; then @@ -22507,7 +22650,12 @@ kpanel_system_resource_hosts_failure() { else version="$(kpanel_system_resource_best_version hosts)" kpanel_system_resource_error "hosts 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" hosts)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "hosts 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -22843,7 +22991,7 @@ kpanel_system_resource_cron_failure() { local existed="$3" local message="$4" local verify="$snapshot_dir/rollback.verify" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_cron_restore "$backup" "$existed" "$verify"; then @@ -22853,7 +23001,12 @@ kpanel_system_resource_cron_failure() { else version="$(kpanel_system_resource_best_version cron)" kpanel_system_resource_error "crontab 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" cron)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "crontab 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -23414,6 +23567,7 @@ kpanel_system_resource_firewall_persist() { local snapshot_dir="$1" local rules_path parent desired_rules verify_rules local cron_current cron_desired cron_verify restore_line count current_line + local comparison KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=false rules_path="$(kpanel_system_resource_iptables_rules_file)" @@ -23425,7 +23579,19 @@ kpanel_system_resource_firewall_persist() { rm -f -- "$desired_rules" return 1 fi - if [ -f "$rules_path" ] && cmp -s -- "$desired_rules" "$rules_path"; then + comparison=1 + if [ -f "$rules_path" ]; then + if kpanel_system_resource_firewall_canonical_equal "$desired_rules" "$rules_path"; then + comparison=0 + else + comparison=$? + fi + if [ "$comparison" -gt 1 ]; then + rm -f -- "$desired_rules" + return 1 + fi + fi + if [ "$comparison" -eq 0 ]; then rm -f -- "$desired_rules" else if [ -f "$rules_path" ]; then @@ -23446,8 +23612,8 @@ kpanel_system_resource_firewall_persist() { KPANEL_SYSTEM_RESOURCE_FIREWALL_PERSIST_CHANGED=true fi verify_rules="$snapshot_dir/iptables.persist.verify" - kpanel_system_resource_firewall_capture "$verify_rules" && - cmp -s -- "$verify_rules" "$rules_path" || return 1 + kpanel_system_resource_firewall_capture "$verify_rules" || return 1 + kpanel_system_resource_firewall_canonical_equal "$verify_rules" "$rules_path" || return 1 restore_line='@reboot iptables-restore < /etc/iptables/rules.v4' cron_current="$snapshot_dir/crontab.persist.current" @@ -23490,7 +23656,7 @@ kpanel_system_resource_firewall_restore() { fi kpanel_system_resource_cron_restore "$snapshot_dir/crontab" "$cron_existed" "$cron_verify" || failed=true kpanel_system_resource_firewall_capture "$verify" || failed=true - cmp -s -- "$snapshot_dir/iptables.rules" "$verify" || failed=true + kpanel_system_resource_firewall_canonical_equal "$snapshot_dir/iptables.rules" "$verify" || failed=true if [ "$rules_existed" = true ]; then cmp -s -- "$snapshot_dir/rules.v4" "$rules_path" || failed=true else @@ -23505,7 +23671,7 @@ kpanel_system_resource_firewall_failure() { local rules_existed="$3" local cron_existed="$4" local message="$5" - local version + local version recovery_path kpanel_system_resource_error "$message" if kpanel_system_resource_firewall_restore "$snapshot_dir" "$rules_path" "$rules_existed" "$cron_existed"; then @@ -23515,7 +23681,12 @@ kpanel_system_resource_firewall_failure() { else version="$(kpanel_system_resource_best_version firewall)" kpanel_system_resource_error "iptables 回滚失败,需要人工恢复" - kpanel_system_resource_emit rollback-failed "$version" "$snapshot_dir" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot_dir" firewall)"; then + kpanel_system_resource_emit rollback-failed "$version" "$recovery_path" + else + kpanel_system_resource_error "iptables 失败快照持久化失败,未生成宿主可见备份路径" + kpanel_system_resource_emit rollback-failed "$version" + fi fi return 1 } @@ -23638,11 +23809,11 @@ kpanel_system_resource_run_locked() ( kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" return 1 } - if ! flock -w 30 -x 9 >/dev/null 2>&1; then + if ! flock -w 5 -x 9 >/dev/null 2>&1; then [ "$resource" = "network-interface" ] && name="${2:-}" kpanel_system_resource_error "system-resource 写锁等待超时" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" - return 1 + kpanel_system_resource_emit conflict "$(kpanel_system_resource_best_version "$resource" "$name")" + return 2 fi case "$resource" in hosts) kpanel_system_resource_hosts_action "$action" "$@" ;; diff --git a/tests/test_kpanel_system_resource_noninteractive_smoke.sh b/tests/test_kpanel_system_resource_noninteractive_smoke.sh index fddefc901..b850153ca 100644 --- a/tests/test_kpanel_system_resource_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_resource_noninteractive_smoke.sh @@ -4,7 +4,11 @@ set -euo pipefail project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" script_path="${project_root}/kejilion.sh" test_root="$(mktemp -d)" -trap 'rm -rf -- "${test_root}"' EXIT +case "$(uname -s)" in + Linux) test_recovery_state="/var/tmp/kejilion-panel-system-resource-test.$$" ;; + *) test_recovery_state="${project_root}/.test-kpanel-system-resource-recovery.$$" ;; +esac +trap 'rm -rf -- "${test_root}" "${test_recovery_state}"' EXIT fail() { printf 'FAIL: %s\n' "$1" >&2 @@ -24,16 +28,21 @@ grep -F 'iptables -w 5 "$@"' "${script_path}" >/dev/null grep -F 'iptables-restore -w 5' "${script_path}" >/dev/null grep -F 'allow-ip|block-ip|remove-ip)' "${script_path}" >/dev/null grep -F 'open-all|close-all|enable-ping|disable-ping|enable-ddos|disable-ddos)' "${script_path}" >/dev/null +grep -F 'printf '\''%s\n'\'' "/var/lib/kejilion-panel"' "${script_path}" >/dev/null +grep -F 'chown -R -- 0:0 "$destination"' "${script_path}" >/dev/null +grep -F 'find "$destination" -type d -exec chmod 700' "${script_path}" >/dev/null +grep -F 'find "$destination" -type f -exec chmod 600' "${script_path}" >/dev/null +grep -F 'flock -w 5 -x 9' "${script_path}" >/dev/null adapter_body="$( sed -n '/^# KPanel system resource protocol start/,/^# KPanel system resource protocol end/p' "${script_path}" | sed 's/\r$//' )" [ -n "${adapter_body}" ] || fail "system-resource adapter block was not found" -grep -Fqx 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1"' <<< "${adapter_body}" || - fail "system-resource protocol v1 marker is missing" -[ "$(grep -Fxc 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="1"' <<< "${adapter_body}")" -eq 1 ] || - fail "system-resource protocol v1 marker must be unique" +grep -Fqx 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2"' <<< "${adapter_body}" || + fail "system-resource protocol v2 marker is missing" +[ "$(grep -Fxc 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2"' <<< "${adapter_body}")" -eq 1 ] || + fail "system-resource protocol v2 marker must be unique" printf '%s\n' "${adapter_body}" | grep -F '[ "$command_source" = "--command-stdin" ]' >/dev/null || fail "cron command stdin marker is missing" if printf '%s\n' "${adapter_body}" | grep -E 'grep .*\$new_line' >/dev/null; then @@ -54,14 +63,25 @@ kpanel_system_resource_hosts_file() { printf '%s\n' "${test_hosts}"; } kpanel_system_resource_lock_file() { printf '%s\n' "${test_lock}"; } kpanel_system_resource_interfaces_dir() { printf '%s\n' "${test_interfaces}"; } kpanel_system_resource_iptables_rules_file() { printf '%s\n' "${test_rules}"; } +kpanel_system_resource_state_root() { + printf '%s\n' "${KPANEL_FAKE_RECOVERY_STATE_ROOT:-${test_recovery_state}}" +} +kpanel_system_resource_tempdir() { + local resource="$1" + local directory + directory="$(mktemp -d "${test_root}/kejilion-system-resource-${resource}.XXXXXX")" || return 1 + chmod 700 "${directory}" || return 1 + printf '%s\n' "${directory}" +} -case "$(uname -s)" in - MINGW*|MSYS*|CYGWIN*) - flock() { - [ "$#" -eq 4 ] && [ "$1" = -w ] && [ "$2" = 30 ] && [ "$3" = -x ] && [ "$4" = 9 ] - } - ;; -esac +flock() { + [ "$#" -eq 4 ] && [ "$1" = -w ] && [ "$2" = 5 ] && [ "$3" = -x ] && [ "$4" = 9 ] || return 1 + [ "${KPANEL_FAKE_FLOCK_TIMEOUT:-0}" != 1 ] || return 1 + case "$(uname -s)" in + MINGW*|MSYS*|CYGWIN*) return 0 ;; + *) command flock "$@" ;; + esac +} crontab() { case "${1:-}" in @@ -205,7 +225,11 @@ iptables-save() { iptables-restore() { [ "${1:-}" = -w ] && [ "${2:-}" = 5 ] || return 1 - command cat > "${test_iptables}" + command cat > "${test_root}/iptables-restore.last" || return 1 + command cp -- "${test_root}/iptables-restore.last" "${test_iptables}" || return 1 + if [ -f "${test_root}/iptables-restore-output" ]; then + command cp -- "${test_root}/iptables-restore-output" "${test_iptables}" || return 1 + fi } mv() { @@ -217,6 +241,24 @@ mv() { command mv "$@" } +cp() { + local destination="${!#}" + if [ "${KPANEL_FAKE_HOSTS_RESTORE_FAIL:-0}" = 1 ] && [ "${destination}" = "${test_hosts}" ]; then + return 1 + fi + command cp "$@" +} + +chown() { + local argument + if [ "$(id -u)" -ne 0 ]; then + for argument in "$@"; do + [ "${argument}" != 0:0 ] || return 0 + done + fi + command chown "$@" +} + assert_receipt() { local expected_status="$1" local line_count @@ -288,6 +330,11 @@ kpanel_system_resource_require_platform() { fi } +KPANEL_FAKE_FLOCK_TIMEOUT=1 +run_dispatch conflict hosts add "${zero_version}" 127.0.0.1 locked.local "" +unset KPANEL_FAKE_FLOCK_TIMEOUT +[ "${RUN_RC}" -eq 2 ] || fail "system-resource lock timeout did not return conflict" + printf '%s\n' \ '127.0.0.1 localhost' \ '10.0.0.1 duplicate.local' \ @@ -317,6 +364,52 @@ unset KPANEL_FAKE_HOSTS_MV_FAIL [ "${RUN_RC}" -eq 1 ] || fail "hosts rollback path did not return 1" cmp -s -- "${hosts_before}" "${test_hosts}" || fail "hosts rollback did not restore original bytes" +printf '%s\n' '127.0.0.1 localhost' '192.0.2.30 recovery.local' > "${test_hosts}" +hosts_recovery_before="${test_root}/hosts.before-needs-attention" +command cp -- "${test_hosts}" "${hosts_recovery_before}" +hosts_recovery_v="$(kpanel_system_resource_hosts_version)" +KPANEL_FAKE_HOSTS_MV_FAIL=1 +KPANEL_FAKE_HOSTS_RESTORE_FAIL=1 +run_dispatch rollback-failed hosts add "${hosts_recovery_v}" 192.0.2.31 broken-rollback.local "" +unset KPANEL_FAKE_HOSTS_MV_FAIL KPANEL_FAKE_HOSTS_RESTORE_FAIL +[ "${RUN_RC}" -eq 1 ] || fail "hosts rollback-failed path did not return 1" +recovery_path="$(printf '%s\n' "${RUN_OUTPUT}" | sed -n 's/^KPANEL_SYSTEM_RESOURCE_BACKUP=//p')" +[ -n "${recovery_path}" ] || fail "rollback-failed receipt did not include a persistent backup" +[[ "${recovery_path}" = "${test_recovery_state}/system/recovery/system-resource/"* ]] || + fail "rollback-failed backup was outside the recovery state directory: ${recovery_path}" +[[ "${recovery_path}" != /tmp/* ]] || fail "rollback-failed backup remained in PrivateTmp" +[ -d "${recovery_path}" ] && [ ! -L "${recovery_path}" ] || fail "persistent recovery backup is not a real directory" +cmp -s -- "${hosts_recovery_before}" "${recovery_path}/hosts.backup" || + fail "persistent recovery backup did not preserve the original hosts bytes" +if [ "$(uname -s)" = Linux ]; then + [ "$(stat -c '%a' "${recovery_path}")" = 700 ] || fail "persistent recovery directory mode is not 0700" + [ "$(stat -c '%a' "${recovery_path}/hosts.backup")" = 600 ] || fail "persistent recovery file mode is not 0600" + if [ "$(id -u)" -eq 0 ]; then + [ "$(stat -c '%u:%g' "${recovery_path}")" = 0:0 ] || fail "persistent recovery directory is not root-owned" + [ "$(stat -c '%u:%g' "${recovery_path}/hosts.backup")" = 0:0 ] || fail "persistent recovery file is not root-owned" + fi +fi + +printf '%s\n' '127.0.0.1 localhost' '192.0.2.40 recovery-fail.local' > "${test_hosts}" +hosts_recovery_fail_before="${test_root}/hosts.before-recovery-persist-fail" +command cp -- "${test_hosts}" "${hosts_recovery_fail_before}" +hosts_recovery_fail_v="$(kpanel_system_resource_hosts_version)" +KPANEL_FAKE_HOSTS_MV_FAIL=1 +KPANEL_FAKE_HOSTS_RESTORE_FAIL=1 +KPANEL_FAKE_RECOVERY_STATE_ROOT="${test_root}/missing-parent/state" +run_dispatch rollback-failed hosts add "${hosts_recovery_fail_v}" 192.0.2.41 no-backup.local "" +unset KPANEL_FAKE_HOSTS_MV_FAIL KPANEL_FAKE_HOSTS_RESTORE_FAIL KPANEL_FAKE_RECOVERY_STATE_ROOT +[ "${RUN_RC}" -eq 1 ] || fail "recovery persistence failure did not return rollback-failed" +if printf '%s\n' "${RUN_OUTPUT}" | grep -q '^KPANEL_SYSTEM_RESOURCE_BACKUP='; then + fail "recovery persistence failure emitted a false backup path" +fi +grep -F '失败快照持久化失败' "${test_stderr}" >/dev/null || + fail "recovery persistence failure was not reported on stderr" +private_recovery_path="$(find "${test_root}" -maxdepth 1 -type d -name 'kejilion-system-resource-hosts.*' -print -quit)" +[ -n "${private_recovery_path}" ] || fail "failed recovery persistence discarded the PrivateTmp fallback snapshot" +cmp -s -- "${hosts_recovery_fail_before}" "${private_recovery_path}/hosts.backup" || + fail "PrivateTmp fallback snapshot did not preserve the original hosts bytes" + cron_line='0 * * * * echo duplicate' printf '%s\n%s\n' "${cron_line}" "${cron_line}" > "${test_crontab}" cron_v0="$(kpanel_system_resource_cron_version)" @@ -392,6 +485,111 @@ run_dispatch failed network-interface state "${interface_v1}" eth-test down [ "${RUN_RC}" -eq 1 ] || fail "partial network interface failure did not return 1" [ "$(kpanel_system_resource_interface_admin_state eth-test)" = up ] || fail "network interface rollback did not restore admin state" +firewall_dynamic_a="${test_root}/iptables.dynamic-a" +firewall_dynamic_b="${test_root}/iptables.dynamic-b" +firewall_rule_changed="${test_root}/iptables.rule-changed" +firewall_policy_changed="${test_root}/iptables.policy-changed" +printf '%s\r\n' \ + '# Generated by iptables-save v1.8.9 (nf_tables) on Mon Aug 10 00:00:00 2026' \ + '*filter' \ + ':INPUT ACCEPT [123:456]' \ + ':FORWARD DROP [7:8]' \ + '-A INPUT -p tcp --dport 22 -j ACCEPT' \ + '# Static audit [12:34]' \ + 'COMMIT' \ + '# Completed on Mon Aug 10 00:00:01 2026' > "${firewall_dynamic_a}" +printf '%s\n' \ + '# Generated by iptables-save v9.9.9 on Tue Aug 11 11:11:11 2026' \ + '*filter' \ + ':INPUT ACCEPT [999:888]' \ + ':FORWARD DROP [0:999]' \ + '-A INPUT -p tcp --dport 22 -j ACCEPT' \ + '# Static audit [12:34]' \ + 'COMMIT' \ + '# Completed on Tue Aug 11 11:11:12 2026' > "${firewall_dynamic_b}" +printf '%s\n' \ + '# Generated by iptables-save v9.9.9 on Tue Aug 11 11:11:11 2026' \ + '*filter' \ + ':INPUT ACCEPT [999:888]' \ + ':FORWARD DROP [0:999]' \ + '-A INPUT -p tcp --dport 23 -j ACCEPT' \ + '# Static audit [12:34]' \ + 'COMMIT' \ + '# Completed on Tue Aug 11 11:11:12 2026' > "${firewall_rule_changed}" +printf '%s\n' \ + '# Generated by iptables-save v9.9.9 on Tue Aug 11 11:11:11 2026' \ + '*filter' \ + ':INPUT DROP [999:888]' \ + ':FORWARD DROP [0:999]' \ + '-A INPUT -p tcp --dport 22 -j ACCEPT' \ + '# Static audit [12:34]' \ + 'COMMIT' \ + '# Completed on Tue Aug 11 11:11:12 2026' > "${firewall_policy_changed}" + +firewall_canonical_actual="${test_root}/iptables.canonical-actual" +firewall_canonical_expected="${test_root}/iptables.canonical-expected" +printf '%s\n' \ + '*filter' \ + ':INPUT ACCEPT [0:0]' \ + ':FORWARD DROP [0:0]' \ + '-A INPUT -p tcp --dport 22 -j ACCEPT' \ + '# Static audit [12:34]' \ + 'COMMIT' > "${firewall_canonical_expected}" +kpanel_system_resource_firewall_canonicalize "${firewall_dynamic_a}" "${firewall_canonical_actual}" || + fail "firewall canonicalization failed" +cmp -s -- "${firewall_canonical_expected}" "${firewall_canonical_actual}" || + fail "firewall canonical bytes do not match the protocol definition" + +command cp -- "${firewall_dynamic_a}" "${test_iptables}" +firewall_dynamic_v1="$(kpanel_system_resource_firewall_version)" +command cp -- "${firewall_dynamic_b}" "${test_iptables}" +firewall_dynamic_v2="$(kpanel_system_resource_firewall_version)" +[ "${firewall_dynamic_v1}" = "${firewall_dynamic_v2}" ] || + fail "firewall version changed for timestamp, counter, or CRLF-only differences" +command cp -- "${firewall_rule_changed}" "${test_iptables}" +firewall_rule_v="$(kpanel_system_resource_firewall_version)" +[ "${firewall_dynamic_v1}" != "${firewall_rule_v}" ] || fail "firewall version ignored a rule change" +command cp -- "${firewall_policy_changed}" "${test_iptables}" +firewall_policy_v="$(kpanel_system_resource_firewall_version)" +[ "${firewall_dynamic_v1}" != "${firewall_policy_v}" ] || fail "firewall version ignored a policy change" + +canonical_cron_before="${test_root}/cron.before-canonical-firewall" +canonical_rules_before="${test_root}/rules.before-canonical-firewall" +canonical_snapshot_dir="${test_root}/firewall-canonical-snapshot" +canonical_persist_dir="${test_root}/firewall-canonical-persist" +command cp -- "${test_crontab}" "${canonical_cron_before}" +command cp -- "${firewall_dynamic_a}" "${test_rules}" +command cp -- "${test_rules}" "${canonical_rules_before}" +command cp -- "${firewall_dynamic_b}" "${test_iptables}" +mkdir -p -- "${canonical_persist_dir}" +kpanel_system_resource_firewall_persist "${canonical_persist_dir}" || + fail "firewall persist rejected a semantically identical dynamic capture" +cmp -s -- "${canonical_rules_before}" "${test_rules}" || + fail "firewall persist rewrote the raw rules snapshot for dynamic-only differences" + +mkdir -p -- "${canonical_snapshot_dir}" +kpanel_system_resource_firewall_snapshot "${canonical_snapshot_dir}" "${test_rules}" || + fail "firewall raw snapshot failed" +cmp -s -- "${firewall_dynamic_b}" "${canonical_snapshot_dir}/iptables.rules" || + fail "firewall runtime snapshot was canonicalized instead of kept raw" +cmp -s -- "${canonical_rules_before}" "${canonical_snapshot_dir}/rules.v4" || + fail "firewall persisted snapshot was canonicalized instead of kept raw" +canonical_cron_existed="${KPANEL_SYSTEM_RESOURCE_FIREWALL_CRON_EXISTED}" +command cp -- "${firewall_rule_changed}" "${test_iptables}" +command cp -- "${firewall_rule_changed}" "${test_rules}" +command cp -- "${firewall_dynamic_a}" "${test_root}/iptables-restore-output" +kpanel_system_resource_firewall_restore \ + "${canonical_snapshot_dir}" "${test_rules}" true "${canonical_cron_existed}" || + fail "firewall restore rejected a semantically identical dynamic capture" +cmp -s -- "${firewall_dynamic_b}" "${test_root}/iptables-restore.last" || + fail "firewall restore input was canonicalized instead of kept raw" +cmp -s -- "${firewall_dynamic_a}" "${test_iptables}" || + fail "firewall restore fixture did not expose dynamic-only output" +cmp -s -- "${canonical_rules_before}" "${test_rules}" || + fail "firewall restore did not preserve the raw persisted rules snapshot" +command rm -f -- "${test_root}/iptables-restore-output" "${test_rules}" +command cp -- "${canonical_cron_before}" "${test_crontab}" + printf '%s\n' \ '-P INPUT ACCEPT' \ '-P FORWARD ACCEPT' \ From 3972217d4d4a51d473b7375f5b850870e066be92 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 10 Aug 2026 13:06:26 +0800 Subject: [PATCH 1259/1285] fix(kpanel): secure system resource lock AI-Scope: kpanel-system-resource-adapters --- cn/kejilion.sh | 96 +++++++++++++++--- kejilion.sh | 96 +++++++++++++++--- ...el_system_resource_noninteractive_smoke.sh | 98 +++++++++++++++++-- 3 files changed, 261 insertions(+), 29 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index af7935d73..4d15f8047 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -22130,7 +22130,7 @@ net_menu() { # KPanel system resource protocol start -KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2" +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="3" kpanel_system_resource_zero_version() { printf '%064d' 0 @@ -22189,8 +22189,24 @@ kpanel_system_resource_hosts_file() { printf '%s\n' "/etc/hosts" } +kpanel_system_resource_lock_dir() { + printf '%s\n' "/run/kejilion-system-resource" +} + +kpanel_system_resource_lock_owner_uid() { + printf '0\n' +} + +kpanel_system_resource_lock_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_system_resource_lock_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + kpanel_system_resource_lock_file() { - printf '%s\n' "/run/lock/kejilion-system-resource.lock" + printf '%s/system-resource.lock\n' "$(kpanel_system_resource_lock_dir)" } kpanel_system_resource_interfaces_dir() { @@ -22231,6 +22247,60 @@ kpanel_system_resource_path_has_no_symlink() { done } +kpanel_system_resource_lock_path_secure() { + local path="$1" + local kind="$2" + local required_mode="${3:-}" + local uid expected_uid mode + + [ ! -L "$path" ] || return 1 + case "$kind" in + directory) [ -d "$path" ] ;; + file) [ -f "$path" ] ;; + *) return 1 ;; + esac || return 1 + uid="$(kpanel_system_resource_lock_stat_uid "$path")" || return 1 + expected_uid="$(kpanel_system_resource_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [[ "$expected_uid" =~ ^[0-9]+$ ]] && + [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_system_resource_lock_stat_mode "$path")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + [ -z "$required_mode" ] || [ "$((8#$mode & 0777))" -eq "$((8#$required_mode))" ] +} + +kpanel_system_resource_prepare_lock_file() { + local lock_dir lock_parent lock_file + + lock_dir="$(kpanel_system_resource_lock_dir)" || return 1 + lock_file="$(kpanel_system_resource_lock_file)" || return 1 + kpanel_system_resource_single_line "$lock_dir" 1024 || return 1 + kpanel_system_resource_single_line "$lock_file" 1024 || return 1 + [[ "$lock_dir" = /* ]] && [ "$lock_file" = "$lock_dir/system-resource.lock" ] || return 1 + kpanel_system_resource_path_has_no_symlink "$lock_dir" || return 1 + lock_parent="$(dirname -- "$lock_dir")" || return 1 + kpanel_system_resource_lock_path_secure "$lock_parent" directory || return 1 + if [ -e "$lock_dir" ]; then + kpanel_system_resource_lock_path_secure "$lock_dir" directory || return 1 + else + (umask 077; mkdir -- "$lock_dir") >/dev/null 2>&1 || return 1 + fi + chown 0:0 "$lock_dir" >/dev/null 2>&1 && chmod 700 "$lock_dir" >/dev/null 2>&1 || return 1 + kpanel_system_resource_lock_path_secure "$lock_dir" directory 700 || return 1 + [ ! -L "$lock_file" ] || return 1 + if [ -e "$lock_file" ]; then + kpanel_system_resource_lock_path_secure "$lock_file" file || return 1 + else + (umask 077; set -o noclobber; : > "$lock_file") >/dev/null 2>&1 || { + [ -e "$lock_file" ] && [ ! -L "$lock_file" ] || return 1 + } + fi + kpanel_system_resource_lock_path_secure "$lock_file" file || return 1 + chown 0:0 "$lock_file" >/dev/null 2>&1 && chmod 600 "$lock_file" >/dev/null 2>&1 || return 1 + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || return 1 + printf '%s\n' "$lock_file" +} + kpanel_system_resource_secure_directory() { local path="$1" [ ! -L "$path" ] || return 1 @@ -23794,23 +23864,27 @@ kpanel_system_resource_firewall_action() { kpanel_system_resource_run_locked() ( local resource="$1" local action="$2" - local lock_file lock_parent name="" + local lock_file name="" shift 2 - lock_file="$(kpanel_system_resource_lock_file)" - lock_parent="$(dirname -- "$lock_file")" - mkdir -p -- "$lock_parent" >/dev/null 2>&1 || { - kpanel_system_resource_error "无法创建 system-resource 锁目录" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + [ "$resource" = "network-interface" ] && name="${2:-}" + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { + kpanel_system_resource_error "system-resource 锁路径不安全或无法创建" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" return 1 } - exec 9>"$lock_file" || { + exec 9<>"$lock_file" || { kpanel_system_resource_error "无法打开 system-resource 锁" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 1 + } + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || { + exec 9>&- + kpanel_system_resource_error "system-resource 锁文件打开后验证失败" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" return 1 } if ! flock -w 5 -x 9 >/dev/null 2>&1; then - [ "$resource" = "network-interface" ] && name="${2:-}" kpanel_system_resource_error "system-resource 写锁等待超时" kpanel_system_resource_emit conflict "$(kpanel_system_resource_best_version "$resource" "$name")" return 2 diff --git a/kejilion.sh b/kejilion.sh index de8be37c2..d97a55541 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -22130,7 +22130,7 @@ net_menu() { # KPanel system resource protocol start -KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2" +KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="3" kpanel_system_resource_zero_version() { printf '%064d' 0 @@ -22189,8 +22189,24 @@ kpanel_system_resource_hosts_file() { printf '%s\n' "/etc/hosts" } +kpanel_system_resource_lock_dir() { + printf '%s\n' "/run/kejilion-system-resource" +} + +kpanel_system_resource_lock_owner_uid() { + printf '0\n' +} + +kpanel_system_resource_lock_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_system_resource_lock_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + kpanel_system_resource_lock_file() { - printf '%s\n' "/run/lock/kejilion-system-resource.lock" + printf '%s/system-resource.lock\n' "$(kpanel_system_resource_lock_dir)" } kpanel_system_resource_interfaces_dir() { @@ -22231,6 +22247,60 @@ kpanel_system_resource_path_has_no_symlink() { done } +kpanel_system_resource_lock_path_secure() { + local path="$1" + local kind="$2" + local required_mode="${3:-}" + local uid expected_uid mode + + [ ! -L "$path" ] || return 1 + case "$kind" in + directory) [ -d "$path" ] ;; + file) [ -f "$path" ] ;; + *) return 1 ;; + esac || return 1 + uid="$(kpanel_system_resource_lock_stat_uid "$path")" || return 1 + expected_uid="$(kpanel_system_resource_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [[ "$expected_uid" =~ ^[0-9]+$ ]] && + [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_system_resource_lock_stat_mode "$path")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + [ -z "$required_mode" ] || [ "$((8#$mode & 0777))" -eq "$((8#$required_mode))" ] +} + +kpanel_system_resource_prepare_lock_file() { + local lock_dir lock_parent lock_file + + lock_dir="$(kpanel_system_resource_lock_dir)" || return 1 + lock_file="$(kpanel_system_resource_lock_file)" || return 1 + kpanel_system_resource_single_line "$lock_dir" 1024 || return 1 + kpanel_system_resource_single_line "$lock_file" 1024 || return 1 + [[ "$lock_dir" = /* ]] && [ "$lock_file" = "$lock_dir/system-resource.lock" ] || return 1 + kpanel_system_resource_path_has_no_symlink "$lock_dir" || return 1 + lock_parent="$(dirname -- "$lock_dir")" || return 1 + kpanel_system_resource_lock_path_secure "$lock_parent" directory || return 1 + if [ -e "$lock_dir" ]; then + kpanel_system_resource_lock_path_secure "$lock_dir" directory || return 1 + else + (umask 077; mkdir -- "$lock_dir") >/dev/null 2>&1 || return 1 + fi + chown 0:0 "$lock_dir" >/dev/null 2>&1 && chmod 700 "$lock_dir" >/dev/null 2>&1 || return 1 + kpanel_system_resource_lock_path_secure "$lock_dir" directory 700 || return 1 + [ ! -L "$lock_file" ] || return 1 + if [ -e "$lock_file" ]; then + kpanel_system_resource_lock_path_secure "$lock_file" file || return 1 + else + (umask 077; set -o noclobber; : > "$lock_file") >/dev/null 2>&1 || { + [ -e "$lock_file" ] && [ ! -L "$lock_file" ] || return 1 + } + fi + kpanel_system_resource_lock_path_secure "$lock_file" file || return 1 + chown 0:0 "$lock_file" >/dev/null 2>&1 && chmod 600 "$lock_file" >/dev/null 2>&1 || return 1 + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || return 1 + printf '%s\n' "$lock_file" +} + kpanel_system_resource_secure_directory() { local path="$1" [ ! -L "$path" ] || return 1 @@ -23794,23 +23864,27 @@ kpanel_system_resource_firewall_action() { kpanel_system_resource_run_locked() ( local resource="$1" local action="$2" - local lock_file lock_parent name="" + local lock_file name="" shift 2 - lock_file="$(kpanel_system_resource_lock_file)" - lock_parent="$(dirname -- "$lock_file")" - mkdir -p -- "$lock_parent" >/dev/null 2>&1 || { - kpanel_system_resource_error "无法创建 system-resource 锁目录" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + [ "$resource" = "network-interface" ] && name="${2:-}" + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { + kpanel_system_resource_error "system-resource 锁路径不安全或无法创建" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" return 1 } - exec 9>"$lock_file" || { + exec 9<>"$lock_file" || { kpanel_system_resource_error "无法打开 system-resource 锁" - kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource")" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" + return 1 + } + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || { + exec 9>&- + kpanel_system_resource_error "system-resource 锁文件打开后验证失败" + kpanel_system_resource_emit failed "$(kpanel_system_resource_best_version "$resource" "$name")" return 1 } if ! flock -w 5 -x 9 >/dev/null 2>&1; then - [ "$resource" = "network-interface" ] && name="${2:-}" kpanel_system_resource_error "system-resource 写锁等待超时" kpanel_system_resource_emit conflict "$(kpanel_system_resource_best_version "$resource" "$name")" return 2 diff --git a/tests/test_kpanel_system_resource_noninteractive_smoke.sh b/tests/test_kpanel_system_resource_noninteractive_smoke.sh index b850153ca..7112a1436 100644 --- a/tests/test_kpanel_system_resource_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_resource_noninteractive_smoke.sh @@ -33,16 +33,21 @@ grep -F 'chown -R -- 0:0 "$destination"' "${script_path}" >/dev/null grep -F 'find "$destination" -type d -exec chmod 700' "${script_path}" >/dev/null grep -F 'find "$destination" -type f -exec chmod 600' "${script_path}" >/dev/null grep -F 'flock -w 5 -x 9' "${script_path}" >/dev/null +grep -F 'printf '\''%s\n'\'' "/run/kejilion-system-resource"' "${script_path}" >/dev/null +grep -F 'exec 9<>"$lock_file"' "${script_path}" >/dev/null +if grep -F '/run/lock/kejilion-system-resource.lock' "${script_path}" >/dev/null; then + fail "system-resource still uses the world-writable /run/lock parent" +fi adapter_body="$( sed -n '/^# KPanel system resource protocol start/,/^# KPanel system resource protocol end/p' "${script_path}" | sed 's/\r$//' )" [ -n "${adapter_body}" ] || fail "system-resource adapter block was not found" -grep -Fqx 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2"' <<< "${adapter_body}" || - fail "system-resource protocol v2 marker is missing" -[ "$(grep -Fxc 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="2"' <<< "${adapter_body}")" -eq 1 ] || - fail "system-resource protocol v2 marker must be unique" +grep -Fqx 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="3"' <<< "${adapter_body}" || + fail "system-resource protocol v3 marker is missing" +[ "$(grep -Fxc 'KPANEL_SYSTEM_RESOURCE_PROTOCOL_VERSION="3"' <<< "${adapter_body}")" -eq 1 ] || + fail "system-resource protocol v3 marker must be unique" printf '%s\n' "${adapter_body}" | grep -F '[ "$command_source" = "--command-stdin" ]' >/dev/null || fail "cron command stdin marker is missing" if printf '%s\n' "${adapter_body}" | grep -E 'grep .*\$new_line' >/dev/null; then @@ -52,15 +57,28 @@ eval "${adapter_body}" test_hosts="${test_root}/hosts" test_crontab="${test_root}/crontab" -test_lock="${test_root}/system-resource.lock" +test_lock_parent="${test_root}/run" +test_lock_dir="${test_lock_parent}/kejilion-system-resource" +test_lock="${test_lock_dir}/system-resource.lock" test_interfaces="${test_root}/interfaces" test_rules="${test_root}/rules.v4" test_iptables="${test_root}/iptables.state" test_stderr="${test_root}/stderr" -mkdir -p -- "${test_interfaces}" +mkdir -p -- "${test_interfaces}" "${test_lock_parent}" +chmod 700 "${test_lock_parent}" kpanel_system_resource_hosts_file() { printf '%s\n' "${test_hosts}"; } -kpanel_system_resource_lock_file() { printf '%s\n' "${test_lock}"; } +kpanel_system_resource_lock_dir() { printf '%s\n' "${test_lock_dir}"; } +kpanel_system_resource_lock_owner_uid() { id -u; } +kpanel_system_resource_lock_stat_mode() { + case "$(uname -s)" in + MINGW*|MSYS*|CYGWIN*) + [ "$1" != "${test_lock_dir}" ] || { printf '700\n'; return 0; } + [ "$1" != "${test_lock}" ] || { printf '600\n'; return 0; } + ;; + esac + command stat -c '%a' "$1" 2>/dev/null +} kpanel_system_resource_interfaces_dir() { printf '%s\n' "${test_interfaces}"; } kpanel_system_resource_iptables_rules_file() { printf '%s\n' "${test_rules}"; } kpanel_system_resource_state_root() { @@ -259,6 +277,16 @@ chown() { command chown "$@" } +reset_test_lock_dir() { + if [ -L "${test_lock_dir}" ]; then + command rm -f -- "${test_lock_dir}" + else + command rm -rf -- "${test_lock_dir}" + fi + mkdir -- "${test_lock_dir}" + chmod 700 "${test_lock_dir}" +} + assert_receipt() { local expected_status="$1" local line_count @@ -334,6 +362,62 @@ KPANEL_FAKE_FLOCK_TIMEOUT=1 run_dispatch conflict hosts add "${zero_version}" 127.0.0.1 locked.local "" unset KPANEL_FAKE_FLOCK_TIMEOUT [ "${RUN_RC}" -eq 2 ] || fail "system-resource lock timeout did not return conflict" +printf 'safe-lock-content\n' > "${test_lock}" +chmod 600 "${test_lock}" +KPANEL_FAKE_FLOCK_TIMEOUT=1 +run_dispatch conflict hosts add "${zero_version}" 127.0.0.1 locked-again.local "" +unset KPANEL_FAKE_FLOCK_TIMEOUT +[ "${RUN_RC}" -eq 2 ] || fail "existing secure lock file could not be reused" +grep -Fqx 'safe-lock-content' "${test_lock}" || fail "opening the secure lock file truncated its content" + +if [ "$(uname -s)" = Linux ] && [ "$(id -u)" -eq 0 ]; then + [ "$(stat -c '%a' "${test_lock_dir}")" = 700 ] || fail "secure lock directory mode is not 0700" + [ "$(stat -c '%u' "${test_lock_dir}")" = 0 ] || fail "secure lock directory is not root-owned" + [ "$(stat -c '%a' "${test_lock}")" = 600 ] || fail "secure lock file mode is not 0600" + [ "$(stat -c '%u' "${test_lock}")" = 0 ] || fail "secure lock file is not root-owned" + + lock_sentinel_dir="${test_root}/lock-sentinel-directory" + lock_sentinel="${test_root}/lock-sentinel" + mkdir -- "${lock_sentinel_dir}" + printf 'directory-symlink-sentinel\n' > "${lock_sentinel_dir}/system-resource.lock" + command rm -rf -- "${test_lock_dir}" + ln -s -- "${lock_sentinel_dir}" "${test_lock_dir}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 unsafe-lock-dir.local "" + [ "${RUN_RC}" -eq 1 ] || fail "lock directory symlink was not rejected" + grep -Fqx 'directory-symlink-sentinel' "${lock_sentinel_dir}/system-resource.lock" || + fail "lock directory symlink target was modified" + + reset_test_lock_dir + printf 'file-symlink-sentinel\n' > "${lock_sentinel}" + ln -s -- "${lock_sentinel}" "${test_lock}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 unsafe-lock-file.local "" + [ "${RUN_RC}" -eq 1 ] || fail "lock file symlink was not rejected" + grep -Fqx 'file-symlink-sentinel' "${lock_sentinel}" || fail "lock file symlink target was modified" + + reset_test_lock_dir + command chown 1:1 "${test_lock_dir}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 wrong-lock-dir-owner.local "" + [ "${RUN_RC}" -eq 1 ] || fail "non-root lock directory owner was not rejected" + + reset_test_lock_dir + : > "${test_lock}" + chmod 600 "${test_lock}" + command chown 1:1 "${test_lock}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 wrong-lock-file-owner.local "" + [ "${RUN_RC}" -eq 1 ] || fail "non-root lock file owner was not rejected" + + reset_test_lock_dir + chmod 770 "${test_lock_dir}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 writable-lock-dir.local "" + [ "${RUN_RC}" -eq 1 ] || fail "group-writable lock directory was not rejected" + + reset_test_lock_dir + : > "${test_lock}" + chmod 660 "${test_lock}" + run_dispatch failed hosts add "${zero_version}" 127.0.0.1 writable-lock-file.local "" + [ "${RUN_RC}" -eq 1 ] || fail "group-writable lock file was not rejected" + reset_test_lock_dir +fi printf '%s\n' \ '127.0.0.1 localhost' \ From a978abedcf2cfd692757327800c037841caea92c Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 11 Aug 2026 01:18:26 +0800 Subject: [PATCH 1260/1285] feat(kpanel): add network and account management protocols --- cn/kejilion.sh | 1201 ++++++++++++++++- kejilion.sh | 1201 ++++++++++++++++- ...account_management_noninteractive_smoke.sh | 133 ++ ...network_operations_noninteractive_smoke.sh | 152 +++ 4 files changed, 2653 insertions(+), 34 deletions(-) create mode 100644 tests/test_kpanel_account_management_noninteractive_smoke.sh create mode 100644 tests/test_kpanel_network_operations_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 4d15f8047..85171c3e1 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -25,6 +25,8 @@ kpanel_protocol_active() { [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || @@ -22341,7 +22343,7 @@ kpanel_system_resource_persist_recovery_snapshot() { local resource="$2" local recovery_root destination timestamp invalid - [[ "$resource" =~ ^(hosts|cron|firewall)$ ]] || return 1 + [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management)$ ]] || return 1 [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 [ -z "$invalid" ] || return 1 @@ -23930,6 +23932,1165 @@ kpanel_system_resource_dispatch() { # KPanel system resource protocol end +# KPanel network operations protocol start +KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1" + +kpanel_network_operations_script_file() { + printf '%s\n' "/root/Limiting_Shut_down.sh" +} + +kpanel_network_operations_net_dev_file() { + printf '%s\n' "/proc/net/dev" +} + +kpanel_network_operations_emit() { + local status="$1" + local version="${2:-}" + local backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_NETWORK_OPERATIONS_STATUS=%s\n' "$status" + printf 'KPANEL_NETWORK_OPERATIONS_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_NETWORK_OPERATIONS_BACKUP=%s\n' "$backup" +} + +kpanel_network_operations_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_network_operations_require() { + local needs_root="$1" + shift + [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || { + kpanel_network_operations_error "KPanel network-operations 协议环境未启用" + kpanel_network_operations_emit failed + return 2 + } + [ "$(uname -s 2>/dev/null)" = "Linux" ] || { + kpanel_network_operations_error "KPanel network-operations 协议仅支持 Linux" + kpanel_network_operations_emit failed + return 2 + } + if [ "$needs_root" = true ] && [ "$(id -u)" -ne 0 ]; then + kpanel_network_operations_error "限流关机管理必须以 root 运行" + kpanel_network_operations_emit failed + return 2 + fi + for command_name in "$@"; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_network_operations_error "缺少必要命令: $command_name" + kpanel_network_operations_emit failed + return 2 + } + done +} + +kpanel_network_operations_port_usage() { + local temporary total truncated=false version line hex count=0 + kpanel_network_operations_require false ss awk wc sha256sum od tr mktemp || return $? + [ "$#" -eq 0 ] || { + kpanel_network_operations_error "port-usage list 不接受额外参数" + kpanel_network_operations_emit failed + return 2 + } + temporary="$(mktemp /tmp/kejilion-network-ports.XXXXXX)" || { + kpanel_network_operations_error "无法创建端口占用快照" + kpanel_network_operations_emit failed + return 1 + } + if ! LC_ALL=C ss -H -lntup > "$temporary" 2>/dev/null; then + rm -f -- "$temporary" + kpanel_network_operations_error "无法读取监听端口" + kpanel_network_operations_emit failed + return 1 + fi + if ! kpanel_system_resource_file_within_bounds "$temporary" 4194304 4096 || + ! awk 'length($0) > 4096 { exit 1 }' "$temporary"; then + rm -f -- "$temporary" + kpanel_network_operations_error "端口占用结果超过协议上限" + kpanel_network_operations_emit failed + return 1 + fi + total="$(awk 'END { print NR + 0 }' "$temporary")" || total=0 + [ "$total" -le 512 ] || truncated=true + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + kpanel_network_operations_emit ok "$version" + printf 'KPANEL_NETWORK_OPERATIONS_TOTAL=%s\n' "$total" + printf 'KPANEL_NETWORK_OPERATIONS_TRUNCATED=%s\n' "$truncated" + while IFS= read -r line && [ "$count" -lt 512 ]; do + hex="$(printf '%s' "$line" | od -An -v -tx1 | tr -d ' \n')" || { + rm -f -- "$temporary" + return 1 + } + printf 'KPANEL_NETWORK_OPERATIONS_PORT_HEX=%s\n' "$hex" + count=$((count + 1)) + done < "$temporary" + rm -f -- "$temporary" +} + +kpanel_network_operations_traffic_bytes() { + local path + path="$(kpanel_network_operations_net_dev_file)" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + awk ' + BEGIN { rx = 0; tx = 0 } + $1 ~ /^(eth|ens|enp|eno)[0-9]+:/ { rx += $2; tx += $10 } + END { printf "%.0f %.0f\n", rx, tx } + ' "$path" +} + +kpanel_network_operations_script_safe() { + local path="$1" uid expected_uid mode + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + kpanel_system_resource_file_within_bounds "$path" 65536 256 || return 1 + uid="$(stat -c '%u' "$path" 2>/dev/null)" || return 1 + expected_uid="$(kpanel_system_resource_lock_owner_uid)" || return 1 + [ "$uid" = "$expected_uid" ] || return 1 + mode="$(stat -c '%a' "$path" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0022))" -eq 0 ] +} + +kpanel_network_operations_cron_relevant() { + local source="$1" + awk ' + $0 == "# kejilion traffic shutdown start" { managed = 1; print; next } + managed { print; if ($0 == "# kejilion traffic shutdown end") managed = 0; next } + $0 == "* * * * * ~/Limiting_Shut_down.sh" || + $0 == "* * * * * /root/Limiting_Shut_down.sh" { print } + ' "$source" +} + +kpanel_network_operations_traffic_version() { + local script_path cron_path canonical version + script_path="$(kpanel_network_operations_script_file)" + [ ! -L "$script_path" ] || return 1 + cron_path="$(mktemp /tmp/kejilion-network-traffic-cron.XXXXXX)" || return 1 + canonical="$(mktemp /tmp/kejilion-network-traffic-version.XXXXXX)" || { + rm -f -- "$cron_path" + return 1 + } + if ! kpanel_system_resource_cron_capture "$cron_path"; then + rm -f -- "$cron_path" "$canonical" + return 1 + fi + if [ -e "$script_path" ]; then + kpanel_network_operations_script_safe "$script_path" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + printf 'script=present\n' > "$canonical" + sha256sum -- "$script_path" >> "$canonical" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + else + printf 'script=absent\n' > "$canonical" + fi + printf 'cron:\n' >> "$canonical" + kpanel_network_operations_cron_relevant "$cron_path" >> "$canonical" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$cron_path" "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_network_operations_parse_script() { + local path="$1" rx tx + grep -Fqx '# KEJILION_TRAFFIC_SHUTDOWN_MANAGED_V1' "$path" || return 1 + rx="$(sed -n 's/^rx_threshold_gb=\([0-9][0-9]*\)$/\1/p' "$path")" + tx="$(sed -n 's/^tx_threshold_gb=\([0-9][0-9]*\)$/\1/p' "$path")" + [[ "$rx" =~ ^[0-9]+$ ]] && [[ "$tx" =~ ^[0-9]+$ ]] || return 1 + [ "$(printf '%s\n' "$rx" | wc -l)" -eq 1 ] && [ "$(printf '%s\n' "$tx" | wc -l)" -eq 1 ] || return 1 + KPANEL_NETWORK_TRAFFIC_RX="$rx" + KPANEL_NETWORK_TRAFFIC_TX="$tx" +} + +kpanel_network_operations_traffic_status() { + local script_path cron_path version bytes rx_bytes tx_bytes enabled=false health=disabled + local rx_threshold=0 tx_threshold=0 reset_day=0 invocation_count reset_line_count start_count end_count expected_script + kpanel_network_operations_require false awk crontab grep sed sha256sum stat wc mktemp cmp || return $? + [ "$#" -eq 0 ] || { + kpanel_network_operations_error "traffic-shutdown status 不接受额外参数" + kpanel_network_operations_emit failed + return 2 + } + script_path="$(kpanel_network_operations_script_file)" + cron_path="$(mktemp /tmp/kejilion-network-traffic-status.XXXXXX)" || { + kpanel_network_operations_emit failed + return 1 + } + if ! kpanel_system_resource_cron_capture "$cron_path"; then + rm -f -- "$cron_path" + kpanel_network_operations_error "无法读取 root crontab" + kpanel_network_operations_emit failed + return 1 + fi + version="$(kpanel_network_operations_traffic_version)" || { + rm -f -- "$cron_path" + kpanel_network_operations_error "限流关机配置不安全或无法计算版本" + kpanel_network_operations_emit failed + return 1 + } + bytes="$(kpanel_network_operations_traffic_bytes)" || { + rm -f -- "$cron_path" + kpanel_network_operations_error "无法读取累计网络流量" + kpanel_network_operations_emit failed "$version" + return 1 + } + read -r rx_bytes tx_bytes <<< "$bytes" + if [ -e "$script_path" ]; then + enabled=true + if kpanel_network_operations_script_safe "$script_path" && + kpanel_network_operations_parse_script "$script_path"; then + rx_threshold="$KPANEL_NETWORK_TRAFFIC_RX" + tx_threshold="$KPANEL_NETWORK_TRAFFIC_TX" + expected_script="$(mktemp /tmp/kejilion-network-traffic-expected.XXXXXX)" || { + rm -f -- "$cron_path" + kpanel_network_operations_emit failed "$version" + return 1 + } + if ! kpanel_network_operations_build_script "$expected_script" "$rx_threshold" "$tx_threshold" || + ! cmp -s -- "$expected_script" "$script_path"; then + rx_threshold=0 + tx_threshold=0 + fi + rm -f -- "$expected_script" + fi + fi + start_count="$(grep -Fxc '# kejilion traffic shutdown start' "$cron_path")" + end_count="$(grep -Fxc '# kejilion traffic shutdown end' "$cron_path")" + invocation_count="$(grep -Fxc "* * * * * $script_path" "$cron_path")" + reset_line_count="$(sed -n '/^# kejilion traffic shutdown start$/,/^# kejilion traffic shutdown end$/p' "$cron_path" | grep -Ec '^0 1 ([1-9]|[12][0-9]|3[01]) \* \* reboot$')" + if [ "$enabled" = true ] && [ "$rx_threshold" -gt 0 ] && [ "$tx_threshold" -gt 0 ] && + [ "$start_count" -eq 1 ] && [ "$end_count" -eq 1 ] && [ "$invocation_count" -eq 1 ] && [ "$reset_line_count" -eq 1 ]; then + reset_day="$(sed -n '/^# kejilion traffic shutdown start$/,/^# kejilion traffic shutdown end$/s/^0 1 \([0-9][0-9]*\) \* \* reboot$/\1/p' "$cron_path")" + if [[ "$reset_day" =~ ^([1-9]|[12][0-9]|3[01])$ ]]; then + health=ready + else + health=inconsistent + fi + elif [ "$enabled" = false ] && [ "$start_count" -eq 0 ] && [ "$end_count" -eq 0 ] && [ "$invocation_count" -eq 0 ]; then + health=disabled + else + health=inconsistent + fi + rm -f -- "$cron_path" + kpanel_network_operations_emit ok "$version" + printf 'KPANEL_NETWORK_OPERATIONS_ENABLED=%s\n' "$enabled" + printf 'KPANEL_NETWORK_OPERATIONS_HEALTH=%s\n' "$health" + printf 'KPANEL_NETWORK_OPERATIONS_RX_BYTES=%s\n' "$rx_bytes" + printf 'KPANEL_NETWORK_OPERATIONS_TX_BYTES=%s\n' "$tx_bytes" + printf 'KPANEL_NETWORK_OPERATIONS_RX_THRESHOLD_GIB=%s\n' "$rx_threshold" + printf 'KPANEL_NETWORK_OPERATIONS_TX_THRESHOLD_GIB=%s\n' "$tx_threshold" + printf 'KPANEL_NETWORK_OPERATIONS_RESET_DAY=%s\n' "$reset_day" +} + +kpanel_network_operations_valid_threshold() { + [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" != 0 ] && [ "$((10#$1))" -le 8388607 ] +} + +kpanel_network_operations_build_script() { + local target="$1" rx="$2" tx="$3" + cat > "$target" < "$target" || return 1 + if [ "$action" = enable ]; then + { + printf '%s\n' '# kejilion traffic shutdown start' + printf '* * * * * %s\n' "$script_path" + printf '0 1 %s * * reboot\n' "$reset_day" + printf '%s\n' '# kejilion traffic shutdown end' + } >> "$target" || return 1 + fi + kpanel_system_resource_file_within_bounds "$target" 262144 512 +} + +kpanel_network_operations_restore_traffic() { + local snapshot="$1" script_path="$2" script_existed="$3" cron_existed="$4" verify version="$5" + if [ "$script_existed" = true ]; then + cp -p -- "$snapshot/script" "$script_path" >/dev/null 2>&1 || return 1 + else + rm -f -- "$script_path" >/dev/null 2>&1 || return 1 + fi + verify="$snapshot/cron.verify" + kpanel_system_resource_cron_restore "$snapshot/crontab" "$cron_existed" "$verify" || return 1 + [ "$(kpanel_network_operations_traffic_version 2>/dev/null)" = "$version" ] +} + +kpanel_network_operations_traffic_failure() { + local snapshot="$1" script_path="$2" script_existed="$3" cron_existed="$4" original_version="$5" message="$6" + local version recovery_path + kpanel_network_operations_error "$message" + if kpanel_network_operations_restore_traffic "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$original_version"; then + version="$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$version" + return 1 + else + version="$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" traffic-shutdown)"; then + kpanel_network_operations_emit rollback-failed "$version" "$recovery_path" + else + kpanel_network_operations_emit rollback-failed "$version" + fi + return 1 + fi +} + +kpanel_network_operations_traffic_action() { + local action="$1" expected="${2:-}" rx="${3:-}" tx="${4:-}" reset_day="${5:-}" + local script_path current_version snapshot cron_existed script_existed=false + local desired_script desired_cron install_temp final_version + case "$action" in + enable) + [ "$#" -eq 5 ] && kpanel_system_resource_valid_version "$expected" && + kpanel_network_operations_valid_threshold "$rx" && + kpanel_network_operations_valid_threshold "$tx" && + [[ "$reset_day" =~ ^([1-9]|[12][0-9]|3[01])$ ]] || { + kpanel_network_operations_error "enable 需要 expectedVersion、正整数 GiB 阈值和 1-31 重置日" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + } + ;; + disable) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$expected" || { + kpanel_network_operations_error "disable 只需要 expectedVersion" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + } + ;; + *) + kpanel_network_operations_error "不支持的 traffic-shutdown 动作" + kpanel_network_operations_emit failed + return 2 + ;; + esac + script_path="$(kpanel_network_operations_script_file)" + [ ! -L "$script_path" ] || { + kpanel_network_operations_error "限流关机脚本不能是符号链接" + kpanel_network_operations_emit failed + return 1 + } + current_version="$(kpanel_network_operations_traffic_version)" || { + kpanel_network_operations_error "无法读取当前限流关机配置" + kpanel_network_operations_emit failed + return 1 + } + if [ "$current_version" != "$expected" ]; then + kpanel_network_operations_error "资源版本已变化,请刷新后重试" + kpanel_network_operations_emit conflict "$current_version" + return 2 + fi + snapshot="$(kpanel_system_resource_tempdir traffic-shutdown)" || { + kpanel_network_operations_emit failed "$current_version" + return 1 + } + if [ -e "$script_path" ]; then + kpanel_network_operations_script_safe "$script_path" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + cp -p -- "$script_path" "$snapshot/script" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + script_existed=true + fi + kpanel_system_resource_cron_capture "$snapshot/crontab" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" + printf '%s\n' "$script_existed" > "$snapshot/script.existed" + printf '%s\n' "$cron_existed" > "$snapshot/cron.existed" + desired_script="$snapshot/script.desired" + desired_cron="$snapshot/cron.desired" + if [ "$action" = enable ]; then + kpanel_network_operations_build_script "$desired_script" "$rx" "$tx" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法生成限流关机脚本" + return $? + } + fi + kpanel_network_operations_build_cron "$snapshot/crontab" "$desired_cron" "$action" "$script_path" "$reset_day" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法生成限流关机 crontab" + return $? + } + if { [ "$action" = enable ] && [ "$script_existed" = true ] && + cmp -s -- "$desired_script" "$script_path" && cmp -s -- "$desired_cron" "$snapshot/crontab"; } || + { [ "$action" = disable ] && [ "$script_existed" = false ] && cmp -s -- "$desired_cron" "$snapshot/crontab"; }; then + rm -rf -- "$snapshot" + kpanel_network_operations_emit unchanged "$current_version" + return 0 + fi + if [ "$action" = enable ]; then + install_temp="$(mktemp "$(dirname -- "$script_path")/.Limiting_Shut_down.sh.XXXXXX")" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法创建限流关机临时文件" + return $? + } + if ! cp -- "$desired_script" "$install_temp" || ! chown 0:0 "$install_temp" 2>/dev/null || + ! chmod 700 "$install_temp" || ! mv -f -- "$install_temp" "$script_path"; then + rm -f -- "$install_temp" + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法原子安装限流关机脚本" + return $? + fi + else + rm -f -- "$script_path" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法删除限流关机脚本" + return $? + } + fi + if ! crontab "$desired_cron"; then + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法安装限流关机 crontab" + return $? + fi + final_version="$(kpanel_network_operations_traffic_version)" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "限流关机配置回读失败" + return $? + } + if [ "$final_version" = "$current_version" ]; then + rm -rf -- "$snapshot" + kpanel_network_operations_emit unchanged "$final_version" + else + rm -rf -- "$snapshot" + kpanel_network_operations_emit applied "$final_version" + fi +} + +kpanel_network_operations_traffic_run_locked() ( + local action="$1" lock_file + shift + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { + kpanel_network_operations_error "network-operations 锁路径不安全或无法创建" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 1 + } + exec 9<>"$lock_file" || return 1 + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || return 1 + if ! flock -w 5 -x 9 >/dev/null 2>&1; then + kpanel_network_operations_error "network-operations 写锁等待超时" + kpanel_network_operations_emit conflict "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + fi + kpanel_network_operations_traffic_action "$action" "$@" +) + +kpanel_network_operations_dispatch() { + local resource="${1:-}" action="${2:-}" + [ "$#" -ge 2 ] || { + kpanel_network_operations_error "用法: kpanel network-operations ..." + kpanel_network_operations_emit failed + return 2 + } + shift 2 + case "$resource:$action" in + port-usage:list) kpanel_network_operations_port_usage "$@" ;; + traffic-shutdown:status) + kpanel_network_operations_traffic_status "$@" + ;; + traffic-shutdown:enable|traffic-shutdown:disable) + kpanel_network_operations_require true awk crontab grep sed sha256sum stat wc mktemp flock cmp cp mv chmod chown || return $? + kpanel_network_operations_traffic_run_locked "$action" "$@" + ;; + *) + kpanel_network_operations_error "不支持的 network-operations 资源或动作" + kpanel_network_operations_emit failed + return 2 + ;; + esac +} + +# KPanel network operations protocol end + + +# KPanel account management protocol start +KPANEL_ACCOUNT_MANAGEMENT_PROTOCOL_VERSION="1" + +kpanel_account_error() { + printf '%s\n' "$*" >&2 +} + +kpanel_account_emit() { + local status="$1" version="${2:-}" backup="${3:-}" + printf 'KPANEL_ACCOUNT_MANAGEMENT_STATUS=%s\n' "$status" + [ -z "$version" ] || printf 'KPANEL_ACCOUNT_MANAGEMENT_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_ACCOUNT_MANAGEMENT_BACKUP=%s\n' "$backup" +} + +kpanel_account_root_path() { + local path="$1" + printf '%s%s\n' "${KPANEL_ACCOUNT_TEST_ROOT:-}" "$path" +} + +kpanel_account_passwd_file() { kpanel_account_root_path /etc/passwd; } +kpanel_account_group_file() { kpanel_account_root_path /etc/group; } +kpanel_account_shadow_file() { kpanel_account_root_path /etc/shadow; } +kpanel_account_gshadow_file() { kpanel_account_root_path /etc/gshadow; } +kpanel_account_login_defs_file() { kpanel_account_root_path /etc/login.defs; } +kpanel_account_sudoers_file() { kpanel_account_root_path /etc/sudoers; } +kpanel_account_sudoers_dir() { kpanel_account_root_path /etc/sudoers.d; } +kpanel_account_sshd_config() { kpanel_account_root_path /etc/ssh/sshd_config; } +kpanel_account_sshd_fragment() { kpanel_account_root_path /etc/ssh/sshd_config.d/00-kejilion-account-management.conf; } + +kpanel_account_host_path() { + local path="$1" + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + printf '%s%s\n' "$KPANEL_ACCOUNT_TEST_ROOT" "$path" + else + printf '%s\n' "$path" + fi +} + +kpanel_account_valid_username() { + [[ "$1" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] && [[ "$1" != *'$' ]] +} + +kpanel_account_require() { + local write="$1" command + shift + [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || { + kpanel_account_error "KPanel account-management 协议环境未启用" + return 2 + } + [ "$EUID" -eq 0 ] || { + kpanel_account_error "KPanel account-management 协议必须以 root 运行" + return 1 + } + [ "$(uname -s 2>/dev/null)" = Linux ] || { + kpanel_account_error "KPanel account-management 协议仅支持 Linux" + return 2 + } + for command in "$@"; do + command -v "$command" >/dev/null 2>&1 || { + kpanel_account_error "缺少 account-management 依赖: $command" + return 2 + } + done + if [ "$write" = true ]; then + for command in flock cp mv chmod chown mktemp; do + command -v "$command" >/dev/null 2>&1 || { + kpanel_account_error "缺少 account-management 写入依赖: $command" + return 2 + } + done + fi +} + +kpanel_account_file_safe() { + local path="$1" max_bytes="$2" max_lines="$3" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + kpanel_system_resource_file_within_bounds "$path" "$max_bytes" "$max_lines" +} + +kpanel_account_find_record() { + local username="$1" passwd_file + passwd_file="$(kpanel_account_passwd_file)" + awk -F: -v username="$username" '$1 == username { print; found=1; exit } END { exit(found ? 0 : 1) }' "$passwd_file" +} + +kpanel_account_exists() { + kpanel_account_find_record "$1" >/dev/null 2>&1 +} + +kpanel_account_home() { + local record + record="$(kpanel_account_find_record "$1")" || return 1 + printf '%s\n' "$record" | awk -F: '{print $6}' +} + +kpanel_account_authorized_keys() { + local username="$1" home + home="$(kpanel_account_home "$username")" || return 1 + [[ "$home" = /* ]] && [ "$home" != / ] || return 1 + printf '%s/.ssh/authorized_keys\n' "$(kpanel_account_host_path "$home")" +} + +kpanel_account_capture_keys() { + local username="$1" target="$2" path + path="$(kpanel_account_authorized_keys "$username")" || return 1 + : > "$target" || return 1 + [ ! -e "$path" ] && return 0 + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + cat -- "$path" > "$target" || return 1 + else + runuser -u "$username" -- cat -- "$path" > "$target" 2>/dev/null || return 1 + fi + kpanel_system_resource_file_within_bounds "$target" 131072 128 +} + +kpanel_account_key_valid() { + local key="$1" temporary LC_ALL=C + [ -n "$key" ] && [ "${#key}" -le 4096 ] && [[ "$key" != *$'\n'* ]] && [[ "$key" != *$'\r'* ]] || return 1 + case "$key" in + ssh-rsa\ *|ssh-ed25519\ *|ecdsa-sha2-*\ *|sk-ssh-ed25519@openssh.com\ *|sk-ecdsa-sha2-nistp256@openssh.com\ *) ;; + *) return 1 ;; + esac + temporary="$(mktemp /tmp/kejilion-account-key.XXXXXX)" || return 1 + chmod 600 "$temporary" || { rm -f -- "$temporary"; return 1; } + printf '%s\n' "$key" > "$temporary" || { rm -f -- "$temporary"; return 1; } + ssh-keygen -lf "$temporary" >/dev/null 2>&1 + local result=$? + rm -f -- "$temporary" + return "$result" +} + +kpanel_account_key_id() { + printf '%s' "$1" | sha256sum | awk '{print $1}' +} + +kpanel_account_install_keys() { + local username="$1" desired="$2" path ssh_dir temp uid gid + path="$(kpanel_account_authorized_keys "$username")" || return 1 + ssh_dir="$(dirname -- "$path")" || return 1 + [ ! -L "$ssh_dir" ] && [ ! -L "$path" ] || return 1 + uid="$(kpanel_account_find_record "$username" | awk -F: '{print $3}')" || return 1 + gid="$(kpanel_account_find_record "$username" | awk -F: '{print $4}')" || return 1 + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + mkdir -p -- "$ssh_dir" || return 1 + chmod 700 "$ssh_dir" || return 1 + temp="$(mktemp "$ssh_dir/.authorized_keys.XXXXXX")" || return 1 + cp -- "$desired" "$temp" && chmod 600 "$temp" && mv -f -- "$temp" "$path" || { rm -f -- "$temp"; return 1; } + return 0 + fi + runuser -u "$username" -- mkdir -p -- "$ssh_dir" >/dev/null 2>&1 || return 1 + runuser -u "$username" -- chmod 700 "$ssh_dir" >/dev/null 2>&1 || return 1 + temp="$ssh_dir/.authorized_keys.kpanel.$$.$RANDOM" + runuser -u "$username" -- tee "$temp" < "$desired" >/dev/null 2>&1 || return 1 + if ! runuser -u "$username" -- chmod 600 "$temp" >/dev/null 2>&1 || + ! runuser -u "$username" -- mv -f -- "$temp" "$path" >/dev/null 2>&1; then + runuser -u "$username" -- rm -f -- "$temp" >/dev/null 2>&1 || true + return 1 + fi + chown "$uid:$gid" "$ssh_dir" "$path" >/dev/null 2>&1 || return 1 +} + +kpanel_account_password_status() { + local username="$1" status + status="$(passwd -S "$username" 2>/dev/null | awk '{print $2}')" || return 1 + case "$status" in + P) printf '%s\n' enabled ;; + L|LK) printf '%s\n' locked ;; + NP) printf '%s\n' unset ;; + *) printf '%s\n' unknown ;; + esac +} + +kpanel_account_admin_group() { + if getent group sudo >/dev/null 2>&1; then + printf '%s\n' sudo + elif getent group wheel >/dev/null 2>&1; then + printf '%s\n' wheel + else + return 1 + fi +} + +kpanel_account_sudo_file() { + printf '%s/90-kejilion-%s\n' "$(kpanel_account_sudoers_dir)" "$1" +} + +kpanel_account_role() { + local username="$1" groups sudo_file + [ "$username" = root ] && { printf '%s\n' root; return 0; } + sudo_file="$(kpanel_account_sudo_file "$username")" + if [ -f "$sudo_file" ] && [ ! -L "$sudo_file" ] && + grep -Fqx "$username ALL=(ALL:ALL) NOPASSWD:ALL" "$sudo_file"; then + printf '%s\n' passwordless-admin + return 0 + fi + groups="$(id -nG "$username" 2>/dev/null)" || return 1 + case " $groups " in + *' sudo '*|*' wheel '*) printf '%s\n' administrator ;; + *) printf '%s\n' standard ;; + esac +} + +kpanel_account_sshd_effective() { + local config password pubkey root + config="$(kpanel_account_sshd_config)" + [ -f "$config" ] && [ ! -L "$config" ] || return 1 + while read -r key value _; do + case "$key" in + passwordauthentication) password="$value" ;; + pubkeyauthentication) pubkey="$value" ;; + permitrootlogin) root="$value" ;; + esac + done < <(sshd -T -f "$config" 2>/dev/null) + [ "$password" = yes ] || password=no + [ "$pubkey" = yes ] || pubkey=no + case "$root" in + yes) root=enabled ;; + prohibit-password|without-password) root=key-only ;; + no) root=disabled ;; + *) root=custom ;; + esac + printf '%s %s %s\n' "$password" "$pubkey" "$root" +} + +kpanel_account_version() { + local canonical file username auth sudo_file effective version + canonical="$(mktemp /tmp/kejilion-account-version.XXXXXX)" || return 1 + chmod 600 "$canonical" || { rm -f -- "$canonical"; return 1; } + for file in "$(kpanel_account_passwd_file)" "$(kpanel_account_group_file)" \ + "$(kpanel_account_shadow_file)" "$(kpanel_account_gshadow_file)" \ + "$(kpanel_account_sudoers_file)" "$(kpanel_account_sshd_config)" "$(kpanel_account_sshd_fragment)"; do + if [ -e "$file" ]; then + kpanel_account_file_safe "$file" 1048576 8192 || { rm -f -- "$canonical"; return 1; } + printf 'file=%s ' "$file" >> "$canonical" + sha256sum -- "$file" >> "$canonical" || { rm -f -- "$canonical"; return 1; } + else + printf 'file=%s absent\n' "$file" >> "$canonical" + fi + done + effective="$(kpanel_account_sshd_effective)" || { rm -f -- "$canonical"; return 1; } + printf 'sshd=%s\n' "$effective" >> "$canonical" + while IFS=: read -r username _; do + kpanel_account_valid_username "$username" || continue + auth="$(mktemp /tmp/kejilion-account-auth.XXXXXX)" || { rm -f -- "$canonical"; return 1; } + if kpanel_account_capture_keys "$username" "$auth"; then + printf 'keys=%s ' "$username" >> "$canonical" + sha256sum -- "$auth" >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } + else + printf 'keys=%s unreadable\n' "$username" >> "$canonical" + fi + rm -f -- "$auth" + sudo_file="$(kpanel_account_sudo_file "$username")" + if [ -e "$sudo_file" ]; then + kpanel_account_file_safe "$sudo_file" 4096 16 || { rm -f -- "$canonical"; return 1; } + printf 'sudo=%s ' "$username" >> "$canonical" + sha256sum -- "$sudo_file" >> "$canonical" || { rm -f -- "$canonical"; return 1; } + fi + done < "$(kpanel_account_passwd_file)" + version="$(sha256sum -- "$canonical" | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_account_hex() { + printf '%s' "$1" | od -An -v -tx1 | tr -d ' \n' +} + +kpanel_account_status() { + local version effective password_auth pubkey_auth root_login passwd_file login_defs uid_min=1000 + local username _ uid gid gecos home shell groups password role kind account_record auth key key_id key_type fingerprint comment + local total=0 emitted=0 truncated=false key_count key_temp + kpanel_account_require false awk cat getent grep id mktemp od passwd runuser sha256sum ssh-keygen sshd stat tr wc || return $? + [ "$#" -eq 0 ] || { kpanel_account_error "status 不接受额外参数"; kpanel_account_emit failed; return 2; } + passwd_file="$(kpanel_account_passwd_file)" + kpanel_account_file_safe "$passwd_file" 1048576 8192 || { kpanel_account_emit failed; return 1; } + login_defs="$(kpanel_account_login_defs_file)" + if [ -f "$login_defs" ] && [ ! -L "$login_defs" ]; then + uid_min="$(awk '$1 == "UID_MIN" && $2 ~ /^[0-9]+$/ {print $2; exit}' "$login_defs")" + [[ "$uid_min" =~ ^[0-9]+$ ]] || uid_min=1000 + fi + version="$(kpanel_account_version)" || { kpanel_account_error "无法计算账户资源版本"; kpanel_account_emit failed; return 1; } + effective="$(kpanel_account_sshd_effective)" || { kpanel_account_emit failed "$version"; return 1; } + read -r password_auth pubkey_auth root_login <<< "$effective" + total="$(wc -l < "$passwd_file")" + [ "$total" -le 256 ] || truncated=true + kpanel_account_emit ok "$version" + printf 'KPANEL_ACCOUNT_MANAGEMENT_PASSWORD_AUTH=%s\n' "$password_auth" + printf 'KPANEL_ACCOUNT_MANAGEMENT_PUBKEY_AUTH=%s\n' "$pubkey_auth" + printf 'KPANEL_ACCOUNT_MANAGEMENT_ROOT_LOGIN=%s\n' "$root_login" + printf 'KPANEL_ACCOUNT_MANAGEMENT_TOTAL=%s\n' "$total" + printf 'KPANEL_ACCOUNT_MANAGEMENT_TRUNCATED=%s\n' "$truncated" + while IFS=: read -r username _ uid gid gecos home shell; do + [ "$emitted" -lt 256 ] || break + kpanel_account_valid_username "$username" || continue + groups="$(id -nG "$username" 2>/dev/null | tr ' ' ',')" || groups="" + password="$(kpanel_account_password_status "$username")" || password=unknown + role="$(kpanel_account_role "$username")" || role=standard + if [ "$username" = root ]; then kind=root; elif [ "$uid" -ge "$uid_min" ] 2>/dev/null; then kind=human; else kind=system; fi + key_temp="$(mktemp /tmp/kejilion-account-status-keys.XXXXXX)" || { kpanel_account_emit failed "$version"; return 1; } + key_count=0 + if kpanel_account_capture_keys "$username" "$key_temp"; then + while IFS= read -r key || [ -n "$key" ]; do + [ -n "$key" ] || continue + kpanel_account_key_valid "$key" || continue + [ "$key_count" -lt 32 ] || break + key_id="$(kpanel_account_key_id "$key")" + key_type="${key%% *}" + fingerprint="$(printf '%s\n' "$key" | ssh-keygen -lf /dev/stdin 2>/dev/null | awk '{print $2}')" + comment="$(printf '%s\n' "$key" | awk '{ $1=""; $2=""; sub(/^ */, ""); print }' | tr '\t\r\n' ' ' | cut -c1-128)" + printf 'KPANEL_ACCOUNT_MANAGEMENT_KEY_HEX=%s\n' "$(kpanel_account_hex "$username $key_id $key_type $fingerprint $comment")" + key_count=$((key_count + 1)) + done < "$key_temp" + fi + rm -f -- "$key_temp" + account_record="$username $uid $gid $home $shell $kind $password $role $groups $key_count" + printf 'KPANEL_ACCOUNT_MANAGEMENT_ACCOUNT_HEX=%s\n' "$(kpanel_account_hex "$account_record")" + emitted=$((emitted + 1)) + done < "$passwd_file" +} + +kpanel_account_read_secret() { + local maximum="$1" frame bytes line_feeds + KPANEL_ACCOUNT_SECRET="" + frame="$(mktemp /tmp/kejilion-account-secret.XXXXXX)" || return 1 + chmod 600 "$frame" || { rm -f -- "$frame"; return 1; } + head -c "$((maximum + 2))" > "$frame" 2>/dev/null || { rm -f -- "$frame"; return 1; } + bytes="$(wc -c < "$frame")" || { rm -f -- "$frame"; return 1; } + if [ "$bytes" -lt 2 ] || [ "$bytes" -gt "$((maximum + 1))" ] || + ! LC_ALL=C tr -d '\000' < "$frame" | cmp -s - "$frame" || LC_ALL=C grep -q $'\r' "$frame"; then + rm -f -- "$frame"; return 1 + fi + line_feeds="$(LC_ALL=C tr -cd '\n' < "$frame" | wc -c)" || { rm -f -- "$frame"; return 1; } + [ "$line_feeds" -eq 1 ] && [ "$(tail -c 1 "$frame" | wc -l)" -eq 1 ] || { rm -f -- "$frame"; return 1; } + IFS= read -r KPANEL_ACCOUNT_SECRET < "$frame" || { rm -f -- "$frame"; return 1; } + rm -f -- "$frame" +} + +kpanel_account_snapshot_core() { + local snapshot="$1" file name + for name in passwd group shadow gshadow; do + case "$name" in + passwd) file="$(kpanel_account_passwd_file)" ;; + group) file="$(kpanel_account_group_file)" ;; + shadow) file="$(kpanel_account_shadow_file)" ;; + gshadow) file="$(kpanel_account_gshadow_file)" ;; + esac + [ ! -e "$file" ] || cp -p -- "$file" "$snapshot/$name" || return 1 + done +} + +kpanel_account_restore_core() { + local snapshot="$1" file name + for name in passwd group shadow gshadow; do + [ -f "$snapshot/$name" ] || continue + case "$name" in + passwd) file="$(kpanel_account_passwd_file)" ;; + group) file="$(kpanel_account_group_file)" ;; + shadow) file="$(kpanel_account_shadow_file)" ;; + gshadow) file="$(kpanel_account_gshadow_file)" ;; + esac + cp -p -- "$snapshot/$name" "$file" || return 1 + done +} + +kpanel_account_snapshot_ssh() { + local snapshot="$1" main fragment + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ ! -e "$main" ] || cp -p -- "$main" "$snapshot/sshd_config" || return 1 + if [ -e "$fragment" ]; then cp -p -- "$fragment" "$snapshot/sshd_fragment" || return 1; else : > "$snapshot/sshd_fragment.absent"; fi +} + +kpanel_account_reload_ssh() { + if command -v systemctl >/dev/null 2>&1; then + systemctl reload sshd >/dev/null 2>&1 || systemctl reload ssh >/dev/null 2>&1 + elif command -v service >/dev/null 2>&1; then + service sshd reload >/dev/null 2>&1 || service ssh reload >/dev/null 2>&1 + else + return 1 + fi +} + +kpanel_account_restore_ssh() { + local snapshot="$1" main fragment + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ ! -f "$snapshot/sshd_config" ] || cp -p -- "$snapshot/sshd_config" "$main" || return 1 + if [ -f "$snapshot/sshd_fragment.absent" ]; then rm -f -- "$fragment" || return 1; else cp -p -- "$snapshot/sshd_fragment" "$fragment" || return 1; fi + sshd -t -f "$main" >/dev/null 2>&1 && kpanel_account_reload_ssh +} + +kpanel_account_apply_ssh_policy() { + local password_auth="$1" root_login="$2" main fragment main_temp fragment_temp + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ -f "$main" ] && [ ! -L "$main" ] && [ ! -L "$fragment" ] || return 1 + mkdir -p -- "$(dirname -- "$fragment")" || return 1 + fragment_temp="$(mktemp "$(dirname -- "$fragment")/.00-kejilion-account-management.conf.XXXXXX")" || return 1 + { + printf '%s\n' '# Managed by kejilion.sh account-management protocol v1' + printf 'PubkeyAuthentication yes\n' + [ "$password_auth" = enabled ] && printf 'PasswordAuthentication yes\n' || printf 'PasswordAuthentication no\n' + printf 'KbdInteractiveAuthentication no\nChallengeResponseAuthentication no\nUsePAM yes\n' + case "$root_login" in enabled) printf 'PermitRootLogin yes\n' ;; key-only) printf 'PermitRootLogin prohibit-password\n' ;; disabled) printf 'PermitRootLogin no\n' ;; *) rm -f -- "$fragment_temp"; return 1 ;; esac + } > "$fragment_temp" || { rm -f -- "$fragment_temp"; return 1; } + chmod 600 "$fragment_temp" && chown 0:0 "$fragment_temp" || { rm -f -- "$fragment_temp"; return 1; } + main_temp="$(mktemp "$(dirname -- "$main")/.sshd_config.XXXXXX")" || { rm -f -- "$fragment_temp"; return 1; } + awk ' + BEGIN { inserted=0 } + /^[[:space:]]*Include[[:space:]]+\/etc\/ssh\/sshd_config\.d\/\*\.conf([[:space:]]|$)/ { if (!inserted) { print "Include /etc/ssh/sshd_config.d/*.conf"; inserted=1 }; next } + { if (!inserted && $0 !~ /^[[:space:]]*(#|$)/) { print "Include /etc/ssh/sshd_config.d/*.conf"; inserted=1 }; print } + END { if (!inserted) print "Include /etc/ssh/sshd_config.d/*.conf" } + ' "$main" > "$main_temp" || { rm -f -- "$fragment_temp" "$main_temp"; return 1; } + chmod --reference="$main" "$main_temp" 2>/dev/null || chmod 600 "$main_temp" + chown --reference="$main" "$main_temp" 2>/dev/null || chown 0:0 "$main_temp" + mv -f -- "$fragment_temp" "$fragment" && mv -f -- "$main_temp" "$main" || { rm -f -- "$fragment_temp" "$main_temp"; return 1; } + sshd -t -f "$main" >/dev/null 2>&1 && kpanel_account_reload_ssh +} + +kpanel_account_set_role() { + local username="$1" role="$2" admin_group sudo_file sudo_dir groups + [ "$username" != root ] || return 1 + sudo_file="$(kpanel_account_sudo_file "$username")"; sudo_dir="$(dirname -- "$sudo_file")" + [ ! -L "$sudo_dir" ] && [ ! -L "$sudo_file" ] || return 1 + mkdir -p -- "$sudo_dir" || return 1 + case "$role" in + standard) + gpasswd -d "$username" sudo >/dev/null 2>&1 || true + gpasswd -d "$username" wheel >/dev/null 2>&1 || true + rm -f -- "$sudo_file" || return 1 + ;; + administrator) + admin_group="$(kpanel_account_admin_group)" || return 1 + [ "$(kpanel_account_password_status "$username")" = enabled ] || return 2 + usermod -a -G "$admin_group" "$username" || return 1 + rm -f -- "$sudo_file" || return 1 + ;; + passwordless-admin) + admin_group="$(kpanel_account_admin_group)" || return 1 + usermod -a -G "$admin_group" "$username" || return 1 + printf '%s ALL=(ALL:ALL) NOPASSWD:ALL\n' "$username" > "$sudo_file" || return 1 + chmod 440 "$sudo_file" && chown 0:0 "$sudo_file" || return 1 + visudo -cf "$sudo_file" >/dev/null 2>&1 || return 1 + ;; + *) return 2 ;; + esac + [ "$(kpanel_account_role "$username")" = "$role" ] +} + +kpanel_account_create() { + local username="$1" role="$2" credential="$3" secret="$4" + local desired sudo_file LC_ALL=C + kpanel_account_valid_username "$username" && [ "$username" != root ] && ! kpanel_account_exists "$username" || return 2 + case "$role" in standard|administrator|passwordless-admin) ;; *) return 2 ;; esac + case "$credential" in + password) [ "${#secret}" -ge 8 ] && [ "${#secret}" -le 256 ] || return 2 ;; + key) kpanel_account_key_valid "$secret" || return 2; [ "$role" != administrator ] || return 2 ;; + *) return 2 ;; + esac + useradd -m -s /bin/bash "$username" || return 1 + if [ "$credential" = password ]; then + if ! printf '%s:%s\n' "$username" "$secret" | chpasswd; then + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + else + desired="$(mktemp /tmp/kejilion-account-create-key.XXXXXX)" || { + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + } + printf '%s\n' "$secret" > "$desired" + if ! kpanel_account_install_keys "$username" "$desired"; then + rm -f -- "$desired" + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + rm -f -- "$desired" + if ! passwd -l "$username" >/dev/null 2>&1; then + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + fi + if ! kpanel_account_set_role "$username" "$role"; then + sudo_file="$(kpanel_account_sudo_file "$username")" + rm -f -- "$sudo_file" >/dev/null 2>&1 || true + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi +} + +kpanel_account_write_failure() { + local snapshot="$1" original_version="$2" message="$3" restore_core="${4:-false}" restore_ssh="${5:-false}" + local version recovery restore_ok=true + kpanel_account_error "$message" + [ "$restore_core" != true ] || kpanel_account_restore_core "$snapshot" || restore_ok=false + [ "$restore_ssh" != true ] || kpanel_account_restore_ssh "$snapshot" || restore_ok=false + version="$(kpanel_account_version 2>/dev/null || true)" + if [ "$restore_ok" = true ] && [ "$version" = "$original_version" ]; then + rm -rf -- "$snapshot" + kpanel_account_emit failed "$version" + return 1 + fi + if recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" account-management)"; then + kpanel_account_emit rollback-failed "$version" "$recovery" + else + kpanel_account_emit rollback-failed "$version" + fi + return 1 +} + +kpanel_account_action() { + local action="$1" expected="$2" current snapshot final recovery username role credential marker secret="" changed=true + local LC_ALL=C + shift 2 + kpanel_system_resource_valid_version "$expected" || { kpanel_account_emit failed; return 2; } + current="$(kpanel_account_version)" || { kpanel_account_emit failed; return 1; } + if [ "$current" != "$expected" ]; then kpanel_account_emit conflict "$current"; return 2; fi + snapshot="$(kpanel_system_resource_tempdir account-management)" || { kpanel_account_emit failed "$current"; return 1; } + case "$action" in + create) + [ "$#" -eq 4 ] && [ "$4" = --secret-stdin ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; role="$2"; credential="$3" + [ "$credential" = password ] && marker=256 || marker=4096 + kpanel_account_read_secret "$marker" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_create "$username" "$role" "$credential" "$secret"; then kpanel_account_write_failure "$snapshot" "$current" "创建账户失败,已尝试恢复账户数据库" true false; return $?; fi + ;; + set-password) + [ "$#" -eq 2 ] && [ "$2" = --secret-stdin ] && kpanel_account_exists "$1" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; kpanel_account_read_secret 256 || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + [ "${#KPANEL_ACCOUNT_SECRET}" -ge 8 ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! printf '%s:%s\n' "$username" "$KPANEL_ACCOUNT_SECRET" | chpasswd; then kpanel_account_write_failure "$snapshot" "$current" "修改密码失败,已尝试恢复" true false; return $?; fi + ;; + add-key) + [ "$#" -eq 2 ] && [ "$2" = --secret-stdin ] && kpanel_account_exists "$1" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; kpanel_account_read_secret 4096 || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; }; secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_key_valid "$secret" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + local keys desired + keys="$snapshot/authorized_keys"; desired="$snapshot/authorized_keys.desired" + kpanel_account_capture_keys "$username" "$keys" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if grep -Fqx "$secret" "$keys"; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + cp -- "$keys" "$desired" && printf '%s\n' "$secret" >> "$desired" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_install_keys "$username" "$desired"; then + kpanel_account_install_keys "$username" "$keys" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "添加 SSH 公钥失败,已尝试恢复" false false + return $? + fi + ;; + delete-key) + [ "$#" -eq 2 ] && kpanel_account_exists "$1" && [[ "$2" =~ ^[0-9a-f]{64}$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; local key_id="$2" keys="$snapshot/authorized_keys" desired="$snapshot/authorized_keys.desired" line found=false + kpanel_account_capture_keys "$username" "$keys" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + : > "$desired" + while IFS= read -r line || [ -n "$line" ]; do if [ -n "$line" ] && [ "$(kpanel_account_key_id "$line")" = "$key_id" ]; then found=true; else printf '%s\n' "$line" >> "$desired"; fi; done < "$keys" + if [ "$found" = false ]; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + if ! kpanel_account_install_keys "$username" "$desired"; then + kpanel_account_install_keys "$username" "$keys" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "删除 SSH 公钥失败,已尝试恢复" false false + return $? + fi + ;; + set-role) + [ "$#" -eq 2 ] && kpanel_account_exists "$1" && [ "$1" != root ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; role="$2"; [ "$(kpanel_account_role "$username")" != "$role" ] || { rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; } + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + local sudo_file; sudo_file="$(kpanel_account_sudo_file "$username")"; if [ -e "$sudo_file" ]; then cp -p -- "$sudo_file" "$snapshot/sudo" || { rm -rf -- "$snapshot"; return 1; }; else : > "$snapshot/sudo.absent"; fi + if ! kpanel_account_set_role "$username" "$role"; then + if [ -f "$snapshot/sudo.absent" ]; then rm -f -- "$sudo_file" >/dev/null 2>&1 || true; else cp -p -- "$snapshot/sudo" "$sudo_file" >/dev/null 2>&1 || true; fi + kpanel_account_write_failure "$snapshot" "$current" "调整账户角色失败,已尝试恢复" true false + return $? + fi + ;; + set-ssh-policy) + [ "$#" -eq 2 ] && [[ "$1" =~ ^(enabled|disabled)$ ]] && [[ "$2" =~ ^(enabled|key-only|disabled)$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_apply_ssh_policy "$1" "$2"; then kpanel_account_write_failure "$snapshot" "$current" "SSH 登录策略应用失败,已尝试恢复" false true; return $?; fi + ;; + disable-root) + [ "$#" -eq 0 ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + if [ "$(kpanel_account_password_status root)" = locked ] && [ "$(kpanel_account_sshd_effective | awk '{print $3}')" = disabled ]; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + kpanel_account_snapshot_core "$snapshot" && kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! passwd -l root >/dev/null 2>&1 || ! kpanel_account_apply_ssh_policy "$(kpanel_account_sshd_effective | awk '{print $1 == "yes" ? "enabled" : "disabled"}')" disabled; then kpanel_account_write_failure "$snapshot" "$current" "禁用 Root 失败,已尝试恢复" true true; return $?; fi + ;; + create-admin-disable-root) + [ "$#" -eq 3 ] && [ "$3" = --secret-stdin ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; credential="$2"; [ "$credential" = password ] && marker=256 || marker=4096 + kpanel_account_read_secret "$marker" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; }; secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_snapshot_core "$snapshot" && kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + role=administrator; [ "$credential" = key ] && role=passwordless-admin + if ! kpanel_account_create "$username" "$role" "$credential" "$secret"; then + kpanel_account_write_failure "$snapshot" "$current" "替代管理员创建失败,已尝试恢复" true true + return $? + fi + if ! passwd -l root >/dev/null 2>&1 || + ! kpanel_account_apply_ssh_policy "$([ "$credential" = password ] && printf enabled || printf disabled)" disabled; then + rm -f -- "$(kpanel_account_sudo_file "$username")" >/dev/null 2>&1 || true + userdel -r "$username" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "Root 安全迁移失败,已尝试恢复" true true + return $? + fi + ;; + delete) + [ "$#" -eq 2 ] && kpanel_account_valid_username "$1" && [ "$1" != root ] && [[ "$2" =~ ^(true|false)$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; if ! kpanel_account_exists "$username"; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + local sudo_file; sudo_file="$(kpanel_account_sudo_file "$username")" + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if [ -e "$sudo_file" ]; then cp -p -- "$sudo_file" "$snapshot/sudo" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; }; else : > "$snapshot/sudo.absent"; fi + if ! { if [ "$2" = true ]; then userdel -r "$username"; else userdel "$username"; fi; }; then + if [ "$2" = false ]; then + kpanel_account_write_failure "$snapshot" "$current" "删除账户失败,已尝试恢复账户数据库" true false + return $? + fi + kpanel_account_restore_core "$snapshot" >/dev/null 2>&1 || true + final="$(kpanel_account_version 2>/dev/null || true)" + recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" account-management 2>/dev/null || true)" + kpanel_account_error "删除账户及主目录失败,主目录可能已被部分删除,需要人工检查" + kpanel_account_emit needs-attention "$final" "$recovery" + return 1 + fi + rm -f -- "$sudo_file" || { rm -rf -- "$snapshot"; kpanel_account_emit needs-attention "$(kpanel_account_version 2>/dev/null || true)"; return 1; } + ;; + *) rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2 ;; + esac + final="$(kpanel_account_version)" || { rm -rf -- "$snapshot"; kpanel_account_emit needs-attention; return 1; } + [ "$final" != "$current" ] || changed=false + rm -rf -- "$snapshot" + [ "$changed" = true ] && kpanel_account_emit applied "$final" || kpanel_account_emit unchanged "$final" +} + +kpanel_account_run_locked() ( + local action="$1" expected="$2" lock_file + shift 2 + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_account_emit failed; return 1; } + exec 9<>"$lock_file" || { kpanel_account_emit failed; return 1; } + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || { kpanel_account_emit failed; return 1; } + if ! flock -w 5 -x 9 >/dev/null 2>&1; then kpanel_account_emit conflict "$(kpanel_account_version 2>/dev/null || true)"; return 2; fi + kpanel_account_action "$action" "$expected" "$@" +) + +kpanel_account_dispatch() { + local action="${1:-}" + [ "$#" -ge 1 ] || { kpanel_account_emit failed; return 2; } + shift + case "$action" in + status) kpanel_account_status "$@" ;; + create|set-password|add-key|delete-key|set-role|set-ssh-policy|disable-root|create-admin-disable-root|delete) + [ "$#" -ge 1 ] || { kpanel_account_emit failed; return 2; } + local expected="$1"; shift + kpanel_account_require true awk cat chpasswd cmp cut getent gpasswd grep head id mkdir mktemp od passwd runuser sed sha256sum ssh-keygen sshd stat tail tr useradd userdel usermod visudo wc || { kpanel_account_emit failed; return $?; } + kpanel_account_run_locked "$action" "$expected" "$@" + ;; + *) kpanel_account_error "不支持的 account-management 动作"; kpanel_account_emit failed; return 2 ;; + esac +} + +# KPanel account management protocol end + + log_menu() { send_stats "系统日志管理工具" @@ -25009,25 +26170,25 @@ EOF read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} - cd ~ - curl -Ss -o ~/Limiting_Shut_down.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/Limiting_Shut_down1.sh - chmod +x ~/Limiting_Shut_down.sh - sed -i "s/110/$rx_threshold_gb/g" ~/Limiting_Shut_down.sh - sed -i "s/120/$tx_threshold_gb/g" ~/Limiting_Shut_down.sh check_crontab_installed - crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - - (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 - crontab -l | grep -v 'reboot' | crontab - - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + local traffic_version + traffic_version="$(kpanel_network_operations_traffic_version)" + if KJ_NETWORK_OPERATIONS_NONINTERACTIVE=1 kpanel_network_operations_traffic_run_locked enable "$traffic_version" "$rx_threshold_gb" "$tx_threshold_gb" "$cz_day"; then + echo "限流关机已设置" + send_stats "限流关机已设置" + else + echo "限流关机设置失败,请根据上方错误检查配置" + fi ;; 2) check_crontab_installed - crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - - crontab -l | grep -v 'reboot' | crontab - - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + local traffic_version + traffic_version="$(kpanel_network_operations_traffic_version)" + if KJ_NETWORK_OPERATIONS_NONINTERACTIVE=1 kpanel_network_operations_traffic_run_locked disable "$traffic_version"; then + echo "已关闭限流关机功能" + else + echo "关闭限流关机失败,请根据上方错误检查配置" + fi ;; *) break @@ -26405,8 +27566,14 @@ else elif [ "${1:-}" = "system-resource" ]; then shift kpanel_system_resource_dispatch "$@" + elif [ "${1:-}" = "network-operations" ]; then + shift + kpanel_network_operations_dispatch "$@" + elif [ "${1:-}" = "account-management" ]; then + shift + kpanel_account_dispatch "$@" else - echo "用法: k kpanel node join <授权> | status | update | uninstall;或 k kpanel system-resource ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/kejilion.sh b/kejilion.sh index d97a55541..4debb112a 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -25,6 +25,8 @@ kpanel_protocol_active() { [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || @@ -22341,7 +22343,7 @@ kpanel_system_resource_persist_recovery_snapshot() { local resource="$2" local recovery_root destination timestamp invalid - [[ "$resource" =~ ^(hosts|cron|firewall)$ ]] || return 1 + [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management)$ ]] || return 1 [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 [ -z "$invalid" ] || return 1 @@ -23930,6 +23932,1165 @@ kpanel_system_resource_dispatch() { # KPanel system resource protocol end +# KPanel network operations protocol start +KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1" + +kpanel_network_operations_script_file() { + printf '%s\n' "/root/Limiting_Shut_down.sh" +} + +kpanel_network_operations_net_dev_file() { + printf '%s\n' "/proc/net/dev" +} + +kpanel_network_operations_emit() { + local status="$1" + local version="${2:-}" + local backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_NETWORK_OPERATIONS_STATUS=%s\n' "$status" + printf 'KPANEL_NETWORK_OPERATIONS_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_NETWORK_OPERATIONS_BACKUP=%s\n' "$backup" +} + +kpanel_network_operations_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_network_operations_require() { + local needs_root="$1" + shift + [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || { + kpanel_network_operations_error "KPanel network-operations 协议环境未启用" + kpanel_network_operations_emit failed + return 2 + } + [ "$(uname -s 2>/dev/null)" = "Linux" ] || { + kpanel_network_operations_error "KPanel network-operations 协议仅支持 Linux" + kpanel_network_operations_emit failed + return 2 + } + if [ "$needs_root" = true ] && [ "$(id -u)" -ne 0 ]; then + kpanel_network_operations_error "限流关机管理必须以 root 运行" + kpanel_network_operations_emit failed + return 2 + fi + for command_name in "$@"; do + command -v "$command_name" >/dev/null 2>&1 || { + kpanel_network_operations_error "缺少必要命令: $command_name" + kpanel_network_operations_emit failed + return 2 + } + done +} + +kpanel_network_operations_port_usage() { + local temporary total truncated=false version line hex count=0 + kpanel_network_operations_require false ss awk wc sha256sum od tr mktemp || return $? + [ "$#" -eq 0 ] || { + kpanel_network_operations_error "port-usage list 不接受额外参数" + kpanel_network_operations_emit failed + return 2 + } + temporary="$(mktemp /tmp/kejilion-network-ports.XXXXXX)" || { + kpanel_network_operations_error "无法创建端口占用快照" + kpanel_network_operations_emit failed + return 1 + } + if ! LC_ALL=C ss -H -lntup > "$temporary" 2>/dev/null; then + rm -f -- "$temporary" + kpanel_network_operations_error "无法读取监听端口" + kpanel_network_operations_emit failed + return 1 + fi + if ! kpanel_system_resource_file_within_bounds "$temporary" 4194304 4096 || + ! awk 'length($0) > 4096 { exit 1 }' "$temporary"; then + rm -f -- "$temporary" + kpanel_network_operations_error "端口占用结果超过协议上限" + kpanel_network_operations_emit failed + return 1 + fi + total="$(awk 'END { print NR + 0 }' "$temporary")" || total=0 + [ "$total" -le 512 ] || truncated=true + version="$(sha256sum -- "$temporary" 2>/dev/null | awk '{print $1}')" + kpanel_network_operations_emit ok "$version" + printf 'KPANEL_NETWORK_OPERATIONS_TOTAL=%s\n' "$total" + printf 'KPANEL_NETWORK_OPERATIONS_TRUNCATED=%s\n' "$truncated" + while IFS= read -r line && [ "$count" -lt 512 ]; do + hex="$(printf '%s' "$line" | od -An -v -tx1 | tr -d ' \n')" || { + rm -f -- "$temporary" + return 1 + } + printf 'KPANEL_NETWORK_OPERATIONS_PORT_HEX=%s\n' "$hex" + count=$((count + 1)) + done < "$temporary" + rm -f -- "$temporary" +} + +kpanel_network_operations_traffic_bytes() { + local path + path="$(kpanel_network_operations_net_dev_file)" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + awk ' + BEGIN { rx = 0; tx = 0 } + $1 ~ /^(eth|ens|enp|eno)[0-9]+:/ { rx += $2; tx += $10 } + END { printf "%.0f %.0f\n", rx, tx } + ' "$path" +} + +kpanel_network_operations_script_safe() { + local path="$1" uid expected_uid mode + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + kpanel_system_resource_file_within_bounds "$path" 65536 256 || return 1 + uid="$(stat -c '%u' "$path" 2>/dev/null)" || return 1 + expected_uid="$(kpanel_system_resource_lock_owner_uid)" || return 1 + [ "$uid" = "$expected_uid" ] || return 1 + mode="$(stat -c '%a' "$path" 2>/dev/null)" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0022))" -eq 0 ] +} + +kpanel_network_operations_cron_relevant() { + local source="$1" + awk ' + $0 == "# kejilion traffic shutdown start" { managed = 1; print; next } + managed { print; if ($0 == "# kejilion traffic shutdown end") managed = 0; next } + $0 == "* * * * * ~/Limiting_Shut_down.sh" || + $0 == "* * * * * /root/Limiting_Shut_down.sh" { print } + ' "$source" +} + +kpanel_network_operations_traffic_version() { + local script_path cron_path canonical version + script_path="$(kpanel_network_operations_script_file)" + [ ! -L "$script_path" ] || return 1 + cron_path="$(mktemp /tmp/kejilion-network-traffic-cron.XXXXXX)" || return 1 + canonical="$(mktemp /tmp/kejilion-network-traffic-version.XXXXXX)" || { + rm -f -- "$cron_path" + return 1 + } + if ! kpanel_system_resource_cron_capture "$cron_path"; then + rm -f -- "$cron_path" "$canonical" + return 1 + fi + if [ -e "$script_path" ]; then + kpanel_network_operations_script_safe "$script_path" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + printf 'script=present\n' > "$canonical" + sha256sum -- "$script_path" >> "$canonical" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + else + printf 'script=absent\n' > "$canonical" + fi + printf 'cron:\n' >> "$canonical" + kpanel_network_operations_cron_relevant "$cron_path" >> "$canonical" || { + rm -f -- "$cron_path" "$canonical" + return 1 + } + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$cron_path" "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_network_operations_parse_script() { + local path="$1" rx tx + grep -Fqx '# KEJILION_TRAFFIC_SHUTDOWN_MANAGED_V1' "$path" || return 1 + rx="$(sed -n 's/^rx_threshold_gb=\([0-9][0-9]*\)$/\1/p' "$path")" + tx="$(sed -n 's/^tx_threshold_gb=\([0-9][0-9]*\)$/\1/p' "$path")" + [[ "$rx" =~ ^[0-9]+$ ]] && [[ "$tx" =~ ^[0-9]+$ ]] || return 1 + [ "$(printf '%s\n' "$rx" | wc -l)" -eq 1 ] && [ "$(printf '%s\n' "$tx" | wc -l)" -eq 1 ] || return 1 + KPANEL_NETWORK_TRAFFIC_RX="$rx" + KPANEL_NETWORK_TRAFFIC_TX="$tx" +} + +kpanel_network_operations_traffic_status() { + local script_path cron_path version bytes rx_bytes tx_bytes enabled=false health=disabled + local rx_threshold=0 tx_threshold=0 reset_day=0 invocation_count reset_line_count start_count end_count expected_script + kpanel_network_operations_require false awk crontab grep sed sha256sum stat wc mktemp cmp || return $? + [ "$#" -eq 0 ] || { + kpanel_network_operations_error "traffic-shutdown status 不接受额外参数" + kpanel_network_operations_emit failed + return 2 + } + script_path="$(kpanel_network_operations_script_file)" + cron_path="$(mktemp /tmp/kejilion-network-traffic-status.XXXXXX)" || { + kpanel_network_operations_emit failed + return 1 + } + if ! kpanel_system_resource_cron_capture "$cron_path"; then + rm -f -- "$cron_path" + kpanel_network_operations_error "无法读取 root crontab" + kpanel_network_operations_emit failed + return 1 + fi + version="$(kpanel_network_operations_traffic_version)" || { + rm -f -- "$cron_path" + kpanel_network_operations_error "限流关机配置不安全或无法计算版本" + kpanel_network_operations_emit failed + return 1 + } + bytes="$(kpanel_network_operations_traffic_bytes)" || { + rm -f -- "$cron_path" + kpanel_network_operations_error "无法读取累计网络流量" + kpanel_network_operations_emit failed "$version" + return 1 + } + read -r rx_bytes tx_bytes <<< "$bytes" + if [ -e "$script_path" ]; then + enabled=true + if kpanel_network_operations_script_safe "$script_path" && + kpanel_network_operations_parse_script "$script_path"; then + rx_threshold="$KPANEL_NETWORK_TRAFFIC_RX" + tx_threshold="$KPANEL_NETWORK_TRAFFIC_TX" + expected_script="$(mktemp /tmp/kejilion-network-traffic-expected.XXXXXX)" || { + rm -f -- "$cron_path" + kpanel_network_operations_emit failed "$version" + return 1 + } + if ! kpanel_network_operations_build_script "$expected_script" "$rx_threshold" "$tx_threshold" || + ! cmp -s -- "$expected_script" "$script_path"; then + rx_threshold=0 + tx_threshold=0 + fi + rm -f -- "$expected_script" + fi + fi + start_count="$(grep -Fxc '# kejilion traffic shutdown start' "$cron_path")" + end_count="$(grep -Fxc '# kejilion traffic shutdown end' "$cron_path")" + invocation_count="$(grep -Fxc "* * * * * $script_path" "$cron_path")" + reset_line_count="$(sed -n '/^# kejilion traffic shutdown start$/,/^# kejilion traffic shutdown end$/p' "$cron_path" | grep -Ec '^0 1 ([1-9]|[12][0-9]|3[01]) \* \* reboot$')" + if [ "$enabled" = true ] && [ "$rx_threshold" -gt 0 ] && [ "$tx_threshold" -gt 0 ] && + [ "$start_count" -eq 1 ] && [ "$end_count" -eq 1 ] && [ "$invocation_count" -eq 1 ] && [ "$reset_line_count" -eq 1 ]; then + reset_day="$(sed -n '/^# kejilion traffic shutdown start$/,/^# kejilion traffic shutdown end$/s/^0 1 \([0-9][0-9]*\) \* \* reboot$/\1/p' "$cron_path")" + if [[ "$reset_day" =~ ^([1-9]|[12][0-9]|3[01])$ ]]; then + health=ready + else + health=inconsistent + fi + elif [ "$enabled" = false ] && [ "$start_count" -eq 0 ] && [ "$end_count" -eq 0 ] && [ "$invocation_count" -eq 0 ]; then + health=disabled + else + health=inconsistent + fi + rm -f -- "$cron_path" + kpanel_network_operations_emit ok "$version" + printf 'KPANEL_NETWORK_OPERATIONS_ENABLED=%s\n' "$enabled" + printf 'KPANEL_NETWORK_OPERATIONS_HEALTH=%s\n' "$health" + printf 'KPANEL_NETWORK_OPERATIONS_RX_BYTES=%s\n' "$rx_bytes" + printf 'KPANEL_NETWORK_OPERATIONS_TX_BYTES=%s\n' "$tx_bytes" + printf 'KPANEL_NETWORK_OPERATIONS_RX_THRESHOLD_GIB=%s\n' "$rx_threshold" + printf 'KPANEL_NETWORK_OPERATIONS_TX_THRESHOLD_GIB=%s\n' "$tx_threshold" + printf 'KPANEL_NETWORK_OPERATIONS_RESET_DAY=%s\n' "$reset_day" +} + +kpanel_network_operations_valid_threshold() { + [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" != 0 ] && [ "$((10#$1))" -le 8388607 ] +} + +kpanel_network_operations_build_script() { + local target="$1" rx="$2" tx="$3" + cat > "$target" < "$target" || return 1 + if [ "$action" = enable ]; then + { + printf '%s\n' '# kejilion traffic shutdown start' + printf '* * * * * %s\n' "$script_path" + printf '0 1 %s * * reboot\n' "$reset_day" + printf '%s\n' '# kejilion traffic shutdown end' + } >> "$target" || return 1 + fi + kpanel_system_resource_file_within_bounds "$target" 262144 512 +} + +kpanel_network_operations_restore_traffic() { + local snapshot="$1" script_path="$2" script_existed="$3" cron_existed="$4" verify version="$5" + if [ "$script_existed" = true ]; then + cp -p -- "$snapshot/script" "$script_path" >/dev/null 2>&1 || return 1 + else + rm -f -- "$script_path" >/dev/null 2>&1 || return 1 + fi + verify="$snapshot/cron.verify" + kpanel_system_resource_cron_restore "$snapshot/crontab" "$cron_existed" "$verify" || return 1 + [ "$(kpanel_network_operations_traffic_version 2>/dev/null)" = "$version" ] +} + +kpanel_network_operations_traffic_failure() { + local snapshot="$1" script_path="$2" script_existed="$3" cron_existed="$4" original_version="$5" message="$6" + local version recovery_path + kpanel_network_operations_error "$message" + if kpanel_network_operations_restore_traffic "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$original_version"; then + version="$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$version" + return 1 + else + version="$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + if recovery_path="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" traffic-shutdown)"; then + kpanel_network_operations_emit rollback-failed "$version" "$recovery_path" + else + kpanel_network_operations_emit rollback-failed "$version" + fi + return 1 + fi +} + +kpanel_network_operations_traffic_action() { + local action="$1" expected="${2:-}" rx="${3:-}" tx="${4:-}" reset_day="${5:-}" + local script_path current_version snapshot cron_existed script_existed=false + local desired_script desired_cron install_temp final_version + case "$action" in + enable) + [ "$#" -eq 5 ] && kpanel_system_resource_valid_version "$expected" && + kpanel_network_operations_valid_threshold "$rx" && + kpanel_network_operations_valid_threshold "$tx" && + [[ "$reset_day" =~ ^([1-9]|[12][0-9]|3[01])$ ]] || { + kpanel_network_operations_error "enable 需要 expectedVersion、正整数 GiB 阈值和 1-31 重置日" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + } + ;; + disable) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$expected" || { + kpanel_network_operations_error "disable 只需要 expectedVersion" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + } + ;; + *) + kpanel_network_operations_error "不支持的 traffic-shutdown 动作" + kpanel_network_operations_emit failed + return 2 + ;; + esac + script_path="$(kpanel_network_operations_script_file)" + [ ! -L "$script_path" ] || { + kpanel_network_operations_error "限流关机脚本不能是符号链接" + kpanel_network_operations_emit failed + return 1 + } + current_version="$(kpanel_network_operations_traffic_version)" || { + kpanel_network_operations_error "无法读取当前限流关机配置" + kpanel_network_operations_emit failed + return 1 + } + if [ "$current_version" != "$expected" ]; then + kpanel_network_operations_error "资源版本已变化,请刷新后重试" + kpanel_network_operations_emit conflict "$current_version" + return 2 + fi + snapshot="$(kpanel_system_resource_tempdir traffic-shutdown)" || { + kpanel_network_operations_emit failed "$current_version" + return 1 + } + if [ -e "$script_path" ]; then + kpanel_network_operations_script_safe "$script_path" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + cp -p -- "$script_path" "$snapshot/script" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + script_existed=true + fi + kpanel_system_resource_cron_capture "$snapshot/crontab" || { + rm -rf -- "$snapshot" + kpanel_network_operations_emit failed "$current_version" + return 1 + } + cron_existed="$KPANEL_SYSTEM_RESOURCE_CRON_EXISTED" + printf '%s\n' "$script_existed" > "$snapshot/script.existed" + printf '%s\n' "$cron_existed" > "$snapshot/cron.existed" + desired_script="$snapshot/script.desired" + desired_cron="$snapshot/cron.desired" + if [ "$action" = enable ]; then + kpanel_network_operations_build_script "$desired_script" "$rx" "$tx" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法生成限流关机脚本" + return $? + } + fi + kpanel_network_operations_build_cron "$snapshot/crontab" "$desired_cron" "$action" "$script_path" "$reset_day" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法生成限流关机 crontab" + return $? + } + if { [ "$action" = enable ] && [ "$script_existed" = true ] && + cmp -s -- "$desired_script" "$script_path" && cmp -s -- "$desired_cron" "$snapshot/crontab"; } || + { [ "$action" = disable ] && [ "$script_existed" = false ] && cmp -s -- "$desired_cron" "$snapshot/crontab"; }; then + rm -rf -- "$snapshot" + kpanel_network_operations_emit unchanged "$current_version" + return 0 + fi + if [ "$action" = enable ]; then + install_temp="$(mktemp "$(dirname -- "$script_path")/.Limiting_Shut_down.sh.XXXXXX")" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法创建限流关机临时文件" + return $? + } + if ! cp -- "$desired_script" "$install_temp" || ! chown 0:0 "$install_temp" 2>/dev/null || + ! chmod 700 "$install_temp" || ! mv -f -- "$install_temp" "$script_path"; then + rm -f -- "$install_temp" + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法原子安装限流关机脚本" + return $? + fi + else + rm -f -- "$script_path" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法删除限流关机脚本" + return $? + } + fi + if ! crontab "$desired_cron"; then + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "无法安装限流关机 crontab" + return $? + fi + final_version="$(kpanel_network_operations_traffic_version)" || { + kpanel_network_operations_traffic_failure "$snapshot" "$script_path" "$script_existed" "$cron_existed" "$current_version" "限流关机配置回读失败" + return $? + } + if [ "$final_version" = "$current_version" ]; then + rm -rf -- "$snapshot" + kpanel_network_operations_emit unchanged "$final_version" + else + rm -rf -- "$snapshot" + kpanel_network_operations_emit applied "$final_version" + fi +} + +kpanel_network_operations_traffic_run_locked() ( + local action="$1" lock_file + shift + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { + kpanel_network_operations_error "network-operations 锁路径不安全或无法创建" + kpanel_network_operations_emit failed "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 1 + } + exec 9<>"$lock_file" || return 1 + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || return 1 + if ! flock -w 5 -x 9 >/dev/null 2>&1; then + kpanel_network_operations_error "network-operations 写锁等待超时" + kpanel_network_operations_emit conflict "$(kpanel_network_operations_traffic_version 2>/dev/null || true)" + return 2 + fi + kpanel_network_operations_traffic_action "$action" "$@" +) + +kpanel_network_operations_dispatch() { + local resource="${1:-}" action="${2:-}" + [ "$#" -ge 2 ] || { + kpanel_network_operations_error "用法: kpanel network-operations ..." + kpanel_network_operations_emit failed + return 2 + } + shift 2 + case "$resource:$action" in + port-usage:list) kpanel_network_operations_port_usage "$@" ;; + traffic-shutdown:status) + kpanel_network_operations_traffic_status "$@" + ;; + traffic-shutdown:enable|traffic-shutdown:disable) + kpanel_network_operations_require true awk crontab grep sed sha256sum stat wc mktemp flock cmp cp mv chmod chown || return $? + kpanel_network_operations_traffic_run_locked "$action" "$@" + ;; + *) + kpanel_network_operations_error "不支持的 network-operations 资源或动作" + kpanel_network_operations_emit failed + return 2 + ;; + esac +} + +# KPanel network operations protocol end + + +# KPanel account management protocol start +KPANEL_ACCOUNT_MANAGEMENT_PROTOCOL_VERSION="1" + +kpanel_account_error() { + printf '%s\n' "$*" >&2 +} + +kpanel_account_emit() { + local status="$1" version="${2:-}" backup="${3:-}" + printf 'KPANEL_ACCOUNT_MANAGEMENT_STATUS=%s\n' "$status" + [ -z "$version" ] || printf 'KPANEL_ACCOUNT_MANAGEMENT_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_ACCOUNT_MANAGEMENT_BACKUP=%s\n' "$backup" +} + +kpanel_account_root_path() { + local path="$1" + printf '%s%s\n' "${KPANEL_ACCOUNT_TEST_ROOT:-}" "$path" +} + +kpanel_account_passwd_file() { kpanel_account_root_path /etc/passwd; } +kpanel_account_group_file() { kpanel_account_root_path /etc/group; } +kpanel_account_shadow_file() { kpanel_account_root_path /etc/shadow; } +kpanel_account_gshadow_file() { kpanel_account_root_path /etc/gshadow; } +kpanel_account_login_defs_file() { kpanel_account_root_path /etc/login.defs; } +kpanel_account_sudoers_file() { kpanel_account_root_path /etc/sudoers; } +kpanel_account_sudoers_dir() { kpanel_account_root_path /etc/sudoers.d; } +kpanel_account_sshd_config() { kpanel_account_root_path /etc/ssh/sshd_config; } +kpanel_account_sshd_fragment() { kpanel_account_root_path /etc/ssh/sshd_config.d/00-kejilion-account-management.conf; } + +kpanel_account_host_path() { + local path="$1" + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + printf '%s%s\n' "$KPANEL_ACCOUNT_TEST_ROOT" "$path" + else + printf '%s\n' "$path" + fi +} + +kpanel_account_valid_username() { + [[ "$1" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] && [[ "$1" != *'$' ]] +} + +kpanel_account_require() { + local write="$1" command + shift + [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || { + kpanel_account_error "KPanel account-management 协议环境未启用" + return 2 + } + [ "$EUID" -eq 0 ] || { + kpanel_account_error "KPanel account-management 协议必须以 root 运行" + return 1 + } + [ "$(uname -s 2>/dev/null)" = Linux ] || { + kpanel_account_error "KPanel account-management 协议仅支持 Linux" + return 2 + } + for command in "$@"; do + command -v "$command" >/dev/null 2>&1 || { + kpanel_account_error "缺少 account-management 依赖: $command" + return 2 + } + done + if [ "$write" = true ]; then + for command in flock cp mv chmod chown mktemp; do + command -v "$command" >/dev/null 2>&1 || { + kpanel_account_error "缺少 account-management 写入依赖: $command" + return 2 + } + done + fi +} + +kpanel_account_file_safe() { + local path="$1" max_bytes="$2" max_lines="$3" + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + kpanel_system_resource_file_within_bounds "$path" "$max_bytes" "$max_lines" +} + +kpanel_account_find_record() { + local username="$1" passwd_file + passwd_file="$(kpanel_account_passwd_file)" + awk -F: -v username="$username" '$1 == username { print; found=1; exit } END { exit(found ? 0 : 1) }' "$passwd_file" +} + +kpanel_account_exists() { + kpanel_account_find_record "$1" >/dev/null 2>&1 +} + +kpanel_account_home() { + local record + record="$(kpanel_account_find_record "$1")" || return 1 + printf '%s\n' "$record" | awk -F: '{print $6}' +} + +kpanel_account_authorized_keys() { + local username="$1" home + home="$(kpanel_account_home "$username")" || return 1 + [[ "$home" = /* ]] && [ "$home" != / ] || return 1 + printf '%s/.ssh/authorized_keys\n' "$(kpanel_account_host_path "$home")" +} + +kpanel_account_capture_keys() { + local username="$1" target="$2" path + path="$(kpanel_account_authorized_keys "$username")" || return 1 + : > "$target" || return 1 + [ ! -e "$path" ] && return 0 + [ -f "$path" ] && [ ! -L "$path" ] || return 1 + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + cat -- "$path" > "$target" || return 1 + else + runuser -u "$username" -- cat -- "$path" > "$target" 2>/dev/null || return 1 + fi + kpanel_system_resource_file_within_bounds "$target" 131072 128 +} + +kpanel_account_key_valid() { + local key="$1" temporary LC_ALL=C + [ -n "$key" ] && [ "${#key}" -le 4096 ] && [[ "$key" != *$'\n'* ]] && [[ "$key" != *$'\r'* ]] || return 1 + case "$key" in + ssh-rsa\ *|ssh-ed25519\ *|ecdsa-sha2-*\ *|sk-ssh-ed25519@openssh.com\ *|sk-ecdsa-sha2-nistp256@openssh.com\ *) ;; + *) return 1 ;; + esac + temporary="$(mktemp /tmp/kejilion-account-key.XXXXXX)" || return 1 + chmod 600 "$temporary" || { rm -f -- "$temporary"; return 1; } + printf '%s\n' "$key" > "$temporary" || { rm -f -- "$temporary"; return 1; } + ssh-keygen -lf "$temporary" >/dev/null 2>&1 + local result=$? + rm -f -- "$temporary" + return "$result" +} + +kpanel_account_key_id() { + printf '%s' "$1" | sha256sum | awk '{print $1}' +} + +kpanel_account_install_keys() { + local username="$1" desired="$2" path ssh_dir temp uid gid + path="$(kpanel_account_authorized_keys "$username")" || return 1 + ssh_dir="$(dirname -- "$path")" || return 1 + [ ! -L "$ssh_dir" ] && [ ! -L "$path" ] || return 1 + uid="$(kpanel_account_find_record "$username" | awk -F: '{print $3}')" || return 1 + gid="$(kpanel_account_find_record "$username" | awk -F: '{print $4}')" || return 1 + if [ -n "${KPANEL_ACCOUNT_TEST_ROOT:-}" ]; then + mkdir -p -- "$ssh_dir" || return 1 + chmod 700 "$ssh_dir" || return 1 + temp="$(mktemp "$ssh_dir/.authorized_keys.XXXXXX")" || return 1 + cp -- "$desired" "$temp" && chmod 600 "$temp" && mv -f -- "$temp" "$path" || { rm -f -- "$temp"; return 1; } + return 0 + fi + runuser -u "$username" -- mkdir -p -- "$ssh_dir" >/dev/null 2>&1 || return 1 + runuser -u "$username" -- chmod 700 "$ssh_dir" >/dev/null 2>&1 || return 1 + temp="$ssh_dir/.authorized_keys.kpanel.$$.$RANDOM" + runuser -u "$username" -- tee "$temp" < "$desired" >/dev/null 2>&1 || return 1 + if ! runuser -u "$username" -- chmod 600 "$temp" >/dev/null 2>&1 || + ! runuser -u "$username" -- mv -f -- "$temp" "$path" >/dev/null 2>&1; then + runuser -u "$username" -- rm -f -- "$temp" >/dev/null 2>&1 || true + return 1 + fi + chown "$uid:$gid" "$ssh_dir" "$path" >/dev/null 2>&1 || return 1 +} + +kpanel_account_password_status() { + local username="$1" status + status="$(passwd -S "$username" 2>/dev/null | awk '{print $2}')" || return 1 + case "$status" in + P) printf '%s\n' enabled ;; + L|LK) printf '%s\n' locked ;; + NP) printf '%s\n' unset ;; + *) printf '%s\n' unknown ;; + esac +} + +kpanel_account_admin_group() { + if getent group sudo >/dev/null 2>&1; then + printf '%s\n' sudo + elif getent group wheel >/dev/null 2>&1; then + printf '%s\n' wheel + else + return 1 + fi +} + +kpanel_account_sudo_file() { + printf '%s/90-kejilion-%s\n' "$(kpanel_account_sudoers_dir)" "$1" +} + +kpanel_account_role() { + local username="$1" groups sudo_file + [ "$username" = root ] && { printf '%s\n' root; return 0; } + sudo_file="$(kpanel_account_sudo_file "$username")" + if [ -f "$sudo_file" ] && [ ! -L "$sudo_file" ] && + grep -Fqx "$username ALL=(ALL:ALL) NOPASSWD:ALL" "$sudo_file"; then + printf '%s\n' passwordless-admin + return 0 + fi + groups="$(id -nG "$username" 2>/dev/null)" || return 1 + case " $groups " in + *' sudo '*|*' wheel '*) printf '%s\n' administrator ;; + *) printf '%s\n' standard ;; + esac +} + +kpanel_account_sshd_effective() { + local config password pubkey root + config="$(kpanel_account_sshd_config)" + [ -f "$config" ] && [ ! -L "$config" ] || return 1 + while read -r key value _; do + case "$key" in + passwordauthentication) password="$value" ;; + pubkeyauthentication) pubkey="$value" ;; + permitrootlogin) root="$value" ;; + esac + done < <(sshd -T -f "$config" 2>/dev/null) + [ "$password" = yes ] || password=no + [ "$pubkey" = yes ] || pubkey=no + case "$root" in + yes) root=enabled ;; + prohibit-password|without-password) root=key-only ;; + no) root=disabled ;; + *) root=custom ;; + esac + printf '%s %s %s\n' "$password" "$pubkey" "$root" +} + +kpanel_account_version() { + local canonical file username auth sudo_file effective version + canonical="$(mktemp /tmp/kejilion-account-version.XXXXXX)" || return 1 + chmod 600 "$canonical" || { rm -f -- "$canonical"; return 1; } + for file in "$(kpanel_account_passwd_file)" "$(kpanel_account_group_file)" \ + "$(kpanel_account_shadow_file)" "$(kpanel_account_gshadow_file)" \ + "$(kpanel_account_sudoers_file)" "$(kpanel_account_sshd_config)" "$(kpanel_account_sshd_fragment)"; do + if [ -e "$file" ]; then + kpanel_account_file_safe "$file" 1048576 8192 || { rm -f -- "$canonical"; return 1; } + printf 'file=%s ' "$file" >> "$canonical" + sha256sum -- "$file" >> "$canonical" || { rm -f -- "$canonical"; return 1; } + else + printf 'file=%s absent\n' "$file" >> "$canonical" + fi + done + effective="$(kpanel_account_sshd_effective)" || { rm -f -- "$canonical"; return 1; } + printf 'sshd=%s\n' "$effective" >> "$canonical" + while IFS=: read -r username _; do + kpanel_account_valid_username "$username" || continue + auth="$(mktemp /tmp/kejilion-account-auth.XXXXXX)" || { rm -f -- "$canonical"; return 1; } + if kpanel_account_capture_keys "$username" "$auth"; then + printf 'keys=%s ' "$username" >> "$canonical" + sha256sum -- "$auth" >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } + else + printf 'keys=%s unreadable\n' "$username" >> "$canonical" + fi + rm -f -- "$auth" + sudo_file="$(kpanel_account_sudo_file "$username")" + if [ -e "$sudo_file" ]; then + kpanel_account_file_safe "$sudo_file" 4096 16 || { rm -f -- "$canonical"; return 1; } + printf 'sudo=%s ' "$username" >> "$canonical" + sha256sum -- "$sudo_file" >> "$canonical" || { rm -f -- "$canonical"; return 1; } + fi + done < "$(kpanel_account_passwd_file)" + version="$(sha256sum -- "$canonical" | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s\n' "$version" +} + +kpanel_account_hex() { + printf '%s' "$1" | od -An -v -tx1 | tr -d ' \n' +} + +kpanel_account_status() { + local version effective password_auth pubkey_auth root_login passwd_file login_defs uid_min=1000 + local username _ uid gid gecos home shell groups password role kind account_record auth key key_id key_type fingerprint comment + local total=0 emitted=0 truncated=false key_count key_temp + kpanel_account_require false awk cat getent grep id mktemp od passwd runuser sha256sum ssh-keygen sshd stat tr wc || return $? + [ "$#" -eq 0 ] || { kpanel_account_error "status 不接受额外参数"; kpanel_account_emit failed; return 2; } + passwd_file="$(kpanel_account_passwd_file)" + kpanel_account_file_safe "$passwd_file" 1048576 8192 || { kpanel_account_emit failed; return 1; } + login_defs="$(kpanel_account_login_defs_file)" + if [ -f "$login_defs" ] && [ ! -L "$login_defs" ]; then + uid_min="$(awk '$1 == "UID_MIN" && $2 ~ /^[0-9]+$/ {print $2; exit}' "$login_defs")" + [[ "$uid_min" =~ ^[0-9]+$ ]] || uid_min=1000 + fi + version="$(kpanel_account_version)" || { kpanel_account_error "无法计算账户资源版本"; kpanel_account_emit failed; return 1; } + effective="$(kpanel_account_sshd_effective)" || { kpanel_account_emit failed "$version"; return 1; } + read -r password_auth pubkey_auth root_login <<< "$effective" + total="$(wc -l < "$passwd_file")" + [ "$total" -le 256 ] || truncated=true + kpanel_account_emit ok "$version" + printf 'KPANEL_ACCOUNT_MANAGEMENT_PASSWORD_AUTH=%s\n' "$password_auth" + printf 'KPANEL_ACCOUNT_MANAGEMENT_PUBKEY_AUTH=%s\n' "$pubkey_auth" + printf 'KPANEL_ACCOUNT_MANAGEMENT_ROOT_LOGIN=%s\n' "$root_login" + printf 'KPANEL_ACCOUNT_MANAGEMENT_TOTAL=%s\n' "$total" + printf 'KPANEL_ACCOUNT_MANAGEMENT_TRUNCATED=%s\n' "$truncated" + while IFS=: read -r username _ uid gid gecos home shell; do + [ "$emitted" -lt 256 ] || break + kpanel_account_valid_username "$username" || continue + groups="$(id -nG "$username" 2>/dev/null | tr ' ' ',')" || groups="" + password="$(kpanel_account_password_status "$username")" || password=unknown + role="$(kpanel_account_role "$username")" || role=standard + if [ "$username" = root ]; then kind=root; elif [ "$uid" -ge "$uid_min" ] 2>/dev/null; then kind=human; else kind=system; fi + key_temp="$(mktemp /tmp/kejilion-account-status-keys.XXXXXX)" || { kpanel_account_emit failed "$version"; return 1; } + key_count=0 + if kpanel_account_capture_keys "$username" "$key_temp"; then + while IFS= read -r key || [ -n "$key" ]; do + [ -n "$key" ] || continue + kpanel_account_key_valid "$key" || continue + [ "$key_count" -lt 32 ] || break + key_id="$(kpanel_account_key_id "$key")" + key_type="${key%% *}" + fingerprint="$(printf '%s\n' "$key" | ssh-keygen -lf /dev/stdin 2>/dev/null | awk '{print $2}')" + comment="$(printf '%s\n' "$key" | awk '{ $1=""; $2=""; sub(/^ */, ""); print }' | tr '\t\r\n' ' ' | cut -c1-128)" + printf 'KPANEL_ACCOUNT_MANAGEMENT_KEY_HEX=%s\n' "$(kpanel_account_hex "$username $key_id $key_type $fingerprint $comment")" + key_count=$((key_count + 1)) + done < "$key_temp" + fi + rm -f -- "$key_temp" + account_record="$username $uid $gid $home $shell $kind $password $role $groups $key_count" + printf 'KPANEL_ACCOUNT_MANAGEMENT_ACCOUNT_HEX=%s\n' "$(kpanel_account_hex "$account_record")" + emitted=$((emitted + 1)) + done < "$passwd_file" +} + +kpanel_account_read_secret() { + local maximum="$1" frame bytes line_feeds + KPANEL_ACCOUNT_SECRET="" + frame="$(mktemp /tmp/kejilion-account-secret.XXXXXX)" || return 1 + chmod 600 "$frame" || { rm -f -- "$frame"; return 1; } + head -c "$((maximum + 2))" > "$frame" 2>/dev/null || { rm -f -- "$frame"; return 1; } + bytes="$(wc -c < "$frame")" || { rm -f -- "$frame"; return 1; } + if [ "$bytes" -lt 2 ] || [ "$bytes" -gt "$((maximum + 1))" ] || + ! LC_ALL=C tr -d '\000' < "$frame" | cmp -s - "$frame" || LC_ALL=C grep -q $'\r' "$frame"; then + rm -f -- "$frame"; return 1 + fi + line_feeds="$(LC_ALL=C tr -cd '\n' < "$frame" | wc -c)" || { rm -f -- "$frame"; return 1; } + [ "$line_feeds" -eq 1 ] && [ "$(tail -c 1 "$frame" | wc -l)" -eq 1 ] || { rm -f -- "$frame"; return 1; } + IFS= read -r KPANEL_ACCOUNT_SECRET < "$frame" || { rm -f -- "$frame"; return 1; } + rm -f -- "$frame" +} + +kpanel_account_snapshot_core() { + local snapshot="$1" file name + for name in passwd group shadow gshadow; do + case "$name" in + passwd) file="$(kpanel_account_passwd_file)" ;; + group) file="$(kpanel_account_group_file)" ;; + shadow) file="$(kpanel_account_shadow_file)" ;; + gshadow) file="$(kpanel_account_gshadow_file)" ;; + esac + [ ! -e "$file" ] || cp -p -- "$file" "$snapshot/$name" || return 1 + done +} + +kpanel_account_restore_core() { + local snapshot="$1" file name + for name in passwd group shadow gshadow; do + [ -f "$snapshot/$name" ] || continue + case "$name" in + passwd) file="$(kpanel_account_passwd_file)" ;; + group) file="$(kpanel_account_group_file)" ;; + shadow) file="$(kpanel_account_shadow_file)" ;; + gshadow) file="$(kpanel_account_gshadow_file)" ;; + esac + cp -p -- "$snapshot/$name" "$file" || return 1 + done +} + +kpanel_account_snapshot_ssh() { + local snapshot="$1" main fragment + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ ! -e "$main" ] || cp -p -- "$main" "$snapshot/sshd_config" || return 1 + if [ -e "$fragment" ]; then cp -p -- "$fragment" "$snapshot/sshd_fragment" || return 1; else : > "$snapshot/sshd_fragment.absent"; fi +} + +kpanel_account_reload_ssh() { + if command -v systemctl >/dev/null 2>&1; then + systemctl reload sshd >/dev/null 2>&1 || systemctl reload ssh >/dev/null 2>&1 + elif command -v service >/dev/null 2>&1; then + service sshd reload >/dev/null 2>&1 || service ssh reload >/dev/null 2>&1 + else + return 1 + fi +} + +kpanel_account_restore_ssh() { + local snapshot="$1" main fragment + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ ! -f "$snapshot/sshd_config" ] || cp -p -- "$snapshot/sshd_config" "$main" || return 1 + if [ -f "$snapshot/sshd_fragment.absent" ]; then rm -f -- "$fragment" || return 1; else cp -p -- "$snapshot/sshd_fragment" "$fragment" || return 1; fi + sshd -t -f "$main" >/dev/null 2>&1 && kpanel_account_reload_ssh +} + +kpanel_account_apply_ssh_policy() { + local password_auth="$1" root_login="$2" main fragment main_temp fragment_temp + main="$(kpanel_account_sshd_config)"; fragment="$(kpanel_account_sshd_fragment)" + [ -f "$main" ] && [ ! -L "$main" ] && [ ! -L "$fragment" ] || return 1 + mkdir -p -- "$(dirname -- "$fragment")" || return 1 + fragment_temp="$(mktemp "$(dirname -- "$fragment")/.00-kejilion-account-management.conf.XXXXXX")" || return 1 + { + printf '%s\n' '# Managed by kejilion.sh account-management protocol v1' + printf 'PubkeyAuthentication yes\n' + [ "$password_auth" = enabled ] && printf 'PasswordAuthentication yes\n' || printf 'PasswordAuthentication no\n' + printf 'KbdInteractiveAuthentication no\nChallengeResponseAuthentication no\nUsePAM yes\n' + case "$root_login" in enabled) printf 'PermitRootLogin yes\n' ;; key-only) printf 'PermitRootLogin prohibit-password\n' ;; disabled) printf 'PermitRootLogin no\n' ;; *) rm -f -- "$fragment_temp"; return 1 ;; esac + } > "$fragment_temp" || { rm -f -- "$fragment_temp"; return 1; } + chmod 600 "$fragment_temp" && chown 0:0 "$fragment_temp" || { rm -f -- "$fragment_temp"; return 1; } + main_temp="$(mktemp "$(dirname -- "$main")/.sshd_config.XXXXXX")" || { rm -f -- "$fragment_temp"; return 1; } + awk ' + BEGIN { inserted=0 } + /^[[:space:]]*Include[[:space:]]+\/etc\/ssh\/sshd_config\.d\/\*\.conf([[:space:]]|$)/ { if (!inserted) { print "Include /etc/ssh/sshd_config.d/*.conf"; inserted=1 }; next } + { if (!inserted && $0 !~ /^[[:space:]]*(#|$)/) { print "Include /etc/ssh/sshd_config.d/*.conf"; inserted=1 }; print } + END { if (!inserted) print "Include /etc/ssh/sshd_config.d/*.conf" } + ' "$main" > "$main_temp" || { rm -f -- "$fragment_temp" "$main_temp"; return 1; } + chmod --reference="$main" "$main_temp" 2>/dev/null || chmod 600 "$main_temp" + chown --reference="$main" "$main_temp" 2>/dev/null || chown 0:0 "$main_temp" + mv -f -- "$fragment_temp" "$fragment" && mv -f -- "$main_temp" "$main" || { rm -f -- "$fragment_temp" "$main_temp"; return 1; } + sshd -t -f "$main" >/dev/null 2>&1 && kpanel_account_reload_ssh +} + +kpanel_account_set_role() { + local username="$1" role="$2" admin_group sudo_file sudo_dir groups + [ "$username" != root ] || return 1 + sudo_file="$(kpanel_account_sudo_file "$username")"; sudo_dir="$(dirname -- "$sudo_file")" + [ ! -L "$sudo_dir" ] && [ ! -L "$sudo_file" ] || return 1 + mkdir -p -- "$sudo_dir" || return 1 + case "$role" in + standard) + gpasswd -d "$username" sudo >/dev/null 2>&1 || true + gpasswd -d "$username" wheel >/dev/null 2>&1 || true + rm -f -- "$sudo_file" || return 1 + ;; + administrator) + admin_group="$(kpanel_account_admin_group)" || return 1 + [ "$(kpanel_account_password_status "$username")" = enabled ] || return 2 + usermod -a -G "$admin_group" "$username" || return 1 + rm -f -- "$sudo_file" || return 1 + ;; + passwordless-admin) + admin_group="$(kpanel_account_admin_group)" || return 1 + usermod -a -G "$admin_group" "$username" || return 1 + printf '%s ALL=(ALL:ALL) NOPASSWD:ALL\n' "$username" > "$sudo_file" || return 1 + chmod 440 "$sudo_file" && chown 0:0 "$sudo_file" || return 1 + visudo -cf "$sudo_file" >/dev/null 2>&1 || return 1 + ;; + *) return 2 ;; + esac + [ "$(kpanel_account_role "$username")" = "$role" ] +} + +kpanel_account_create() { + local username="$1" role="$2" credential="$3" secret="$4" + local desired sudo_file LC_ALL=C + kpanel_account_valid_username "$username" && [ "$username" != root ] && ! kpanel_account_exists "$username" || return 2 + case "$role" in standard|administrator|passwordless-admin) ;; *) return 2 ;; esac + case "$credential" in + password) [ "${#secret}" -ge 8 ] && [ "${#secret}" -le 256 ] || return 2 ;; + key) kpanel_account_key_valid "$secret" || return 2; [ "$role" != administrator ] || return 2 ;; + *) return 2 ;; + esac + useradd -m -s /bin/bash "$username" || return 1 + if [ "$credential" = password ]; then + if ! printf '%s:%s\n' "$username" "$secret" | chpasswd; then + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + else + desired="$(mktemp /tmp/kejilion-account-create-key.XXXXXX)" || { + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + } + printf '%s\n' "$secret" > "$desired" + if ! kpanel_account_install_keys "$username" "$desired"; then + rm -f -- "$desired" + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + rm -f -- "$desired" + if ! passwd -l "$username" >/dev/null 2>&1; then + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi + fi + if ! kpanel_account_set_role "$username" "$role"; then + sudo_file="$(kpanel_account_sudo_file "$username")" + rm -f -- "$sudo_file" >/dev/null 2>&1 || true + userdel -r "$username" >/dev/null 2>&1 || true + return 1 + fi +} + +kpanel_account_write_failure() { + local snapshot="$1" original_version="$2" message="$3" restore_core="${4:-false}" restore_ssh="${5:-false}" + local version recovery restore_ok=true + kpanel_account_error "$message" + [ "$restore_core" != true ] || kpanel_account_restore_core "$snapshot" || restore_ok=false + [ "$restore_ssh" != true ] || kpanel_account_restore_ssh "$snapshot" || restore_ok=false + version="$(kpanel_account_version 2>/dev/null || true)" + if [ "$restore_ok" = true ] && [ "$version" = "$original_version" ]; then + rm -rf -- "$snapshot" + kpanel_account_emit failed "$version" + return 1 + fi + if recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" account-management)"; then + kpanel_account_emit rollback-failed "$version" "$recovery" + else + kpanel_account_emit rollback-failed "$version" + fi + return 1 +} + +kpanel_account_action() { + local action="$1" expected="$2" current snapshot final recovery username role credential marker secret="" changed=true + local LC_ALL=C + shift 2 + kpanel_system_resource_valid_version "$expected" || { kpanel_account_emit failed; return 2; } + current="$(kpanel_account_version)" || { kpanel_account_emit failed; return 1; } + if [ "$current" != "$expected" ]; then kpanel_account_emit conflict "$current"; return 2; fi + snapshot="$(kpanel_system_resource_tempdir account-management)" || { kpanel_account_emit failed "$current"; return 1; } + case "$action" in + create) + [ "$#" -eq 4 ] && [ "$4" = --secret-stdin ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; role="$2"; credential="$3" + [ "$credential" = password ] && marker=256 || marker=4096 + kpanel_account_read_secret "$marker" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_create "$username" "$role" "$credential" "$secret"; then kpanel_account_write_failure "$snapshot" "$current" "创建账户失败,已尝试恢复账户数据库" true false; return $?; fi + ;; + set-password) + [ "$#" -eq 2 ] && [ "$2" = --secret-stdin ] && kpanel_account_exists "$1" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; kpanel_account_read_secret 256 || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + [ "${#KPANEL_ACCOUNT_SECRET}" -ge 8 ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! printf '%s:%s\n' "$username" "$KPANEL_ACCOUNT_SECRET" | chpasswd; then kpanel_account_write_failure "$snapshot" "$current" "修改密码失败,已尝试恢复" true false; return $?; fi + ;; + add-key) + [ "$#" -eq 2 ] && [ "$2" = --secret-stdin ] && kpanel_account_exists "$1" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; kpanel_account_read_secret 4096 || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; }; secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_key_valid "$secret" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + local keys desired + keys="$snapshot/authorized_keys"; desired="$snapshot/authorized_keys.desired" + kpanel_account_capture_keys "$username" "$keys" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if grep -Fqx "$secret" "$keys"; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + cp -- "$keys" "$desired" && printf '%s\n' "$secret" >> "$desired" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_install_keys "$username" "$desired"; then + kpanel_account_install_keys "$username" "$keys" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "添加 SSH 公钥失败,已尝试恢复" false false + return $? + fi + ;; + delete-key) + [ "$#" -eq 2 ] && kpanel_account_exists "$1" && [[ "$2" =~ ^[0-9a-f]{64}$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; local key_id="$2" keys="$snapshot/authorized_keys" desired="$snapshot/authorized_keys.desired" line found=false + kpanel_account_capture_keys "$username" "$keys" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + : > "$desired" + while IFS= read -r line || [ -n "$line" ]; do if [ -n "$line" ] && [ "$(kpanel_account_key_id "$line")" = "$key_id" ]; then found=true; else printf '%s\n' "$line" >> "$desired"; fi; done < "$keys" + if [ "$found" = false ]; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + if ! kpanel_account_install_keys "$username" "$desired"; then + kpanel_account_install_keys "$username" "$keys" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "删除 SSH 公钥失败,已尝试恢复" false false + return $? + fi + ;; + set-role) + [ "$#" -eq 2 ] && kpanel_account_exists "$1" && [ "$1" != root ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; role="$2"; [ "$(kpanel_account_role "$username")" != "$role" ] || { rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; } + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + local sudo_file; sudo_file="$(kpanel_account_sudo_file "$username")"; if [ -e "$sudo_file" ]; then cp -p -- "$sudo_file" "$snapshot/sudo" || { rm -rf -- "$snapshot"; return 1; }; else : > "$snapshot/sudo.absent"; fi + if ! kpanel_account_set_role "$username" "$role"; then + if [ -f "$snapshot/sudo.absent" ]; then rm -f -- "$sudo_file" >/dev/null 2>&1 || true; else cp -p -- "$snapshot/sudo" "$sudo_file" >/dev/null 2>&1 || true; fi + kpanel_account_write_failure "$snapshot" "$current" "调整账户角色失败,已尝试恢复" true false + return $? + fi + ;; + set-ssh-policy) + [ "$#" -eq 2 ] && [[ "$1" =~ ^(enabled|disabled)$ ]] && [[ "$2" =~ ^(enabled|key-only|disabled)$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! kpanel_account_apply_ssh_policy "$1" "$2"; then kpanel_account_write_failure "$snapshot" "$current" "SSH 登录策略应用失败,已尝试恢复" false true; return $?; fi + ;; + disable-root) + [ "$#" -eq 0 ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + if [ "$(kpanel_account_password_status root)" = locked ] && [ "$(kpanel_account_sshd_effective | awk '{print $3}')" = disabled ]; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + kpanel_account_snapshot_core "$snapshot" && kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if ! passwd -l root >/dev/null 2>&1 || ! kpanel_account_apply_ssh_policy "$(kpanel_account_sshd_effective | awk '{print $1 == "yes" ? "enabled" : "disabled"}')" disabled; then kpanel_account_write_failure "$snapshot" "$current" "禁用 Root 失败,已尝试恢复" true true; return $?; fi + ;; + create-admin-disable-root) + [ "$#" -eq 3 ] && [ "$3" = --secret-stdin ] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; credential="$2"; [ "$credential" = password ] && marker=256 || marker=4096 + kpanel_account_read_secret "$marker" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; }; secret="$KPANEL_ACCOUNT_SECRET" + kpanel_account_snapshot_core "$snapshot" && kpanel_account_snapshot_ssh "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + role=administrator; [ "$credential" = key ] && role=passwordless-admin + if ! kpanel_account_create "$username" "$role" "$credential" "$secret"; then + kpanel_account_write_failure "$snapshot" "$current" "替代管理员创建失败,已尝试恢复" true true + return $? + fi + if ! passwd -l root >/dev/null 2>&1 || + ! kpanel_account_apply_ssh_policy "$([ "$credential" = password ] && printf enabled || printf disabled)" disabled; then + rm -f -- "$(kpanel_account_sudo_file "$username")" >/dev/null 2>&1 || true + userdel -r "$username" >/dev/null 2>&1 || true + kpanel_account_write_failure "$snapshot" "$current" "Root 安全迁移失败,已尝试恢复" true true + return $? + fi + ;; + delete) + [ "$#" -eq 2 ] && kpanel_account_valid_username "$1" && [ "$1" != root ] && [[ "$2" =~ ^(true|false)$ ]] || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2; } + username="$1"; if ! kpanel_account_exists "$username"; then rm -rf -- "$snapshot"; kpanel_account_emit unchanged "$current"; return 0; fi + local sudo_file; sudo_file="$(kpanel_account_sudo_file "$username")" + kpanel_account_snapshot_core "$snapshot" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; } + if [ -e "$sudo_file" ]; then cp -p -- "$sudo_file" "$snapshot/sudo" || { rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 1; }; else : > "$snapshot/sudo.absent"; fi + if ! { if [ "$2" = true ]; then userdel -r "$username"; else userdel "$username"; fi; }; then + if [ "$2" = false ]; then + kpanel_account_write_failure "$snapshot" "$current" "删除账户失败,已尝试恢复账户数据库" true false + return $? + fi + kpanel_account_restore_core "$snapshot" >/dev/null 2>&1 || true + final="$(kpanel_account_version 2>/dev/null || true)" + recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" account-management 2>/dev/null || true)" + kpanel_account_error "删除账户及主目录失败,主目录可能已被部分删除,需要人工检查" + kpanel_account_emit needs-attention "$final" "$recovery" + return 1 + fi + rm -f -- "$sudo_file" || { rm -rf -- "$snapshot"; kpanel_account_emit needs-attention "$(kpanel_account_version 2>/dev/null || true)"; return 1; } + ;; + *) rm -rf -- "$snapshot"; kpanel_account_emit failed "$current"; return 2 ;; + esac + final="$(kpanel_account_version)" || { rm -rf -- "$snapshot"; kpanel_account_emit needs-attention; return 1; } + [ "$final" != "$current" ] || changed=false + rm -rf -- "$snapshot" + [ "$changed" = true ] && kpanel_account_emit applied "$final" || kpanel_account_emit unchanged "$final" +} + +kpanel_account_run_locked() ( + local action="$1" expected="$2" lock_file + shift 2 + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_account_emit failed; return 1; } + exec 9<>"$lock_file" || { kpanel_account_emit failed; return 1; } + kpanel_system_resource_lock_path_secure "$lock_file" file 600 || { kpanel_account_emit failed; return 1; } + if ! flock -w 5 -x 9 >/dev/null 2>&1; then kpanel_account_emit conflict "$(kpanel_account_version 2>/dev/null || true)"; return 2; fi + kpanel_account_action "$action" "$expected" "$@" +) + +kpanel_account_dispatch() { + local action="${1:-}" + [ "$#" -ge 1 ] || { kpanel_account_emit failed; return 2; } + shift + case "$action" in + status) kpanel_account_status "$@" ;; + create|set-password|add-key|delete-key|set-role|set-ssh-policy|disable-root|create-admin-disable-root|delete) + [ "$#" -ge 1 ] || { kpanel_account_emit failed; return 2; } + local expected="$1"; shift + kpanel_account_require true awk cat chpasswd cmp cut getent gpasswd grep head id mkdir mktemp od passwd runuser sed sha256sum ssh-keygen sshd stat tail tr useradd userdel usermod visudo wc || { kpanel_account_emit failed; return $?; } + kpanel_account_run_locked "$action" "$expected" "$@" + ;; + *) kpanel_account_error "不支持的 account-management 动作"; kpanel_account_emit failed; return 2 ;; + esac +} + +# KPanel account management protocol end + + log_menu() { send_stats "系统日志管理工具" @@ -25009,25 +26170,25 @@ EOF read -e -p "请输入流量重置日期(默认每月1日重置): " cz_day cz_day=${cz_day:-1} - cd ~ - curl -Ss -o ~/Limiting_Shut_down.sh ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/Limiting_Shut_down1.sh - chmod +x ~/Limiting_Shut_down.sh - sed -i "s/110/$rx_threshold_gb/g" ~/Limiting_Shut_down.sh - sed -i "s/120/$tx_threshold_gb/g" ~/Limiting_Shut_down.sh check_crontab_installed - crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - - (crontab -l ; echo "* * * * * ~/Limiting_Shut_down.sh") | crontab - > /dev/null 2>&1 - crontab -l | grep -v 'reboot' | crontab - - (crontab -l ; echo "0 1 $cz_day * * reboot") | crontab - > /dev/null 2>&1 - echo "限流关机已设置" - send_stats "限流关机已设置" + local traffic_version + traffic_version="$(kpanel_network_operations_traffic_version)" + if KJ_NETWORK_OPERATIONS_NONINTERACTIVE=1 kpanel_network_operations_traffic_run_locked enable "$traffic_version" "$rx_threshold_gb" "$tx_threshold_gb" "$cz_day"; then + echo "限流关机已设置" + send_stats "限流关机已设置" + else + echo "限流关机设置失败,请根据上方错误检查配置" + fi ;; 2) check_crontab_installed - crontab -l | grep -v '~/Limiting_Shut_down.sh' | crontab - - crontab -l | grep -v 'reboot' | crontab - - rm ~/Limiting_Shut_down.sh - echo "已关闭限流关机功能" + local traffic_version + traffic_version="$(kpanel_network_operations_traffic_version)" + if KJ_NETWORK_OPERATIONS_NONINTERACTIVE=1 kpanel_network_operations_traffic_run_locked disable "$traffic_version"; then + echo "已关闭限流关机功能" + else + echo "关闭限流关机失败,请根据上方错误检查配置" + fi ;; *) break @@ -26405,8 +27566,14 @@ else elif [ "${1:-}" = "system-resource" ]; then shift kpanel_system_resource_dispatch "$@" + elif [ "${1:-}" = "network-operations" ]; then + shift + kpanel_network_operations_dispatch "$@" + elif [ "${1:-}" = "account-management" ]; then + shift + kpanel_account_dispatch "$@" else - echo "用法: k kpanel node join <授权> | status | update | uninstall;或 k kpanel system-resource ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/tests/test_kpanel_account_management_noninteractive_smoke.sh b/tests/test_kpanel_account_management_noninteractive_smoke.sh new file mode 100644 index 000000000..6da7340c4 --- /dev/null +++ b/tests/test_kpanel_account_management_noninteractive_smoke.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" +temporary="$(mktemp -d)" +trap 'rm -rf -- "${temporary}"' EXIT + +fail() { + echo "account-management smoke failed: $*" >&2 + exit 1 +} + +normalized="${temporary}/kejilion.sh" +adapter="${temporary}/adapter.sh" +tr -d '\r' < "${script_path}" > "${normalized}" +awk ' + /^# KPanel account management protocol start$/ { capture=1; next } + /^# KPanel account management protocol end$/ { capture=0 } + capture { print } +' "${normalized}" > "${adapter}" + +[ -s "${adapter}" ] || fail "adapter block was not found" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_PROTOCOL_VERSION="1"' "${adapter}" || fail "protocol v1 marker is missing" +[ "$(grep -Fxc 'KPANEL_ACCOUNT_MANAGEMENT_PROTOCOL_VERSION="1"' "${adapter}")" -eq 1 ] || fail "protocol marker is not unique" +grep -F '[ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] ||' "${normalized}" >/dev/null || fail "startup guard is missing" +grep -F 'kpanel_account_dispatch "$@"' "${normalized}" >/dev/null || fail "CLI dispatch is missing" +grep -F -- '--secret-stdin' "${adapter}" >/dev/null || fail "bounded stdin marker is missing" +if grep -E 'chpasswd[^|]*\$KPANEL_ACCOUNT_SECRET|useradd[^|]*\$KPANEL_ACCOUNT_SECRET' "${adapter}" >/dev/null; then + fail "secret is passed as an external command argument" +fi + +# shellcheck disable=SC1090 +source "${adapter}" + +kpanel_account_valid_username operator || fail "valid username was rejected" +if kpanel_account_valid_username 'root;reboot'; then fail "injected username was accepted"; fi +if kpanel_account_valid_username 'user$'; then fail "machine account suffix was accepted"; fi + +kpanel_account_read_secret 256 <<< 'correct horse battery staple' || fail "valid stdin secret frame was rejected" +[ "${KPANEL_ACCOUNT_SECRET}" = 'correct horse battery staple' ] || fail "stdin secret was changed" +if kpanel_account_read_secret 256 <<< $'first\nsecond'; then fail "multiline secret was accepted"; fi +if kpanel_account_read_secret 8 <<< '123456789'; then fail "oversized secret was accepted"; fi + +ssh-keygen -q -t ed25519 -N '' -C laptop -f "${temporary}/id_ed25519" || fail "could not build key fixture" +valid_key="$(cat "${temporary}/id_ed25519.pub")" +kpanel_account_key_valid "${valid_key}" || fail "valid ed25519 key was rejected" +if kpanel_account_key_valid 'command="reboot" ssh-ed25519 AAAA'; then fail "authorized_keys options were accepted as a raw key"; fi + +# A standard account does not need sudo/wheel to exist. Minimal servers may +# legitimately have neither group until an administrator role is requested. +kpanel_account_sudo_file() { printf '%s\n' "${temporary}/90-kejilion-operator"; } +kpanel_account_admin_group() { return 1; } +kpanel_account_role() { printf '%s\n' standard; } +gpasswd() { return 0; } +kpanel_account_set_role operator standard || fail "standard role incorrectly required an administrator group" + +fixture_expected="$(printf 'a%.0s' {1..64})" +fixture_final="$(printf 'b%.0s' {1..64})" +capture="${temporary}/create.capture" +version_calls="${temporary}/version.calls" +fixture_lock_file="${temporary}/system-resource.lock" +: > "${fixture_lock_file}" +chmod 600 "${fixture_lock_file}" + +kpanel_account_require() { return 0; } +kpanel_system_resource_prepare_lock_file() { printf '%s\n' "${fixture_lock_file}"; } +kpanel_system_resource_lock_path_secure() { return 0; } +# Git for Windows cannot flock a Bash file descriptor. The production lock +# implementation is covered by the system-resource root smoke; this fixture +# only verifies the account dispatcher uses the fixed lock call. +flock() { [ "$*" = "-w 5 -x 9" ]; } +kpanel_system_resource_valid_version() { [[ "$1" =~ ^[0-9a-f]{64}$ ]]; } +kpanel_system_resource_tempdir() { mktemp -d "${temporary}/snapshot.XXXXXX"; } +kpanel_account_snapshot_core() { return 0; } +kpanel_account_create() { + printf 'username=%s\nrole=%s\ncredential=%s\nsecret=%s\n' "$1" "$2" "$3" "$4" > "${capture}" +} +kpanel_account_version() { + local count=0 + [ ! -f "${version_calls}" ] || count="$(cat "${version_calls}")" + count=$((count + 1)) + printf '%s\n' "${count}" > "${version_calls}" + if [ "${count}" -eq 1 ]; then printf '%s\n' "${fixture_expected}"; else printf '%s\n' "${fixture_final}"; fi +} + +receipt="$(printf '%s\n' 'correct horse battery staple' | kpanel_account_dispatch create "${fixture_expected}" operator administrator password --secret-stdin)" || fail "create transaction failed" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_STATUS=applied' <<< "${receipt}" || fail "create did not return applied" +grep -Fqx "KPANEL_ACCOUNT_MANAGEMENT_VERSION=${fixture_final}" <<< "${receipt}" || fail "create final version is missing" +grep -Fqx 'secret=correct horse battery staple' "${capture}" || fail "stdin secret did not reach the fixed action" +if grep -F 'correct horse battery staple' <<< "${receipt}" >/dev/null; then fail "secret leaked into receipt"; fi + +# The guided Root migration must remove the newly created account and restore +# both account files and SSH policy if the second phase fails. +: > "${version_calls}" +printf '0\n' > "${version_calls}" +restore_capture="${temporary}/restore.capture" +cleanup_capture="${temporary}/cleanup.capture" +kpanel_account_version() { printf '%s\n' "${fixture_expected}"; } +kpanel_account_snapshot_ssh() { return 0; } +kpanel_account_restore_core() { printf 'core\n' >> "${restore_capture}"; } +kpanel_account_restore_ssh() { printf 'ssh\n' >> "${restore_capture}"; } +kpanel_account_create() { return 0; } +kpanel_account_apply_ssh_policy() { return 1; } +kpanel_account_sudo_file() { printf '%s\n' "${temporary}/90-kejilion-operator"; } +passwd() { return 0; } +userdel() { printf '%s\n' "$*" > "${cleanup_capture}"; } +set +e +failure_receipt="$(printf '%s\n' "${valid_key}" | kpanel_account_dispatch create-admin-disable-root "${fixture_expected}" operator key --secret-stdin)" +failure_rc=$? +set -e +[ "${failure_rc}" -ne 0 ] || fail "failed Root migration returned success" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_STATUS=failed' <<< "${failure_receipt}" || fail "failed Root migration did not report rollback" +grep -Fqx core "${restore_capture}" && grep -Fqx ssh "${restore_capture}" || fail "Root migration did not restore both resources" +grep -Fqx -- '-r operator' "${cleanup_capture}" || fail "Root migration did not remove the replacement account" + +# A failed userdel -r cannot promise that the home directory is intact. The +# adapter must preserve the account snapshot and report needs-attention. +kpanel_account_exists() { return 0; } +kpanel_account_snapshot_core() { return 0; } +kpanel_account_restore_core() { return 0; } +kpanel_account_version() { printf '%s\n' "${fixture_expected}"; } +kpanel_system_resource_persist_recovery_snapshot() { printf '%s\n' '/var/lib/kejilion-panel/system/recovery/system-resource/20260811T000000Z-account-management.ABC123'; } +userdel() { return 1; } +set +e +delete_receipt="$(kpanel_account_dispatch delete "${fixture_expected}" operator true)" +delete_rc=$? +set -e +[ "${delete_rc}" -ne 0 ] || fail "failed home removal returned success" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_STATUS=needs-attention' <<< "${delete_receipt}" || fail "partial home removal was reported as rolled back" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_BACKUP=/var/lib/kejilion-panel/system/recovery/system-resource/20260811T000000Z-account-management.ABC123' <<< "${delete_receipt}" || fail "partial home removal did not preserve its recovery snapshot" + +echo "account-management smoke passed" diff --git a/tests/test_kpanel_network_operations_noninteractive_smoke.sh b/tests/test_kpanel_network_operations_noninteractive_smoke.sh new file mode 100644 index 000000000..f1754a631 --- /dev/null +++ b/tests/test_kpanel_network_operations_noninteractive_smoke.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +script_path="${project_root}/kejilion.sh" +test_root="$(mktemp -d)" +trap 'rm -rf -- "${test_root}"' EXIT + +fail() { + echo "network-operations smoke failed: $*" >&2 + exit 1 +} + +adapter_file="${test_root}/adapter.sh" +{ + sed 's/\r$//' "${script_path}" | sed -n '/^# KPanel system resource protocol start$/,/^# KPanel system resource protocol end$/p' + sed 's/\r$//' "${script_path}" | sed -n '/^# KPanel network operations protocol start$/,/^# KPanel network operations protocol end$/p' +} > "${adapter_file}" + +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1"' "${adapter_file}" || + fail "protocol v1 marker is missing" +[ "$(grep -Fxc 'KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1"' "${adapter_file}")" -eq 1 ] || + fail "protocol v1 marker must be unique" + +# shellcheck disable=SC1090 +source "${adapter_file}" + +unset KJ_NETWORK_OPERATIONS_NONINTERACTIVE || true +set +e +guard_output="$(kpanel_network_operations_dispatch port-usage list 2>/dev/null)" +guard_rc=$? +set -e +[ "${guard_rc}" -eq 2 ] || fail "protocol guard did not reject an unguarded call" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=failed' <<< "${guard_output}" || fail "protocol guard receipt missing" + +mock_bin="${test_root}/bin" +mkdir -p "${mock_bin}" +mock_crontab="${test_root}/crontab" +mock_ss="${test_root}/ss.output" +traffic_script="${test_root}/Limiting_Shut_down.sh" +net_dev="${test_root}/net.dev" +recovery_root="${test_root}/state" +export MOCK_CRONTAB="${mock_crontab}" MOCK_SS="${mock_ss}" +export MOCK_CRONTAB_FAIL_ONCE="${test_root}/crontab.fail-once" + +cat > "${mock_bin}/crontab" <<'MOCK' +#!/usr/bin/env bash +set -euo pipefail +case "${1:-}" in + -l) + if [ -f "${MOCK_CRONTAB}" ]; then cat "${MOCK_CRONTAB}"; else echo "no crontab for root" >&2; exit 1; fi + ;; + -r) rm -f -- "${MOCK_CRONTAB}" ;; + '') exit 2 ;; + *) + if [ -e "${MOCK_CRONTAB_FAIL_ONCE}" ]; then rm -f -- "${MOCK_CRONTAB_FAIL_ONCE}"; exit 1; fi + cp -- "$1" "${MOCK_CRONTAB}" + ;; +esac +MOCK +cat > "${mock_bin}/ss" <<'MOCK' +#!/usr/bin/env bash +cat "${MOCK_SS}" +MOCK +chmod +x "${mock_bin}/crontab" "${mock_bin}/ss" +PATH="${mock_bin}:${PATH}" + +kpanel_network_operations_script_file() { printf '%s\n' "${traffic_script}"; } +kpanel_network_operations_net_dev_file() { printf '%s\n' "${net_dev}"; } +kpanel_system_resource_state_root() { printf '%s\n' "${recovery_root}"; } +kpanel_system_resource_lock_owner_uid() { id -u; } +kpanel_system_resource_tempdir() { + local resource="$1" directory + directory="$(mktemp -d "${test_root}/${resource}.XXXXXX")" + chmod 700 "${directory}" + printf '%s\n' "${directory}" +} +chown() { return 0; } +kpanel_network_operations_require() { return 0; } + +{ + for index in $(seq 1 514); do + printf 'tcp LISTEN 0 4096 127.0.0.1:%s 0.0.0.0:* users:(("demo",pid=%s,fd=3))\n' "$((8000 + index))" "$index" + done +} > "${mock_ss}" + +port_output="$(kpanel_network_operations_port_usage)" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=ok' <<< "${port_output}" || fail "port list status missing" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_TOTAL=514' <<< "${port_output}" || fail "port total is wrong" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_TRUNCATED=true' <<< "${port_output}" || fail "port truncation missing" +[ "$(grep -Fc 'KPANEL_NETWORK_OPERATIONS_PORT_HEX=' <<< "${port_output}")" -eq 512 ] || fail "port list was not bounded" +first_hex="$(sed -n '0,/^KPANEL_NETWORK_OPERATIONS_PORT_HEX=/{s/^KPANEL_NETWORK_OPERATIONS_PORT_HEX=//p}' <<< "${port_output}")" +[ "$(printf '%s' "${first_hex}" | xxd -r -p)" = 'tcp LISTEN 0 4096 127.0.0.1:8001 0.0.0.0:* users:(("demo",pid=1,fd=3))' ] || + fail "port line encoding changed content" + +cat > "${net_dev}" <<'NET' +Inter-| Receive | Transmit + face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + lo: 999 0 0 0 0 0 0 0 888 0 0 0 0 0 0 0 +eth0: 1073741824 0 0 0 0 0 0 0 2147483648 0 0 0 0 0 0 0 +NET +printf '15 4 * * * reboot --reason unrelated\n0 2 1 * * reboot\n' > "${mock_crontab}" + +status_output="$(kpanel_network_operations_traffic_status)" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_HEALTH=disabled' <<< "${status_output}" || fail "disabled status is wrong" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_RX_BYTES=1073741824' <<< "${status_output}" || fail "rx counter is wrong" +version0="$(sed -n 's/^KPANEL_NETWORK_OPERATIONS_VERSION=//p' <<< "${status_output}")" + +enable_output="$(kpanel_network_operations_traffic_action enable "${version0}" 100 200 5)" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=applied' <<< "${enable_output}" || fail "enable was not applied" +grep -Fqx 'rx_threshold_gb=100' "${traffic_script}" || fail "rx threshold was not written" +grep -Fqx 'tx_threshold_gb=200' "${traffic_script}" || fail "tx threshold was not written" +grep -Fqx '15 4 * * * reboot --reason unrelated' "${mock_crontab}" || fail "unrelated reboot cron was deleted" +grep -Fqx '0 2 1 * * reboot' "${mock_crontab}" || fail "ambiguous legacy reboot cron was deleted" +grep -Fqx '0 1 5 * * reboot' "${mock_crontab}" || fail "managed reset cron is missing" + +status_output="$(kpanel_network_operations_traffic_status)" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_HEALTH=ready' <<< "${status_output}" || fail "enabled status is not ready" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_RESET_DAY=5' <<< "${status_output}" || fail "reset day is wrong" +version1="$(sed -n 's/^KPANEL_NETWORK_OPERATIONS_VERSION=//p' <<< "${status_output}")" + +set +e +conflict_output="$(kpanel_network_operations_traffic_action disable "${version0}" 2>/dev/null)" +conflict_rc=$? +set -e +[ "${conflict_rc}" -eq 2 ] || fail "stale write did not return conflict" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=conflict' <<< "${conflict_output}" || fail "conflict receipt missing" + +unchanged_output="$(kpanel_network_operations_traffic_action enable "${version1}" 100 200 5)" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=unchanged' <<< "${unchanged_output}" || fail "idempotent enable changed state" +version1="$(sed -n 's/^KPANEL_NETWORK_OPERATIONS_VERSION=//p' <<< "${unchanged_output}")" + +disable_output="$(kpanel_network_operations_traffic_action disable "${version1}")" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=applied' <<< "${disable_output}" || fail "disable was not applied" +[ ! -e "${traffic_script}" ] || fail "managed script remains after disable" +grep -Fqx '15 4 * * * reboot --reason unrelated' "${mock_crontab}" || fail "disable deleted unrelated reboot cron" +grep -Fqx '0 2 1 * * reboot' "${mock_crontab}" || fail "disable deleted ambiguous reboot cron" +if grep -Fq 'kejilion traffic shutdown' "${mock_crontab}"; then fail "managed cron block remains after disable"; fi + +version2="$(kpanel_network_operations_traffic_version)" +touch "${MOCK_CRONTAB_FAIL_ONCE}" +set +e +rollback_output="$(kpanel_network_operations_traffic_action enable "${version2}" 300 400 9 2>/dev/null)" +rollback_rc=$? +set -e +[ "${rollback_rc}" -eq 1 ] || fail "failed crontab install did not report a rolled-back failure" +grep -Fqx 'KPANEL_NETWORK_OPERATIONS_STATUS=failed' <<< "${rollback_output}" || fail "rollback receipt missing" +[ ! -e "${traffic_script}" ] || fail "failed enable did not roll back the managed script" +[ "$(kpanel_network_operations_traffic_version)" = "${version2}" ] || fail "failed enable did not restore the resource version" +grep -Fqx '15 4 * * * reboot --reason unrelated' "${mock_crontab}" || fail "rollback did not restore unrelated cron" + +printf '%s\n' 'kpanel_network_operations_noninteractive_smoke=pass' From a01067d63676b36c6067275d03a4827a7cb142bd Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 11 Aug 2026 01:56:30 +0800 Subject: [PATCH 1261/1285] fix(account): stabilize management resource versions --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- ...account_management_noninteractive_smoke.sh | 23 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 85171c3e1..b53beaded 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -24679,7 +24679,7 @@ kpanel_account_version() { auth="$(mktemp /tmp/kejilion-account-auth.XXXXXX)" || { rm -f -- "$canonical"; return 1; } if kpanel_account_capture_keys "$username" "$auth"; then printf 'keys=%s ' "$username" >> "$canonical" - sha256sum -- "$auth" >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } + sha256sum -- "$auth" | awk '{print $1}' >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } else printf 'keys=%s unreadable\n' "$username" >> "$canonical" fi diff --git a/kejilion.sh b/kejilion.sh index 4debb112a..22f1004fe 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -24679,7 +24679,7 @@ kpanel_account_version() { auth="$(mktemp /tmp/kejilion-account-auth.XXXXXX)" || { rm -f -- "$canonical"; return 1; } if kpanel_account_capture_keys "$username" "$auth"; then printf 'keys=%s ' "$username" >> "$canonical" - sha256sum -- "$auth" >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } + sha256sum -- "$auth" | awk '{print $1}' >> "$canonical" || { rm -f -- "$canonical" "$auth"; return 1; } else printf 'keys=%s unreadable\n' "$username" >> "$canonical" fi diff --git a/tests/test_kpanel_account_management_noninteractive_smoke.sh b/tests/test_kpanel_account_management_noninteractive_smoke.sh index 6da7340c4..2bb367244 100644 --- a/tests/test_kpanel_account_management_noninteractive_smoke.sh +++ b/tests/test_kpanel_account_management_noninteractive_smoke.sh @@ -47,6 +47,29 @@ valid_key="$(cat "${temporary}/id_ed25519.pub")" kpanel_account_key_valid "${valid_key}" || fail "valid ed25519 key was rejected" if kpanel_account_key_valid 'command="reboot" ssh-ed25519 AAAA'; then fail "authorized_keys options were accepted as a raw key"; fi +# Resource versions must hash key content, not the random mktemp filename used +# while capturing it. Two reads of unchanged account state must be identical. +version_fixture="${temporary}/version-fixture" +mkdir -p "${version_fixture}" +for name in passwd group shadow gshadow sudoers sshd_config; do + printf '%s\n' "${name}-fixture" > "${version_fixture}/${name}" +done +printf 'root:x:0:0:root:/root:/bin/bash\noperator:x:1000:1000::/home/operator:/bin/bash\n' > "${version_fixture}/passwd" +kpanel_account_passwd_file() { printf '%s\n' "${version_fixture}/passwd"; } +kpanel_account_group_file() { printf '%s\n' "${version_fixture}/group"; } +kpanel_account_shadow_file() { printf '%s\n' "${version_fixture}/shadow"; } +kpanel_account_gshadow_file() { printf '%s\n' "${version_fixture}/gshadow"; } +kpanel_account_sudoers_file() { printf '%s\n' "${version_fixture}/sudoers"; } +kpanel_account_sshd_config() { printf '%s\n' "${version_fixture}/sshd_config"; } +kpanel_account_sshd_fragment() { printf '%s\n' "${version_fixture}/sshd_fragment"; } +kpanel_account_file_safe() { return 0; } +kpanel_account_sshd_effective() { printf '%s\n' 'yes yes enabled'; } +kpanel_account_capture_keys() { printf '%s\n' "${valid_key}" > "$2"; } +kpanel_account_sudo_file() { printf '%s/90-kejilion-%s\n' "${version_fixture}" "$1"; } +stable_version_a="$(kpanel_account_version)" +stable_version_b="$(kpanel_account_version)" +[ "${stable_version_a}" = "${stable_version_b}" ] || fail "unchanged account state produced unstable resource versions" + # A standard account does not need sudo/wheel to exist. Minimal servers may # legitimately have neither group until an administrator role is requested. kpanel_account_sudo_file() { printf '%s\n' "${temporary}/90-kejilion-operator"; } From d82f043aa95064235b2bfe370e25e141cd75c321 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 11 Aug 2026 03:13:06 +0800 Subject: [PATCH 1262/1285] fix(account): count only protocol usernames --- cn/kejilion.sh | 5 ++++- kejilion.sh | 5 ++++- ...nel_account_management_noninteractive_smoke.sh | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index b53beaded..6ee294b9e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -24717,7 +24717,10 @@ kpanel_account_status() { version="$(kpanel_account_version)" || { kpanel_account_error "无法计算账户资源版本"; kpanel_account_emit failed; return 1; } effective="$(kpanel_account_sshd_effective)" || { kpanel_account_emit failed "$version"; return 1; } read -r password_auth pubkey_auth root_login <<< "$effective" - total="$(wc -l < "$passwd_file")" + while IFS=: read -r username _; do + kpanel_account_valid_username "$username" || continue + total=$((total + 1)) + done < "$passwd_file" [ "$total" -le 256 ] || truncated=true kpanel_account_emit ok "$version" printf 'KPANEL_ACCOUNT_MANAGEMENT_PASSWORD_AUTH=%s\n' "$password_auth" diff --git a/kejilion.sh b/kejilion.sh index 22f1004fe..959053a67 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -24717,7 +24717,10 @@ kpanel_account_status() { version="$(kpanel_account_version)" || { kpanel_account_error "无法计算账户资源版本"; kpanel_account_emit failed; return 1; } effective="$(kpanel_account_sshd_effective)" || { kpanel_account_emit failed "$version"; return 1; } read -r password_auth pubkey_auth root_login <<< "$effective" - total="$(wc -l < "$passwd_file")" + while IFS=: read -r username _; do + kpanel_account_valid_username "$username" || continue + total=$((total + 1)) + done < "$passwd_file" [ "$total" -le 256 ] || truncated=true kpanel_account_emit ok "$version" printf 'KPANEL_ACCOUNT_MANAGEMENT_PASSWORD_AUTH=%s\n' "$password_auth" diff --git a/tests/test_kpanel_account_management_noninteractive_smoke.sh b/tests/test_kpanel_account_management_noninteractive_smoke.sh index 2bb367244..93933ed6d 100644 --- a/tests/test_kpanel_account_management_noninteractive_smoke.sh +++ b/tests/test_kpanel_account_management_noninteractive_smoke.sh @@ -70,6 +70,21 @@ stable_version_a="$(kpanel_account_version)" stable_version_b="$(kpanel_account_version)" [ "${stable_version_a}" = "${stable_version_b}" ] || fail "unchanged account state produced unstable resource versions" +# Hosts may contain historical service accounts that cannot be represented by +# the bounded protocol username grammar. Totals must count only emitted +# accounts, otherwise the Agent correctly rejects the snapshot as inconsistent. +printf 'root:x:0:0:root:/root:/bin/bash\nDebian-exim:x:101:101::/var/spool/exim4:/usr/sbin/nologin\noperator:x:1000:1000::/home/operator:/bin/bash\n' > "${version_fixture}/passwd" +kpanel_account_require() { return 0; } +kpanel_account_version() { printf 'a%.0s' {1..64}; printf '\n'; } +kpanel_account_login_defs_file() { printf '%s\n' "${version_fixture}/login.defs"; } +kpanel_account_password_status() { printf '%s\n' unset; } +kpanel_account_role() { if [ "$1" = root ]; then printf '%s\n' root; else printf '%s\n' standard; fi; } +kpanel_account_capture_keys() { : > "$2"; } +status_receipt="$(kpanel_account_status)" || fail "status rejected an unrepresentable historical username" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_TOTAL=2' <<< "${status_receipt}" || fail "status total included an unrepresentable username" +grep -Fqx 'KPANEL_ACCOUNT_MANAGEMENT_TRUNCATED=false' <<< "${status_receipt}" || fail "status incorrectly marked the filtered snapshot as truncated" +[ "$(grep -Fc 'KPANEL_ACCOUNT_MANAGEMENT_ACCOUNT_HEX=' <<< "${status_receipt}")" -eq 2 ] || fail "status total does not match emitted records" + # A standard account does not need sudo/wheel to exist. Minimal servers may # legitimately have neither group until an administrator role is requested. kpanel_account_sudo_file() { printf '%s\n' "${temporary}/90-kejilion-operator"; } From e9c3078eb516b05f9df6d2a9294cf3b226ca02bd Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 11 Aug 2026 11:46:23 +0800 Subject: [PATCH 1263/1285] feat(kpanel): add SSH defense manager protocol AI-Scope: kpanel-ssh-defense-manager --- cn/kejilion.sh | 459 +++++++++++++++++- kejilion.sh | 459 +++++++++++++++++- ...kpanel_f2b_manager_noninteractive_smoke.sh | 148 ++++++ 3 files changed, 1064 insertions(+), 2 deletions(-) create mode 100644 tests/test_kpanel_f2b_manager_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 6ee294b9e..273024256 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -3805,6 +3805,11 @@ kpanel_f2b_status() { kpanel_f2b_dispatch() { local command="${1:-status}" changed=false printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + if [ "$command" = "manager" ]; then + shift + kpanel_f2b_manager_dispatch "$@" + return $? + fi case "$command" in status) kpanel_f2b_status @@ -3853,6 +3858,458 @@ kpanel_f2b_dispatch() { esac } +KPANEL_F2B_MANAGER_PROTOCOL_VERSION="1" + +kpanel_f2b_manager_config_file() { + printf '%s/etc/fail2ban/jail.d/99-kejilion-sshd.local\n' "${KPANEL_F2B_TEST_ROOT:-}" +} + +kpanel_f2b_manager_log_file() { + printf '%s/var/log/fail2ban.log\n' "${KPANEL_F2B_TEST_ROOT:-}" +} + +kpanel_f2b_manager_emit() { + local status="$1" version="${2:-}" backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_F2B_MANAGER_STATUS=%s\n' "$status" + printf 'KPANEL_F2B_MANAGER_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_F2B_MANAGER_BACKUP=%s\n' "$backup" +} + +kpanel_f2b_manager_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_f2b_manager_valid_address() { + local value="$1" + [ -n "$value" ] && [ "${#value}" -le 80 ] && + [[ "$value" != *$'\n'* ]] && [[ "$value" != *$'\r'* ]] && + command -v python3 >/dev/null 2>&1 && + python3 -c 'import ipaddress,sys; value=sys.argv[1]; ipaddress.ip_network(value, strict=False) if "/" in value else ipaddress.ip_address(value)' "$value" >/dev/null 2>&1 +} + +kpanel_f2b_manager_valid_ip() { + local value="$1" + [ -n "$value" ] && [ "${#value}" -le 80 ] && [[ "$value" != */* ]] && + command -v python3 >/dev/null 2>&1 && + python3 -c 'import ipaddress,sys; ipaddress.ip_address(sys.argv[1])' "$value" >/dev/null 2>&1 +} + +kpanel_f2b_manager_profile_values() { + case "$1" in + mild) printf '%s\n' "600 600 8" ;; + standard) printf '%s\n' "3600 600 5" ;; + strict) printf '%s\n' "43200 600 3" ;; + *) return 1 ;; + esac +} + +kpanel_f2b_manager_profile() { + case "$1:$2:$3" in + 600:600:8) printf '%s\n' "mild" ;; + 3600:600:5) printf '%s\n' "standard" ;; + 43200:600:3) printf '%s\n' "strict" ;; + *) printf '%s\n' "custom" ;; + esac +} + +kpanel_f2b_manager_read_number() { + local jail="$1" key="$2" fallback="$3" value + value="$(fail2ban-client get "$jail" "$key" 2>/dev/null | tail -n 1 | tr -d '[:space:]')" || true + [[ "$value" =~ ^[0-9]+$ ]] && [ "$value" -le 315360000 ] || value="$fallback" + printf '%s\n' "$value" +} + +kpanel_f2b_manager_collect() { + local status_file token raw line hex log_file + F2B_MANAGER_INSTALLED=false + F2B_MANAGER_RUNNING=false + F2B_MANAGER_ENABLED=false + F2B_MANAGER_AUTOSTART=false + F2B_MANAGER_JAIL="$(kpanel_f2b_jail_name)" + F2B_MANAGER_CURRENT_FAILED=0 + F2B_MANAGER_TOTAL_FAILED=0 + F2B_MANAGER_CURRENT_BANNED=0 + F2B_MANAGER_TOTAL_BANNED=0 + F2B_MANAGER_BANTIME=3600 + F2B_MANAGER_FINDTIME=600 + F2B_MANAGER_MAXRETRY=5 + F2B_MANAGER_PROFILE=standard + F2B_MANAGER_BANS=() + F2B_MANAGER_TRUSTED=() + F2B_MANAGER_EVENTS=() + F2B_MANAGER_BANS_TRUNCATED=false + + command -v fail2ban-client >/dev/null 2>&1 || return 0 + F2B_MANAGER_INSTALLED=true + fail2ban-client ping >/dev/null 2>&1 || { + kpanel_f2b_autostart && F2B_MANAGER_AUTOSTART=true + return 0 + } + F2B_MANAGER_RUNNING=true + kpanel_f2b_autostart && F2B_MANAGER_AUTOSTART=true + status_file="$(mktemp /tmp/kejilion-f2b-status.XXXXXX)" || return 1 + if ! fail2ban-client status "$F2B_MANAGER_JAIL" > "$status_file" 2>/dev/null; then + rm -f -- "$status_file" + return 0 + fi + if ! kpanel_system_resource_file_within_bounds "$status_file" 4194304 4096; then + rm -f -- "$status_file" + return 1 + fi + F2B_MANAGER_ENABLED=true + F2B_MANAGER_CURRENT_FAILED="$(awk -F: '/Currently failed/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_TOTAL_FAILED="$(awk -F: '/Total failed/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_CURRENT_BANNED="$(awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_TOTAL_BANNED="$(awk -F: '/Total banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + for token in F2B_MANAGER_CURRENT_FAILED F2B_MANAGER_TOTAL_FAILED F2B_MANAGER_CURRENT_BANNED F2B_MANAGER_TOTAL_BANNED; do + raw="${!token}" + [[ "$raw" =~ ^[0-9]+$ ]] && [ "$raw" -le 1000000000 ] || printf -v "$token" '%s' 0 + done + raw="$(awk -F: '/Banned IP list/{sub(/^[^:]*:[[:space:]]*/, ""); print; exit}' "$status_file")" + rm -f -- "$status_file" + for token in $raw; do + if kpanel_f2b_manager_valid_ip "$token"; then + if [ "${#F2B_MANAGER_BANS[@]}" -lt 256 ]; then + F2B_MANAGER_BANS+=("$token") + else + F2B_MANAGER_BANS_TRUNCATED=true + break + fi + fi + done + + F2B_MANAGER_BANTIME="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" bantime 3600)" + F2B_MANAGER_FINDTIME="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" findtime 600)" + F2B_MANAGER_MAXRETRY="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" maxretry 5)" + [ "$F2B_MANAGER_MAXRETRY" -ge 1 ] && [ "$F2B_MANAGER_MAXRETRY" -le 1000 ] || F2B_MANAGER_MAXRETRY=5 + F2B_MANAGER_PROFILE="$(kpanel_f2b_manager_profile "$F2B_MANAGER_BANTIME" "$F2B_MANAGER_FINDTIME" "$F2B_MANAGER_MAXRETRY")" + + raw="$(fail2ban-client get "$F2B_MANAGER_JAIL" ignoreip 2>/dev/null || true)" + for token in $raw; do + token="${token#[}" + token="${token%]}" + token="${token%,}" + token="${token#\'}" + token="${token%\'}" + if kpanel_f2b_manager_valid_address "$token"; then + [ "${#F2B_MANAGER_TRUSTED[@]}" -ge 64 ] || F2B_MANAGER_TRUSTED+=("$token") + fi + done + + log_file="$(kpanel_f2b_manager_log_file)" + if [ -f "$log_file" ] && [ ! -L "$log_file" ]; then + while IFS= read -r line; do + [ "${#line}" -le 2048 ] || line="${line:0:2048}" + hex="$(printf '%s' "$line" | od -An -v -tx1 | tr -d ' \n')" || continue + [ -n "$hex" ] && F2B_MANAGER_EVENTS+=("$hex") + done < <(tail -n 200 -- "$log_file" 2>/dev/null | grep -E '\[(sshd|alpine-sshd)\].*(Found|Ban|Unban)[[:space:]]' | tail -n 20) + fi +} + +kpanel_f2b_manager_set_version() { + local canonical config_file config_hash=absent value version + kpanel_f2b_manager_collect || return 1 + canonical="$(mktemp /tmp/kejilion-f2b-version.XXXXXX)" || return 1 + config_file="$(kpanel_f2b_manager_config_file)" + if [ -f "$config_file" ] && [ ! -L "$config_file" ]; then + config_hash="$(sha256sum -- "$config_file" 2>/dev/null | awk '{print $1}')" + fi + { + printf 'installed=%s\nrunning=%s\nenabled=%s\nautostart=%s\njail=%s\n' \ + "$F2B_MANAGER_INSTALLED" "$F2B_MANAGER_RUNNING" "$F2B_MANAGER_ENABLED" "$F2B_MANAGER_AUTOSTART" "$F2B_MANAGER_JAIL" + printf 'bantime=%s\nfindtime=%s\nmaxretry=%s\nconfig=%s\n' \ + "$F2B_MANAGER_BANTIME" "$F2B_MANAGER_FINDTIME" "$F2B_MANAGER_MAXRETRY" "$config_hash" + printf '%s\n' "${F2B_MANAGER_TRUSTED[@]}" | sed '/^$/d' | sort -u | sed 's/^/trusted=/' + } > "$canonical" + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + F2B_MANAGER_VERSION="$version" +} + +kpanel_f2b_manager_current_version() { + kpanel_f2b_manager_set_version || return 1 + printf '%s\n' "$F2B_MANAGER_VERSION" +} + +kpanel_f2b_manager_snapshot() { + local status="${1:-ok}" backup="${2:-}" version value + kpanel_f2b_manager_set_version || { + kpanel_f2b_manager_emit failed "" + return 1 + } + version="$F2B_MANAGER_VERSION" + kpanel_f2b_manager_emit "$status" "$version" "$backup" + printf 'KPANEL_F2B_MANAGER_INSTALLED=%s\n' "$F2B_MANAGER_INSTALLED" + printf 'KPANEL_F2B_MANAGER_RUNNING=%s\n' "$F2B_MANAGER_RUNNING" + printf 'KPANEL_F2B_MANAGER_ENABLED=%s\n' "$F2B_MANAGER_ENABLED" + printf 'KPANEL_F2B_MANAGER_AUTOSTART=%s\n' "$F2B_MANAGER_AUTOSTART" + printf 'KPANEL_F2B_MANAGER_JAIL=%s\n' "$F2B_MANAGER_JAIL" + printf 'KPANEL_F2B_MANAGER_CURRENT_FAILED=%s\n' "$F2B_MANAGER_CURRENT_FAILED" + printf 'KPANEL_F2B_MANAGER_TOTAL_FAILED=%s\n' "$F2B_MANAGER_TOTAL_FAILED" + printf 'KPANEL_F2B_MANAGER_CURRENT_BANNED=%s\n' "$F2B_MANAGER_CURRENT_BANNED" + printf 'KPANEL_F2B_MANAGER_TOTAL_BANNED=%s\n' "$F2B_MANAGER_TOTAL_BANNED" + printf 'KPANEL_F2B_MANAGER_BANTIME=%s\n' "$F2B_MANAGER_BANTIME" + printf 'KPANEL_F2B_MANAGER_FINDTIME=%s\n' "$F2B_MANAGER_FINDTIME" + printf 'KPANEL_F2B_MANAGER_MAXRETRY=%s\n' "$F2B_MANAGER_MAXRETRY" + printf 'KPANEL_F2B_MANAGER_PROFILE=%s\n' "$F2B_MANAGER_PROFILE" + printf 'KPANEL_F2B_MANAGER_BANS_TRUNCATED=%s\n' "$F2B_MANAGER_BANS_TRUNCATED" + for value in "${F2B_MANAGER_BANS[@]}"; do printf 'KPANEL_F2B_MANAGER_BAN=%s\n' "$value"; done + for value in "${F2B_MANAGER_TRUSTED[@]}"; do printf 'KPANEL_F2B_MANAGER_TRUSTED=%s\n' "$value"; done + for value in "${F2B_MANAGER_EVENTS[@]}"; do printf 'KPANEL_F2B_MANAGER_EVENT_HEX=%s\n' "$value"; done +} + +kpanel_f2b_manager_set_file_identity() { + local path="$1" + if [ -n "${KPANEL_F2B_TEST_ROOT:-}" ]; then + chmod 600 -- "$path" + else + chown 0:0 -- "$path" && chmod 600 -- "$path" + fi +} + +kpanel_f2b_manager_write_config() { + local jail="$1" bantime="$2" findtime="$3" maxretry="$4" config_file config_dir temporary value + shift 4 + config_file="$(kpanel_f2b_manager_config_file)" + config_dir="$(dirname -- "$config_file")" + [ -d "$config_dir" ] && [ ! -L "$config_dir" ] && [ ! -L "$config_file" ] || return 1 + temporary="$(mktemp "$config_dir/.99-kejilion-sshd.local.XXXXXX")" || return 1 + { + printf '[%s]\n' "$jail" + printf '%s\n' '# Managed by kejilion.sh for SSH defense' + printf 'enabled = true\nbantime = %s\nfindtime = %s\nmaxretry = %s\n' "$bantime" "$findtime" "$maxretry" + if [ "$#" -gt 0 ]; then + printf 'ignoreip =' + for value in "$@"; do printf ' %s' "$value"; done + printf '\n' + fi + } > "$temporary" || { rm -f -- "$temporary"; return 1; } + kpanel_f2b_manager_set_file_identity "$temporary" && mv -f -- "$temporary" "$config_file" +} + +kpanel_f2b_manager_restore_config() { + local snapshot="$1" config_file + config_file="$(kpanel_f2b_manager_config_file)" + if [ "$(cat "$snapshot/config.existed" 2>/dev/null)" = true ]; then + cp -a -- "$snapshot/config" "$config_file" || return 1 + else + rm -f -- "$config_file" || return 1 + fi + fail2ban-client -t >/dev/null 2>&1 && fail2ban-client reload >/dev/null 2>&1 +} + +kpanel_f2b_manager_config_failure() { + local snapshot="$1" message="$2" version recovery="" + kpanel_f2b_manager_error "$message" + if kpanel_f2b_manager_restore_config "$snapshot"; then + version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + rm -rf -- "$snapshot" + kpanel_f2b_manager_emit failed "$version" + else + recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" ssh-defense 2>/dev/null || true)" + version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + kpanel_f2b_manager_emit rollback-failed "$version" "$recovery" + fi + return 1 +} + +kpanel_f2b_manager_config_action() { + local action="$1" expected="$2" value="$3" current_version profile bantime findtime maxretry snapshot config_file + local trusted=() item changed=false + kpanel_f2b_manager_set_version || { kpanel_f2b_manager_emit failed ""; return 1; } + current_version="$F2B_MANAGER_VERSION" + if [ "$current_version" != "$expected" ]; then + kpanel_f2b_manager_emit conflict "$current_version" + return 2 + fi + [ "$F2B_MANAGER_ENABLED" = true ] || { kpanel_f2b_manager_error "SSH jail 未运行"; kpanel_f2b_manager_emit failed "$current_version"; return 1; } + bantime="$F2B_MANAGER_BANTIME"; findtime="$F2B_MANAGER_FINDTIME"; maxretry="$F2B_MANAGER_MAXRETRY" + trusted=("${F2B_MANAGER_TRUSTED[@]}") + case "$action" in + set-profile) + read -r bantime findtime maxretry <<< "$(kpanel_f2b_manager_profile_values "$value")" || return 2 + [ "$F2B_MANAGER_PROFILE" = "$value" ] || changed=true + ;; + add-trusted) + kpanel_f2b_manager_valid_address "$value" || return 2 + for item in "${trusted[@]}"; do [ "$item" != "$value" ] || { kpanel_f2b_manager_snapshot unchanged; return 0; }; done + [ "${#trusted[@]}" -lt 64 ] || { kpanel_f2b_manager_error "信任地址已达到 64 条上限"; return 1; } + trusted+=("$value"); changed=true + ;; + remove-trusted) + kpanel_f2b_manager_valid_address "$value" || return 2 + local filtered=() + for item in "${trusted[@]}"; do [ "$item" = "$value" ] || filtered+=("$item"); done + [ "${#filtered[@]}" -ne "${#trusted[@]}" ] || { kpanel_f2b_manager_snapshot unchanged; return 0; } + trusted=("${filtered[@]}"); changed=true + ;; + *) return 2 ;; + esac + [ "$changed" = true ] || { kpanel_f2b_manager_snapshot unchanged; return 0; } + snapshot="$(kpanel_system_resource_tempdir ssh-defense)" || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + config_file="$(kpanel_f2b_manager_config_file)" + if [ -f "$config_file" ] && [ ! -L "$config_file" ]; then + printf '%s\n' true > "$snapshot/config.existed" + cp -a -- "$config_file" "$snapshot/config" || { rm -rf -- "$snapshot"; return 1; } + else + printf '%s\n' false > "$snapshot/config.existed" + fi + kpanel_f2b_manager_write_config "$F2B_MANAGER_JAIL" "$bantime" "$findtime" "$maxretry" "${trusted[@]}" || + kpanel_f2b_manager_config_failure "$snapshot" "无法写入 SSH 防御配置" || return 1 + fail2ban-client -t >/dev/null 2>&1 || kpanel_f2b_manager_config_failure "$snapshot" "Fail2Ban 配置验证失败" || return 1 + fail2ban-client reload >/dev/null 2>&1 || kpanel_f2b_manager_config_failure "$snapshot" "Fail2Ban 配置重载失败" || return 1 + kpanel_f2b_manager_collect || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御配置回读失败" || return 1 + [ "$F2B_MANAGER_BANTIME" = "$bantime" ] && [ "$F2B_MANAGER_FINDTIME" = "$findtime" ] && [ "$F2B_MANAGER_MAXRETRY" = "$maxretry" ] || + kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御策略回读不一致" || return 1 + case "$action" in + add-trusted) + for item in "${F2B_MANAGER_TRUSTED[@]}"; do [ "$item" != "$value" ] || changed=verified; done + [ "$changed" = verified ] || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御信任地址回读不一致" || return 1 + ;; + remove-trusted) + for item in "${F2B_MANAGER_TRUSTED[@]}"; do + [ "$item" != "$value" ] || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御信任地址仍然生效" || return 1 + done + ;; + esac + rm -rf -- "$snapshot" + kpanel_f2b_manager_snapshot applied +} + +kpanel_f2b_manager_unban_action() { + local expected="$1" address="${2:-}" current_version item target changed=false + local targets=() + kpanel_f2b_manager_set_version || { kpanel_f2b_manager_emit failed ""; return 1; } + current_version="$F2B_MANAGER_VERSION" + [ "$current_version" = "$expected" ] || { kpanel_f2b_manager_emit conflict "$current_version"; return 2; } + [ "$F2B_MANAGER_ENABLED" = true ] || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + if [ -n "$address" ]; then + kpanel_f2b_manager_valid_ip "$address" || return 2 + for item in "${F2B_MANAGER_BANS[@]}"; do + [ "$item" = "$address" ] || continue + fail2ban-client set "$F2B_MANAGER_JAIL" unbanip --report-absent "$address" >/dev/null 2>&1 || { + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + targets+=("$address") + changed=true + done + else + for item in "${F2B_MANAGER_BANS[@]}"; do + fail2ban-client set "$F2B_MANAGER_JAIL" unbanip --report-absent "$item" >/dev/null 2>&1 || { + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + targets+=("$item") + changed=true + done + fi + if [ "$changed" = true ]; then + kpanel_f2b_manager_collect || { kpanel_f2b_manager_emit needs-attention "$current_version"; return 1; } + for target in "${targets[@]}"; do + for item in "${F2B_MANAGER_BANS[@]}"; do + [ "$item" != "$target" ] || { + kpanel_f2b_manager_error "SSH 封禁解除后回读不一致" + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + done + done + fi + kpanel_f2b_manager_snapshot "$([ "$changed" = true ] && printf applied || printf unchanged)" +} + +kpanel_f2b_manager_service_action() { + local action="$1" current_version changed=false + root_use + current_version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + case "$action" in + enable) + if kpanel_f2b_enabled && kpanel_f2b_autostart; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + f2b_install_sshd >/dev/null || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + kpanel_f2b_enabled || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + disable) + if ! command -v fail2ban-client >/dev/null 2>&1; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + fi + fail2ban-client ping >/dev/null 2>&1 && { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + uninstall) + if ! command -v fail2ban-client >/dev/null 2>&1; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + remove fail2ban >/dev/null 2>&1 || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + rm -rf -- "${KPANEL_F2B_TEST_ROOT:-}/etc/fail2ban" || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + *) return 2 ;; + esac + kpanel_f2b_manager_snapshot "$([ "$changed" = true ] && printf applied || printf unchanged)" +} + +kpanel_f2b_manager_run_locked() ( + local action="$1" + shift + case "$action" in + set-profile|add-trusted|remove-trusted) kpanel_f2b_manager_config_action "$action" "$@" ;; + unban) kpanel_f2b_manager_unban_action "$@" ;; + unban-all) kpanel_f2b_manager_unban_action "$1" ;; + enable|disable|uninstall) kpanel_f2b_manager_service_action "$action" ;; + *) return 2 ;; + esac +) + +kpanel_f2b_manager_dispatch() { + local action="${1:-status}" expected value lock_file rc + shift || true + printf '%s\n' "KPANEL_F2B_MANAGER_PROTOCOL 1" + case "$action" in + status) + [ "$#" -eq 0 ] || return 2 + kpanel_f2b_manager_snapshot ok + ;; + set-profile) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_profile_values "$2" >/dev/null || return 2 + expected="$1"; value="$2" + ;; + add-trusted|remove-trusted) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_valid_address "$2" || return 2 + expected="$1"; value="$2" + ;; + unban) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_valid_ip "$2" || return 2 + expected="$1"; value="$2" + ;; + unban-all) + [ "$#" -eq 1 ] && kpanel_system_resource_valid_version "$1" || return 2 + expected="$1" + ;; + enable|disable|uninstall) + [ "$#" -eq 0 ] || return 2 + ;; + *) + kpanel_f2b_manager_error "用法: k f2b manager " + return 2 + ;; + esac + [ "$action" = status ] && return 0 + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_f2b_manager_emit failed ""; return 1; } + exec 9<>"$lock_file" || { kpanel_f2b_manager_emit failed ""; return 1; } + if ! flock -w 5 9; then kpanel_f2b_manager_emit conflict "$(kpanel_f2b_manager_current_version 2>/dev/null || true)"; return 2; fi + case "$action" in + set-profile|add-trusted|remove-trusted|unban) kpanel_f2b_manager_run_locked "$action" "$expected" "$value" ;; + unban-all) kpanel_f2b_manager_run_locked "$action" "$expected" ;; + *) kpanel_f2b_manager_run_locked "$action" ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -22343,7 +22800,7 @@ kpanel_system_resource_persist_recovery_snapshot() { local resource="$2" local recovery_root destination timestamp invalid - [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management)$ ]] || return 1 + [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management|ssh-defense)$ ]] || return 1 [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 [ -z "$invalid" ] || return 1 diff --git a/kejilion.sh b/kejilion.sh index 959053a67..aeec58cf0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -3805,6 +3805,11 @@ kpanel_f2b_status() { kpanel_f2b_dispatch() { local command="${1:-status}" changed=false printf '%s\n' "KPANEL_F2B_PROTOCOL 1" + if [ "$command" = "manager" ]; then + shift + kpanel_f2b_manager_dispatch "$@" + return $? + fi case "$command" in status) kpanel_f2b_status @@ -3853,6 +3858,458 @@ kpanel_f2b_dispatch() { esac } +KPANEL_F2B_MANAGER_PROTOCOL_VERSION="1" + +kpanel_f2b_manager_config_file() { + printf '%s/etc/fail2ban/jail.d/99-kejilion-sshd.local\n' "${KPANEL_F2B_TEST_ROOT:-}" +} + +kpanel_f2b_manager_log_file() { + printf '%s/var/log/fail2ban.log\n' "${KPANEL_F2B_TEST_ROOT:-}" +} + +kpanel_f2b_manager_emit() { + local status="$1" version="${2:-}" backup="${3:-}" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || version="$(kpanel_system_resource_zero_version)" + printf 'KPANEL_F2B_MANAGER_STATUS=%s\n' "$status" + printf 'KPANEL_F2B_MANAGER_VERSION=%s\n' "$version" + [ -z "$backup" ] || printf 'KPANEL_F2B_MANAGER_BACKUP=%s\n' "$backup" +} + +kpanel_f2b_manager_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_f2b_manager_valid_address() { + local value="$1" + [ -n "$value" ] && [ "${#value}" -le 80 ] && + [[ "$value" != *$'\n'* ]] && [[ "$value" != *$'\r'* ]] && + command -v python3 >/dev/null 2>&1 && + python3 -c 'import ipaddress,sys; value=sys.argv[1]; ipaddress.ip_network(value, strict=False) if "/" in value else ipaddress.ip_address(value)' "$value" >/dev/null 2>&1 +} + +kpanel_f2b_manager_valid_ip() { + local value="$1" + [ -n "$value" ] && [ "${#value}" -le 80 ] && [[ "$value" != */* ]] && + command -v python3 >/dev/null 2>&1 && + python3 -c 'import ipaddress,sys; ipaddress.ip_address(sys.argv[1])' "$value" >/dev/null 2>&1 +} + +kpanel_f2b_manager_profile_values() { + case "$1" in + mild) printf '%s\n' "600 600 8" ;; + standard) printf '%s\n' "3600 600 5" ;; + strict) printf '%s\n' "43200 600 3" ;; + *) return 1 ;; + esac +} + +kpanel_f2b_manager_profile() { + case "$1:$2:$3" in + 600:600:8) printf '%s\n' "mild" ;; + 3600:600:5) printf '%s\n' "standard" ;; + 43200:600:3) printf '%s\n' "strict" ;; + *) printf '%s\n' "custom" ;; + esac +} + +kpanel_f2b_manager_read_number() { + local jail="$1" key="$2" fallback="$3" value + value="$(fail2ban-client get "$jail" "$key" 2>/dev/null | tail -n 1 | tr -d '[:space:]')" || true + [[ "$value" =~ ^[0-9]+$ ]] && [ "$value" -le 315360000 ] || value="$fallback" + printf '%s\n' "$value" +} + +kpanel_f2b_manager_collect() { + local status_file token raw line hex log_file + F2B_MANAGER_INSTALLED=false + F2B_MANAGER_RUNNING=false + F2B_MANAGER_ENABLED=false + F2B_MANAGER_AUTOSTART=false + F2B_MANAGER_JAIL="$(kpanel_f2b_jail_name)" + F2B_MANAGER_CURRENT_FAILED=0 + F2B_MANAGER_TOTAL_FAILED=0 + F2B_MANAGER_CURRENT_BANNED=0 + F2B_MANAGER_TOTAL_BANNED=0 + F2B_MANAGER_BANTIME=3600 + F2B_MANAGER_FINDTIME=600 + F2B_MANAGER_MAXRETRY=5 + F2B_MANAGER_PROFILE=standard + F2B_MANAGER_BANS=() + F2B_MANAGER_TRUSTED=() + F2B_MANAGER_EVENTS=() + F2B_MANAGER_BANS_TRUNCATED=false + + command -v fail2ban-client >/dev/null 2>&1 || return 0 + F2B_MANAGER_INSTALLED=true + fail2ban-client ping >/dev/null 2>&1 || { + kpanel_f2b_autostart && F2B_MANAGER_AUTOSTART=true + return 0 + } + F2B_MANAGER_RUNNING=true + kpanel_f2b_autostart && F2B_MANAGER_AUTOSTART=true + status_file="$(mktemp /tmp/kejilion-f2b-status.XXXXXX)" || return 1 + if ! fail2ban-client status "$F2B_MANAGER_JAIL" > "$status_file" 2>/dev/null; then + rm -f -- "$status_file" + return 0 + fi + if ! kpanel_system_resource_file_within_bounds "$status_file" 4194304 4096; then + rm -f -- "$status_file" + return 1 + fi + F2B_MANAGER_ENABLED=true + F2B_MANAGER_CURRENT_FAILED="$(awk -F: '/Currently failed/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_TOTAL_FAILED="$(awk -F: '/Total failed/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_CURRENT_BANNED="$(awk -F: '/Currently banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + F2B_MANAGER_TOTAL_BANNED="$(awk -F: '/Total banned/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$status_file")" + for token in F2B_MANAGER_CURRENT_FAILED F2B_MANAGER_TOTAL_FAILED F2B_MANAGER_CURRENT_BANNED F2B_MANAGER_TOTAL_BANNED; do + raw="${!token}" + [[ "$raw" =~ ^[0-9]+$ ]] && [ "$raw" -le 1000000000 ] || printf -v "$token" '%s' 0 + done + raw="$(awk -F: '/Banned IP list/{sub(/^[^:]*:[[:space:]]*/, ""); print; exit}' "$status_file")" + rm -f -- "$status_file" + for token in $raw; do + if kpanel_f2b_manager_valid_ip "$token"; then + if [ "${#F2B_MANAGER_BANS[@]}" -lt 256 ]; then + F2B_MANAGER_BANS+=("$token") + else + F2B_MANAGER_BANS_TRUNCATED=true + break + fi + fi + done + + F2B_MANAGER_BANTIME="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" bantime 3600)" + F2B_MANAGER_FINDTIME="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" findtime 600)" + F2B_MANAGER_MAXRETRY="$(kpanel_f2b_manager_read_number "$F2B_MANAGER_JAIL" maxretry 5)" + [ "$F2B_MANAGER_MAXRETRY" -ge 1 ] && [ "$F2B_MANAGER_MAXRETRY" -le 1000 ] || F2B_MANAGER_MAXRETRY=5 + F2B_MANAGER_PROFILE="$(kpanel_f2b_manager_profile "$F2B_MANAGER_BANTIME" "$F2B_MANAGER_FINDTIME" "$F2B_MANAGER_MAXRETRY")" + + raw="$(fail2ban-client get "$F2B_MANAGER_JAIL" ignoreip 2>/dev/null || true)" + for token in $raw; do + token="${token#[}" + token="${token%]}" + token="${token%,}" + token="${token#\'}" + token="${token%\'}" + if kpanel_f2b_manager_valid_address "$token"; then + [ "${#F2B_MANAGER_TRUSTED[@]}" -ge 64 ] || F2B_MANAGER_TRUSTED+=("$token") + fi + done + + log_file="$(kpanel_f2b_manager_log_file)" + if [ -f "$log_file" ] && [ ! -L "$log_file" ]; then + while IFS= read -r line; do + [ "${#line}" -le 2048 ] || line="${line:0:2048}" + hex="$(printf '%s' "$line" | od -An -v -tx1 | tr -d ' \n')" || continue + [ -n "$hex" ] && F2B_MANAGER_EVENTS+=("$hex") + done < <(tail -n 200 -- "$log_file" 2>/dev/null | grep -E '\[(sshd|alpine-sshd)\].*(Found|Ban|Unban)[[:space:]]' | tail -n 20) + fi +} + +kpanel_f2b_manager_set_version() { + local canonical config_file config_hash=absent value version + kpanel_f2b_manager_collect || return 1 + canonical="$(mktemp /tmp/kejilion-f2b-version.XXXXXX)" || return 1 + config_file="$(kpanel_f2b_manager_config_file)" + if [ -f "$config_file" ] && [ ! -L "$config_file" ]; then + config_hash="$(sha256sum -- "$config_file" 2>/dev/null | awk '{print $1}')" + fi + { + printf 'installed=%s\nrunning=%s\nenabled=%s\nautostart=%s\njail=%s\n' \ + "$F2B_MANAGER_INSTALLED" "$F2B_MANAGER_RUNNING" "$F2B_MANAGER_ENABLED" "$F2B_MANAGER_AUTOSTART" "$F2B_MANAGER_JAIL" + printf 'bantime=%s\nfindtime=%s\nmaxretry=%s\nconfig=%s\n' \ + "$F2B_MANAGER_BANTIME" "$F2B_MANAGER_FINDTIME" "$F2B_MANAGER_MAXRETRY" "$config_hash" + printf '%s\n' "${F2B_MANAGER_TRUSTED[@]}" | sed '/^$/d' | sort -u | sed 's/^/trusted=/' + } > "$canonical" + version="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$version" =~ ^[0-9a-f]{64}$ ]] || return 1 + F2B_MANAGER_VERSION="$version" +} + +kpanel_f2b_manager_current_version() { + kpanel_f2b_manager_set_version || return 1 + printf '%s\n' "$F2B_MANAGER_VERSION" +} + +kpanel_f2b_manager_snapshot() { + local status="${1:-ok}" backup="${2:-}" version value + kpanel_f2b_manager_set_version || { + kpanel_f2b_manager_emit failed "" + return 1 + } + version="$F2B_MANAGER_VERSION" + kpanel_f2b_manager_emit "$status" "$version" "$backup" + printf 'KPANEL_F2B_MANAGER_INSTALLED=%s\n' "$F2B_MANAGER_INSTALLED" + printf 'KPANEL_F2B_MANAGER_RUNNING=%s\n' "$F2B_MANAGER_RUNNING" + printf 'KPANEL_F2B_MANAGER_ENABLED=%s\n' "$F2B_MANAGER_ENABLED" + printf 'KPANEL_F2B_MANAGER_AUTOSTART=%s\n' "$F2B_MANAGER_AUTOSTART" + printf 'KPANEL_F2B_MANAGER_JAIL=%s\n' "$F2B_MANAGER_JAIL" + printf 'KPANEL_F2B_MANAGER_CURRENT_FAILED=%s\n' "$F2B_MANAGER_CURRENT_FAILED" + printf 'KPANEL_F2B_MANAGER_TOTAL_FAILED=%s\n' "$F2B_MANAGER_TOTAL_FAILED" + printf 'KPANEL_F2B_MANAGER_CURRENT_BANNED=%s\n' "$F2B_MANAGER_CURRENT_BANNED" + printf 'KPANEL_F2B_MANAGER_TOTAL_BANNED=%s\n' "$F2B_MANAGER_TOTAL_BANNED" + printf 'KPANEL_F2B_MANAGER_BANTIME=%s\n' "$F2B_MANAGER_BANTIME" + printf 'KPANEL_F2B_MANAGER_FINDTIME=%s\n' "$F2B_MANAGER_FINDTIME" + printf 'KPANEL_F2B_MANAGER_MAXRETRY=%s\n' "$F2B_MANAGER_MAXRETRY" + printf 'KPANEL_F2B_MANAGER_PROFILE=%s\n' "$F2B_MANAGER_PROFILE" + printf 'KPANEL_F2B_MANAGER_BANS_TRUNCATED=%s\n' "$F2B_MANAGER_BANS_TRUNCATED" + for value in "${F2B_MANAGER_BANS[@]}"; do printf 'KPANEL_F2B_MANAGER_BAN=%s\n' "$value"; done + for value in "${F2B_MANAGER_TRUSTED[@]}"; do printf 'KPANEL_F2B_MANAGER_TRUSTED=%s\n' "$value"; done + for value in "${F2B_MANAGER_EVENTS[@]}"; do printf 'KPANEL_F2B_MANAGER_EVENT_HEX=%s\n' "$value"; done +} + +kpanel_f2b_manager_set_file_identity() { + local path="$1" + if [ -n "${KPANEL_F2B_TEST_ROOT:-}" ]; then + chmod 600 -- "$path" + else + chown 0:0 -- "$path" && chmod 600 -- "$path" + fi +} + +kpanel_f2b_manager_write_config() { + local jail="$1" bantime="$2" findtime="$3" maxretry="$4" config_file config_dir temporary value + shift 4 + config_file="$(kpanel_f2b_manager_config_file)" + config_dir="$(dirname -- "$config_file")" + [ -d "$config_dir" ] && [ ! -L "$config_dir" ] && [ ! -L "$config_file" ] || return 1 + temporary="$(mktemp "$config_dir/.99-kejilion-sshd.local.XXXXXX")" || return 1 + { + printf '[%s]\n' "$jail" + printf '%s\n' '# Managed by kejilion.sh for SSH defense' + printf 'enabled = true\nbantime = %s\nfindtime = %s\nmaxretry = %s\n' "$bantime" "$findtime" "$maxretry" + if [ "$#" -gt 0 ]; then + printf 'ignoreip =' + for value in "$@"; do printf ' %s' "$value"; done + printf '\n' + fi + } > "$temporary" || { rm -f -- "$temporary"; return 1; } + kpanel_f2b_manager_set_file_identity "$temporary" && mv -f -- "$temporary" "$config_file" +} + +kpanel_f2b_manager_restore_config() { + local snapshot="$1" config_file + config_file="$(kpanel_f2b_manager_config_file)" + if [ "$(cat "$snapshot/config.existed" 2>/dev/null)" = true ]; then + cp -a -- "$snapshot/config" "$config_file" || return 1 + else + rm -f -- "$config_file" || return 1 + fi + fail2ban-client -t >/dev/null 2>&1 && fail2ban-client reload >/dev/null 2>&1 +} + +kpanel_f2b_manager_config_failure() { + local snapshot="$1" message="$2" version recovery="" + kpanel_f2b_manager_error "$message" + if kpanel_f2b_manager_restore_config "$snapshot"; then + version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + rm -rf -- "$snapshot" + kpanel_f2b_manager_emit failed "$version" + else + recovery="$(kpanel_system_resource_persist_recovery_snapshot "$snapshot" ssh-defense 2>/dev/null || true)" + version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + kpanel_f2b_manager_emit rollback-failed "$version" "$recovery" + fi + return 1 +} + +kpanel_f2b_manager_config_action() { + local action="$1" expected="$2" value="$3" current_version profile bantime findtime maxretry snapshot config_file + local trusted=() item changed=false + kpanel_f2b_manager_set_version || { kpanel_f2b_manager_emit failed ""; return 1; } + current_version="$F2B_MANAGER_VERSION" + if [ "$current_version" != "$expected" ]; then + kpanel_f2b_manager_emit conflict "$current_version" + return 2 + fi + [ "$F2B_MANAGER_ENABLED" = true ] || { kpanel_f2b_manager_error "SSH jail 未运行"; kpanel_f2b_manager_emit failed "$current_version"; return 1; } + bantime="$F2B_MANAGER_BANTIME"; findtime="$F2B_MANAGER_FINDTIME"; maxretry="$F2B_MANAGER_MAXRETRY" + trusted=("${F2B_MANAGER_TRUSTED[@]}") + case "$action" in + set-profile) + read -r bantime findtime maxretry <<< "$(kpanel_f2b_manager_profile_values "$value")" || return 2 + [ "$F2B_MANAGER_PROFILE" = "$value" ] || changed=true + ;; + add-trusted) + kpanel_f2b_manager_valid_address "$value" || return 2 + for item in "${trusted[@]}"; do [ "$item" != "$value" ] || { kpanel_f2b_manager_snapshot unchanged; return 0; }; done + [ "${#trusted[@]}" -lt 64 ] || { kpanel_f2b_manager_error "信任地址已达到 64 条上限"; return 1; } + trusted+=("$value"); changed=true + ;; + remove-trusted) + kpanel_f2b_manager_valid_address "$value" || return 2 + local filtered=() + for item in "${trusted[@]}"; do [ "$item" = "$value" ] || filtered+=("$item"); done + [ "${#filtered[@]}" -ne "${#trusted[@]}" ] || { kpanel_f2b_manager_snapshot unchanged; return 0; } + trusted=("${filtered[@]}"); changed=true + ;; + *) return 2 ;; + esac + [ "$changed" = true ] || { kpanel_f2b_manager_snapshot unchanged; return 0; } + snapshot="$(kpanel_system_resource_tempdir ssh-defense)" || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + config_file="$(kpanel_f2b_manager_config_file)" + if [ -f "$config_file" ] && [ ! -L "$config_file" ]; then + printf '%s\n' true > "$snapshot/config.existed" + cp -a -- "$config_file" "$snapshot/config" || { rm -rf -- "$snapshot"; return 1; } + else + printf '%s\n' false > "$snapshot/config.existed" + fi + kpanel_f2b_manager_write_config "$F2B_MANAGER_JAIL" "$bantime" "$findtime" "$maxretry" "${trusted[@]}" || + kpanel_f2b_manager_config_failure "$snapshot" "无法写入 SSH 防御配置" || return 1 + fail2ban-client -t >/dev/null 2>&1 || kpanel_f2b_manager_config_failure "$snapshot" "Fail2Ban 配置验证失败" || return 1 + fail2ban-client reload >/dev/null 2>&1 || kpanel_f2b_manager_config_failure "$snapshot" "Fail2Ban 配置重载失败" || return 1 + kpanel_f2b_manager_collect || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御配置回读失败" || return 1 + [ "$F2B_MANAGER_BANTIME" = "$bantime" ] && [ "$F2B_MANAGER_FINDTIME" = "$findtime" ] && [ "$F2B_MANAGER_MAXRETRY" = "$maxretry" ] || + kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御策略回读不一致" || return 1 + case "$action" in + add-trusted) + for item in "${F2B_MANAGER_TRUSTED[@]}"; do [ "$item" != "$value" ] || changed=verified; done + [ "$changed" = verified ] || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御信任地址回读不一致" || return 1 + ;; + remove-trusted) + for item in "${F2B_MANAGER_TRUSTED[@]}"; do + [ "$item" != "$value" ] || kpanel_f2b_manager_config_failure "$snapshot" "SSH 防御信任地址仍然生效" || return 1 + done + ;; + esac + rm -rf -- "$snapshot" + kpanel_f2b_manager_snapshot applied +} + +kpanel_f2b_manager_unban_action() { + local expected="$1" address="${2:-}" current_version item target changed=false + local targets=() + kpanel_f2b_manager_set_version || { kpanel_f2b_manager_emit failed ""; return 1; } + current_version="$F2B_MANAGER_VERSION" + [ "$current_version" = "$expected" ] || { kpanel_f2b_manager_emit conflict "$current_version"; return 2; } + [ "$F2B_MANAGER_ENABLED" = true ] || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + if [ -n "$address" ]; then + kpanel_f2b_manager_valid_ip "$address" || return 2 + for item in "${F2B_MANAGER_BANS[@]}"; do + [ "$item" = "$address" ] || continue + fail2ban-client set "$F2B_MANAGER_JAIL" unbanip --report-absent "$address" >/dev/null 2>&1 || { + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + targets+=("$address") + changed=true + done + else + for item in "${F2B_MANAGER_BANS[@]}"; do + fail2ban-client set "$F2B_MANAGER_JAIL" unbanip --report-absent "$item" >/dev/null 2>&1 || { + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + targets+=("$item") + changed=true + done + fi + if [ "$changed" = true ]; then + kpanel_f2b_manager_collect || { kpanel_f2b_manager_emit needs-attention "$current_version"; return 1; } + for target in "${targets[@]}"; do + for item in "${F2B_MANAGER_BANS[@]}"; do + [ "$item" != "$target" ] || { + kpanel_f2b_manager_error "SSH 封禁解除后回读不一致" + kpanel_f2b_manager_emit needs-attention "$current_version" + return 1 + } + done + done + fi + kpanel_f2b_manager_snapshot "$([ "$changed" = true ] && printf applied || printf unchanged)" +} + +kpanel_f2b_manager_service_action() { + local action="$1" current_version changed=false + root_use + current_version="$(kpanel_f2b_manager_current_version 2>/dev/null || true)" + case "$action" in + enable) + if kpanel_f2b_enabled && kpanel_f2b_autostart; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + f2b_install_sshd >/dev/null || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + kpanel_f2b_enabled || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + disable) + if ! command -v fail2ban-client >/dev/null 2>&1; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + if command -v apk >/dev/null 2>&1; then + service fail2ban stop >/dev/null 2>&1 || true + rc-update del fail2ban default >/dev/null 2>&1 || true + else + /bin/systemctl disable --now fail2ban.service >/dev/null 2>&1 || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + fi + fail2ban-client ping >/dev/null 2>&1 && { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + uninstall) + if ! command -v fail2ban-client >/dev/null 2>&1; then kpanel_f2b_manager_snapshot unchanged; return 0; fi + remove fail2ban >/dev/null 2>&1 || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + rm -rf -- "${KPANEL_F2B_TEST_ROOT:-}/etc/fail2ban" || { kpanel_f2b_manager_emit failed "$current_version"; return 1; } + changed=true + ;; + *) return 2 ;; + esac + kpanel_f2b_manager_snapshot "$([ "$changed" = true ] && printf applied || printf unchanged)" +} + +kpanel_f2b_manager_run_locked() ( + local action="$1" + shift + case "$action" in + set-profile|add-trusted|remove-trusted) kpanel_f2b_manager_config_action "$action" "$@" ;; + unban) kpanel_f2b_manager_unban_action "$@" ;; + unban-all) kpanel_f2b_manager_unban_action "$1" ;; + enable|disable|uninstall) kpanel_f2b_manager_service_action "$action" ;; + *) return 2 ;; + esac +) + +kpanel_f2b_manager_dispatch() { + local action="${1:-status}" expected value lock_file rc + shift || true + printf '%s\n' "KPANEL_F2B_MANAGER_PROTOCOL 1" + case "$action" in + status) + [ "$#" -eq 0 ] || return 2 + kpanel_f2b_manager_snapshot ok + ;; + set-profile) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_profile_values "$2" >/dev/null || return 2 + expected="$1"; value="$2" + ;; + add-trusted|remove-trusted) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_valid_address "$2" || return 2 + expected="$1"; value="$2" + ;; + unban) + [ "$#" -eq 2 ] && kpanel_system_resource_valid_version "$1" && kpanel_f2b_manager_valid_ip "$2" || return 2 + expected="$1"; value="$2" + ;; + unban-all) + [ "$#" -eq 1 ] && kpanel_system_resource_valid_version "$1" || return 2 + expected="$1" + ;; + enable|disable|uninstall) + [ "$#" -eq 0 ] || return 2 + ;; + *) + kpanel_f2b_manager_error "用法: k f2b manager " + return 2 + ;; + esac + [ "$action" = status ] && return 0 + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_f2b_manager_emit failed ""; return 1; } + exec 9<>"$lock_file" || { kpanel_f2b_manager_emit failed ""; return 1; } + if ! flock -w 5 9; then kpanel_f2b_manager_emit conflict "$(kpanel_f2b_manager_current_version 2>/dev/null || true)"; return 2; fi + case "$action" in + set-profile|add-trusted|remove-trusted|unban) kpanel_f2b_manager_run_locked "$action" "$expected" "$value" ;; + unban-all) kpanel_f2b_manager_run_locked "$action" "$expected" ;; + *) kpanel_f2b_manager_run_locked "$action" ;; + esac +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -22343,7 +22800,7 @@ kpanel_system_resource_persist_recovery_snapshot() { local resource="$2" local recovery_root destination timestamp invalid - [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management)$ ]] || return 1 + [[ "$resource" =~ ^(hosts|cron|firewall|traffic-shutdown|account-management|ssh-defense)$ ]] || return 1 [ -d "$snapshot_dir" ] && [ ! -L "$snapshot_dir" ] || return 1 invalid="$(find "$snapshot_dir" -mindepth 1 \( -type l -o ! -type f \) -print -quit 2>/dev/null)" || return 1 [ -z "$invalid" ] || return 1 diff --git a/tests/test_kpanel_f2b_manager_noninteractive_smoke.sh b/tests/test_kpanel_f2b_manager_noninteractive_smoke.sh new file mode 100644 index 000000000..6ac91fee2 --- /dev/null +++ b/tests/test_kpanel_f2b_manager_noninteractive_smoke.sh @@ -0,0 +1,148 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +source_script="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" +temporary="$(mktemp -d)" +trap 'rm -rf -- "$temporary"' EXIT +script_path="$temporary/kejilion.sh" +sed 's/\r$//' "$source_script" > "$script_path" + +bash -n "$script_path" +grep -Fqx 'KPANEL_F2B_MANAGER_PROTOCOL_VERSION="1"' "$script_path" +[ "$(grep -Fxc 'KPANEL_F2B_MANAGER_PROTOCOL_VERSION="1"' "$script_path")" -eq 1 ] +grep -F 'kpanel_f2b_manager_dispatch "$@"' "$script_path" >/dev/null + +functions="$({ + awk ' + /^kpanel_f2b_jail_name\(\) \{/ { capture=1 } + /^f2b_sshd\(\) \{/ { exit } + capture { print } + ' "$script_path" +})" +eval "$functions" + +KPANEL_F2B_TEST_ROOT="$temporary/root" +mkdir -p "$KPANEL_F2B_TEST_ROOT/etc/fail2ban/jail.d" "$KPANEL_F2B_TEST_ROOT/var/log" +cat > "$KPANEL_F2B_TEST_ROOT/var/log/fail2ban.log" <<'EOF' +2026-08-11 01:02:03,000 fail2ban.filter [1]: INFO [sshd] Found 198.51.100.8 - 2026-08-11 01:02:03 +2026-08-11 01:02:04,000 fail2ban.actions [1]: NOTICE [sshd] Ban 198.51.100.8 +EOF + +F2B_TEST_BANS="198.51.100.8 2001:db8::8" +F2B_TEST_DEFAULT_TRUSTED="127.0.0.1/8 ::1" +F2B_TEST_FAIL_VALIDATE=0 +F2B_TEST_UNBAN_STICKY=0 + +kpanel_system_resource_zero_version() { printf '%064d\n' 0; } +kpanel_system_resource_valid_version() { [[ "$1" =~ ^[0-9a-f]{64}$ ]]; } +kpanel_system_resource_file_within_bounds() { + [ "$(wc -c < "$1")" -le "$2" ] && [ "$(awk 'END { print NR + 0 }' "$1")" -le "$3" ] +} +kpanel_system_resource_tempdir() { mktemp -d "$temporary/$1.XXXXXX"; } +kpanel_system_resource_persist_recovery_snapshot() { printf '%s\n' "$1"; } +kpanel_f2b_autostart() { return 0; } +if [[ "${OSTYPE:-}" == msys* ]]; then + python3() { + local value="${*: -1}" + case "$value" in 999.999.999.999|203.0.113.0/99|203.0.113.0/24) [[ "$*" == *ip_network* && "$value" = 203.0.113.0/24 ]] ;; *) return 0 ;; esac + } +fi + +managed_value() { + local key="$1" fallback="$2" config="$KPANEL_F2B_TEST_ROOT/etc/fail2ban/jail.d/99-kejilion-sshd.local" value + value="$(awk -F= -v key="$key" '$1 ~ "^[[:space:]]*" key "[[:space:]]*$" { gsub(/[[:space:]]/, "", $2); print $2; exit }' "$config" 2>/dev/null || true)" + printf '%s\n' "${value:-$fallback}" +} + +fail2ban-client() { + case "${1:-}" in + ping) return 0 ;; + status) + printf '%s\n' \ + "Status for the jail: sshd" \ + "|- Filter" \ + "| |- Currently failed: 1" \ + "| |- Total failed: 12" \ + "|- Actions" \ + " |- Currently banned: $(wc -w <<< "$F2B_TEST_BANS")" \ + " |- Total banned: 4" \ + " \\- Banned IP list: $F2B_TEST_BANS" + ;; + get) + case "${3:-}" in + bantime) managed_value bantime 3600 ;; + findtime) managed_value findtime 600 ;; + maxretry) managed_value maxretry 5 ;; + ignoreip) + local config="$KPANEL_F2B_TEST_ROOT/etc/fail2ban/jail.d/99-kejilion-sshd.local" value + value="$(awk -F= '/^[[:space:]]*ignoreip[[:space:]]*=/{sub(/^[^=]*=[[:space:]]*/, ""); print; exit}' "$config" 2>/dev/null || true)" + printf '%s\n' "${value:-$F2B_TEST_DEFAULT_TRUSTED}" + ;; + esac + ;; + set) + local ip="${6:-${5:-}}" + [ "$F2B_TEST_UNBAN_STICKY" -eq 1 ] || F2B_TEST_BANS="$(for value in $F2B_TEST_BANS; do [ "$value" = "$ip" ] || printf '%s ' "$value"; done)" + ;; + -t) + if [ "$F2B_TEST_FAIL_VALIDATE" -gt 0 ]; then + F2B_TEST_FAIL_VALIDATE=$((F2B_TEST_FAIL_VALIDATE - 1)) + return 1 + fi + return 0 + ;; + reload) return 0 ;; + esac +} + +status_output="$(kpanel_f2b_dispatch manager status)" +grep -F 'KPANEL_F2B_PROTOCOL 1' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_PROTOCOL 1' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_STATUS=ok' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_PROFILE=standard' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_CURRENT_FAILED=1' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_BAN=198.51.100.8' <<< "$status_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_TRUSTED=127.0.0.1/8' <<< "$status_output" >/dev/null +[ "$(grep -c '^KPANEL_F2B_MANAGER_EVENT_HEX=' <<< "$status_output")" -eq 2 ] +! kpanel_f2b_manager_valid_address '999.999.999.999' +! kpanel_f2b_manager_valid_address '203.0.113.0/99' +! kpanel_f2b_manager_valid_ip '203.0.113.0/24' + +version="$(grep '^KPANEL_F2B_MANAGER_VERSION=' <<< "$status_output" | cut -d= -f2)" +profile_output="$(kpanel_f2b_manager_config_action set-profile "$version" strict)" +grep -F 'KPANEL_F2B_MANAGER_STATUS=applied' <<< "$profile_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_PROFILE=strict' <<< "$profile_output" >/dev/null +grep -F 'bantime = 43200' "$KPANEL_F2B_TEST_ROOT/etc/fail2ban/jail.d/99-kejilion-sshd.local" >/dev/null + +version="$(grep '^KPANEL_F2B_MANAGER_VERSION=' <<< "$profile_output" | cut -d= -f2)" +trusted_output="$(kpanel_f2b_manager_config_action add-trusted "$version" 203.0.113.0/24)" +grep -F 'KPANEL_F2B_MANAGER_STATUS=applied' <<< "$trusted_output" >/dev/null +grep -F 'KPANEL_F2B_MANAGER_TRUSTED=203.0.113.0/24' <<< "$trusted_output" >/dev/null + +version="$(grep '^KPANEL_F2B_MANAGER_VERSION=' <<< "$trusted_output" | cut -d= -f2)" +unban_output="$(kpanel_f2b_manager_unban_action "$version" 198.51.100.8)" +grep -F 'KPANEL_F2B_MANAGER_STATUS=applied' <<< "$unban_output" >/dev/null +! grep -F 'KPANEL_F2B_MANAGER_BAN=198.51.100.8' <<< "$unban_output" >/dev/null + +F2B_TEST_UNBAN_STICKY=1 +version="$(grep '^KPANEL_F2B_MANAGER_VERSION=' <<< "$unban_output" | cut -d= -f2)" +if kpanel_f2b_manager_unban_action "$version" 2001:db8::8 > "$temporary/unban-failure.out" 2>/dev/null; then + echo "unban readback mismatch unexpectedly succeeded" >&2 + exit 1 +fi +grep -F 'KPANEL_F2B_MANAGER_STATUS=needs-attention' "$temporary/unban-failure.out" >/dev/null +F2B_TEST_UNBAN_STICKY=0 + +config="$KPANEL_F2B_TEST_ROOT/etc/fail2ban/jail.d/99-kejilion-sshd.local" +before_hash="$(sha256sum "$config" | awk '{print $1}')" +version="$(grep '^KPANEL_F2B_MANAGER_VERSION=' <<< "$unban_output" | cut -d= -f2)" +F2B_TEST_FAIL_VALIDATE=1 +if kpanel_f2b_manager_config_action set-profile "$version" mild > "$temporary/failure.out" 2>/dev/null; then + echo "invalid configuration unexpectedly succeeded" >&2 + exit 1 +fi +grep -F 'KPANEL_F2B_MANAGER_STATUS=failed' "$temporary/failure.out" >/dev/null +[ "$(sha256sum "$config" | awk '{print $1}')" = "$before_hash" ] + +printf '%s\n' "kpanel_f2b_manager_noninteractive_smoke=pass" From 28f89c1b34df4b25e6ef9b144c328fdea75dbac9 Mon Sep 17 00:00:00 2001 From: kejilion Date: Tue, 11 Aug 2026 16:14:28 +0800 Subject: [PATCH 1264/1285] feat(kpanel): add one-click system tuning protocol AI-Scope: kpanel-system-tuning-assistant --- cn/kejilion.sh | 181 ++++++++++++++++-- kejilion.sh | 181 ++++++++++++++++-- ...anel_system_tuning_noninteractive_smoke.sh | 77 ++++++++ 3 files changed, 411 insertions(+), 28 deletions(-) create mode 100644 tests/test_kpanel_system_tuning_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 273024256..7ccf7471a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -28,6 +28,7 @@ kpanel_protocol_active() { [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_SYSTEM_TUNING_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || @@ -4310,6 +4311,156 @@ kpanel_f2b_manager_dispatch() { esac } +KPANEL_SYSTEM_TUNING_PROTOCOL_VERSION="1" +KPANEL_SYSTEM_TUNING_MIRROR_COMMIT="649e948763042e485e411be540d21c32cface1c1" +KPANEL_SYSTEM_TUNING_MIRROR_SHA256="2e3b78a460f10ef291f30e3cbf3d3b28a9521d6615364f11b36e4a70ec97d18d" +KPANEL_SYSTEM_TUNING_NETWORK_COMMIT="e9c3078eb516b05f9df6d2a9294cf3b226ca02bd" +KPANEL_SYSTEM_TUNING_NETWORK_SHA256="94f86598805b7a8155f444f35a446df4657985ef81b25f96f7799aa465033bbb" + +kpanel_system_tuning_error() { printf '错误: %s\n' "$1" >&2; } + +kpanel_system_tuning_valid_item() { + case "$1" in + system-update|system-cleanup|swap-1g|ssh-port-5522|ssh-defense|firewall-open-all|bbr|timezone-shanghai|dns-auto|ipv4-preferred|basic-tools|kernel-auto) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_system_tuning_download_verified() { + local url="$1" expected="$2" output="$3" actual size + curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 + [ -f "$output" ] && [ ! -L "$output" ] || return 1 + size="$(wc -c < "$output" | tr -d '[:space:]')" + [[ "$size" =~ ^[0-9]+$ ]] && [ "$size" -gt 0 ] && [ "$size" -le 1048576 ] || return 1 + actual="$(sha256sum -- "$output" | awk '{print $1}')" + [ "$actual" = "$expected" ] +} + +kpanel_system_tuning_switch_mirror() { + local script country url + script="$(mktemp /tmp/kejilion-system-tuning-mirror.XXXXXX)" || return 1 + url="${gh_proxy}raw.githubusercontent.com/SuperManito/LinuxMirrors/${KPANEL_SYSTEM_TUNING_MIRROR_COMMIT}/ChangeMirrors.sh" + kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_MIRROR_SHA256" "$script" || { rm -f -- "$script"; return 1; } + country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + if [ "$country" = CN ]; then + bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + elif grep -qi oracle /etc/os-release 2>/dev/null; then + bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + else + bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + fi + local result=$? + rm -f -- "$script" + return "$result" +} + +kpanel_system_tuning_kernel_auto() { + local script url + script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 + url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" + kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } + bash "$script" + local result=$? + rm -f -- "$script" + return "$result" +} + +kpanel_system_tuning_firewall_open_all() { + local version + version="$(kpanel_system_resource_firewall_version)" || return 1 + kpanel_system_resource_firewall_action open-all "$version" >&2 +} + +kpanel_system_tuning_item_ready() { + local item="$1" command_name + case "$item" in + swap-1g) [ "$(free -m 2>/dev/null | awk '/^Swap:/{print $2; exit}')" = 1024 ] ;; + ssh-port-5522) sshd -T 2>/dev/null | grep -Eq '^port 5522$' ;; + ssh-defense) kpanel_f2b_enabled >/dev/null 2>&1 ;; + firewall-open-all) iptables-save 2>/dev/null | awk '$0=="*filter"{f=1;next} f&&$0=="COMMIT"{exit} f&&/^:INPUT /{i=$2} f&&/^:FORWARD /{w=$2} END{exit !(i=="ACCEPT"&&w=="ACCEPT")}' ;; + bbr) [ "$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)" = bbr ] && [ "$(sysctl -n net.core.default_qdisc 2>/dev/null)" = fq ] ;; + timezone-shanghai) [ "$(timedatectl show -p Timezone --value 2>/dev/null)" = Asia/Shanghai ] ;; + ipv4-preferred) grep -Eq '^precedence[[:space:]]+::ffff:0:0/96[[:space:]]+100([[:space:]]|$)' /etc/gai.conf 2>/dev/null ;; + basic-tools) for command_name in docker wget sudo tar unzip socat btop nano vim; do command -v "$command_name" >/dev/null 2>&1 || return 1; done ;; + kernel-auto) [ -s /etc/sysctl.d/99-network-optimize.conf ] || { [ -s /etc/sysctl.conf ] && grep -q 'net.core.default_qdisc' /etc/sysctl.conf 2>/dev/null; } ;; + *) return 1 ;; + esac +} + +kpanel_system_tuning_collect() { + local canonical item state + TUNING_ITEMS=() + for item in system-update system-cleanup swap-1g ssh-port-5522 ssh-defense firewall-open-all bbr timezone-shanghai dns-auto ipv4-preferred basic-tools kernel-auto; do + state=pending + kpanel_system_tuning_item_ready "$item" && state=ready + TUNING_ITEMS+=("$item:$state") + done + canonical="$(mktemp /tmp/kejilion-system-tuning-version.XXXXXX)" || return 1 + printf '%s\n' "${TUNING_ITEMS[@]}" > "$canonical" + TUNING_VERSION="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$TUNING_VERSION" =~ ^[0-9a-f]{64}$ ]] +} + +kpanel_system_tuning_emit() { + local status="$1" selected="${2:-}" item + kpanel_system_tuning_collect || { TUNING_VERSION="$(kpanel_system_resource_zero_version)"; TUNING_ITEMS=(); } + printf 'KPANEL_SYSTEM_TUNING_STATUS=%s\n' "$status" + printf 'KPANEL_SYSTEM_TUNING_VERSION=%s\n' "$TUNING_VERSION" + [ -z "$selected" ] || printf 'KPANEL_SYSTEM_TUNING_SELECTED=%s\n' "$selected" + for item in "${TUNING_ITEMS[@]}"; do printf 'KPANEL_SYSTEM_TUNING_ITEM=%s\n' "$item"; done +} + +kpanel_system_tuning_run_item() { + case "$1" in + system-update) kpanel_system_tuning_switch_mirror && linux_update ;; + system-cleanup) linux_clean ;; + swap-1g) add_swap 1024 ;; + ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; + ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; + firewall-open-all) kpanel_system_tuning_firewall_open_all ;; + bbr) bbr_on ;; + timezone-shanghai) set_timedate Asia/Shanghai ;; + dns-auto) auto_optimize_dns ;; + ipv4-preferred) prefer_ipv4 ;; + basic-tools) install_docker && install wget sudo tar unzip socat btop nano vim ;; + kernel-auto) kpanel_system_tuning_kernel_auto ;; + *) return 2 ;; + esac +} + +kpanel_system_tuning_apply_item() { + local item="$1" status=applied + if kpanel_system_tuning_item_ready "$item"; then + status=unchanged + elif ! kpanel_system_tuning_run_item "$item" >&2; then + kpanel_system_tuning_emit needs-attention "$item" + return 1 + fi + case "$item" in system-update|system-cleanup|dns-auto) ;; *) + kpanel_system_tuning_item_ready "$item" || { kpanel_system_tuning_emit needs-attention "$item"; return 1; } + ;; esac + kpanel_system_tuning_emit "$status" "$item" +} + +kpanel_system_tuning_dispatch() { + local action="${1:-status}" item lock_file + shift || true + printf '%s\n' "KPANEL_SYSTEM_TUNING_PROTOCOL 1" + [ "${KJ_SYSTEM_TUNING_NONINTERACTIVE:-}" = 1 ] || { kpanel_system_tuning_error "KPanel system-tuning 协议环境未启用"; return 2; } + [ "$EUID" -eq 0 ] || { kpanel_system_tuning_error "KPanel system-tuning 协议必须以 root 运行"; return 1; } + [ "$(uname -s)" = Linux ] || { kpanel_system_tuning_error "KPanel system-tuning 协议仅支持 Linux"; return 1; } + case "$action" in + status) [ "$#" -eq 0 ] || return 2; kpanel_system_tuning_emit ok; return $? ;; + apply-item) [ "$#" -eq 1 ] && kpanel_system_tuning_valid_item "$1" || return 2; item="$1" ;; + *) kpanel_system_tuning_error "用法: k kpanel system-tuning "; return 2 ;; + esac + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_system_tuning_emit failed "$item"; return 1; } + exec 9<>"$lock_file" || { kpanel_system_tuning_emit failed "$item"; return 1; } + if ! flock -w 5 9; then kpanel_system_tuning_emit conflict "$item"; return 2; fi + kpanel_system_tuning_apply_item "$item" +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -26838,52 +26989,51 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" - switch_mirror false false - linux_update + kpanel_system_tuning_run_item system-update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" - linux_clean + kpanel_system_tuning_run_item system-cleanup echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" - add_swap 1024 + kpanel_system_tuning_run_item swap-1g echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - new_ssh_port 5522 + kpanel_system_tuning_run_item ssh-port-5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - f2b_install_sshd + kpanel_system_tuning_run_item ssh-defense cd ~ f2b_status echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" echo "------------------------------------------------" + kpanel_system_tuning_run_item firewall-open-all echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" - bbr_on + kpanel_system_tuning_run_item bbr echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" - set_timedate Asia/Shanghai + kpanel_system_tuning_run_item timezone-shanghai echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - auto_optimize_dns + kpanel_system_tuning_run_item dns-auto echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" - prefer_ipv4 + kpanel_system_tuning_run_item ipv4-preferred echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" - install_docker - install wget sudo tar unzip socat btop nano vim + kpanel_system_tuning_run_item basic-tools echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + kpanel_system_tuning_run_item kernel-auto echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" @@ -28032,8 +28182,11 @@ else elif [ "${1:-}" = "account-management" ]; then shift kpanel_account_dispatch "$@" + elif [ "${1:-}" = "system-tuning" ]; then + shift + kpanel_system_tuning_dispatch "$@" else - echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ... | system-tuning ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/kejilion.sh b/kejilion.sh index aeec58cf0..59ceebbe3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -28,6 +28,7 @@ kpanel_protocol_active() { [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_SYSTEM_TUNING_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_BBRV3_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_APP_INTERACTIVE:-}" = "1" ] || @@ -4310,6 +4311,156 @@ kpanel_f2b_manager_dispatch() { esac } +KPANEL_SYSTEM_TUNING_PROTOCOL_VERSION="1" +KPANEL_SYSTEM_TUNING_MIRROR_COMMIT="649e948763042e485e411be540d21c32cface1c1" +KPANEL_SYSTEM_TUNING_MIRROR_SHA256="2e3b78a460f10ef291f30e3cbf3d3b28a9521d6615364f11b36e4a70ec97d18d" +KPANEL_SYSTEM_TUNING_NETWORK_COMMIT="e9c3078eb516b05f9df6d2a9294cf3b226ca02bd" +KPANEL_SYSTEM_TUNING_NETWORK_SHA256="94f86598805b7a8155f444f35a446df4657985ef81b25f96f7799aa465033bbb" + +kpanel_system_tuning_error() { printf '错误: %s\n' "$1" >&2; } + +kpanel_system_tuning_valid_item() { + case "$1" in + system-update|system-cleanup|swap-1g|ssh-port-5522|ssh-defense|firewall-open-all|bbr|timezone-shanghai|dns-auto|ipv4-preferred|basic-tools|kernel-auto) return 0 ;; + *) return 1 ;; + esac +} + +kpanel_system_tuning_download_verified() { + local url="$1" expected="$2" output="$3" actual size + curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 + [ -f "$output" ] && [ ! -L "$output" ] || return 1 + size="$(wc -c < "$output" | tr -d '[:space:]')" + [[ "$size" =~ ^[0-9]+$ ]] && [ "$size" -gt 0 ] && [ "$size" -le 1048576 ] || return 1 + actual="$(sha256sum -- "$output" | awk '{print $1}')" + [ "$actual" = "$expected" ] +} + +kpanel_system_tuning_switch_mirror() { + local script country url + script="$(mktemp /tmp/kejilion-system-tuning-mirror.XXXXXX)" || return 1 + url="${gh_proxy}raw.githubusercontent.com/SuperManito/LinuxMirrors/${KPANEL_SYSTEM_TUNING_MIRROR_COMMIT}/ChangeMirrors.sh" + kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_MIRROR_SHA256" "$script" || { rm -f -- "$script"; return 1; } + country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + if [ "$country" = CN ]; then + bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + elif grep -qi oracle /etc/os-release 2>/dev/null; then + bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + else + bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + fi + local result=$? + rm -f -- "$script" + return "$result" +} + +kpanel_system_tuning_kernel_auto() { + local script url + script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 + url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" + kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } + bash "$script" + local result=$? + rm -f -- "$script" + return "$result" +} + +kpanel_system_tuning_firewall_open_all() { + local version + version="$(kpanel_system_resource_firewall_version)" || return 1 + kpanel_system_resource_firewall_action open-all "$version" >&2 +} + +kpanel_system_tuning_item_ready() { + local item="$1" command_name + case "$item" in + swap-1g) [ "$(free -m 2>/dev/null | awk '/^Swap:/{print $2; exit}')" = 1024 ] ;; + ssh-port-5522) sshd -T 2>/dev/null | grep -Eq '^port 5522$' ;; + ssh-defense) kpanel_f2b_enabled >/dev/null 2>&1 ;; + firewall-open-all) iptables-save 2>/dev/null | awk '$0=="*filter"{f=1;next} f&&$0=="COMMIT"{exit} f&&/^:INPUT /{i=$2} f&&/^:FORWARD /{w=$2} END{exit !(i=="ACCEPT"&&w=="ACCEPT")}' ;; + bbr) [ "$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)" = bbr ] && [ "$(sysctl -n net.core.default_qdisc 2>/dev/null)" = fq ] ;; + timezone-shanghai) [ "$(timedatectl show -p Timezone --value 2>/dev/null)" = Asia/Shanghai ] ;; + ipv4-preferred) grep -Eq '^precedence[[:space:]]+::ffff:0:0/96[[:space:]]+100([[:space:]]|$)' /etc/gai.conf 2>/dev/null ;; + basic-tools) for command_name in docker wget sudo tar unzip socat btop nano vim; do command -v "$command_name" >/dev/null 2>&1 || return 1; done ;; + kernel-auto) [ -s /etc/sysctl.d/99-network-optimize.conf ] || { [ -s /etc/sysctl.conf ] && grep -q 'net.core.default_qdisc' /etc/sysctl.conf 2>/dev/null; } ;; + *) return 1 ;; + esac +} + +kpanel_system_tuning_collect() { + local canonical item state + TUNING_ITEMS=() + for item in system-update system-cleanup swap-1g ssh-port-5522 ssh-defense firewall-open-all bbr timezone-shanghai dns-auto ipv4-preferred basic-tools kernel-auto; do + state=pending + kpanel_system_tuning_item_ready "$item" && state=ready + TUNING_ITEMS+=("$item:$state") + done + canonical="$(mktemp /tmp/kejilion-system-tuning-version.XXXXXX)" || return 1 + printf '%s\n' "${TUNING_ITEMS[@]}" > "$canonical" + TUNING_VERSION="$(sha256sum -- "$canonical" 2>/dev/null | awk '{print $1}')" + rm -f -- "$canonical" + [[ "$TUNING_VERSION" =~ ^[0-9a-f]{64}$ ]] +} + +kpanel_system_tuning_emit() { + local status="$1" selected="${2:-}" item + kpanel_system_tuning_collect || { TUNING_VERSION="$(kpanel_system_resource_zero_version)"; TUNING_ITEMS=(); } + printf 'KPANEL_SYSTEM_TUNING_STATUS=%s\n' "$status" + printf 'KPANEL_SYSTEM_TUNING_VERSION=%s\n' "$TUNING_VERSION" + [ -z "$selected" ] || printf 'KPANEL_SYSTEM_TUNING_SELECTED=%s\n' "$selected" + for item in "${TUNING_ITEMS[@]}"; do printf 'KPANEL_SYSTEM_TUNING_ITEM=%s\n' "$item"; done +} + +kpanel_system_tuning_run_item() { + case "$1" in + system-update) kpanel_system_tuning_switch_mirror && linux_update ;; + system-cleanup) linux_clean ;; + swap-1g) add_swap 1024 ;; + ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; + ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; + firewall-open-all) kpanel_system_tuning_firewall_open_all ;; + bbr) bbr_on ;; + timezone-shanghai) set_timedate Asia/Shanghai ;; + dns-auto) auto_optimize_dns ;; + ipv4-preferred) prefer_ipv4 ;; + basic-tools) install_docker && install wget sudo tar unzip socat btop nano vim ;; + kernel-auto) kpanel_system_tuning_kernel_auto ;; + *) return 2 ;; + esac +} + +kpanel_system_tuning_apply_item() { + local item="$1" status=applied + if kpanel_system_tuning_item_ready "$item"; then + status=unchanged + elif ! kpanel_system_tuning_run_item "$item" >&2; then + kpanel_system_tuning_emit needs-attention "$item" + return 1 + fi + case "$item" in system-update|system-cleanup|dns-auto) ;; *) + kpanel_system_tuning_item_ready "$item" || { kpanel_system_tuning_emit needs-attention "$item"; return 1; } + ;; esac + kpanel_system_tuning_emit "$status" "$item" +} + +kpanel_system_tuning_dispatch() { + local action="${1:-status}" item lock_file + shift || true + printf '%s\n' "KPANEL_SYSTEM_TUNING_PROTOCOL 1" + [ "${KJ_SYSTEM_TUNING_NONINTERACTIVE:-}" = 1 ] || { kpanel_system_tuning_error "KPanel system-tuning 协议环境未启用"; return 2; } + [ "$EUID" -eq 0 ] || { kpanel_system_tuning_error "KPanel system-tuning 协议必须以 root 运行"; return 1; } + [ "$(uname -s)" = Linux ] || { kpanel_system_tuning_error "KPanel system-tuning 协议仅支持 Linux"; return 1; } + case "$action" in + status) [ "$#" -eq 0 ] || return 2; kpanel_system_tuning_emit ok; return $? ;; + apply-item) [ "$#" -eq 1 ] && kpanel_system_tuning_valid_item "$1" || return 2; item="$1" ;; + *) kpanel_system_tuning_error "用法: k kpanel system-tuning "; return 2 ;; + esac + lock_file="$(kpanel_system_resource_prepare_lock_file)" || { kpanel_system_tuning_emit failed "$item"; return 1; } + exec 9<>"$lock_file" || { kpanel_system_tuning_emit failed "$item"; return 1; } + if ! flock -w 5 9; then kpanel_system_tuning_emit conflict "$item"; return 2; fi + kpanel_system_tuning_apply_item "$item" +} + f2b_sshd() { if grep -q 'Alpine' /etc/issue; then xxx=alpine-sshd @@ -26838,52 +26989,51 @@ EOF clear send_stats "一条龙调优启动" echo "------------------------------------------------" - switch_mirror false false - linux_update + kpanel_system_tuning_run_item system-update echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" echo "------------------------------------------------" - linux_clean + kpanel_system_tuning_run_item system-cleanup echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" echo "------------------------------------------------" - add_swap 1024 + kpanel_system_tuning_run_item swap-1g echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" echo "------------------------------------------------" - new_ssh_port 5522 + kpanel_system_tuning_run_item ssh-port-5522 echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" echo "------------------------------------------------" - f2b_install_sshd + kpanel_system_tuning_run_item ssh-defense cd ~ f2b_status echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" echo "------------------------------------------------" + kpanel_system_tuning_run_item firewall-open-all echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" echo "------------------------------------------------" - bbr_on + kpanel_system_tuning_run_item bbr echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" echo "------------------------------------------------" - set_timedate Asia/Shanghai + kpanel_system_tuning_run_item timezone-shanghai echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" echo "------------------------------------------------" - auto_optimize_dns + kpanel_system_tuning_run_item dns-auto echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" echo "------------------------------------------------" - prefer_ipv4 + kpanel_system_tuning_run_item ipv4-preferred echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" echo "------------------------------------------------" - install_docker - install wget sudo tar unzip socat btop nano vim + kpanel_system_tuning_run_item basic-tools echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" echo "------------------------------------------------" - curl -sS ${gh_proxy}raw.githubusercontent.com/kejilion/sh/refs/heads/main/network-optimize.sh | bash + kpanel_system_tuning_run_item kernel-auto echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" @@ -28032,8 +28182,11 @@ else elif [ "${1:-}" = "account-management" ]; then shift kpanel_account_dispatch "$@" + elif [ "${1:-}" = "system-tuning" ]; then + shift + kpanel_system_tuning_dispatch "$@" else - echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ... | system-tuning ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh new file mode 100644 index 000000000..7790526ca --- /dev/null +++ b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +source_script="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" +temporary="$(mktemp -d)" +trap 'rm -rf -- "$temporary"' EXIT +script_path="$temporary/kejilion.sh" +sed 's/\r$//' "$source_script" > "$script_path" + +bash -n "$script_path" +grep -Fqx 'KPANEL_SYSTEM_TUNING_PROTOCOL_VERSION="1"' "$script_path" +[ "$(grep -Fxc 'KPANEL_SYSTEM_TUNING_PROTOCOL_VERSION="1"' "$script_path")" -eq 1 ] +grep -Fqx 'KPANEL_SYSTEM_TUNING_MIRROR_COMMIT="649e948763042e485e411be540d21c32cface1c1"' "$script_path" +grep -Fqx 'KPANEL_SYSTEM_TUNING_MIRROR_SHA256="2e3b78a460f10ef291f30e3cbf3d3b28a9521d6615364f11b36e4a70ec97d18d"' "$script_path" +grep -Fqx 'KPANEL_SYSTEM_TUNING_NETWORK_COMMIT="e9c3078eb516b05f9df6d2a9294cf3b226ca02bd"' "$script_path" +grep -Fqx 'KPANEL_SYSTEM_TUNING_NETWORK_SHA256="94f86598805b7a8155f444f35a446df4657985ef81b25f96f7799aa465033bbb"' "$script_path" +grep -F '[ "${KJ_SYSTEM_TUNING_NONINTERACTIVE:-}" = 1 ] ||' "$script_path" >/dev/null +grep -F 'kpanel_system_tuning_dispatch "$@"' "$script_path" >/dev/null + +functions="$(awk ' + /^KPANEL_SYSTEM_TUNING_PROTOCOL_VERSION=/ { capture=1 } + /^f2b_sshd\(\) \{/ { exit } + capture { print } +' "$script_path")" +eval "$functions" + +kpanel_system_resource_zero_version() { printf '%064d\n' 0; } +: > "$temporary/ready-items" +kpanel_system_tuning_item_ready() { grep -Fxq "$1" "$temporary/ready-items"; } +kpanel_system_tuning_run_item() { printf '%s\n' "$1" >> "$temporary/run-items"; printf '%s\n' "$1" >> "$temporary/ready-items"; } + +status_output="$(kpanel_system_tuning_emit ok)" +grep -F 'KPANEL_SYSTEM_TUNING_STATUS=ok' <<< "$status_output" >/dev/null +[ "$(grep -c '^KPANEL_SYSTEM_TUNING_ITEM=' <<< "$status_output")" -eq 12 ] +for item in system-update system-cleanup swap-1g ssh-port-5522 ssh-defense firewall-open-all bbr timezone-shanghai dns-auto ipv4-preferred basic-tools kernel-auto; do + grep -F "KPANEL_SYSTEM_TUNING_ITEM=$item:pending" <<< "$status_output" >/dev/null + kpanel_system_tuning_valid_item "$item" +done +version="$(grep '^KPANEL_SYSTEM_TUNING_VERSION=' <<< "$status_output" | cut -d= -f2)" +[[ "$version" =~ ^[0-9a-f]{64}$ ]] +! kpanel_system_tuning_valid_item arbitrary-command + +apply_output="$(kpanel_system_tuning_apply_item bbr)" +grep -F 'KPANEL_SYSTEM_TUNING_STATUS=applied' <<< "$apply_output" >/dev/null +grep -F 'KPANEL_SYSTEM_TUNING_SELECTED=bbr' <<< "$apply_output" >/dev/null +grep -F 'KPANEL_SYSTEM_TUNING_ITEM=bbr:ready' <<< "$apply_output" >/dev/null +grep -Fx bbr "$temporary/run-items" >/dev/null + +unchanged_output="$(kpanel_system_tuning_apply_item bbr)" +grep -F 'KPANEL_SYSTEM_TUNING_STATUS=unchanged' <<< "$unchanged_output" >/dev/null +[ "$(grep -Fxc bbr "$temporary/run-items")" -eq 1 ] + +kpanel_system_tuning_run_item() { return 1; } +if kpanel_system_tuning_apply_item ssh-defense > "$temporary/failure.out" 2>/dev/null; then + echo "failed item unexpectedly succeeded" >&2 + exit 1 +fi +grep -F 'KPANEL_SYSTEM_TUNING_STATUS=needs-attention' "$temporary/failure.out" >/dev/null +grep -F 'KPANEL_SYSTEM_TUNING_SELECTED=ssh-defense' "$temporary/failure.out" >/dev/null + +printf 'fixture\n' > "$temporary/source" +source_hash="$(sha256sum "$temporary/source" | awk '{print $1}')" +curl() { + while [ "$#" -gt 0 ]; do + [ "$1" = --output ] && { cp -- "$temporary/source" "$2"; return; } + shift + done + return 1 +} +kpanel_system_tuning_download_verified https://example.invalid/source "$source_hash" "$temporary/downloaded" +if kpanel_system_tuning_download_verified https://example.invalid/source "$(kpanel_system_resource_zero_version)" "$temporary/rejected"; then + echo "wrong external source digest unexpectedly accepted" >&2 + exit 1 +fi + +printf '%s\n' 'kpanel_system_tuning_noninteractive_smoke=pass' From 73c9090862778050be43c95df01ac1097d4b7296 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 10:58:13 +0800 Subject: [PATCH 1265/1285] feat(app): add lightweight DeepSeek Hermes manager --- cn/kejilion.sh | 6 +- deepseek_hermes_manager.sh | 464 ++++++++++++++++++++++++++ kejilion.sh | 6 +- tests/test_deepseek_hermes_manager.sh | 45 +++ 4 files changed, 519 insertions(+), 2 deletions(-) create mode 100644 deepseek_hermes_manager.sh create mode 100644 tests/test_deepseek_hermes_manager.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7ccf7471a..a65427da9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Hermes基础轻量版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -22263,6 +22263,10 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) ;; + 116|deepseek-hermes|DeepSeek-Hermes|ds-hermes) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_hermes_manager.sh) + ;; + b) clear send_stats "全部应用备份" diff --git a/deepseek_hermes_manager.sh b/deepseek_hermes_manager.sh new file mode 100644 index 000000000..b2712327d --- /dev/null +++ b/deepseek_hermes_manager.sh @@ -0,0 +1,464 @@ +#!/bin/bash +# DeepSeek Hermes 终端管理脚本(基础轻量版) +# 仅提供:安装、启动、停止、API 管理、切换模型、命令行聊天、更新、卸载。 + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +HERMES_DATA_DIR="${HERMES_HOME:-$HOME/.hermes}" +HERMES_ENV_FILE="${HERMES_DATA_DIR}/.env" +HERMES_INSTALLER_URL="https://hermes-agent.nousresearch.com/install.sh" +DEEPSEEK_BASE_URL="https://api.deepseek.com" +DEFAULT_DEEPSEEK_MODEL="deepseek-v4-pro" +APP_ID="116" + +refresh_hermes_path() { + local candidate + for candidate in \ + "/usr/local/bin" \ + "$HOME/.local/bin" \ + "$HERMES_DATA_DIR/hermes-agent/venv/bin"; do + [ -d "$candidate" ] || continue + case ":$PATH:" in + *":$candidate:"*) ;; + *) PATH="$candidate:$PATH" ;; + esac + done + export PATH + hash -r 2>/dev/null || true +} + +hermes_installed() { + refresh_hermes_path + command -v hermes >/dev/null 2>&1 +} + +hermes_running() { + if command -v systemctl >/dev/null 2>&1 \ + && systemctl --user is-active --quiet hermes-gateway.service 2>/dev/null; then + return 0 + fi + pgrep -u "$(id -u)" -f '(hermes_cli\.main.*gateway|hermes[[:space:]]+gateway[[:space:]]+(run|start)|hermes-gateway)' >/dev/null 2>&1 +} + +read_deepseek_api_key() { + [ -r "$HERMES_ENV_FILE" ] || return 1 + sed -n 's/^[[:space:]]*DEEPSEEK_API_KEY=//p' "$HERMES_ENV_FILE" \ + | tail -n 1 \ + | sed 's/^"//;s/"$//;s/^'"'"'//;s/'"'"'$//' +} + +mask_api_key() { + local api_key="$1" + local key_length=${#api_key} + if [ "$key_length" -le 8 ]; then + printf '%s' '********' + else + printf '%s****%s' "${api_key:0:3}" "${api_key: -4}" + fi +} + +write_deepseek_api_key() { + local api_key="$1" + local temporary_file + + mkdir -p "$HERMES_DATA_DIR" || return 1 + umask 077 + temporary_file=$(mktemp "${HERMES_ENV_FILE}.tmp.XXXXXX") || return 1 + if [ -f "$HERMES_ENV_FILE" ]; then + grep -v '^[[:space:]]*DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE" > "$temporary_file" || true + fi + printf 'DEEPSEEK_API_KEY=%s\n' "$api_key" >> "$temporary_file" + mv -f -- "$temporary_file" "$HERMES_ENV_FILE" + chmod 600 "$HERMES_ENV_FILE" +} + +delete_deepseek_api_key() { + local temporary_file + [ -f "$HERMES_ENV_FILE" ] || return 0 + umask 077 + temporary_file=$(mktemp "${HERMES_ENV_FILE}.tmp.XXXXXX") || return 1 + grep -v '^[[:space:]]*DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE" > "$temporary_file" || true + mv -f -- "$temporary_file" "$HERMES_ENV_FILE" + chmod 600 "$HERMES_ENV_FILE" +} + +current_model() { + local model_name + hermes_installed || return 0 + model_name=$(hermes config get model.default 2>/dev/null | tail -n 1 | tr -d '"' | xargs) + if [ -z "$model_name" ] || [ "$model_name" = "null" ]; then + model_name=$(hermes config get model.model 2>/dev/null | tail -n 1 | tr -d '"' | xargs) + fi + [ "$model_name" = "null" ] && model_name="" + printf '%s' "$model_name" +} + +current_provider() { + local provider_name + hermes_installed || return 0 + provider_name=$(hermes config get model.provider 2>/dev/null | tail -n 1 | tr -d '"' | xargs) + [ "$provider_name" = "null" ] && provider_name="" + printf '%s' "$provider_name" +} + +apply_deepseek_model() { + local model_name="$1" + local restart_gateway="${2:-true}" + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + if [ -z "$model_name" ]; then + echo -e "${RED}模型 ID 不能为空。${NC}" + return 1 + fi + + hermes config set model.provider deepseek || return 1 + hermes config set model.default "$model_name" || return 1 + hermes config set model.base_url "$DEEPSEEK_BASE_URL" || return 1 + echo -e "${GREEN}模型已切换为:${model_name}${NC}" + + if [ "$restart_gateway" = "true" ] && hermes_running; then + echo -e "${YELLOW}正在重启 Gateway 以应用新模型...${NC}" + hermes gateway restart + fi +} + +ensure_default_model() { + local model_name provider_name restart_gateway + restart_gateway="${1:-true}" + model_name=$(current_model) + provider_name=$(current_provider) + if [ "$provider_name" = "deepseek" ] && [ -n "$model_name" ]; then + return 0 + fi + case "$model_name" in + deepseek-*) ;; + *) model_name="$DEFAULT_DEEPSEEK_MODEL" ;; + esac + apply_deepseek_model "$model_name" "$restart_gateway" +} + +mark_app_installed() { + mkdir -p /home/docker 2>/dev/null || return 0 + touch /home/docker/appno.txt 2>/dev/null || return 0 + grep -qxF "$APP_ID" /home/docker/appno.txt 2>/dev/null \ + || echo "$APP_ID" >> /home/docker/appno.txt +} + +unmark_app_installed() { + [ -f /home/docker/appno.txt ] || return 0 + sed -i "/^${APP_ID}$/d" /home/docker/appno.txt +} + +install_prerequisites() { + if command -v git >/dev/null 2>&1 \ + && command -v curl >/dev/null 2>&1 \ + && command -v xz >/dev/null 2>&1; then + return 0 + fi + + echo -e "${YELLOW}正在安装 Git、curl 和 xz...${NC}" + if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y git curl xz-utils ca-certificates + elif command -v dnf >/dev/null 2>&1; then + dnf install -y git curl xz ca-certificates + elif command -v yum >/dev/null 2>&1; then + yum install -y git curl xz ca-certificates + elif command -v apk >/dev/null 2>&1; then + apk add git curl xz ca-certificates + elif command -v pacman >/dev/null 2>&1; then + pacman -Sy --noconfirm git curl xz ca-certificates + elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive install git curl xz ca-certificates + else + echo -e "${RED}未识别到支持的软件包管理器,请手动安装 git、curl、xz。${NC}" + return 1 + fi +} + +install_deepseek_hermes() { + local installer_file + if hermes_installed; then + echo -e "${YELLOW}Hermes 已安装,无需重复安装。${NC}" + mark_app_installed + return 0 + fi + + install_prerequisites || return 1 + installer_file=$(mktemp) || return 1 + echo -e "${YELLOW}正在下载并安装 Hermes 基础轻量版...${NC}" + if ! curl -fsSL "$HERMES_INSTALLER_URL" -o "$installer_file"; then + rm -f -- "$installer_file" + echo -e "${RED}Hermes 安装脚本下载失败。${NC}" + return 1 + fi + + if ! bash "$installer_file" \ + --skip-setup \ + --skip-browser \ + --skip-computer-use \ + --no-skills; then + rm -f -- "$installer_file" + echo -e "${RED}Hermes 安装失败,请检查上方输出。${NC}" + return 1 + fi + rm -f -- "$installer_file" + refresh_hermes_path + + if ! hermes_installed; then + echo -e "${RED}安装程序已结束,但未找到 hermes 命令。${NC}" + return 1 + fi + + mark_app_installed + echo -e "${GREEN}DeepSeek Hermes 基础轻量版安装完成。${NC}" + echo "下一步请进入“API 管理”设置 DeepSeek API Key,再启动或聊天。" +} + +start_deepseek_hermes() { + local api_key + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + api_key=$(read_deepseek_api_key) + if [ -z "$api_key" ]; then + echo -e "${RED}尚未配置 DeepSeek API Key,请先进入 API 管理。${NC}" + return 1 + fi + ensure_default_model false || return 1 + + echo -e "${YELLOW}正在启动 Hermes Gateway...${NC}" + hermes gateway install >/dev/null 2>&1 || true + if hermes gateway start; then + mark_app_installed + echo -e "${GREEN}Hermes Gateway 已启动。${NC}" + else + echo -e "${RED}Gateway 启动失败,请查看上方输出。${NC}" + return 1 + fi +} + +stop_deepseek_hermes() { + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + echo -e "${YELLOW}正在停止 Hermes Gateway...${NC}" + hermes gateway stop +} + +api_management_menu() { + local choice api_key confirm + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + + while true; do + clear + api_key=$(read_deepseek_api_key) + echo -e "${CYAN}=======================================${NC}" + echo " DeepSeek API 管理" + echo -e "${CYAN}=======================================${NC}" + if [ -n "$api_key" ]; then + echo -e "API 状态:${GREEN}已配置 $(mask_api_key "$api_key")${NC}" + else + echo -e "API 状态:${RED}未配置${NC}" + fi + echo "Base URL:$DEEPSEEK_BASE_URL" + echo "---------------------------------------" + echo "1. 设置或更换 API Key" + echo "2. 删除 API Key" + echo "0. 返回" + read -r -p "请输入选项: " choice + + case "$choice" in + 1) + read -r -s -p "请输入 DeepSeek API Key: " api_key + echo + if [ -z "$api_key" ]; then + echo -e "${RED}API Key 不能为空。${NC}" + elif write_deepseek_api_key "$api_key"; then + if ensure_default_model false; then + if hermes_running; then + hermes gateway restart + fi + echo -e "${GREEN}DeepSeek API Key 已安全保存。${NC}" + else + echo -e "${YELLOW}API Key 已保存,但 DeepSeek 模型配置失败。${NC}" + fi + else + echo -e "${RED}API Key 保存失败。${NC}" + fi + read -r -p "按回车键继续..." + ;; + 2) + read -r -p "确定删除 DeepSeek API Key?(y/N): " confirm + case "$confirm" in + [yY]) + if hermes_running; then + hermes gateway stop >/dev/null 2>&1 || true + fi + delete_deepseek_api_key + echo -e "${GREEN}DeepSeek API Key 已删除。${NC}" + ;; + *) echo "已取消。" ;; + esac + read -r -p "按回车键继续..." + ;; + 0) return 0 ;; + *) sleep 1 ;; + esac + done +} + +change_deepseek_model() { + local choice model_name + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + + echo "当前模型:$(current_model)" + echo "1. deepseek-v4-pro" + echo "2. deepseek-v4-flash" + echo "3. 手动输入模型 ID" + echo "0. 取消" + read -r -p "请选择模型: " choice + case "$choice" in + 1) model_name="deepseek-v4-pro" ;; + 2) model_name="deepseek-v4-flash" ;; + 3) read -r -p "请输入模型 ID: " model_name ;; + 0) return 0 ;; + *) echo -e "${RED}无效选项。${NC}"; return 1 ;; + esac + apply_deepseek_model "$model_name" +} + +chat_with_deepseek_hermes() { + local api_key + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + api_key=$(read_deepseek_api_key) + if [ -z "$api_key" ]; then + echo -e "${RED}尚未配置 DeepSeek API Key,请先进入 API 管理。${NC}" + return 1 + fi + ensure_default_model || return 1 + echo -e "${YELLOW}正在进入 Hermes 命令行聊天,退出后将返回本菜单。${NC}" + hermes +} + +update_deepseek_hermes() { + if ! hermes_installed; then + echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" + return 1 + fi + echo -e "${YELLOW}正在更新 Hermes...${NC}" + if hermes update; then + mark_app_installed + echo -e "${GREEN}Hermes 更新完成。${NC}" + fi +} + +uninstall_deepseek_hermes() { + local confirm + if ! hermes_installed; then + echo -e "${YELLOW}Hermes 未安装。${NC}" + unmark_app_installed + return 0 + fi + + read -r -p "确定卸载 Hermes?官方卸载器会询问是否保留配置。(y/N): " confirm + case "$confirm" in + [yY]) ;; + *) echo "已取消。"; return 0 ;; + esac + + hermes gateway stop >/dev/null 2>&1 || true + hermes uninstall + refresh_hermes_path + if hermes_installed; then + echo -e "${YELLOW}仍检测到 hermes 命令,未移除应用市场安装标记。${NC}" + return 1 + fi + unmark_app_installed + echo -e "${GREEN}Hermes 已卸载。${NC}" +} + +show_menu() { + local install_status running_status model_name api_key + if hermes_installed; then + install_status="${GREEN}已安装${NC}" + model_name=$(current_model) + [ -n "$model_name" ] || model_name="未配置" + if hermes_running; then + running_status="${GREEN}运行中${NC}" + else + running_status="${YELLOW}已停止${NC}" + fi + else + install_status="${RED}未安装${NC}" + running_status="${RED}未运行${NC}" + model_name="未配置" + fi + api_key=$(read_deepseek_api_key) + + clear + echo -e "${CYAN}=================================================${NC}" + echo " DeepSeek Hermes 基础轻量管理工具" + echo -e "${CYAN}=================================================${NC}" + echo -e "安装状态:${install_status} 运行状态:${running_status}" + echo "当前模型:${model_name}" + if [ -n "$api_key" ]; then + echo -e "API 状态:${GREEN}已配置 $(mask_api_key "$api_key")${NC}" + else + echo -e "API 状态:${RED}未配置${NC}" + fi + echo -e "${CYAN}-------------------------------------------------${NC}" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" + echo "4. API 管理" + echo "5. 换模型" + echo "6. 命令行聊天" + echo "7. 更新" + echo "8. 卸载" + echo "0. 返回应用市场" + echo -e "${CYAN}=================================================${NC}" +} + +deepseek_hermes_main() { + local menu_choice + refresh_hermes_path + while true; do + show_menu + read -r -p "请输入选项 [0-8]: " menu_choice || return 0 + case "$menu_choice" in + 1) install_deepseek_hermes ;; + 2) start_deepseek_hermes ;; + 3) stop_deepseek_hermes ;; + 4) api_management_menu ;; + 5) change_deepseek_model ;; + 6) chat_with_deepseek_hermes ;; + 7) update_deepseek_hermes ;; + 8) uninstall_deepseek_hermes ;; + 0) return 0 ;; + *) echo -e "${RED}无效选项。${NC}" ;; + esac + echo + read -r -p "按回车键返回菜单..." + done +} + +if [ "${BASH_SOURCE[0]}" = "$0" ]; then + deepseek_hermes_main +fi diff --git a/kejilion.sh b/kejilion.sh index 59ceebbe3..56e654cd5 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Hermes基础轻量版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -22263,6 +22263,10 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) ;; + 116|deepseek-hermes|DeepSeek-Hermes|ds-hermes) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_hermes_manager.sh) + ;; + b) clear send_stats "全部应用备份" diff --git a/tests/test_deepseek_hermes_manager.sh b/tests/test_deepseek_hermes_manager.sh new file mode 100644 index 000000000..fab3d007f --- /dev/null +++ b/tests/test_deepseek_hermes_manager.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -euo pipefail + +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +temporary_dir="$(mktemp -d)" +trap 'rm -rf -- "${temporary_dir}"' EXIT + +export HOME="${temporary_dir}/home" +export HERMES_HOME="${HOME}/.hermes" +export PATH="${temporary_dir}/bin:${PATH}" +export MOCK_HERMES_LOG="${temporary_dir}/hermes.log" +mkdir -p "$HERMES_HOME" "${temporary_dir}/bin" + +cat >"${temporary_dir}/bin/hermes" <<'MOCK' +#!/bin/bash +printf '%s\n' "$*" >>"$MOCK_HERMES_LOG" +if [ "$*" = "config get model.default" ]; then + printf '%s\n' 'deepseek-v4-pro' +fi +MOCK +chmod +x "${temporary_dir}/bin/hermes" + +# shellcheck source=../deepseek_hermes_manager.sh +source "${project_root}/deepseek_hermes_manager.sh" + +printf '%s\n' 'OTHER_KEY=keep-me' >"$HERMES_ENV_FILE" +write_deepseek_api_key 'sk-test-secret-1234' +grep -qxF 'OTHER_KEY=keep-me' "$HERMES_ENV_FILE" +grep -qxF 'DEEPSEEK_API_KEY=sk-test-secret-1234' "$HERMES_ENV_FILE" +[ "$(stat -c '%a' "$HERMES_ENV_FILE")" = "600" ] +[ "$(mask_api_key 'sk-test-secret-1234')" = 'sk-****1234' ] + +delete_deepseek_api_key +grep -qxF 'OTHER_KEY=keep-me' "$HERMES_ENV_FILE" +if grep -q '^DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE"; then + echo 'FAIL: DeepSeek API key was not deleted' >&2 + exit 1 +fi + +apply_deepseek_model 'deepseek-v4-flash' +grep -qxF 'config set model.provider deepseek' "$MOCK_HERMES_LOG" +grep -qxF 'config set model.default deepseek-v4-flash' "$MOCK_HERMES_LOG" +grep -qxF 'config set model.base_url https://api.deepseek.com' "$MOCK_HERMES_LOG" + +echo 'PASS: DeepSeek Hermes manager smoke tests' From 601594897e8c74377331577c0e219a93af1dbfbc Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 11:15:25 +0800 Subject: [PATCH 1266/1285] fix(hermes): report stopped gateway correctly --- deepseek_hermes_manager.sh | 3 ++- tests/test_deepseek_hermes_manager.sh | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/deepseek_hermes_manager.sh b/deepseek_hermes_manager.sh index b2712327d..bcd35a80c 100644 --- a/deepseek_hermes_manager.sh +++ b/deepseek_hermes_manager.sh @@ -41,7 +41,8 @@ hermes_running() { && systemctl --user is-active --quiet hermes-gateway.service 2>/dev/null; then return 0 fi - pgrep -u "$(id -u)" -f '(hermes_cli\.main.*gateway|hermes[[:space:]]+gateway[[:space:]]+(run|start)|hermes-gateway)' >/dev/null 2>&1 + # The bracketed first character prevents pgrep from matching its own argv. + pgrep -u "$(id -u)" -f '[p]ython([^[:space:]]*)?[[:space:]]+-m[[:space:]]+hermes_cli\.main[[:space:]]+gateway[[:space:]]+run([[:space:]]|$)' >/dev/null 2>&1 } read_deepseek_api_key() { diff --git a/tests/test_deepseek_hermes_manager.sh b/tests/test_deepseek_hermes_manager.sh index fab3d007f..b5bdfb432 100644 --- a/tests/test_deepseek_hermes_manager.sh +++ b/tests/test_deepseek_hermes_manager.sh @@ -42,4 +42,9 @@ grep -qxF 'config set model.provider deepseek' "$MOCK_HERMES_LOG" grep -qxF 'config set model.default deepseek-v4-flash' "$MOCK_HERMES_LOG" grep -qxF 'config set model.base_url https://api.deepseek.com' "$MOCK_HERMES_LOG" +if hermes_running; then + echo 'FAIL: stopped gateway was reported as running by the pgrep fallback' >&2 + exit 1 +fi + echo 'PASS: DeepSeek Hermes manager smoke tests' From a7db8ead4dc3b1d26938ebbf872f018de86762f0 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 12:35:17 +0800 Subject: [PATCH 1267/1285] fix(app): replace Hermes option with DeepSeek Harness --- cn/kejilion.sh | 6 +- deepseek_harness_manager.sh | 547 +++++++++++++++++++++++++ deepseek_hermes_manager.sh | 465 --------------------- kejilion.sh | 6 +- tests/test_deepseek_harness_manager.sh | 97 +++++ tests/test_deepseek_hermes_manager.sh | 50 --- 6 files changed, 650 insertions(+), 521 deletions(-) create mode 100644 deepseek_harness_manager.sh delete mode 100644 deepseek_hermes_manager.sh create mode 100644 tests/test_deepseek_harness_manager.sh delete mode 100644 tests/test_deepseek_hermes_manager.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a65427da9..3caa9ce88 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Hermes基础轻量版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness基础版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -22263,8 +22263,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) ;; - 116|deepseek-hermes|DeepSeek-Hermes|ds-hermes) - bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_hermes_manager.sh) + 116|deepseek-harness|DeepSeek-Harness|dsh) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_harness_manager.sh) ;; b) diff --git a/deepseek_harness_manager.sh b/deepseek_harness_manager.sh new file mode 100644 index 000000000..6b949853b --- /dev/null +++ b/deepseek_harness_manager.sh @@ -0,0 +1,547 @@ +#!/bin/bash +# DeepSeek Harness 管理脚本(基础版) +# 官方项目:https://github.com/deepseek-ai/deepseek-harness +# 仅提供:安装、启动、停止、API 管理、切换模型、命令行任务、更新、卸载。 + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +DSH_HOME="${DSH_HOME:-$HOME/.dsh}" +DSH_ENV_FILE="${DSH_ENV_FILE:-$DSH_HOME/kejilion.env}" +MODEL_PATCH_FILE="${MODEL_PATCH_FILE:-$DSH_HOME/kejilion-model.patch.yml}" +SERVICE_FILE="${DEEPSEEK_HARNESS_SERVICE_FILE:-/etc/systemd/system/deepseek-harness.service}" +PID_FILE="${DEEPSEEK_HARNESS_PID_FILE:-$DSH_HOME/deepseek-harness.pid}" +LOG_FILE="${DEEPSEEK_HARNESS_LOG_FILE:-$DSH_HOME/deepseek-harness.log}" +APP_MARKER_FILE="${DEEPSEEK_HARNESS_APP_MARKER_FILE:-/home/docker/appno.txt}" +NPM_PACKAGE="@deepseek-ai/dsh" +DEEPSEEK_BASE_URL="https://api.deepseek.com" +DEFAULT_MODEL="deepseek-v4-flash" +LISTEN_HOST="127.0.0.1" +LISTEN_PORT="3080" +APP_ID="116" + +require_root() { + if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}此操作需要 root 权限。${NC}" + return 1 + fi +} + +dsh_installed() { + hash -r 2>/dev/null || true + command -v dsh >/dev/null 2>&1 +} + +node_version_supported() { + local version major minor + command -v node >/dev/null 2>&1 || return 1 + version=$(node -p 'process.versions.node' 2>/dev/null) || return 1 + major=${version%%.*} + minor=${version#*.} + minor=${minor%%.*} + case "$major:$minor" in + 22:*) [ "$minor" -ge 19 ] ;; + *) [ "$major" -ge 24 ] ;; + esac +} + +systemd_available() { + command -v systemctl >/dev/null 2>&1 \ + && [ "$(ps -p 1 -o comm= 2>/dev/null | tr -d '[:space:]')" = "systemd" ] +} + +harness_running() { + if systemd_available \ + && systemctl is-active --quiet deepseek-harness.service 2>/dev/null; then + return 0 + fi + if [ -r "$PID_FILE" ]; then + local pid + pid=$(cat "$PID_FILE" 2>/dev/null) + case "$pid" in + ''|*[!0-9]*) ;; + *) kill -0 "$pid" 2>/dev/null && return 0 ;; + esac + fi + pgrep -u "$(id -u)" -f '[n]ode.*[/]dsh.*([[:space:]]web|--profile[[:space:]]+web)' >/dev/null 2>&1 +} + +web_ready() { + command -v curl >/dev/null 2>&1 \ + && curl -fsS --max-time 2 "http://${LISTEN_HOST}:${LISTEN_PORT}/" >/dev/null 2>&1 +} + +wait_for_web_ready() { + local _ + for _ in {1..30}; do + harness_running && web_ready && return 0 + sleep 1 + done + return 1 +} + +read_api_key() { + [ -r "$DSH_ENV_FILE" ] || return 1 + sed -n 's/^DEEPSEEK_API_KEY=//p' "$DSH_ENV_FILE" | tail -n 1 +} + +mask_api_key() { + local api_key="$1" + if [ "${#api_key}" -le 8 ]; then + printf '%s' '********' + else + printf '%s****%s' "${api_key:0:3}" "${api_key: -4}" + fi +} + +valid_api_key() { + [[ "$1" =~ ^sk-[A-Za-z0-9._-]+$ ]] +} + +write_api_key() { + local api_key="$1" temporary_file + valid_api_key "$api_key" || return 1 + mkdir -p "$DSH_HOME" || return 1 + umask 077 + temporary_file=$(mktemp "${DSH_ENV_FILE}.tmp.XXXXXX") || return 1 + { + printf 'DEEPSEEK_API_KEY=%s\n' "$api_key" + printf 'DEEPSEEK_BASE_URL=%s\n' "$DEEPSEEK_BASE_URL" + } >"$temporary_file" + chmod 600 "$temporary_file" + mv -f "$temporary_file" "$DSH_ENV_FILE" +} + +delete_api_key() { + [ -e "$DSH_ENV_FILE" ] || return 0 + : >"$DSH_ENV_FILE" + chmod 600 "$DSH_ENV_FILE" +} + +load_managed_environment() { + export DSH_HOME DSH_TELEMETRY_DISABLED=1 + if [ -r "$DSH_ENV_FILE" ]; then + set -a + # shellcheck disable=SC1090 + . "$DSH_ENV_FILE" + set +a + fi +} + +valid_model_id() { + case "$1" in + ''|*[!A-Za-z0-9._:/-]*) return 1 ;; + *) return 0 ;; + esac +} + +current_model() { + local model + if [ -r "$MODEL_PATCH_FILE" ]; then + model=$(sed -n 's/^[[:space:]]*model:[[:space:]]*//p' "$MODEL_PATCH_FILE" | tail -n 1) + fi + printf '%s' "${model:-$DEFAULT_MODEL}" +} + +write_model_patch() { + local model="$1" temporary_file + valid_model_id "$model" || return 1 + mkdir -p "$DSH_HOME" || return 1 + umask 077 + temporary_file=$(mktemp "${MODEL_PATCH_FILE}.tmp.XXXXXX") || return 1 + { + printf '%s\n' '- id: agent-default-model' + printf '%s\n' ' config:' + printf '%s\n' ' provider: deepseek-official' + printf ' model: %s\n' "$model" + } >"$temporary_file" + chmod 600 "$temporary_file" + mv -f "$temporary_file" "$MODEL_PATCH_FILE" +} + +mark_app_installed() { + mkdir -p "$(dirname "$APP_MARKER_FILE")" 2>/dev/null || return 0 + touch "$APP_MARKER_FILE" 2>/dev/null || return 0 + grep -qxF "$APP_ID" "$APP_MARKER_FILE" 2>/dev/null || echo "$APP_ID" >>"$APP_MARKER_FILE" +} + +unmark_app_installed() { + [ -f "$APP_MARKER_FILE" ] || return 0 + sed -i "/^${APP_ID}$/d" "$APP_MARKER_FILE" +} + +install_node24() { + require_root || return 1 + command -v curl >/dev/null 2>&1 || { + echo -e "${RED}缺少 curl,无法安装 Node.js。${NC}" + return 1 + } + echo -e "${YELLOW}正在安装 Node.js 24...${NC}" + if command -v apt-get >/dev/null 2>&1; then + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - || return 1 + apt-get install -y nodejs || return 1 + elif command -v dnf >/dev/null 2>&1; then + curl -fsSL https://rpm.nodesource.com/setup_24.x | bash - || return 1 + dnf install -y nodejs || return 1 + else + echo -e "${RED}当前系统不支持自动安装 Node.js,请先安装 Node.js 22.19+ 或 24+。${NC}" + return 1 + fi + node_version_supported +} + +ensure_node_runtime() { + if node_version_supported && command -v npm >/dev/null 2>&1; then + return 0 + fi + install_node24 +} + +configure_systemd_service() { + local dsh_bin node_bin service_path + dsh_bin=$(command -v dsh) || return 1 + node_bin=$(command -v node) || return 1 + service_path="$(dirname "$dsh_bin"):$(dirname "$node_bin"):/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + mkdir -p "$DSH_HOME" || return 1 + cat >"$SERVICE_FILE" </dev/null || return 1 + dsh web --dump-default-config >/dev/null || return 1 +} + +install_deepseek_harness() { + require_root || return 1 + if dsh_installed; then + echo -e "${YELLOW}DeepSeek Harness 已安装,可使用更新功能升级。${NC}" + mark_app_installed + return 0 + fi + ensure_node_runtime || return 1 + echo -e "${YELLOW}正在安装官方 $NPM_PACKAGE,首次安装可能需要数分钟...${NC}" + npm install -g "${NPM_PACKAGE}@latest" || return 1 + dsh_installed || { + echo -e "${RED}安装完成后仍找不到 dsh 命令。${NC}" + return 1 + } + [ -f "$MODEL_PATCH_FILE" ] || write_model_patch "$DEFAULT_MODEL" || return 1 + initialize_profiles || return 1 + if systemd_available; then + configure_systemd_service || return 1 + fi + mark_app_installed + echo -e "${GREEN}DeepSeek Harness 安装完成:$(dsh --version 2>/dev/null)${NC}" + echo "默认模型:$(current_model)" + echo "Web UI 默认仅监听:http://${LISTEN_HOST}:${LISTEN_PORT}" + echo "安装后不会自动启动,请返回菜单选择启动。" +} + +start_deepseek_harness() { + require_root || return 1 + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + [ -f "$MODEL_PATCH_FILE" ] || write_model_patch "$DEFAULT_MODEL" || return 1 + if systemd_available; then + configure_systemd_service || return 1 + systemctl enable --now deepseek-harness.service || return 1 + else + if harness_running; then + echo -e "${YELLOW}DeepSeek Harness 已在运行。${NC}" + return 0 + fi + mkdir -p "$DSH_HOME" + load_managed_environment + nohup dsh web --patch "$MODEL_PATCH_FILE" --host "$LISTEN_HOST" --port "$LISTEN_PORT" >"$LOG_FILE" 2>&1 & + echo "$!" >"$PID_FILE" + fi + if wait_for_web_ready; then + mark_app_installed + echo -e "${GREEN}DeepSeek Harness 已启动。${NC}" + echo "本机访问:http://${LISTEN_HOST}:${LISTEN_PORT}" + echo "远程访问建议:ssh -L ${LISTEN_PORT}:${LISTEN_HOST}:${LISTEN_PORT} <服务器>" + else + echo -e "${RED}启动失败,请检查 $LOG_FILE 或 systemctl status deepseek-harness。${NC}" + return 1 + fi +} + +stop_deepseek_harness() { + require_root || return 1 + if systemd_available && [ -f "$SERVICE_FILE" ]; then + systemctl disable --now deepseek-harness.service >/dev/null 2>&1 || true + fi + if [ -r "$PID_FILE" ]; then + local pid + pid=$(cat "$PID_FILE" 2>/dev/null) + case "$pid" in + ''|*[!0-9]*) ;; + *) kill "$pid" 2>/dev/null || true ;; + esac + rm -f -- "$PID_FILE" + fi + sleep 1 + if harness_running; then + echo -e "${RED}DeepSeek Harness 仍在运行,请检查残留进程。${NC}" + return 1 + fi + echo -e "${GREEN}DeepSeek Harness 已停止,并取消开机启动。${NC}" +} + +restart_if_running() { + local was_running=false + harness_running && was_running=true + [ "$was_running" = "true" ] || return 0 + if systemd_available && [ -f "$SERVICE_FILE" ]; then + configure_systemd_service \ + && systemctl restart deepseek-harness.service \ + && wait_for_web_ready + else + stop_deepseek_harness && start_deepseek_harness + fi +} + +api_management_menu() { + local choice api_key confirm was_running + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + while true; do + clear 2>/dev/null || true + api_key=$(read_api_key) + echo -e "${CYAN}=======================================${NC}" + echo " DeepSeek Harness API 管理" + echo -e "${CYAN}=======================================${NC}" + if [ -n "$api_key" ]; then + echo -e "脚本托管 API:${GREEN}已配置 $(mask_api_key "$api_key")${NC}" + else + echo -e "脚本托管 API:${RED}未配置${NC}" + fi + echo "Base URL:$DEEPSEEK_BASE_URL" + echo "1. 设置或更换 API Key" + echo "2. 删除脚本托管 API Key" + echo "0. 返回" + read -r -p "请输入选项: " choice + case "$choice" in + 1) + read -r -s -p "请输入 DeepSeek API Key: " api_key + echo + if ! valid_api_key "$api_key"; then + echo -e "${RED}API Key 格式无效,应以 sk- 开头且不能包含空格。${NC}" + else + harness_running && was_running=true || was_running=false + if write_api_key "$api_key"; then + [ "$was_running" = "true" ] && restart_if_running + echo -e "${GREEN}API Key 已保存,文件权限为 600。${NC}" + fi + fi + read -r -p "按回车键继续..." + ;; + 2) + read -r -p "确定删除脚本托管的 API Key?(y/N): " confirm + case "$confirm" in + [yY]) + harness_running && was_running=true || was_running=false + delete_api_key + [ "$was_running" = "true" ] && restart_if_running + echo -e "${GREEN}脚本托管 API Key 已删除。${NC}" + ;; + *) echo "已取消。" ;; + esac + read -r -p "按回车键继续..." + ;; + 0) return 0 ;; + esac + done +} + +change_model() { + local choice model + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + echo "当前默认模型:$(current_model)" + echo "1. deepseek-v4-flash" + echo "2. deepseek-v4-pro" + echo "3. 手动输入模型 ID" + echo "0. 取消" + read -r -p "请选择模型: " choice + case "$choice" in + 1) model="deepseek-v4-flash" ;; + 2) model="deepseek-v4-pro" ;; + 3) read -r -p "请输入模型 ID: " model ;; + 0) return 0 ;; + *) echo -e "${RED}无效选项。${NC}"; return 1 ;; + esac + if ! write_model_patch "$model"; then + echo -e "${RED}模型 ID 无效。${NC}" + return 1 + fi + restart_if_running + echo -e "${GREEN}默认模型已切换为:$model${NC}" +} + +run_headless_task() { + local task api_key + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + api_key=$(read_api_key) + if [ -z "$api_key" ]; then + echo -e "${RED}尚未配置脚本托管的 DeepSeek API Key。${NC}" + return 1 + fi + read -r -p "请输入命令行任务: " task + [ -n "$task" ] || { + echo -e "${RED}任务不能为空。${NC}" + return 1 + } + load_managed_environment + dsh --profile headless --patch "$MODEL_PATCH_FILE" "$task" +} + +update_deepseek_harness() { + local was_running=false + require_root || return 1 + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + harness_running && was_running=true + echo -e "${YELLOW}正在更新官方 $NPM_PACKAGE...${NC}" + npm install -g "${NPM_PACKAGE}@latest" || return 1 + initialize_profiles || return 1 + [ "$was_running" = "true" ] && restart_if_running + mark_app_installed + echo -e "${GREEN}DeepSeek Harness 更新完成:$(dsh --version 2>/dev/null)${NC}" +} + +uninstall_deepseek_harness() { + local confirm remove_data + require_root || return 1 + read -r -p "确定卸载 DeepSeek Harness?(y/N): " confirm + case "$confirm" in + [yY]) ;; + *) echo "已取消。"; return 0 ;; + esac + stop_deepseek_harness >/dev/null 2>&1 || true + if systemd_available && [ -f "$SERVICE_FILE" ]; then + rm -f -- "$SERVICE_FILE" + systemctl daemon-reload + fi + if dsh_installed; then + npm uninstall -g "$NPM_PACKAGE" || return 1 + fi + read -r -p "是否同时删除 $DSH_HOME 中的配置、凭据引用和会话?(y/N): " remove_data + case "$remove_data" in + [yY]) + case "$DSH_HOME" in + "$HOME/.dsh"|/root/.dsh) rm -rf -- "$DSH_HOME" ;; + *) echo -e "${YELLOW}自定义 DSH_HOME 未自动删除:$DSH_HOME${NC}" ;; + esac + ;; + esac + if dsh_installed; then + echo -e "${RED}卸载后仍能找到 dsh 命令,请检查 npm 全局目录。${NC}" + return 1 + fi + unmark_app_installed + echo -e "${GREEN}DeepSeek Harness 已卸载。Node.js 及 npm 缓存未自动删除。${NC}" +} + +show_menu() { + local install_status running_status api_status model version + if dsh_installed; then + version=$(dsh --version 2>/dev/null) + install_status="${GREEN}已安装 ${version}${NC}" + else + install_status="${RED}未安装${NC}" + fi + if harness_running; then + running_status="${GREEN}运行中${NC}" + else + running_status="${YELLOW}已停止${NC}" + fi + if [ -n "$(read_api_key)" ]; then + api_status="${GREEN}已配置${NC}" + else + api_status="${RED}未配置${NC}" + fi + model=$(current_model) + clear 2>/dev/null || true + echo -e "${CYAN}=================================================${NC}" + echo " DeepSeek Harness 基础管理工具" + echo -e "${CYAN}=================================================${NC}" + echo -e "安装状态:$install_status 运行状态:$running_status" + echo -e "API 状态:$api_status 默认模型:$model" + echo "Web UI:http://${LISTEN_HOST}:${LISTEN_PORT}(仅本机)" + echo -e "${CYAN}-------------------------------------------------${NC}" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" + echo "4. API 管理" + echo "5. 换模型" + echo "6. 命令行任务" + echo "7. 更新" + echo "8. 卸载" + echo "0. 返回应用市场" + echo -e "${CYAN}=================================================${NC}" +} + +deepseek_harness_main() { + local choice + while true; do + show_menu + read -r -p "请输入选项 [0-8]: " choice || return 0 + case "$choice" in + 1) install_deepseek_harness ;; + 2) start_deepseek_harness ;; + 3) stop_deepseek_harness ;; + 4) api_management_menu ;; + 5) change_model ;; + 6) run_headless_task ;; + 7) update_deepseek_harness ;; + 8) uninstall_deepseek_harness ;; + 0) return 0 ;; + *) echo -e "${RED}无效选项。${NC}" ;; + esac + echo + read -r -p "按回车键返回菜单..." + done +} + +if [ "${BASH_SOURCE[0]}" = "$0" ]; then + deepseek_harness_main +fi diff --git a/deepseek_hermes_manager.sh b/deepseek_hermes_manager.sh deleted file mode 100644 index bcd35a80c..000000000 --- a/deepseek_hermes_manager.sh +++ /dev/null @@ -1,465 +0,0 @@ -#!/bin/bash -# DeepSeek Hermes 终端管理脚本(基础轻量版) -# 仅提供:安装、启动、停止、API 管理、切换模型、命令行聊天、更新、卸载。 - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -CYAN='\033[0;36m' -NC='\033[0m' - -HERMES_DATA_DIR="${HERMES_HOME:-$HOME/.hermes}" -HERMES_ENV_FILE="${HERMES_DATA_DIR}/.env" -HERMES_INSTALLER_URL="https://hermes-agent.nousresearch.com/install.sh" -DEEPSEEK_BASE_URL="https://api.deepseek.com" -DEFAULT_DEEPSEEK_MODEL="deepseek-v4-pro" -APP_ID="116" - -refresh_hermes_path() { - local candidate - for candidate in \ - "/usr/local/bin" \ - "$HOME/.local/bin" \ - "$HERMES_DATA_DIR/hermes-agent/venv/bin"; do - [ -d "$candidate" ] || continue - case ":$PATH:" in - *":$candidate:"*) ;; - *) PATH="$candidate:$PATH" ;; - esac - done - export PATH - hash -r 2>/dev/null || true -} - -hermes_installed() { - refresh_hermes_path - command -v hermes >/dev/null 2>&1 -} - -hermes_running() { - if command -v systemctl >/dev/null 2>&1 \ - && systemctl --user is-active --quiet hermes-gateway.service 2>/dev/null; then - return 0 - fi - # The bracketed first character prevents pgrep from matching its own argv. - pgrep -u "$(id -u)" -f '[p]ython([^[:space:]]*)?[[:space:]]+-m[[:space:]]+hermes_cli\.main[[:space:]]+gateway[[:space:]]+run([[:space:]]|$)' >/dev/null 2>&1 -} - -read_deepseek_api_key() { - [ -r "$HERMES_ENV_FILE" ] || return 1 - sed -n 's/^[[:space:]]*DEEPSEEK_API_KEY=//p' "$HERMES_ENV_FILE" \ - | tail -n 1 \ - | sed 's/^"//;s/"$//;s/^'"'"'//;s/'"'"'$//' -} - -mask_api_key() { - local api_key="$1" - local key_length=${#api_key} - if [ "$key_length" -le 8 ]; then - printf '%s' '********' - else - printf '%s****%s' "${api_key:0:3}" "${api_key: -4}" - fi -} - -write_deepseek_api_key() { - local api_key="$1" - local temporary_file - - mkdir -p "$HERMES_DATA_DIR" || return 1 - umask 077 - temporary_file=$(mktemp "${HERMES_ENV_FILE}.tmp.XXXXXX") || return 1 - if [ -f "$HERMES_ENV_FILE" ]; then - grep -v '^[[:space:]]*DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE" > "$temporary_file" || true - fi - printf 'DEEPSEEK_API_KEY=%s\n' "$api_key" >> "$temporary_file" - mv -f -- "$temporary_file" "$HERMES_ENV_FILE" - chmod 600 "$HERMES_ENV_FILE" -} - -delete_deepseek_api_key() { - local temporary_file - [ -f "$HERMES_ENV_FILE" ] || return 0 - umask 077 - temporary_file=$(mktemp "${HERMES_ENV_FILE}.tmp.XXXXXX") || return 1 - grep -v '^[[:space:]]*DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE" > "$temporary_file" || true - mv -f -- "$temporary_file" "$HERMES_ENV_FILE" - chmod 600 "$HERMES_ENV_FILE" -} - -current_model() { - local model_name - hermes_installed || return 0 - model_name=$(hermes config get model.default 2>/dev/null | tail -n 1 | tr -d '"' | xargs) - if [ -z "$model_name" ] || [ "$model_name" = "null" ]; then - model_name=$(hermes config get model.model 2>/dev/null | tail -n 1 | tr -d '"' | xargs) - fi - [ "$model_name" = "null" ] && model_name="" - printf '%s' "$model_name" -} - -current_provider() { - local provider_name - hermes_installed || return 0 - provider_name=$(hermes config get model.provider 2>/dev/null | tail -n 1 | tr -d '"' | xargs) - [ "$provider_name" = "null" ] && provider_name="" - printf '%s' "$provider_name" -} - -apply_deepseek_model() { - local model_name="$1" - local restart_gateway="${2:-true}" - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - if [ -z "$model_name" ]; then - echo -e "${RED}模型 ID 不能为空。${NC}" - return 1 - fi - - hermes config set model.provider deepseek || return 1 - hermes config set model.default "$model_name" || return 1 - hermes config set model.base_url "$DEEPSEEK_BASE_URL" || return 1 - echo -e "${GREEN}模型已切换为:${model_name}${NC}" - - if [ "$restart_gateway" = "true" ] && hermes_running; then - echo -e "${YELLOW}正在重启 Gateway 以应用新模型...${NC}" - hermes gateway restart - fi -} - -ensure_default_model() { - local model_name provider_name restart_gateway - restart_gateway="${1:-true}" - model_name=$(current_model) - provider_name=$(current_provider) - if [ "$provider_name" = "deepseek" ] && [ -n "$model_name" ]; then - return 0 - fi - case "$model_name" in - deepseek-*) ;; - *) model_name="$DEFAULT_DEEPSEEK_MODEL" ;; - esac - apply_deepseek_model "$model_name" "$restart_gateway" -} - -mark_app_installed() { - mkdir -p /home/docker 2>/dev/null || return 0 - touch /home/docker/appno.txt 2>/dev/null || return 0 - grep -qxF "$APP_ID" /home/docker/appno.txt 2>/dev/null \ - || echo "$APP_ID" >> /home/docker/appno.txt -} - -unmark_app_installed() { - [ -f /home/docker/appno.txt ] || return 0 - sed -i "/^${APP_ID}$/d" /home/docker/appno.txt -} - -install_prerequisites() { - if command -v git >/dev/null 2>&1 \ - && command -v curl >/dev/null 2>&1 \ - && command -v xz >/dev/null 2>&1; then - return 0 - fi - - echo -e "${YELLOW}正在安装 Git、curl 和 xz...${NC}" - if command -v apt-get >/dev/null 2>&1; then - apt-get update && apt-get install -y git curl xz-utils ca-certificates - elif command -v dnf >/dev/null 2>&1; then - dnf install -y git curl xz ca-certificates - elif command -v yum >/dev/null 2>&1; then - yum install -y git curl xz ca-certificates - elif command -v apk >/dev/null 2>&1; then - apk add git curl xz ca-certificates - elif command -v pacman >/dev/null 2>&1; then - pacman -Sy --noconfirm git curl xz ca-certificates - elif command -v zypper >/dev/null 2>&1; then - zypper --non-interactive install git curl xz ca-certificates - else - echo -e "${RED}未识别到支持的软件包管理器,请手动安装 git、curl、xz。${NC}" - return 1 - fi -} - -install_deepseek_hermes() { - local installer_file - if hermes_installed; then - echo -e "${YELLOW}Hermes 已安装,无需重复安装。${NC}" - mark_app_installed - return 0 - fi - - install_prerequisites || return 1 - installer_file=$(mktemp) || return 1 - echo -e "${YELLOW}正在下载并安装 Hermes 基础轻量版...${NC}" - if ! curl -fsSL "$HERMES_INSTALLER_URL" -o "$installer_file"; then - rm -f -- "$installer_file" - echo -e "${RED}Hermes 安装脚本下载失败。${NC}" - return 1 - fi - - if ! bash "$installer_file" \ - --skip-setup \ - --skip-browser \ - --skip-computer-use \ - --no-skills; then - rm -f -- "$installer_file" - echo -e "${RED}Hermes 安装失败,请检查上方输出。${NC}" - return 1 - fi - rm -f -- "$installer_file" - refresh_hermes_path - - if ! hermes_installed; then - echo -e "${RED}安装程序已结束,但未找到 hermes 命令。${NC}" - return 1 - fi - - mark_app_installed - echo -e "${GREEN}DeepSeek Hermes 基础轻量版安装完成。${NC}" - echo "下一步请进入“API 管理”设置 DeepSeek API Key,再启动或聊天。" -} - -start_deepseek_hermes() { - local api_key - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - api_key=$(read_deepseek_api_key) - if [ -z "$api_key" ]; then - echo -e "${RED}尚未配置 DeepSeek API Key,请先进入 API 管理。${NC}" - return 1 - fi - ensure_default_model false || return 1 - - echo -e "${YELLOW}正在启动 Hermes Gateway...${NC}" - hermes gateway install >/dev/null 2>&1 || true - if hermes gateway start; then - mark_app_installed - echo -e "${GREEN}Hermes Gateway 已启动。${NC}" - else - echo -e "${RED}Gateway 启动失败,请查看上方输出。${NC}" - return 1 - fi -} - -stop_deepseek_hermes() { - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - echo -e "${YELLOW}正在停止 Hermes Gateway...${NC}" - hermes gateway stop -} - -api_management_menu() { - local choice api_key confirm - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - - while true; do - clear - api_key=$(read_deepseek_api_key) - echo -e "${CYAN}=======================================${NC}" - echo " DeepSeek API 管理" - echo -e "${CYAN}=======================================${NC}" - if [ -n "$api_key" ]; then - echo -e "API 状态:${GREEN}已配置 $(mask_api_key "$api_key")${NC}" - else - echo -e "API 状态:${RED}未配置${NC}" - fi - echo "Base URL:$DEEPSEEK_BASE_URL" - echo "---------------------------------------" - echo "1. 设置或更换 API Key" - echo "2. 删除 API Key" - echo "0. 返回" - read -r -p "请输入选项: " choice - - case "$choice" in - 1) - read -r -s -p "请输入 DeepSeek API Key: " api_key - echo - if [ -z "$api_key" ]; then - echo -e "${RED}API Key 不能为空。${NC}" - elif write_deepseek_api_key "$api_key"; then - if ensure_default_model false; then - if hermes_running; then - hermes gateway restart - fi - echo -e "${GREEN}DeepSeek API Key 已安全保存。${NC}" - else - echo -e "${YELLOW}API Key 已保存,但 DeepSeek 模型配置失败。${NC}" - fi - else - echo -e "${RED}API Key 保存失败。${NC}" - fi - read -r -p "按回车键继续..." - ;; - 2) - read -r -p "确定删除 DeepSeek API Key?(y/N): " confirm - case "$confirm" in - [yY]) - if hermes_running; then - hermes gateway stop >/dev/null 2>&1 || true - fi - delete_deepseek_api_key - echo -e "${GREEN}DeepSeek API Key 已删除。${NC}" - ;; - *) echo "已取消。" ;; - esac - read -r -p "按回车键继续..." - ;; - 0) return 0 ;; - *) sleep 1 ;; - esac - done -} - -change_deepseek_model() { - local choice model_name - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - - echo "当前模型:$(current_model)" - echo "1. deepseek-v4-pro" - echo "2. deepseek-v4-flash" - echo "3. 手动输入模型 ID" - echo "0. 取消" - read -r -p "请选择模型: " choice - case "$choice" in - 1) model_name="deepseek-v4-pro" ;; - 2) model_name="deepseek-v4-flash" ;; - 3) read -r -p "请输入模型 ID: " model_name ;; - 0) return 0 ;; - *) echo -e "${RED}无效选项。${NC}"; return 1 ;; - esac - apply_deepseek_model "$model_name" -} - -chat_with_deepseek_hermes() { - local api_key - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - api_key=$(read_deepseek_api_key) - if [ -z "$api_key" ]; then - echo -e "${RED}尚未配置 DeepSeek API Key,请先进入 API 管理。${NC}" - return 1 - fi - ensure_default_model || return 1 - echo -e "${YELLOW}正在进入 Hermes 命令行聊天,退出后将返回本菜单。${NC}" - hermes -} - -update_deepseek_hermes() { - if ! hermes_installed; then - echo -e "${RED}请先安装 DeepSeek Hermes。${NC}" - return 1 - fi - echo -e "${YELLOW}正在更新 Hermes...${NC}" - if hermes update; then - mark_app_installed - echo -e "${GREEN}Hermes 更新完成。${NC}" - fi -} - -uninstall_deepseek_hermes() { - local confirm - if ! hermes_installed; then - echo -e "${YELLOW}Hermes 未安装。${NC}" - unmark_app_installed - return 0 - fi - - read -r -p "确定卸载 Hermes?官方卸载器会询问是否保留配置。(y/N): " confirm - case "$confirm" in - [yY]) ;; - *) echo "已取消。"; return 0 ;; - esac - - hermes gateway stop >/dev/null 2>&1 || true - hermes uninstall - refresh_hermes_path - if hermes_installed; then - echo -e "${YELLOW}仍检测到 hermes 命令,未移除应用市场安装标记。${NC}" - return 1 - fi - unmark_app_installed - echo -e "${GREEN}Hermes 已卸载。${NC}" -} - -show_menu() { - local install_status running_status model_name api_key - if hermes_installed; then - install_status="${GREEN}已安装${NC}" - model_name=$(current_model) - [ -n "$model_name" ] || model_name="未配置" - if hermes_running; then - running_status="${GREEN}运行中${NC}" - else - running_status="${YELLOW}已停止${NC}" - fi - else - install_status="${RED}未安装${NC}" - running_status="${RED}未运行${NC}" - model_name="未配置" - fi - api_key=$(read_deepseek_api_key) - - clear - echo -e "${CYAN}=================================================${NC}" - echo " DeepSeek Hermes 基础轻量管理工具" - echo -e "${CYAN}=================================================${NC}" - echo -e "安装状态:${install_status} 运行状态:${running_status}" - echo "当前模型:${model_name}" - if [ -n "$api_key" ]; then - echo -e "API 状态:${GREEN}已配置 $(mask_api_key "$api_key")${NC}" - else - echo -e "API 状态:${RED}未配置${NC}" - fi - echo -e "${CYAN}-------------------------------------------------${NC}" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" - echo "4. API 管理" - echo "5. 换模型" - echo "6. 命令行聊天" - echo "7. 更新" - echo "8. 卸载" - echo "0. 返回应用市场" - echo -e "${CYAN}=================================================${NC}" -} - -deepseek_hermes_main() { - local menu_choice - refresh_hermes_path - while true; do - show_menu - read -r -p "请输入选项 [0-8]: " menu_choice || return 0 - case "$menu_choice" in - 1) install_deepseek_hermes ;; - 2) start_deepseek_hermes ;; - 3) stop_deepseek_hermes ;; - 4) api_management_menu ;; - 5) change_deepseek_model ;; - 6) chat_with_deepseek_hermes ;; - 7) update_deepseek_hermes ;; - 8) uninstall_deepseek_hermes ;; - 0) return 0 ;; - *) echo -e "${RED}无效选项。${NC}" ;; - esac - echo - read -r -p "按回车键返回菜单..." - done -} - -if [ "${BASH_SOURCE[0]}" = "$0" ]; then - deepseek_hermes_main -fi diff --git a/kejilion.sh b/kejilion.sh index 56e654cd5..01df831f0 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Hermes基础轻量版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness基础版${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" @@ -22263,8 +22263,8 @@ discourse,yunsou,ahhhhfs,nsgame,gying" \ bash <(curl -sL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/hermes_manager.sh) ;; - 116|deepseek-hermes|DeepSeek-Hermes|ds-hermes) - bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_hermes_manager.sh) + 116|deepseek-harness|DeepSeek-Harness|dsh) + bash <(curl -fsSL ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/deepseek_harness_manager.sh) ;; b) diff --git a/tests/test_deepseek_harness_manager.sh b/tests/test_deepseek_harness_manager.sh new file mode 100644 index 000000000..df254c018 --- /dev/null +++ b/tests/test_deepseek_harness_manager.sh @@ -0,0 +1,97 @@ +#!/bin/bash +set -euo pipefail + +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +temporary_dir="$(mktemp -d)" +trap 'rm -rf -- "${temporary_dir}"' EXIT + +export DSH_HOME="${temporary_dir}/dsh-home" +export DSH_ENV_FILE="${DSH_HOME}/kejilion.env" +export MODEL_PATCH_FILE="${DSH_HOME}/kejilion-model.patch.yml" +export DEEPSEEK_HARNESS_SERVICE_FILE="${temporary_dir}/deepseek-harness.service" +export DEEPSEEK_HARNESS_PID_FILE="${temporary_dir}/deepseek-harness.pid" +export DEEPSEEK_HARNESS_LOG_FILE="${temporary_dir}/deepseek-harness.log" +export DEEPSEEK_HARNESS_APP_MARKER_FILE="${temporary_dir}/appno.txt" +export PATH="${temporary_dir}/bin:${PATH}" +mkdir -p "${temporary_dir}/bin" "$DSH_HOME" + +cat >"${temporary_dir}/bin/dsh" <<'MOCK' +#!/bin/bash +if [ "$*" = "--version" ]; then + printf '%s\n' '0.1.0-rc.6' +fi +MOCK +cat >"${temporary_dir}/bin/node" <<'MOCK' +#!/bin/bash +printf '%s\n' '24.18.0' +MOCK +cat >"${temporary_dir}/bin/systemctl" <<'MOCK' +#!/bin/bash +if [ "$*" = "daemon-reload" ]; then + exit 0 +fi +exit 1 +MOCK +cat >"${temporary_dir}/bin/curl" <<'MOCK' +#!/bin/bash +exit 1 +MOCK +chmod +x "${temporary_dir}/bin/dsh" "${temporary_dir}/bin/node" "${temporary_dir}/bin/systemctl" "${temporary_dir}/bin/curl" + +# shellcheck source=../deepseek_harness_manager.sh +source "${project_root}/deepseek_harness_manager.sh" + +node_version_supported +write_api_key 'sk-test-secret-1234' +grep -qxF 'DEEPSEEK_API_KEY=sk-test-secret-1234' "$DSH_ENV_FILE" +grep -qxF 'DEEPSEEK_BASE_URL=https://api.deepseek.com' "$DSH_ENV_FILE" +[ "$(stat -c '%a' "$DSH_ENV_FILE")" = "600" ] +[ "$(mask_api_key 'sk-test-secret-1234')" = 'sk-****1234' ] +if valid_api_key 'sk-invalid key'; then + echo 'FAIL: unsafe API key was accepted' >&2 + exit 1 +fi + +delete_api_key +if grep -q '^DEEPSEEK_API_KEY=' "$DSH_ENV_FILE"; then + echo 'FAIL: DeepSeek API key was not deleted' >&2 + exit 1 +fi + +write_model_patch 'deepseek-v4-pro' +grep -qxF -- '- id: agent-default-model' "$MODEL_PATCH_FILE" +grep -qxF ' provider: deepseek-official' "$MODEL_PATCH_FILE" +grep -qxF ' model: deepseek-v4-pro' "$MODEL_PATCH_FILE" +[ "$(current_model)" = 'deepseek-v4-pro' ] +[ "$(stat -c '%a' "$MODEL_PATCH_FILE")" = "600" ] + +if write_model_patch $'bad\nmodel'; then + echo 'FAIL: unsafe model id was accepted' >&2 + exit 1 +fi + +if harness_running; then + echo 'FAIL: stopped Harness was reported as running' >&2 + exit 1 +fi +if web_ready; then + echo 'FAIL: unavailable Web UI was reported as ready' >&2 + exit 1 +fi + +configure_systemd_service +grep -Fq 'ExecStart=' "$DEEPSEEK_HARNESS_SERVICE_FILE" +grep -Fq ' web --patch ' "$DEEPSEEK_HARNESS_SERVICE_FILE" +grep -Fq ' --host 127.0.0.1 --port 3080' "$DEEPSEEK_HARNESS_SERVICE_FILE" +grep -Fq 'Environment=DSH_TELEMETRY_DISABLED=1' "$DEEPSEEK_HARNESS_SERVICE_FILE" +grep -Fq 'Environment=PATH=' "$DEEPSEEK_HARNESS_SERVICE_FILE" + +mark_app_installed +grep -qxF '116' "$DEEPSEEK_HARNESS_APP_MARKER_FILE" +unmark_app_installed +if grep -qxF '116' "$DEEPSEEK_HARNESS_APP_MARKER_FILE"; then + echo 'FAIL: app marker was not removed' >&2 + exit 1 +fi + +echo 'PASS: DeepSeek Harness manager smoke tests' diff --git a/tests/test_deepseek_hermes_manager.sh b/tests/test_deepseek_hermes_manager.sh deleted file mode 100644 index b5bdfb432..000000000 --- a/tests/test_deepseek_hermes_manager.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -set -euo pipefail - -project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" -temporary_dir="$(mktemp -d)" -trap 'rm -rf -- "${temporary_dir}"' EXIT - -export HOME="${temporary_dir}/home" -export HERMES_HOME="${HOME}/.hermes" -export PATH="${temporary_dir}/bin:${PATH}" -export MOCK_HERMES_LOG="${temporary_dir}/hermes.log" -mkdir -p "$HERMES_HOME" "${temporary_dir}/bin" - -cat >"${temporary_dir}/bin/hermes" <<'MOCK' -#!/bin/bash -printf '%s\n' "$*" >>"$MOCK_HERMES_LOG" -if [ "$*" = "config get model.default" ]; then - printf '%s\n' 'deepseek-v4-pro' -fi -MOCK -chmod +x "${temporary_dir}/bin/hermes" - -# shellcheck source=../deepseek_hermes_manager.sh -source "${project_root}/deepseek_hermes_manager.sh" - -printf '%s\n' 'OTHER_KEY=keep-me' >"$HERMES_ENV_FILE" -write_deepseek_api_key 'sk-test-secret-1234' -grep -qxF 'OTHER_KEY=keep-me' "$HERMES_ENV_FILE" -grep -qxF 'DEEPSEEK_API_KEY=sk-test-secret-1234' "$HERMES_ENV_FILE" -[ "$(stat -c '%a' "$HERMES_ENV_FILE")" = "600" ] -[ "$(mask_api_key 'sk-test-secret-1234')" = 'sk-****1234' ] - -delete_deepseek_api_key -grep -qxF 'OTHER_KEY=keep-me' "$HERMES_ENV_FILE" -if grep -q '^DEEPSEEK_API_KEY=' "$HERMES_ENV_FILE"; then - echo 'FAIL: DeepSeek API key was not deleted' >&2 - exit 1 -fi - -apply_deepseek_model 'deepseek-v4-flash' -grep -qxF 'config set model.provider deepseek' "$MOCK_HERMES_LOG" -grep -qxF 'config set model.default deepseek-v4-flash' "$MOCK_HERMES_LOG" -grep -qxF 'config set model.base_url https://api.deepseek.com' "$MOCK_HERMES_LOG" - -if hermes_running; then - echo 'FAIL: stopped gateway was reported as running by the pgrep fallback' >&2 - exit 1 -fi - -echo 'PASS: DeepSeek Hermes manager smoke tests' From 9d718cb69ba38b84043ae0890a878e0b5a6b9370 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 12:51:00 +0800 Subject: [PATCH 1268/1285] fix(app): align DeepSeek Harness catalog label --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- tests/test_deepseek_harness_manager.sh | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 3caa9ce88..76132e1ce 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness基础版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" diff --git a/kejilion.sh b/kejilion.sh index 01df831f0..5a89ed68b 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -18579,7 +18579,7 @@ while true; do echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}111. ${color111}多格式文件转换工具 ${gl_kjlan}112. ${color112}Lucky大内网穿透工具" echo -e "${gl_kjlan}113. ${color113}Firefox浏览器 ${gl_kjlan}114. ${color114}OpenClaw机器人管理工具${gl_huang}★${gl_bai}" - echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness基础版${gl_huang}★${gl_bai}" + echo -e "${gl_kjlan}115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness管理工具${gl_huang}★${gl_bai}" echo -e "${gl_kjlan}-------------------------" echo -e "${gl_kjlan}第三方应用列表" echo -e "${gl_kjlan}想要让你的应用出现在这里?查看开发者指南: ${gl_huang}https://dev.kejilion.sh/${gl_bai}" diff --git a/tests/test_deepseek_harness_manager.sh b/tests/test_deepseek_harness_manager.sh index df254c018..32c11f935 100644 --- a/tests/test_deepseek_harness_manager.sh +++ b/tests/test_deepseek_harness_manager.sh @@ -15,6 +15,14 @@ export DEEPSEEK_HARNESS_APP_MARKER_FILE="${temporary_dir}/appno.txt" export PATH="${temporary_dir}/bin:${PATH}" mkdir -p "${temporary_dir}/bin" "$DSH_HOME" +catalog_entry='115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness管理工具${gl_huang}★${gl_bai}' +for catalog_file in "${project_root}/kejilion.sh" "${project_root}/cn/kejilion.sh"; do + if ! grep -Fq "$catalog_entry" "$catalog_file"; then + echo "FAIL: DeepSeek Harness catalog description or alignment is incorrect in ${catalog_file}" >&2 + exit 1 + fi +done + cat >"${temporary_dir}/bin/dsh" <<'MOCK' #!/bin/bash if [ "$*" = "--version" ]; then From d1e210d90af62cd74a91407c7565a62a9c29a672 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 13:06:44 +0800 Subject: [PATCH 1269/1285] fix(harness): allow required npm install scripts --- deepseek_harness_manager.sh | 28 +++++++++++++++++++-- tests/test_deepseek_harness_manager.sh | 34 +++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/deepseek_harness_manager.sh b/deepseek_harness_manager.sh index 6b949853b..288edfae8 100644 --- a/deepseek_harness_manager.sh +++ b/deepseek_harness_manager.sh @@ -17,6 +17,7 @@ PID_FILE="${DEEPSEEK_HARNESS_PID_FILE:-$DSH_HOME/deepseek-harness.pid}" LOG_FILE="${DEEPSEEK_HARNESS_LOG_FILE:-$DSH_HOME/deepseek-harness.log}" APP_MARKER_FILE="${DEEPSEEK_HARNESS_APP_MARKER_FILE:-/home/docker/appno.txt}" NPM_PACKAGE="@deepseek-ai/dsh" +NPM_INSTALL_SCRIPT_ALLOWLIST="@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs" DEEPSEEK_BASE_URL="https://api.deepseek.com" DEFAULT_MODEL="deepseek-v4-flash" LISTEN_HOST="127.0.0.1" @@ -48,6 +49,29 @@ node_version_supported() { esac } +npm_allow_scripts_supported() { + local version major minor + version="${1:-$(npm --version 2>/dev/null)}" || return 1 + version=${version#v} + major=${version%%.*} + minor=${version#*.} + minor=${minor%%.*} + case "$major:$minor" in + *[!0-9:]*|:*) return 1 ;; + 11:*) [ "$minor" -ge 16 ] ;; + *) [ "$major" -ge 12 ] ;; + esac +} + +install_dsh_npm_package() { + local -a npm_args=(install -g) + if npm_allow_scripts_supported; then + npm_args+=("--allow-scripts=${NPM_INSTALL_SCRIPT_ALLOWLIST}") + fi + npm_args+=("${NPM_PACKAGE}@latest") + npm "${npm_args[@]}" +} + systemd_available() { command -v systemctl >/dev/null 2>&1 \ && [ "$(ps -p 1 -o comm= 2>/dev/null | tr -d '[:space:]')" = "systemd" ] @@ -247,7 +271,7 @@ install_deepseek_harness() { fi ensure_node_runtime || return 1 echo -e "${YELLOW}正在安装官方 $NPM_PACKAGE,首次安装可能需要数分钟...${NC}" - npm install -g "${NPM_PACKAGE}@latest" || return 1 + install_dsh_npm_package || return 1 dsh_installed || { echo -e "${RED}安装完成后仍找不到 dsh 命令。${NC}" return 1 @@ -441,7 +465,7 @@ update_deepseek_harness() { } harness_running && was_running=true echo -e "${YELLOW}正在更新官方 $NPM_PACKAGE...${NC}" - npm install -g "${NPM_PACKAGE}@latest" || return 1 + install_dsh_npm_package || return 1 initialize_profiles || return 1 [ "$was_running" = "true" ] && restart_if_running mark_app_installed diff --git a/tests/test_deepseek_harness_manager.sh b/tests/test_deepseek_harness_manager.sh index 32c11f935..006a88f2d 100644 --- a/tests/test_deepseek_harness_manager.sh +++ b/tests/test_deepseek_harness_manager.sh @@ -12,6 +12,7 @@ export DEEPSEEK_HARNESS_SERVICE_FILE="${temporary_dir}/deepseek-harness.service" export DEEPSEEK_HARNESS_PID_FILE="${temporary_dir}/deepseek-harness.pid" export DEEPSEEK_HARNESS_LOG_FILE="${temporary_dir}/deepseek-harness.log" export DEEPSEEK_HARNESS_APP_MARKER_FILE="${temporary_dir}/appno.txt" +export MOCK_NPM_ARGS_LOG="${temporary_dir}/npm-args.log" export PATH="${temporary_dir}/bin:${PATH}" mkdir -p "${temporary_dir}/bin" "$DSH_HOME" @@ -33,6 +34,14 @@ cat >"${temporary_dir}/bin/node" <<'MOCK' #!/bin/bash printf '%s\n' '24.18.0' MOCK +cat >"${temporary_dir}/bin/npm" <<'MOCK' +#!/bin/bash +if [ "${1:-}" = "--version" ]; then + printf '%s\n' "${MOCK_NPM_VERSION:-11.16.0}" + exit 0 +fi +printf '%s\n' "$@" >"$MOCK_NPM_ARGS_LOG" +MOCK cat >"${temporary_dir}/bin/systemctl" <<'MOCK' #!/bin/bash if [ "$*" = "daemon-reload" ]; then @@ -44,12 +53,35 @@ cat >"${temporary_dir}/bin/curl" <<'MOCK' #!/bin/bash exit 1 MOCK -chmod +x "${temporary_dir}/bin/dsh" "${temporary_dir}/bin/node" "${temporary_dir}/bin/systemctl" "${temporary_dir}/bin/curl" +chmod +x "${temporary_dir}/bin/dsh" "${temporary_dir}/bin/node" "${temporary_dir}/bin/npm" "${temporary_dir}/bin/systemctl" "${temporary_dir}/bin/curl" # shellcheck source=../deepseek_harness_manager.sh source "${project_root}/deepseek_harness_manager.sh" node_version_supported +npm_allow_scripts_supported '11.16.0' +npm_allow_scripts_supported '12.0.2' +if npm_allow_scripts_supported '11.15.9'; then + echo 'FAIL: unsupported npm version accepted allow-scripts' >&2 + exit 1 +fi + +export MOCK_NPM_VERSION='11.16.0' +install_dsh_npm_package +mapfile -t npm_args <"$MOCK_NPM_ARGS_LOG" +[ "${#npm_args[@]}" -eq 4 ] +[ "${npm_args[0]}" = 'install' ] +[ "${npm_args[1]}" = '-g' ] +[ "${npm_args[2]}" = '--allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs' ] +[ "${npm_args[3]}" = '@deepseek-ai/dsh@latest' ] + +export MOCK_NPM_VERSION='11.15.9' +install_dsh_npm_package +mapfile -t npm_args <"$MOCK_NPM_ARGS_LOG" +[ "${#npm_args[@]}" -eq 3 ] +[ "${npm_args[0]}" = 'install' ] +[ "${npm_args[1]}" = '-g' ] +[ "${npm_args[2]}" = '@deepseek-ai/dsh@latest' ] write_api_key 'sk-test-secret-1234' grep -qxF 'DEEPSEEK_API_KEY=sk-test-secret-1234' "$DSH_ENV_FILE" grep -qxF 'DEEPSEEK_BASE_URL=https://api.deepseek.com' "$DSH_ENV_FILE" From a3820af1f161da07cdc3406ea0e26190b11de8dd Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 14:05:23 +0800 Subject: [PATCH 1270/1285] feat(harness): add protected WebUI domain access --- deepseek_harness_manager.sh | 310 ++++++++++++++++++++++++- tests/test_deepseek_harness_manager.sh | 126 +++++++++- 2 files changed, 426 insertions(+), 10 deletions(-) diff --git a/deepseek_harness_manager.sh b/deepseek_harness_manager.sh index 288edfae8..c3914f1f9 100644 --- a/deepseek_harness_manager.sh +++ b/deepseek_harness_manager.sh @@ -1,7 +1,7 @@ #!/bin/bash # DeepSeek Harness 管理脚本(基础版) # 官方项目:https://github.com/deepseek-ai/deepseek-harness -# 仅提供:安装、启动、停止、API 管理、切换模型、命令行任务、更新、卸载。 +# 仅提供:安装、启动、停止、API 管理、切换模型、命令行任务、WebUI 设置、更新、卸载。 RED='\033[0;31m' GREEN='\033[0;32m' @@ -16,6 +16,10 @@ SERVICE_FILE="${DEEPSEEK_HARNESS_SERVICE_FILE:-/etc/systemd/system/deepseek-harn PID_FILE="${DEEPSEEK_HARNESS_PID_FILE:-$DSH_HOME/deepseek-harness.pid}" LOG_FILE="${DEEPSEEK_HARNESS_LOG_FILE:-$DSH_HOME/deepseek-harness.log}" APP_MARKER_FILE="${DEEPSEEK_HARNESS_APP_MARKER_FILE:-/home/docker/appno.txt}" +WEBUI_DOMAINS_FILE="${DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE:-$DSH_HOME/kejilion-webui-domains}" +WEB_CONF_DIR="${DEEPSEEK_HARNESS_WEB_CONF_DIR:-/home/web/conf.d}" +WEB_CERT_DIR="${DEEPSEEK_HARNESS_WEB_CERT_DIR:-/home/web/certs}" +K_COMMAND="${DEEPSEEK_HARNESS_K_COMMAND:-k}" NPM_PACKAGE="@deepseek-ai/dsh" NPM_INSTALL_SCRIPT_ALLOWLIST="@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs" DEEPSEEK_BASE_URL="https://api.deepseek.com" @@ -162,6 +166,208 @@ valid_model_id() { esac } +normalize_domain() { + printf '%s' "$1" | tr '[:upper:]' '[:lower:]' +} + +valid_domain() { + local domain="$1" label + local -a labels + [ -n "$domain" ] && [ "${#domain}" -le 253 ] || return 1 + [[ "$domain" =~ ^[0-9]+(\.[0-9]+){3}$ ]] && return 1 + case "$domain" in + *..*|.*|*.) return 1 ;; + esac + local IFS='.' + read -r -a labels <<<"$domain" + [ "${#labels[@]}" -ge 2 ] || return 1 + for label in "${labels[@]}"; do + [ -n "$label" ] && [ "${#label}" -le 63 ] || return 1 + [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || return 1 + done +} + +list_webui_domains() { + [ -r "$WEBUI_DOMAINS_FILE" ] || return 0 + awk 'NF && !seen[$0]++ { print $0 }' "$WEBUI_DOMAINS_FILE" +} + +webui_domain_managed() { + [ -r "$WEBUI_DOMAINS_FILE" ] && grep -qxF "$1" "$WEBUI_DOMAINS_FILE" +} + +add_webui_domain_record() { + local domain="$1" temporary_file + mkdir -p "$DSH_HOME" || return 1 + umask 077 + temporary_file=$(mktemp "${WEBUI_DOMAINS_FILE}.tmp.XXXXXX") || return 1 + { + list_webui_domains + printf '%s\n' "$domain" + } | awk 'NF && !seen[$0]++' >"$temporary_file" + chmod 600 "$temporary_file" + mv -f "$temporary_file" "$WEBUI_DOMAINS_FILE" +} + +remove_webui_domain_record() { + local domain="$1" temporary_file + [ -e "$WEBUI_DOMAINS_FILE" ] || return 0 + umask 077 + temporary_file=$(mktemp "${WEBUI_DOMAINS_FILE}.tmp.XXXXXX") || return 1 + grep -vxF "$domain" "$WEBUI_DOMAINS_FILE" >"$temporary_file" || true + chmod 600 "$temporary_file" + mv -f "$temporary_file" "$WEBUI_DOMAINS_FILE" +} + +webui_auth_file() { + printf '%s/.deepseek-harness-%s.htpasswd' "$WEB_CONF_DIR" "$1" +} + +valid_basic_auth_user() { + [ -n "$1" ] && [ "${#1}" -le 64 ] && [[ "$1" =~ ^[A-Za-z0-9._-]+$ ]] +} + +write_webui_auth_file() { + local domain="$1" username="$2" password="$3" auth_file password_hash temporary_file + valid_basic_auth_user "$username" || return 1 + [ -n "$password" ] || return 1 + command -v openssl >/dev/null 2>&1 || return 1 + auth_file=$(webui_auth_file "$domain") + mkdir -p "$WEB_CONF_DIR" || return 1 + password_hash=$(printf '%s\n' "$password" | openssl passwd -apr1 -stdin 2>/dev/null) || return 1 + [ -n "$password_hash" ] || return 1 + umask 077 + temporary_file=$(mktemp "${auth_file}.tmp.XXXXXX") || return 1 + printf '%s:%s\n' "$username" "$password_hash" >"$temporary_file" + # Nginx worker needs read access; the file stores only an APR1 password hash. + chmod 644 "$temporary_file" + mv -f "$temporary_file" "$auth_file" +} + +patch_webui_proxy_config() { + local domain="$1" conf_file auth_path + conf_file="$WEB_CONF_DIR/${domain}.conf" + auth_path="/etc/nginx/conf.d/$(basename "$(webui_auth_file "$domain")")" + [ -f "$conf_file" ] || return 1 + grep -q 'kejilion-deepseek-harness-managed' "$conf_file" || + sed -i "/^[[:space:]]*server_name[[:space:]]/a\\ + # kejilion-deepseek-harness-managed\\ + auth_basic \"DeepSeek Harness\";\\ + auth_basic_user_file ${auth_path};" "$conf_file" || return 1 + sed -i \ + -e 's/^[[:space:]]*#[[:space:]]*proxy_read_timeout[[:space:]]*1d;/ proxy_read_timeout 1d;/' \ + -e 's/^[[:space:]]*#[[:space:]]*proxy_send_timeout[[:space:]]*1d;/ proxy_send_timeout 1d;/' \ + -e '/^[[:space:]]*proxy_cache[[:space:]]/d' \ + "$conf_file" +} + +reload_managed_nginx() { + command -v docker >/dev/null 2>&1 || return 1 + docker inspect nginx >/dev/null 2>&1 || return 1 + docker exec nginx nginx -t >/dev/null 2>&1 || return 1 + docker exec nginx nginx -s reload >/dev/null 2>&1 +} + +webui_domain_artifacts_exist() { + local domain="$1" + [ -e "$WEB_CONF_DIR/${domain}.conf" ] \ + || [ -e "$WEB_CERT_DIR/${domain}_cert.pem" ] \ + || [ -e "$WEB_CERT_DIR/${domain}_key.pem" ] \ + || [ -e "$(webui_auth_file "$domain")" ] +} + +remove_webui_domain_artifacts() { + local domain="$1" + rm -f -- \ + "$WEB_CONF_DIR/${domain}.conf" \ + "$(webui_auth_file "$domain")" \ + "$WEB_CERT_DIR/${domain}_cert.pem" \ + "$WEB_CERT_DIR/${domain}_key.pem" +} + +refresh_trusted_hosts() { + if harness_running; then + restart_if_running + elif systemd_available && [ -f "$SERVICE_FILE" ]; then + configure_systemd_service + fi +} + +rollback_webui_domain_add() { + local domain="$1" + remove_webui_domain_record "$domain" || true + remove_webui_domain_artifacts "$domain" + reload_managed_nginx >/dev/null 2>&1 || true + refresh_trusted_hosts >/dev/null 2>&1 || true +} + +create_webui_domain() { + local domain username password + domain=$(normalize_domain "$1") + username="$2" + password="$3" + valid_domain "$domain" || { + echo -e "${RED}域名格式无效,请输入 example.com,不带协议和路径。${NC}" + return 1 + } + valid_basic_auth_user "$username" || { + echo -e "${RED}访问用户名只能包含字母、数字、点、下划线或横线。${NC}" + return 1 + } + [ "${#password}" -ge 8 ] || { + echo -e "${RED}访问密码至少需要 8 个字符。${NC}" + return 1 + } + if webui_domain_managed "$domain"; then + echo -e "${YELLOW}该域名已由 DeepSeek Harness 管理。${NC}" + return 0 + fi + if webui_domain_artifacts_exist "$domain"; then + echo -e "${RED}域名已有站点、证书或认证文件,为避免覆盖已拒绝操作。${NC}" + return 1 + fi + command -v "$K_COMMAND" >/dev/null 2>&1 || { + echo -e "${RED}找不到 k 命令,无法调用 k fd 创建反向代理。${NC}" + return 1 + } + if ! "$K_COMMAND" fd "$domain" "$LISTEN_HOST" "$LISTEN_PORT"; then + rollback_webui_domain_add "$domain" + echo -e "${RED}k fd 创建反向代理失败,已清理本次产生的文件。${NC}" + return 1 + fi + if ! write_webui_auth_file "$domain" "$username" "$password" \ + || ! patch_webui_proxy_config "$domain" \ + || ! reload_managed_nginx \ + || ! add_webui_domain_record "$domain" \ + || ! refresh_trusted_hosts; then + rollback_webui_domain_add "$domain" + echo -e "${RED}域名配置失败,已回滚本次创建的反代文件。${NC}" + return 1 + fi + echo -e "${GREEN}域名访问已启用:https://${domain}${NC}" + echo "已启用 HTTPS、Basic Auth 和 Harness trusted-host。" +} + +delete_webui_domain() { + local domain + domain=$(normalize_domain "$1") + valid_domain "$domain" || return 1 + webui_domain_managed "$domain" || { + echo -e "${RED}该域名不在 DeepSeek Harness 托管列表中,拒绝删除。${NC}" + return 1 + } + remove_webui_domain_artifacts "$domain" || return 1 + remove_webui_domain_record "$domain" || return 1 + if command -v docker >/dev/null 2>&1 && docker inspect nginx >/dev/null 2>&1; then + reload_managed_nginx || { + echo -e "${YELLOW}域名文件已删除,但 Nginx 验证或重载失败,请手动检查。${NC}" + return 1 + } + fi + refresh_trusted_hosts || return 1 + echo -e "${GREEN}已删除域名访问:https://${domain}${NC}" +} + current_model() { local model if [ -r "$MODEL_PATCH_FILE" ]; then @@ -225,10 +431,15 @@ ensure_node_runtime() { } configure_systemd_service() { - local dsh_bin node_bin service_path + local dsh_bin node_bin service_path trusted_host_args domain dsh_bin=$(command -v dsh) || return 1 node_bin=$(command -v node) || return 1 service_path="$(dirname "$dsh_bin"):$(dirname "$node_bin"):/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + trusted_host_args="" + while IFS= read -r domain; do + valid_domain "$domain" || continue + trusted_host_args+=" --trusted-host $domain" + done < <(list_webui_domains) mkdir -p "$DSH_HOME" || return 1 cat >"$SERVICE_FILE" <"$LOG_FILE" 2>&1 & + web_args=(web --patch "$MODEL_PATCH_FILE" --host "$LISTEN_HOST" --port "$LISTEN_PORT") + while IFS= read -r domain; do + valid_domain "$domain" || continue + web_args+=(--trusted-host "$domain") + done < <(list_webui_domains) + nohup dsh "${web_args[@]}" >"$LOG_FILE" 2>&1 & echo "$!" >"$PID_FILE" fi if wait_for_web_ready; then @@ -456,6 +674,75 @@ run_headless_task() { dsh --profile headless --patch "$MODEL_PATCH_FILE" "$task" } +show_webui_addresses() { + local domains domain + echo "本机地址:http://${LISTEN_HOST}:${LISTEN_PORT}" + domains=$(list_webui_domains) + if [ -n "$domains" ]; then + echo "域名地址:" + while IFS= read -r domain; do + echo " https://${domain}(密码保护)" + done <<<"$domains" + else + echo "域名地址:未配置" + fi +} + +webui_settings_menu() { + local choice domain username password confirm domains + dsh_installed || { + echo -e "${RED}请先安装 DeepSeek Harness。${NC}" + return 1 + } + while true; do + clear 2>/dev/null || true + echo -e "${CYAN}=======================================${NC}" + echo " DeepSeek Harness WebUI 设置" + echo -e "${CYAN}=======================================${NC}" + show_webui_addresses + echo "1. 添加域名访问" + echo "2. 删除域名访问" + echo "0. 返回" + read -r -p "请输入选项: " choice + case "$choice" in + 1) + require_root || { read -r -p "按回车键继续..."; continue; } + read -r -p "请输入已解析到本机的域名(不带 https://): " domain + read -r -p "请输入访问用户名 [admin]: " username + username=${username:-admin} + read -r -s -p "请输入访问密码: " password + echo + create_webui_domain "$domain" "$username" "$password" + password="" + read -r -p "按回车键继续..." + ;; + 2) + require_root || { read -r -p "按回车键继续..."; continue; } + domains=$(list_webui_domains) + if [ -z "$domains" ]; then + echo -e "${YELLOW}当前没有托管的域名。${NC}" + read -r -p "按回车键继续..." + continue + fi + echo "$domains" + read -r -p "请输入要删除的域名: " domain + domain=$(normalize_domain "$domain") + if ! webui_domain_managed "$domain"; then + echo -e "${RED}该域名不在托管列表中。${NC}" + else + read -r -p "确定删除 https://${domain} 的反代、证书和认证文件?(y/N): " confirm + case "$confirm" in + [yY]) delete_webui_domain "$domain" ;; + *) echo "已取消。" ;; + esac + fi + read -r -p "按回车键继续..." + ;; + 0) return 0 ;; + esac + done +} + update_deepseek_harness() { local was_running=false require_root || return 1 @@ -506,7 +793,7 @@ uninstall_deepseek_harness() { } show_menu() { - local install_status running_status api_status model version + local install_status running_status api_status model version domain_count if dsh_installed; then version=$(dsh --version 2>/dev/null) install_status="${GREEN}已安装 ${version}${NC}" @@ -524,22 +811,28 @@ show_menu() { api_status="${RED}未配置${NC}" fi model=$(current_model) + domain_count=$(list_webui_domains | wc -l | tr -d '[:space:]') clear 2>/dev/null || true echo -e "${CYAN}=================================================${NC}" echo " DeepSeek Harness 基础管理工具" echo -e "${CYAN}=================================================${NC}" echo -e "安装状态:$install_status 运行状态:$running_status" echo -e "API 状态:$api_status 默认模型:$model" - echo "Web UI:http://${LISTEN_HOST}:${LISTEN_PORT}(仅本机)" + if [ "$domain_count" -gt 0 ]; then + echo "Web UI:http://${LISTEN_HOST}:${LISTEN_PORT}(本机) 已配置域名:${domain_count} 个" + else + echo "Web UI:http://${LISTEN_HOST}:${LISTEN_PORT}(仅本机)" + fi echo -e "${CYAN}-------------------------------------------------${NC}" echo "1. 安装" echo "2. 启动" echo "3. 停止" echo "4. API 管理" echo "5. 换模型" - echo "6. 命令行任务" + echo "6. 命令行单次任务" echo "7. 更新" echo "8. 卸载" + echo "9. WebUI 设置" echo "0. 返回应用市场" echo -e "${CYAN}=================================================${NC}" } @@ -548,7 +841,7 @@ deepseek_harness_main() { local choice while true; do show_menu - read -r -p "请输入选项 [0-8]: " choice || return 0 + read -r -p "请输入选项 [0-9]: " choice || return 0 case "$choice" in 1) install_deepseek_harness ;; 2) start_deepseek_harness ;; @@ -558,6 +851,7 @@ deepseek_harness_main() { 6) run_headless_task ;; 7) update_deepseek_harness ;; 8) uninstall_deepseek_harness ;; + 9) webui_settings_menu ;; 0) return 0 ;; *) echo -e "${RED}无效选项。${NC}" ;; esac diff --git a/tests/test_deepseek_harness_manager.sh b/tests/test_deepseek_harness_manager.sh index 006a88f2d..8c71be59a 100644 --- a/tests/test_deepseek_harness_manager.sh +++ b/tests/test_deepseek_harness_manager.sh @@ -12,9 +12,15 @@ export DEEPSEEK_HARNESS_SERVICE_FILE="${temporary_dir}/deepseek-harness.service" export DEEPSEEK_HARNESS_PID_FILE="${temporary_dir}/deepseek-harness.pid" export DEEPSEEK_HARNESS_LOG_FILE="${temporary_dir}/deepseek-harness.log" export DEEPSEEK_HARNESS_APP_MARKER_FILE="${temporary_dir}/appno.txt" +export DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE="${DSH_HOME}/kejilion-webui-domains" +export DEEPSEEK_HARNESS_WEB_CONF_DIR="${temporary_dir}/web/conf.d" +export DEEPSEEK_HARNESS_WEB_CERT_DIR="${temporary_dir}/web/certs" +export DEEPSEEK_HARNESS_K_COMMAND="k" export MOCK_NPM_ARGS_LOG="${temporary_dir}/npm-args.log" +export MOCK_K_ARGS_LOG="${temporary_dir}/k-args.log" +export MOCK_DOCKER_ARGS_LOG="${temporary_dir}/docker-args.log" export PATH="${temporary_dir}/bin:${PATH}" -mkdir -p "${temporary_dir}/bin" "$DSH_HOME" +mkdir -p "${temporary_dir}/bin" "$DSH_HOME" "$DEEPSEEK_HARNESS_WEB_CONF_DIR" "$DEEPSEEK_HARNESS_WEB_CERT_DIR" catalog_entry='115. ${color115}Hermes机器人管理工具${gl_huang}★${gl_bai} ${gl_kjlan}116. ${color116}DeepSeek Harness管理工具${gl_huang}★${gl_bai}' for catalog_file in "${project_root}/kejilion.sh" "${project_root}/cn/kejilion.sh"; do @@ -53,7 +59,61 @@ cat >"${temporary_dir}/bin/curl" <<'MOCK' #!/bin/bash exit 1 MOCK -chmod +x "${temporary_dir}/bin/dsh" "${temporary_dir}/bin/node" "${temporary_dir}/bin/npm" "${temporary_dir}/bin/systemctl" "${temporary_dir}/bin/curl" +cat >"${temporary_dir}/bin/openssl" <<'MOCK' +#!/bin/bash +if [ "$*" = "passwd -apr1 -stdin" ]; then + read -r password + [ -n "$password" ] || exit 1 + printf '%s\n' '$apr1$mock$hashed-password' + exit 0 +fi +exit 1 +MOCK +cat >"${temporary_dir}/bin/docker" <<'MOCK' +#!/bin/bash +printf '%s\n' "$*" >>"$MOCK_DOCKER_ARGS_LOG" +exit 0 +MOCK +cat >"${temporary_dir}/bin/k" <<'MOCK' +#!/bin/bash +printf '%s\n' "$*" >>"$MOCK_K_ARGS_LOG" +[ "${1:-}" = "fd" ] || exit 1 +domain="${2:-}" +host="${3:-}" +port="${4:-}" +[ -n "$domain" ] && [ "$host" = "127.0.0.1" ] && [ "$port" = "3080" ] || exit 1 +cat >"$DEEPSEEK_HARNESS_WEB_CONF_DIR/${domain}.conf" <&2 + exit 1 +fi +if valid_domain 'bad..example.com'; then + echo 'FAIL: malformed domain was accepted' >&2 + exit 1 +fi +if valid_domain '127.0.0.1'; then + echo 'FAIL: IP address was accepted as a domain' >&2 + exit 1 +fi + +create_webui_domain 'Chat.Example.com' 'admin' 'test-password' +[ "$(cat "$MOCK_K_ARGS_LOG")" = 'fd chat.example.com 127.0.0.1 3080' ] +grep -qxF 'chat.example.com' "$DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE" +[ "$(stat -c '%a' "$DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE")" = '600' ] +webui_conf="$DEEPSEEK_HARNESS_WEB_CONF_DIR/chat.example.com.conf" +webui_auth="$DEEPSEEK_HARNESS_WEB_CONF_DIR/.deepseek-harness-chat.example.com.htpasswd" +grep -Fq '# kejilion-deepseek-harness-managed' "$webui_conf" +grep -Fq 'auth_basic "DeepSeek Harness";' "$webui_conf" +grep -Fq 'auth_basic_user_file /etc/nginx/conf.d/.deepseek-harness-chat.example.com.htpasswd;' "$webui_conf" +grep -Fq 'proxy_read_timeout 1d;' "$webui_conf" +grep -Fq 'proxy_send_timeout 1d;' "$webui_conf" +if grep -Eq '^[[:space:]]*proxy_cache[[:space:]]' "$webui_conf"; then + echo 'FAIL: generated WebUI proxy still enables static asset cache' >&2 + exit 1 +fi +grep -qxF 'admin:$apr1$mock$hashed-password' "$webui_auth" +[ "$(stat -c '%a' "$webui_auth")" = '644' ] + +configure_systemd_service +grep -Fq ' --trusted-host chat.example.com' "$DEEPSEEK_HARNESS_SERVICE_FILE" + +touch "$DEEPSEEK_HARNESS_WEB_CONF_DIR/existing.example.com.conf" +if create_webui_domain 'existing.example.com' 'admin' 'test-password'; then + echo 'FAIL: existing website was overwritten' >&2 + exit 1 +fi +[ "$(wc -l <"$MOCK_K_ARGS_LOG" | tr -d '[:space:]')" = '1' ] + +delete_webui_domain 'chat.example.com' +[ ! -e "$webui_conf" ] +[ ! -e "$webui_auth" ] +[ ! -e "$DEEPSEEK_HARNESS_WEB_CERT_DIR/chat.example.com_cert.pem" ] +[ ! -e "$DEEPSEEK_HARNESS_WEB_CERT_DIR/chat.example.com_key.pem" ] +if grep -qxF 'chat.example.com' "$DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE"; then + echo 'FAIL: deleted domain remains in trusted-host records' >&2 + exit 1 +fi +if grep -Fq 'web del' "$MOCK_K_ARGS_LOG"; then + echo 'FAIL: WebUI deletion called the generic site/database deletion path' >&2 + exit 1 +fi +configure_systemd_service +if grep -Fq ' --trusted-host chat.example.com' "$DEEPSEEK_HARNESS_SERVICE_FILE"; then + echo 'FAIL: deleted domain remains in the generated systemd service' >&2 + exit 1 +fi + mark_app_installed grep -qxF '116' "$DEEPSEEK_HARNESS_APP_MARKER_FILE" unmark_app_installed From a70793a344bdb0fc214d4b5ef1e722516d5d36e4 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sat, 15 Aug 2026 14:24:53 +0800 Subject: [PATCH 1271/1285] chore: release kejilion.sh 4.5.6 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kejilion_sh_log.txt | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 76132e1ce..7abd689d9 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.5" +sh_v="4.5.6" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 5a89ed68b..60ba3c8ac 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.5" +sh_v="4.5.6" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index f8d181e6b..cdad8777c 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1536,4 +1536,9 @@ KPanel调用BBRv3流程时不会自动重启服务器,任务完成后由用户 新增KPanel SSH端口非交互适配入口,复用脚本原有单端口修改业务,并在配置语法和新端口监听均验证通过后返回机器可读结果。 修复多网络容器的IP端口访问规则只处理单一地址的问题,对每个Docker IPv4同步写入、识别和清理DOCKER-USER规则。 根目录与CN脚本保持同步;原SSH交互入口、单网络容器和应用访问策略保持兼容。 +------------------------ +2026-08-15 v4.5.6 +应用市场新增官方DeepSeek Harness管理工具,支持安装、启动、停止、API管理、模型切换、命令行单次任务、更新和卸载。 +优化DeepSeek Harness的npm安装脚本兼容性,确保官方本地子进程等必要依赖能够正确安装。 +DeepSeek Harness新增WebUI域名访问管理,支持HTTPS、Basic Auth和trusted-host安全配置,并可安全删除已托管域名。 From 2e3a39ef25c47c5e26dc9de927df3f0104648904 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 16 Aug 2026 11:07:09 +0800 Subject: [PATCH 1272/1285] fix(harness): grant nginx scoped auth access --- deepseek_harness_manager.sh | 49 ++++++++++++++++++++++++-- tests/test_deepseek_harness_manager.sh | 16 ++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/deepseek_harness_manager.sh b/deepseek_harness_manager.sh index c3914f1f9..60e1b822c 100644 --- a/deepseek_harness_manager.sh +++ b/deepseek_harness_manager.sh @@ -239,11 +239,51 @@ write_webui_auth_file() { umask 077 temporary_file=$(mktemp "${auth_file}.tmp.XXXXXX") || return 1 printf '%s:%s\n' "$username" "$password_hash" >"$temporary_file" - # Nginx worker needs read access; the file stores only an APR1 password hash. - chmod 644 "$temporary_file" + chmod 600 "$temporary_file" mv -f "$temporary_file" "$auth_file" } +ensure_webui_acl_tool() { + command -v setfacl >/dev/null 2>&1 && return 0 + echo -e "${YELLOW}正在安装 ACL 工具,用于限定 Nginx 仅访问 Harness 认证文件...${NC}" + if command -v apt-get >/dev/null 2>&1; then + apt-get install -y acl >/dev/null 2>&1 + elif command -v dnf >/dev/null 2>&1; then + dnf install -y acl >/dev/null 2>&1 + elif command -v yum >/dev/null 2>&1; then + yum install -y acl >/dev/null 2>&1 + elif command -v apk >/dev/null 2>&1; then + apk add --no-cache acl >/dev/null 2>&1 + else + return 1 + fi + command -v setfacl >/dev/null 2>&1 +} + +nginx_worker_uid() { + local uid + uid=$(docker exec nginx id -u nginx 2>/dev/null) || return 1 + uid=$(printf '%s' "$uid" | tr -d '[:space:]') + case "$uid" in + ''|*[!0-9]*) return 1 ;; + esac + printf '%s' "$uid" +} + +grant_webui_auth_access() { + local domain="$1" auth_file auth_path nginx_uid + auth_file=$(webui_auth_file "$domain") + auth_path="/etc/nginx/conf.d/$(basename "$auth_file")" + [ -f "$auth_file" ] || return 1 + nginx_uid=$(nginx_worker_uid) || return 1 + # Keep the shared conf.d mode unchanged: allow only directory traversal and + # read access to this Harness password file for the Nginx worker UID. + setfacl -m "u:${nginx_uid}:--x" "$WEB_CONF_DIR" || return 1 + setfacl -m "u:${nginx_uid}:r--" "$auth_file" || return 1 + # Open the file as the worker UID; BusyBox test -r may ignore POSIX ACLs. + docker exec -u "$nginx_uid" nginx sh -c ': < "$1"' sh "$auth_path" >/dev/null 2>&1 +} + patch_webui_proxy_config() { local domain="$1" conf_file auth_path conf_file="$WEB_CONF_DIR/${domain}.conf" @@ -330,12 +370,17 @@ create_webui_domain() { echo -e "${RED}找不到 k 命令,无法调用 k fd 创建反向代理。${NC}" return 1 } + ensure_webui_acl_tool || { + echo -e "${RED}缺少 ACL 工具,无法安全配置 Nginx 认证文件权限。${NC}" + return 1 + } if ! "$K_COMMAND" fd "$domain" "$LISTEN_HOST" "$LISTEN_PORT"; then rollback_webui_domain_add "$domain" echo -e "${RED}k fd 创建反向代理失败,已清理本次产生的文件。${NC}" return 1 fi if ! write_webui_auth_file "$domain" "$username" "$password" \ + || ! grant_webui_auth_access "$domain" \ || ! patch_webui_proxy_config "$domain" \ || ! reload_managed_nginx \ || ! add_webui_domain_record "$domain" \ diff --git a/tests/test_deepseek_harness_manager.sh b/tests/test_deepseek_harness_manager.sh index 8c71be59a..9c45b452a 100644 --- a/tests/test_deepseek_harness_manager.sh +++ b/tests/test_deepseek_harness_manager.sh @@ -19,6 +19,7 @@ export DEEPSEEK_HARNESS_K_COMMAND="k" export MOCK_NPM_ARGS_LOG="${temporary_dir}/npm-args.log" export MOCK_K_ARGS_LOG="${temporary_dir}/k-args.log" export MOCK_DOCKER_ARGS_LOG="${temporary_dir}/docker-args.log" +export MOCK_SETFACL_ARGS_LOG="${temporary_dir}/setfacl-args.log" export PATH="${temporary_dir}/bin:${PATH}" mkdir -p "${temporary_dir}/bin" "$DSH_HOME" "$DEEPSEEK_HARNESS_WEB_CONF_DIR" "$DEEPSEEK_HARNESS_WEB_CERT_DIR" @@ -72,8 +73,15 @@ MOCK cat >"${temporary_dir}/bin/docker" <<'MOCK' #!/bin/bash printf '%s\n' "$*" >>"$MOCK_DOCKER_ARGS_LOG" +if [ "$*" = "exec nginx id -u nginx" ]; then + printf '%s\n' '101' +fi exit 0 MOCK +cat >"${temporary_dir}/bin/setfacl" <<'MOCK' +#!/bin/bash +printf '%s\n' "$*" >>"$MOCK_SETFACL_ARGS_LOG" +MOCK cat >"${temporary_dir}/bin/k" <<'MOCK' #!/bin/bash printf '%s\n' "$*" >>"$MOCK_K_ARGS_LOG" @@ -113,6 +121,7 @@ chmod +x \ "${temporary_dir}/bin/curl" \ "${temporary_dir}/bin/openssl" \ "${temporary_dir}/bin/docker" \ + "${temporary_dir}/bin/setfacl" \ "${temporary_dir}/bin/k" # shellcheck source=../deepseek_harness_manager.sh @@ -201,6 +210,7 @@ if valid_domain '127.0.0.1'; then exit 1 fi +chmod 750 "$DEEPSEEK_HARNESS_WEB_CONF_DIR" create_webui_domain 'Chat.Example.com' 'admin' 'test-password' [ "$(cat "$MOCK_K_ARGS_LOG")" = 'fd chat.example.com 127.0.0.1 3080' ] grep -qxF 'chat.example.com' "$DEEPSEEK_HARNESS_WEBUI_DOMAINS_FILE" @@ -217,7 +227,11 @@ if grep -Eq '^[[:space:]]*proxy_cache[[:space:]]' "$webui_conf"; then exit 1 fi grep -qxF 'admin:$apr1$mock$hashed-password' "$webui_auth" -[ "$(stat -c '%a' "$webui_auth")" = '644' ] +[ "$(stat -c '%a' "$webui_auth")" = '600' ] +[ "$(stat -c '%a' "$DEEPSEEK_HARNESS_WEB_CONF_DIR")" = '750' ] +grep -Fqx -- "-m u:101:--x $DEEPSEEK_HARNESS_WEB_CONF_DIR" "$MOCK_SETFACL_ARGS_LOG" +grep -Fqx -- "-m u:101:r-- $webui_auth" "$MOCK_SETFACL_ARGS_LOG" +grep -Fqx -- 'exec -u 101 nginx sh -c : < "$1" sh /etc/nginx/conf.d/.deepseek-harness-chat.example.com.htpasswd' "$MOCK_DOCKER_ARGS_LOG" configure_systemd_service grep -Fq ' --trusted-host chat.example.com' "$DEEPSEEK_HARNESS_SERVICE_FILE" From c5fc243d4a7891fd66f92e36204a17584afb1535 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 16 Aug 2026 12:24:52 +0800 Subject: [PATCH 1273/1285] chore: release kejilion.sh 4.5.7 --- cn/kejilion.sh | 2 +- kejilion.sh | 2 +- kejilion_sh_log.txt | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7abd689d9..a3a6f4b6c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.6" +sh_v="4.5.7" gl_hui='\e[37m' diff --git a/kejilion.sh b/kejilion.sh index 60ba3c8ac..ac4950c17 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -1,5 +1,5 @@ #!/bin/bash -sh_v="4.5.6" +sh_v="4.5.7" gl_hui='\e[37m' diff --git a/kejilion_sh_log.txt b/kejilion_sh_log.txt index cdad8777c..e22a2f649 100644 --- a/kejilion_sh_log.txt +++ b/kejilion_sh_log.txt @@ -1541,4 +1541,8 @@ KPanel调用BBRv3流程时不会自动重启服务器,任务完成后由用户 应用市场新增官方DeepSeek Harness管理工具,支持安装、启动、停止、API管理、模型切换、命令行单次任务、更新和卸载。 优化DeepSeek Harness的npm安装脚本兼容性,确保官方本地子进程等必要依赖能够正确安装。 DeepSeek Harness新增WebUI域名访问管理,支持HTTPS、Basic Auth和trusted-host安全配置,并可安全删除已托管域名。 +------------------------ +2026-08-16 v4.5.7 +修复DeepSeek Harness WebUI认证文件权限,使用POSIX ACL仅向Nginx工作进程授予目录遍历和认证文件读取权限。 +认证文件继续保持0600,不扩大共享Nginx配置目录或其他文件的读取范围。 From 70a36d736f933d78bbe682f53e37efb729d03e7e Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 16 Aug 2026 15:33:11 +0800 Subject: [PATCH 1274/1285] fix(harness): explicitly remove domain credentials --- deepseek_harness_manager.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/deepseek_harness_manager.sh b/deepseek_harness_manager.sh index 60e1b822c..7b44c57a5 100644 --- a/deepseek_harness_manager.sh +++ b/deepseek_harness_manager.sh @@ -320,11 +320,16 @@ remove_webui_domain_artifacts() { local domain="$1" rm -f -- \ "$WEB_CONF_DIR/${domain}.conf" \ - "$(webui_auth_file "$domain")" \ "$WEB_CERT_DIR/${domain}_cert.pem" \ "$WEB_CERT_DIR/${domain}_key.pem" } +remove_webui_auth_credentials() { + local domain="$1" + # Delete only the Basic Auth file belonging to this managed Harness domain. + rm -f -- "$(webui_auth_file "$domain")" +} + refresh_trusted_hosts() { if harness_running; then restart_if_running @@ -336,6 +341,7 @@ refresh_trusted_hosts() { rollback_webui_domain_add() { local domain="$1" remove_webui_domain_record "$domain" || true + remove_webui_auth_credentials "$domain" || true remove_webui_domain_artifacts "$domain" reload_managed_nginx >/dev/null 2>&1 || true refresh_trusted_hosts >/dev/null 2>&1 || true @@ -401,6 +407,7 @@ delete_webui_domain() { echo -e "${RED}该域名不在 DeepSeek Harness 托管列表中,拒绝删除。${NC}" return 1 } + remove_webui_auth_credentials "$domain" || return 1 remove_webui_domain_artifacts "$domain" || return 1 remove_webui_domain_record "$domain" || return 1 if command -v docker >/dev/null 2>&1 && docker inspect nginx >/dev/null 2>&1; then From e79796b4da84b9bbe2c9bf13d221581cd631a5d0 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 15:11:41 +0800 Subject: [PATCH 1275/1285] fix(kpanel): harden one-click system tuning AI-Scope: system-tuning-runtime-compat --- cn/kejilion.sh | 176 +++++++++++------- kejilion.sh | 176 +++++++++++------- tests/test_kpanel_dns_noninteractive_smoke.sh | 25 ++- ...anel_system_tuning_noninteractive_smoke.sh | 58 +++++- 4 files changed, 291 insertions(+), 144 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index a3a6f4b6c..60f961823 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4371,10 +4371,51 @@ kpanel_system_tuning_firewall_open_all() { kpanel_system_resource_firewall_action open-all "$version" >&2 } +kpanel_system_tuning_swap_1g_ready() { + local swapfile="${1:-/swapfile}" swaps="${2:-/proc/swaps}" fstab="${3:-/etc/fstab}" size + [ -f "$swapfile" ] && [ ! -L "$swapfile" ] || return 1 + size="$(stat -c '%s' -- "$swapfile" 2>/dev/null)" + [ "$size" = 1073741824 ] || return 1 + awk -v path="$swapfile" 'NR > 1 && $1 == path { found=1 } END { exit !found }' "$swaps" 2>/dev/null || return 1 + awk -v path="$swapfile" '$1 == path && $2 == "swap" { found=1 } END { exit !found }' "$fstab" 2>/dev/null +} + +kpanel_system_tuning_dns_auto() { + local country dns1_ipv4 dns2_ipv4 dns1_ipv6 dns2_ipv6 + local dns=() + country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + if [ "$country" = CN ]; then + dns1_ipv4="223.5.5.5" + dns2_ipv4="183.60.83.19" + dns1_ipv6="2400:3200::1" + dns2_ipv6="2400:da00::6666" + else + dns1_ipv4="1.1.1.1" + dns2_ipv4="8.8.8.8" + dns1_ipv6="2606:4700:4700::1111" + dns2_ipv6="2001:4860:4860::8888" + fi + ip_address + [ -n "$ipv4_address" ] && dns+=("$dns1_ipv4" "$dns2_ipv4") + [ -n "$ipv6_address" ] && dns+=("$dns1_ipv6" "$dns2_ipv6") + [ "${#dns[@]}" -gt 0 ] || dns=("$dns1_ipv4" "$dns2_ipv4") + KJ_DNS_NONINTERACTIVE=1 kpanel_set_dns_noninteractive "${dns[@]}" +} + +kpanel_system_tuning_has_package_manager() { + local mode="$1" command_name + local commands=(dnf yum apt apk pacman zypper opkg) + [ "$mode" = cleanup ] && commands+=(pkg) + for command_name in "${commands[@]}"; do + command -v "$command_name" >/dev/null 2>&1 && return 0 + done + return 1 +} + kpanel_system_tuning_item_ready() { local item="$1" command_name case "$item" in - swap-1g) [ "$(free -m 2>/dev/null | awk '/^Swap:/{print $2; exit}')" = 1024 ] ;; + swap-1g) kpanel_system_tuning_swap_1g_ready ;; ssh-port-5522) sshd -T 2>/dev/null | grep -Eq '^port 5522$' ;; ssh-defense) kpanel_f2b_enabled >/dev/null 2>&1 ;; firewall-open-all) iptables-save 2>/dev/null | awk '$0=="*filter"{f=1;next} f&&$0=="COMMIT"{exit} f&&/^:INPUT /{i=$2} f&&/^:FORWARD /{w=$2} END{exit !(i=="ACCEPT"&&w=="ACCEPT")}' ;; @@ -4413,15 +4454,22 @@ kpanel_system_tuning_emit() { kpanel_system_tuning_run_item() { case "$1" in - system-update) kpanel_system_tuning_switch_mirror && linux_update ;; - system-cleanup) linux_clean ;; + system-update) + kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } + kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } + linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } + ;; + system-cleanup) + kpanel_system_tuning_has_package_manager cleanup || { kpanel_system_tuning_error "当前系统没有受支持的清理适配器"; return 1; } + linux_clean || { kpanel_system_tuning_error "系统清理失败"; return 1; } + ;; swap-1g) add_swap 1024 ;; ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; firewall-open-all) kpanel_system_tuning_firewall_open_all ;; bbr) bbr_on ;; timezone-shanghai) set_timedate Asia/Shanghai ;; - dns-auto) auto_optimize_dns ;; + dns-auto) kpanel_system_tuning_dns_auto ;; ipv4-preferred) prefer_ipv4 ;; basic-tools) install_docker && install wget sudo tar unzip socat btop nano vim ;; kernel-auto) kpanel_system_tuning_kernel_auto ;; @@ -4429,6 +4477,22 @@ kpanel_system_tuning_run_item() { esac } +kpanel_system_tuning_menu_item() { + local item="$1" index="$2" label="$3" + echo "------------------------------------------------" + if ! kpanel_system_tuning_run_item "$item"; then + echo -e "[${gl_hong}FAIL${gl_bai}] ${index}/12. ${label},一条龙调优已停止" + return 1 + fi + case "$item" in system-update|system-cleanup|dns-auto) ;; *) + if ! kpanel_system_tuning_item_ready "$item"; then + echo -e "[${gl_hong}FAIL${gl_bai}] ${index}/12. ${label},完成态回读失败,一条龙调优已停止" + return 1 + fi + ;; esac + echo -e "[${gl_lv}OK${gl_bai}] ${index}/12. ${label}" +} + kpanel_system_tuning_apply_item() { local item="$1" status=applied if kpanel_system_tuning_item_ready "$item"; then @@ -6124,7 +6188,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" local parent desired backup old_mode old_immutable="false" existed="false" - local expected="" value + local expected="" value published="false" if [ -L "$target" ]; then target="$(readlink -f "$target")" @@ -6138,11 +6202,6 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - command -v chattr >/dev/null 2>&1 || { - echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" - return 1 - } - desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { rm -f "$desired" @@ -6168,25 +6227,23 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if command -v lsattr >/dev/null 2>&1 && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - chattr +i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法锁定 DNS 配置" - return 1 - } + command -v chattr >/dev/null 2>&1 && chattr +i "$target" >/dev/null 2>&1 || true rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } + if [ "$old_immutable" = "true" ]; then + command -v chattr >/dev/null 2>&1 && chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } + fi else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6194,9 +6251,13 @@ kpanel_dns_write_static() { } fi - if ! mv -f "$desired" "$target" || - ! chattr +i "$target" >/dev/null 2>&1 || - [ "$(cat "$target")"$'\n' != "$expected" ]; then + if mv -f "$desired" "$target" 2>/dev/null; then + published="true" + elif cat "$desired" > "$target" 2>/dev/null; then + rm -f "$desired" + published="true" + fi + if [ "$published" != "true" ] || [ "$(cat "$target" 2>/dev/null)"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6206,6 +6267,16 @@ kpanel_dns_write_static() { echo "错误: DNS 写入或回读验证失败,已恢复原配置" return 1 fi + if command -v chattr >/dev/null 2>&1 && ! chattr +i "$target" >/dev/null 2>&1 && [ "$old_immutable" = "true" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 配置锁定恢复失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: 无法恢复原有 DNS 配置锁定,已恢复原配置" + return 1 + fi rm -f "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT applied" @@ -26992,53 +27063,20 @@ EOF [Yy]) clear send_stats "一条龙调优启动" - echo "------------------------------------------------" - kpanel_system_tuning_run_item system-update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item system-cleanup - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item swap-1g - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item ssh-port-5522 - echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo "------------------------------------------------" - kpanel_system_tuning_run_item ssh-defense + kpanel_system_tuning_menu_item system-update 1 "更新系统到最新" || break + kpanel_system_tuning_menu_item system-cleanup 2 "清理系统垃圾文件" || break + kpanel_system_tuning_menu_item swap-1g 3 "设置虚拟内存${gl_huang}1G${gl_bai}" || break + kpanel_system_tuning_menu_item ssh-port-5522 4 "设置SSH端口号为${gl_huang}5522${gl_bai}" || break + kpanel_system_tuning_menu_item ssh-defense 5 "启动fail2ban防御SSH暴力破解" || break cd ~ f2b_status - echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item firewall-open-all - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item bbr - echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item timezone-shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item dns-auto - echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" - echo "------------------------------------------------" - kpanel_system_tuning_run_item ipv4-preferred - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item basic-tools - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo "------------------------------------------------" - - kpanel_system_tuning_run_item kernel-auto - echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" + kpanel_system_tuning_menu_item firewall-open-all 6 "开放所有端口" || break + kpanel_system_tuning_menu_item bbr 7 "开启${gl_huang}BBR${gl_bai}加速" || break + kpanel_system_tuning_menu_item timezone-shanghai 8 "设置时区到${gl_huang}上海${gl_bai}" || break + kpanel_system_tuning_menu_item dns-auto 9 "自动优化DNS地址" || break + kpanel_system_tuning_menu_item ipv4-preferred 10 "设置网络为${gl_huang}IPv4优先${gl_bai}" || break + kpanel_system_tuning_menu_item basic-tools 11 "安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" || break + kpanel_system_tuning_menu_item kernel-auto 12 "Linux系统内核参数优化" || break echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; diff --git a/kejilion.sh b/kejilion.sh index ac4950c17..a78c60255 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4371,10 +4371,51 @@ kpanel_system_tuning_firewall_open_all() { kpanel_system_resource_firewall_action open-all "$version" >&2 } +kpanel_system_tuning_swap_1g_ready() { + local swapfile="${1:-/swapfile}" swaps="${2:-/proc/swaps}" fstab="${3:-/etc/fstab}" size + [ -f "$swapfile" ] && [ ! -L "$swapfile" ] || return 1 + size="$(stat -c '%s' -- "$swapfile" 2>/dev/null)" + [ "$size" = 1073741824 ] || return 1 + awk -v path="$swapfile" 'NR > 1 && $1 == path { found=1 } END { exit !found }' "$swaps" 2>/dev/null || return 1 + awk -v path="$swapfile" '$1 == path && $2 == "swap" { found=1 } END { exit !found }' "$fstab" 2>/dev/null +} + +kpanel_system_tuning_dns_auto() { + local country dns1_ipv4 dns2_ipv4 dns1_ipv6 dns2_ipv6 + local dns=() + country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + if [ "$country" = CN ]; then + dns1_ipv4="223.5.5.5" + dns2_ipv4="183.60.83.19" + dns1_ipv6="2400:3200::1" + dns2_ipv6="2400:da00::6666" + else + dns1_ipv4="1.1.1.1" + dns2_ipv4="8.8.8.8" + dns1_ipv6="2606:4700:4700::1111" + dns2_ipv6="2001:4860:4860::8888" + fi + ip_address + [ -n "$ipv4_address" ] && dns+=("$dns1_ipv4" "$dns2_ipv4") + [ -n "$ipv6_address" ] && dns+=("$dns1_ipv6" "$dns2_ipv6") + [ "${#dns[@]}" -gt 0 ] || dns=("$dns1_ipv4" "$dns2_ipv4") + KJ_DNS_NONINTERACTIVE=1 kpanel_set_dns_noninteractive "${dns[@]}" +} + +kpanel_system_tuning_has_package_manager() { + local mode="$1" command_name + local commands=(dnf yum apt apk pacman zypper opkg) + [ "$mode" = cleanup ] && commands+=(pkg) + for command_name in "${commands[@]}"; do + command -v "$command_name" >/dev/null 2>&1 && return 0 + done + return 1 +} + kpanel_system_tuning_item_ready() { local item="$1" command_name case "$item" in - swap-1g) [ "$(free -m 2>/dev/null | awk '/^Swap:/{print $2; exit}')" = 1024 ] ;; + swap-1g) kpanel_system_tuning_swap_1g_ready ;; ssh-port-5522) sshd -T 2>/dev/null | grep -Eq '^port 5522$' ;; ssh-defense) kpanel_f2b_enabled >/dev/null 2>&1 ;; firewall-open-all) iptables-save 2>/dev/null | awk '$0=="*filter"{f=1;next} f&&$0=="COMMIT"{exit} f&&/^:INPUT /{i=$2} f&&/^:FORWARD /{w=$2} END{exit !(i=="ACCEPT"&&w=="ACCEPT")}' ;; @@ -4413,15 +4454,22 @@ kpanel_system_tuning_emit() { kpanel_system_tuning_run_item() { case "$1" in - system-update) kpanel_system_tuning_switch_mirror && linux_update ;; - system-cleanup) linux_clean ;; + system-update) + kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } + kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } + linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } + ;; + system-cleanup) + kpanel_system_tuning_has_package_manager cleanup || { kpanel_system_tuning_error "当前系统没有受支持的清理适配器"; return 1; } + linux_clean || { kpanel_system_tuning_error "系统清理失败"; return 1; } + ;; swap-1g) add_swap 1024 ;; ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; firewall-open-all) kpanel_system_tuning_firewall_open_all ;; bbr) bbr_on ;; timezone-shanghai) set_timedate Asia/Shanghai ;; - dns-auto) auto_optimize_dns ;; + dns-auto) kpanel_system_tuning_dns_auto ;; ipv4-preferred) prefer_ipv4 ;; basic-tools) install_docker && install wget sudo tar unzip socat btop nano vim ;; kernel-auto) kpanel_system_tuning_kernel_auto ;; @@ -4429,6 +4477,22 @@ kpanel_system_tuning_run_item() { esac } +kpanel_system_tuning_menu_item() { + local item="$1" index="$2" label="$3" + echo "------------------------------------------------" + if ! kpanel_system_tuning_run_item "$item"; then + echo -e "[${gl_hong}FAIL${gl_bai}] ${index}/12. ${label},一条龙调优已停止" + return 1 + fi + case "$item" in system-update|system-cleanup|dns-auto) ;; *) + if ! kpanel_system_tuning_item_ready "$item"; then + echo -e "[${gl_hong}FAIL${gl_bai}] ${index}/12. ${label},完成态回读失败,一条龙调优已停止" + return 1 + fi + ;; esac + echo -e "[${gl_lv}OK${gl_bai}] ${index}/12. ${label}" +} + kpanel_system_tuning_apply_item() { local item="$1" status=applied if kpanel_system_tuning_item_ready "$item"; then @@ -6124,7 +6188,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" local parent desired backup old_mode old_immutable="false" existed="false" - local expected="" value + local expected="" value published="false" if [ -L "$target" ]; then target="$(readlink -f "$target")" @@ -6138,11 +6202,6 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - command -v chattr >/dev/null 2>&1 || { - echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" - return 1 - } - desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { rm -f "$desired" @@ -6168,25 +6227,23 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if command -v lsattr >/dev/null 2>&1 && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - chattr +i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法锁定 DNS 配置" - return 1 - } + command -v chattr >/dev/null 2>&1 && chattr +i "$target" >/dev/null 2>&1 || true rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } + if [ "$old_immutable" = "true" ]; then + command -v chattr >/dev/null 2>&1 && chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } + fi else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6194,9 +6251,13 @@ kpanel_dns_write_static() { } fi - if ! mv -f "$desired" "$target" || - ! chattr +i "$target" >/dev/null 2>&1 || - [ "$(cat "$target")"$'\n' != "$expected" ]; then + if mv -f "$desired" "$target" 2>/dev/null; then + published="true" + elif cat "$desired" > "$target" 2>/dev/null; then + rm -f "$desired" + published="true" + fi + if [ "$published" != "true" ] || [ "$(cat "$target" 2>/dev/null)"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6206,6 +6267,16 @@ kpanel_dns_write_static() { echo "错误: DNS 写入或回读验证失败,已恢复原配置" return 1 fi + if command -v chattr >/dev/null 2>&1 && ! chattr +i "$target" >/dev/null 2>&1 && [ "$old_immutable" = "true" ]; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 配置锁定恢复失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: 无法恢复原有 DNS 配置锁定,已恢复原配置" + return 1 + fi rm -f "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT applied" @@ -26992,53 +27063,20 @@ EOF [Yy]) clear send_stats "一条龙调优启动" - echo "------------------------------------------------" - kpanel_system_tuning_run_item system-update - echo -e "[${gl_lv}OK${gl_bai}] 1/12. 更新系统到最新" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item system-cleanup - echo -e "[${gl_lv}OK${gl_bai}] 2/12. 清理系统垃圾文件" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item swap-1g - echo -e "[${gl_lv}OK${gl_bai}] 3/12. 设置虚拟内存${gl_huang}1G${gl_bai}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item ssh-port-5522 - echo -e "[${gl_lv}OK${gl_bai}] 4/12. 设置SSH端口号为${gl_huang}5522${gl_bai}" - echo "------------------------------------------------" - kpanel_system_tuning_run_item ssh-defense + kpanel_system_tuning_menu_item system-update 1 "更新系统到最新" || break + kpanel_system_tuning_menu_item system-cleanup 2 "清理系统垃圾文件" || break + kpanel_system_tuning_menu_item swap-1g 3 "设置虚拟内存${gl_huang}1G${gl_bai}" || break + kpanel_system_tuning_menu_item ssh-port-5522 4 "设置SSH端口号为${gl_huang}5522${gl_bai}" || break + kpanel_system_tuning_menu_item ssh-defense 5 "启动fail2ban防御SSH暴力破解" || break cd ~ f2b_status - echo -e "[${gl_lv}OK${gl_bai}] 5/12. 启动fail2ban防御SSH暴力破解" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item firewall-open-all - echo -e "[${gl_lv}OK${gl_bai}] 6/12. 开放所有端口" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item bbr - echo -e "[${gl_lv}OK${gl_bai}] 7/12. 开启${gl_huang}BBR${gl_bai}加速" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item timezone-shanghai - echo -e "[${gl_lv}OK${gl_bai}] 8/12. 设置时区到${gl_huang}上海${gl_bai}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item dns-auto - echo -e "[${gl_lv}OK${gl_bai}] 9/12. 自动优化DNS地址${gl_huang}${gl_bai}" - echo "------------------------------------------------" - kpanel_system_tuning_run_item ipv4-preferred - echo -e "[${gl_lv}OK${gl_bai}] 10/12. 设置网络为${gl_huang}ipv4优先${gl_bai}}" - - echo "------------------------------------------------" - kpanel_system_tuning_run_item basic-tools - echo -e "[${gl_lv}OK${gl_bai}] 11/12. 安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" - echo "------------------------------------------------" - - kpanel_system_tuning_run_item kernel-auto - echo -e "[${gl_lv}OK${gl_bai}] 12/12. Linux系统内核参数优化" + kpanel_system_tuning_menu_item firewall-open-all 6 "开放所有端口" || break + kpanel_system_tuning_menu_item bbr 7 "开启${gl_huang}BBR${gl_bai}加速" || break + kpanel_system_tuning_menu_item timezone-shanghai 8 "设置时区到${gl_huang}上海${gl_bai}" || break + kpanel_system_tuning_menu_item dns-auto 9 "自动优化DNS地址" || break + kpanel_system_tuning_menu_item ipv4-preferred 10 "设置网络为${gl_huang}IPv4优先${gl_bai}" || break + kpanel_system_tuning_menu_item basic-tools 11 "安装基础工具${gl_huang}docker wget sudo tar unzip socat btop nano vim${gl_bai}" || break + kpanel_system_tuning_menu_item kernel-auto 12 "Linux系统内核参数优化" || break echo -e "${gl_lv}一条龙系统调优已完成${gl_bai}" ;; diff --git a/tests/test_kpanel_dns_noninteractive_smoke.sh b/tests/test_kpanel_dns_noninteractive_smoke.sh index 5b8f3ec3d..e514e5e4b 100644 --- a/tests/test_kpanel_dns_noninteractive_smoke.sh +++ b/tests/test_kpanel_dns_noninteractive_smoke.sh @@ -2,7 +2,11 @@ set -euo pipefail project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -script_path="${project_root}/kejilion.sh" +source_script="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" +temporary="$(mktemp -d)" +trap 'rm -rf -- "$temporary"' EXIT +script_path="$temporary/kejilion.sh" +sed 's/\r$//' "$source_script" > "$script_path" bash -n "${script_path}" grep -F 'kpanel_set_dns_noninteractive() {' "${script_path}" >/dev/null @@ -55,4 +59,23 @@ if kpanel_protocol_active; then exit 1 fi +dns_writer_body="$( + awk ' + /^kpanel_dns_restore_file\(\) \{/ { capture=1 } + /^kpanel_dns_write_systemd_resolved\(\) \{/ { exit } + capture { print } + ' "${script_path}" | sed 's#local target="/etc/resolv.conf"#local target="$KPANEL_DNS_TEST_TARGET"#' +)" +eval "$dns_writer_body" +KPANEL_DNS_TEST_TARGET="$temporary/resolv.conf" +printf 'nameserver 9.9.9.9\n' > "$KPANEL_DNS_TEST_TARGET" +chattr() { return 1; } +lsattr() { return 1; } +mv() { return 1; } +dns_result="$(kpanel_dns_write_static 1.1.1.1 8.8.8.8)" +grep -F 'KPANEL_DNS_RESULT applied' <<< "$dns_result" >/dev/null +[ "$(cat "$KPANEL_DNS_TEST_TARGET")"$'\n' = $'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' ] +dns_result="$(kpanel_dns_write_static 1.1.1.1 8.8.8.8)" +grep -F 'KPANEL_DNS_RESULT unchanged' <<< "$dns_result" >/dev/null + printf '%s\n' "kpanel_dns_noninteractive_smoke=pass" diff --git a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh index 7790526ca..5844a1bd0 100644 --- a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh @@ -26,6 +26,23 @@ functions="$(awk ' eval "$functions" kpanel_system_resource_zero_version() { printf '%064d\n' 0; } + +truncate -s 1073741824 "$temporary/swapfile" +printf 'Filename Type Size Used Priority\n%s file 1048572 0 -2\n' "$temporary/swapfile" > "$temporary/swaps" +printf '%s swap swap defaults 0 0\n' "$temporary/swapfile" > "$temporary/fstab" +kpanel_system_tuning_swap_1g_ready "$temporary/swapfile" "$temporary/swaps" "$temporary/fstab" +truncate -s 1073737728 "$temporary/swapfile" +if kpanel_system_tuning_swap_1g_ready "$temporary/swapfile" "$temporary/swaps" "$temporary/fstab"; then + echo "undersized swapfile was accepted as a complete 1 GiB swap" >&2 + exit 1 +fi + +curl() { printf 'CN\n'; } +ip_address() { ipv4_address="192.0.2.1"; ipv6_address=""; } +kpanel_set_dns_noninteractive() { printf '%s\n' "$KJ_DNS_NONINTERACTIVE:$*" > "$temporary/dns-action"; } +kpanel_system_tuning_dns_auto +grep -Fqx '1:223.5.5.5 183.60.83.19' "$temporary/dns-action" + : > "$temporary/ready-items" kpanel_system_tuning_item_ready() { grep -Fxq "$1" "$temporary/ready-items"; } kpanel_system_tuning_run_item() { printf '%s\n' "$1" >> "$temporary/run-items"; printf '%s\n' "$1" >> "$temporary/ready-items"; } @@ -41,17 +58,20 @@ version="$(grep '^KPANEL_SYSTEM_TUNING_VERSION=' <<< "$status_output" | cut -d= [[ "$version" =~ ^[0-9a-f]{64}$ ]] ! kpanel_system_tuning_valid_item arbitrary-command -apply_output="$(kpanel_system_tuning_apply_item bbr)" -grep -F 'KPANEL_SYSTEM_TUNING_STATUS=applied' <<< "$apply_output" >/dev/null -grep -F 'KPANEL_SYSTEM_TUNING_SELECTED=bbr' <<< "$apply_output" >/dev/null -grep -F 'KPANEL_SYSTEM_TUNING_ITEM=bbr:ready' <<< "$apply_output" >/dev/null -grep -Fx bbr "$temporary/run-items" >/dev/null +for item in system-update system-cleanup swap-1g ssh-port-5522 ssh-defense firewall-open-all bbr timezone-shanghai dns-auto ipv4-preferred basic-tools kernel-auto; do + apply_output="$(kpanel_system_tuning_apply_item "$item")" + grep -F 'KPANEL_SYSTEM_TUNING_STATUS=applied' <<< "$apply_output" >/dev/null + grep -F "KPANEL_SYSTEM_TUNING_SELECTED=$item" <<< "$apply_output" >/dev/null + grep -F "KPANEL_SYSTEM_TUNING_ITEM=$item:ready" <<< "$apply_output" >/dev/null + grep -Fx "$item" "$temporary/run-items" >/dev/null +done unchanged_output="$(kpanel_system_tuning_apply_item bbr)" grep -F 'KPANEL_SYSTEM_TUNING_STATUS=unchanged' <<< "$unchanged_output" >/dev/null [ "$(grep -Fxc bbr "$temporary/run-items")" -eq 1 ] kpanel_system_tuning_run_item() { return 1; } +: > "$temporary/ready-items" if kpanel_system_tuning_apply_item ssh-defense > "$temporary/failure.out" 2>/dev/null; then echo "failed item unexpectedly succeeded" >&2 exit 1 @@ -59,6 +79,34 @@ fi grep -F 'KPANEL_SYSTEM_TUNING_STATUS=needs-attention' "$temporary/failure.out" >/dev/null grep -F 'KPANEL_SYSTEM_TUNING_SELECTED=ssh-defense' "$temporary/failure.out" >/dev/null +gl_hong="" +gl_bai="" +gl_lv="" +if kpanel_system_tuning_menu_item system-cleanup 2 "清理系统垃圾文件" > "$temporary/menu-failure.out"; then + echo "interactive tuning item unexpectedly ignored a failure" >&2 + exit 1 +fi +grep -F '[FAIL] 2/12. 清理系统垃圾文件,一条龙调优已停止' "$temporary/menu-failure.out" >/dev/null +if grep -Fq '[OK]' "$temporary/menu-failure.out"; then + echo "interactive tuning item printed a false success" >&2 + exit 1 +fi +kpanel_system_tuning_run_item() { return 0; } +if kpanel_system_tuning_menu_item swap-1g 3 "设置虚拟内存1G" > "$temporary/menu-readback-failure.out"; then + echo "interactive tuning item ignored a failed completion readback" >&2 + exit 1 +fi +grep -F '完成态回读失败' "$temporary/menu-readback-failure.out" >/dev/null + +old_path="$PATH" +mkdir -p "$temporary/empty-path" +PATH="$temporary/empty-path" +if kpanel_system_tuning_has_package_manager update; then + echo "missing package manager was accepted" >&2 + exit 1 +fi +PATH="$old_path" + printf 'fixture\n' > "$temporary/source" source_hash="$(sha256sum "$temporary/source" | awk '{print $1}')" curl() { From f34e6d0b9c40c7927e1ccba69cf8b1d6d8bba74c Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 15:20:15 +0800 Subject: [PATCH 1276/1285] fix(kpanel): keep tuning changes isolated AI-Scope: system-tuning-runtime-compat --- cn/kejilion.sh | 47 ++++++++----------- kejilion.sh | 47 ++++++++----------- tests/test_kpanel_dns_noninteractive_smoke.sh | 25 +--------- 3 files changed, 41 insertions(+), 78 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 60f961823..d8173a43b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6188,7 +6188,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" local parent desired backup old_mode old_immutable="false" existed="false" - local expected="" value published="false" + local expected="" value if [ -L "$target" ]; then target="$(readlink -f "$target")" @@ -6202,6 +6202,11 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } + command -v chattr >/dev/null 2>&1 || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { rm -f "$desired" @@ -6227,23 +6232,25 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if command -v lsattr >/dev/null 2>&1 && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - command -v chattr >/dev/null 2>&1 && chattr +i "$target" >/dev/null 2>&1 || true + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + } rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - if [ "$old_immutable" = "true" ]; then - command -v chattr >/dev/null 2>&1 && chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } - fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6251,13 +6258,9 @@ kpanel_dns_write_static() { } fi - if mv -f "$desired" "$target" 2>/dev/null; then - published="true" - elif cat "$desired" > "$target" 2>/dev/null; then - rm -f "$desired" - published="true" - fi - if [ "$published" != "true" ] || [ "$(cat "$target" 2>/dev/null)"$'\n' != "$expected" ]; then + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6267,16 +6270,6 @@ kpanel_dns_write_static() { echo "错误: DNS 写入或回读验证失败,已恢复原配置" return 1 fi - if command -v chattr >/dev/null 2>&1 && ! chattr +i "$target" >/dev/null 2>&1 && [ "$old_immutable" = "true" ]; then - kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { - rm -f "$desired" "$backup" - echo "错误: DNS 配置锁定恢复失败,需要人工检查" - return 1 - } - rm -f "$desired" "$backup" - echo "错误: 无法恢复原有 DNS 配置锁定,已恢复原配置" - return 1 - fi rm -f "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT applied" diff --git a/kejilion.sh b/kejilion.sh index a78c60255..b144127c2 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6188,7 +6188,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" local parent desired backup old_mode old_immutable="false" existed="false" - local expected="" value published="false" + local expected="" value if [ -L "$target" ]; then target="$(readlink -f "$target")" @@ -6202,6 +6202,11 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } + command -v chattr >/dev/null 2>&1 || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { rm -f "$desired" @@ -6227,23 +6232,25 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if command -v lsattr >/dev/null 2>&1 && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - command -v chattr >/dev/null 2>&1 && chattr +i "$target" >/dev/null 2>&1 || true + chattr +i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + } rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - if [ "$old_immutable" = "true" ]; then - command -v chattr >/dev/null 2>&1 && chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } - fi + chattr -i "$target" >/dev/null 2>&1 || { + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + } else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6251,13 +6258,9 @@ kpanel_dns_write_static() { } fi - if mv -f "$desired" "$target" 2>/dev/null; then - published="true" - elif cat "$desired" > "$target" 2>/dev/null; then - rm -f "$desired" - published="true" - fi - if [ "$published" != "true" ] || [ "$(cat "$target" 2>/dev/null)"$'\n' != "$expected" ]; then + if ! mv -f "$desired" "$target" || + ! chattr +i "$target" >/dev/null 2>&1 || + [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6267,16 +6270,6 @@ kpanel_dns_write_static() { echo "错误: DNS 写入或回读验证失败,已恢复原配置" return 1 fi - if command -v chattr >/dev/null 2>&1 && ! chattr +i "$target" >/dev/null 2>&1 && [ "$old_immutable" = "true" ]; then - kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { - rm -f "$desired" "$backup" - echo "错误: DNS 配置锁定恢复失败,需要人工检查" - return 1 - } - rm -f "$desired" "$backup" - echo "错误: 无法恢复原有 DNS 配置锁定,已恢复原配置" - return 1 - fi rm -f "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT applied" diff --git a/tests/test_kpanel_dns_noninteractive_smoke.sh b/tests/test_kpanel_dns_noninteractive_smoke.sh index e514e5e4b..5b8f3ec3d 100644 --- a/tests/test_kpanel_dns_noninteractive_smoke.sh +++ b/tests/test_kpanel_dns_noninteractive_smoke.sh @@ -2,11 +2,7 @@ set -euo pipefail project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -source_script="${KEJILION_SCRIPT_PATH:-${project_root}/kejilion.sh}" -temporary="$(mktemp -d)" -trap 'rm -rf -- "$temporary"' EXIT -script_path="$temporary/kejilion.sh" -sed 's/\r$//' "$source_script" > "$script_path" +script_path="${project_root}/kejilion.sh" bash -n "${script_path}" grep -F 'kpanel_set_dns_noninteractive() {' "${script_path}" >/dev/null @@ -59,23 +55,4 @@ if kpanel_protocol_active; then exit 1 fi -dns_writer_body="$( - awk ' - /^kpanel_dns_restore_file\(\) \{/ { capture=1 } - /^kpanel_dns_write_systemd_resolved\(\) \{/ { exit } - capture { print } - ' "${script_path}" | sed 's#local target="/etc/resolv.conf"#local target="$KPANEL_DNS_TEST_TARGET"#' -)" -eval "$dns_writer_body" -KPANEL_DNS_TEST_TARGET="$temporary/resolv.conf" -printf 'nameserver 9.9.9.9\n' > "$KPANEL_DNS_TEST_TARGET" -chattr() { return 1; } -lsattr() { return 1; } -mv() { return 1; } -dns_result="$(kpanel_dns_write_static 1.1.1.1 8.8.8.8)" -grep -F 'KPANEL_DNS_RESULT applied' <<< "$dns_result" >/dev/null -[ "$(cat "$KPANEL_DNS_TEST_TARGET")"$'\n' = $'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' ] -dns_result="$(kpanel_dns_write_static 1.1.1.1 8.8.8.8)" -grep -F 'KPANEL_DNS_RESULT unchanged' <<< "$dns_result" >/dev/null - printf '%s\n' "kpanel_dns_noninteractive_smoke=pass" From 4d7265310cb89d39c09201d99bef213a0e494e3c Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 16:04:32 +0800 Subject: [PATCH 1277/1285] fix(kpanel): bootstrap SSH in one-click tuning AI-Scope: one-click OpenSSH installation and service readiness only --- cn/kejilion.sh | 69 ++++++++++++++++++- kejilion.sh | 69 ++++++++++++++++++- ...anel_system_tuning_noninteractive_smoke.sh | 19 +++++ 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d8173a43b..ff0d7468b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4412,6 +4412,73 @@ kpanel_system_tuning_has_package_manager() { return 1 } +kpanel_system_tuning_ssh_server_ready() { + local config="${KPANEL_SYSTEM_TUNING_SSHD_CONFIG:-/etc/ssh/sshd_config}" + [ -f "$config" ] && [ ! -L "$config" ] && + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 +} + +kpanel_system_tuning_prepare_ssh_service() { + local run_dir="${KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR:-/run/sshd}" + local systemd_dir="${KPANEL_SYSTEM_TUNING_SYSTEMD_DIR:-/run/systemd/system}" + local alias_path="${KPANEL_SYSTEM_TUNING_SSHD_UNIT_ALIAS:-/etc/systemd/system/sshd.service}" + local fragment systemctl_bin + mkdir -p -- "$run_dir" && chmod 0755 "$run_dir" || return 1 + systemctl_bin="$(type -P systemctl 2>/dev/null || true)" + if [ -n "$systemctl_bin" ] && [ -d "$systemd_dir" ]; then + if "$systemctl_bin" cat ssh.service >/dev/null 2>&1; then + if ! "$systemctl_bin" cat sshd.service >/dev/null 2>&1; then + fragment="$("$systemctl_bin" show -p FragmentPath --value ssh.service 2>/dev/null)" + case "$fragment" in /lib/systemd/system/*|/usr/lib/systemd/system/*) ;; *) return 1 ;; esac + ln -sfn -- "$fragment" "$alias_path" || return 1 + "$systemctl_bin" daemon-reload || return 1 + fi + if "$systemctl_bin" cat ssh.socket >/dev/null 2>&1; then + "$systemctl_bin" disable ssh.socket >/dev/null 2>&1 || return 1 + "$systemctl_bin" stop ssh.socket >/dev/null 2>&1 || return 1 + if ! "$systemctl_bin" enable --now ssh.service >/dev/null 2>&1; then + "$systemctl_bin" enable --now ssh.socket >/dev/null 2>&1 || true + return 1 + fi + else + "$systemctl_bin" enable --now ssh.service >/dev/null 2>&1 || return 1 + fi + else + "$systemctl_bin" enable --now sshd.service >/dev/null 2>&1 || return 1 + fi + elif command -v rc-service >/dev/null 2>&1; then + rc-service sshd start >/dev/null 2>&1 || return 1 + fi +} + +kpanel_system_tuning_ensure_ssh_server() { + local package_name + if ! kpanel_system_tuning_ssh_server_ready; then + if command -v apt >/dev/null 2>&1 || command -v dnf >/dev/null 2>&1 || + command -v yum >/dev/null 2>&1 || command -v zypper >/dev/null 2>&1 || + command -v opkg >/dev/null 2>&1; then + package_name=openssh-server + elif command -v apk >/dev/null 2>&1 || command -v pacman >/dev/null 2>&1; then + package_name=openssh + else + kpanel_system_tuning_error "当前系统没有受支持的 OpenSSH Server 安装适配器" + return 1 + fi + install "$package_name" || { + kpanel_system_tuning_error "OpenSSH Server 安装失败" + return 1 + } + fi + kpanel_system_tuning_ssh_server_ready || { + kpanel_system_tuning_error "OpenSSH Server 安装后配置或工具仍不可用" + return 1 + } + kpanel_system_tuning_prepare_ssh_service || { + kpanel_system_tuning_error "OpenSSH Server 运行环境准备失败" + return 1 + } +} + kpanel_system_tuning_item_ready() { local item="$1" command_name case "$item" in @@ -4464,7 +4531,7 @@ kpanel_system_tuning_run_item() { linux_clean || { kpanel_system_tuning_error "系统清理失败"; return 1; } ;; swap-1g) add_swap 1024 ;; - ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; + ssh-port-5522) kpanel_system_tuning_ensure_ssh_server && KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; firewall-open-all) kpanel_system_tuning_firewall_open_all ;; bbr) bbr_on ;; diff --git a/kejilion.sh b/kejilion.sh index b144127c2..67045b38c 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4412,6 +4412,73 @@ kpanel_system_tuning_has_package_manager() { return 1 } +kpanel_system_tuning_ssh_server_ready() { + local config="${KPANEL_SYSTEM_TUNING_SSHD_CONFIG:-/etc/ssh/sshd_config}" + [ -f "$config" ] && [ ! -L "$config" ] && + command -v sshd >/dev/null 2>&1 && command -v ss >/dev/null 2>&1 +} + +kpanel_system_tuning_prepare_ssh_service() { + local run_dir="${KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR:-/run/sshd}" + local systemd_dir="${KPANEL_SYSTEM_TUNING_SYSTEMD_DIR:-/run/systemd/system}" + local alias_path="${KPANEL_SYSTEM_TUNING_SSHD_UNIT_ALIAS:-/etc/systemd/system/sshd.service}" + local fragment systemctl_bin + mkdir -p -- "$run_dir" && chmod 0755 "$run_dir" || return 1 + systemctl_bin="$(type -P systemctl 2>/dev/null || true)" + if [ -n "$systemctl_bin" ] && [ -d "$systemd_dir" ]; then + if "$systemctl_bin" cat ssh.service >/dev/null 2>&1; then + if ! "$systemctl_bin" cat sshd.service >/dev/null 2>&1; then + fragment="$("$systemctl_bin" show -p FragmentPath --value ssh.service 2>/dev/null)" + case "$fragment" in /lib/systemd/system/*|/usr/lib/systemd/system/*) ;; *) return 1 ;; esac + ln -sfn -- "$fragment" "$alias_path" || return 1 + "$systemctl_bin" daemon-reload || return 1 + fi + if "$systemctl_bin" cat ssh.socket >/dev/null 2>&1; then + "$systemctl_bin" disable ssh.socket >/dev/null 2>&1 || return 1 + "$systemctl_bin" stop ssh.socket >/dev/null 2>&1 || return 1 + if ! "$systemctl_bin" enable --now ssh.service >/dev/null 2>&1; then + "$systemctl_bin" enable --now ssh.socket >/dev/null 2>&1 || true + return 1 + fi + else + "$systemctl_bin" enable --now ssh.service >/dev/null 2>&1 || return 1 + fi + else + "$systemctl_bin" enable --now sshd.service >/dev/null 2>&1 || return 1 + fi + elif command -v rc-service >/dev/null 2>&1; then + rc-service sshd start >/dev/null 2>&1 || return 1 + fi +} + +kpanel_system_tuning_ensure_ssh_server() { + local package_name + if ! kpanel_system_tuning_ssh_server_ready; then + if command -v apt >/dev/null 2>&1 || command -v dnf >/dev/null 2>&1 || + command -v yum >/dev/null 2>&1 || command -v zypper >/dev/null 2>&1 || + command -v opkg >/dev/null 2>&1; then + package_name=openssh-server + elif command -v apk >/dev/null 2>&1 || command -v pacman >/dev/null 2>&1; then + package_name=openssh + else + kpanel_system_tuning_error "当前系统没有受支持的 OpenSSH Server 安装适配器" + return 1 + fi + install "$package_name" || { + kpanel_system_tuning_error "OpenSSH Server 安装失败" + return 1 + } + fi + kpanel_system_tuning_ssh_server_ready || { + kpanel_system_tuning_error "OpenSSH Server 安装后配置或工具仍不可用" + return 1 + } + kpanel_system_tuning_prepare_ssh_service || { + kpanel_system_tuning_error "OpenSSH Server 运行环境准备失败" + return 1 + } +} + kpanel_system_tuning_item_ready() { local item="$1" command_name case "$item" in @@ -4464,7 +4531,7 @@ kpanel_system_tuning_run_item() { linux_clean || { kpanel_system_tuning_error "系统清理失败"; return 1; } ;; swap-1g) add_swap 1024 ;; - ssh-port-5522) KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; + ssh-port-5522) kpanel_system_tuning_ensure_ssh_server && KJ_SSH_PORT_NONINTERACTIVE=1 kpanel_ssh_port_noninteractive 5522 ;; ssh-defense) kpanel_f2b_manager_service_action enable && kpanel_f2b_enabled ;; firewall-open-all) kpanel_system_tuning_firewall_open_all ;; bbr) bbr_on ;; diff --git a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh index 5844a1bd0..d7de0a4a6 100644 --- a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh @@ -43,6 +43,25 @@ kpanel_set_dns_noninteractive() { printf '%s\n' "$KJ_DNS_NONINTERACTIVE:$*" > "$ kpanel_system_tuning_dns_auto grep -Fqx '1:223.5.5.5 183.60.83.19' "$temporary/dns-action" +KPANEL_SYSTEM_TUNING_SSHD_CONFIG="$temporary/sshd_config" +KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR="$temporary/run-sshd" +KPANEL_SYSTEM_TUNING_SYSTEMD_DIR="$temporary/no-systemd" +apt() { :; } +sshd() { :; } +ss() { :; } +install() { printf '%s\n' "$1" > "$temporary/ssh-package"; : > "$KPANEL_SYSTEM_TUNING_SSHD_CONFIG"; } +kpanel_system_tuning_ensure_ssh_server +grep -Fqx 'openssh-server' "$temporary/ssh-package" +test -d "$KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR" +rm -f "$KPANEL_SYSTEM_TUNING_SSHD_CONFIG" +install() { return 1; } +if kpanel_system_tuning_ensure_ssh_server 2>/dev/null; then + echo "failed OpenSSH Server installation was accepted" >&2 + exit 1 +fi +unset KPANEL_SYSTEM_TUNING_SSHD_CONFIG KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR KPANEL_SYSTEM_TUNING_SYSTEMD_DIR +unset -f apt sshd ss install + : > "$temporary/ready-items" kpanel_system_tuning_item_ready() { grep -Fxq "$1" "$temporary/ready-items"; } kpanel_system_tuning_run_item() { printf '%s\n' "$1" >> "$temporary/run-items"; printf '%s\n' "$1" >> "$temporary/ready-items"; } From d132a93b6d8b2d1d140c681cd8e1806f8fc3d611 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 17:22:04 +0800 Subject: [PATCH 1278/1285] fix(kpanel): support minimal rhel tuning hosts --- cn/kejilion.sh | 184 ++++++++++++++++++++++++++++++++++------------- kejilion.sh | 188 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 272 insertions(+), 100 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index ff0d7468b..5478d419a 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -716,6 +716,7 @@ check_crontab_installed() { install_crontab() { + local package_manager if [ -f /etc/os-release ]; then . /etc/os-release @@ -727,9 +728,18 @@ install_crontab() { systemctl start cron ;; centos|rhel|almalinux|rocky|fedora) - yum install -y cronie - systemctl enable crond - systemctl start crond + if command -v dnf >/dev/null 2>&1; then + package_manager=dnf + elif command -v yum >/dev/null 2>&1; then + package_manager=yum + else + echo "错误: 未找到 DNF/YUM,无法安装 cronie" + return 1 + fi + "$package_manager" install -y cronie || return 1 + /bin/systemctl enable --now crond.service || return 1 + command -v crontab >/dev/null 2>&1 || return 1 + /bin/systemctl is-active --quiet crond.service || return 1 ;; alpine) apk add --no-cache cronie @@ -767,6 +777,7 @@ install_crontab() { return fi + command -v crontab >/dev/null 2>&1 || return 1 echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -843,11 +854,11 @@ docker_ipv6_off() { save_iptables_rules() { mkdir -p /etc/iptables - touch /etc/iptables/rules.v4 - iptables-save > /etc/iptables/rules.v4 - check_crontab_installed - crontab -l | grep -v 'iptables-restore' | crontab - > /dev/null 2>&1 - (crontab -l ; echo '@reboot iptables-restore < /etc/iptables/rules.v4') | crontab - > /dev/null 2>&1 + touch /etc/iptables/rules.v4 || return 1 + iptables-save > /etc/iptables/rules.v4 || return 1 + check_crontab_installed || return 1 + crontab -l | grep -v 'iptables-restore' | crontab - > /dev/null 2>&1 || return 1 + (crontab -l ; echo '@reboot iptables-restore < /etc/iptables/rules.v4') | crontab - > /dev/null 2>&1 || return 1 } @@ -855,17 +866,17 @@ save_iptables_rules() { iptables_open() { - install iptables - save_iptables_rules - iptables -P INPUT ACCEPT - iptables -P FORWARD ACCEPT - iptables -P OUTPUT ACCEPT - iptables -F + install iptables || return 1 + save_iptables_rules || return 1 + iptables -P INPUT ACCEPT || return 1 + iptables -P FORWARD ACCEPT || return 1 + iptables -P OUTPUT ACCEPT || return 1 + iptables -F || return 1 - ip6tables -P INPUT ACCEPT - ip6tables -P FORWARD ACCEPT - ip6tables -P OUTPUT ACCEPT - ip6tables -F + ip6tables -P INPUT ACCEPT || return 1 + ip6tables -P FORWARD ACCEPT || return 1 + ip6tables -P OUTPUT ACCEPT || return 1 + ip6tables -F || return 1 } @@ -878,7 +889,7 @@ open_port() { return 1 fi - install iptables + install iptables || return 1 for port in "${ports[@]}"; do # 删除已存在的关闭规则 @@ -896,7 +907,7 @@ open_port() { fi done - save_iptables_rules + save_iptables_rules || return 1 send_stats "已打开端口" } @@ -3736,20 +3747,35 @@ check_f2b_status() { f2b_install_sshd() { docker rm -f fail2ban >/dev/null 2>&1 - install fail2ban - start fail2ban - enable fail2ban + install fail2ban || return 1 - if command -v dnf &>/dev/null; then + if command -v dnf &>/dev/null || command -v yum &>/dev/null; then + install rsyslog || return 1 + /bin/systemctl enable --now rsyslog.service || return 1 cd /etc/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + curl --fail --silent --show-error --location \ + --output centos-ssh.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf" || return 1 + if [ ! -e /var/log/secure ]; then + touch /var/log/secure || return 1 + chmod 0600 /var/log/secure || return 1 + command -v restorecon >/dev/null 2>&1 && restorecon /var/log/secure || true + fi fi if command -v apt &>/dev/null; then - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog + install rsyslog || return 1 + /bin/systemctl enable --now rsyslog.service || return 1 + fi + + if command -v apk >/dev/null 2>&1; then + rc-update add fail2ban default || return 1 + rc-service fail2ban start || return 1 + else + /bin/systemctl enable --now fail2ban.service || return 1 fi + fail2ban-client -t >/dev/null 2>&1 || return 1 + fail2ban-client reload >/dev/null 2>&1 || /bin/systemctl restart fail2ban.service } @@ -4356,6 +4382,10 @@ kpanel_system_tuning_switch_mirror() { kpanel_system_tuning_kernel_auto() { local script url + mkdir -p /etc/sysctl.d /etc/modules-load.d || { + kpanel_system_tuning_error "内核参数配置目录无法创建" + return 1 + } script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } @@ -4367,6 +4397,18 @@ kpanel_system_tuning_kernel_auto() { kpanel_system_tuning_firewall_open_all() { local version + if ! command -v iptables >/dev/null 2>&1 || + ! command -v iptables-save >/dev/null 2>&1 || + ! command -v iptables-restore >/dev/null 2>&1; then + install iptables || { + kpanel_system_tuning_error "iptables 兼容工具安装失败" + return 1 + } + fi + check_crontab_installed || { + kpanel_system_tuning_error "iptables 持久化依赖 crontab/crond 不可用" + return 1 + } version="$(kpanel_system_resource_firewall_version)" || return 1 kpanel_system_resource_firewall_action open-all "$version" >&2 } @@ -4383,6 +4425,12 @@ kpanel_system_tuning_swap_1g_ready() { kpanel_system_tuning_dns_auto() { local country dns1_ipv4 dns2_ipv4 dns1_ipv6 dns2_ipv6 local dns=() + if ! command -v chattr >/dev/null 2>&1; then + install e2fsprogs || { + kpanel_system_tuning_error "DNS 依赖 e2fsprogs/chattr 安装失败" + return 1 + } + fi country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" if [ "$country" = CN ]; then dns1_ipv4="223.5.5.5" @@ -6235,6 +6283,11 @@ kpanel_dns_is_ipv6() { [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] } +kpanel_dns_wsl_environment() { + grep -qiE '(microsoft|wsl)' /proc/sys/kernel/osrelease 2>/dev/null || + uname -r 2>/dev/null | grep -qiE '(microsoft|wsl)' +} + kpanel_dns_restore_file() { local target="$1" local backup="$2" @@ -6254,7 +6307,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" - local parent desired backup old_mode old_immutable="false" existed="false" + local parent desired backup old_mode old_immutable="false" existed="false" lock_dns="true" local expected="" value if [ -L "$target" ]; then @@ -6269,10 +6322,13 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - command -v chattr >/dev/null 2>&1 || { - echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" - return 1 - } + if ! command -v chattr >/dev/null 2>&1; then + kpanel_dns_wsl_environment || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + lock_dns="false" + fi desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { @@ -6299,25 +6355,33 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if [ "$lock_dns" = "true" ] && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - chattr +i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法锁定 DNS 配置" - return 1 - } + if [ "$lock_dns" = "true" ] && ! chattr +i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + fi + fi rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } + if [ "$lock_dns" = "true" ] && ! chattr -i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + fi + fi else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6325,9 +6389,31 @@ kpanel_dns_write_static() { } fi - if ! mv -f "$desired" "$target" || - ! chattr +i "$target" >/dev/null 2>&1 || - [ "$(cat "$target")"$'\n' != "$expected" ]; then + if ! mv -f "$desired" "$target"; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + if [ "$lock_dns" = "true" ] && ! chattr +i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + fi + if [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6552,8 +6638,8 @@ new_ssh_port() { correct_ssh_config - restart_ssh - open_port $new_port + restart_ssh || return 1 + open_port "$new_port" || return 1 remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "SSH 端口已修改为: $new_port" diff --git a/kejilion.sh b/kejilion.sh index 67045b38c..dab307547 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -716,6 +716,7 @@ check_crontab_installed() { install_crontab() { + local package_manager if [ -f /etc/os-release ]; then . /etc/os-release @@ -727,9 +728,18 @@ install_crontab() { systemctl start cron ;; centos|rhel|almalinux|rocky|fedora) - yum install -y cronie - systemctl enable crond - systemctl start crond + if command -v dnf >/dev/null 2>&1; then + package_manager=dnf + elif command -v yum >/dev/null 2>&1; then + package_manager=yum + else + echo "错误: 未找到 DNF/YUM,无法安装 cronie" + return 1 + fi + "$package_manager" install -y cronie || return 1 + /bin/systemctl enable --now crond.service || return 1 + command -v crontab >/dev/null 2>&1 || return 1 + /bin/systemctl is-active --quiet crond.service || return 1 ;; alpine) apk add --no-cache cronie @@ -767,6 +777,7 @@ install_crontab() { return fi + command -v crontab >/dev/null 2>&1 || return 1 echo -e "${gl_lv}crontab 已安装且 cron 服务正在运行。${gl_bai}" } @@ -843,11 +854,11 @@ docker_ipv6_off() { save_iptables_rules() { mkdir -p /etc/iptables - touch /etc/iptables/rules.v4 - iptables-save > /etc/iptables/rules.v4 - check_crontab_installed - crontab -l | grep -v 'iptables-restore' | crontab - > /dev/null 2>&1 - (crontab -l ; echo '@reboot iptables-restore < /etc/iptables/rules.v4') | crontab - > /dev/null 2>&1 + touch /etc/iptables/rules.v4 || return 1 + iptables-save > /etc/iptables/rules.v4 || return 1 + check_crontab_installed || return 1 + crontab -l | grep -v 'iptables-restore' | crontab - > /dev/null 2>&1 || return 1 + (crontab -l ; echo '@reboot iptables-restore < /etc/iptables/rules.v4') | crontab - > /dev/null 2>&1 || return 1 } @@ -855,17 +866,17 @@ save_iptables_rules() { iptables_open() { - install iptables - save_iptables_rules - iptables -P INPUT ACCEPT - iptables -P FORWARD ACCEPT - iptables -P OUTPUT ACCEPT - iptables -F + install iptables || return 1 + save_iptables_rules || return 1 + iptables -P INPUT ACCEPT || return 1 + iptables -P FORWARD ACCEPT || return 1 + iptables -P OUTPUT ACCEPT || return 1 + iptables -F || return 1 - ip6tables -P INPUT ACCEPT - ip6tables -P FORWARD ACCEPT - ip6tables -P OUTPUT ACCEPT - ip6tables -F + ip6tables -P INPUT ACCEPT || return 1 + ip6tables -P FORWARD ACCEPT || return 1 + ip6tables -P OUTPUT ACCEPT || return 1 + ip6tables -F || return 1 } @@ -878,7 +889,7 @@ open_port() { return 1 fi - install iptables + install iptables || return 1 for port in "${ports[@]}"; do # 删除已存在的关闭规则 @@ -896,7 +907,7 @@ open_port() { fi done - save_iptables_rules + save_iptables_rules || return 1 send_stats "已打开端口" } @@ -3736,20 +3747,35 @@ check_f2b_status() { f2b_install_sshd() { docker rm -f fail2ban >/dev/null 2>&1 - install fail2ban - start fail2ban - enable fail2ban + install fail2ban || return 1 - if command -v dnf &>/dev/null; then + if command -v dnf &>/dev/null || command -v yum &>/dev/null; then + install rsyslog || return 1 + /bin/systemctl enable --now rsyslog.service || return 1 cd /etc/fail2ban/jail.d/ - curl -sS -O ${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf + curl --fail --silent --show-error --location \ + --output centos-ssh.conf \ + "${gh_proxy}raw.githubusercontent.com/kejilion/config/main/fail2ban/centos-ssh.conf" || return 1 + if [ ! -e /var/log/secure ]; then + touch /var/log/secure || return 1 + chmod 0600 /var/log/secure || return 1 + command -v restorecon >/dev/null 2>&1 && restorecon /var/log/secure || true + fi fi if command -v apt &>/dev/null; then - install rsyslog - systemctl start rsyslog - systemctl enable rsyslog + install rsyslog || return 1 + /bin/systemctl enable --now rsyslog.service || return 1 + fi + + if command -v apk >/dev/null 2>&1; then + rc-update add fail2ban default || return 1 + rc-service fail2ban start || return 1 + else + /bin/systemctl enable --now fail2ban.service || return 1 fi + fail2ban-client -t >/dev/null 2>&1 || return 1 + fail2ban-client reload >/dev/null 2>&1 || /bin/systemctl restart fail2ban.service } @@ -4356,6 +4382,10 @@ kpanel_system_tuning_switch_mirror() { kpanel_system_tuning_kernel_auto() { local script url + mkdir -p /etc/sysctl.d /etc/modules-load.d || { + kpanel_system_tuning_error "内核参数配置目录无法创建" + return 1 + } script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } @@ -4367,6 +4397,18 @@ kpanel_system_tuning_kernel_auto() { kpanel_system_tuning_firewall_open_all() { local version + if ! command -v iptables >/dev/null 2>&1 || + ! command -v iptables-save >/dev/null 2>&1 || + ! command -v iptables-restore >/dev/null 2>&1; then + install iptables || { + kpanel_system_tuning_error "iptables 兼容工具安装失败" + return 1 + } + fi + check_crontab_installed || { + kpanel_system_tuning_error "iptables 持久化依赖 crontab/crond 不可用" + return 1 + } version="$(kpanel_system_resource_firewall_version)" || return 1 kpanel_system_resource_firewall_action open-all "$version" >&2 } @@ -4383,6 +4425,12 @@ kpanel_system_tuning_swap_1g_ready() { kpanel_system_tuning_dns_auto() { local country dns1_ipv4 dns2_ipv4 dns1_ipv6 dns2_ipv6 local dns=() + if ! command -v chattr >/dev/null 2>&1; then + install e2fsprogs || { + kpanel_system_tuning_error "DNS 依赖 e2fsprogs/chattr 安装失败" + return 1 + } + fi country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" if [ "$country" = CN ]; then dns1_ipv4="223.5.5.5" @@ -6235,6 +6283,11 @@ kpanel_dns_is_ipv6() { [[ "$value" =~ ^[0-9A-Fa-f:.]+$ ]] } +kpanel_dns_wsl_environment() { + grep -qiE '(microsoft|wsl)' /proc/sys/kernel/osrelease 2>/dev/null || + uname -r 2>/dev/null | grep -qiE '(microsoft|wsl)' +} + kpanel_dns_restore_file() { local target="$1" local backup="$2" @@ -6254,7 +6307,7 @@ kpanel_dns_restore_file() { kpanel_dns_write_static() { local target="/etc/resolv.conf" - local parent desired backup old_mode old_immutable="false" existed="false" + local parent desired backup old_mode old_immutable="false" existed="false" lock_dns="true" local expected="" value if [ -L "$target" ]; then @@ -6269,10 +6322,13 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - command -v chattr >/dev/null 2>&1 || { - echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" - return 1 - } + if ! command -v chattr >/dev/null 2>&1; then + kpanel_dns_wsl_environment || { + echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" + return 1 + } + lock_dns="false" + fi desired="$(mktemp "${parent}/.resolv.conf.kpanel.XXXXXX")" || return 1 backup="$(mktemp "${parent}/.resolv.conf.backup.XXXXXX")" || { @@ -6299,25 +6355,33 @@ kpanel_dns_write_static() { return 1 } chown --reference="$target" "$desired" >/dev/null 2>&1 || true - if lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then + if [ "$lock_dns" = "true" ] && lsattr -d "$target" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then old_immutable="true" fi if [ "$(cat "$target")"$'\n' = "$expected" ]; then - chattr +i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法锁定 DNS 配置" - return 1 - } + if [ "$lock_dns" = "true" ] && ! chattr +i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + rm -f "$desired" "$backup" + echo "错误: 无法锁定 DNS 配置" + return 1 + fi + fi rm -f "$desired" "$backup" echo "KPANEL_DNS_MANAGER resolv.conf" echo "KPANEL_DNS_RESULT unchanged" return 0 fi - chattr -i "$target" >/dev/null 2>&1 || { - rm -f "$desired" "$backup" - echo "错误: 无法解除现有 DNS 配置锁定" - return 1 - } + if [ "$lock_dns" = "true" ] && ! chattr -i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + rm -f "$desired" "$backup" + echo "错误: 无法解除现有 DNS 配置锁定" + return 1 + fi + fi else chmod 644 "$desired" || { rm -f "$desired" "$backup" @@ -6325,9 +6389,31 @@ kpanel_dns_write_static() { } fi - if ! mv -f "$desired" "$target" || - ! chattr +i "$target" >/dev/null 2>&1 || - [ "$(cat "$target")"$'\n' != "$expected" ]; then + if ! mv -f "$desired" "$target"; then + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + if [ "$lock_dns" = "true" ] && ! chattr +i "$target" >/dev/null 2>&1; then + if kpanel_dns_wsl_environment; then + lock_dns="false" + else + kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { + rm -f "$desired" "$backup" + echo "错误: DNS 写入失败且回滚失败,需要人工检查" + return 1 + } + rm -f "$desired" "$backup" + echo "错误: DNS 写入或回读验证失败,已恢复原配置" + return 1 + fi + fi + if [ "$(cat "$target")"$'\n' != "$expected" ]; then kpanel_dns_restore_file "$target" "$backup" "$existed" "$old_immutable" || { rm -f "$desired" "$backup" echo "错误: DNS 写入失败且回滚失败,需要人工检查" @@ -6550,11 +6636,11 @@ new_ssh_port() { sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config sed -i "1i Port $new_port" /etc/ssh/sshd_config - correct_ssh_config + correct_ssh_config - restart_ssh - open_port $new_port - remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 + restart_ssh || return 1 + open_port "$new_port" || return 1 + remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "SSH 端口已修改为: $new_port" From 4211d575b653be0826f7efc2fc5915bc1e4574e9 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 17:37:21 +0800 Subject: [PATCH 1279/1285] fix(kpanel): persist WSL tuning DNS --- cn/kejilion.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++++++- kejilion.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 5478d419a..e4fc26b7c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -6288,6 +6288,54 @@ kpanel_dns_wsl_environment() { uname -r 2>/dev/null | grep -qiE '(microsoft|wsl)' } +kpanel_dns_wsl_persist_resolver() { + local expected="$1" config="/etc/wsl.conf" state_dir="/etc/kpanel" + local state_file="/etc/kpanel/resolv.conf" unit="/etc/systemd/system/kpanel-wsl-resolvconf.service" + local desired + + desired="$(mktemp /etc/.wsl.conf.kpanel.XXXXXX)" || return 1 + if [ -f "$config" ]; then + awk ' + BEGIN { in_network=0; inserted=0 } + /^\[network\][[:space:]]*$/ { + in_network=1; print + if (!inserted) { print "generateResolvConf = false"; inserted=1 } + next + } + /^\[/ { in_network=0; print; next } + in_network && /^[[:space:]]*generateResolvConf[[:space:]]*=/ { next } + { print } + END { if (!inserted) print "\n[network]\ngenerateResolvConf = false" } + ' "$config" > "$desired" || { rm -f "$desired"; return 1; } + else + printf '[network]\ngenerateResolvConf = false\n' > "$desired" || { rm -f "$desired"; return 1; } + fi + grep -q '^\[boot\][[:space:]]*$' "$desired" || + printf '\n[boot]\nsystemd = true\n' >> "$desired" || { rm -f "$desired"; return 1; } + chmod 644 "$desired" && mv -f "$desired" "$config" || { rm -f "$desired"; return 1; } + mkdir -p "$state_dir" || return 1 + printf '%s' "$expected" > "$state_file" || return 1 + chmod 644 "$state_file" || return 1 + printf '%s\n' \ + '[Unit]' \ + 'Description=Restore KPanel managed WSL DNS' \ + 'After=local-fs.target' \ + 'Before=network-pre.target' \ + '' \ + '[Service]' \ + 'Type=oneshot' \ + 'ExecStart=/usr/bin/cp -f /etc/kpanel/resolv.conf /etc/resolv.conf' \ + '' \ + '[Install]' \ + 'WantedBy=multi-user.target' > "$unit" || return 1 + chmod 644 "$unit" || return 1 + mkdir -p /etc/systemd/system/multi-user.target.wants || return 1 + ln -sfn "$unit" /etc/systemd/system/multi-user.target.wants/kpanel-wsl-resolvconf.service || return 1 + if systemctl daemon-reload >/dev/null 2>&1; then + systemctl enable --now kpanel-wsl-resolvconf.service >/dev/null 2>&1 || return 1 + fi +} + kpanel_dns_restore_file() { local target="$1" local backup="$2" @@ -6322,7 +6370,8 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - if ! command -v chattr >/dev/null 2>&1; then + kpanel_dns_wsl_environment && lock_dns="false" + if [ "$lock_dns" = "true" ] && ! command -v chattr >/dev/null 2>&1; then kpanel_dns_wsl_environment || { echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" return 1 @@ -6338,6 +6387,11 @@ kpanel_dns_write_static() { for value in "$@"; do expected="${expected}nameserver ${value}"$'\n' done + if [ "$lock_dns" = "false" ] && ! kpanel_dns_wsl_persist_resolver "$expected"; then + rm -f "$desired" "$backup" + echo "错误: WSL DNS 持久化配置失败" + return 1 + fi printf '%s' "$expected" > "$desired" || { rm -f "$desired" "$backup" return 1 diff --git a/kejilion.sh b/kejilion.sh index dab307547..8052d3838 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6288,6 +6288,54 @@ kpanel_dns_wsl_environment() { uname -r 2>/dev/null | grep -qiE '(microsoft|wsl)' } +kpanel_dns_wsl_persist_resolver() { + local expected="$1" config="/etc/wsl.conf" state_dir="/etc/kpanel" + local state_file="/etc/kpanel/resolv.conf" unit="/etc/systemd/system/kpanel-wsl-resolvconf.service" + local desired + + desired="$(mktemp /etc/.wsl.conf.kpanel.XXXXXX)" || return 1 + if [ -f "$config" ]; then + awk ' + BEGIN { in_network=0; inserted=0 } + /^\[network\][[:space:]]*$/ { + in_network=1; print + if (!inserted) { print "generateResolvConf = false"; inserted=1 } + next + } + /^\[/ { in_network=0; print; next } + in_network && /^[[:space:]]*generateResolvConf[[:space:]]*=/ { next } + { print } + END { if (!inserted) print "\n[network]\ngenerateResolvConf = false" } + ' "$config" > "$desired" || { rm -f "$desired"; return 1; } + else + printf '[network]\ngenerateResolvConf = false\n' > "$desired" || { rm -f "$desired"; return 1; } + fi + grep -q '^\[boot\][[:space:]]*$' "$desired" || + printf '\n[boot]\nsystemd = true\n' >> "$desired" || { rm -f "$desired"; return 1; } + chmod 644 "$desired" && mv -f "$desired" "$config" || { rm -f "$desired"; return 1; } + mkdir -p "$state_dir" || return 1 + printf '%s' "$expected" > "$state_file" || return 1 + chmod 644 "$state_file" || return 1 + printf '%s\n' \ + '[Unit]' \ + 'Description=Restore KPanel managed WSL DNS' \ + 'After=local-fs.target' \ + 'Before=network-pre.target' \ + '' \ + '[Service]' \ + 'Type=oneshot' \ + 'ExecStart=/usr/bin/cp -f /etc/kpanel/resolv.conf /etc/resolv.conf' \ + '' \ + '[Install]' \ + 'WantedBy=multi-user.target' > "$unit" || return 1 + chmod 644 "$unit" || return 1 + mkdir -p /etc/systemd/system/multi-user.target.wants || return 1 + ln -sfn "$unit" /etc/systemd/system/multi-user.target.wants/kpanel-wsl-resolvconf.service || return 1 + if systemctl daemon-reload >/dev/null 2>&1; then + systemctl enable --now kpanel-wsl-resolvconf.service >/dev/null 2>&1 || return 1 + fi +} + kpanel_dns_restore_file() { local target="$1" local backup="$2" @@ -6322,7 +6370,8 @@ kpanel_dns_write_static() { echo "错误: DNS 配置目录不存在" return 1 } - if ! command -v chattr >/dev/null 2>&1; then + kpanel_dns_wsl_environment && lock_dns="false" + if [ "$lock_dns" = "true" ] && ! command -v chattr >/dev/null 2>&1; then kpanel_dns_wsl_environment || { echo "错误: chattr 不可用,无法保持 kejilion.sh DNS 生命周期语义" return 1 @@ -6338,6 +6387,11 @@ kpanel_dns_write_static() { for value in "$@"; do expected="${expected}nameserver ${value}"$'\n' done + if [ "$lock_dns" = "false" ] && ! kpanel_dns_wsl_persist_resolver "$expected"; then + rm -f "$desired" "$backup" + echo "错误: WSL DNS 持久化配置失败" + return 1 + fi printf '%s' "$expected" > "$desired" || { rm -f "$desired" "$backup" return 1 From fdb0ac0e1f2b98d27339937e7f8eb0c9299c56a9 Mon Sep 17 00:00:00 2001 From: kejilion Date: Mon, 17 Aug 2026 17:52:38 +0800 Subject: [PATCH 1280/1285] fix(kpanel): synchronize SSH tuning scripts --- kejilion.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kejilion.sh b/kejilion.sh index 8052d3838..7fc1154e3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -6690,11 +6690,11 @@ new_ssh_port() { sed -i '/^\s*#\?\s*Port\s\+/d' /etc/ssh/sshd_config sed -i "1i Port $new_port" /etc/ssh/sshd_config - correct_ssh_config + correct_ssh_config - restart_ssh || return 1 - open_port "$new_port" || return 1 - remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 + restart_ssh || return 1 + open_port "$new_port" || return 1 + remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 echo "SSH 端口已修改为: $new_port" From 6fa7bcc7c2d15fe09d829cb9664941ff40bf4aaf Mon Sep 17 00:00:00 2001 From: kejilion Date: Thu, 20 Aug 2026 11:44:36 +0800 Subject: [PATCH 1281/1285] fix(kpanel): keep system tuning network direct --- cn/kejilion.sh | 25 +++++++++++++------ kejilion.sh | 25 +++++++++++++------ ...anel_system_tuning_noninteractive_smoke.sh | 20 +++++++++++++++ 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index e4fc26b7c..7e8af6c8c 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4352,9 +4352,20 @@ kpanel_system_tuning_valid_item() { esac } +kpanel_system_tuning_run_command() { + ( + unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY + "$@" + ) +} + +kpanel_system_tuning_curl() { + kpanel_system_tuning_run_command curl --proxy '' --noproxy '*' "$@" +} + kpanel_system_tuning_download_verified() { local url="$1" expected="$2" output="$3" actual size - curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 + kpanel_system_tuning_curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 [ -f "$output" ] && [ ! -L "$output" ] || return 1 size="$(wc -c < "$output" | tr -d '[:space:]')" [[ "$size" =~ ^[0-9]+$ ]] && [ "$size" -gt 0 ] && [ "$size" -le 1048576 ] || return 1 @@ -4367,13 +4378,13 @@ kpanel_system_tuning_switch_mirror() { script="$(mktemp /tmp/kejilion-system-tuning-mirror.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/SuperManito/LinuxMirrors/${KPANEL_SYSTEM_TUNING_MIRROR_COMMIT}/ChangeMirrors.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_MIRROR_SHA256" "$script" || { rm -f -- "$script"; return 1; } - country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + country="$(kpanel_system_tuning_curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" if [ "$country" = CN ]; then - bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode elif grep -qi oracle /etc/os-release 2>/dev/null; then - bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode else - bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode fi local result=$? rm -f -- "$script" @@ -4389,7 +4400,7 @@ kpanel_system_tuning_kernel_auto() { script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } - bash "$script" + kpanel_system_tuning_run_command bash "$script" local result=$? rm -f -- "$script" return "$result" @@ -4572,7 +4583,7 @@ kpanel_system_tuning_run_item() { system-update) kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } - linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } + kpanel_system_tuning_run_command linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } ;; system-cleanup) kpanel_system_tuning_has_package_manager cleanup || { kpanel_system_tuning_error "当前系统没有受支持的清理适配器"; return 1; } diff --git a/kejilion.sh b/kejilion.sh index 7fc1154e3..995ed933e 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4352,9 +4352,20 @@ kpanel_system_tuning_valid_item() { esac } +kpanel_system_tuning_run_command() { + ( + unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY + "$@" + ) +} + +kpanel_system_tuning_curl() { + kpanel_system_tuning_run_command curl --proxy '' --noproxy '*' "$@" +} + kpanel_system_tuning_download_verified() { local url="$1" expected="$2" output="$3" actual size - curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 + kpanel_system_tuning_curl --fail --silent --show-error --location --max-time 120 --output "$output" "$url" || return 1 [ -f "$output" ] && [ ! -L "$output" ] || return 1 size="$(wc -c < "$output" | tr -d '[:space:]')" [[ "$size" =~ ^[0-9]+$ ]] && [ "$size" -gt 0 ] && [ "$size" -le 1048576 ] || return 1 @@ -4367,13 +4378,13 @@ kpanel_system_tuning_switch_mirror() { script="$(mktemp /tmp/kejilion-system-tuning-mirror.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/SuperManito/LinuxMirrors/${KPANEL_SYSTEM_TUNING_MIRROR_COMMIT}/ChangeMirrors.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_MIRROR_SHA256" "$script" || { rm -f -- "$script"; return 1; } - country="$(curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" + country="$(kpanel_system_tuning_curl --fail --silent --show-error --max-time 10 https://ipinfo.io/country 2>/dev/null | tr -d '\r\n' || true)" if [ "$country" = CN ]; then - bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --source mirrors.huaweicloud.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode elif grep -qi oracle /etc/os-release 2>/dev/null; then - bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --source mirrors.xtom.com --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode else - bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode + kpanel_system_tuning_run_command bash "$script" --use-official-source true --protocol https --use-intranet-source false --backup true --upgrade-software false --clean-cache false --ignore-backup-tips --install-epel false --pure-mode fi local result=$? rm -f -- "$script" @@ -4389,7 +4400,7 @@ kpanel_system_tuning_kernel_auto() { script="$(mktemp /tmp/kejilion-system-tuning-network.XXXXXX)" || return 1 url="${gh_proxy}raw.githubusercontent.com/kejilion/sh/${KPANEL_SYSTEM_TUNING_NETWORK_COMMIT}/network-optimize.sh" kpanel_system_tuning_download_verified "$url" "$KPANEL_SYSTEM_TUNING_NETWORK_SHA256" "$script" || { rm -f -- "$script"; return 1; } - bash "$script" + kpanel_system_tuning_run_command bash "$script" local result=$? rm -f -- "$script" return "$result" @@ -4572,7 +4583,7 @@ kpanel_system_tuning_run_item() { system-update) kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } - linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } + kpanel_system_tuning_run_command linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } ;; system-cleanup) kpanel_system_tuning_has_package_manager cleanup || { kpanel_system_tuning_error "当前系统没有受支持的清理适配器"; return 1; } diff --git a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh index d7de0a4a6..0d94a9cf1 100644 --- a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh @@ -141,4 +141,24 @@ if kpanel_system_tuning_download_verified https://example.invalid/source "$(kpan exit 1 fi +export http_proxy="http://127.0.0.1:10808" +proxy_curl_calls_file="$temporary/proxy-curl-calls" +proxy_direct_args_file="$temporary/proxy-direct-args" +curl() { + printf '%s\n' curl >> "$proxy_curl_calls_file" + printf '%s\n' "$*" > "$proxy_direct_args_file" + while [ "$#" -gt 0 ]; do + [ "$1" = --output ] && { cp -- "$temporary/source" "$2"; return; } + shift + done + return 1 +} +kpanel_system_tuning_curl --fail --silent --show-error --location --output "$temporary/proxy-download" https://example.invalid/source +[ "$(wc -l < "$proxy_curl_calls_file" | tr -d '[:space:]')" -eq 1 ] +proxy_direct_args="$(cat -- "$proxy_direct_args_file")" +[[ "$proxy_direct_args" == *"--proxy"* && "$proxy_direct_args" == *"--noproxy"* ]] +kpanel_system_tuning_run_command env > "$temporary/direct-env" +! grep -Eiq '^(http|https|all)_proxy=' "$temporary/direct-env" +unset http_proxy + printf '%s\n' 'kpanel_system_tuning_noninteractive_smoke=pass' From 2d1a37416c574c7398445a54cd6d9d3a0d4bc124 Mon Sep 17 00:00:00 2001 From: kejilion Date: Fri, 21 Aug 2026 12:10:09 +0800 Subject: [PATCH 1282/1285] feat: add VMRack affiliate offer --- cn/kejilion.sh | 3 +++ kejilion.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index 7e8af6c8c..d8f50437b 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -27763,6 +27763,9 @@ echo "------------------------" echo -e "${gl_lan}莱卡云 香港CN2 GIA 韩国双ISP 美国CN2 GIA 优惠活动${gl_bai}" echo -e "${gl_bai}网址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" +echo -e "${gl_lan}VMRack 美国优质原生 CN2 大带宽 每月9.9刀起${gl_bai}" +echo -e "${gl_bai}网址: https://www.vmrack.net?ref_code=5bFonow83w5${gl_bai}" +echo "------------------------" echo -e "${gl_lan}RackNerd 10.99刀每年 美国 1核心 1G内存 20G硬盘 1T流量每月${gl_bai}" echo -e "${gl_bai}网址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" diff --git a/kejilion.sh b/kejilion.sh index 995ed933e..f202ee8bb 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -27763,6 +27763,9 @@ echo "------------------------" echo -e "${gl_lan}莱卡云 香港CN2 GIA 韩国双ISP 美国CN2 GIA 优惠活动${gl_bai}" echo -e "${gl_bai}网址: https://www.lcayun.com/aff/ZEXUQBIM${gl_bai}" echo "------------------------" +echo -e "${gl_lan}VMRack 美国优质原生 CN2 大带宽 每月9.9刀起${gl_bai}" +echo -e "${gl_bai}网址: https://www.vmrack.net?ref_code=5bFonow83w5${gl_bai}" +echo "------------------------" echo -e "${gl_lan}RackNerd 10.99刀每年 美国 1核心 1G内存 20G硬盘 1T流量每月${gl_bai}" echo -e "${gl_bai}网址: https://my.racknerd.com/aff.php?aff=5501&pid=879${gl_bai}" echo "------------------------" From 3d45e51117519fac9ee9ca27b9cde43a14293e0a Mon Sep 17 00:00:00 2001 From: Su-cyber-art <72259479+Su-cyber-art@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:39:30 +0800 Subject: [PATCH 1283/1285] fix(hermes): preserve named provider when switching models --- hermes_manager.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hermes_manager.sh b/hermes_manager.sh index 169ce0364..9bf18079f 100755 --- a/hermes_manager.sh +++ b/hermes_manager.sh @@ -227,7 +227,10 @@ try: print(json.dumps(out)) elif action == "switch": n, u, k, m = sys.argv[3:7] - data['model'] = {"default": m, "provider": "custom", "base_url": u, "api_key": k} + # Preserve the selected named custom provider. A bare "custom" route + # is ambiguous when multiple entries share a base URL but use + # different API keys or have different model entitlements. + data['model'] = {"default": m, "provider": f"custom:{n}", "base_url": u, "api_key": k} save(data) except Exception as e: From ca91f4d757dab0f16bf3868a6e33e7e3f1d8ed2b Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 23 Aug 2026 11:06:28 +0800 Subject: [PATCH 1284/1285] fix(kpanel): make mirror optimization non-blocking --- cn/kejilion.sh | 3 ++- kejilion.sh | 3 ++- tests/test_kpanel_system_tuning_noninteractive_smoke.sh | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cn/kejilion.sh b/cn/kejilion.sh index d8f50437b..dccb731ae 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -4582,7 +4582,8 @@ kpanel_system_tuning_run_item() { case "$1" in system-update) kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } - kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } + # 更新源优化保持尽力执行,不因其返回码中断一条龙调优。 + kpanel_system_tuning_switch_mirror || true kpanel_system_tuning_run_command linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } ;; system-cleanup) diff --git a/kejilion.sh b/kejilion.sh index f202ee8bb..9d276e8a3 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -4582,7 +4582,8 @@ kpanel_system_tuning_run_item() { case "$1" in system-update) kpanel_system_tuning_has_package_manager update || { kpanel_system_tuning_error "当前系统没有受支持的软件包管理器"; return 1; } - kpanel_system_tuning_switch_mirror || { kpanel_system_tuning_error "系统更新源优化失败"; return 1; } + # 更新源优化保持尽力执行,不因其返回码中断一条龙调优。 + kpanel_system_tuning_switch_mirror || true kpanel_system_tuning_run_command linux_update || { kpanel_system_tuning_error "系统软件包更新失败"; return 1; } ;; system-cleanup) diff --git a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh index 0d94a9cf1..cad102d9c 100644 --- a/tests/test_kpanel_system_tuning_noninteractive_smoke.sh +++ b/tests/test_kpanel_system_tuning_noninteractive_smoke.sh @@ -62,6 +62,15 @@ fi unset KPANEL_SYSTEM_TUNING_SSHD_CONFIG KPANEL_SYSTEM_TUNING_SSHD_RUN_DIR KPANEL_SYSTEM_TUNING_SYSTEMD_DIR unset -f apt sshd ss install +: > "$temporary/system-update-actions" +( + kpanel_system_tuning_has_package_manager() { return 0; } + kpanel_system_tuning_switch_mirror() { printf '%s\n' mirror >> "$temporary/system-update-actions"; return 1; } + linux_update() { printf '%s\n' update >> "$temporary/system-update-actions"; } + kpanel_system_tuning_run_item system-update +) +[ "$(paste -sd, "$temporary/system-update-actions")" = "mirror,update" ] + : > "$temporary/ready-items" kpanel_system_tuning_item_ready() { grep -Fxq "$1" "$temporary/ready-items"; } kpanel_system_tuning_run_item() { printf '%s\n' "$1" >> "$temporary/run-items"; printf '%s\n' "$1" >> "$temporary/ready-items"; } From 9fec61b50cc6ef798dfac1edf11c2ec60ca6b0d1 Mon Sep 17 00:00:00 2001 From: kejilion Date: Sun, 23 Aug 2026 02:51:40 -0300 Subject: [PATCH 1285/1285] feat(kpanel): add safe disk management protocol --- cn/kejilion.sh | 1364 ++++++++++++++++- kejilion.sh | 1364 ++++++++++++++++- ...el_disk_management_noninteractive_smoke.sh | 550 +++++++ 3 files changed, 3276 insertions(+), 2 deletions(-) create mode 100644 tests/test_kpanel_disk_management_noninteractive_smoke.sh diff --git a/cn/kejilion.sh b/cn/kejilion.sh index dccb731ae..46af8e32e 100644 --- a/cn/kejilion.sh +++ b/cn/kejilion.sh @@ -25,6 +25,7 @@ kpanel_protocol_active() { [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || @@ -24827,6 +24828,1364 @@ kpanel_system_resource_dispatch() { # KPanel system resource protocol end +# KPanel disk management protocol start +KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION="1" + +kpanel_disk_management_hex_encode() { + local value="${1-}" encoded="" byte decimal index + local LC_ALL=C + for ((index = 0; index < ${#value}; index++)); do + byte="${value:index:1}" + printf -v decimal '%d' "'$byte" + printf -v byte '%02x' "$decimal" + encoded+="$byte" + done + printf '%s' "$encoded" +} + +kpanel_disk_management_emit() { + local status="$1" device="${2:-}" message="${3:-}" backup="${4:-}" + case "$status" in + applied|unchanged|failed|conflict|needs-attention|rollback-failed) ;; + *) status=failed ;; + esac + [[ "$device" =~ ^[0-9]+:[0-9]+$ ]] || device="" + printf 'KPANEL_DISK_MANAGEMENT_STATUS=%s\n' "$status" + printf 'KPANEL_DISK_MANAGEMENT_DEVICE=%s\n' "$device" + printf 'KPANEL_DISK_MANAGEMENT_MESSAGE_HEX=%s\n' "$(kpanel_disk_management_hex_encode "$message")" + printf 'KPANEL_DISK_MANAGEMENT_BACKUP_HEX=%s\n' "$(kpanel_disk_management_hex_encode "$backup")" +} + +kpanel_disk_management_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_disk_management_reply() { + local status="$1" device="$2" message="$3" backup="$4" result="$5" + case "$status" in applied|unchanged) ;; *) kpanel_disk_management_error "$message" ;; esac + kpanel_disk_management_emit "$status" "$device" "$message" "$backup" + return "$result" +} + +kpanel_disk_management_lock_file() { + printf '%s\n' "/run/lock/kejilion-kpanel-disk.lock" +} + +kpanel_disk_management_lock_owner_uid() { + printf '0\n' +} + +kpanel_disk_management_lock_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_gid() { + stat -c '%g' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_links() { + stat -c '%h' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_parent_secure() { + local parent="$1" uid expected_uid gid mode numeric_mode + [ ! -L "$parent" ] && [ -d "$parent" ] || return 1 + uid="$(kpanel_disk_management_lock_stat_uid "$parent")" || return 1 + expected_uid="$(kpanel_disk_management_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_disk_management_lock_stat_mode "$parent")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + numeric_mode=$((8#$mode)) + # A newly created private parent is 0700. Existing system-managed /run/lock + # may be 0755/0775 or 1777; require root:root and sticky when world-writable. + [ "$((numeric_mode & 0777))" -eq 448 ] && return 0 + gid="$(kpanel_disk_management_lock_stat_gid "$parent")" || return 1 + [[ "$gid" =~ ^[0-9]+$ ]] && [ "$gid" = 0 ] || return 1 + [ "$((numeric_mode & 0002))" -eq 0 ] || [ "$((numeric_mode & 01000))" -ne 0 ] +} + +kpanel_disk_management_lock_file_secure() { + local path="$1" uid expected_uid mode links + [ ! -L "$path" ] && [ -f "$path" ] || return 1 + uid="$(kpanel_disk_management_lock_stat_uid "$path")" || return 1 + expected_uid="$(kpanel_disk_management_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_disk_management_lock_stat_mode "$path")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0777))" -eq 384 ] || return 1 + links="$(kpanel_disk_management_lock_stat_links "$path")" || return 1 + [[ "$links" =~ ^[0-9]+$ ]] && [ "$links" -eq 1 ] +} + +kpanel_disk_management_prepare_lock_file() { + local lock_file parent parent_parent created=false + lock_file="$(kpanel_disk_management_lock_file)" || return 1 + [[ "$lock_file" = /* ]] && [[ "$lock_file" != *$'\n'* ]] && [[ "$lock_file" != *$'\r'* ]] || return 1 + parent="$(dirname -- "$lock_file")" || return 1 + [ ! -L "$parent" ] || return 1 + if [ ! -e "$parent" ]; then + parent_parent="$(dirname -- "$parent")" || return 1 + [ -d "$parent_parent" ] && [ ! -L "$parent_parent" ] || return 1 + (umask 077; mkdir -- "$parent") >/dev/null 2>&1 || return 1 + chown 0:0 "$parent" >/dev/null 2>&1 && chmod 700 "$parent" >/dev/null 2>&1 || return 1 + fi + kpanel_disk_management_lock_parent_secure "$parent" || return 1 + [ ! -L "$lock_file" ] || return 1 + if [ ! -e "$lock_file" ]; then + (umask 077; set -o noclobber; : > "$lock_file") >/dev/null 2>&1 || return 1 + created=true + fi + [ -f "$lock_file" ] && [ ! -L "$lock_file" ] || return 1 + if [ "$created" = true ]; then + chown 0:0 "$lock_file" >/dev/null 2>&1 && chmod 600 "$lock_file" >/dev/null 2>&1 || return 1 + fi + kpanel_disk_management_lock_file_secure "$lock_file" || return 1 + printf '%s\n' "$lock_file" +} + +kpanel_disk_management_require_commands() { + local command_name + for command_name in "$@"; do + command -v "$command_name" >/dev/null 2>&1 || { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="缺少必要命令: $command_name" + return 1 + } + done +} + +kpanel_disk_management_command_available() { + command -v "$1" >/dev/null 2>&1 +} + +kpanel_disk_management_require_platform() { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="" + if [ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" != "1" ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议环境未启用" + return 2 + fi + if [ "$EUID" -ne 0 ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议必须以 root 运行" + return 2 + fi + if ! command -v uname >/dev/null 2>&1; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="缺少必要命令: uname" + return 1 + fi + if [ "$(uname -s 2>/dev/null)" != Linux ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议仅支持 Linux" + return 2 + fi + kpanel_disk_management_require_commands \ + awk basename blkid chmod chown cp date dirname find findmnt flock grep lsblk mkdir mktemp \ + mount mv readlink rm rmdir sha256sum stat sync umount uname wc +} + +kpanel_disk_management_path_owner_uid() { + printf '0\n' +} + +kpanel_disk_management_path_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_disk_management_path_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + +kpanel_disk_management_path_chain_secure() { + local path="$1" expected_uid remainder current component uid mode + local components=() + [[ "$path" = /* ]] && [ -d "$path" ] && [ ! -L "$path" ] || return 1 + [ "$path" = / ] || kpanel_system_resource_path_has_no_symlink "$path" || return 1 + expected_uid="$(kpanel_disk_management_path_owner_uid)" || return 1 + [[ "$expected_uid" =~ ^[0-9]+$ ]] || return 1 + current=/ + remainder="${path#/}" + IFS=/ read -r -a components <<< "$remainder" + components=("/" "${components[@]}") + for component in "${components[@]}"; do + if [ "$component" != / ]; then + [ -n "$component" ] && [ "$component" != . ] && [ "$component" != .. ] || return 1 + current="${current%/}/$component" + fi + [ -d "$current" ] && [ ! -L "$current" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$current")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$current")" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + done +} + +kpanel_disk_management_mountpoint_path_secure() { + local mountpoint="$1" allow_missing="$2" parent + kpanel_system_resource_path_has_no_symlink "$mountpoint" || return 1 + if [ -e "$mountpoint" ] || [ -L "$mountpoint" ]; then + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 1 + kpanel_disk_management_path_chain_secure "$mountpoint" + return $? + fi + [ "$allow_missing" = true ] || return 1 + parent="$(dirname -- "$mountpoint")" || return 1 + kpanel_disk_management_path_chain_secure "$parent" +} + +kpanel_disk_management_mountpoint_parent_secure() { + local mountpoint="$1" allow_missing="$2" parent + kpanel_system_resource_path_has_no_symlink "$mountpoint" || return 1 + if [ -e "$mountpoint" ] || [ -L "$mountpoint" ]; then + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 1 + else + [ "$allow_missing" = true ] || return 1 + fi + parent="$(dirname -- "$mountpoint")" || return 1 + kpanel_disk_management_path_chain_secure "$parent" +} + +kpanel_disk_management_decode_mountpoint() { + local encoded="$1" decoded="" canonical pair byte decimal index protected parent leaf canonical_parent + local LC_ALL=C + [ -n "$encoded" ] && [ "${#encoded}" -le 8192 ] && [ "$(( ${#encoded} % 2 ))" -eq 0 ] || return 1 + [[ "$encoded" =~ ^[0-9a-fA-F]+$ ]] || return 1 + for ((index = 0; index < ${#encoded}; index += 2)); do + pair="${encoded:index:2}" + decimal=$((16#$pair)) + [ "$decimal" -ge 32 ] && [ "$decimal" -ne 127 ] || return 1 + printf -v byte '%b' "\\x$pair" + decoded+="$byte" + done + [ -n "$decoded" ] && [[ "$decoded" = /* ]] || return 1 + [[ "$decoded" != *$'\n'* ]] && [[ "$decoded" != *$'\r'* ]] || return 1 + if [ -e "$decoded" ] || [ -L "$decoded" ]; then + canonical="$(readlink -f -- "$decoded" 2>/dev/null)" || return 1 + else + parent="$(dirname -- "$decoded")" || return 1 + leaf="$(basename -- "$decoded")" || return 1 + [ -n "$leaf" ] && [ "$leaf" != . ] && [ "$leaf" != .. ] || return 1 + canonical_parent="$(readlink -f -- "$parent" 2>/dev/null)" || return 1 + [ -d "$canonical_parent" ] && [ ! -L "$canonical_parent" ] || return 1 + canonical="${canonical_parent%/}/$leaf" + fi + [ "$canonical" = "$decoded" ] || return 1 + [ "$decoded" != / ] || return 1 + for protected in /boot /boot/efi /home /var/lib/kejilion-panel /home/docker; do + case "$decoded" in "$protected"|"$protected"/*) return 1 ;; esac + case "$protected" in "$decoded"/*) return 1 ;; esac + done + KPANEL_DISK_MANAGEMENT_MOUNTPOINT="$decoded" + KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX="$(kpanel_disk_management_hex_encode "$decoded")" +} + +kpanel_disk_management_is_block_device() { + [ -b "$1" ] +} + +kpanel_disk_management_resolve_device() { + local requested="$1" output line device_id device_path extra resolved verify matches=0 invalid=false + [[ "$requested" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + output="$(lsblk --noheadings --raw --paths --output MAJ:MIN,PATH 2>/dev/null)" || return 1 + while IFS= read -r line; do + [ -n "$line" ] || continue + device_id=""; device_path=""; extra="" + read -r device_id device_path extra <<< "$line" + if [ -n "$extra" ] || [[ ! "$device_id" =~ ^[0-9]+:[0-9]+$ ]] || [[ "$device_path" != /dev/* ]]; then + invalid=true + continue + fi + if [ "$device_id" = "$requested" ]; then + matches=$((matches + 1)) + KPANEL_DISK_MANAGEMENT_LISTED_PATH="$device_path" + fi + done <<< "$output" + [ "$invalid" = false ] && [ "$matches" -eq 1 ] || return 1 + resolved="$(readlink -f -- "$KPANEL_DISK_MANAGEMENT_LISTED_PATH" 2>/dev/null)" || return 1 + [[ "$resolved" = /dev/* ]] && kpanel_disk_management_is_block_device "$resolved" || return 1 + verify="$(lsblk --nodeps --noheadings --raw --output MAJ:MIN -- "$resolved" 2>/dev/null)" || return 1 + [ "$verify" = "$requested" ] || return 1 + KPANEL_DISK_MANAGEMENT_DEVICE_PATH="$resolved" + KPANEL_DISK_MANAGEMENT_DEVICE_ID="$requested" +} + +kpanel_disk_management_lsblk_value() { + local path="$1" column="$2" value + case "$column" in TYPE|RO|FSTYPE) ;; *) return 1 ;; esac + value="$(lsblk --nodeps --noheadings --raw --output "$column" -- "$path" 2>/dev/null)" || return 1 + [[ "$value" != *$'\n'* ]] && [[ "$value" != *$'\r'* ]] || return 1 + printf '%s' "$value" +} + +kpanel_disk_management_swaps_file() { + printf '%s\n' "/proc/swaps" +} + +kpanel_disk_management_device_is_active_swap() { + local device="$1" swaps source rest resolved + swaps="$(kpanel_disk_management_swaps_file)" || return 2 + [ -r "$swaps" ] || return 2 + while read -r source rest; do + [ -n "$source" ] || continue + [ "$source" != Filename ] || continue + case "$source" in + /dev/*) + resolved="$(readlink -f -- "$source" 2>/dev/null)" || return 2 + [ "$resolved" != "$device" ] || return 0 + ;; + esac + done < "$swaps" + return 1 +} + +kpanel_disk_management_validate_device_common() { + local type ro fstype probed probe_rc swap_rc + type="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" TYPE)" || return 1 + ro="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" RO)" || return 1 + fstype="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" FSTYPE)" || return 1 + [[ "$type" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + [[ "$ro" =~ ^[01]$ ]] || return 1 + [ -z "$fstype" ] || [[ "$fstype" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + probed="$(blkid -p -c /dev/null -s TYPE -o value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" 2>/dev/null)" + probe_rc=$? + case "$probe_rc" in + 0) + [[ "$probed" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + fstype="$probed" + ;; + 2) [ -z "$fstype" ] || return 1 ;; + *) return 1 ;; + esac + [ "$ro" = 0 ] || return 3 + [ "$fstype" != swap ] || return 3 + kpanel_disk_management_device_is_active_swap "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + swap_rc=$? + [ "$swap_rc" -ne 0 ] || return 3 + [ "$swap_rc" -eq 1 ] || return 1 + KPANEL_DISK_MANAGEMENT_DEVICE_TYPE="$type" + KPANEL_DISK_MANAGEMENT_FSTYPE="$fstype" +} + +kpanel_disk_management_device_is_leaf() { + local path="$1" expected="$2" output line count=0 + output="$(lsblk --noheadings --raw --output MAJ:MIN -- "$path" 2>/dev/null)" || return 2 + while IFS= read -r line; do + [ -n "$line" ] || continue + [[ "$line" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + [ "$count" -ne 0 ] || [ "$line" = "$expected" ] || return 2 + count=$((count + 1)) + done <<< "$output" + [ "$count" -eq 1 ] +} + +kpanel_disk_management_holders_dir() { + printf '/sys/dev/block/%s/holders\n' "$1" +} + +kpanel_disk_management_device_has_holders() { + local device_id="$1" directory first + directory="$(kpanel_disk_management_holders_dir "$device_id")" || return 2 + [ -d "$directory" ] || return 2 + first="$(find "$directory" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || return 2 + [ -n "$first" ] +} + +kpanel_disk_management_mount_ids() { + local output line + output="$(findmnt --kernel --raw --noheadings --output MAJ:MIN 2>/dev/null)" || return 2 + [ -n "$output" ] || return 2 + while IFS= read -r line; do + [ -n "$line" ] || continue + [[ "$line" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + printf '%s\n' "$line" + done <<< "$output" +} + +kpanel_disk_management_device_is_mounted() { + local requested="$1" output line + output="$(kpanel_disk_management_mount_ids)" || return 2 + while IFS= read -r line; do + [ "$line" != "$requested" ] || return 0 + done <<< "$output" + return 1 +} + +kpanel_disk_management_target_device() { + local mountpoint="$1" output rc + output="$(findmnt --kernel --raw --noheadings --output MAJ:MIN --mountpoint "$mountpoint" 2>/dev/null)" + rc=$? + if [ "$rc" -ne 0 ]; then + [ "$rc" -eq 1 ] && [ -z "$output" ] && return 1 + return 2 + fi + [[ "$output" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + printf '%s' "$output" +} + +kpanel_disk_management_require_leaf_unmounted() { + local leaf_rc holders_rc mounted_rc + kpanel_disk_management_device_is_leaf "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + leaf_rc=$? + [ "$leaf_rc" -eq 0 ] || { [ "$leaf_rc" -eq 1 ] && return 3; return 1; } + kpanel_disk_management_device_has_holders "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + holders_rc=$? + [ "$holders_rc" -ne 0 ] || return 3 + [ "$holders_rc" -eq 1 ] || return 1 + kpanel_disk_management_device_is_mounted "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + mounted_rc=$? + [ "$mounted_rc" -ne 0 ] || return 3 + [ "$mounted_rc" -eq 1 ] || return 1 +} + +kpanel_disk_management_fstab_file() { + printf '%s\n' "/etc/fstab" +} + +kpanel_disk_management_state_root() { + printf '%s/system/disk-management\n' "$(kpanel_system_resource_state_root)" +} + +kpanel_disk_management_prepare_state_subdir() { + local name="$1" root path + case "$name" in mountpoints|recovery) ;; *) return 1 ;; esac + root="$(kpanel_disk_management_state_root)" || return 1 + [[ "$root" = /* ]] && [ "$root" != / ] || return 1 + kpanel_system_resource_path_has_no_symlink "$root" || return 1 + if [ ! -e "$root" ]; then + (umask 077; mkdir -p -- "$root") >/dev/null 2>&1 || return 1 + fi + kpanel_system_resource_path_has_no_symlink "$root" && + kpanel_system_resource_secure_directory "$root" || return 1 + path="$root/$name" + kpanel_system_resource_path_has_no_symlink "$path" || return 1 + if [ ! -e "$path" ]; then + (umask 077; mkdir -- "$path") >/dev/null 2>&1 || return 1 + fi + kpanel_system_resource_path_has_no_symlink "$path" && + kpanel_system_resource_secure_directory "$path" || return 1 + printf '%s\n' "$path" +} + +kpanel_disk_management_fstab_escape() { + local value="$1" + value="${value//\\/\\134}" + value="${value// /\\040}" + printf '%s' "$value" +} + +kpanel_disk_management_persistence_source() { + local path="$1" value rc + value="$(blkid -c /dev/null -s UUID -o value "$path" 2>/dev/null)" + rc=$? + if [ "$rc" -eq 0 ]; then + [[ "$value" =~ ^[A-Za-z0-9._:+-]+$ ]] || return 1 + KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE="UUID=$value" + return 0 + fi + [ "$rc" -eq 2 ] || return 1 + value="$(blkid -c /dev/null -s PARTUUID -o value "$path" 2>/dev/null)" + rc=$? + if [ "$rc" -eq 0 ]; then + [[ "$value" =~ ^[A-Za-z0-9._:+-]+$ ]] || return 1 + KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE="PARTUUID=$value" + return 0 + fi + [ "$rc" -eq 2 ] || return 1 + return 2 +} + +kpanel_disk_management_probe_fstype() { + local path="$1" value + value="$(blkid -p -c /dev/null -s TYPE -o value "$path" 2>/dev/null)" || return 1 + [[ "$value" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + printf '%s' "$value" +} + +kpanel_disk_management_cleanup_incomplete_backup() { + local snapshot="$1" + [ -d "$snapshot" ] && [ ! -L "$snapshot" ] || return 1 + rm -f -- "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 || return 1 + rmdir -- "$snapshot" >/dev/null 2>&1 +} + +kpanel_disk_management_fstab_backup_valid() ( + local snapshot="$1" recovery="$2" name expected_uid uid mode links entry count=0 file saved_mode saved_owner + local entries=() + [ "$(dirname -- "$snapshot")" = "$recovery" ] || return 1 + name="${snapshot##*/}" + [[ "$name" =~ ^[0-9]{8}T[0-9]{6}Z-fstab\.[A-Za-z0-9]{6}$ ]] || return 1 + kpanel_system_resource_path_has_no_symlink "$snapshot" || return 1 + [ -d "$snapshot" ] && [ ! -L "$snapshot" ] || return 1 + expected_uid="$(kpanel_disk_management_path_owner_uid)" || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$snapshot")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$snapshot")" || return 1 + [[ "$expected_uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0777))" -eq 448 ] || return 1 + shopt -s nullglob dotglob + entries=("$snapshot"/*) + for entry in "${entries[@]}"; do + case "$entry" in + "$snapshot/fstab"|"$snapshot/mode"|"$snapshot/owner") ;; + *) return 1 ;; + esac + count=$((count + 1)) + done + [ "$count" -eq 3 ] || return 1 + for file in "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner"; do + [ -f "$file" ] && [ ! -L "$file" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$file")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$file")" || return 1 + links="$(kpanel_disk_management_lock_stat_links "$file")" || return 1 + [ "$uid" = "$expected_uid" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$links" =~ ^[0-9]+$ ]] && + [ "$((8#$mode & 0777))" -eq 384 ] && [ "$links" -eq 1 ] || return 1 + done + kpanel_system_resource_file_within_bounds "$snapshot/fstab" 1048576 16384 || return 1 + saved_mode="$(<"$snapshot/mode")" || return 1 + saved_owner="$(<"$snapshot/owner")" || return 1 + [[ "$saved_mode" =~ ^[0-7]{3,4}$ ]] && [[ "$saved_owner" =~ ^[0-9]+:[0-9]+$ ]] +) + +kpanel_disk_management_remove_fstab_backup() { + local snapshot="$1" recovery="$2" + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || return 1 + rm -f -- "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 || return 1 + rmdir -- "$snapshot" >/dev/null 2>&1 +} + +kpanel_disk_management_prune_fstab_backups() ( + local limit="$1" protected="${2:-}" recovery="${3:-}" entry remaining index=0 + local entries=() + local LC_ALL=C + [[ "$limit" =~ ^[0-9]+$ ]] || return 1 + [ -n "$recovery" ] || recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + [ -d "$recovery" ] && [ ! -L "$recovery" ] || return 1 + shopt -s nullglob dotglob + entries=("$recovery"/*) + for entry in "${entries[@]}"; do + kpanel_disk_management_fstab_backup_valid "$entry" "$recovery" || return 1 + done + if [ -n "$protected" ]; then + kpanel_disk_management_fstab_backup_valid "$protected" "$recovery" || return 1 + fi + remaining="${#entries[@]}" + while [ "$remaining" -gt "$limit" ]; do + [ "$index" -lt "${#entries[@]}" ] || return 1 + entry="${entries[$index]}" + index=$((index + 1)) + [ "$entry" != "$protected" ] || continue + kpanel_disk_management_remove_fstab_backup "$entry" "$recovery" || return 1 + remaining=$((remaining - 1)) + done +) + +kpanel_disk_management_create_fstab_backup() { + local fstab="$1" recovery timestamp snapshot mode owner + recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + kpanel_disk_management_prune_fstab_backups 15 "" "$recovery" || return 1 + timestamp="$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null)" || return 1 + [[ "$timestamp" =~ ^[0-9]{8}T[0-9]{6}Z$ ]] || return 1 + snapshot="$(mktemp -d "$recovery/${timestamp}-fstab.XXXXXX")" || return 1 + chmod 700 "$snapshot" >/dev/null 2>&1 && chown 0:0 "$snapshot" >/dev/null 2>&1 || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + mode="$(stat -c '%a' "$fstab" 2>/dev/null)" || { kpanel_disk_management_cleanup_incomplete_backup "$snapshot"; return 1; } + owner="$(stat -c '%u:%g' "$fstab" 2>/dev/null)" || { kpanel_disk_management_cleanup_incomplete_backup "$snapshot"; return 1; } + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + cp -- "$fstab" "$snapshot/fstab" >/dev/null 2>&1 && + printf '%s\n' "$mode" > "$snapshot/mode" && + printf '%s\n' "$owner" > "$snapshot/owner" || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + chown 0:0 "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 && + chmod 600 "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 && + sync -f "$snapshot/fstab" >/dev/null 2>&1 && sync -f "$snapshot" >/dev/null 2>&1 || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + printf '%s\n' "$snapshot" +} + +kpanel_disk_management_restore_fstab() { + local fstab="$1" snapshot="$2" directory temporary mode owner recovery + recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || return 1 + mode="$(<"$snapshot/mode")" || return 1 + owner="$(<"$snapshot/owner")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || return 1 + directory="$(dirname -- "$fstab")" || return 1 + temporary="$(mktemp "$directory/.fstab.kpanel-restore.XXXXXX")" || return 1 + cp -- "$snapshot/fstab" "$temporary" >/dev/null 2>&1 && + chown "$owner" "$temporary" >/dev/null 2>&1 && chmod "$mode" "$temporary" >/dev/null 2>&1 && + findmnt --verify --tab-file "$temporary" >&2 && sync -f "$temporary" >/dev/null 2>&1 && + mv -f -- "$temporary" "$fstab" >/dev/null 2>&1 && sync -f "$fstab" >/dev/null 2>&1 && + sync -f "$directory" >/dev/null 2>&1 || { + rm -f -- "$temporary" >/dev/null 2>&1 + return 1 + } + findmnt --verify --tab-file "$fstab" >&2 +} + +kpanel_disk_management_fstab_transaction() { + local operation="$1" source="$2" mountpoint="$3" fstype="$4" + local fstab directory escaped_target desired="" pass_number=0 analysis exact desired_count conflict extra temporary backup uid mode + KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED=false + KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP="" + KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED=false + case "$operation" in ensure|remove) ;; *) return 1 ;; esac + [[ "$source" =~ ^(UUID|PARTUUID)=[A-Za-z0-9._:+-]+$ ]] || return 1 + if [ "$operation" = ensure ]; then + [[ "$fstype" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + fi + fstab="$(kpanel_disk_management_fstab_file)" || return 1 + [ -f "$fstab" ] && [ ! -L "$fstab" ] || return 1 + kpanel_system_resource_path_has_no_symlink "$fstab" || return 1 + kpanel_system_resource_file_within_bounds "$fstab" 1048576 16384 || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$fstab")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$fstab")" || return 1 + [ "$uid" = "$(kpanel_disk_management_path_owner_uid)" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + directory="$(dirname -- "$fstab")" || return 1 + [ -d "$directory" ] && [ ! -L "$directory" ] || return 1 + escaped_target="$(kpanel_disk_management_fstab_escape "$mountpoint")" || return 1 + case "$fstype" in ext2|ext3|ext4) pass_number=2 ;; esac + desired="$source $escaped_target $fstype defaults,nofail 0 $pass_number" + analysis="$(awk -v source="$source" -v target="$escaped_target" -v desired="$desired" -v operation="$operation" ' + BEGIN { exact=0; desired_count=0; conflict=0 } + { + active=($0 !~ /^[[:space:]]*#/ && $0 !~ /^[[:space:]]*$/) + if (active && NF >= 2) { + if ($1 == source && $2 == target) { + exact++ + if ($0 == desired) desired_count++ + } else if ($2 == target || (operation == "ensure" && $1 == source)) { + conflict=1 + } + } + } + END { printf "%d %d %d\n", exact, desired_count, conflict } + ' "$fstab" 2>/dev/null)" || return 1 + read -r exact desired_count conflict extra <<< "$analysis" + [ -z "$extra" ] && [[ "$exact" =~ ^[0-9]+$ ]] && [[ "$desired_count" =~ ^[0-9]+$ ]] && + [[ "$conflict" =~ ^[01]$ ]] || return 1 + [ "$conflict" -eq 0 ] || return 2 + findmnt --verify --tab-file "$fstab" >&2 || return 1 + kpanel_disk_management_prune_fstab_backups 16 || return 1 + if [ "$operation" = ensure ] && [ "$exact" -eq 1 ] && [ "$desired_count" -eq 1 ]; then + return 0 + fi + if [ "$operation" = remove ] && [ "$exact" -eq 0 ]; then + return 0 + fi + temporary="$(mktemp "$directory/.fstab.kpanel.XXXXXX")" || return 1 + awk -v source="$source" -v target="$escaped_target" ' + { + active=($0 !~ /^[[:space:]]*#/ && $0 !~ /^[[:space:]]*$/) + if (active && NF >= 2 && $1 == source && $2 == target) next + print + } + ' "$fstab" > "$temporary" || { rm -f -- "$temporary"; return 1; } + if [ "$operation" = ensure ]; then + printf '%s\n' "$desired" >> "$temporary" || { rm -f -- "$temporary"; return 1; } + fi + kpanel_system_resource_copy_identity "$fstab" "$temporary" || { rm -f -- "$temporary"; return 1; } + findmnt --verify --tab-file "$temporary" >&2 || { rm -f -- "$temporary"; return 1; } + backup="$(kpanel_disk_management_create_fstab_backup "$fstab")" || { rm -f -- "$temporary"; return 1; } + KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP="$backup" + if ! sync -f "$temporary" >/dev/null 2>&1 || + ! mv -f -- "$temporary" "$fstab" >/dev/null 2>&1 || + ! sync -f "$fstab" >/dev/null 2>&1 || + ! sync -f "$directory" >/dev/null 2>&1 || + ! findmnt --verify --tab-file "$fstab" >&2; then + rm -f -- "$temporary" >/dev/null 2>&1 + if ! kpanel_disk_management_restore_fstab "$fstab" "$backup"; then + KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED=true + fi + return 1 + fi + KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED=true +} + +kpanel_disk_management_mountpoint_marker_path() { + local mountpoint="$1" directory digest + directory="$(kpanel_disk_management_prepare_state_subdir mountpoints)" || return 1 + digest="$(printf '%s' "$mountpoint" | sha256sum 2>/dev/null | awk '{print $1}')" || return 1 + [[ "$digest" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s/%s.mountpoint\n' "$directory" "$digest" +} + +kpanel_disk_management_marker_valid() { + local marker="$1" device_id="$2" mountpoint_hex="$3" uid mode links + [ -f "$marker" ] && [ ! -L "$marker" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$marker")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$marker")" || return 1 + links="$(kpanel_disk_management_lock_stat_links "$marker")" || return 1 + [ "$uid" = "$(kpanel_disk_management_path_owner_uid)" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && + [[ "$links" =~ ^[0-9]+$ ]] && [ "$((8#$mode & 0777))" -eq 384 ] && [ "$links" -eq 1 ] || return 1 + kpanel_system_resource_file_within_bounds "$marker" 8192 8 || return 1 + grep -Fqx 'protocol=1' "$marker" && + grep -Fqx "device=$device_id" "$marker" && + grep -Fqx "mountpoint_hex=$mountpoint_hex" "$marker" +} + +kpanel_disk_management_record_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker directory temporary + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint")" || return 1 + directory="$(dirname -- "$marker")" || return 1 + [ ! -L "$marker" ] || return 1 + if [ -e "$marker" ]; then + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" + return $? + fi + temporary="$(mktemp "$directory/.mountpoint.XXXXXX")" || return 1 + printf 'protocol=1\ndevice=%s\nmountpoint_hex=%s\n' "$device_id" "$mountpoint_hex" > "$temporary" || { + rm -f -- "$temporary" + return 1 + } + chown 0:0 "$temporary" >/dev/null 2>&1 && chmod 600 "$temporary" >/dev/null 2>&1 && + sync -f "$temporary" >/dev/null 2>&1 && mv -f -- "$temporary" "$marker" >/dev/null 2>&1 && + sync -f "$directory" >/dev/null 2>&1 || { + rm -f -- "$temporary" + return 1 + } + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" +} + +kpanel_disk_management_forget_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker directory content + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint" 2>/dev/null)" || return 0 + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" || return 0 + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 0 + content="$(find "$mountpoint" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || return 0 + [ -z "$content" ] || return 0 + rmdir -- "$mountpoint" >/dev/null 2>&1 || return 0 + directory="$(dirname -- "$marker")" || return 0 + rm -f -- "$marker" >/dev/null 2>&1 || return 0 + sync -f "$directory" >/dev/null 2>&1 || true +} + +kpanel_disk_management_cleanup_new_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint" 2>/dev/null || true)" + if [ -n "$marker" ] && kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex"; then + rm -f -- "$marker" >/dev/null 2>&1 || true + fi + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] && rmdir -- "$mountpoint" >/dev/null 2>&1 || true +} + +kpanel_disk_management_prepare_device() { + local device_id="$1" rc + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="" + kpanel_disk_management_resolve_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法按 MAJ:MIN 唯一解析安全块设备" + return 1 + fi + kpanel_disk_management_validate_device_common + rc=$? + case "$rc" in + 0) return 0 ;; + 3) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="设备为只读设备或 Swap,拒绝操作" + return 3 + ;; + *) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法可靠读取设备属性" + return 1 + ;; + esac +} + +kpanel_disk_management_require_safe_leaf() { + local rc + kpanel_disk_management_require_leaf_unmounted + rc=$? + case "$rc" in + 0) return 0 ;; + 3) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="设备已挂载、存在子设备或仍被 holder 使用" + return 3 + ;; + *) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法可靠确认设备拓扑或挂载状态" + return 1 + ;; + esac +} + +kpanel_disk_management_rollback_live_mount() { + local device_id="$1" mountpoint="$2" created="$3" mountpoint_hex="$4" target rc + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + if [ "$rc" -eq 0 ]; then + [ "$target" = "$device_id" ] || return 1 + umount -- "$mountpoint" >&2 || return 1 + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + [ "$rc" -eq 1 ] || return 1 + elif [ "$rc" -ne 1 ]; then + return 1 + fi + if [ "$created" = true ]; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$mountpoint" "$mountpoint_hex" + fi +} + +kpanel_disk_management_restore_live_mount() { + local device_id="$1" device_path="$2" mountpoint="$3" target rc + mount --source "$device_path" --target "$mountpoint" >&2 || return 1 + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + [ "$rc" -eq 0 ] && [ "$target" = "$device_id" ] +} + +kpanel_disk_management_mount_action() { + local device_id="$1" mountpoint_hex="$2" persist="$3" + local rc target mounted_rc content parent created=false source_rc fstab_rc backup="" + if ! kpanel_disk_management_decode_mountpoint "$mountpoint_hex"; then + kpanel_disk_management_reply failed "$device_id" "挂载点编码、规范路径或保护路径校验失败" "" 2 + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" true; then + kpanel_disk_management_reply needs-attention "$device_id" "挂载点路径包含符号链接、非 root 目录或可被非 root 写入" "" 3 + return $? + fi + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + [ -n "$KPANEL_DISK_MANAGEMENT_FSTYPE" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "设备没有可挂载的已知文件系统" "" 3 + return $? + } + case "$KPANEL_DISK_MANAGEMENT_FSTYPE" in + swap|LVM2_member|linux_raid_member|crypto_LUKS|zfs_member) + kpanel_disk_management_reply needs-attention "$device_id" "设备签名不是可直接挂载的文件系统" "" 3 + return $? + ;; + esac + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -eq 0 ]; then + [ "$target" = "$device_id" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "目标已被其他设备占用" "" 3 + return $? + } + if [ "$persist" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法安全持久化" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + kpanel_disk_management_fstab_transaction ensure "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "fstab 更新失败且配置回滚失败,需要人工恢复" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在设备或挂载点冲突" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "fstab 持久化失败,原有实时挂载保持不变" "$backup" 1 + fi + return $? + fi + if [ "$KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED" = true ]; then + kpanel_disk_management_reply applied "$device_id" "实时挂载未变化,持久化配置已应用" "$backup" 0 + else + kpanel_disk_management_reply unchanged "$device_id" "设备已经按目标挂载并持久化" "" 0 + fi + return $? + fi + kpanel_disk_management_reply unchanged "$device_id" "设备已经按目标挂载" "" 0 + return $? + elif [ "$rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取目标挂载状态" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" true; then + kpanel_disk_management_reply needs-attention "$device_id" "未挂载目标不是 root 独占的安全目录路径" "" 3 + return $? + fi + kpanel_disk_management_device_is_mounted "$device_id" + mounted_rc=$? + if [ "$mounted_rc" -eq 0 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备已挂载在其他目标,拒绝重复挂载" "" 3 + return $? + elif [ "$mounted_rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取设备挂载状态" "" 1 + return $? + fi + if [ -e "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] || [ -L "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ]; then + [ -d "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] && [ ! -L "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "目标不是安全的真实目录" "" 3 + return $? + } + else + parent="$(dirname -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" || { + kpanel_disk_management_reply failed "$device_id" "无法解析挂载点父目录" "" 1 + return $? + } + [ -d "$parent" ] && [ ! -L "$parent" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "挂载点父目录不存在或不安全" "" 3 + return $? + } + if ! (umask 077; mkdir -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT") >/dev/null 2>&1; then + kpanel_disk_management_reply failed "$device_id" "创建挂载点失败" "" 1 + return $? + fi + created=true + if ! chown 0:0 "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >/dev/null 2>&1 || + ! chmod 700 "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >/dev/null 2>&1; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法设置新挂载点安全属性" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "新挂载点安全属性复核失败" "" 1 + return $? + fi + if ! kpanel_disk_management_record_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法记录 KPanel 创建的挂载点" "" 1 + return $? + fi + fi + content="$(find "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || { + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法安全检查挂载点内容" "" 1 + return $? + } + if [ -n "$content" ]; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply needs-attention "$device_id" "挂载点非空,拒绝覆盖现有内容" "" 3 + return $? + fi + if [ "$persist" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法安全持久化" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply needs-attention "$device_id" "挂载前安全复核失败" "" 3 + return $? + fi + if ! mount --source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" --target "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >&2; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载命令失败,未保留部分状态" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载命令失败且无法确认或清理部分挂载" "" 4 + fi + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载后安全属性复核失败,已回滚" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载后安全属性复核失败且回滚失败" "" 4 + fi + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -ne 0 ] || [ "$target" != "$device_id" ]; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载完成态回读失败,已回滚" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载完成态回读失败且回滚失败" "" 4 + fi + return $? + fi + if [ "$persist" = 1 ]; then + kpanel_disk_management_fstab_transaction ensure "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if ! kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" || + [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "fstab 持久化失败且回滚未完整完成" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在冲突,实时挂载已回滚" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "fstab 持久化失败,实时挂载已回滚" "$backup" 1 + fi + return $? + fi + fi + backup="${KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP:-}" + kpanel_disk_management_reply applied "$device_id" "设备已挂载并完成状态回读" "$backup" 0 +} + +kpanel_disk_management_unmount_action() { + local device_id="$1" mountpoint_hex="$2" remove_persistence="$3" + local rc target mounted_rc source_rc fstab_rc backup="" + if ! kpanel_disk_management_decode_mountpoint "$mountpoint_hex"; then + kpanel_disk_management_reply failed "$device_id" "挂载点编码、规范路径或保护路径校验失败" "" 2 + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_reply needs-attention "$device_id" "卸载目标路径包含符号链接、非 root 目录或可被非 root 写入" "" 3 + return $? + fi + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -eq 1 ]; then + kpanel_disk_management_device_is_mounted "$device_id" + mounted_rc=$? + if [ "$mounted_rc" -eq 0 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备挂载在其他目标,拒绝卸载" "" 3 + elif [ "$mounted_rc" -eq 1 ]; then + kpanel_disk_management_reply unchanged "$device_id" "设备未挂载在指定目标" "" 0 + else + kpanel_disk_management_reply failed "$device_id" "无法可靠读取设备挂载状态" "" 1 + fi + return $? + elif [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取目标挂载状态" "" 1 + return $? + fi + [ "$target" = "$device_id" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "指定目标由其他设备占用" "" 3 + return $? + } + if [ "$remove_persistence" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法精确移除持久化记录" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_reply needs-attention "$device_id" "卸载前安全复核失败" "" 3 + return $? + fi + if ! umount -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >&2; then + kpanel_disk_management_reply needs-attention "$device_id" "普通卸载失败,设备可能正被使用" "" 3 + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "卸载完成态回读失败" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + if kpanel_disk_management_restore_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT"; then + kpanel_disk_management_reply failed "$device_id" "卸载后安全属性复核失败,实时挂载已恢复" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "卸载后安全属性复核失败且实时挂载恢复失败" "" 4 + fi + return $? + fi + if [ "$remove_persistence" = 1 ]; then + kpanel_disk_management_fstab_transaction remove "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if ! kpanel_disk_management_restore_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" || + [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "持久化移除失败且实时挂载回滚失败" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在冲突,实时挂载已恢复" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "持久化移除失败,实时挂载已恢复" "$backup" 1 + fi + return $? + fi + fi + kpanel_disk_management_forget_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + backup="${KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP:-}" + kpanel_disk_management_reply applied "$device_id" "设备已从指定目标卸载" "$backup" 0 +} + +kpanel_disk_management_format_action() { + local device_id="$1" requested_fstype="$2" command_name rc actual + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + kpanel_disk_management_require_safe_leaf + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + case "$requested_fstype" in + ext4) command_name=mkfs.ext4 ;; + xfs) command_name=mkfs.xfs ;; + ntfs) + if kpanel_disk_management_command_available mkfs.ntfs; then + command_name=mkfs.ntfs + elif kpanel_disk_management_command_available mkntfs; then + command_name=mkntfs + else + command_name="" + fi + ;; + vfat) + if kpanel_disk_management_command_available mkfs.vfat; then + command_name=mkfs.vfat + elif kpanel_disk_management_command_available mkfs.fat; then + command_name=mkfs.fat + else + command_name="" + fi + ;; + esac + if [ -z "$command_name" ] || ! kpanel_disk_management_command_available "$command_name"; then + kpanel_disk_management_reply needs-attention "$device_id" "缺少所选文件系统的格式化工具" "" 3 + return $? + fi + case "$requested_fstype" in + ext4) mkfs.ext4 -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs) mkfs.xfs -f "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs) + case "$command_name" in + mkfs.ntfs) mkfs.ntfs -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + mkntfs) mkntfs -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + vfat) + case "$command_name" in + mkfs.vfat) mkfs.vfat "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + mkfs.fat) mkfs.fat "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + esac + rc=$? + if [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "$device_id" "格式化命令失败,未声明可回滚" "" 1 + return $? + fi + command -v udevadm >/dev/null 2>&1 && udevadm settle >&2 || true + actual="$(kpanel_disk_management_probe_fstype "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH")" || { + kpanel_disk_management_reply failed "$device_id" "格式化后无法重读文件系统类型" "" 1 + return $? + } + [ "$actual" = "$requested_fstype" ] || { + kpanel_disk_management_reply failed "$device_id" "格式化后文件系统类型回读不一致" "" 1 + return $? + } + kpanel_disk_management_reply applied "$device_id" "格式化已完成并通过文件系统类型回读" "" 0 +} + +kpanel_disk_management_check_action() { + local device_id="$1" mode="$2" fstype command_name rc + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + kpanel_disk_management_require_safe_leaf + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + fstype="$(kpanel_disk_management_probe_fstype "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH")" || { + kpanel_disk_management_reply needs-attention "$device_id" "无法识别可检查的文件系统" "" 3 + return $? + } + case "$fstype" in + ext4) command_name=e2fsck ;; + xfs) command_name=xfs_repair ;; + ntfs) command_name=ntfsfix ;; + vfat) + if kpanel_disk_management_command_available fsck.vfat; then + command_name=fsck.vfat + elif kpanel_disk_management_command_available fsck.fat; then + command_name=fsck.fat + else + command_name="" + fi + ;; + *) + kpanel_disk_management_reply needs-attention "$device_id" "当前文件系统不在 v1 检查支持范围" "" 3 + return $? + ;; + esac + if [ -z "$command_name" ] || ! kpanel_disk_management_command_available "$command_name"; then + kpanel_disk_management_reply needs-attention "$device_id" "缺少当前文件系统的检查工具" "" 3 + return $? + fi + case "$fstype:$mode" in + ext4:readonly) e2fsck -fn "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ext4:repair) e2fsck -fy "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs:readonly) xfs_repair -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs:repair) xfs_repair "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs:readonly) ntfsfix -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs:repair) ntfsfix "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + vfat:readonly) + case "$command_name" in + fsck.vfat) fsck.vfat -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + fsck.fat) fsck.fat -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + vfat:repair) + case "$command_name" in + fsck.vfat) fsck.vfat -a "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + fsck.fat) fsck.fat -a "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + esac + rc=$? + if [ "$mode" = readonly ]; then + if [ "$rc" -eq 0 ]; then + kpanel_disk_management_reply unchanged "$device_id" "只读文件系统检查完成,未执行修复" "" 0 + else + kpanel_disk_management_reply needs-attention "$device_id" "只读检查发现问题或检查工具未能完整执行" "" 3 + fi + return $? + fi + case "$fstype:$rc" in + ext4:0|ext4:1|ext4:2|ext4:3|vfat:0|vfat:1|xfs:0|ntfs:0) + kpanel_disk_management_reply applied "$device_id" "文件系统修复命令已成功完成" "" 0 + ;; + *) + kpanel_disk_management_reply failed "$device_id" "文件系统修复命令失败" "" 1 + ;; + esac +} + +kpanel_disk_management_run_locked() ( + local action="$1" + shift + case "$action" in + mount) kpanel_disk_management_mount_action "$@" ;; + unmount) kpanel_disk_management_unmount_action "$@" ;; + format) kpanel_disk_management_format_action "$@" ;; + check) kpanel_disk_management_check_action "$@" ;; + *) kpanel_disk_management_reply failed "" "不支持的 disk-management 动作" "" 2 ;; + esac +) + +kpanel_disk_management_dispatch() { + local action="${1:-}" device_id="" lock_file rc + shift || true + [[ "${1:-}" =~ ^[0-9]+:[0-9]+$ ]] && device_id="$1" + printf 'KPANEL_DISK_MANAGEMENT_PROTOCOL %s\n' "$KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION" + kpanel_disk_management_require_platform + rc=$? + if [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "" "$KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE" "" "$rc" + return $? + fi + case "$action" in + mount|unmount) + [ "$#" -eq 3 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && + [[ "$2" =~ ^[0-9a-fA-F]+$ ]] && [ "$(( ${#2} % 2 ))" -eq 0 ] && + [[ "$3" =~ ^[01]$ ]] || { + kpanel_disk_management_reply failed "$device_id" "mount/unmount 参数无效" "" 2 + return $? + } + ;; + format) + [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && [[ "$2" =~ ^(ext4|xfs|ntfs|vfat)$ ]] || { + kpanel_disk_management_reply failed "$device_id" "format 参数无效" "" 2 + return $? + } + ;; + check) + [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && [[ "$2" =~ ^(readonly|repair)$ ]] || { + kpanel_disk_management_reply failed "$device_id" "check 参数无效" "" 2 + return $? + } + ;; + *) + kpanel_disk_management_reply failed "$device_id" "用法: k kpanel disk-management ..." "" 2 + return $? + ;; + esac + lock_file="$(kpanel_disk_management_prepare_lock_file)" || { + kpanel_disk_management_reply failed "$device_id" "disk-management 锁路径不安全或无法创建" "" 1 + return $? + } + exec 9<>"$lock_file" || { + kpanel_disk_management_reply failed "$device_id" "无法打开 disk-management 锁" "" 1 + return $? + } + kpanel_disk_management_lock_file_secure "$lock_file" || { + exec 9>&- + kpanel_disk_management_reply failed "$device_id" "disk-management 锁文件打开后验证失败" "" 1 + return $? + } + if ! flock -w 5 -x 9 >/dev/null 2>&1; then + exec 9>&- + kpanel_disk_management_reply conflict "$device_id" "disk-management 写锁等待超时" "" 2 + return $? + fi + kpanel_disk_management_run_locked "$action" "$@" +} + +# KPanel disk management protocol end + + # KPanel network operations protocol start KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1" @@ -28433,6 +29792,9 @@ else elif [ "${1:-}" = "system-resource" ]; then shift kpanel_system_resource_dispatch "$@" + elif [ "${1:-}" = "disk-management" ]; then + shift + kpanel_disk_management_dispatch "$@" elif [ "${1:-}" = "network-operations" ]; then shift kpanel_network_operations_dispatch "$@" @@ -28443,7 +29805,7 @@ else shift kpanel_system_tuning_dispatch "$@" else - echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ... | system-tuning ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | disk-management ... | network-operations ... | account-management ... | system-tuning ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/kejilion.sh b/kejilion.sh index 9d276e8a3..9eea87797 100644 --- a/kejilion.sh +++ b/kejilion.sh @@ -25,6 +25,7 @@ kpanel_protocol_active() { [ "${KJ_SSH_PORT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_DNS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_SYSTEM_RESOURCE_NONINTERACTIVE:-}" = "1" ] || + [ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_NETWORK_OPERATIONS_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_ACCOUNT_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] || [ "${KJ_F2B_NONINTERACTIVE:-}" = "1" ] || @@ -24827,6 +24828,1364 @@ kpanel_system_resource_dispatch() { # KPanel system resource protocol end +# KPanel disk management protocol start +KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION="1" + +kpanel_disk_management_hex_encode() { + local value="${1-}" encoded="" byte decimal index + local LC_ALL=C + for ((index = 0; index < ${#value}; index++)); do + byte="${value:index:1}" + printf -v decimal '%d' "'$byte" + printf -v byte '%02x' "$decimal" + encoded+="$byte" + done + printf '%s' "$encoded" +} + +kpanel_disk_management_emit() { + local status="$1" device="${2:-}" message="${3:-}" backup="${4:-}" + case "$status" in + applied|unchanged|failed|conflict|needs-attention|rollback-failed) ;; + *) status=failed ;; + esac + [[ "$device" =~ ^[0-9]+:[0-9]+$ ]] || device="" + printf 'KPANEL_DISK_MANAGEMENT_STATUS=%s\n' "$status" + printf 'KPANEL_DISK_MANAGEMENT_DEVICE=%s\n' "$device" + printf 'KPANEL_DISK_MANAGEMENT_MESSAGE_HEX=%s\n' "$(kpanel_disk_management_hex_encode "$message")" + printf 'KPANEL_DISK_MANAGEMENT_BACKUP_HEX=%s\n' "$(kpanel_disk_management_hex_encode "$backup")" +} + +kpanel_disk_management_error() { + printf '错误: %s\n' "$1" >&2 +} + +kpanel_disk_management_reply() { + local status="$1" device="$2" message="$3" backup="$4" result="$5" + case "$status" in applied|unchanged) ;; *) kpanel_disk_management_error "$message" ;; esac + kpanel_disk_management_emit "$status" "$device" "$message" "$backup" + return "$result" +} + +kpanel_disk_management_lock_file() { + printf '%s\n' "/run/lock/kejilion-kpanel-disk.lock" +} + +kpanel_disk_management_lock_owner_uid() { + printf '0\n' +} + +kpanel_disk_management_lock_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_gid() { + stat -c '%g' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_stat_links() { + stat -c '%h' "$1" 2>/dev/null +} + +kpanel_disk_management_lock_parent_secure() { + local parent="$1" uid expected_uid gid mode numeric_mode + [ ! -L "$parent" ] && [ -d "$parent" ] || return 1 + uid="$(kpanel_disk_management_lock_stat_uid "$parent")" || return 1 + expected_uid="$(kpanel_disk_management_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_disk_management_lock_stat_mode "$parent")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || return 1 + numeric_mode=$((8#$mode)) + # A newly created private parent is 0700. Existing system-managed /run/lock + # may be 0755/0775 or 1777; require root:root and sticky when world-writable. + [ "$((numeric_mode & 0777))" -eq 448 ] && return 0 + gid="$(kpanel_disk_management_lock_stat_gid "$parent")" || return 1 + [[ "$gid" =~ ^[0-9]+$ ]] && [ "$gid" = 0 ] || return 1 + [ "$((numeric_mode & 0002))" -eq 0 ] || [ "$((numeric_mode & 01000))" -ne 0 ] +} + +kpanel_disk_management_lock_file_secure() { + local path="$1" uid expected_uid mode links + [ ! -L "$path" ] && [ -f "$path" ] || return 1 + uid="$(kpanel_disk_management_lock_stat_uid "$path")" || return 1 + expected_uid="$(kpanel_disk_management_lock_owner_uid)" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + mode="$(kpanel_disk_management_lock_stat_mode "$path")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0777))" -eq 384 ] || return 1 + links="$(kpanel_disk_management_lock_stat_links "$path")" || return 1 + [[ "$links" =~ ^[0-9]+$ ]] && [ "$links" -eq 1 ] +} + +kpanel_disk_management_prepare_lock_file() { + local lock_file parent parent_parent created=false + lock_file="$(kpanel_disk_management_lock_file)" || return 1 + [[ "$lock_file" = /* ]] && [[ "$lock_file" != *$'\n'* ]] && [[ "$lock_file" != *$'\r'* ]] || return 1 + parent="$(dirname -- "$lock_file")" || return 1 + [ ! -L "$parent" ] || return 1 + if [ ! -e "$parent" ]; then + parent_parent="$(dirname -- "$parent")" || return 1 + [ -d "$parent_parent" ] && [ ! -L "$parent_parent" ] || return 1 + (umask 077; mkdir -- "$parent") >/dev/null 2>&1 || return 1 + chown 0:0 "$parent" >/dev/null 2>&1 && chmod 700 "$parent" >/dev/null 2>&1 || return 1 + fi + kpanel_disk_management_lock_parent_secure "$parent" || return 1 + [ ! -L "$lock_file" ] || return 1 + if [ ! -e "$lock_file" ]; then + (umask 077; set -o noclobber; : > "$lock_file") >/dev/null 2>&1 || return 1 + created=true + fi + [ -f "$lock_file" ] && [ ! -L "$lock_file" ] || return 1 + if [ "$created" = true ]; then + chown 0:0 "$lock_file" >/dev/null 2>&1 && chmod 600 "$lock_file" >/dev/null 2>&1 || return 1 + fi + kpanel_disk_management_lock_file_secure "$lock_file" || return 1 + printf '%s\n' "$lock_file" +} + +kpanel_disk_management_require_commands() { + local command_name + for command_name in "$@"; do + command -v "$command_name" >/dev/null 2>&1 || { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="缺少必要命令: $command_name" + return 1 + } + done +} + +kpanel_disk_management_command_available() { + command -v "$1" >/dev/null 2>&1 +} + +kpanel_disk_management_require_platform() { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="" + if [ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" != "1" ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议环境未启用" + return 2 + fi + if [ "$EUID" -ne 0 ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议必须以 root 运行" + return 2 + fi + if ! command -v uname >/dev/null 2>&1; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="缺少必要命令: uname" + return 1 + fi + if [ "$(uname -s 2>/dev/null)" != Linux ]; then + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="KPanel disk-management 协议仅支持 Linux" + return 2 + fi + kpanel_disk_management_require_commands \ + awk basename blkid chmod chown cp date dirname find findmnt flock grep lsblk mkdir mktemp \ + mount mv readlink rm rmdir sha256sum stat sync umount uname wc +} + +kpanel_disk_management_path_owner_uid() { + printf '0\n' +} + +kpanel_disk_management_path_stat_uid() { + stat -c '%u' "$1" 2>/dev/null +} + +kpanel_disk_management_path_stat_mode() { + stat -c '%a' "$1" 2>/dev/null +} + +kpanel_disk_management_path_chain_secure() { + local path="$1" expected_uid remainder current component uid mode + local components=() + [[ "$path" = /* ]] && [ -d "$path" ] && [ ! -L "$path" ] || return 1 + [ "$path" = / ] || kpanel_system_resource_path_has_no_symlink "$path" || return 1 + expected_uid="$(kpanel_disk_management_path_owner_uid)" || return 1 + [[ "$expected_uid" =~ ^[0-9]+$ ]] || return 1 + current=/ + remainder="${path#/}" + IFS=/ read -r -a components <<< "$remainder" + components=("/" "${components[@]}") + for component in "${components[@]}"; do + if [ "$component" != / ]; then + [ -n "$component" ] && [ "$component" != . ] && [ "$component" != .. ] || return 1 + current="${current%/}/$component" + fi + [ -d "$current" ] && [ ! -L "$current" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$current")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$current")" || return 1 + [[ "$uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + done +} + +kpanel_disk_management_mountpoint_path_secure() { + local mountpoint="$1" allow_missing="$2" parent + kpanel_system_resource_path_has_no_symlink "$mountpoint" || return 1 + if [ -e "$mountpoint" ] || [ -L "$mountpoint" ]; then + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 1 + kpanel_disk_management_path_chain_secure "$mountpoint" + return $? + fi + [ "$allow_missing" = true ] || return 1 + parent="$(dirname -- "$mountpoint")" || return 1 + kpanel_disk_management_path_chain_secure "$parent" +} + +kpanel_disk_management_mountpoint_parent_secure() { + local mountpoint="$1" allow_missing="$2" parent + kpanel_system_resource_path_has_no_symlink "$mountpoint" || return 1 + if [ -e "$mountpoint" ] || [ -L "$mountpoint" ]; then + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 1 + else + [ "$allow_missing" = true ] || return 1 + fi + parent="$(dirname -- "$mountpoint")" || return 1 + kpanel_disk_management_path_chain_secure "$parent" +} + +kpanel_disk_management_decode_mountpoint() { + local encoded="$1" decoded="" canonical pair byte decimal index protected parent leaf canonical_parent + local LC_ALL=C + [ -n "$encoded" ] && [ "${#encoded}" -le 8192 ] && [ "$(( ${#encoded} % 2 ))" -eq 0 ] || return 1 + [[ "$encoded" =~ ^[0-9a-fA-F]+$ ]] || return 1 + for ((index = 0; index < ${#encoded}; index += 2)); do + pair="${encoded:index:2}" + decimal=$((16#$pair)) + [ "$decimal" -ge 32 ] && [ "$decimal" -ne 127 ] || return 1 + printf -v byte '%b' "\\x$pair" + decoded+="$byte" + done + [ -n "$decoded" ] && [[ "$decoded" = /* ]] || return 1 + [[ "$decoded" != *$'\n'* ]] && [[ "$decoded" != *$'\r'* ]] || return 1 + if [ -e "$decoded" ] || [ -L "$decoded" ]; then + canonical="$(readlink -f -- "$decoded" 2>/dev/null)" || return 1 + else + parent="$(dirname -- "$decoded")" || return 1 + leaf="$(basename -- "$decoded")" || return 1 + [ -n "$leaf" ] && [ "$leaf" != . ] && [ "$leaf" != .. ] || return 1 + canonical_parent="$(readlink -f -- "$parent" 2>/dev/null)" || return 1 + [ -d "$canonical_parent" ] && [ ! -L "$canonical_parent" ] || return 1 + canonical="${canonical_parent%/}/$leaf" + fi + [ "$canonical" = "$decoded" ] || return 1 + [ "$decoded" != / ] || return 1 + for protected in /boot /boot/efi /home /var/lib/kejilion-panel /home/docker; do + case "$decoded" in "$protected"|"$protected"/*) return 1 ;; esac + case "$protected" in "$decoded"/*) return 1 ;; esac + done + KPANEL_DISK_MANAGEMENT_MOUNTPOINT="$decoded" + KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX="$(kpanel_disk_management_hex_encode "$decoded")" +} + +kpanel_disk_management_is_block_device() { + [ -b "$1" ] +} + +kpanel_disk_management_resolve_device() { + local requested="$1" output line device_id device_path extra resolved verify matches=0 invalid=false + [[ "$requested" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + output="$(lsblk --noheadings --raw --paths --output MAJ:MIN,PATH 2>/dev/null)" || return 1 + while IFS= read -r line; do + [ -n "$line" ] || continue + device_id=""; device_path=""; extra="" + read -r device_id device_path extra <<< "$line" + if [ -n "$extra" ] || [[ ! "$device_id" =~ ^[0-9]+:[0-9]+$ ]] || [[ "$device_path" != /dev/* ]]; then + invalid=true + continue + fi + if [ "$device_id" = "$requested" ]; then + matches=$((matches + 1)) + KPANEL_DISK_MANAGEMENT_LISTED_PATH="$device_path" + fi + done <<< "$output" + [ "$invalid" = false ] && [ "$matches" -eq 1 ] || return 1 + resolved="$(readlink -f -- "$KPANEL_DISK_MANAGEMENT_LISTED_PATH" 2>/dev/null)" || return 1 + [[ "$resolved" = /dev/* ]] && kpanel_disk_management_is_block_device "$resolved" || return 1 + verify="$(lsblk --nodeps --noheadings --raw --output MAJ:MIN -- "$resolved" 2>/dev/null)" || return 1 + [ "$verify" = "$requested" ] || return 1 + KPANEL_DISK_MANAGEMENT_DEVICE_PATH="$resolved" + KPANEL_DISK_MANAGEMENT_DEVICE_ID="$requested" +} + +kpanel_disk_management_lsblk_value() { + local path="$1" column="$2" value + case "$column" in TYPE|RO|FSTYPE) ;; *) return 1 ;; esac + value="$(lsblk --nodeps --noheadings --raw --output "$column" -- "$path" 2>/dev/null)" || return 1 + [[ "$value" != *$'\n'* ]] && [[ "$value" != *$'\r'* ]] || return 1 + printf '%s' "$value" +} + +kpanel_disk_management_swaps_file() { + printf '%s\n' "/proc/swaps" +} + +kpanel_disk_management_device_is_active_swap() { + local device="$1" swaps source rest resolved + swaps="$(kpanel_disk_management_swaps_file)" || return 2 + [ -r "$swaps" ] || return 2 + while read -r source rest; do + [ -n "$source" ] || continue + [ "$source" != Filename ] || continue + case "$source" in + /dev/*) + resolved="$(readlink -f -- "$source" 2>/dev/null)" || return 2 + [ "$resolved" != "$device" ] || return 0 + ;; + esac + done < "$swaps" + return 1 +} + +kpanel_disk_management_validate_device_common() { + local type ro fstype probed probe_rc swap_rc + type="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" TYPE)" || return 1 + ro="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" RO)" || return 1 + fstype="$(kpanel_disk_management_lsblk_value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" FSTYPE)" || return 1 + [[ "$type" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + [[ "$ro" =~ ^[01]$ ]] || return 1 + [ -z "$fstype" ] || [[ "$fstype" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + probed="$(blkid -p -c /dev/null -s TYPE -o value "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" 2>/dev/null)" + probe_rc=$? + case "$probe_rc" in + 0) + [[ "$probed" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + fstype="$probed" + ;; + 2) [ -z "$fstype" ] || return 1 ;; + *) return 1 ;; + esac + [ "$ro" = 0 ] || return 3 + [ "$fstype" != swap ] || return 3 + kpanel_disk_management_device_is_active_swap "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + swap_rc=$? + [ "$swap_rc" -ne 0 ] || return 3 + [ "$swap_rc" -eq 1 ] || return 1 + KPANEL_DISK_MANAGEMENT_DEVICE_TYPE="$type" + KPANEL_DISK_MANAGEMENT_FSTYPE="$fstype" +} + +kpanel_disk_management_device_is_leaf() { + local path="$1" expected="$2" output line count=0 + output="$(lsblk --noheadings --raw --output MAJ:MIN -- "$path" 2>/dev/null)" || return 2 + while IFS= read -r line; do + [ -n "$line" ] || continue + [[ "$line" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + [ "$count" -ne 0 ] || [ "$line" = "$expected" ] || return 2 + count=$((count + 1)) + done <<< "$output" + [ "$count" -eq 1 ] +} + +kpanel_disk_management_holders_dir() { + printf '/sys/dev/block/%s/holders\n' "$1" +} + +kpanel_disk_management_device_has_holders() { + local device_id="$1" directory first + directory="$(kpanel_disk_management_holders_dir "$device_id")" || return 2 + [ -d "$directory" ] || return 2 + first="$(find "$directory" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || return 2 + [ -n "$first" ] +} + +kpanel_disk_management_mount_ids() { + local output line + output="$(findmnt --kernel --raw --noheadings --output MAJ:MIN 2>/dev/null)" || return 2 + [ -n "$output" ] || return 2 + while IFS= read -r line; do + [ -n "$line" ] || continue + [[ "$line" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + printf '%s\n' "$line" + done <<< "$output" +} + +kpanel_disk_management_device_is_mounted() { + local requested="$1" output line + output="$(kpanel_disk_management_mount_ids)" || return 2 + while IFS= read -r line; do + [ "$line" != "$requested" ] || return 0 + done <<< "$output" + return 1 +} + +kpanel_disk_management_target_device() { + local mountpoint="$1" output rc + output="$(findmnt --kernel --raw --noheadings --output MAJ:MIN --mountpoint "$mountpoint" 2>/dev/null)" + rc=$? + if [ "$rc" -ne 0 ]; then + [ "$rc" -eq 1 ] && [ -z "$output" ] && return 1 + return 2 + fi + [[ "$output" =~ ^[0-9]+:[0-9]+$ ]] || return 2 + printf '%s' "$output" +} + +kpanel_disk_management_require_leaf_unmounted() { + local leaf_rc holders_rc mounted_rc + kpanel_disk_management_device_is_leaf "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + leaf_rc=$? + [ "$leaf_rc" -eq 0 ] || { [ "$leaf_rc" -eq 1 ] && return 3; return 1; } + kpanel_disk_management_device_has_holders "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + holders_rc=$? + [ "$holders_rc" -ne 0 ] || return 3 + [ "$holders_rc" -eq 1 ] || return 1 + kpanel_disk_management_device_is_mounted "$KPANEL_DISK_MANAGEMENT_DEVICE_ID" + mounted_rc=$? + [ "$mounted_rc" -ne 0 ] || return 3 + [ "$mounted_rc" -eq 1 ] || return 1 +} + +kpanel_disk_management_fstab_file() { + printf '%s\n' "/etc/fstab" +} + +kpanel_disk_management_state_root() { + printf '%s/system/disk-management\n' "$(kpanel_system_resource_state_root)" +} + +kpanel_disk_management_prepare_state_subdir() { + local name="$1" root path + case "$name" in mountpoints|recovery) ;; *) return 1 ;; esac + root="$(kpanel_disk_management_state_root)" || return 1 + [[ "$root" = /* ]] && [ "$root" != / ] || return 1 + kpanel_system_resource_path_has_no_symlink "$root" || return 1 + if [ ! -e "$root" ]; then + (umask 077; mkdir -p -- "$root") >/dev/null 2>&1 || return 1 + fi + kpanel_system_resource_path_has_no_symlink "$root" && + kpanel_system_resource_secure_directory "$root" || return 1 + path="$root/$name" + kpanel_system_resource_path_has_no_symlink "$path" || return 1 + if [ ! -e "$path" ]; then + (umask 077; mkdir -- "$path") >/dev/null 2>&1 || return 1 + fi + kpanel_system_resource_path_has_no_symlink "$path" && + kpanel_system_resource_secure_directory "$path" || return 1 + printf '%s\n' "$path" +} + +kpanel_disk_management_fstab_escape() { + local value="$1" + value="${value//\\/\\134}" + value="${value// /\\040}" + printf '%s' "$value" +} + +kpanel_disk_management_persistence_source() { + local path="$1" value rc + value="$(blkid -c /dev/null -s UUID -o value "$path" 2>/dev/null)" + rc=$? + if [ "$rc" -eq 0 ]; then + [[ "$value" =~ ^[A-Za-z0-9._:+-]+$ ]] || return 1 + KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE="UUID=$value" + return 0 + fi + [ "$rc" -eq 2 ] || return 1 + value="$(blkid -c /dev/null -s PARTUUID -o value "$path" 2>/dev/null)" + rc=$? + if [ "$rc" -eq 0 ]; then + [[ "$value" =~ ^[A-Za-z0-9._:+-]+$ ]] || return 1 + KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE="PARTUUID=$value" + return 0 + fi + [ "$rc" -eq 2 ] || return 1 + return 2 +} + +kpanel_disk_management_probe_fstype() { + local path="$1" value + value="$(blkid -p -c /dev/null -s TYPE -o value "$path" 2>/dev/null)" || return 1 + [[ "$value" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + printf '%s' "$value" +} + +kpanel_disk_management_cleanup_incomplete_backup() { + local snapshot="$1" + [ -d "$snapshot" ] && [ ! -L "$snapshot" ] || return 1 + rm -f -- "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 || return 1 + rmdir -- "$snapshot" >/dev/null 2>&1 +} + +kpanel_disk_management_fstab_backup_valid() ( + local snapshot="$1" recovery="$2" name expected_uid uid mode links entry count=0 file saved_mode saved_owner + local entries=() + [ "$(dirname -- "$snapshot")" = "$recovery" ] || return 1 + name="${snapshot##*/}" + [[ "$name" =~ ^[0-9]{8}T[0-9]{6}Z-fstab\.[A-Za-z0-9]{6}$ ]] || return 1 + kpanel_system_resource_path_has_no_symlink "$snapshot" || return 1 + [ -d "$snapshot" ] && [ ! -L "$snapshot" ] || return 1 + expected_uid="$(kpanel_disk_management_path_owner_uid)" || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$snapshot")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$snapshot")" || return 1 + [[ "$expected_uid" =~ ^[0-9]+$ ]] && [ "$uid" = "$expected_uid" ] || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [ "$((8#$mode & 0777))" -eq 448 ] || return 1 + shopt -s nullglob dotglob + entries=("$snapshot"/*) + for entry in "${entries[@]}"; do + case "$entry" in + "$snapshot/fstab"|"$snapshot/mode"|"$snapshot/owner") ;; + *) return 1 ;; + esac + count=$((count + 1)) + done + [ "$count" -eq 3 ] || return 1 + for file in "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner"; do + [ -f "$file" ] && [ ! -L "$file" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$file")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$file")" || return 1 + links="$(kpanel_disk_management_lock_stat_links "$file")" || return 1 + [ "$uid" = "$expected_uid" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$links" =~ ^[0-9]+$ ]] && + [ "$((8#$mode & 0777))" -eq 384 ] && [ "$links" -eq 1 ] || return 1 + done + kpanel_system_resource_file_within_bounds "$snapshot/fstab" 1048576 16384 || return 1 + saved_mode="$(<"$snapshot/mode")" || return 1 + saved_owner="$(<"$snapshot/owner")" || return 1 + [[ "$saved_mode" =~ ^[0-7]{3,4}$ ]] && [[ "$saved_owner" =~ ^[0-9]+:[0-9]+$ ]] +) + +kpanel_disk_management_remove_fstab_backup() { + local snapshot="$1" recovery="$2" + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || return 1 + rm -f -- "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 || return 1 + rmdir -- "$snapshot" >/dev/null 2>&1 +} + +kpanel_disk_management_prune_fstab_backups() ( + local limit="$1" protected="${2:-}" recovery="${3:-}" entry remaining index=0 + local entries=() + local LC_ALL=C + [[ "$limit" =~ ^[0-9]+$ ]] || return 1 + [ -n "$recovery" ] || recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + [ -d "$recovery" ] && [ ! -L "$recovery" ] || return 1 + shopt -s nullglob dotglob + entries=("$recovery"/*) + for entry in "${entries[@]}"; do + kpanel_disk_management_fstab_backup_valid "$entry" "$recovery" || return 1 + done + if [ -n "$protected" ]; then + kpanel_disk_management_fstab_backup_valid "$protected" "$recovery" || return 1 + fi + remaining="${#entries[@]}" + while [ "$remaining" -gt "$limit" ]; do + [ "$index" -lt "${#entries[@]}" ] || return 1 + entry="${entries[$index]}" + index=$((index + 1)) + [ "$entry" != "$protected" ] || continue + kpanel_disk_management_remove_fstab_backup "$entry" "$recovery" || return 1 + remaining=$((remaining - 1)) + done +) + +kpanel_disk_management_create_fstab_backup() { + local fstab="$1" recovery timestamp snapshot mode owner + recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + kpanel_disk_management_prune_fstab_backups 15 "" "$recovery" || return 1 + timestamp="$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null)" || return 1 + [[ "$timestamp" =~ ^[0-9]{8}T[0-9]{6}Z$ ]] || return 1 + snapshot="$(mktemp -d "$recovery/${timestamp}-fstab.XXXXXX")" || return 1 + chmod 700 "$snapshot" >/dev/null 2>&1 && chown 0:0 "$snapshot" >/dev/null 2>&1 || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + mode="$(stat -c '%a' "$fstab" 2>/dev/null)" || { kpanel_disk_management_cleanup_incomplete_backup "$snapshot"; return 1; } + owner="$(stat -c '%u:%g' "$fstab" 2>/dev/null)" || { kpanel_disk_management_cleanup_incomplete_backup "$snapshot"; return 1; } + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + cp -- "$fstab" "$snapshot/fstab" >/dev/null 2>&1 && + printf '%s\n' "$mode" > "$snapshot/mode" && + printf '%s\n' "$owner" > "$snapshot/owner" || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + chown 0:0 "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 && + chmod 600 "$snapshot/fstab" "$snapshot/mode" "$snapshot/owner" >/dev/null 2>&1 && + sync -f "$snapshot/fstab" >/dev/null 2>&1 && sync -f "$snapshot" >/dev/null 2>&1 || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || { + kpanel_disk_management_cleanup_incomplete_backup "$snapshot" >/dev/null 2>&1 || true + return 1 + } + printf '%s\n' "$snapshot" +} + +kpanel_disk_management_restore_fstab() { + local fstab="$1" snapshot="$2" directory temporary mode owner recovery + recovery="$(kpanel_disk_management_prepare_state_subdir recovery)" || return 1 + kpanel_disk_management_fstab_backup_valid "$snapshot" "$recovery" || return 1 + mode="$(<"$snapshot/mode")" || return 1 + owner="$(<"$snapshot/owner")" || return 1 + [[ "$mode" =~ ^[0-7]{3,4}$ ]] && [[ "$owner" =~ ^[0-9]+:[0-9]+$ ]] || return 1 + directory="$(dirname -- "$fstab")" || return 1 + temporary="$(mktemp "$directory/.fstab.kpanel-restore.XXXXXX")" || return 1 + cp -- "$snapshot/fstab" "$temporary" >/dev/null 2>&1 && + chown "$owner" "$temporary" >/dev/null 2>&1 && chmod "$mode" "$temporary" >/dev/null 2>&1 && + findmnt --verify --tab-file "$temporary" >&2 && sync -f "$temporary" >/dev/null 2>&1 && + mv -f -- "$temporary" "$fstab" >/dev/null 2>&1 && sync -f "$fstab" >/dev/null 2>&1 && + sync -f "$directory" >/dev/null 2>&1 || { + rm -f -- "$temporary" >/dev/null 2>&1 + return 1 + } + findmnt --verify --tab-file "$fstab" >&2 +} + +kpanel_disk_management_fstab_transaction() { + local operation="$1" source="$2" mountpoint="$3" fstype="$4" + local fstab directory escaped_target desired="" pass_number=0 analysis exact desired_count conflict extra temporary backup uid mode + KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED=false + KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP="" + KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED=false + case "$operation" in ensure|remove) ;; *) return 1 ;; esac + [[ "$source" =~ ^(UUID|PARTUUID)=[A-Za-z0-9._:+-]+$ ]] || return 1 + if [ "$operation" = ensure ]; then + [[ "$fstype" =~ ^[A-Za-z0-9._+-]+$ ]] || return 1 + fi + fstab="$(kpanel_disk_management_fstab_file)" || return 1 + [ -f "$fstab" ] && [ ! -L "$fstab" ] || return 1 + kpanel_system_resource_path_has_no_symlink "$fstab" || return 1 + kpanel_system_resource_file_within_bounds "$fstab" 1048576 16384 || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$fstab")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$fstab")" || return 1 + [ "$uid" = "$(kpanel_disk_management_path_owner_uid)" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && + [ "$((8#$mode & 0022))" -eq 0 ] || return 1 + directory="$(dirname -- "$fstab")" || return 1 + [ -d "$directory" ] && [ ! -L "$directory" ] || return 1 + escaped_target="$(kpanel_disk_management_fstab_escape "$mountpoint")" || return 1 + case "$fstype" in ext2|ext3|ext4) pass_number=2 ;; esac + desired="$source $escaped_target $fstype defaults,nofail 0 $pass_number" + analysis="$(awk -v source="$source" -v target="$escaped_target" -v desired="$desired" -v operation="$operation" ' + BEGIN { exact=0; desired_count=0; conflict=0 } + { + active=($0 !~ /^[[:space:]]*#/ && $0 !~ /^[[:space:]]*$/) + if (active && NF >= 2) { + if ($1 == source && $2 == target) { + exact++ + if ($0 == desired) desired_count++ + } else if ($2 == target || (operation == "ensure" && $1 == source)) { + conflict=1 + } + } + } + END { printf "%d %d %d\n", exact, desired_count, conflict } + ' "$fstab" 2>/dev/null)" || return 1 + read -r exact desired_count conflict extra <<< "$analysis" + [ -z "$extra" ] && [[ "$exact" =~ ^[0-9]+$ ]] && [[ "$desired_count" =~ ^[0-9]+$ ]] && + [[ "$conflict" =~ ^[01]$ ]] || return 1 + [ "$conflict" -eq 0 ] || return 2 + findmnt --verify --tab-file "$fstab" >&2 || return 1 + kpanel_disk_management_prune_fstab_backups 16 || return 1 + if [ "$operation" = ensure ] && [ "$exact" -eq 1 ] && [ "$desired_count" -eq 1 ]; then + return 0 + fi + if [ "$operation" = remove ] && [ "$exact" -eq 0 ]; then + return 0 + fi + temporary="$(mktemp "$directory/.fstab.kpanel.XXXXXX")" || return 1 + awk -v source="$source" -v target="$escaped_target" ' + { + active=($0 !~ /^[[:space:]]*#/ && $0 !~ /^[[:space:]]*$/) + if (active && NF >= 2 && $1 == source && $2 == target) next + print + } + ' "$fstab" > "$temporary" || { rm -f -- "$temporary"; return 1; } + if [ "$operation" = ensure ]; then + printf '%s\n' "$desired" >> "$temporary" || { rm -f -- "$temporary"; return 1; } + fi + kpanel_system_resource_copy_identity "$fstab" "$temporary" || { rm -f -- "$temporary"; return 1; } + findmnt --verify --tab-file "$temporary" >&2 || { rm -f -- "$temporary"; return 1; } + backup="$(kpanel_disk_management_create_fstab_backup "$fstab")" || { rm -f -- "$temporary"; return 1; } + KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP="$backup" + if ! sync -f "$temporary" >/dev/null 2>&1 || + ! mv -f -- "$temporary" "$fstab" >/dev/null 2>&1 || + ! sync -f "$fstab" >/dev/null 2>&1 || + ! sync -f "$directory" >/dev/null 2>&1 || + ! findmnt --verify --tab-file "$fstab" >&2; then + rm -f -- "$temporary" >/dev/null 2>&1 + if ! kpanel_disk_management_restore_fstab "$fstab" "$backup"; then + KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED=true + fi + return 1 + fi + KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED=true +} + +kpanel_disk_management_mountpoint_marker_path() { + local mountpoint="$1" directory digest + directory="$(kpanel_disk_management_prepare_state_subdir mountpoints)" || return 1 + digest="$(printf '%s' "$mountpoint" | sha256sum 2>/dev/null | awk '{print $1}')" || return 1 + [[ "$digest" =~ ^[0-9a-f]{64}$ ]] || return 1 + printf '%s/%s.mountpoint\n' "$directory" "$digest" +} + +kpanel_disk_management_marker_valid() { + local marker="$1" device_id="$2" mountpoint_hex="$3" uid mode links + [ -f "$marker" ] && [ ! -L "$marker" ] || return 1 + uid="$(kpanel_disk_management_path_stat_uid "$marker")" || return 1 + mode="$(kpanel_disk_management_path_stat_mode "$marker")" || return 1 + links="$(kpanel_disk_management_lock_stat_links "$marker")" || return 1 + [ "$uid" = "$(kpanel_disk_management_path_owner_uid)" ] && [[ "$mode" =~ ^[0-7]{3,4}$ ]] && + [[ "$links" =~ ^[0-9]+$ ]] && [ "$((8#$mode & 0777))" -eq 384 ] && [ "$links" -eq 1 ] || return 1 + kpanel_system_resource_file_within_bounds "$marker" 8192 8 || return 1 + grep -Fqx 'protocol=1' "$marker" && + grep -Fqx "device=$device_id" "$marker" && + grep -Fqx "mountpoint_hex=$mountpoint_hex" "$marker" +} + +kpanel_disk_management_record_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker directory temporary + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint")" || return 1 + directory="$(dirname -- "$marker")" || return 1 + [ ! -L "$marker" ] || return 1 + if [ -e "$marker" ]; then + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" + return $? + fi + temporary="$(mktemp "$directory/.mountpoint.XXXXXX")" || return 1 + printf 'protocol=1\ndevice=%s\nmountpoint_hex=%s\n' "$device_id" "$mountpoint_hex" > "$temporary" || { + rm -f -- "$temporary" + return 1 + } + chown 0:0 "$temporary" >/dev/null 2>&1 && chmod 600 "$temporary" >/dev/null 2>&1 && + sync -f "$temporary" >/dev/null 2>&1 && mv -f -- "$temporary" "$marker" >/dev/null 2>&1 && + sync -f "$directory" >/dev/null 2>&1 || { + rm -f -- "$temporary" + return 1 + } + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" +} + +kpanel_disk_management_forget_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker directory content + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint" 2>/dev/null)" || return 0 + kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex" || return 0 + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] || return 0 + content="$(find "$mountpoint" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || return 0 + [ -z "$content" ] || return 0 + rmdir -- "$mountpoint" >/dev/null 2>&1 || return 0 + directory="$(dirname -- "$marker")" || return 0 + rm -f -- "$marker" >/dev/null 2>&1 || return 0 + sync -f "$directory" >/dev/null 2>&1 || true +} + +kpanel_disk_management_cleanup_new_mountpoint() { + local device_id="$1" mountpoint="$2" mountpoint_hex="$3" marker + marker="$(kpanel_disk_management_mountpoint_marker_path "$mountpoint" 2>/dev/null || true)" + if [ -n "$marker" ] && kpanel_disk_management_marker_valid "$marker" "$device_id" "$mountpoint_hex"; then + rm -f -- "$marker" >/dev/null 2>&1 || true + fi + [ -d "$mountpoint" ] && [ ! -L "$mountpoint" ] && rmdir -- "$mountpoint" >/dev/null 2>&1 || true +} + +kpanel_disk_management_prepare_device() { + local device_id="$1" rc + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="" + kpanel_disk_management_resolve_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法按 MAJ:MIN 唯一解析安全块设备" + return 1 + fi + kpanel_disk_management_validate_device_common + rc=$? + case "$rc" in + 0) return 0 ;; + 3) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="设备为只读设备或 Swap,拒绝操作" + return 3 + ;; + *) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法可靠读取设备属性" + return 1 + ;; + esac +} + +kpanel_disk_management_require_safe_leaf() { + local rc + kpanel_disk_management_require_leaf_unmounted + rc=$? + case "$rc" in + 0) return 0 ;; + 3) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="设备已挂载、存在子设备或仍被 holder 使用" + return 3 + ;; + *) + KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE="无法可靠确认设备拓扑或挂载状态" + return 1 + ;; + esac +} + +kpanel_disk_management_rollback_live_mount() { + local device_id="$1" mountpoint="$2" created="$3" mountpoint_hex="$4" target rc + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + if [ "$rc" -eq 0 ]; then + [ "$target" = "$device_id" ] || return 1 + umount -- "$mountpoint" >&2 || return 1 + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + [ "$rc" -eq 1 ] || return 1 + elif [ "$rc" -ne 1 ]; then + return 1 + fi + if [ "$created" = true ]; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$mountpoint" "$mountpoint_hex" + fi +} + +kpanel_disk_management_restore_live_mount() { + local device_id="$1" device_path="$2" mountpoint="$3" target rc + mount --source "$device_path" --target "$mountpoint" >&2 || return 1 + target="$(kpanel_disk_management_target_device "$mountpoint")" + rc=$? + [ "$rc" -eq 0 ] && [ "$target" = "$device_id" ] +} + +kpanel_disk_management_mount_action() { + local device_id="$1" mountpoint_hex="$2" persist="$3" + local rc target mounted_rc content parent created=false source_rc fstab_rc backup="" + if ! kpanel_disk_management_decode_mountpoint "$mountpoint_hex"; then + kpanel_disk_management_reply failed "$device_id" "挂载点编码、规范路径或保护路径校验失败" "" 2 + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" true; then + kpanel_disk_management_reply needs-attention "$device_id" "挂载点路径包含符号链接、非 root 目录或可被非 root 写入" "" 3 + return $? + fi + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + [ -n "$KPANEL_DISK_MANAGEMENT_FSTYPE" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "设备没有可挂载的已知文件系统" "" 3 + return $? + } + case "$KPANEL_DISK_MANAGEMENT_FSTYPE" in + swap|LVM2_member|linux_raid_member|crypto_LUKS|zfs_member) + kpanel_disk_management_reply needs-attention "$device_id" "设备签名不是可直接挂载的文件系统" "" 3 + return $? + ;; + esac + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -eq 0 ]; then + [ "$target" = "$device_id" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "目标已被其他设备占用" "" 3 + return $? + } + if [ "$persist" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法安全持久化" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + kpanel_disk_management_fstab_transaction ensure "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "fstab 更新失败且配置回滚失败,需要人工恢复" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在设备或挂载点冲突" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "fstab 持久化失败,原有实时挂载保持不变" "$backup" 1 + fi + return $? + fi + if [ "$KPANEL_DISK_MANAGEMENT_FSTAB_CHANGED" = true ]; then + kpanel_disk_management_reply applied "$device_id" "实时挂载未变化,持久化配置已应用" "$backup" 0 + else + kpanel_disk_management_reply unchanged "$device_id" "设备已经按目标挂载并持久化" "" 0 + fi + return $? + fi + kpanel_disk_management_reply unchanged "$device_id" "设备已经按目标挂载" "" 0 + return $? + elif [ "$rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取目标挂载状态" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" true; then + kpanel_disk_management_reply needs-attention "$device_id" "未挂载目标不是 root 独占的安全目录路径" "" 3 + return $? + fi + kpanel_disk_management_device_is_mounted "$device_id" + mounted_rc=$? + if [ "$mounted_rc" -eq 0 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备已挂载在其他目标,拒绝重复挂载" "" 3 + return $? + elif [ "$mounted_rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取设备挂载状态" "" 1 + return $? + fi + if [ -e "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] || [ -L "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ]; then + [ -d "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] && [ ! -L "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "目标不是安全的真实目录" "" 3 + return $? + } + else + parent="$(dirname -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" || { + kpanel_disk_management_reply failed "$device_id" "无法解析挂载点父目录" "" 1 + return $? + } + [ -d "$parent" ] && [ ! -L "$parent" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "挂载点父目录不存在或不安全" "" 3 + return $? + } + if ! (umask 077; mkdir -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT") >/dev/null 2>&1; then + kpanel_disk_management_reply failed "$device_id" "创建挂载点失败" "" 1 + return $? + fi + created=true + if ! chown 0:0 "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >/dev/null 2>&1 || + ! chmod 700 "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >/dev/null 2>&1; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法设置新挂载点安全属性" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "新挂载点安全属性复核失败" "" 1 + return $? + fi + if ! kpanel_disk_management_record_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法记录 KPanel 创建的挂载点" "" 1 + return $? + fi + fi + content="$(find "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" || { + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply failed "$device_id" "无法安全检查挂载点内容" "" 1 + return $? + } + if [ -n "$content" ]; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply needs-attention "$device_id" "挂载点非空,拒绝覆盖现有内容" "" 3 + return $? + fi + if [ "$persist" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法安全持久化" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + [ "$created" = true ] && kpanel_disk_management_cleanup_new_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + kpanel_disk_management_reply needs-attention "$device_id" "挂载前安全复核失败" "" 3 + return $? + fi + if ! mount --source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" --target "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >&2; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载命令失败,未保留部分状态" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载命令失败且无法确认或清理部分挂载" "" 4 + fi + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载后安全属性复核失败,已回滚" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载后安全属性复核失败且回滚失败" "" 4 + fi + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -ne 0 ] || [ "$target" != "$device_id" ]; then + if kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX"; then + kpanel_disk_management_reply failed "$device_id" "挂载完成态回读失败,已回滚" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "挂载完成态回读失败且回滚失败" "" 4 + fi + return $? + fi + if [ "$persist" = 1 ]; then + kpanel_disk_management_fstab_transaction ensure "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if ! kpanel_disk_management_rollback_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$created" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" || + [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "fstab 持久化失败且回滚未完整完成" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在冲突,实时挂载已回滚" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "fstab 持久化失败,实时挂载已回滚" "$backup" 1 + fi + return $? + fi + fi + backup="${KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP:-}" + kpanel_disk_management_reply applied "$device_id" "设备已挂载并完成状态回读" "$backup" 0 +} + +kpanel_disk_management_unmount_action() { + local device_id="$1" mountpoint_hex="$2" remove_persistence="$3" + local rc target mounted_rc source_rc fstab_rc backup="" + if ! kpanel_disk_management_decode_mountpoint "$mountpoint_hex"; then + kpanel_disk_management_reply failed "$device_id" "挂载点编码、规范路径或保护路径校验失败" "" 2 + return $? + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_reply needs-attention "$device_id" "卸载目标路径包含符号链接、非 root 目录或可被非 root 写入" "" 3 + return $? + fi + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -eq 1 ]; then + kpanel_disk_management_device_is_mounted "$device_id" + mounted_rc=$? + if [ "$mounted_rc" -eq 0 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备挂载在其他目标,拒绝卸载" "" 3 + elif [ "$mounted_rc" -eq 1 ]; then + kpanel_disk_management_reply unchanged "$device_id" "设备未挂载在指定目标" "" 0 + else + kpanel_disk_management_reply failed "$device_id" "无法可靠读取设备挂载状态" "" 1 + fi + return $? + elif [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "$device_id" "无法可靠读取目标挂载状态" "" 1 + return $? + fi + [ "$target" = "$device_id" ] || { + kpanel_disk_management_reply needs-attention "$device_id" "指定目标由其他设备占用" "" 3 + return $? + } + if [ "$remove_persistence" = 1 ]; then + kpanel_disk_management_persistence_source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" + source_rc=$? + if [ "$source_rc" -ne 0 ]; then + if [ "$source_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "设备缺少 UUID/PARTUUID,无法精确移除持久化记录" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "无法读取设备持久化标识" "" 1 + fi + return $? + fi + fi + if ! kpanel_disk_management_mountpoint_parent_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + kpanel_disk_management_reply needs-attention "$device_id" "卸载前安全复核失败" "" 3 + return $? + fi + if ! umount -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" >&2; then + kpanel_disk_management_reply needs-attention "$device_id" "普通卸载失败,设备可能正被使用" "" 3 + return $? + fi + target="$(kpanel_disk_management_target_device "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT")" + rc=$? + if [ "$rc" -ne 1 ]; then + kpanel_disk_management_reply failed "$device_id" "卸载完成态回读失败" "" 1 + return $? + fi + if ! kpanel_disk_management_mountpoint_path_secure "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" false; then + if kpanel_disk_management_restore_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT"; then + kpanel_disk_management_reply failed "$device_id" "卸载后安全属性复核失败,实时挂载已恢复" "" 1 + else + kpanel_disk_management_reply rollback-failed "$device_id" "卸载后安全属性复核失败且实时挂载恢复失败" "" 4 + fi + return $? + fi + if [ "$remove_persistence" = 1 ]; then + kpanel_disk_management_fstab_transaction remove "$KPANEL_DISK_MANAGEMENT_PERSISTENCE_SOURCE" \ + "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_FSTYPE" + fstab_rc=$? + backup="$KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP" + if [ "$fstab_rc" -ne 0 ]; then + if ! kpanel_disk_management_restore_live_mount "$device_id" "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" || + [ "$KPANEL_DISK_MANAGEMENT_FSTAB_ROLLBACK_FAILED" = true ]; then + kpanel_disk_management_reply rollback-failed "$device_id" "持久化移除失败且实时挂载回滚失败" "$backup" 4 + elif [ "$fstab_rc" -eq 2 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "fstab 存在冲突,实时挂载已恢复" "$backup" 3 + else + kpanel_disk_management_reply failed "$device_id" "持久化移除失败,实时挂载已恢复" "$backup" 1 + fi + return $? + fi + fi + kpanel_disk_management_forget_mountpoint "$device_id" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT" "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT_HEX" + backup="${KPANEL_DISK_MANAGEMENT_FSTAB_BACKUP:-}" + kpanel_disk_management_reply applied "$device_id" "设备已从指定目标卸载" "$backup" 0 +} + +kpanel_disk_management_format_action() { + local device_id="$1" requested_fstype="$2" command_name rc actual + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + kpanel_disk_management_require_safe_leaf + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + case "$requested_fstype" in + ext4) command_name=mkfs.ext4 ;; + xfs) command_name=mkfs.xfs ;; + ntfs) + if kpanel_disk_management_command_available mkfs.ntfs; then + command_name=mkfs.ntfs + elif kpanel_disk_management_command_available mkntfs; then + command_name=mkntfs + else + command_name="" + fi + ;; + vfat) + if kpanel_disk_management_command_available mkfs.vfat; then + command_name=mkfs.vfat + elif kpanel_disk_management_command_available mkfs.fat; then + command_name=mkfs.fat + else + command_name="" + fi + ;; + esac + if [ -z "$command_name" ] || ! kpanel_disk_management_command_available "$command_name"; then + kpanel_disk_management_reply needs-attention "$device_id" "缺少所选文件系统的格式化工具" "" 3 + return $? + fi + case "$requested_fstype" in + ext4) mkfs.ext4 -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs) mkfs.xfs -f "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs) + case "$command_name" in + mkfs.ntfs) mkfs.ntfs -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + mkntfs) mkntfs -F "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + vfat) + case "$command_name" in + mkfs.vfat) mkfs.vfat "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + mkfs.fat) mkfs.fat "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + esac + rc=$? + if [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "$device_id" "格式化命令失败,未声明可回滚" "" 1 + return $? + fi + command -v udevadm >/dev/null 2>&1 && udevadm settle >&2 || true + actual="$(kpanel_disk_management_probe_fstype "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH")" || { + kpanel_disk_management_reply failed "$device_id" "格式化后无法重读文件系统类型" "" 1 + return $? + } + [ "$actual" = "$requested_fstype" ] || { + kpanel_disk_management_reply failed "$device_id" "格式化后文件系统类型回读不一致" "" 1 + return $? + } + kpanel_disk_management_reply applied "$device_id" "格式化已完成并通过文件系统类型回读" "" 0 +} + +kpanel_disk_management_check_action() { + local device_id="$1" mode="$2" fstype command_name rc + kpanel_disk_management_prepare_device "$device_id" + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + kpanel_disk_management_require_safe_leaf + rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 3 ]; then + kpanel_disk_management_reply needs-attention "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 3 + else + kpanel_disk_management_reply failed "$device_id" "$KPANEL_DISK_MANAGEMENT_PREPARE_MESSAGE" "" 1 + fi + return $? + fi + fstype="$(kpanel_disk_management_probe_fstype "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH")" || { + kpanel_disk_management_reply needs-attention "$device_id" "无法识别可检查的文件系统" "" 3 + return $? + } + case "$fstype" in + ext4) command_name=e2fsck ;; + xfs) command_name=xfs_repair ;; + ntfs) command_name=ntfsfix ;; + vfat) + if kpanel_disk_management_command_available fsck.vfat; then + command_name=fsck.vfat + elif kpanel_disk_management_command_available fsck.fat; then + command_name=fsck.fat + else + command_name="" + fi + ;; + *) + kpanel_disk_management_reply needs-attention "$device_id" "当前文件系统不在 v1 检查支持范围" "" 3 + return $? + ;; + esac + if [ -z "$command_name" ] || ! kpanel_disk_management_command_available "$command_name"; then + kpanel_disk_management_reply needs-attention "$device_id" "缺少当前文件系统的检查工具" "" 3 + return $? + fi + case "$fstype:$mode" in + ext4:readonly) e2fsck -fn "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ext4:repair) e2fsck -fy "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs:readonly) xfs_repair -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + xfs:repair) xfs_repair "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs:readonly) ntfsfix -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + ntfs:repair) ntfsfix "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + vfat:readonly) + case "$command_name" in + fsck.vfat) fsck.vfat -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + fsck.fat) fsck.fat -n "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + vfat:repair) + case "$command_name" in + fsck.vfat) fsck.vfat -a "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + fsck.fat) fsck.fat -a "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" >&2 ;; + esac + ;; + esac + rc=$? + if [ "$mode" = readonly ]; then + if [ "$rc" -eq 0 ]; then + kpanel_disk_management_reply unchanged "$device_id" "只读文件系统检查完成,未执行修复" "" 0 + else + kpanel_disk_management_reply needs-attention "$device_id" "只读检查发现问题或检查工具未能完整执行" "" 3 + fi + return $? + fi + case "$fstype:$rc" in + ext4:0|ext4:1|ext4:2|ext4:3|vfat:0|vfat:1|xfs:0|ntfs:0) + kpanel_disk_management_reply applied "$device_id" "文件系统修复命令已成功完成" "" 0 + ;; + *) + kpanel_disk_management_reply failed "$device_id" "文件系统修复命令失败" "" 1 + ;; + esac +} + +kpanel_disk_management_run_locked() ( + local action="$1" + shift + case "$action" in + mount) kpanel_disk_management_mount_action "$@" ;; + unmount) kpanel_disk_management_unmount_action "$@" ;; + format) kpanel_disk_management_format_action "$@" ;; + check) kpanel_disk_management_check_action "$@" ;; + *) kpanel_disk_management_reply failed "" "不支持的 disk-management 动作" "" 2 ;; + esac +) + +kpanel_disk_management_dispatch() { + local action="${1:-}" device_id="" lock_file rc + shift || true + [[ "${1:-}" =~ ^[0-9]+:[0-9]+$ ]] && device_id="$1" + printf 'KPANEL_DISK_MANAGEMENT_PROTOCOL %s\n' "$KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION" + kpanel_disk_management_require_platform + rc=$? + if [ "$rc" -ne 0 ]; then + kpanel_disk_management_reply failed "" "$KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE" "" "$rc" + return $? + fi + case "$action" in + mount|unmount) + [ "$#" -eq 3 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && + [[ "$2" =~ ^[0-9a-fA-F]+$ ]] && [ "$(( ${#2} % 2 ))" -eq 0 ] && + [[ "$3" =~ ^[01]$ ]] || { + kpanel_disk_management_reply failed "$device_id" "mount/unmount 参数无效" "" 2 + return $? + } + ;; + format) + [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && [[ "$2" =~ ^(ext4|xfs|ntfs|vfat)$ ]] || { + kpanel_disk_management_reply failed "$device_id" "format 参数无效" "" 2 + return $? + } + ;; + check) + [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+:[0-9]+$ ]] && [[ "$2" =~ ^(readonly|repair)$ ]] || { + kpanel_disk_management_reply failed "$device_id" "check 参数无效" "" 2 + return $? + } + ;; + *) + kpanel_disk_management_reply failed "$device_id" "用法: k kpanel disk-management ..." "" 2 + return $? + ;; + esac + lock_file="$(kpanel_disk_management_prepare_lock_file)" || { + kpanel_disk_management_reply failed "$device_id" "disk-management 锁路径不安全或无法创建" "" 1 + return $? + } + exec 9<>"$lock_file" || { + kpanel_disk_management_reply failed "$device_id" "无法打开 disk-management 锁" "" 1 + return $? + } + kpanel_disk_management_lock_file_secure "$lock_file" || { + exec 9>&- + kpanel_disk_management_reply failed "$device_id" "disk-management 锁文件打开后验证失败" "" 1 + return $? + } + if ! flock -w 5 -x 9 >/dev/null 2>&1; then + exec 9>&- + kpanel_disk_management_reply conflict "$device_id" "disk-management 写锁等待超时" "" 2 + return $? + fi + kpanel_disk_management_run_locked "$action" "$@" +} + +# KPanel disk management protocol end + + # KPanel network operations protocol start KPANEL_NETWORK_OPERATIONS_PROTOCOL_VERSION="1" @@ -28433,6 +29792,9 @@ else elif [ "${1:-}" = "system-resource" ]; then shift kpanel_system_resource_dispatch "$@" + elif [ "${1:-}" = "disk-management" ]; then + shift + kpanel_disk_management_dispatch "$@" elif [ "${1:-}" = "network-operations" ]; then shift kpanel_network_operations_dispatch "$@" @@ -28443,7 +29805,7 @@ else shift kpanel_system_tuning_dispatch "$@" else - echo "用法: k kpanel node ... | system-resource ... | network-operations ... | account-management ... | system-tuning ..." >&2 + echo "用法: k kpanel node ... | system-resource ... | disk-management ... | network-operations ... | account-management ... | system-tuning ..." >&2 return 2 2>/dev/null || exit 2 fi ;; diff --git a/tests/test_kpanel_disk_management_noninteractive_smoke.sh b/tests/test_kpanel_disk_management_noninteractive_smoke.sh new file mode 100644 index 000000000..95510c875 --- /dev/null +++ b/tests/test_kpanel_disk_management_noninteractive_smoke.sh @@ -0,0 +1,550 @@ +#!/bin/bash +set -euo pipefail + +project_root="${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +script_path="${project_root}/kejilion.sh" +cn_script_path="${project_root}/cn/kejilion.sh" +test_root="$(mktemp -d)" +mock_bin="${test_root}/bin" +test_stderr="${test_root}/stderr" +test_stdout="${test_root}/stdout" +mock_log="${test_root}/commands.log" +mock_mounts="${test_root}/mounts" +mock_fstype="${test_root}/fstype" +mock_fstab="${test_root}/fstab" +mock_swaps="${test_root}/swaps" +mock_holders="${test_root}/holders" +mock_state="${test_root}/state" +mock_lock_parent="${test_root}/run-lock" +mock_lock="${mock_lock_parent}/kejilion-kpanel-disk.lock" +mock_verify_log="${test_root}/verify.log" +mock_verify_fail_postwrite="${test_root}/verify-fail-postwrite" +trap 'rm -rf -- "${test_root}"' EXIT + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + if [ -s "${test_stderr}" ]; then + printf '%s\n' '--- adapter stderr ---' >&2 + command cat -- "${test_stderr}" >&2 + fi + exit 1 +} + +assert_file_line() { + local expected="$1" file="$2" + expected="${expected//\\t/$'\t'}" + grep -Fqx -- "${expected}" "${file}" || fail "missing exact command: ${expected}" +} + +grep -F '[ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" = "1" ] ||' "${script_path}" >/dev/null +grep -F 'KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION="1"' "${script_path}" >/dev/null +grep -F 'kpanel_disk_management_dispatch "$@"' "${script_path}" >/dev/null +grep -F 'printf '\''%s\n'\'' "/run/lock/kejilion-kpanel-disk.lock"' "${script_path}" >/dev/null +grep -F 'flock -w 5 -x 9' "${script_path}" >/dev/null +grep -F 'kpanel_system_resource_path_has_no_symlink "$mountpoint"' "${script_path}" >/dev/null +grep -F '[ "${#encoded}" -le 8192 ]' "${script_path}" >/dev/null +grep -F 'kpanel_disk_management_prune_fstab_backups 15' "${script_path}" >/dev/null +grep -F 'mount --source "$KPANEL_DISK_MANAGEMENT_DEVICE_PATH" --target "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT"' "${script_path}" >/dev/null +grep -F 'umount -- "$KPANEL_DISK_MANAGEMENT_MOUNTPOINT"' "${script_path}" >/dev/null +if grep -E 'umount[[:space:]]+(-f|-l|--force|--lazy)' "${script_path}" >/dev/null; then + fail "disk-management must not force or lazy unmount" +fi + +system_body="$( + sed -n '/^# KPanel system resource protocol start/,/^# KPanel system resource protocol end/p' "${script_path}" | + sed 's/\r$//' +)" +disk_body="$( + sed -n '/^# KPanel disk management protocol start/,/^# KPanel disk management protocol end/p' "${script_path}" | + sed 's/\r$//' +)" +cn_disk_body="$( + sed -n '/^# KPanel disk management protocol start/,/^# KPanel disk management protocol end/p' "${cn_script_path}" | + sed 's/\r$//' +)" +[ -n "${system_body}" ] || fail "system-resource dependency block was not found" +[ -n "${disk_body}" ] || fail "disk-management adapter block was not found" +[ "$(grep -Fxc 'KPANEL_DISK_MANAGEMENT_PROTOCOL_VERSION="1"' <<< "${disk_body}")" -eq 1 ] || + fail "disk-management protocol marker must be unique" +[ "${disk_body}" = "${cn_disk_body}" ] || fail "root and cn disk-management blocks differ" +if grep -F 'rm -rf' <<< "${disk_body}" >/dev/null; then + fail "disk-management backup cleanup must not use broad recursive removal" +fi + +normalized_script="${test_root}/kejilion.normalized.sh" +sed 's/\r$//' "${script_path}" > "${normalized_script}" +set +e +KJ_DISK_MANAGEMENT_NONINTERACTIVE=1 bash "${normalized_script}" kpanel disk-management unknown \ + >"${test_stdout}" 2>"${test_stderr}" +entry_rc=$? +set -e +[ "${entry_rc}" -ne 0 ] || fail "unknown entry action unexpectedly succeeded" +mapfile -t entry_lines < "${test_stdout}" +[ "${#entry_lines[@]}" -eq 5 ] || fail "entry must emit exactly five receipt lines" +[ "${entry_lines[0]}" = 'KPANEL_DISK_MANAGEMENT_PROTOCOL 1' ] || fail "entry protocol header mismatch" +[ "${entry_lines[1]}" = 'KPANEL_DISK_MANAGEMENT_STATUS=failed' ] || fail "entry failure status mismatch" +[[ "${entry_lines[2]}" =~ ^KPANEL_DISK_MANAGEMENT_DEVICE=([0-9]+:[0-9]+)?$ ]] || fail "entry device field mismatch" +[[ "${entry_lines[3]}" =~ ^KPANEL_DISK_MANAGEMENT_MESSAGE_HEX=[0-9a-f]+$ ]] || fail "entry message field mismatch" +[ "${entry_lines[4]}" = 'KPANEL_DISK_MANAGEMENT_BACKUP_HEX=' ] || fail "entry backup field mismatch" + +eval "${system_body}" +eval "${disk_body}" + +mkdir -p -- "${mock_bin}" "${mock_holders}" "${mock_lock_parent}" +chmod 700 "${mock_lock_parent}" +printf 'Filename\tType\tSize\tUsed\tPriority\n' > "${mock_swaps}" + +cat > "${mock_bin}/lsblk" <<'MOCK_LSBLK' +#!/bin/bash +set -u +if [ "${MOCK_LSBLK_MODE:-}" = fail ]; then + exit 71 +fi +if [ "$#" -eq 5 ] && [ "$1" = --noheadings ] && [ "$2" = --raw ] && [ "$3" = --paths ] && + [ "$4" = --output ] && [ "$5" = MAJ:MIN,PATH ]; then + case "${MOCK_LSBLK_MODE:-normal}" in + normal) printf '8:1 /dev/kpanel-test-disk\n' ;; + duplicate) printf '8:1 /dev/kpanel-test-disk\n8:1 /dev/kpanel-test-disk-alias\n' ;; + malformed) printf 'unexpected output\n' ;; + *) exit 72 ;; + esac + exit 0 +fi +if [ "$#" -eq 7 ] && [ "$1" = --nodeps ] && [ "$2" = --noheadings ] && [ "$3" = --raw ] && + [ "$4" = --output ] && [ "$6" = -- ] && [ "$7" = /dev/kpanel-test-disk ]; then + case "$5" in + MAJ:MIN) printf '8:1\n' ;; + TYPE) printf 'part\n' ;; + RO) printf '%s\n' "${MOCK_DEVICE_RO:-0}" ;; + FSTYPE) command cat -- "${MOCK_FSTYPE}" ;; + *) exit 73 ;; + esac + exit 0 +fi +if [ "$#" -eq 6 ] && [ "$1" = --noheadings ] && [ "$2" = --raw ] && + [ "$3" = --output ] && [ "$4" = MAJ:MIN ] && [ "$5" = -- ] && [ "$6" = /dev/kpanel-test-disk ]; then + printf '8:1\n' + [ "${MOCK_LSBLK_CHILD:-0}" != 1 ] || printf '8:2\n' + exit 0 +fi +printf 'unexpected lsblk argv: %s\n' "$*" >&2 +exit 74 +MOCK_LSBLK + +cat > "${mock_bin}/findmnt" <<'MOCK_FINDMNT' +#!/bin/bash +set -u +if [ "$#" -eq 5 ] && [ "$1" = --kernel ] && [ "$2" = --raw ] && [ "$3" = --noheadings ] && + [ "$4" = --output ] && [ "$5" = MAJ:MIN ]; then + [ "${MOCK_FINDMNT_READ_FAIL:-0}" != 1 ] || exit 75 + awk -F '\t' 'NF >= 2 {print $1}' "${MOCK_MOUNTS}" + exit 0 +fi +if [ "$#" -eq 7 ] && [ "$1" = --kernel ] && [ "$2" = --raw ] && [ "$3" = --noheadings ] && + [ "$4" = --output ] && [ "$5" = MAJ:MIN ] && [ "$6" = --mountpoint ]; then + [ "${MOCK_FINDMNT_READ_FAIL:-0}" != 1 ] || exit 75 + value="$(awk -F '\t' -v target="$7" '$2 == target {print $1}' "${MOCK_MOUNTS}")" + [ -n "${value}" ] || exit 1 + printf '%s\n' "${value}" + exit 0 +fi +if [ "$#" -eq 3 ] && [ "$1" = --verify ] && [ "$2" = --tab-file ]; then + printf 'verify\t%s\n' "$3" >> "${MOCK_VERIFY_LOG}" + count="$(wc -l < "${MOCK_VERIFY_LOG}" | tr -d '[:space:]')" + if [ -e "${MOCK_VERIFY_FAIL_POSTWRITE}" ] && [ "${count}" -eq 3 ]; then + printf 'mock fstab verification failure\n' >&2 + exit 76 + fi + [ -f "$3" ] || exit 77 + exit 0 +fi +printf 'unexpected findmnt argv: %s\n' "$*" >&2 +exit 78 +MOCK_FINDMNT + +cat > "${mock_bin}/blkid" <<'MOCK_BLKID' +#!/bin/bash +set -u +case "$*" in + '-p -c /dev/null -s TYPE -o value /dev/kpanel-test-disk') + command cat -- "${MOCK_FSTYPE}" + ;; + '-c /dev/null -s UUID -o value /dev/kpanel-test-disk') + case "${MOCK_BLKID_MODE:-normal}" in + normal) printf 'kpanel-test-uuid\n' ;; + no-uuid|no-id) exit 2 ;; + *) exit 79 ;; + esac + ;; + '-c /dev/null -s PARTUUID -o value /dev/kpanel-test-disk') + case "${MOCK_BLKID_MODE:-normal}" in + no-uuid) printf 'kpanel-test-partuuid\n' ;; + no-id) exit 2 ;; + normal) printf 'kpanel-test-partuuid\n' ;; + *) exit 79 ;; + esac + ;; + *) printf 'unexpected blkid argv: %s\n' "$*" >&2; exit 80 ;; +esac +MOCK_BLKID + +cat > "${mock_bin}/mount" <<'MOCK_MOUNT' +#!/bin/bash +set -u +printf 'mount' >> "${MOCK_LOG}" +printf '\t%s' "$@" >> "${MOCK_LOG}" +printf '\n' >> "${MOCK_LOG}" +[ "$#" -eq 4 ] && [ "$1" = --source ] && [ "$2" = /dev/kpanel-test-disk ] && [ "$3" = --target ] || exit 81 +[ "${MOCK_FAIL_COMMAND:-}" != mount ] || exit 82 +printf '8:1\t%s\n' "$4" >> "${MOCK_MOUNTS}" +MOCK_MOUNT + +cat > "${mock_bin}/umount" <<'MOCK_UMOUNT' +#!/bin/bash +set -u +printf 'umount' >> "${MOCK_LOG}" +printf '\t%s' "$@" >> "${MOCK_LOG}" +printf '\n' >> "${MOCK_LOG}" +[ "$#" -eq 2 ] && [ "$1" = -- ] || exit 83 +[ "${MOCK_FAIL_COMMAND:-}" != umount ] || exit 84 +temporary="${MOCK_MOUNTS}.tmp" +awk -F '\t' -v target="$2" '$2 != target {print}' "${MOCK_MOUNTS}" > "${temporary}" || exit 85 +mv -f -- "${temporary}" "${MOCK_MOUNTS}" +MOCK_UMOUNT + +cat > "${mock_bin}/mock-mkfs" <<'MOCK_MKFS' +#!/bin/bash +set -u +name="${0##*/}" +printf '%s' "${name}" >> "${MOCK_LOG}" +printf '\t%s' "$@" >> "${MOCK_LOG}" +printf '\n' >> "${MOCK_LOG}" +[ "${MOCK_FAIL_COMMAND:-}" != "${name}" ] || exit 86 +case "${name}" in + mkfs.ext4) [ "$#" -eq 2 ] && [ "$1" = -F ] && [ "$2" = /dev/kpanel-test-disk ] && fstype=ext4 ;; + mkfs.xfs) [ "$#" -eq 2 ] && [ "$1" = -f ] && [ "$2" = /dev/kpanel-test-disk ] && fstype=xfs ;; + mkfs.ntfs) [ "$#" -eq 2 ] && [ "$1" = -F ] && [ "$2" = /dev/kpanel-test-disk ] && fstype=ntfs ;; + mkntfs) [ "$#" -eq 2 ] && [ "$1" = -F ] && [ "$2" = /dev/kpanel-test-disk ] && fstype=ntfs ;; + mkfs.vfat) [ "$#" -eq 1 ] && [ "$1" = /dev/kpanel-test-disk ] && fstype=vfat ;; + mkfs.fat) [ "$#" -eq 1 ] && [ "$1" = /dev/kpanel-test-disk ] && fstype=vfat ;; + *) exit 87 ;; +esac || exit 88 +printf '%s\n' "${fstype}" > "${MOCK_FSTYPE}" +MOCK_MKFS + +cat > "${mock_bin}/mock-check" <<'MOCK_CHECK' +#!/bin/bash +set -u +name="${0##*/}" +printf '%s' "${name}" >> "${MOCK_LOG}" +printf '\t%s' "$@" >> "${MOCK_LOG}" +printf '\n' >> "${MOCK_LOG}" +[ "${MOCK_FAIL_COMMAND:-}" != "${name}" ] || exit 89 +exit "${MOCK_CHECK_RC:-0}" +MOCK_CHECK + +cat > "${mock_bin}/flock" <<'MOCK_FLOCK' +#!/bin/bash +set -u +printf 'flock' >> "${MOCK_LOG}" +printf '\t%s' "$@" >> "${MOCK_LOG}" +printf '\n' >> "${MOCK_LOG}" +[ "$#" -eq 4 ] && [ "$1" = -w ] && [ "$2" = 5 ] && [ "$3" = -x ] && [ "$4" = 9 ] || exit 90 +[ "${MOCK_FLOCK_FAIL:-0}" != 1 ] +MOCK_FLOCK + +cat > "${mock_bin}/chown" <<'MOCK_CHOWN' +#!/bin/bash +# Ownership changes are deliberately virtualized inside the temporary test tree. +exit 0 +MOCK_CHOWN + +cat > "${mock_bin}/sync" <<'MOCK_SYNC' +#!/bin/bash +[ "${MOCK_FAIL_COMMAND:-}" != sync ] +MOCK_SYNC + +chmod +x "${mock_bin}"/* +for tool in mkfs.ext4 mkfs.xfs mkfs.ntfs mkntfs mkfs.vfat mkfs.fat; do + cp -- "${mock_bin}/mock-mkfs" "${mock_bin}/${tool}" +done +for tool in e2fsck xfs_repair ntfsfix fsck.vfat fsck.fat; do + cp -- "${mock_bin}/mock-check" "${mock_bin}/${tool}" +done +chmod +x "${mock_bin}"/* + +export PATH="${mock_bin}:${PATH}" +export MOCK_LOG="${mock_log}" MOCK_MOUNTS="${mock_mounts}" MOCK_FSTYPE="${mock_fstype}" +export MOCK_VERIFY_LOG="${mock_verify_log}" MOCK_VERIFY_FAIL_POSTWRITE="${mock_verify_fail_postwrite}" + +kpanel_disk_management_is_block_device() { [ "$1" = /dev/kpanel-test-disk ]; } +kpanel_disk_management_swaps_file() { printf '%s\n' "${mock_swaps}"; } +kpanel_disk_management_holders_dir() { printf '%s\n' "${mock_holders}"; } +kpanel_disk_management_fstab_file() { printf '%s\n' "${mock_fstab}"; } +kpanel_disk_management_state_root() { printf '%s\n' "${mock_state}"; } +kpanel_disk_management_lock_file() { printf '%s\n' "${mock_lock}"; } +kpanel_disk_management_lock_owner_uid() { id -u; } +kpanel_disk_management_require_platform() { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="" + [ "${KJ_DISK_MANAGEMENT_NONINTERACTIVE:-}" = 1 ] || { + KPANEL_DISK_MANAGEMENT_REQUIRE_MESSAGE="protocol environment is disabled" + return 2 + } + kpanel_disk_management_require_commands \ + awk basename blkid chmod chown cp date dirname find findmnt flock grep lsblk mkdir mktemp \ + mount mv readlink rm rmdir sha256sum stat sync umount uname wc +} + +kpanel_disk_management_path_owner_uid() { id -u; } +kpanel_disk_management_command_available() { + case " ${MOCK_MISSING_TOOLS:-} " in + *" $1 "*) return 1 ;; + esac + command -v "$1" >/dev/null 2>&1 +} +kpanel_disk_management_path_stat_uid() { + case "${test_root}" in + "$1"|"$1"/*) id -u; return 0 ;; + esac + command stat -c '%u' "$1" 2>/dev/null +} +kpanel_disk_management_path_stat_mode() { + if [ -n "${MOCK_UNSAFE_COMPONENT:-}" ] && [ "$1" = "${MOCK_UNSAFE_COMPONENT}" ]; then + printf '777\n' + return 0 + fi + case "${test_root}" in + "$1"/*) printf '755\n'; return 0 ;; + esac + command stat -c '%a' "$1" 2>/dev/null +} + +reset_case() { + : > "${mock_log}" + : > "${mock_verify_log}" + rm -f -- "${mock_verify_fail_postwrite}" + rm -rf -- "${mock_state}" + printf '0:1\t/\n' > "${mock_mounts}" + printf 'ext4\n' > "${mock_fstype}" + printf '# kpanel disk-management smoke\n' > "${mock_fstab}" + chmod 644 "${mock_fstab}" + unset MOCK_LSBLK_MODE MOCK_LSBLK_CHILD MOCK_DEVICE_RO MOCK_FINDMNT_READ_FAIL + unset MOCK_BLKID_MODE MOCK_FAIL_COMMAND MOCK_CHECK_RC MOCK_FLOCK_FAIL + unset MOCK_UNSAFE_COMPONENT MOCK_MISSING_TOOLS +} + +run_receipt() { + local expected_status="$1" expected_rc="$2" + shift 2 + set +e + ( + export KJ_DISK_MANAGEMENT_NONINTERACTIVE=1 + kpanel_disk_management_dispatch "$@" + ) > "${test_stdout}" 2> "${test_stderr}" + local actual_rc=$? + set -e + [ "${actual_rc}" -eq "${expected_rc}" ] || fail "unexpected rc ${actual_rc}, expected ${expected_rc}: $*" + mapfile -t receipt_lines < "${test_stdout}" + [ "${#receipt_lines[@]}" -eq 5 ] || fail "receipt must contain exactly five lines: $*" + [ "${receipt_lines[0]}" = 'KPANEL_DISK_MANAGEMENT_PROTOCOL 1' ] || fail "protocol header mismatch: $*" + [ "${receipt_lines[1]}" = "KPANEL_DISK_MANAGEMENT_STATUS=${expected_status}" ] || fail "status mismatch: $*" + [[ "${receipt_lines[2]}" =~ ^KPANEL_DISK_MANAGEMENT_DEVICE=([0-9]+:[0-9]+)?$ ]] || fail "device field mismatch: $*" + [[ "${receipt_lines[3]}" =~ ^KPANEL_DISK_MANAGEMENT_MESSAGE_HEX=[0-9a-f]+$ ]] || fail "message hex mismatch: $*" + [[ "${receipt_lines[4]}" =~ ^KPANEL_DISK_MANAGEMENT_BACKUP_HEX=[0-9a-f]*$ ]] || fail "backup hex mismatch: $*" +} + +mount_hex() { kpanel_disk_management_hex_encode "$1"; } + +reset_case +run_receipt failed 2 mount 8:1 zz 0 +[ "${receipt_lines[2]}" = 'KPANEL_DISK_MANAGEMENT_DEVICE=8:1' ] || fail "valid requested MAJ:MIN was omitted from rejection receipt" +[ ! -s "${mock_log}" ] || fail "invalid hex reached an external disk command" +run_receipt failed 2 format 8:1 ext3 +run_receipt failed 2 check broken readonly + +protected_hex="$(mount_hex /home/kpanel-test)" +run_receipt failed 2 mount 8:1 "${protected_hex}" 0 +if grep -q '^mount' "${mock_log}"; then fail "protected mountpoint reached mount"; fi + +reset_case +unsafe_parent="${test_root}/unsafe-parent" +mkdir -- "${unsafe_parent}" +export MOCK_UNSAFE_COMPONENT="${unsafe_parent}" +run_receipt needs-attention 3 mount 8:1 "$(mount_hex "${unsafe_parent}/target")" 0 +if grep -q '^mount' "${mock_log}"; then fail "group/world-writable mountpoint chain reached mount"; fi + +reset_case +symlink_real="${test_root}/symlink-real" +symlink_parent="${test_root}/symlink-parent" +mkdir -- "${symlink_real}" +ln -s -- "${symlink_real}" "${symlink_parent}" +run_receipt failed 2 mount 8:1 "$(mount_hex "${symlink_parent}/target")" 0 +if grep -q '^mount' "${mock_log}"; then fail "symlink mountpoint chain reached mount"; fi + +reset_case +export MOCK_LSBLK_MODE=duplicate +duplicate_target="${test_root}/duplicate-target" +mkdir -- "${duplicate_target}" +run_receipt failed 1 mount 8:1 "$(mount_hex "${duplicate_target}")" 0 +if grep -q '^mount' "${mock_log}"; then fail "duplicate MAJ:MIN resolution reached mount"; fi +export MOCK_LSBLK_MODE=malformed +run_receipt failed 1 format 8:1 ext4 +if grep -q '^mkfs\.' "${mock_log}"; then fail "malformed lsblk output reached mkfs"; fi +export MOCK_LSBLK_MODE=fail +run_receipt failed 1 check 8:1 readonly +if grep -Eq '^(e2fsck|xfs_repair|ntfsfix|fsck\.vfat)' "${mock_log}"; then fail "failed lsblk reached checker"; fi + +reset_case +mount_target="${test_root}/mount-existing" +mkdir -- "${mount_target}" +run_receipt applied 0 mount 8:1 "$(mount_hex "${mount_target}")" 0 +assert_file_line "mount\t--source\t/dev/kpanel-test-disk\t--target\t${mount_target}" "${mock_log}" +run_receipt unchanged 0 mount 8:1 "$(mount_hex "${mount_target}")" 0 +run_receipt applied 0 unmount 8:1 "$(mount_hex "${mount_target}")" 0 +assert_file_line "umount\t--\t${mount_target}" "${mock_log}" + +reset_case +nonempty_target="${test_root}/nonempty-target" +mkdir -- "${nonempty_target}" +printf 'keep\n' > "${nonempty_target}/user-data" +run_receipt needs-attention 3 mount 8:1 "$(mount_hex "${nonempty_target}")" 0 +if grep -q '^mount' "${mock_log}"; then fail "nonempty mountpoint reached mount"; fi + +reset_case +mount_failure_target="${test_root}/mount-failure-target" +mkdir -- "${mount_failure_target}" +export MOCK_FAIL_COMMAND=mount +run_receipt failed 1 mount 8:1 "$(mount_hex "${mount_failure_target}")" 0 +if grep -Fqx 'KPANEL_DISK_MANAGEMENT_STATUS=applied' "${test_stdout}"; then + fail "failed mount command was reported as applied" +fi + +reset_case +persistent_target="${test_root}/persistent-target" +mkdir -- "${persistent_target}" +run_receipt applied 0 mount 8:1 "$(mount_hex "${persistent_target}")" 1 +grep -Fqx "UUID=kpanel-test-uuid ${persistent_target} ext4 defaults,nofail 0 2" "${mock_fstab}" || + fail "persistent mount did not write the expected exact fstab entry" +[[ "${receipt_lines[4]}" =~ ^KPANEL_DISK_MANAGEMENT_BACKUP_HEX=[0-9a-f]+$ ]] || fail "persistent update omitted backup" +run_receipt applied 0 unmount 8:1 "$(mount_hex "${persistent_target}")" 1 +if grep -Fq 'UUID=kpanel-test-uuid' "${mock_fstab}"; then fail "persistent unmount did not remove exact fstab entry"; fi + +reset_case +unmount_rollback_target="${test_root}/unmount-rollback-target" +mkdir -- "${unmount_rollback_target}" +run_receipt applied 0 mount 8:1 "$(mount_hex "${unmount_rollback_target}")" 1 +: > "${mock_verify_log}" +touch "${mock_verify_fail_postwrite}" +run_receipt failed 1 unmount 8:1 "$(mount_hex "${unmount_rollback_target}")" 1 +grep -Fqx "UUID=kpanel-test-uuid ${unmount_rollback_target} ext4 defaults,nofail 0 2" "${mock_fstab}" || + fail "failed persistence removal did not restore fstab" +awk -F '\t' -v target="${unmount_rollback_target}" '$1 == "8:1" && $2 == target {found=1} END {exit found ? 0 : 1}' "${mock_mounts}" || + fail "failed persistence removal did not restore the live mount" + +reset_case +rollback_target="${test_root}/rollback-created" +touch "${mock_verify_fail_postwrite}" +run_receipt failed 1 mount 8:1 "$(mount_hex "${rollback_target}")" 1 +[ ! -e "${rollback_target}" ] || fail "fstab failure did not clean the newly created empty mountpoint" +if awk -F '\t' '$1 == "8:1" {found=1} END {exit found ? 0 : 1}' "${mock_mounts}"; then + fail "fstab failure left the device mounted" +fi +[ "$(command cat -- "${mock_fstab}")" = '# kpanel disk-management smoke' ] || fail "fstab failure did not restore original content" +assert_file_line "mount\t--source\t/dev/kpanel-test-disk\t--target\t${rollback_target}" "${mock_log}" +assert_file_line "umount\t--\t${rollback_target}" "${mock_log}" +[[ "${receipt_lines[4]}" =~ ^KPANEL_DISK_MANAGEMENT_BACKUP_HEX=[0-9a-f]+$ ]] || fail "post-write fstab failure omitted recovery backup" + +reset_case +for ((backup_index = 0; backup_index < 20; backup_index++)); do + kpanel_disk_management_create_fstab_backup "${mock_fstab}" >/dev/null || fail "bounded backup creation failed" +done +backup_count="$(find "${mock_state}/recovery" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d '[:space:]')" +[ "${backup_count}" -eq 16 ] || fail "fstab recovery retention is not bounded to 16 snapshots" + +reset_case +printf '8:1\t%s\n' "${test_root}/already-mounted" >> "${mock_mounts}" +run_receipt needs-attention 3 format 8:1 ext4 +if grep -q '^mkfs\.ext4' "${mock_log}"; then fail "mounted device reached mkfs"; fi + +for filesystem in ext4 xfs ntfs vfat; do + reset_case + run_receipt applied 0 format 8:1 "${filesystem}" + case "${filesystem}" in + ext4) expected="mkfs.ext4\t-F\t/dev/kpanel-test-disk" ;; + xfs) expected="mkfs.xfs\t-f\t/dev/kpanel-test-disk" ;; + ntfs) expected="mkfs.ntfs\t-F\t/dev/kpanel-test-disk" ;; + vfat) expected="mkfs.vfat\t/dev/kpanel-test-disk" ;; + esac + assert_file_line "${expected}" "${mock_log}" +done + +reset_case +export MOCK_MISSING_TOOLS=mkfs.ntfs +run_receipt applied 0 format 8:1 ntfs +assert_file_line 'mkntfs\t-F\t/dev/kpanel-test-disk' "${mock_log}" +if grep -q '^mkfs\.ntfs' "${mock_log}"; then fail "ntfs fallback called unavailable primary command"; fi + +reset_case +export MOCK_MISSING_TOOLS=mkfs.vfat +run_receipt applied 0 format 8:1 vfat +assert_file_line 'mkfs.fat\t/dev/kpanel-test-disk' "${mock_log}" +if grep -q '^mkfs\.vfat' "${mock_log}"; then fail "fat fallback called unavailable primary command"; fi + +for specification in \ + 'ext4 readonly e2fsck\t-fn\t/dev/kpanel-test-disk unchanged 0' \ + 'ext4 repair e2fsck\t-fy\t/dev/kpanel-test-disk applied 0' \ + 'xfs readonly xfs_repair\t-n\t/dev/kpanel-test-disk unchanged 0' \ + 'xfs repair xfs_repair\t/dev/kpanel-test-disk applied 0' \ + 'ntfs readonly ntfsfix\t-n\t/dev/kpanel-test-disk unchanged 0' \ + 'ntfs repair ntfsfix\t/dev/kpanel-test-disk applied 0' \ + 'vfat readonly fsck.vfat\t-n\t/dev/kpanel-test-disk unchanged 0' \ + 'vfat repair fsck.vfat\t-a\t/dev/kpanel-test-disk applied 0'; do + read -r filesystem mode expected status rc <<< "${specification}" + reset_case + printf '%s\n' "${filesystem}" > "${mock_fstype}" + run_receipt "${status}" "${rc}" check 8:1 "${mode}" + assert_file_line "${expected}" "${mock_log}" +done + +reset_case +printf 'vfat\n' > "${mock_fstype}" +export MOCK_MISSING_TOOLS=fsck.vfat +run_receipt unchanged 0 check 8:1 readonly +assert_file_line 'fsck.fat\t-n\t/dev/kpanel-test-disk' "${mock_log}" +if grep -q '^fsck\.vfat' "${mock_log}"; then fail "fat checker fallback called unavailable primary command"; fi + +reset_case +printf 'vfat\n' > "${mock_fstype}" +export MOCK_MISSING_TOOLS=fsck.vfat +run_receipt applied 0 check 8:1 repair +assert_file_line 'fsck.fat\t-a\t/dev/kpanel-test-disk' "${mock_log}" + +reset_case +export MOCK_FAIL_COMMAND=mkfs.ext4 +run_receipt failed 1 format 8:1 ext4 +if grep -Fqx 'KPANEL_DISK_MANAGEMENT_STATUS=applied' "${test_stdout}"; then + fail "failed mkfs was reported as applied" +fi + +reset_case +export MOCK_FAIL_COMMAND=e2fsck +run_receipt needs-attention 3 check 8:1 readonly +if grep -Fqx 'KPANEL_DISK_MANAGEMENT_STATUS=unchanged' "${test_stdout}"; then + fail "failed readonly checker was reported as unchanged" +fi + +reset_case +export MOCK_FLOCK_FAIL=1 +run_receipt conflict 2 format 8:1 ext4 +if grep -q '^mkfs\.ext4' "${mock_log}"; then fail "lock conflict reached mkfs"; fi + +reset_case +rm -f -- "${mock_lock}" +lock_hardlink_source="${mock_lock_parent}/hardlink-source" +: > "${lock_hardlink_source}" +chmod 600 "${lock_hardlink_source}" +ln -- "${lock_hardlink_source}" "${mock_lock}" +run_receipt failed 1 format 8:1 ext4 +if grep -q '^mkfs\.ext4' "${mock_log}"; then fail "hard-linked lock reached mkfs"; fi + +printf '%s\n' 'PASS: KPanel disk-management noninteractive smoke tests'